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 | |