Pretty C 是一种与 C 兼容的新脚本语言。 Pretty C 通过动态类型、泛型迭代、资源跟踪和其他细节来增强您的程序。而且它向后兼容 C 及其所有库!受到 Lua、Python、JavaScript 和 Lisp 的启发。下面是使用 Pretty C 简单地重新实现head实用程序的样子:
#include "pretty.h"
int main ( int argc , string argv [])
{
if ( argc above 1 )
with ( f , fclose , fopen ( argv [ 1 ], "r" ))
fortimes ( line , 10 )
with ( buf , free , vector ( 200 , char , 0 ))
when ( fgets ( buf , 200 , f ))
then print ( buf )
otherwise 0 ;
else
println ( "Please provide an input file" );
return EXIT_SUCCESS ;
}Pretty C 的目标是:
#include include - 可来自任意 C 文件!),将任何代码库变成初学者友好的代码库。签出存储库
git clone https://github.com/aartaka/pretty.c或者直接复制pretty.h文件——Pretty C 是一个仅包含头文件的库,因此您可以
#include "pretty.h"从您将pretty.h放入的目录中的任何文件。或者实际上来自任何文件,如果您将 Pretty C 的路径指定为包含 ( -I ) 路径。
以下是让 C 再次流行的所有漂亮变化。
true 、 false和bool 。uint64_t 。&&的and和||的or 。整洁的! 每个人都定义了这些,那么为什么不提供它们呢?
max和min 。len为数组长度。default提供后备值。limit以确保正确的值范围。between检查数字是否在某个范围内。divisible检查一个数字是否可以被另一个数字模整除。 输入别名:
string == char* 。byte == char 。bytes == char* 。any == void* 。uchar 。ushort 。uint 。ulong . 主要模仿Lua和Lisp:
eq ,因为iso646.h只有not_eq 。is也意味着== 。bitnot和bitxor用于在iso646.h中调用不一致的操作(分别为compl和xor )。success == 0模式的success和fail / failure 。below 、 above 、 upto和downto比较运算符。even 、 odd 、 positive 、 negative 、 zero和empty作为数字/数据的谓词。nil代表NULL 。until取反while 。elif为else if 。ifnt代表if(!...)和elifnt (你猜对了。)repeat Lua 作为do的别名。done~/~finish和pass分别作为break和continue别名。always 、 forever 、 loop和indefinitely以便您可以进行无限(事件?服务器?)循环 always println ( "After all this time?" );never和comment只用一个关键字注释掉一些代码,同时仍然允许编译器分析/优化它(类似于 Clojure comment形式): never println ( "This never runs, but never gets outdated, because compiler will shout at you if it does." );是的,你可以做
var t = time ( 0 );
let lt = localtime ( & t );
local at = asctime ( lt );
println ( at );和漂亮的C.
print打印你输入的任何内容。 println在其后添加一个换行符。
println ( 3.1 );
print ( "Hello world!n" );比较所有的事情!
equal ( "NA" , line ); // true
equal ( 0.3 , 0.2 + 0.1 ); // true 三元数很可怕,所以添加一些纯文本也没什么坏处。 if和else被采用,但是有一些看起来很像 Python/Lisp 的适当的语言替代方案:
return when some_condition
then do_something ()
other do_something_else ();下面是三元组:
when扩展为空字符串,仅为了可读性而提供。unless扩展为not when的负版本。then扩展到? 。other / otherwise扩展为: . only当不需要otherwise子句时才适用:
return when done ()
then 42 only ;和otherwhen为下一个条件
return when c is 'A'
then 'a'
otherwhen c is 'B'
then 'b' only ;for宏这些宏是某些for循环模式的别名,每个宏都抽象了一些频繁的for循环使用。
foreach (var, type, length, ...)该函数遍历初始化为 vararg 表达式的数组或内存区域。每次迭代时, var都会被设置为指向相应数组元素的指针。是的,指针——这样您就可以在必要时修改元素。
foreach ( i , int , 10 , vector ( 10 , int , 1 , 2 , 3 , 3 , 4 , 5 ))
println ( * i );还展示了vector的使用。
forthese (var, type, ...)迭代提供的可变参数,将每个可变参数绑定到type -d var 。上面的循环可以翻译为:
forthese ( i , int , 1 , 2 , 3 , 3 , 4 , 5 )
println ( i );fortimes (var, times)从 0 到某个正数的常见情况。为您节省相当多的时间
for ( int i = 0 ; i < 28 ; i ++ )
println ( i + 1 );把它变成一个简单的
fortimes ( i , 28 )
println ( i + 1 );
println ( "28 stab wounds, you didn't want to leave him a chance, huh?" );forrange (var, init, target)迭代从init到target的一系列数字。蟒蛇式的。这是使用forrange摄氏温度到华氏温度的转换循环:
forrange ( c , -10 , 20 )
printf ( "Celsius %i = Fahrenheit %fn" , c , ( 32 + ( c * 1.8 )));请注意, init和target是任意整数,有符号和无符号。并且init可能大于target ,在这种情况下迭代步骤会减少变量。
forrangeby (var, type, init, target, by)将type -d var从iter迭代到target ,每次by逐步执行。蟒蛇式的。
forrangeby ( x , double , 1.0 , 10.0 , 0.5 )
println ( x );这些允许对典型模式进行快速而肮脏的分配。主要模仿 C++。
new (type, ...) C++ new运算符很好,所以在 C 中拥有类似的东西不会有什么坏处,对吧?别再问了:
struct ListNode {
int val ;
struct ListNode * next ;
};
struct ListNode * node = new ( struct ListNode , 2 , new ( struct ListNode , 1 , nil ));或者,如果您愿意,您可以在上面添加更多语法:
#define cons ( val , ...) new(struct ListNode, val, __VA_ARGS__)
cons ( 2 , cons ( 1 , nil ));vector (length, type, ...)又是C++。 std::vector是一种非常有用且通用的数据结构,很容易推理。虽然这个宏的功能远远不如 C++ 对应的宏,但它简化了“分配这么多元素和这些内容的数组”的常见模式:
double * vec = vector ( 10 , double , 1 , 2 , 3 , 4 , 5 );delete (...)如果您不喜欢free资源并且更喜欢更漂亮的 C++ 名称。
否则与free一样。
它们建立新的本地绑定,确保延迟计算,或者以其他方式作用于它们之后的块。
lambda (ret, name, ...) (GCC、Clang 或 C++)嵌套函数/lambdas/闭包,现在用 C 语言!
int * arr = vector ( 10 , int , 23423 , 23423 , 234 , 5233 , 6 , 4 , 34 , 643 , 3 , 9 );
lambda ( int , cmp , int * a , int * b ) {
return * a - * b ;
};
qsort ( arr , 10 , sizeof ( int ), cmp );
// arr becomes {3, 4, 6, 9, 34, 234, 643, 5233, 23423, 23423}with (var, close, ...)这可以确保您永远不会出现释放后使用,因为您预先提供了释放过程( close )。对于动态分配的对象和文件指示符特别有用。
with ( file , fclose , fopen ( "hello.txt" , "w" ))
fprintf ( file , "Hello world!n" );缺点之一是绑定的var是void * ,因此您可能需要在使用它之前将其强制为您的类型。
defer (...)卸载要在下一个块之后执行的代码。不像 Go 中那样在函数末尾,因为那是不可能的在 C 中很难实现。不过,Pretty C defer已经足够有用了。
try并catch花哨的错误处理,现在在 C 中。来自 errno 参考的重构示例:
try log ( 0.0 );
catch ( NOERR )
println ( "No error." );
catch ( EDOM , ERANGE )
println ( "Math error!" ); Pretty C 还提供了NOERR和NOERROR ,以方便错误切换。
make indent ,这应该处理大部分样式细节。