A C-like programming language developed with ANTLR, LLVM, and C#
Re:C utilizes modern C# (version 14) as well as ANTLR4 (to generate the language's parser) and bindings LLVM (for low-level assembly and compilation). Furthermore, the codebase follows various modern programming conventions not typically found in C#, like explicit null handling and algebriac data types.
To maintain organization, the codebase is split up into many folders, each corresponding to a namespace.
All code within this project will be defined in the namespace Re.C, typically within subnamespaces that more narrowly classify the types. Folders within the Core folder should contain all code within the identically named sub-namespace of Re.C, and others the identically named sub-namespace including the name of the containing folder.
Below is a list of the most important namespaces within core and what they hold:
Re.C.Vocabularydefines general-purpose types and functionality for use throughout the codebase. This namespace is automatically imported viaGlobalUsings.csRe.C.Antlrholds the.g4grammar file used to generate the language's parser, as well as any utility code associated with that parser.Re.C.Antlr.Generatedholds the code generated by Antlr. It should remain.gitignored and is populated automatically by the providedbuild_antlr.batfile.
Re.C.Typesholds all definitions of types in the Re:C languageRe.C.Definitionsdefines all base types related to scoping and definitions within a Re:C compilationRe.C.Syntaxholds everything relating to the bound syntax tree that the compiler generates when type-checkingRe.C.Passesdefines the passes of the compiler via classesRe.C.Visitordefines a visitor protocol through interfaces and extension methods
In general, the Re:C codebase is written with the intent to remain extensible and efficient. For this reason, there are many layers of abstraction within the codebase. When creating such a layer of abstraction, it is critical that core classes are well documented. Should an API decision be far-reaching or abnormal, a small markdown file explaining the decision should be included in the relevant namespace (see Passes.md).
Furthermore, code in this codebase should generally strive to remain consistent. This can be achieved by adhering to the following guidelines:
- Prefer generalizeable methodology when applicable; if you see yourself needing to perform a task multiple times, attempt to create an ergonomic API for it.
- Minimize allocations where possible; when it is feasible, try to implement your functions such that they do not allocate new memory. See the implementation of
Visitorfor an example of this. - Prefer using modern features over boilerplate when available; use primary constructors over single-constructor classes, records over explicit definitions of equality for dataclasses, and extension blocks over extension methods when possible.
- Use partial classes when defining a large class, such as a visitor.