Pretty C es un nuevo lenguaje de scripting compatible con C. Pretty C potencia tus programas con escritura dinámica, iteración genérica, seguimiento de recursos y otras sutilezas. ¡Y es compatible con versiones anteriores de C y todas sus bibliotecas! Inspirado en Lua, Python, JavaScript y Lisp. Así es como podría verse una reimplementación ingenua de la utilidad head
con 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 ;
}
Los objetivos de Pretty C son:
#include
-able desde un archivo C arbitrario) para convertir cualquier código base en uno amigable para principiantes.Consulta el repositorio
git clone https://github.com/aartaka/pretty.c
O simplemente copie el archivo pretty.h
: Pretty C es una biblioteca de solo encabezados, por lo que puede
#include "pretty.h"
desde cualquier archivo en el directorio al que coloques pretty.h
. O realmente desde cualquier archivo, si especifica la ruta a Pretty C como una ruta incluida ( -I
).
Aquí están todos los bonitos cambios que hacen que C vuelva a estar de moda.
true
, false
y bool
.uint64_t
.and
para &&
y or
para ||
. ¡Limpio! Todo el mundo los define, así que ¿por qué no proporcionarlos?
max
y min
de dos números.len
para la longitud de la matriz.default
para proporcionar un valor de reserva.limit
para garantizar el rango de valores adecuado.between
para comprobar si el número cae dentro de un rango.divisible
para comprobar si un número es módulo divisible por otro número. Alias de tipo:
string
== char*
.byte
== char
.bytes
== char*
.any
== void*
.uchar
.ushort
.uint
.ulong
. Principalmente modelado a partir de Lua y Lisp:
eq
, porque iso646.h
solo tiene not_eq
.is
significa ==
también.bitnot
y bitxor
para operaciones que solían llamarse de manera inconsistente ( compl
y xor
respectivamente) en iso646.h
.success
y fail
/ failure
para el patrón de success == 0
.below
, above
, upto
y downto
.even
, odd
, positive
, negative
, zero
y empty
como predicados para números/datos.nil
para NULL
.until
por negado while
.elif
para else if
.ifnt
para if(!...)
y elifnt
(lo has adivinado).repeat
desde Lua como alias para do
.done~/~finish
y pass
como alias para break
y continue
, respectivamente.always
, forever
, loop
e indefinitely
para que puedas hacer bucles infinitos (¿evento? ¿servidor?) always println ( "After all this time?" );
never
y comment
para comentar algún código con una sola palabra clave, al tiempo que permite que el compilador lo analice/optimice (similar al formulario comment
de Clojure): never println ( "This never runs, but never gets outdated, because compiler will shout at you if it does." );
Si, puedes hacer
var t = time ( 0 );
let lt = localtime ( & t );
local at = asctime ( lt );
println ( at );
Con la bonita C.
print
todo lo que le das de comer. println
agrega una nueva línea después.
println ( 3.1 );
print ( "Hello world!n" );
¡Compara todas las cosas!
equal ( "NA" , line ); // true
equal ( 0.3 , 0.2 + 0.1 ); // true
Los ternarios dan miedo, por lo que no estará de más agregar texto sin formato. Se toman if
y else
, pero existen alternativas lingüísticas adecuadas que se parecen bastante a Python/Lisp:
return when some_condition
then do_something ()
other do_something_else ();
Son ternarios debajo:
when
se expande a una cadena vacía y solo se proporciona para facilitar la lectura.unless
se expanda para not
ser una versión negativa de when
.then
se expande a ?
.other
/ otherwise
se expande a :
. También existe only
para cuando la cláusula otherwise
es innecesaria:
return when done ()
then 42 only ;
y otherwhen
para la siguiente condición
return when c is 'A'
then 'a'
otherwhen c is 'B'
then 'b' only ;
for
macros Estas macros son alias para ciertos patrones de bucle for
, y cada una abstrae algunos de los usos frecuentes for
bucle for.
foreach (var, type, length, ...)
Este recorre una matriz o región de memoria inicializada con la expresión vararg. Cada vez que se itera, var
se establece en un puntero al elemento de matriz respectivo. Sí, puntero, para que pueda modificar el elemento en su lugar si es necesario.
foreach ( i , int , 10 , vector ( 10 , int , 1 , 2 , 3 , 3 , 4 , 5 ))
println ( * i );
También muestra el uso de vector
.
forthese (var, type, ...)
Itera sobre los varargs proporcionados, vinculando cada uno de ellos al type
-d var
. El bucle anterior se puede traducir como:
forthese ( i , int , 1 , 2 , 3 , 3 , 4 , 5 )
println ( i );
fortimes (var, times)
Un caso frecuente de pasar de 0 a algún número positivo. Le ahorra bastante tiempo para su
for ( int i = 0 ; i < 28 ; i ++ )
println ( i + 1 );
convirtiéndolo en un simple
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 sobre un rango de números desde init
hasta target
. Pitonesco. Aquí está el bucle de conversión de Celsius a Fahrenheit con forrange
:
forrange ( c , -10 , 20 )
printf ( "Celsius %i = Fahrenheit %fn" , c , ( 32 + ( c * 1.8 )));
Tenga en cuenta que init
y target
son números enteros arbitrarios, con y sin signo. Y init
podría ser mayor que target
, en cuyo caso el paso de iteración disminuye la variable.
forrangeby (var, type, init, target, by)
Itere type
-d var
desde iter
hasta target
, avanzando paso a by
cada vez. Pitonesco.
forrangeby ( x , double , 1.0 , 10.0 , 0.5 )
println ( x );
Estos permiten una asignación rápida y precisa para patrones típicos. Principalmente modelado a partir de C++.
new (type, ...)
new
operador de C++ es bueno, por lo que no vendrá mal tener algo similar en C, ¿verdad? No preguntes más:
struct ListNode {
int val ;
struct ListNode * next ;
};
struct ListNode * node = new ( struct ListNode , 2 , new ( struct ListNode , 1 , nil ));
O, si lo deseas, puedes agregar aún más sintaxis encima:
#define cons ( val , ...) new(struct ListNode, val, __VA_ARGS__)
cons ( 2 , cons ( 1 , nil ));
vector (length, type, ...)
C++ de nuevo. std::vector
es una estructura de datos extremadamente útil y versátil sobre la que es fácil razonar. Si bien esta macro no tiene ni remotamente tantas funciones como su contraparte de C++, simplifica un patrón frecuente de "asignar una matriz de esa cantidad de elementos y con estos contenidos":
double * vec = vector ( 10 , double , 1 , 2 , 3 , 4 , 5 );
delete (...)
En caso de que no le guste free
los recursos y prefiera un nombre C++ más elegante.
Por lo demás igual que free
.
Estos establecen nuevos enlaces locales, garantizan cálculos diferidos o actúan de otro modo en el bloque posterior a ellos.
lambda (ret, name, ...)
(GCC, Clang o C++)Funciones anidadas/lambdas/cierres, ¡ahora en 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, ...)
Esto garantiza que nunca tendrá uso después de la liberación, porque proporciona el procedimiento de liberación ( close
) por adelantado. Especialmente útil para objetos asignados dinámicamente y designadores de archivos.
with ( file , fclose , fopen ( "hello.txt" , "w" ))
fprintf ( file , "Hello world!n" );
Una de las desventajas es que la var
vinculada es void *
, por lo que es posible que deba forzarla a su tipo antes de usarla.
defer (...)
Descarga el código que se ejecutará después del siguiente bloque. No al final de la función como en Go, porque eso es imposible difícil de implementar en C. Aún así, Pretty C defer
es bastante útil.
try
catch
Manejo de errores sofisticado, ahora en C. Ejemplo refactorizado a partir de la referencia de errno:
try log ( 0.0 );
catch ( NOERR )
println ( "No error." );
catch ( EDOM , ERANGE )
println ( "Math error!" );
Pretty C también proporciona NOERR
y NOERROR
, para facilitar el error en la carcasa del interruptor.
make indent
antes de confirmar, eso debería manejar la mayoría de los detalles de estilo.