Pretty C est un nouveau langage de script compatible avec C. Pretty C améliore vos programmes avec un typage dynamique, une itération générique, un suivi des ressources et d'autres subtilités. Et il est rétrocompatible avec C et toutes ses bibliothèques ! Inspiré de Lua, Python, JavaScript et Lisp. Voici à quoi pourrait ressembler une réimplémentation naïve de l’utilitaire head
avec 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 ;
}
Les objectifs de Pretty C sont :
#include
-capable à partir d'un fichier C arbitraire !) pour transformer n'importe quelle base de code en une base conviviale pour les débutants.Extraire le référentiel
git clone https://github.com/aartaka/pretty.c
Ou copiez simplement le fichier pretty.h
: Pretty C est une bibliothèque contenant uniquement des en-têtes, vous pouvez donc
#include "pretty.h"
à partir de n'importe quel fichier du répertoire dans lequel vous déposez pretty.h
. Ou à partir de n'importe quel fichier, si vous spécifiez le chemin d'accès à Pretty C comme chemin d'inclusion ( -I
).
Voici tous les jolis changements qui rendent C à nouveau branché.
true
, false
et bool
.uint64_t
.and
pour &&
et or
pour ||
. Soigné! Tout le monde les définit, alors pourquoi ne pas les fournir ?
max
et min
de deux nombres.len
pour la longueur du tableau.default
pour fournir une valeur de repli.limit
pour garantir une plage de valeurs appropriée.between
pour vérifier si le nombre se situe dans une plage.divisible
pour vérifier si un nombre est modulo divisible par un autre nombre. Tapez les alias :
string
== char*
.byte
== char
.bytes
== char*
.any
== void*
.uchar
.ushort
.uint
.ulong
. Principalement calqué sur Lua et Lisp :
eq
, car iso646.h
n'a que not_eq
.is
signifie ==
aussi.bitnot
et bitxor
pour les opérations qui étaient appelées de manière incohérente ( respectivement compl
et xor
) dans iso646.h
.success
et fail
/ failure
pour le modèle de success == 0
.below
, above
, upto
et downto
.even
, odd
, positive
, negative
, zero
et empty
comme prédicats pour les nombres/données.nil
pour NULL
.until
ce que while
annulé.elif
pour else if
.ifnt
pour if(!...)
et elifnt
(vous l'avez deviné.)repeat
depuis Lua comme alias pour do
.done~/~finish
et pass
comme alias pour break
et continue
, respectivement.always
, forever
, loop
et indefinitely
pour que vous puissiez créer des boucles infinies (événement ? serveur ?) always println ( "After all this time?" );
never
comment
pour commenter du code avec un seul mot-clé, tout en permettant au compilateur de l'analyser/de l'optimiser (similaire au formulaire comment
Clojure) : never println ( "This never runs, but never gets outdated, because compiler will shout at you if it does." );
Oui, tu peux le faire
var t = time ( 0 );
let lt = localtime ( & t );
local at = asctime ( lt );
println ( at );
Avec Jolie C.
print
imprime tout ce que vous lui donnez. println
ajoute une nouvelle ligne après.
println ( 3.1 );
print ( "Hello world!n" );
Comparez tout !
equal ( "NA" , line ); // true
equal ( 0.3 , 0.2 + 0.1 ); // true
Les ternaires sont effrayants, donc cela ne fera pas de mal d'ajouter du texte brut. if
et else
sont pris, mais il existe des alternatives linguistiques appropriées qui ressemblent assez à Python/Lisp :
return when some_condition
then do_something ()
other do_something_else ();
C'est des ternaires en dessous :
when
se développe en chaîne vide et n'est fourni que pour des raisons de lisibilité.unless
ne s'étende pour not
être une version négative de when
.then
s'étend à ?
.other
/ otherwise
se développe en :
. Il n'y a également only
lorsque la clause otherwise
n'est pas nécessaire :
return when done ()
then 42 only ;
et otherwhen
pour la condition suivante
return when c is 'A'
then 'a'
otherwhen c is 'B'
then 'b' only ;
for
les macros Ces macros sont des alias pour certains modèles for
, chacun faisant abstraction de certaines des utilisations fréquentes for
la boucle for.
foreach (var, type, length, ...)
Celui-ci parcourt un tableau ou une région mémoire initialisé à l'expression vararg. Chaque fois qu'il itère, var
est défini sur un pointeur vers l'élément de tableau respectif. Oui, pointeur, afin que vous puissiez modifier l'élément en place si nécessaire.
foreach ( i , int , 10 , vector ( 10 , int , 1 , 2 , 3 , 3 , 4 , 5 ))
println ( * i );
Montre également l'utilisation du vector
.
forthese (var, type, ...)
Parcourt les varargs fournis, liant chacun d'eux au type
-d var
. La boucle ci-dessus peut être traduite par :
forthese ( i , int , 1 , 2 , 3 , 3 , 4 , 5 )
println ( i );
fortimes (var, times)
Cas fréquent de passage de 0 à un nombre positif. Vous fait gagner beaucoup de temps pour votre
for ( int i = 0 ; i < 28 ; i ++ )
println ( i + 1 );
le transformer 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)
Parcourez une plage de nombres de init
à target
. Pythonesque. Voici la boucle de conversion Celsius en Fahrenheit avec forrange
:
forrange ( c , -10 , 20 )
printf ( "Celsius %i = Fahrenheit %fn" , c , ( 32 + ( c * 1.8 )));
Notez que init
et target
sont des entiers arbitraires, signés et non signés. Et init
peut être supérieur à target
, auquel cas l'étape d'itération diminue la variable.
forrangeby (var, type, init, target, by)
Itérer type
-d var
de iter
à target
, en passant by
chaque fois. Pythonesque.
forrangeby ( x , double , 1.0 , 10.0 , 0.5 )
println ( x );
Ceux-ci permettent une allocation rapide et sale pour les modèles typiques. Principalement calqué sur le C++.
new (type, ...)
new
opérateur C++ est sympa, donc ça ne fera pas de mal d'avoir quelque chose de similaire en C, n'est-ce pas ? Ne demandez plus :
struct ListNode {
int val ;
struct ListNode * next ;
};
struct ListNode * node = new ( struct ListNode , 2 , new ( struct ListNode , 1 , nil ));
Ou, si vous le souhaitez, vous pouvez ajouter encore plus de syntaxe :
#define cons ( val , ...) new(struct ListNode, val, __VA_ARGS__)
cons ( 2 , cons ( 1 , nil ));
vector (length, type, ...)
Encore du C++. std::vector
est une structure de données extrêmement utile et polyvalente sur laquelle il est facile de raisonner. Bien que cette macro ne soit pas aussi fonctionnelle que son homologue C++, elle simplifie un modèle fréquent consistant à « allouer un tableau d'autant d'éléments et avec ce contenu » :
double * vec = vector ( 10 , double , 1 , 2 , 3 , 4 , 5 );
delete (...)
Si vous n'aimez pas free
les ressources et préférez un nom C++ plus sophistiqué.
Sinon, c'est pareil que free
.
Ceux-ci établissent de nouvelles liaisons locales, assurent des calculs différés ou agissent d'une autre manière sur le bloc qui les suit.
lambda (ret, name, ...)
(GCC, Clang ou C++)Fonctions/lambdas/fermetures imbriquées, maintenant 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, ...)
Cela garantit que vous n'aurez jamais d'utilisation après libération, car vous fournissez la procédure de libération ( close
) dès le départ. Particulièrement utile pour les objets alloués dynamiquement et les désignateurs de fichiers.
with ( file , fclose , fopen ( "hello.txt" , "w" ))
fprintf ( file , "Hello world!n" );
L'un des inconvénients est que le var
lié est un void *
, vous devrez donc peut-être le contraindre à votre type avant de l'utiliser.
defer (...)
Décharge le code à exécuter après le bloc suivant. Pas en fin de fonction comme dans Go, car c'est impossible difficile à implémenter en C. Pourtant, Pretty C defer
est assez utile.
try
d' catch
Gestion des erreurs sophistiquée, maintenant en C. Exemple refactorisé à partir de la référence errno :
try log ( 0.0 );
catch ( NOERR )
println ( "No error." );
catch ( EDOM , ERANGE )
println ( "Math error!" );
NOERR
et NOERROR
sont également fournis par Pretty C, pour faciliter le boîtier de commutation d'erreur.
make indent
avant de valider, cela devrait gérer la plupart des détails de style.