https://github.com/aartaka/pretty.c Skip to content Navigation Menu Toggle navigation Sign in * Product + GitHub Copilot Write better code with AI + Security Find and fix vulnerabilities + Actions Automate any workflow + Codespaces Instant dev environments + Issues Plan and track work + Code Review Manage code changes + Discussions Collaborate outside of code + Code Search Find more, search less Explore + All features + Documentation + GitHub Skills + Blog * Solutions By company size + Enterprises + Small and medium teams + Startups By use case + DevSecOps + DevOps + CI/CD + View all use cases By industry + Healthcare + Financial services + Manufacturing + Government + View all industries View all solutions * Resources Topics + AI + DevOps + Security + Software Development + View all Explore + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Enterprise + Enterprise platform AI-powered developer platform Available add-ons + Advanced Security Enterprise-grade security features + GitHub Copilot Enterprise-grade AI features + Premium Support Enterprise-grade 24/7 support * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up Reseting focus You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} aartaka / pretty.c Public * Notifications You must be signed in to change notification settings * Fork 7 * Star 390 Making C Look Prettyand Lua/Lisp/Python-esque License WTFPL license 390 stars 7 forks Branches Tags Activity Star Notifications You must be signed in to change notification settings * Code * Issues 1 * Pull requests 0 * Actions * Projects 0 * Security * Insights Additional navigation options * Code * Issues * Pull requests * Actions * Projects * Security * Insights aartaka/pretty.c master BranchesTags Go to file Code Folders and files Name Name Last commit message Last commit date Latest commit History 345 Commits LICENSE LICENSE README.org README.org pretty.h pretty.h View all files Repository files navigation * README * WTFPL license Pretty C: Pretty Scripting on Top of C Pretty C is a new scripting language compatible with C. Pretty C boosts your programs with dynamic typing, generic iteration, resource tracking and other niceties. And it's backwards-compatible with C and all of its libraries! Inspired by Lua, Python, JavaScript, and Lisp. Here's how a naive re-implementation of head utility might look like with 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; } The goals for Pretty C are: * Provide so much syntactic sugar as to cause any C developer a diabetes-induced heart attack. * Deprecate Lua, Python, JavaScript, Ruby and a dozen other languages, because Pretty C is the ultimate scripting language, but lightning-fast and strongly typed! * Including only one header (yes, Pretty C is a header-only library #include-able from arbitrary C file!) to turn any codebase into a beginner friendly one. Getting Started Checkout the repository git clone https://github.com/aartaka/pretty.c Or simply copy the pretty.h file--Pretty C is a header-only library, so you can #include "pretty.h" from any file in the directory you drop pretty.h to. Or from any file really, if you specify the path to Pretty C as an include (-I) path. Provided Conveniences Here are all the pretty changes making C hip again. Included Standard Headers * stdbool.h for pretty booleans: true, false, and bool. * stdint.h for fixed-width integer types like uint64_t. * iso646.h for readable alternatives to regular operators, including and for && and or for ||. Neat! Simple macros Everyone defines these, so why not provide them? * max and min of two numbers. * len for array length. * default for providing a fallback value. * limit to ensure proper value range. * between to check whether the number falls in a range. * divisible to check whether a number is modulo divisible by another number. New types Type aliases: * string == char*. * byte == char. * bytes == char*. * any == void*. * Integer shortcuts: + uchar. + ushort. + uint. + ulong. New aliases Mainly modeled after Lua and Lisp: * eq, because iso646.h only has not_eq. + is means == too. * bitnot and bitxor for operations that used to be called inconsistently (compl and xor respectively) in iso646.h. * below, above, upto, and downto comparison operators. * even, odd, positive, negative, zero, and empty as predicates for numbers/data. * nil for NULL. * until for negated while. * elif for else if. * ifnt for if(!...). * repeat from Lua as an alias for do. * done~/~finish and pass as aliases for break and continue, respectively. * always, forever, loop, and indefinitely so that you can make infinite (event? server?) loops always println("After all this time?"); * and never and comment to comment out some code with just one keyword, while still allowing the compiler to analyze/optimize it (similar to Clojure comment form): never println("This never runs, but never gets outdated, because compiler will shout at you if it does."); Type inference (GCC, Clang, or C23+) Yes, you can do var t = time(0); let lt = localtime(&t); local at = asctime(lt); println(at); With Pretty C. Generic printing (C11+) print prints whatever you feed it. println adds a newline after it. println(3.1); print("Hello world!\n"); Generic equality (C11+) Compare all the things! equal("NA", line); // true equal(0.3, 0.2 + 0.1); // true Pretty ternaries Ternaries are frightening, so it won't hurt to add some plain text. if and else are taken, but there are proper linguistic alternatives that look quite Python/Lisp-like: return when some_condition then do_something() other do_something_else(); It's ternaries underneath: * when expands to empty string and is only provided for readability. + unless expands to not to be a negative version of when. * then expands to ?. * other / otherwise expands to :. There's also only for when the otherwise clause is unnecessary: return when done() then 42 only; and otherwhen for the next condition return when c is 'A' then 'a' otherwhen c is 'B' then 'b' only; for Macros These macros are aliases for certain for loop pattern, each abstracting away some of the frequent for loop uses. foreach (var, type, length, ...) This one walks an array or memory region initialized to the vararg expression. Every time it iterates, var is set to a pointer to the respective array element. Yes, pointer--so that you can modify the element in place if you have to. foreach (i, int, 10, vector(10, int, 1, 2, 3, 3, 4, 5)) println(*i); Also shows the use of vector. forthese (var, type, ...) Iterates over the provided varargs, binding each of these to type-d var. The loop above can be translated as: forthese (i, int, 1, 2, 3, 3, 4, 5) println(i); fortimes (var, times) A frequent case of going from 0 to some positive number. Saves you quite some time for your for (int i = 0; i < 28; i++) println(i+1); turning it into a 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) Iterate over a range of numbers from init to target. Pythonesque. Here's Celsius to Fahrenheit conversion loop with forrange: forrange (c, -10, 20) printf("Celsius %i = Fahrenheit %f\n", c, (32 + (c * 1.8))); Note that init and target are arbitrary integers, signed and unsigned. And init might be greater than target in which case the iteration step decreases the variable. forrangeby (var, type, init, target, by) Iterate type-d var from iter to target, stepping by by every time. Pythonesque. forrangeby (x, double, 1.0, 10.0, 0.5) println(x); Allocation macros These allow quick-and-dirty allocation for typical patterns. Mostly modeled after C++. new (type, ...) C++ new operator is nice, so it won't hurt having something similar in C, right? Ask no more: struct ListNode { int val; struct ListNode *next; }; struct ListNode *node = new(struct ListNode, 2, new(struct ListNode, 1, nil)); Or, if you fancy, you can add even more syntax on top: #define cons(val, ...) new(struct ListNode, val, __VA_ARGS__) cons(2, cons(1, nil)); vector (length, type, ...) C++ again. std::vector is an extremely useful and versatile data structure that's easy to reason about. While this macro is not even remotely as featureful as C++ counterpart, it simplifies a frequent pattern of "allocate an array of that much elements and with these contents": double *vec = vector(10, double, 1, 2, 3, 4, 5); delete (...) In case you don't like free-ing the resources and prefer a fancier C++ name. Otherwise the same as free. Block utilities These establish new local bindings, ensure deferred computations, or otherwise act on the block after them. lambda (ret, name, ...) (GCC, Clang, or C++) Nested functions/lambdas/closures, now in 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, ...) This ensures that you never have use-after-free, because you provide the freeing procedure (close) upfront. Especially useful for dynamically allocated objects and file designators. with (file, fclose, fopen("hello.txt", "w")) fprintf(file, "Hello world!\n"); One of the downsides is that the bound var is a void *, so you might need to coerce it to your type before using it. defer (...) Offloads the code to be executed after the following block. Not at the end of function as in Go, because that's [DEL:impossible:DEL] hard to implement in C. Still, Pretty C defer is useful enough. try,, and catch Fancy error handling, now in C. Refactored example from errno reference: try log(0.0); catch (NOERR) println("No error."); catch (EDOM, ERANGE) println("Math error!"); NOERR and NOERROR are also provided by Pretty C, for convenience of error switch-casing. About Making C Look Prettyand Lua/Lisp/Python-esque Resources Readme License WTFPL license Activity Stars 390 stars Watchers 3 watching Forks 7 forks Report repository Releases No releases published Packages 0 No packages published Languages * C 100.0% Footer (c) 2024 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact * Manage cookies * Do not share my personal information You can't perform that action at this time.