diff options
author | Matthew Sotoudeh <matthew@masot.net> | 2024-03-22 23:48:16 -0400 |
---|---|---|
committer | Matthew Sotoudeh <matthew@masot.net> | 2024-03-22 23:48:16 -0400 |
commit | 61a87d12aebbcbd0b70eaa9cb0244b2faf989c91 (patch) | |
tree | 7f0043372efeab40691c152bb47cb4b88ae75fda | |
parent | 2043ff5746e0df3b2be6ff6bcf712901daa8f5e6 (diff) |
improve readmes
-rw-r--r-- | README.txt | 108 | ||||
-rw-r--r-- | c_version/README.txt | 13 | ||||
-rw-r--r-- | gamma_version/README.txt | 20 |
3 files changed, 127 insertions, 14 deletions
@@ -1 +1,109 @@ ####### Gamma: Backwards-Compatible Templates for C ####### +Gamma is a C preprocessor designed to make simple templated data structures +ergonomic in C. + +It was designed by Akshay, Matthew, and Zach. + +####### Selling Points ####### +Selling points include: + + - It aims to be fully backwards compatible: + + * Gamma is designed to be a strict superset of C, never breaking + currently working C code. + + * Simply add CC=gc gcc and LD=gc gcc to your Makefile and everything + will work, including object files, static libraries, etc. + + * If you have a GCC-compatible toolchain for your target architecture, + you can immediately wrap it in Gamma and everything works. + + * Slowdown on sequential C builds (no templates) is only about 30%. + + - Template definitions can be in .c files just like normal C function + definitions; only declarations need to be placed in header files. + + - Specialization and partial specialization is supported. + + - The implementation is simple, easy to hack on, and easy to understand. It + is arguably simpler than CPP. + + - The implementation relies on almost no knowledge about the C grammar + except for a lightweight, best-effort lexing pass. This makes it + relatively easy to port as a preprocessor for other languages, e.g., + Hare. + +####### Code Samples ####### + +> uint32_t vector_push::[type T](struct vector::[T] *vector, T item) { +> if ((2 * vector->count) >= vector->cap) { +> vector->cap *= 4; +> vector->cap = vector->cap ? vector->cap : 128; +> vector->data = realloc(vector->data, vector->cap * sizeof(vector->data[0])); +> } +> vector->data[vector->count++] = item; +> } +> +> T vector_pop::[type T](struct vector::[T] *vector) { +> return vector->data[--(vector->count)]; +> } +> +> struct vector::[T] *vector_init::[type T]() { +> return calloc(1, sizeof(struct vector::[T])); +> } + +####### Versions & Self-Hosting ####### +There are three versions: + + - `py_version` is written in Python and is the oldest & slowest. It does + not support the latest syntax features. It's designed to infer template + locations, so you can write just "foo[T]" instead of, say, "foo![T]". + + - `c_version` is written in C and supports all the current features. + + - `gamma_version` is written in Gamma and supports all the current + features. It's also faster for projects with many templates. + +The Gamma-in-Gamma version requires an existing Gamma compiler. It is currently +set up to use the result of the C version, hence you must build like so: + + gamma $ make -C c_version + gamma $ make -C gamma_version + +####### How it Works ####### +------- The Preprocessor +The code is lexed and broken up into 'chunks;' each chunk is meant to represent +one top-level C statement (i.e., a variable/function/type +declaration/definition). Specifically, chunks are matched greedily and end once +a top-level '}' or '}\s*;' is read. + +Any sequence of the form "ident::[...]" is interpreted as a template call. + +The last template call on the outer nesting level of a chunk is its _defining +call_ and is used as the template pattern for that chunk. + +Type variables in the defining call are indicated by the prefix "type "; all +other arguments in a defining call are assumed to be concrete types. + +After collecting all chunks and their calls, we solve to determine all the +concrete template instantiations that will be needed. + +Then, the file is printed out with each template duplicated once for each +instantiation needed. Type variables are replaced by their concrete +instantiations and the template call syntax is mangled. + +------- The Compiler Wrapper +When the -c flag is used, i.e., an intermediate object file compilation is +requested, we first check if the file uses templates. If not, we build the +object file as normal. If so, we store the preprocessed source code and the +compile flags used in a custom '.o' file format. + +At link time, we read all the '.o's in our custom format and consider template +instantiations needed by, and definitions provided by, all of them. + +Currently this sequentializes the compilation of Gamma files (but not pure-C +files). In theory only the fixedpoint stage needs to be sequentialized; we are +interested in improving this in the future. + +####### Security ####### +Don't compile object files with an untrusted source through Gamma. diff --git a/c_version/README.txt b/c_version/README.txt index 9ff18da..d836bb6 100644 --- a/c_version/README.txt +++ b/c_version/README.txt @@ -4,19 +4,18 @@ Why? Zach wanted a self-hostable version -Differences? +Differences to the Python version? It uses a slightly different approach to picking up chunks + templates - Specifically, you're now *forced* to use "foo![...]" for templates + Specifically, you're now *forced* to use "foo![...]" or "foo::[...]" for + templates On the plus side, this means you can have templated arrays and typedefs - Static libraries (.a's) don't work yet - How to use? - gamma/self-hosted $ make -B - gamma/self-hosted $ ./build/gc gcc examples/hashmap.c - gamma/self-hosted $ ./a.out + gamma/c_version $ make -B + gamma/c_version $ ./build/gc gcc examples/hashmap.c + gamma/c_version $ ./a.out ... diff --git a/gamma_version/README.txt b/gamma_version/README.txt index 9ff18da..348c9ff 100644 --- a/gamma_version/README.txt +++ b/gamma_version/README.txt @@ -1,22 +1,28 @@ -====== Gamma-C, in C ====== +====== Gamma-C, in Gamma ====== Why? Zach wanted a self-hostable version -Differences? +Differences to the Python version? It uses a slightly different approach to picking up chunks + templates - Specifically, you're now *forced* to use "foo![...]" for templates + Specifically, you're now *forced* to use "foo![...]" or "foo::[...]" for + templates On the plus side, this means you can have templated arrays and typedefs - Static libraries (.a's) don't work yet +Differences to the C version? + + Because data structures become so simple, we're using a significantly more + efficient fixedpoint engine (i.e., a work queue instead of 'loop over + everything every iteration'). So, if you're compiling a project with many + templates, Gamma-in-Gamma is the way to go! How to use? - gamma/self-hosted $ make -B - gamma/self-hosted $ ./build/gc gcc examples/hashmap.c - gamma/self-hosted $ ./a.out + gamma/gamma_version $ make -B + gamma/gamma_version $ ./build/gc gcc examples/hashmap.c + gamma/gamma_version $ ./a.out ... |