implement bytecode interpreter and compiler

This commit is contained in:
Lobo 2026-01-13 17:45:29 -03:00
parent d23a9a4827
commit c63c1eaf6e
19 changed files with 1055 additions and 547 deletions

View file

@ -14,6 +14,7 @@ typedef intptr_t I;
typedef uintptr_t U;
typedef char C;
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef int32_t I32;
typedef size_t Z;
@ -26,7 +27,7 @@ typedef U O;
#define NUM(x) (((O)((I)(x) << 1)) | (O)1)
#define ORD(x) ((I)(x) >> 1)
// Pair
// Cons pair
typedef struct Pa {
O head, tail;
} Pa;
@ -48,11 +49,21 @@ typedef struct Cl {
O args, body, env;
} Cl;
// Bytecode
typedef struct Bc {
Z len;
U8 *data;
Z constant_count;
O *constants;
} Bc;
// Primitive
typedef struct In In;
typedef struct Pr {
const char *name;
O (*fn)(In *, O, O);
O (*fn)(In *, O *, int, O); // fn(interp, args_array, argc, env)
int min_args; // Minimum number of arguments (-1 for no check)
int max_args; // Maximum number of arguments (-1 for variadic)
} Pr;
// Symbol table
@ -62,7 +73,7 @@ typedef struct St {
Sy **data;
} St;
#define HEAP_BYTES (1024 * 1024)
#define HEAP_BYTES (4 * 1024 * 1024)
#define TYPE_MASK 7
enum {
@ -81,6 +92,7 @@ enum {
TYPE_STR,
TYPE_CLOS,
TYPE_MAC,
TYPE_CODE,
TYPE_FWD,
TYPE__MAX,
};
@ -125,6 +137,14 @@ typedef struct Er {
} stack;
} Er;
// Call frame
typedef struct Fr {
U8 *ip;
O env;
} Fr;
#define VM_STACK_SIZE 4096
// Interpreter context
typedef struct In {
Gc gc;
@ -132,8 +152,64 @@ typedef struct In {
O env;
Er err;
O t; // the T symbol
O stack[VM_STACK_SIZE];
O *sp;
} In;
// Opcodes
enum {
OP_HALT,
OP_CONST,
OP_GET,
OP_SET,
OP_JUMP,
OP_JUMP_IF_NIL,
OP_CALL,
OP_RET,
OP_POP,
OP_CLOS,
OP_TAIL_CALL,
OP_BIND,
OP_BIND_REST,
OP_PEEK,
OP_GET_LOCAL, // Get local variable from stack frame
OP_SET_LOCAL, // Set local variable in stack frame
OP_RESERVE, // Reserve space for local variables
};
// Local variable info
typedef struct Lv {
O name; // Symbol name
U16 index; // Stack slot index
int captured; // Is this variable captured by a closure?
} Lv;
// Compiler context
typedef struct Cm {
In *in;
U8 *code;
Z count;
Z capacity;
struct {
O *data;
Z count;
Z capacity;
} constants;
struct {
O quote;
O iff;
O fn;
O progn;
O def;
} specials;
struct {
Lv *data;
Z count;
Z capacity;
} locals;
int use_stack_locals; // Use stack-based locals instead of env
} Cm;
enum {
TOK_EOF = 0,
TOK_COMMENT = ';',
@ -180,8 +256,6 @@ V gc_finalize(Gc *gc);
void error_init(Er *err);
void error_throw(In *in, const char *fmt, ...);
void error_push_frame(In *in, const char *frame);
void error_pop_frame(In *in);
void error_print(In *in);
// Initialize an interpreter context.
@ -189,12 +263,6 @@ V interp_init(In *in);
// Finalize an interpreter context.
V interp_finalize(In *in);
// Evaluate a list of values.
O interp_eval_list(In *in, O list, O env);
// Evaluate an expression.
O interp_eval(In *in, O obj, O env);
// Intern a string
Sy *intern(St *tab, const char *str, Z len);
@ -209,10 +277,15 @@ V print(O obj);
V println(O obj);
O symbol_make(In *in, const char *str);
O prim_make(In *in, const char *name, O (*fn)(In *, O, O));
O prim_make(In *in, const char *name, O (*fn)(In *, O *, int, O), int min_args, int max_args);
O list_assoc(In *in, O key, O alist);
O list_reverse(In *in, O list);
O list_next(In *in, O *list);
V compile(Cm *co, O expr, I toplevel);
V disassemble(Cm *co);
O vm_run(Cm *c);
int nexttoken(Lx *lex);