| 1 | #ifndef wren_compiler_h |
| 2 | #define wren_compiler_h |
| 3 | |
| 4 | #include "wren.h" |
| 5 | #include "wren_value.h" |
| 6 | |
| 7 | typedef struct sCompiler Compiler; |
| 8 | |
| 9 | // This module defines the compiler for Wren. It takes a string of source code |
| 10 | // and lexes, parses, and compiles it. Wren uses a single-pass compiler. It |
| 11 | // does not build an actual AST during parsing and then consume that to |
| 12 | // generate code. Instead, the parser directly emits bytecode. |
| 13 | // |
| 14 | // This forces a few restrictions on the grammar and semantics of the language. |
| 15 | // Things like forward references and arbitrary lookahead are much harder. We |
| 16 | // get a lot in return for that, though. |
| 17 | // |
| 18 | // The implementation is much simpler since we don't need to define a bunch of |
| 19 | // AST data structures. More so, we don't have to deal with managing memory for |
| 20 | // AST objects. The compiler does almost no dynamic allocation while running. |
| 21 | // |
| 22 | // Compilation is also faster since we don't create a bunch of temporary data |
| 23 | // structures and destroy them after generating code. |
| 24 | |
| 25 | // Compiles [source], a string of Wren source code located in [module], to an |
| 26 | // [ObjFn] that will execute that code when invoked. Returns `NULL` if the |
| 27 | // source contains any syntax errors. |
| 28 | // |
| 29 | // If [isExpression] is `true`, [source] should be a single expression, and |
| 30 | // this compiles it to a function that evaluates and returns that expression. |
| 31 | // Otherwise, [source] should be a series of top level statements. |
| 32 | // |
| 33 | // If [printErrors] is `true`, any compile errors are output to stderr. |
| 34 | // Otherwise, they are silently discarded. |
| 35 | ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source, |
| 36 | bool isExpression, bool printErrors); |
| 37 | |
| 38 | // When a class is defined, its superclass is not known until runtime since |
| 39 | // class definitions are just imperative statements. Most of the bytecode for a |
| 40 | // a method doesn't care, but there are two places where it matters: |
| 41 | // |
| 42 | // - To load or store a field, we need to know the index of the field in the |
| 43 | // instance's field array. We need to adjust this so that subclass fields |
| 44 | // are positioned after superclass fields, and we don't know this until the |
| 45 | // superclass is known. |
| 46 | // |
| 47 | // - Superclass calls need to know which superclass to dispatch to. |
| 48 | // |
| 49 | // We could handle this dynamically, but that adds overhead. Instead, when a |
| 50 | // method is bound, we walk the bytecode for the function and patch it up. |
| 51 | void wrenBindMethodCode(ObjClass* classObj, ObjFn* fn); |
| 52 | |
| 53 | // Reaches all of the heap-allocated objects in use by [compiler] (and all of |
| 54 | // its parents) so that they are not collected by the GC. |
| 55 | void wrenMarkCompiler(WrenVM* vm, Compiler* compiler); |
| 56 | |
| 57 | #endif |
| 58 | |