Pretty C — это новый язык сценариев, совместимый с C. Pretty C расширяет ваши программы за счет динамической типизации, общей итерации, отслеживания ресурсов и других тонкостей. И он обратно совместим с C и всеми его библиотеками! Вдохновлен Lua, Python, JavaScript и Lisp. Вот как может выглядеть наивная повторная реализация утилиты head
с помощью Pretty C:
#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
способная из произвольного файла 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
for ||
. Аккуратный! Их определяет каждый, так почему бы не предоставить их?
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
для операций, которые раньше вызывались непоследовательно ( compl
и xor
соответственно) в iso646.h
.success
и fail
/ failure
для шаблона success == 0
.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
, чтобы закомментировать некоторый код с помощью всего одного ключевого слова, в то же время позволяя компилятору анализировать/оптимизировать его (аналогично форме comment
Clojure): 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 );
С Красоткой С.
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, ...)
new
оператор в C++ хорош, так что не помешает иметь что-то подобное в 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, ...)
С++ снова. std::vector
— чрезвычайно полезная и универсальная структура данных, о которой легко рассуждать. Хотя этот макрос даже отдаленно не так функционален, как аналог C++, он упрощает частую схему «выделить массив из такого-то количества элементов и с таким-то содержимым»:
double * vec = vector ( 10 , double , 1 , 2 , 3 , 4 , 5 );
delete (...)
На случай, если вам не нравится free
использование ресурсов и вы предпочитаете более красивое имя C++.
В остальном то же самое, что и free
.
Они устанавливают новые локальные привязки, обеспечивают отложенные вычисления или иным образом воздействуют на блок после них.
lambda (ret, name, ...)
(GCC, Clang или C++)Вложенные функции/лямбда-выражения/замыкания теперь и в 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!" );
NOERR
и NOERROR
также предоставляются в Pretty C для удобства переключения ошибок.
make indent
, которая должна обрабатывать большую часть деталей стиля.