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
,这应该处理大部分样式细节。