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' catchGestion 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.