From fccc7f25b511a4990cdd308caed545a144832103 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sun, 12 Feb 2017 15:16:55 -0500 Subject: [PATCH] Make some changes and begin work on macros. --- compile.c | 212 ++++++++++++++++++++---------------- compile.h | 6 ++ datatypes.h | 3 +- main.c | 161 ++++++++++++++-------------- parse.c | 24 ++--- value.c | 42 ++++---- vm.c | 304 +++++++++++++++++++++++++++------------------------- vm.h | 11 +- 8 files changed, 400 insertions(+), 363 deletions(-) diff --git a/compile.c b/compile.c index 92eaa5b3..1bc9b9da 100644 --- a/compile.c +++ b/compile.c @@ -96,8 +96,8 @@ BufferDefine(Int16, int16_t); /* If there is an error during compilation, * jump back to start */ static void CError(Compiler * c, const char * e) { - c->error = e; - longjmp(c->onError, 1); + c->error = e; + longjmp(c->onError, 1); } /* Push a new scope in the compiler and return @@ -117,11 +117,11 @@ static Scope * CompilerPushScope(Compiler * c, int sameFunction) { c->tail->nextScope = scope; scope->level = c->tail->level + (sameFunction ? 0 : 1); } else { - scope->level = 0; + scope->level = 0; } if (sameFunction) { if (!c->tail) { - CError(c, "Cannot inherit scope when root scope"); + CError(c, "Cannot inherit scope when root scope"); } scope->nextLocal = c->tail->nextLocal; scope->literals = c->tail->literals; @@ -144,17 +144,17 @@ static void CompilerPopScope(Compiler * c) { CError(c, "No scope to pop."); } else { if (last->nextLocal > last->frameSize) { - last->frameSize = last->nextLocal; + last->frameSize = last->nextLocal; } c->tail = last->previousScope; if (c->tail) { if (last->frameSize > c->tail->frameSize) { - c->tail->frameSize = last->frameSize; + c->tail->frameSize = last->frameSize; } c->tail->nextScope = NULL; } else { /* We deleted the last scope */ - c->root = NULL; + c->root = NULL; } } } @@ -227,39 +227,39 @@ static Slot CompilerReturn(Compiler * c, Slot slot) { /* Gets a temporary slot for the bottom-most scope. */ static Slot CompilerGetTemp(Compiler * c) { - Scope * scope = c->tail; - Slot ret; - ret.isTemp = 1; - ret.isNil = 0; - ret.hasReturned = 0; - ret.index = CompilerGetLocal(c, scope); - return ret; + Scope * scope = c->tail; + Slot ret; + ret.isTemp = 1; + ret.isNil = 0; + ret.hasReturned = 0; + ret.index = CompilerGetLocal(c, scope); + return ret; } /* Return a slot that is the target Slot given some FormOptions. Will * Create a temporary slot if needed, so be sure to drop the slot after use. */ static Slot CompilerGetTarget(Compiler * c, FormOptions opts) { - if (opts.canChoose) { - return CompilerGetTemp(c); - } else { + if (opts.canChoose) { + return CompilerGetTemp(c); + } else { Slot ret; ret.isTemp = 0; ret.isNil = 0; ret.hasReturned = 0; ret.index = opts.target; return ret; - } + } } /* If a slot is a nil slot, create a slot that has * an actual location on the stack. */ static Slot CompilerRealizeSlot(Compiler * c, Slot slot) { - if (slot.isNil) { - slot = CompilerGetTemp(c); + if (slot.isNil) { + slot = CompilerGetTemp(c); BufferPushUInt16(c->vm, c->buffer, VM_OP_NIL); BufferPushUInt16(c->vm, c->buffer, slot.index); - } - return slot; + } + return slot; } /* Helper to get a nil slot */ @@ -368,9 +368,9 @@ static Slot CompileValue(Compiler * c, FormOptions opts, Value x); /* Compile a structure that evaluates to a literal value. Useful * for objects like strings, or anything else that cannot be instatiated else { - break; + break; } - * from bytecode and doesn't do anything in the AST. */ + * from bytecode and doesn't do anything in the AST. */ static Slot CompileLiteral(Compiler * c, FormOptions opts, Value x) { Scope * scope = c->tail; Buffer * buffer = c->buffer; @@ -569,7 +569,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form, /* Free up space */ CompilerTrackerFree(c, scope, &tracker); if (opts.resultUnused) { - ret = NilSlot(); + ret = NilSlot(); } else { ret = CompilerGetTarget(c, opts); /* Write the correct opcode */ @@ -669,7 +669,7 @@ static Slot CompileAssign(Compiler * c, FormOptions opts, Value left, Value righ /* Local variable */ subOpts.canChoose = 0; subOpts.target = target; - slot = CompileValue(c, subOpts, right); + slot = CompileValue(c, subOpts, right); } } else { /* We need to declare a new symbol */ @@ -701,8 +701,8 @@ static Slot CompileBlock(Compiler * c, FormOptions opts, Array * form, uint32_t CompilerDropSlot(c, scope, CompileValue(c, subOpts, form->data[current])); ++current; } - /* Compile the last expression in the body */ - return CompileValue(c, opts, form->data[form->count - 1]); + /* Compile the last expression in the body */ + return CompileValue(c, opts, form->data[form->count - 1]); } /* Extract the last n bytes from the buffer and use them to construct @@ -713,7 +713,7 @@ static FuncDef * CompilerGenFuncDef(Compiler * c, uint32_t lastNBytes, uint32_t FuncDef * def = VMAlloc(c->vm, sizeof(FuncDef)); /* Create enough space for the new byteCode */ if (lastNBytes > buffer->count) - CError(c, "Trying to extract more bytes from buffer than in buffer."); + CError(c, "Trying to extract more bytes from buffer than in buffer."); uint8_t * byteCode = VMAlloc(c->vm, lastNBytes); def->byteCode = (uint16_t *) byteCode; def->byteCodeLen = lastNBytes / 2; @@ -726,9 +726,9 @@ static FuncDef * CompilerGenFuncDef(Compiler * c, uint32_t lastNBytes, uint32_t if (scope->literalsArray->count) { def->literals = VMAlloc(c->vm, scope->literalsArray->count * sizeof(Value)); memcpy(def->literals, scope->literalsArray->data, - scope->literalsArray->count * sizeof(Value)); + scope->literalsArray->count * sizeof(Value)); } else { - def->literals = NULL; + def->literals = NULL; } def->literalsLen = scope->literalsArray->count; /* Delete the sub scope */ @@ -736,7 +736,7 @@ static FuncDef * CompilerGenFuncDef(Compiler * c, uint32_t lastNBytes, uint32_t /* Initialize the new FuncDef */ def->locals = scope->frameSize; def->arity = arity; - return def; + return def; } /* Compile a function from a function literal */ @@ -812,7 +812,7 @@ static Slot CompileIf(Compiler * c, FormOptions opts, Array * form) { /* If the condition is nil, just compile false path */ if (condition.isNil) { if (form->count == 4) { - return CompileValue(c, opts, form->data[3]); + return CompileValue(c, opts, form->data[3]); } return condition; } @@ -823,9 +823,9 @@ static Slot CompileIf(Compiler * c, FormOptions opts, Array * form) { BufferPushUInt16(c->vm, buffer, VM_OP_JIF); BufferPushUInt16(c->vm, buffer, condition.index); BufferPushUInt32(c->vm, buffer, 0); - /* Configure branch form options */ - branchOpts.canChoose = 0; - branchOpts.target = condition.index; + /* Configure branch form options */ + branchOpts.canChoose = 0; + branchOpts.target = condition.index; /* Compile true path */ left = CompileValue(c, branchOpts, form->data[2]); if (opts.isTail) { @@ -870,21 +870,21 @@ static Slot CompileIf(Compiler * c, FormOptions opts, Array * form) { /* While special */ static Slot CompileWhile(Compiler * c, FormOptions opts, Array * form) { Slot cond; - uint32_t countAtStart = c->buffer->count; - uint32_t countAtJumpDelta; - uint32_t countAtFinish; - FormOptions defaultOpts = FormOptionsDefault(); + uint32_t countAtStart = c->buffer->count; + uint32_t countAtJumpDelta; + uint32_t countAtFinish; + FormOptions defaultOpts = FormOptionsDefault(); CompilerPushScope(c, 1); /* Compile condition */ - cond = CompileValue(c, defaultOpts, form->data[1]); - /* Assert that cond is a real value - otherwise do nothing (nil is false, + cond = CompileValue(c, defaultOpts, form->data[1]); + /* Assert that cond is a real value - otherwise do nothing (nil is false, * so loop never runs.) */ - if (cond.isNil) return cond; - /* Leave space for jump later */ - countAtJumpDelta = c->buffer->count; - c->buffer->count += sizeof(uint16_t) * 2 + sizeof(int32_t); - /* Compile loop body */ - defaultOpts.resultUnused = 1; + if (cond.isNil) return cond; + /* Leave space for jump later */ + countAtJumpDelta = c->buffer->count; + c->buffer->count += sizeof(uint16_t) * 2 + sizeof(int32_t); + /* Compile loop body */ + defaultOpts.resultUnused = 1; CompilerDropSlot(c, c->tail, CompileBlock(c, defaultOpts, form, 2)); /* Jump back to the loop start */ countAtFinish = c->buffer->count; @@ -893,16 +893,16 @@ static Slot CompileWhile(Compiler * c, FormOptions opts, Array * form) { countAtFinish = c->buffer->count; /* Set the jump to the correct length */ c->buffer->count = countAtJumpDelta; - BufferPushUInt16(c->vm, c->buffer, VM_OP_JIF); - BufferPushUInt16(c->vm, c->buffer, cond.index); + BufferPushUInt16(c->vm, c->buffer, VM_OP_JIF); + BufferPushUInt16(c->vm, c->buffer, cond.index); BufferPushInt32(c->vm, c->buffer, (int32_t)(countAtFinish - countAtJumpDelta) / 2); - /* Pop scope */ - c->buffer->count = countAtFinish; + /* Pop scope */ + c->buffer->count = countAtFinish; CompilerPopScope(c); - /* Return nil */ - if (opts.resultUnused) - return NilSlot(); - else + /* Return nil */ + if (opts.resultUnused) + return NilSlot(); + else return cond; } @@ -967,30 +967,30 @@ static SpecialFormHelper GetSpecial(Array * form) { case '/': return CompileDivision; case '>': return CompileGreaterThan; case '<': return CompileLessThan; - case '=': return CompileEquals; + case '=': return CompileEquals; case '\'': return CompileQuote; default: - break; + break; } } /* Multi character specials. Mostly control flow. */ switch (name[0]) { case '>': - { - if (VStringSize(name) == 2 && - name[1] == '=') { - return CompileGreaterThanOrEqual; - } - } - break; + { + if (VStringSize(name) == 2 && + name[1] == '=') { + return CompileGreaterThanOrEqual; + } + } + break; case '<': - { - if (VStringSize(name) == 2 && - name[1] == '=') { - return CompileLessThanOrEqual; - } - } - break; + { + if (VStringSize(name) == 2 && + name[1] == '=') { + return CompileLessThanOrEqual; + } + } + break; case 'd': { if (VStringSize(name) == 2 && @@ -1015,14 +1015,14 @@ static SpecialFormHelper GetSpecial(Array * form) { } } break; - case 'n': - { - if (VStringSize(name) == 3 && - name[1] == 'o' && - name[2] == 't') { - return CompileNot; - } - } + case 'n': + { + if (VStringSize(name) == 3 && + name[1] == 'o' && + name[2] == 't') { + return CompileNot; + } + } case 'q': { if (VStringSize(name) == 5 && @@ -1030,7 +1030,7 @@ static SpecialFormHelper GetSpecial(Array * form) { name[2] == 'o' && name[3] == 't' && name[4] == 'e') { - return CompileQuote; + return CompileQuote; } } break; @@ -1044,15 +1044,15 @@ static SpecialFormHelper GetSpecial(Array * form) { } break; case 'w': - { - if (VStringSize(name) == 5 && - name[1] == 'h' && - name[2] == 'i' && - name[3] == 'l' && - name[4] == 'e') { - return CompileWhile; - } - } + { + if (VStringSize(name) == 5 && + name[1] == 'h' && + name[2] == 'i' && + name[3] == 'l' && + name[4] == 'e') { + return CompileWhile; + } + } default: break; } @@ -1149,10 +1149,10 @@ void CompilerAddGlobal(Compiler * c, const char * name, Value x) { /* Register a global c function for the compilation environment. */ void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f) { - Value func; - func.type = TYPE_CFUNCTION; - func.data.cfunction = f; - return CompilerAddGlobal(c, name, func); + Value func; + func.type = TYPE_CFUNCTION; + func.data.cfunction = f; + return CompilerAddGlobal(c, name, func); } /* Compile interface. Returns a function that evaluates the @@ -1185,3 +1185,27 @@ Func * CompilerCompile(Compiler * c, Value form) { return func; } } + +/* Macro expansion. Macro expansion happens prior to the compilation process + * and is completely separate. This allows the compilation to not have to worry + * about garbage collection and other issues that would complicate both the + * runtime and the compilation. */ +int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out) { + while (x.type == TYPE_FORM) { + Array * form = x.data.array; + Value sym, macroFn; + if (form->count == 0) break; + sym = form->data[0]; + macroFn = DictGet(macros, sym); + if (macroFn.type != TYPE_FUNCTION && macroFn.type != TYPE_CFUNCTION) break; + VMLoad(vm, macroFn); + if (VMStart(vm)) { + /* We encountered an error during parsing */ + return 1;; + } else { + x = vm->ret; + } + } + *out = x; + return 0; +} diff --git a/compile.h b/compile.h index 3206eb6e..1f384fc4 100644 --- a/compile.h +++ b/compile.h @@ -15,4 +15,10 @@ void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f); /* Compile a function that evaluates the given form. */ Func * CompilerCompile(Compiler * c, Value form); +/* Macro expansion. Macro expansion happens prior to the compilation process + * and is completely separate. This allows the compilation to not have to worry + * about garbage collection and other issues that would complicate both the + * runtime and the compilation. */ +int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out); + #endif /* end of include guard: COMPILE_H_9VXF71HY */ diff --git a/datatypes.h b/datatypes.h index 3a0b6cef..87e14073 100644 --- a/datatypes.h +++ b/datatypes.h @@ -127,10 +127,11 @@ struct VM { uint16_t * pc; Array * thread; Value * base; + Value root; /* Global state - prevents GC cleanup */ /* Return state */ const char * error; jmp_buf jump; - Value tempRoot; /* Temporary GC root */ + Value ret; /* Returned value from VMStart */ }; /* Parsing */ diff --git a/main.c b/main.c index 947d1eab..139b4b3b 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,6 @@ #include #include #include "datatypes.h" -#include "gc.h" #include "vm.h" #include "parse.h" #include "compile.h" @@ -9,100 +8,98 @@ #include "disasm.h" Value print(VM * vm) { - uint32_t i, j, count; - Value nil; - count = VMCountArgs(vm); - for (j = 0; j < count; ++j) { - uint8_t * string = ValueToString(vm, VMGetArg(vm, j)); - uint32_t len = VStringSize(string); - for (i = 0; i < len; ++i) - fputc(string[i], stdout); - fputc('\n', stdout); - } - nil.type = TYPE_NIL; - return nil; + uint32_t i, j, count; + Value nil; + count = VMCountArgs(vm); + for (j = 0; j < count; ++j) { + uint8_t * string = ValueToString(vm, VMGetArg(vm, j)); + uint32_t len = VStringSize(string); + for (i = 0; i < len; ++i) + fputc(string[i], stdout); + fputc('\n', stdout); + } + nil.type = TYPE_NIL; + return nil; } /* A simple repl for debugging */ void debugRepl() { - char buffer[128] = {0}; - const char * reader = buffer; - Func * func; - VM vm; - Parser p; - Compiler c; + char buffer[128] = {0}; + const char * reader = buffer; + Value func; + VM vm; + Parser p; + Compiler c; - VMInit(&vm); + VMInit(&vm); - for (;;) { + for (;;) { - /* Run garbage collection */ - VMMaybeCollect(&vm); + /* Run garbage collection */ + VMMaybeCollect(&vm); - /* Reset state */ - ParserInit(&p, &vm); + /* Reset state */ + ParserInit(&p, &vm); - /* Get and parse input until we have a full form */ - while (p.status == PARSER_PENDING) { - /* Get some input if we are done */ - if (*reader == '\0') { - printf("> "); - if (!fgets(buffer, sizeof(buffer), stdin)) { - return; - } - p.index = 0; - reader = buffer; - } - reader += ParserParseCString(&p, reader); - } - - /* Check for parsing errors */ - if (p.error) { - unsigned i; - printf("\n"); - printf("%s\n", buffer); - for (i = 0; i < p.index; ++i) { - printf(" "); - } - printf("^\n"); - printf("\nParse error: %s\n", p.error); - reader = buffer; /* Flush the input buffer */ - buffer[0] = '\0'; - continue; - } - - /* Try to compile generated AST */ - CompilerInit(&c, &vm); - CompilerAddGlobalCFunc(&c, "print", print); - func = CompilerCompile(&c, p.value); - - /* Check for compilation errors */ - if (c.error) { - printf("Compiler error: %s\n", c.error); - reader = buffer; - buffer[0] = 0; - continue; - } - - /* Print the function that will be executed */ - dasmFunc(stdout, func); - - /* Execute function */ - VMLoad(&vm, func); - if (VMStart(&vm)) { - printf("VM error: %s\n", vm.error); - reader = buffer; - buffer[0] = 0; - continue; - } else { - ValuePrint(vm.tempRoot, 0); - printf("\n"); + /* Get and parse input until we have a full form */ + while (p.status == PARSER_PENDING) { + /* Get some input if we are done */ + if (*reader == '\0') { + printf("> "); + if (!fgets(buffer, sizeof(buffer), stdin)) { + return; } + p.index = 0; + reader = buffer; + } + reader += ParserParseCString(&p, reader); } + /* Check for parsing errors */ + if (p.error) { + unsigned i; + printf("\n"); + printf("%s\n", buffer); + for (i = 0; i < p.index; ++i) { + printf(" "); + } + printf("^\n"); + printf("\nParse error: %s\n", p.error); + reader = buffer; /* Flush the input buffer */ + buffer[0] = '\0'; + continue; + } + + /* Try to compile generated AST */ + CompilerInit(&c, &vm); + CompilerAddGlobalCFunc(&c, "print", print); + func.type = TYPE_FUNCTION; + func.data.func = CompilerCompile(&c, p.value); + + /* Check for compilation errors */ + if (c.error) { + printf("Compiler error: %s\n", c.error); + reader = buffer; + buffer[0] = 0; + continue; + } + + /* Execute function */ + VMLoad(&vm, func); + if (VMStart(&vm)) { + printf("VM error: %s\n", vm.error); + reader = buffer; + buffer[0] = 0; + continue; + } else { + ValuePrint(vm.ret, 0); + printf("\n"); + } + } + } int main() { - printf("Super cool interpreter v0.0\n"); - debugRepl(); + printf("Super cool interpreter v0.0\n"); + debugRepl(); } diff --git a/parse.c b/parse.c index 7a3326f4..c34f1f12 100644 --- a/parse.c +++ b/parse.c @@ -128,16 +128,16 @@ static int isWhitespace(uint8_t c) { /* Check if a character is a valid symbol character */ static int isSymbolChar(uint8_t c) { - if (c >= 'a' && c <= 'z') return 1; - if (c >= 'A' && c <= 'Z') return 1; - if (c >= '0' && c <= '9') return 1; - if (c >= '<' && c <= '@') return 1; - if (c >= '*' && c <= '/') return 1; - if (c >= '#' && c <= '&') return 1; - if (c == '_') return 1; - if (c == '^') return 1; - if (c == '!') return 1; - return 0; + if (c >= 'a' && c <= 'z') return 1; + if (c >= 'A' && c <= 'Z') return 1; + if (c >= '0' && c <= '9') return 1; + if (c >= '<' && c <= '@') return 1; + if (c >= '*' && c <= '/') return 1; + if (c >= '#' && c <= '&') return 1; + if (c == '_') return 1; + if (c == '^') return 1; + if (c == '!') return 1; + return 0; } /* Get an integer power of 10 */ @@ -308,8 +308,8 @@ static int ParserStringState(Parser * p, uint8_t c) { case '\'': next = '\''; break; case 'z': next = '\0'; break; default: - PError(p, "Unknown string escape sequence."); - return 1; + PError(p, "Unknown string escape sequence."); + return 1; } BufferPush(p->vm, top->buf.string.buffer, next); top->buf.string.state = STRING_STATE_BASE; diff --git a/value.c b/value.c index 01a67bfb..dd6c12a5 100644 --- a/value.c +++ b/value.c @@ -9,14 +9,14 @@ static void FuncDefBytecodePrint(FuncDef * def) { uint32_t count, i; count = def->byteCodeLen; - printf("(bytecode)["); - if (count) { - for (i = 0; i < count - 1; ++i) { - printf("%04x ", def->byteCode[i]); - } - printf("%04x", def->byteCode[i]); - } - printf("]"); + printf("(bytecode)["); + if (count) { + for (i = 0; i < count - 1; ++i) { + printf("%04x ", def->byteCode[i]); + } + printf("%04x", def->byteCode[i]); + } + printf("]"); } /* Print a value recursively. Used for debugging */ @@ -55,8 +55,8 @@ void ValuePrint(Value x, uint32_t indent) { break; case TYPE_FUNCTION: printf("def); - printf(">"); + FuncDefBytecodePrint(x.data.func->def); + printf(">"); break; case TYPE_DICTIONARY: printf(""); @@ -66,8 +66,8 @@ void ValuePrint(Value x, uint32_t indent) { break; case TYPE_FUNCDEF: printf(""); + FuncDefBytecodePrint(x.data.funcdef); + printf(">"); break; case TYPE_FUNCENV: printf(""); @@ -197,10 +197,10 @@ int ValueEqual(Value x, Value y) { case TYPE_NUMBER: result = (x.data.number == y.data.number); break; - /* Assume that when strings are created, equal strings - * are set to the same string */ + /* Assume that when strings are created, equal strings + * are set to the same string */ case TYPE_STRING: - /* TODO: keep cache to for symbols to get quick equality. */ + /* TODO: keep cache to for symbols to get quick equality. */ case TYPE_SYMBOL: if (x.data.string == y.data.string) { result = 1; @@ -274,12 +274,12 @@ uint32_t ValueHash(Value x) { case TYPE_THREAD: /* Cast the pointer */ { - union { - void * pointer; - uint32_t hash; - } u; - u.pointer = x.data.pointer; - hash = u.hash; + union { + void * pointer; + uint32_t hash; + } u; + u.pointer = x.data.pointer; + hash = u.hash; } break; } diff --git a/vm.c b/vm.c index 73fe0446..3e23015b 100644 --- a/vm.c +++ b/vm.c @@ -15,21 +15,19 @@ static const char VMS_EXPECTED_NUMBER_LOP[] = "Expected left operand to be numbe typedef struct StackFrame StackFrame; struct StackFrame { Value callee; - uint16_t size; - uint16_t prevSize; - uint16_t ret; - FuncEnv * env; - uint16_t * pc; + uint16_t size; + uint16_t prevSize; + uint16_t ret; + FuncEnv * env; + uint16_t * pc; }; /* The size of a StackFrame in units of Values. */ -static size_t FRAME_SIZE() { - return ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value)); -} +#define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value)) /* Get the stack frame pointer for a thread */ static StackFrame * ThreadFrame(Array * thread) { - return (StackFrame *)(thread->data + thread->count - FRAME_SIZE()); + return (StackFrame *)(thread->data + thread->count - FRAME_SIZE); } /* The metadata header associated with an allocated block of memory */ @@ -93,7 +91,7 @@ static void VMMark(VM * vm, Value * x) { GCHeader(x->data.array)->color = vm->black; GCHeader(x->data.array->data)->color = vm->black; for (i = 0; i < count; ++i) - VMMark(vm, x->data.array->data + i); + VMMark(vm, x->data.array->data + i); } break; @@ -102,19 +100,19 @@ static void VMMark(VM * vm, Value * x) { uint32_t i; Array * thread = x->data.array; StackFrame * frame = (StackFrame *)thread->data; - StackFrame * end = (StackFrame *)(thread->data + thread->count - FRAME_SIZE()); + StackFrame * end = (StackFrame *)(thread->data + thread->count - FRAME_SIZE); GCHeader(thread)->color = vm->black; GCHeader(thread->data)->color = vm->black; - while (frame <= end) { - Value * stack = (Value *)frame + FRAME_SIZE(); - VMMark(vm, &frame->callee); - if (frame->env) - VMMarkFuncEnv(vm, frame->env); - for (i = 0; i < frame->size; ++i) { - VMMark(vm, stack + i); - } - frame = (StackFrame *)(stack + frame->size); - } + while (frame <= end) { + Value * stack = (Value *)frame + FRAME_SIZE; + VMMark(vm, &frame->callee); + if (frame->env) + VMMarkFuncEnv(vm, frame->env); + for (i = 0; i < frame->size; ++i) { + VMMark(vm, stack + i); + } + frame = (StackFrame *)(stack + frame->size); + } } break; @@ -165,9 +163,9 @@ static void VMMark(VM * vm, Value * x) { } break; - case TYPE_FUNCENV: - VMMarkFuncEnv(vm, x->data.funcenv); - break; + case TYPE_FUNCENV: + VMMarkFuncEnv(vm, x->data.funcenv); + break; } @@ -224,20 +222,23 @@ void * VMZalloc(VM * vm, uint32_t size) { /* Run garbage collection */ void VMCollect(VM * vm) { if (vm->lock > 0) return; - Value thread; - thread.type = TYPE_THREAD; - thread.data.array = vm->thread; - VMMark(vm, &thread); - VMMark(vm, &vm->tempRoot); + /* Thread can be null */ + if (vm->thread) { + Value thread; + thread.type = TYPE_THREAD; + thread.data.array = vm->thread; + VMMark(vm, &thread); + } + VMMark(vm, &vm->ret); + VMMark(vm, &vm->root); VMSweep(vm); vm->nextCollection = 0; } /* Run garbage collection if needed */ void VMMaybeCollect(VM * vm) { - if (vm->nextCollection >= vm->memoryInterval) { + if (vm->nextCollection >= vm->memoryInterval) VMCollect(vm); - } } /* Push a stack frame onto a thread */ @@ -245,19 +246,19 @@ static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) { uint16_t oldSize; uint32_t nextCount, i; StackFrame * frame; - if (thread->count) { - frame = ThreadFrame(thread); - oldSize = frame->size; + if (thread->count) { + frame = ThreadFrame(thread); + oldSize = frame->size; } else { - oldSize = 0; + oldSize = 0; } - nextCount = thread->count + oldSize + FRAME_SIZE(); - ArrayEnsure(vm, thread, nextCount + size); + nextCount = thread->count + oldSize + FRAME_SIZE; + ArrayEnsure(vm, thread, nextCount + size); thread->count = nextCount; - /* Ensure values start out as nil so as to not confuse - * the garabage collector */ - for (i = nextCount; i < nextCount + size; ++i) - thread->data[i].type = TYPE_NIL; + /* Ensure values start out as nil so as to not confuse + * the garabage collector */ + for (i = nextCount; i < nextCount + size; ++i) + thread->data[i].type = TYPE_NIL; frame = ThreadFrame(thread); /* Set up the new stack frame */ frame->prevSize = oldSize; @@ -271,28 +272,28 @@ static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) { environment */ static void VMThreadSplitStack(VM * vm, Array * thread) { StackFrame * frame = ThreadFrame(thread); - FuncEnv * env = frame->env; - /* Check for closures */ - if (env) { - uint32_t size = frame->size; - env->thread = NULL; - env->stackOffset = size; - env->values = VMAlloc(vm, sizeof(Value) * size); - memcpy(env->values, thread->data + thread->count, size * sizeof(Value)); - } + FuncEnv * env = frame->env; + /* Check for closures */ + if (env) { + uint32_t size = frame->size; + env->thread = NULL; + env->stackOffset = size; + env->values = VMAlloc(vm, sizeof(Value) * size); + memcpy(env->values, thread->data + thread->count, size * sizeof(Value)); + } } /* Pop the top-most stack frame from stack */ static void VMThreadPop(VM * vm, Array * thread) { StackFrame * frame = ThreadFrame(thread); - uint32_t delta = FRAME_SIZE() + frame->prevSize; - if (thread->count) { - VMThreadSplitStack(vm, thread); - } else { - VMError(vm, "Nothing to pop from stack."); - } - thread->count -= delta; - vm->base -= delta; + uint32_t delta = FRAME_SIZE + frame->prevSize; + if (thread->count) { + VMThreadSplitStack(vm, thread); + } else { + VMError(vm, "Nothing to pop from stack."); + } + thread->count -= delta; + vm->base -= delta; } /* Get an upvalue */ @@ -300,7 +301,7 @@ static Value * GetUpValue(VM * vm, Func * fn, uint16_t level, uint16_t index) { FuncEnv * env; Value * stack; if (!level) { - return vm->base + index; + return vm->base + index; } while (fn && --level) fn = fn->parent; @@ -330,7 +331,7 @@ static int truthy(Value v) { static void VMReturn(VM * vm, Value ret) { Array * thread = vm->thread; StackFrame * frame = ThreadFrame(thread); - VMThreadPop(vm, thread); + VMThreadPop(vm, thread); if (thread->count == 0) { VMExit(vm, ret); } @@ -348,7 +349,7 @@ static void VMCallOp(VM * vm) { uint32_t oldCount = thread->count; uint32_t i; Value * oldBase; - frame->pc = vm->pc + 4 + arity; + frame->pc = vm->pc + 4 + arity; frame->ret = vm->pc[2]; if (callee.type == TYPE_FUNCTION) { Func * fn = callee.data.func; @@ -365,15 +366,15 @@ static void VMCallOp(VM * vm) { ++vm->lock; VMReturn(vm, callee.data.cfunction(vm)); --vm->lock; - } else { - Func * f = callee.data.func; - uint32_t locals = f->def->locals; - for (i = 0; i < arity; ++i) - vm->base[i] = oldBase[vm->pc[4 + i]]; - for (; i < locals; ++i) - vm->base[i].type = TYPE_NIL; + } else { + Func * f = callee.data.func; + uint32_t locals = f->def->locals; + for (i = 0; i < arity; ++i) + vm->base[i] = oldBase[vm->pc[4 + i]]; + for (; i < locals; ++i) + vm->base[i].type = TYPE_NIL; vm->pc = f->def->byteCode; - } + } VMMaybeCollect(vm); } @@ -386,42 +387,42 @@ static void VMTailCallOp(VM * vm) { uint16_t newFrameSize, currentFrameSize; uint32_t i; /* Check for closures */ - VMThreadSplitStack(vm, thread); + VMThreadSplitStack(vm, thread); if (callee.type == TYPE_CFUNCTION) { - newFrameSize = arity; - } else if (callee.type == TYPE_FUNCTION) { - Func * f = callee.data.func; - newFrameSize = f->def->locals; - } else { - VMError(vm, EXPECTED_FUNCTION); - } - /* Ensure stack has enough space for copies of arguments */ - currentFrameSize = frame->size; - ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); - frame = ThreadFrame(thread); + newFrameSize = arity; + } else if (callee.type == TYPE_FUNCTION) { + Func * f = callee.data.func; + newFrameSize = f->def->locals; + } else { + VMError(vm, EXPECTED_FUNCTION); + } + /* Ensure stack has enough space for copies of arguments */ + currentFrameSize = frame->size; + ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); + frame = ThreadFrame(thread); vm->base = thread->data + thread->count; /* Copy the arguments into the extra space */ for (i = 0; i < arity; ++i) { - vm->base[currentFrameSize + i] = vm->base[vm->pc[3 + i]]; + vm->base[currentFrameSize + i] = vm->base[vm->pc[3 + i]]; } /* Copy the end of the stack to the parameter position */ memcpy(vm->base, vm->base + currentFrameSize, arity * sizeof(Value)); - /* nil the non argument part of the stack for gc */ + /* nil the non argument part of the stack for gc */ for (i = arity; i < newFrameSize; ++i) { - vm->base[i].type = TYPE_NIL; + vm->base[i].type = TYPE_NIL; } /* Update the stack frame */ - frame->size = newFrameSize; + frame->size = newFrameSize; frame->callee = callee; frame->env = NULL; if (callee.type == TYPE_CFUNCTION) { ++vm->lock; VMReturn(vm, callee.data.cfunction(vm)); --vm->lock; - } else { - Func * f = callee.data.func; + } else { + Func * f = callee.data.func; vm->pc = f->def->byteCode; - } + } VMMaybeCollect(vm); } @@ -440,7 +441,7 @@ static Value VMMakeClosure(VM * vm, uint16_t literal) { env->thread = thread; env->stackOffset = thread->count; env->values = NULL; - frame->env = env; + frame->env = env; } current = frame->callee.data.func; constant = LoadConstant(vm, current, literal); @@ -482,29 +483,29 @@ int VMStart(VM * vm) { Value temp, v1, v2; #define DO_BINARY_MATH(op) \ - v1 = vm->base[vm->pc[2]]; \ - v2 = vm->base[vm->pc[3]]; \ + v1 = vm->base[vm->pc[2]]; \ + v2 = vm->base[vm->pc[3]]; \ VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \ VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \ temp.type = TYPE_NUMBER; \ temp.data.number = v1.data.number op v2.data.number; \ vm->base[vm->pc[1]] = temp; \ vm->pc += 4; \ - break; + break; - case VM_OP_ADD: /* Addition */ - DO_BINARY_MATH(+) + case VM_OP_ADD: /* Addition */ + DO_BINARY_MATH(+) case VM_OP_SUB: /* Subtraction */ - DO_BINARY_MATH(-) + DO_BINARY_MATH(-) case VM_OP_MUL: /* Multiplication */ - DO_BINARY_MATH(*) + DO_BINARY_MATH(*) case VM_OP_DIV: /* Division */ - DO_BINARY_MATH(/) + DO_BINARY_MATH(/) - #undef DO_BINARY_MATH + #undef DO_BINARY_MATH case VM_OP_NOT: /* Boolean unary (Boolean not) */ temp.type = TYPE_BOOLEAN; @@ -528,22 +529,22 @@ int VMStart(VM * vm) { break; case VM_OP_FLS: /* Load False */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = 0; - vm->base[vm->pc[1]] = temp; + temp.type = TYPE_BOOLEAN; + temp.data.boolean = 0; + vm->base[vm->pc[1]] = temp; vm->pc += 2; break; case VM_OP_TRU: /* Load True */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = 1; - vm->base[vm->pc[1]] = temp; + temp.type = TYPE_BOOLEAN; + temp.data.boolean = 1; + vm->base[vm->pc[1]] = temp; vm->pc += 2; break; case VM_OP_NIL: /* Load Nil */ - temp.type = TYPE_NIL; - vm->base[vm->pc[1]] = temp; + temp.type = TYPE_NIL; + vm->base[vm->pc[1]] = temp; vm->pc += 2; break; @@ -578,7 +579,7 @@ int VMStart(VM * vm) { break; case VM_OP_RET: /* Return */ - VMReturn(vm, vm->base[vm->pc[1]]); + VMReturn(vm, vm->base[vm->pc[1]]); break; case VM_OP_SUV: /* Set Up Value */ @@ -641,46 +642,46 @@ int VMStart(VM * vm) { break; case VM_OP_ARR: /* Array literal */ - { - uint32_t i; - uint32_t arrayLen = vm->pc[2]; - Array * array = ArrayNew(vm, arrayLen); - array->count = arrayLen; - for (i = 0; i < arrayLen; ++i) - array->data[i] = vm->base[vm->pc[3 + i]]; - temp.type = TYPE_ARRAY; - temp.data.array = array; - vm->base[vm->pc[1]] = temp; + { + uint32_t i; + uint32_t arrayLen = vm->pc[2]; + Array * array = ArrayNew(vm, arrayLen); + array->count = arrayLen; + for (i = 0; i < arrayLen; ++i) + array->data[i] = vm->base[vm->pc[3 + i]]; + temp.type = TYPE_ARRAY; + temp.data.array = array; + vm->base[vm->pc[1]] = temp; vm->pc += 3 + arrayLen; VMMaybeCollect(vm); - } + } break; case VM_OP_DIC: /* Dictionary literal */ - { - uint32_t i = 3; - uint32_t kvs = vm->pc[2]; - Dictionary * dict = DictNew(vm, kvs); - kvs = kvs + 3; - while (i < kvs) { + { + uint32_t i = 3; + uint32_t kvs = vm->pc[2]; + Dictionary * dict = DictNew(vm, kvs); + kvs = kvs + 3; + while (i < kvs) { v1 = vm->base[vm->pc[i++]]; v2 = vm->base[vm->pc[i++]]; - DictPut(vm, dict, v1, v2); + DictPut(vm, dict, v1, v2); } - temp.type = TYPE_DICTIONARY; - temp.data.dict = dict; - vm->base[vm->pc[1]] = temp; - vm->pc += kvs; - VMMaybeCollect(vm); - } + temp.type = TYPE_DICTIONARY; + temp.data.dict = dict; + vm->base[vm->pc[1]] = temp; + vm->pc += kvs; + VMMaybeCollect(vm); + } break; - case VM_OP_TCL: /* Tail call */ + case VM_OP_TCL: /* Tail call */ VMTailCallOp(vm); break; /* Macro for generating some math operators */ - #define DO_MULTI_MATH(op, start) { \ + #define DO_MULTI_MATH(op, start) { \ uint16_t count = vm->pc[2]; \ uint16_t i; \ Number accum = start; \ @@ -709,7 +710,7 @@ int VMStart(VM * vm) { case VM_OP_DVM: DO_MULTI_MATH(/, 1) - #undef DO_MULTI_MATH + #undef DO_MULTI_MATH case VM_OP_RTN: /* Return nil */ temp.type = TYPE_NIL; @@ -727,14 +728,14 @@ int VMStart(VM * vm) { Value VMGetArg(VM * vm, uint16_t index) { uint16_t frameSize = ThreadFrame(vm->thread)->size; VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); - return vm->base[index]; + return vm->base[index]; } /* Put a value on the stack */ void VMSetArg(VM * vm, uint16_t index, Value x) { uint16_t frameSize = ThreadFrame(vm->thread)->size; VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); - vm->base[index] = x; + vm->base[index] = x; } /* Get the size of the VMStack */ @@ -744,29 +745,36 @@ uint16_t VMCountArgs(VM * vm) { /* Initialize the VM */ void VMInit(VM * vm) { - vm->tempRoot.type = TYPE_NIL; + vm->ret.type = TYPE_NIL; + vm->root.type = TYPE_NIL; vm->base = NULL; vm->pc = NULL; vm->error = NULL; - /* Garbage collection */ + /* Garbage collection */ vm->blocks = NULL; vm->nextCollection = 0; - vm->memoryInterval = 1024 * 256; + vm->memoryInterval = 0; vm->black = 0; vm->lock = 0; - /* Create new thread */ - vm->thread = ArrayNew(vm, 20); + /* Set to empty thread */ + vm->thread = NULL; } /* Load a function into the VM. The function will be called with * no arguments when run */ -void VMLoad(VM * vm, Func * func) { - Value callee; - callee.type = TYPE_FUNCTION; - callee.data.func = func; - vm->thread = ArrayNew(vm, 100); - VMThreadPush(vm, vm->thread, callee, func->def->locals); - vm->pc = func->def->byteCode; +void VMLoad(VM * vm, Value func) { + Array * thread = ArrayNew(vm, 100); + vm->thread = thread; + if (func.type == TYPE_FUNCTION) { + Func * fn = func.data.func; + VMThreadPush(vm, thread, func, fn->def->locals); + vm->pc = fn->def->byteCode; + } else if (func.type == TYPE_CFUNCTION) { + VMThreadPush(vm, thread, func, 0); + vm->pc = NULL; + } else { + return; + } } /* Clear all memory associated with the VM */ diff --git a/vm.h b/vm.h index e047e7d8..26a12ec1 100644 --- a/vm.h +++ b/vm.h @@ -4,7 +4,7 @@ #include "datatypes.h" /* Exit from the VM normally */ -#define VMExit(vm, r) ((vm)->tempRoot = (r), longjmp((vm)->jump, 1)) +#define VMExit(vm, r) ((vm)->ret = (r), longjmp((vm)->jump, 1)) /* Bail from the VM with an error. */ #define VMError(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2)) @@ -16,6 +16,10 @@ #define VMAssert(vm, cond, e) do \ { if (!(cond)) { VMError((vm), (e)); } } while (0) +/* Type assertion */ +#define VMAssertType(vm, f, type) \ + VMAssert(vm, (f).type == (type), "Expected type " type) + /* Initialize the VM */ void VMInit(VM * vm); @@ -23,14 +27,11 @@ void VMInit(VM * vm); void VMDeinit(VM * vm); /* Load a function to be run on the VM */ -void VMLoad(VM * vm, Func * func); +void VMLoad(VM * vm, Value func); /* Start running the VM */ int VMStart(VM * vm); -/* Get the result after VMStart returns */ -#define VMResult(vm) ((vm)->tempRoot) - /* Run garbage collection */ void VMCollect(VM * vm);