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 , которая должна обрабатывать большую часть деталей стиля.