From ae665d89ed88431f690a8c6440ff4b2e745f586d Mon Sep 17 00:00:00 2001 From: zongor Date: Sun, 4 May 2025 14:51:38 -0400 Subject: [PATCH] migrate old compiler, hack on that instead --- docs/SPECIFICATION.org | 52 +-- src/chunk.c | 19 +- src/chunk.h | 32 +- src/common.h | 13 +- src/compiler.c | 869 +++++++++++++++++++++++++++++++++++------ src/compiler.h | 8 +- src/debug.c | 155 ++++++-- src/debug.h | 4 +- src/main.c | 20 +- src/memory.c | 237 ++++++++++- src/memory.h | 17 +- src/object.c | 163 ++++++++ src/object.h | 114 ++++++ src/scanner.c | 265 +++++++------ src/scanner.h | 7 +- src/table.c | 151 +++++++ src/table.h | 29 ++ src/value.c | 12 +- src/value.h | 39 +- src/vm.c | 522 +++++++++++++++++++++---- src/vm.h | 39 +- 21 files changed, 2300 insertions(+), 467 deletions(-) create mode 100644 src/object.c create mode 100644 src/object.h create mode 100644 src/table.c create mode 100644 src/table.h diff --git a/docs/SPECIFICATION.org b/docs/SPECIFICATION.org index 345392a..6505828 100644 --- a/docs/SPECIFICATION.org +++ b/docs/SPECIFICATION.org @@ -1,4 +1,4 @@ -* /ztl/ (zongors transpiler language) Design parameters +* /ZTL/ (Zongors Transpiler Language) Design parameters :PROPERTIES: :CUSTOM_ID: ztl-zongors-transpiler-language-design-parameters :END: @@ -12,7 +12,7 @@ systems. /ztl/ also can "run" standalone inside of a lua vm for debugging purposes, it could be used for small scripting tasks or the like. -* /ztl/ Grammar and Specification +* /ZTL/ Grammar and Specification :PROPERTIES: :CUSTOM_ID: ztl-grammar-and-specification :END: @@ -33,7 +33,7 @@ type «token» { } #+end_src ztl -* Substantial Types +* Basic Types :PROPERTIES: :CUSTOM_ID: substantial-types :END: @@ -41,39 +41,9 @@ type «token» { :PROPERTIES: :CUSTOM_ID: numeric :END: -*** bit (or unsigned units) -:PROPERTIES: -:CUSTOM_ID: bit-or-unsigned-units -:END: -- =u8= +- =byte= - unsigned 8 bit integer (uint8_t) -- =u16= - - unsigned 16 bit integer (uint16_t) -- =u32= - - unsigned 32 bit integer (uint32_t) -- =u64= - - unsigned 64 bit integer (uint64_t) - -*** integer (signed) -:PROPERTIES: -:CUSTOM_ID: integer-signed -:END: -- =i8= - - signed 8 bit integer (int8_t) -- =i16= - - signed 16 bit integer (int16_t) -- =i32= - - signed 32 bit integer (int32_t) -- =i64= - - signed 64 bit integer (int64_t) - -*** real -:PROPERTIES: -:CUSTOM_ID: real -:END: -- =f32= - - 32 bit floating point (float) -- =f64= +- =number= - 64 bit floating point (double) ** string @@ -157,8 +127,6 @@ The following is a list of global operators and their effect: - =//= - comment -- =/**/= - - block comment - =??= - unwrap or - =+= @@ -205,14 +173,8 @@ The following is a list of global operators and their effect: :PROPERTIES: :CUSTOM_ID: logical-bitwise-operators :END: -- =eq= - - equal to -- =ne= - - not equals to - =mod= - modulo -- =not= - - logical not - =and= - logical and - =or= @@ -255,10 +217,6 @@ if («token» is i32) { also used for letting constants -#+begin_src ztl -const PURPLE is Color(255, 255, 0); -#+end_src ztl - =as= coerces a type as another type if possible diff --git a/src/chunk.c b/src/chunk.c index 1d86f26..8eddb39 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -1,16 +1,16 @@ -#include - #include "chunk.h" +#include "memory.h" +#include "vm.h" -void newChunk(Chunk* chunk) { +void initChunk(Chunk* chunk) { chunk->count = 0; chunk->capacity = 0; - chunk->code = NULL; chunk->lines = NULL; - newValueArray(&chunk->constants); + chunk->code = NULL; + initValueArray(&chunk->constants); } -void writeChunk(Chunk *chunk, uint8_t byte, int line) { +void writeChunk(Chunk* chunk, uint8_t byte, int line) { if (chunk->capacity < chunk->count + 1) { int oldCapacity = chunk->capacity; chunk->capacity = GROW_CAPACITY(oldCapacity); @@ -25,15 +25,16 @@ void writeChunk(Chunk *chunk, uint8_t byte, int line) { chunk->count++; } -void freeChunk(Chunk *chunk) { +void freeChunk(Chunk* chunk) { FREE_ARRAY(uint8_t, chunk->code, chunk->capacity); - FREE_ARRAY(int, chunk->lines, chunk->capacity); freeValueArray(&chunk->constants); - newChunk(chunk); + initChunk(chunk); } int addConstant(Chunk* chunk, Value value) { + push(value); writeValueArray(&chunk->constants, value); + pop(); return chunk->constants.count - 1; } diff --git a/src/chunk.h b/src/chunk.h index 563a80c..122ea0e 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -1,16 +1,24 @@ -#ifndef ztl_chunk_h -#define ztl_chunk_h +#ifndef zlc_chunk_h +#define zlc_chunk_h #include "common.h" -#include "memory.h" #include "value.h" typedef enum { - OP_NOOP, OP_CONSTANT, OP_NIL, OP_TRUE, OP_FALSE, + OP_POP, + OP_GET_LOCAL, + OP_GET_GLOBAL, + OP_DEFINE_GLOBAL, + OP_SET_LOCAL, + OP_SET_GLOBAL, + OP_GET_UPVALUE, + OP_SET_UPVALUE, + OP_GET_PROPERTY, + OP_SET_PROPERTY, OP_EQUAL, OP_GREATER, OP_LESS, @@ -20,10 +28,20 @@ typedef enum { OP_DIVIDE, OP_NOT, OP_NEGATE, - OP_RETURN, + OP_PRINT, + OP_JUMP, + OP_JUMP_IF_FALSE, + OP_LOOP, + OP_CALL, + OP_INVOKE, + OP_CLOSURE, + OP_CLOSE_UPVALUE, + OP_RETURN, + OP_TYPE, + OP_METHOD } OpCode; -typedef struct Chunk { +typedef struct { int count; int capacity; uint8_t *code; @@ -31,7 +49,7 @@ typedef struct Chunk { ValueArray constants; } Chunk; -void newChunk(Chunk *chunk); +void initChunk(Chunk *chunk); void freeChunk(Chunk *chunk); void writeChunk(Chunk *chunk, uint8_t byte, int line); int addConstant(Chunk *chunk, Value value); diff --git a/src/common.h b/src/common.h index 98d48b6..5368a37 100644 --- a/src/common.h +++ b/src/common.h @@ -1,11 +1,16 @@ -#ifndef ztl_common_h -#define ztl_common_h +#ifndef zlc_common_h +#define zlc_common_h #include #include #include -#define DEBUG_TRACE_EXECUTION -#define DEBUG_PRINT_CODE +/* #define DEBUG_TRACE_EXECUTION */ +/* #define DEBUG_PRINT_CODE */ + +/* #define DEBUG_STRESS_GC */ +/* #define DEBUG_LOG_GC */ + +#define UINT8_COUNT (UINT8_MAX + 1) #endif diff --git a/src/compiler.c b/src/compiler.c index 9416a3e..780ba66 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1,8 +1,10 @@ #include #include +#include #include "common.h" #include "compiler.h" +#include "memory.h" #include "scanner.h" #ifdef DEBUG_PRINT_CODE @@ -18,19 +20,19 @@ typedef struct { typedef enum { PREC_NONE, - PREC_ASSIGNMENT, // = - PREC_OR, // or - PREC_AND, // and - PREC_EQUALITY, // == != - PREC_COMPARISON, // < > <= >= - PREC_TERM, // + - - PREC_FACTOR, // * / - PREC_UNARY, // ! - - PREC_CALL, // . () + PREC_ASSIGNMENT, // = + PREC_OR, // or + PREC_AND, // and + PREC_EQUALITY, // == != + PREC_COMPARISON, // < > <= >= + PREC_TERM, // + - + PREC_FACTOR, // * / + PREC_UNARY, // ! - + PREC_CALL, // . () PREC_PRIMARY } Precedence; -typedef void (*ParseFn)(); +typedef void (*ParseFn)(bool canAssign); typedef struct { ParseFn prefix; @@ -38,15 +40,47 @@ typedef struct { Precedence precedence; } ParseRule; +typedef struct { + Token name; + int depth; + bool isCaptured; +} Local; + +typedef struct { + uint8_t index; + bool isLocal; +} Upvalue; + +typedef enum { + TYPE_FUNCTION, + TYPE_INITIALIZER, + TYPE_METHOD, + TYPE_SCRIPT +} FunctionType; + +typedef struct Compiler { + struct Compiler *enclosing; + ObjFunction *function; + FunctionType type; + Local locals[UINT8_COUNT]; + int localCount; + Upvalue upvalues[UINT8_COUNT]; + int scopeDepth; +} Compiler; + +typedef struct TypeCompiler { + struct TypeCompiler *enclosing; +} TypeCompiler; + Parser parser; -Chunk* compilingChunk; +Compiler *current = NULL; +TypeCompiler *currentType = NULL; -static Chunk* currentChunk() { - return compilingChunk; -} +static Chunk *currentChunk() { return ¤t->function->chunk; } -static void errorAt(Token* token, const char* message) { - if (parser.panicMode) return; +static void errorAt(Token *token, const char *message) { + if (parser.panicMode) + return; parser.panicMode = true; fprintf(stderr, "[line %d] Error", token->line); @@ -62,11 +96,9 @@ static void errorAt(Token* token, const char* message) { parser.hadError = true; } -static void error(const char* message) { - errorAt(&parser.previous, message); -} +static void error(const char *message) { errorAt(&parser.previous, message); } -static void errorAtCurrent(const char* message) { +static void errorAtCurrent(const char *message) { errorAt(&parser.current, message); } @@ -75,13 +107,14 @@ static void advance() { for (;;) { parser.current = scanToken(); - if (parser.current.type != TOKEN_ERROR) break; + if (parser.current.type != TOKEN_ERROR) + break; errorAtCurrent(parser.current.start); } } -static void consume(TokenType type, const char* message) { +static void consume(TokenType type, const char *message) { if (parser.current.type == type) { advance(); return; @@ -90,6 +123,15 @@ static void consume(TokenType type, const char* message) { errorAtCurrent(message); } +static bool check(TokenType type) { return parser.current.type == type; } + +static bool match(TokenType type) { + if (!check(type)) + return false; + advance(); + return true; +} + static void emitByte(uint8_t byte) { writeChunk(currentChunk(), byte, parser.previous.line); } @@ -99,7 +141,31 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) { emitByte(byte2); } +static void emitLoop(int loopStart) { + emitByte(OP_LOOP); + + int offset = currentChunk()->count - loopStart + 2; + if (offset > UINT16_MAX) + error("Loop body too large."); + + emitByte((offset >> 8) & 0xff); + emitByte(offset & 0xff); +} + +static int emitJump(uint8_t instruction) { + emitByte(instruction); + emitByte(0xff); + emitByte(0xff); + return currentChunk()->count - 2; +} + static void emitReturn() { + if (current->type == TYPE_INITIALIZER) { + emitBytes(OP_GET_LOCAL, 0); + } else { + emitByte(OP_NIL); + } + emitByte(OP_RETURN); } @@ -117,63 +183,628 @@ static void emitConstant(Value value) { emitBytes(OP_CONSTANT, makeConstant(value)); } -static void endCompiler() { +static void patchJump(int offset) { + // -2 to adjust for the bytecode for the jump offset itself. + int jump = currentChunk()->count - offset - 2; + + if (jump > UINT16_MAX) { + error("Too much code to jump over."); + } + + currentChunk()->code[offset] = (jump >> 8) & 0xff; + currentChunk()->code[offset + 1] = jump & 0xff; +} + +static void initCompiler(Compiler *compiler, FunctionType type) { + compiler->enclosing = current; + compiler->function = NULL; + compiler->type = type; + compiler->localCount = 0; + compiler->scopeDepth = 0; + compiler->function = newFunction(); + current = compiler; + if (type != TYPE_SCRIPT) { + current->function->name = + copyString(parser.previous.start, parser.previous.length); + } + + Local *local = ¤t->locals[current->localCount++]; + local->depth = 0; + local->isCaptured = false; + if (type != TYPE_FUNCTION) { + local->name.start = "this"; + local->name.length = 4; + } else { + local->name.start = ""; + local->name.length = 0; + } +} + +static ObjFunction *endCompiler() { emitReturn(); + ObjFunction *function = current->function; + #ifdef DEBUG_PRINT_CODE if (!parser.hadError) { - disassembleChunk(currentChunk(), "code"); + disassembleChunk(currentChunk(), function->name != NULL + ? function->name->chars + : "