58 lines
2.6 KiB
C
58 lines
2.6 KiB
C
#ifndef wren_compiler_h
|
|
#define wren_compiler_h
|
|
|
|
#include "wren.h"
|
|
#include "wren_value.h"
|
|
|
|
typedef struct sCompiler Compiler;
|
|
|
|
// This module defines the compiler for Wren. It takes a string of source code
|
|
// and lexes, parses, and compiles it. Wren uses a single-pass compiler. It
|
|
// does not build an actual AST during parsing and then consume that to
|
|
// generate code. Instead, the parser directly emits bytecode.
|
|
//
|
|
// This forces a few restrictions on the grammar and semantics of the language.
|
|
// Things like forward references and arbitrary lookahead are much harder. We
|
|
// get a lot in return for that, though.
|
|
//
|
|
// The implementation is much simpler since we don't need to define a bunch of
|
|
// AST data structures. More so, we don't have to deal with managing memory for
|
|
// AST objects. The compiler does almost no dynamic allocation while running.
|
|
//
|
|
// Compilation is also faster since we don't create a bunch of temporary data
|
|
// structures and destroy them after generating code.
|
|
|
|
// Compiles [source], a string of Wren source code located in [module], to an
|
|
// [ObjFn] that will execute that code when invoked. Returns `NULL` if the
|
|
// source contains any syntax errors.
|
|
//
|
|
// If [isExpression] is `true`, [source] should be a single expression, and
|
|
// this compiles it to a function that evaluates and returns that expression.
|
|
// Otherwise, [source] should be a series of top level statements.
|
|
//
|
|
// If [printErrors] is `true`, any compile errors are output to stderr.
|
|
// Otherwise, they are silently discarded.
|
|
ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
|
|
bool isExpression, bool printErrors);
|
|
|
|
// When a class is defined, its superclass is not known until runtime since
|
|
// class definitions are just imperative statements. Most of the bytecode for a
|
|
// a method doesn't care, but there are two places where it matters:
|
|
//
|
|
// - To load or store a field, we need to know the index of the field in the
|
|
// instance's field array. We need to adjust this so that subclass fields
|
|
// are positioned after superclass fields, and we don't know this until the
|
|
// superclass is known.
|
|
//
|
|
// - Superclass calls need to know which superclass to dispatch to.
|
|
//
|
|
// We could handle this dynamically, but that adds overhead. Instead, when a
|
|
// method is bound, we walk the bytecode for the function and patch it up.
|
|
void wrenBindMethodCode(ObjClass* classObj, ObjFn* fn);
|
|
|
|
// Reaches all of the heap-allocated objects in use by [compiler] (and all of
|
|
// its parents) so that they are not collected by the GC.
|
|
void wrenMarkCompiler(WrenVM* vm, Compiler* compiler);
|
|
|
|
#endif
|