Pretty.c - scripting que funciona sobre C
(github.com/aartaka)- Pretty C es un nuevo lenguaje de scripting compatible con C que añade a los programas en C funciones de conveniencia como tipado dinámico, iteración genérica y seguimiento de recursos
- Se usa como una biblioteca header-only que solo requiere incluir
pretty.h, y puede utilizarse junto con archivos C y bibliotecas C existentes - Entre las funciones que ofrece están alias como
string,any,nil, inferencia de tipos convar/let, salida genérica conprint/println, comparación genérica conequaly macros ternarias más legibles - Para reducir el trabajo repetitivo en iteración y memoria, proporciona sintaxis basada en macros como
foreach,forthese,fortimes,forrange,new,vector,delete,with,lambda,try/catch - Algunas funciones dependen de condiciones como GCC, Clang, C23+, C11+, y las variables ligadas con
withsonvoid *, por lo que puede ser necesario convertirlas de tipo antes de usarlas
Objetivos y forma de uso de Pretty C
- Pretty C es un lenguaje de scripting compatible con C que añade a los programas en C tipado dinámico, iteración genérica, seguimiento de recursos y varias comodidades sintácticas
- Mantiene la compatibilidad hacia atrás con C existente y con bibliotecas C
- Está inspirado en Lua, Python, JavaScript y Lisp
- Para instalarlo, se puede clonar el repositorio o copiar únicamente el archivo
pretty.h- Puede incluirse en cualquier archivo C con
#include "pretty.h" - También puede usarse especificando la ruta de Pretty C en el include path
- Puede incluirse en cualquier archivo C con
Headers incluidos por defecto y macros simples
- Pretty C incluye headers estándar para que tipos de uso frecuente y expresiones alternativas de operadores estén disponibles de inmediato
- También proporciona macros simples de uso común
max,min: valor máximo y mínimo entre dos númeroslen: longitud de un arreglodefault: proporciona un valor fallbacklimit: limita un valor a un rangobetween: verifica si un número está dentro de un rangodivisible: verifica si se divide exactamente entre otro número
Tipos y alias
- Pretty C ofrece alias de tipos cortos para tipos de C
stringeschar*byteescharbyteseschar*anyesvoid*- También ofrece abreviaciones enteras como
uchar,ushort,uint,ulong
- También incluye alias sintácticos influenciados por Lua y Lisp
eq,is:==bitnot,bitxor: alias para operaciones de bitssuccess,fail,failure: alias para el patrónsuccess == 0below,above,upto,downto: operadores de comparacióneven,odd,positive,negative,zero,empty: predicados para números y datosnil:NULLuntil:whilenegadoelif:else ififnt,elifnt: expresiones del tipoif(!...)repeat: alias estilo Lua paradodone,finish,pass: alias parabreak,continuealways,forever,loop,indefinitely: expresiones para bucles infinitosnever,comment: expresiones que no ejecutan código pero permiten que el compilador lo analice
Inferencia de tipos, salida, comparación y ternarios
- La inferencia de tipos puede usarse con GCC, Clang o C23+
- Como ejemplo, ofrece formas como
var t = time(0);,let lt = localtime(&t);,local at = asctime(lt);
- Como ejemplo, ofrece formas como
- La salida genérica está disponible en C11+
printimprime el valor recibidoprintlnagrega un salto de línea después de imprimir
- La comparación genérica de igualdad también se ofrece como función de C11+
- Comparación de cadenas como
equal("NA", line) - Incluye ejemplos como
equal(0.3, 0.2 + 0.1)
- Comparación de cadenas como
- El operador ternario puede hacerse más legible con macros basadas en texto
whense expande a una cadena vacía para mejorar la legibilidadunlessse expande anoty funciona como forma negativa dewhenthenes?otheryotherwiseson:onlyse usa cuando no se necesita la cláusulaotherwiseotherwhense usa para encadenar la siguiente condición
Macros de iteración
- Pretty C abstrae mediante macros patrones frecuentes de bucles
for foreach (var, type, length, ...)- Recorre un arreglo o una región de memoria
- En cada iteración,
varse convierte en un puntero al elemento correspondiente del arreglo - Como es un puntero, permite modificar el elemento in-place si hace falta
forthese (var, type, ...)- Recorre los argumentos variables recibidos y liga cada valor a
vardeltypeindicado
- Recorre los argumentos variables recibidos y liga cada valor a
fortimes (var, times)- Reduce el patrón común de iterar desde 0 hasta una cantidad positiva de veces
forrange (var, init, target)- Recorre un rango numérico desde
inithastatarget initytargetpueden ser cualquier entero con signo o sin signo- Si
inites mayor quetarget, el paso de iteración disminuye
- Recorre un rango numérico desde
forrangeby (var, type, init, target, by)- Recorre
vardeltypeespecificado desdeinithastatargetcon incrementos deby
- Recorre
Utilidades de asignación y de bloques
- Las macros de asignación simplifican patrones comunes de reserva de memoria con una forma influenciada por C++
new (type, ...): crea structs y otros objetos con una forma parecida anewde C++vector (length, type, ...): simplifica el patrón de asignar un arreglo del tamaño y tipo indicados con contenido inicialdelete (...): equivale afree, pero puede usarse si se prefiere un nombre al estilo C++
- Las utilidades de bloque proporcionan macros para enlaces locales, ejecución diferida y trabajo por bloques
lambda (ret, name, ...): permite usar funciones anidadas, lambdas o cierres en C con GCC, Clang o C++with (var, close, ...): proporciona por adelantado la función de liberaciónclose, útil para objetos asignados dinámicamente o file handles- Como desventaja, la variable ligada
varesvoid *, por lo que puede requerir conversión al tipo deseado antes de usarse
- Como desventaja, la variable ligada
defer: fue eliminado, y se indica usar el nuevodeferdisponibletryycatch: permiten escribir el manejo de errores en C con una forma más vistosaNOERR,NOERROR: se proporcionan para facilitar switch-case de errores
Cómo contribuir
- Al añadir funciones, se pide seguir la Linux Kernel Style Guide
- Se recomienda ejecutar
make indentantes de hacer commit
- Se recomienda ejecutar
- Se prefiere seguir la A’s Commit Message Guide, aunque no es obligatorio
1 comentarios
Opiniones de Hacker News
La tradición de crear lenguajes específicos de dominio dentro de C viene de hace mucho.
Stephen Bourne quería escribir el shell en ALGOL, así que martilló obstinadamente el preprocesador de C hasta hacerlo parecer el lenguaje que prefería.
https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...
https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...
https://www.ioccc.org/
Me pregunto si alguien puede explicar si esto es una broma o si el autor está realmente confundido.
Nada tiene sentido. No es “scripting”, dice que introduce “tipado fuerte” pero no hace nada con los tipos, y los alias de operadores supuestamente inspirados en Lua y Lisp en realidad no existen en ninguno de esos dos lenguajes. Pero tampoco parece una parodia evidente, así que de verdad desconcierta.
Afirma ser un lenguaje de scripting, pero igual hay que compilar el programa. Dan ganas de abuchear.
Si le agregas CINT(https://root.cern.ch/root/html534/guides/users-guide/CINT.ht...), puedes ejecutarlo de inmediato y tener un REPL.
Hace tiempo vi una entrada de blog que explicaba en detalle cómo funciona
./fooy cómo se ejecutan los archivos ELF. Parecería posible registrar programas.cde la misma manera para que se compilen y luego se ejecuten.[0] https://gist.github.com/jdarpinian/1952a58b823222627cc1a8b83...
[0] https://bellard.org/tcc/tcc-doc.html
“Ofrece suficiente azúcar sintáctico como para provocarle a un desarrollador de C un infarto diabético”.
Esa frase me encanta.
Veo algunas cosas que habría que agregar a CNoEvil[0] y ogw[1]. Parece que cada vez que este proyecto vuelve a aparecer cada pocos meses, siempre hay más.
[0] https://git.sr.ht/~shakna/cnoevil3/
[1] https://git.sr.ht/~shakna/ogw
Es una frase que sinceramente termino amando desde lo más profundo.
Esto comete el mismo error que Python 2. Las cadenas y los bytes no son el mismo tipo, y no deberían tratarse como si lo fueran.
argvo la salida de subprocesos?Ahí puede haber basura arbitraria, así que no es una cadena UTF-8 válida, pero herramientas como awk y grep se usan en todas partes.
Creo que las cadenas y los bytes pueden verse como el mismo tipo general, aunque a veces es útil darles internamente otro tipo a los bytes UTF-8 válidos. Rust maneja esto bastante bien con OsString y String.
https://en.cppreference.com/w/c/string/multibyte
Ninguna de esas cosas es siempre cierta. Es útil envolver una secuencia de bytes validada en un tipo que solo pueda construirse mediante validación, pero una vez que haces eso,
Utf8StringyEmailAddressson básicamente de la misma categoría. No hay razón para darle un trato especial solo a la codificación dentro del sistema de tipos.Si significa “texto legible por humanos”, estoy de acuerdo en que una cadena no es lo mismo que un arreglo arbitrario de bytes. Pero muchos lenguajes no imponen esa definición.
Me recordó a una base de código en C++ que tuve que revisar hace tiempo. Todo estaba hecho como si estuviera escrito en Java: camelCase en todo, getters/setters para todas las variables de clase e interfaces por todas partes.
https://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd...
Cuesta creer que no sea ALGOL.
std::stringcon métodos al estilo Java.https://learn.microsoft.com/en-us/cpp/cpp/property-cpp?view=...
f(String *), así que el código C++ era del estilof(new String("Hello").Si esto te parece interesante, quizá también te guste libcello.h:
https://www.libcello.org
Me gustan los nombres de los tipos, y la elección de macros para funciones integradas como
mines perfecta. También me gustaLen.Los operadores booleanos con nombre quizá sean un poco excesivos, pero vale la pena probarlos; el operador ternario ya de por sí es difícil de leer, así que tiene mucho margen de mejora. No me convencen del todo todas las definiciones de bucles, aunque algunas tienen sentido. El seguimiento de recursos es impresionante, y la forma
for...se ve un poco fea, así que quizá se le podría poner otro nombre.En conjunto, es un intento bastante sólido. Le daría al diseño algo así como 8/10. La forma en que está esbozado con macros de C es realmente elegante y de hecho parece buen código. No sé si lo usaría yo mismo: es un lenguaje nuevo y ya me gusta C. Aun así, la implementación es muy clara, así que puede ayudar a la gente a aprender C y a pensar en el diseño de lenguajes.
len(),max/miny algunas macros de operadores. Es porque todavía no he necesitado muchas de las otras funciones sabrosas. Así que estaría bueno que probaras aunque sea algunas macros de operadores.Si
ifntes paraif(!...), unless me parece más legible queifnt.alwaysal bucle infinitofor(;;).En otros lenguajes he visto
loop. Pero Qt lo llamaforever, y eso es realmente bonito. También es muy Qt.ifntsuena divertido cuando lo dices en voz alta.unlesspara las condiciones ternarias, porque ahí, al fin y al cabo, es más útil.Ah, espera, eres John Tromp. ¡El creador de BLC! Soy fan.