Pretty C é uma nova linguagem de script compatível com C. Pretty C aprimora seus programas com digitação dinâmica, iteração genérica, rastreamento de recursos e outras sutilezas. E é compatível com versões anteriores de C e todas as suas bibliotecas! Inspirado em Lua, Python, JavaScript e Lisp. Veja como seria uma reimplementação ingênua do utilitário head
com 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 ;
}
Os objetivos do Pretty C são:
#include
-capaz de arquivo C arbitrário!) para transformar qualquer base de código em uma base amigável para iniciantes.Confira o repositório
git clone https://github.com/aartaka/pretty.c
Ou simplesmente copie o arquivo pretty.h
- Pretty C é uma biblioteca somente de cabeçalho, então você pode
#include "pretty.h"
de qualquer arquivo no diretório para o qual você colocou pretty.h
. Ou de qualquer arquivo, se você especificar o caminho para Pretty C como um caminho de inclusão ( -I
).
Aqui estão todas as mudanças bonitas que fizeram o C hip novamente.
true
, false
e bool
.uint64_t
.and
para &&
e or
para ||
. Organizado! Todo mundo define isso, então por que não fornecê-los?
max
e min
de dois números.len
para comprimento da matriz.default
para fornecer um valor substituto.limit
para garantir a faixa de valores adequada.between
para verificar se o número está em um intervalo.divisible
para verificar se um número é módulo divisível por outro número. Aliases de tipo:
string
== char*
.byte
== char
.bytes
== char*
.any
== void*
.uchar
.ushort
.uint
.ulong
. Modelado principalmente após Lua e Lisp:
eq
, porque iso646.h
só possui not_eq
.is
significa ==
também.bitnot
e bitxor
para operações que costumavam ser chamadas de forma inconsistente ( compl
e xor
respectivamente) em iso646.h
.success
e fail
/ failure
para padrão de success == 0
.below
, above
, upto
e downto
dos operadores de comparação.even
, odd
, positive
, negative
, zero
e empty
como predicados para números/dados.nil
para NULL
.until
para negado while
.elif
para else if
.ifnt
para if(!...)
e elifnt
(você adivinhou.)repeat
de Lua como um alias para do
.done~/~finish
e pass
como apelidos para break
e continue
, respectivamente.always
, forever
, loop
e indefinitely
para que você possa fazer loops infinitos (evento? servidor?) always println ( "After all this time?" );
never
e comment
para comentar algum código com apenas uma palavra-chave, enquanto ainda permite que o compilador o analise/otimize (semelhante ao formulário comment
do Clojure): never println ( "This never runs, but never gets outdated, because compiler will shout at you if it does." );
Sim, você pode fazer
var t = time ( 0 );
let lt = localtime ( & t );
local at = asctime ( lt );
println ( at );
Com Linda C.
print
tudo o que você alimenta. println
adiciona uma nova linha depois dele.
println ( 3.1 );
print ( "Hello world!n" );
Compare todas as coisas!
equal ( "NA" , line ); // true
equal ( 0.3 , 0.2 + 0.1 ); // true
Ternários são assustadores, então não custa nada adicionar algum texto simples. if
e else
são usados, mas existem alternativas linguísticas adequadas que se parecem bastante com Python/Lisp:
return when some_condition
then do_something ()
other do_something_else ();
São ternários abaixo:
when
se expande para uma string vazia e é fornecido apenas para facilitar a leitura.unless
se expanda para not
ser uma versão negativa de when
.then
se expande para ?
.other
/ otherwise
expande para :
. Há também only
quando a cláusula otherwise
for desnecessária:
return when done ()
then 42 only ;
e otherwhen
para a próxima condição
return when c is 'A'
then 'a'
otherwhen c is 'B'
then 'b' only ;
for
macros Essas macros são aliases para determinados padrões de loop for
, cada uma abstraindo alguns dos usos frequentes for
loop for.
foreach (var, type, length, ...)
Este percorre um array ou região de memória inicializada na expressão vararg. Cada vez que itera, var
é definido como um ponteiro para o respectivo elemento da matriz. Sim, ponteiro - para que você possa modificar o elemento no local, se necessário.
foreach ( i , int , 10 , vector ( 10 , int , 1 , 2 , 3 , 3 , 4 , 5 ))
println ( * i );
Também mostra o uso de vector
.
forthese (var, type, ...)
Itera sobre os varargs fornecidos, vinculando cada um deles ao type
-d var
. O loop acima pode ser traduzido como:
forthese ( i , int , 1 , 2 , 3 , 3 , 4 , 5 )
println ( i );
fortimes (var, times)
Um caso frequente de ir de 0 a algum número positivo. Economiza bastante tempo para o seu
for ( int i = 0 ; i < 28 ; i ++ )
println ( i + 1 );
transformando-o em um simples
fortimes ( i , 28 )
println ( i + 1 );
println ( "28 stab wounds, you didn't want to leave him a chance, huh?" );
forrange (var, init, target)
Itere em um intervalo de números de init
a target
. Pitonesco. Aqui está o loop de conversão de Celsius para Fahrenheit com forrange
:
forrange ( c , -10 , 20 )
printf ( "Celsius %i = Fahrenheit %fn" , c , ( 32 + ( c * 1.8 )));
Observe que init
e target
são números inteiros arbitrários, assinados e não assinados. E init
pode ser maior que target
, caso em que a etapa de iteração diminui a variável.
forrangeby (var, type, init, target, by)
Itere type
-d var
de iter
para target
, passando by
. Pitonesco.
forrangeby ( x , double , 1.0 , 10.0 , 0.5 )
println ( x );
Isso permite uma alocação rápida e suja para padrões típicos. Principalmente modelado após C++.
new (type, ...)
O new
operador C++ é legal, então não vai doer ter algo semelhante em C, certo? Não pergunte mais:
struct ListNode {
int val ;
struct ListNode * next ;
};
struct ListNode * node = new ( struct ListNode , 2 , new ( struct ListNode , 1 , nil ));
Ou, se desejar, você pode adicionar ainda mais sintaxe:
#define cons ( val , ...) new(struct ListNode, val, __VA_ARGS__)
cons ( 2 , cons ( 1 , nil ));
vector (length, type, ...)
C++ novamente. std::vector
é uma estrutura de dados extremamente útil e versátil, fácil de raciocinar. Embora esta macro não seja nem remotamente tão funcional quanto a contraparte C++, ela simplifica um padrão frequente de “alocar uma matriz com tantos elementos e com estes conteúdos”:
double * vec = vector ( 10 , double , 1 , 2 , 3 , 4 , 5 );
delete (...)
Caso você não goste de free
recursos e prefira um nome C++ mais sofisticado.
Caso contrário, o mesmo que free
.
Eles estabelecem novas ligações locais, garantem cálculos adiados ou atuam no bloco após eles.
lambda (ret, name, ...)
(GCC, Clang ou C++)Funções/lambdas/fechamentos aninhados, agora em 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, ...)
Isso garante que você nunca use depois de liberar, porque você fornece o procedimento de liberação ( close
) antecipadamente. Especialmente útil para objetos alocados dinamicamente e designadores de arquivos.
with ( file , fclose , fopen ( "hello.txt" , "w" ))
fprintf ( file , "Hello world!n" );
Uma das desvantagens é que o var
vinculado é void *
, portanto, talvez seja necessário forçá-lo ao seu tipo antes de usá-lo.
defer (...)
Descarrega o código a ser executado após o bloco seguinte. Não no final da função como em Go, porque isso é impossível difícil de implementar em C. Ainda assim, Pretty C defer
é bastante útil.
try
catch
Tratamento de erros sofisticado, agora em C. Exemplo refatorado da referência errno:
try log ( 0.0 );
catch ( NOERR )
println ( "No error." );
catch ( EDOM , ERANGE )
println ( "Math error!" );
NOERR
e NOERROR
também são fornecidos pelo Pretty C, para conveniência de caixa de comutação de erros.
make indent
antes de confirmar, que deve lidar com a maioria dos detalhes do estilo.