1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-17 10:49:56 +00:00

Merge branch 'master' of git+ssh://eng-grid.bu.edu/home/calsrose/code/interp

This commit is contained in:
Calvin Rose 2017-02-12 15:55:45 -05:00
commit f2d6b979f0
8 changed files with 400 additions and 363 deletions

212
compile.c
View File

@ -96,8 +96,8 @@ BufferDefine(Int16, int16_t);
/* If there is an error during compilation, /* If there is an error during compilation,
* jump back to start */ * jump back to start */
static void CError(Compiler * c, const char * e) { static void CError(Compiler * c, const char * e) {
c->error = e; c->error = e;
longjmp(c->onError, 1); longjmp(c->onError, 1);
} }
/* Push a new scope in the compiler and return /* Push a new scope in the compiler and return
@ -117,11 +117,11 @@ static Scope * CompilerPushScope(Compiler * c, int sameFunction) {
c->tail->nextScope = scope; c->tail->nextScope = scope;
scope->level = c->tail->level + (sameFunction ? 0 : 1); scope->level = c->tail->level + (sameFunction ? 0 : 1);
} else { } else {
scope->level = 0; scope->level = 0;
} }
if (sameFunction) { if (sameFunction) {
if (!c->tail) { 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->nextLocal = c->tail->nextLocal;
scope->literals = c->tail->literals; scope->literals = c->tail->literals;
@ -144,17 +144,17 @@ static void CompilerPopScope(Compiler * c) {
CError(c, "No scope to pop."); CError(c, "No scope to pop.");
} else { } else {
if (last->nextLocal > last->frameSize) { if (last->nextLocal > last->frameSize) {
last->frameSize = last->nextLocal; last->frameSize = last->nextLocal;
} }
c->tail = last->previousScope; c->tail = last->previousScope;
if (c->tail) { if (c->tail) {
if (last->frameSize > c->tail->frameSize) { if (last->frameSize > c->tail->frameSize) {
c->tail->frameSize = last->frameSize; c->tail->frameSize = last->frameSize;
} }
c->tail->nextScope = NULL; c->tail->nextScope = NULL;
} else { } else {
/* We deleted the last scope */ /* 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. */ /* Gets a temporary slot for the bottom-most scope. */
static Slot CompilerGetTemp(Compiler * c) { static Slot CompilerGetTemp(Compiler * c) {
Scope * scope = c->tail; Scope * scope = c->tail;
Slot ret; Slot ret;
ret.isTemp = 1; ret.isTemp = 1;
ret.isNil = 0; ret.isNil = 0;
ret.hasReturned = 0; ret.hasReturned = 0;
ret.index = CompilerGetLocal(c, scope); ret.index = CompilerGetLocal(c, scope);
return ret; return ret;
} }
/* Return a slot that is the target Slot given some FormOptions. Will /* 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. */ * Create a temporary slot if needed, so be sure to drop the slot after use. */
static Slot CompilerGetTarget(Compiler * c, FormOptions opts) { static Slot CompilerGetTarget(Compiler * c, FormOptions opts) {
if (opts.canChoose) { if (opts.canChoose) {
return CompilerGetTemp(c); return CompilerGetTemp(c);
} else { } else {
Slot ret; Slot ret;
ret.isTemp = 0; ret.isTemp = 0;
ret.isNil = 0; ret.isNil = 0;
ret.hasReturned = 0; ret.hasReturned = 0;
ret.index = opts.target; ret.index = opts.target;
return ret; return ret;
} }
} }
/* If a slot is a nil slot, create a slot that has /* If a slot is a nil slot, create a slot that has
* an actual location on the stack. */ * an actual location on the stack. */
static Slot CompilerRealizeSlot(Compiler * c, Slot slot) { static Slot CompilerRealizeSlot(Compiler * c, Slot slot) {
if (slot.isNil) { if (slot.isNil) {
slot = CompilerGetTemp(c); slot = CompilerGetTemp(c);
BufferPushUInt16(c->vm, c->buffer, VM_OP_NIL); BufferPushUInt16(c->vm, c->buffer, VM_OP_NIL);
BufferPushUInt16(c->vm, c->buffer, slot.index); BufferPushUInt16(c->vm, c->buffer, slot.index);
} }
return slot; return slot;
} }
/* Helper to get a nil 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 /* Compile a structure that evaluates to a literal value. Useful
* for objects like strings, or anything else that cannot be instatiated else { * 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) { static Slot CompileLiteral(Compiler * c, FormOptions opts, Value x) {
Scope * scope = c->tail; Scope * scope = c->tail;
Buffer * buffer = c->buffer; Buffer * buffer = c->buffer;
@ -569,7 +569,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form,
/* Free up space */ /* Free up space */
CompilerTrackerFree(c, scope, &tracker); CompilerTrackerFree(c, scope, &tracker);
if (opts.resultUnused) { if (opts.resultUnused) {
ret = NilSlot(); ret = NilSlot();
} else { } else {
ret = CompilerGetTarget(c, opts); ret = CompilerGetTarget(c, opts);
/* Write the correct opcode */ /* Write the correct opcode */
@ -669,7 +669,7 @@ static Slot CompileAssign(Compiler * c, FormOptions opts, Value left, Value righ
/* Local variable */ /* Local variable */
subOpts.canChoose = 0; subOpts.canChoose = 0;
subOpts.target = target; subOpts.target = target;
slot = CompileValue(c, subOpts, right); slot = CompileValue(c, subOpts, right);
} }
} else { } else {
/* We need to declare a new symbol */ /* 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])); CompilerDropSlot(c, scope, CompileValue(c, subOpts, form->data[current]));
++current; ++current;
} }
/* Compile the last expression in the body */ /* Compile the last expression in the body */
return CompileValue(c, opts, form->data[form->count - 1]); return CompileValue(c, opts, form->data[form->count - 1]);
} }
/* Extract the last n bytes from the buffer and use them to construct /* 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)); FuncDef * def = VMAlloc(c->vm, sizeof(FuncDef));
/* Create enough space for the new byteCode */ /* Create enough space for the new byteCode */
if (lastNBytes > buffer->count) 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); uint8_t * byteCode = VMAlloc(c->vm, lastNBytes);
def->byteCode = (uint16_t *) byteCode; def->byteCode = (uint16_t *) byteCode;
def->byteCodeLen = lastNBytes / 2; def->byteCodeLen = lastNBytes / 2;
@ -726,9 +726,9 @@ static FuncDef * CompilerGenFuncDef(Compiler * c, uint32_t lastNBytes, uint32_t
if (scope->literalsArray->count) { if (scope->literalsArray->count) {
def->literals = VMAlloc(c->vm, scope->literalsArray->count * sizeof(Value)); def->literals = VMAlloc(c->vm, scope->literalsArray->count * sizeof(Value));
memcpy(def->literals, scope->literalsArray->data, memcpy(def->literals, scope->literalsArray->data,
scope->literalsArray->count * sizeof(Value)); scope->literalsArray->count * sizeof(Value));
} else { } else {
def->literals = NULL; def->literals = NULL;
} }
def->literalsLen = scope->literalsArray->count; def->literalsLen = scope->literalsArray->count;
/* Delete the sub scope */ /* Delete the sub scope */
@ -736,7 +736,7 @@ static FuncDef * CompilerGenFuncDef(Compiler * c, uint32_t lastNBytes, uint32_t
/* Initialize the new FuncDef */ /* Initialize the new FuncDef */
def->locals = scope->frameSize; def->locals = scope->frameSize;
def->arity = arity; def->arity = arity;
return def; return def;
} }
/* Compile a function from a function literal */ /* 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 the condition is nil, just compile false path */
if (condition.isNil) { if (condition.isNil) {
if (form->count == 4) { if (form->count == 4) {
return CompileValue(c, opts, form->data[3]); return CompileValue(c, opts, form->data[3]);
} }
return condition; 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, VM_OP_JIF);
BufferPushUInt16(c->vm, buffer, condition.index); BufferPushUInt16(c->vm, buffer, condition.index);
BufferPushUInt32(c->vm, buffer, 0); BufferPushUInt32(c->vm, buffer, 0);
/* Configure branch form options */ /* Configure branch form options */
branchOpts.canChoose = 0; branchOpts.canChoose = 0;
branchOpts.target = condition.index; branchOpts.target = condition.index;
/* Compile true path */ /* Compile true path */
left = CompileValue(c, branchOpts, form->data[2]); left = CompileValue(c, branchOpts, form->data[2]);
if (opts.isTail) { if (opts.isTail) {
@ -870,21 +870,21 @@ static Slot CompileIf(Compiler * c, FormOptions opts, Array * form) {
/* While special */ /* While special */
static Slot CompileWhile(Compiler * c, FormOptions opts, Array * form) { static Slot CompileWhile(Compiler * c, FormOptions opts, Array * form) {
Slot cond; Slot cond;
uint32_t countAtStart = c->buffer->count; uint32_t countAtStart = c->buffer->count;
uint32_t countAtJumpDelta; uint32_t countAtJumpDelta;
uint32_t countAtFinish; uint32_t countAtFinish;
FormOptions defaultOpts = FormOptionsDefault(); FormOptions defaultOpts = FormOptionsDefault();
CompilerPushScope(c, 1); CompilerPushScope(c, 1);
/* Compile condition */ /* Compile condition */
cond = CompileValue(c, defaultOpts, form->data[1]); cond = CompileValue(c, defaultOpts, form->data[1]);
/* Assert that cond is a real value - otherwise do nothing (nil is false, /* Assert that cond is a real value - otherwise do nothing (nil is false,
* so loop never runs.) */ * so loop never runs.) */
if (cond.isNil) return cond; if (cond.isNil) return cond;
/* Leave space for jump later */ /* Leave space for jump later */
countAtJumpDelta = c->buffer->count; countAtJumpDelta = c->buffer->count;
c->buffer->count += sizeof(uint16_t) * 2 + sizeof(int32_t); c->buffer->count += sizeof(uint16_t) * 2 + sizeof(int32_t);
/* Compile loop body */ /* Compile loop body */
defaultOpts.resultUnused = 1; defaultOpts.resultUnused = 1;
CompilerDropSlot(c, c->tail, CompileBlock(c, defaultOpts, form, 2)); CompilerDropSlot(c, c->tail, CompileBlock(c, defaultOpts, form, 2));
/* Jump back to the loop start */ /* Jump back to the loop start */
countAtFinish = c->buffer->count; countAtFinish = c->buffer->count;
@ -893,16 +893,16 @@ static Slot CompileWhile(Compiler * c, FormOptions opts, Array * form) {
countAtFinish = c->buffer->count; countAtFinish = c->buffer->count;
/* Set the jump to the correct length */ /* Set the jump to the correct length */
c->buffer->count = countAtJumpDelta; c->buffer->count = countAtJumpDelta;
BufferPushUInt16(c->vm, c->buffer, VM_OP_JIF); BufferPushUInt16(c->vm, c->buffer, VM_OP_JIF);
BufferPushUInt16(c->vm, c->buffer, cond.index); BufferPushUInt16(c->vm, c->buffer, cond.index);
BufferPushInt32(c->vm, c->buffer, (int32_t)(countAtFinish - countAtJumpDelta) / 2); BufferPushInt32(c->vm, c->buffer, (int32_t)(countAtFinish - countAtJumpDelta) / 2);
/* Pop scope */ /* Pop scope */
c->buffer->count = countAtFinish; c->buffer->count = countAtFinish;
CompilerPopScope(c); CompilerPopScope(c);
/* Return nil */ /* Return nil */
if (opts.resultUnused) if (opts.resultUnused)
return NilSlot(); return NilSlot();
else else
return cond; return cond;
} }
@ -967,30 +967,30 @@ static SpecialFormHelper GetSpecial(Array * form) {
case '/': return CompileDivision; case '/': return CompileDivision;
case '>': return CompileGreaterThan; case '>': return CompileGreaterThan;
case '<': return CompileLessThan; case '<': return CompileLessThan;
case '=': return CompileEquals; case '=': return CompileEquals;
case '\'': return CompileQuote; case '\'': return CompileQuote;
default: default:
break; break;
} }
} }
/* Multi character specials. Mostly control flow. */ /* Multi character specials. Mostly control flow. */
switch (name[0]) { switch (name[0]) {
case '>': case '>':
{ {
if (VStringSize(name) == 2 && if (VStringSize(name) == 2 &&
name[1] == '=') { name[1] == '=') {
return CompileGreaterThanOrEqual; return CompileGreaterThanOrEqual;
} }
} }
break; break;
case '<': case '<':
{ {
if (VStringSize(name) == 2 && if (VStringSize(name) == 2 &&
name[1] == '=') { name[1] == '=') {
return CompileLessThanOrEqual; return CompileLessThanOrEqual;
} }
} }
break; break;
case 'd': case 'd':
{ {
if (VStringSize(name) == 2 && if (VStringSize(name) == 2 &&
@ -1015,14 +1015,14 @@ static SpecialFormHelper GetSpecial(Array * form) {
} }
} }
break; break;
case 'n': case 'n':
{ {
if (VStringSize(name) == 3 && if (VStringSize(name) == 3 &&
name[1] == 'o' && name[1] == 'o' &&
name[2] == 't') { name[2] == 't') {
return CompileNot; return CompileNot;
} }
} }
case 'q': case 'q':
{ {
if (VStringSize(name) == 5 && if (VStringSize(name) == 5 &&
@ -1030,7 +1030,7 @@ static SpecialFormHelper GetSpecial(Array * form) {
name[2] == 'o' && name[2] == 'o' &&
name[3] == 't' && name[3] == 't' &&
name[4] == 'e') { name[4] == 'e') {
return CompileQuote; return CompileQuote;
} }
} }
break; break;
@ -1044,15 +1044,15 @@ static SpecialFormHelper GetSpecial(Array * form) {
} }
break; break;
case 'w': case 'w':
{ {
if (VStringSize(name) == 5 && if (VStringSize(name) == 5 &&
name[1] == 'h' && name[1] == 'h' &&
name[2] == 'i' && name[2] == 'i' &&
name[3] == 'l' && name[3] == 'l' &&
name[4] == 'e') { name[4] == 'e') {
return CompileWhile; return CompileWhile;
} }
} }
default: default:
break; break;
} }
@ -1149,10 +1149,10 @@ void CompilerAddGlobal(Compiler * c, const char * name, Value x) {
/* Register a global c function for the compilation environment. */ /* Register a global c function for the compilation environment. */
void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f) { void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f) {
Value func; Value func;
func.type = TYPE_CFUNCTION; func.type = TYPE_CFUNCTION;
func.data.cfunction = f; func.data.cfunction = f;
return CompilerAddGlobal(c, name, func); return CompilerAddGlobal(c, name, func);
} }
/* Compile interface. Returns a function that evaluates the /* Compile interface. Returns a function that evaluates the
@ -1185,3 +1185,27 @@ Func * CompilerCompile(Compiler * c, Value form) {
return func; 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;
}

View File

@ -15,4 +15,10 @@ void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f);
/* Compile a function that evaluates the given form. */ /* Compile a function that evaluates the given form. */
Func * CompilerCompile(Compiler * c, Value 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 */ #endif /* end of include guard: COMPILE_H_9VXF71HY */

View File

@ -127,10 +127,11 @@ struct VM {
uint16_t * pc; uint16_t * pc;
Array * thread; Array * thread;
Value * base; Value * base;
Value root; /* Global state - prevents GC cleanup */
/* Return state */ /* Return state */
const char * error; const char * error;
jmp_buf jump; jmp_buf jump;
Value tempRoot; /* Temporary GC root */ Value ret; /* Returned value from VMStart */
}; };
/* Parsing */ /* Parsing */

161
main.c
View File

@ -1,7 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "datatypes.h" #include "datatypes.h"
#include "gc.h"
#include "vm.h" #include "vm.h"
#include "parse.h" #include "parse.h"
#include "compile.h" #include "compile.h"
@ -10,100 +9,98 @@
/* Test c function */ /* Test c function */
Value print(VM * vm) { Value print(VM * vm) {
uint32_t i, j, count; uint32_t i, j, count;
Value nil; Value nil;
count = VMCountArgs(vm); count = VMCountArgs(vm);
for (j = 0; j < count; ++j) { for (j = 0; j < count; ++j) {
uint8_t * string = ValueToString(vm, VMGetArg(vm, j)); uint8_t * string = ValueToString(vm, VMGetArg(vm, j));
uint32_t len = VStringSize(string); uint32_t len = VStringSize(string);
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
fputc(string[i], stdout); fputc(string[i], stdout);
fputc('\n', stdout); fputc('\n', stdout);
} }
nil.type = TYPE_NIL; nil.type = TYPE_NIL;
return nil; return nil;
} }
/* A simple repl for debugging */ /* A simple repl for debugging */
void debugRepl() { void debugRepl() {
char buffer[128] = {0}; char buffer[128] = {0};
const char * reader = buffer; const char * reader = buffer;
Func * func; Value func;
VM vm; VM vm;
Parser p; Parser p;
Compiler c; Compiler c;
VMInit(&vm); VMInit(&vm);
for (;;) { for (;;) {
/* Run garbage collection */ /* Run garbage collection */
VMMaybeCollect(&vm); VMMaybeCollect(&vm);
/* Reset state */ /* Reset state */
ParserInit(&p, &vm); ParserInit(&p, &vm);
/* Get and parse input until we have a full form */ /* Get and parse input until we have a full form */
while (p.status == PARSER_PENDING) { while (p.status == PARSER_PENDING) {
/* Get some input if we are done */ /* Get some input if we are done */
if (*reader == '\0') { if (*reader == '\0') {
printf("> "); printf("> ");
if (!fgets(buffer, sizeof(buffer), stdin)) { if (!fgets(buffer, sizeof(buffer), stdin)) {
return; 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");
} }
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() { int main() {
printf("Super cool interpreter v0.0\n"); printf("Super cool interpreter v0.0\n");
debugRepl(); debugRepl();
} }

24
parse.c
View File

@ -128,16 +128,16 @@ static int isWhitespace(uint8_t c) {
/* Check if a character is a valid symbol character */ /* Check if a character is a valid symbol character */
static int isSymbolChar(uint8_t c) { static int isSymbolChar(uint8_t c) {
if (c >= 'a' && c <= 'z') return 1; if (c >= 'a' && c <= 'z') return 1;
if (c >= 'A' && c <= 'Z') return 1; if (c >= 'A' && c <= 'Z') return 1;
if (c >= '0' && c <= '9') 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 >= '*' && 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; if (c == '^') return 1;
if (c == '!') return 1; if (c == '!') return 1;
return 0; return 0;
} }
/* Get an integer power of 10 */ /* Get an integer power of 10 */
@ -308,8 +308,8 @@ static int ParserStringState(Parser * p, uint8_t c) {
case '\'': next = '\''; break; case '\'': next = '\''; break;
case 'z': next = '\0'; break; case 'z': next = '\0'; break;
default: default:
PError(p, "Unknown string escape sequence."); PError(p, "Unknown string escape sequence.");
return 1; return 1;
} }
BufferPush(p->vm, top->buf.string.buffer, next); BufferPush(p->vm, top->buf.string.buffer, next);
top->buf.string.state = STRING_STATE_BASE; top->buf.string.state = STRING_STATE_BASE;

42
value.c
View File

@ -9,14 +9,14 @@
static void FuncDefBytecodePrint(FuncDef * def) { static void FuncDefBytecodePrint(FuncDef * def) {
uint32_t count, i; uint32_t count, i;
count = def->byteCodeLen; count = def->byteCodeLen;
printf("(bytecode)["); printf("(bytecode)[");
if (count) { if (count) {
for (i = 0; i < count - 1; ++i) { for (i = 0; i < count - 1; ++i) {
printf("%04x ", def->byteCode[i]); printf("%04x ", def->byteCode[i]);
} }
printf("%04x", def->byteCode[i]); printf("%04x", def->byteCode[i]);
} }
printf("]"); printf("]");
} }
/* Print a value recursively. Used for debugging */ /* Print a value recursively. Used for debugging */
@ -55,8 +55,8 @@ void ValuePrint(Value x, uint32_t indent) {
break; break;
case TYPE_FUNCTION: case TYPE_FUNCTION:
printf("<function "); printf("<function ");
FuncDefBytecodePrint(x.data.func->def); FuncDefBytecodePrint(x.data.func->def);
printf(">"); printf(">");
break; break;
case TYPE_DICTIONARY: case TYPE_DICTIONARY:
printf("<dictionary>"); printf("<dictionary>");
@ -66,8 +66,8 @@ void ValuePrint(Value x, uint32_t indent) {
break; break;
case TYPE_FUNCDEF: case TYPE_FUNCDEF:
printf("<funcdef "); printf("<funcdef ");
FuncDefBytecodePrint(x.data.funcdef); FuncDefBytecodePrint(x.data.funcdef);
printf(">"); printf(">");
break; break;
case TYPE_FUNCENV: case TYPE_FUNCENV:
printf("<funcenv>"); printf("<funcenv>");
@ -197,10 +197,10 @@ int ValueEqual(Value x, Value y) {
case TYPE_NUMBER: case TYPE_NUMBER:
result = (x.data.number == y.data.number); result = (x.data.number == y.data.number);
break; break;
/* Assume that when strings are created, equal strings /* Assume that when strings are created, equal strings
* are set to the same string */ * are set to the same string */
case TYPE_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: case TYPE_SYMBOL:
if (x.data.string == y.data.string) { if (x.data.string == y.data.string) {
result = 1; result = 1;
@ -274,12 +274,12 @@ uint32_t ValueHash(Value x) {
case TYPE_THREAD: case TYPE_THREAD:
/* Cast the pointer */ /* Cast the pointer */
{ {
union { union {
void * pointer; void * pointer;
uint32_t hash; uint32_t hash;
} u; } u;
u.pointer = x.data.pointer; u.pointer = x.data.pointer;
hash = u.hash; hash = u.hash;
} }
break; break;
} }

304
vm.c
View File

@ -15,21 +15,19 @@ static const char VMS_EXPECTED_NUMBER_LOP[] = "Expected left operand to be numbe
typedef struct StackFrame StackFrame; typedef struct StackFrame StackFrame;
struct StackFrame { struct StackFrame {
Value callee; Value callee;
uint16_t size; uint16_t size;
uint16_t prevSize; uint16_t prevSize;
uint16_t ret; uint16_t ret;
FuncEnv * env; FuncEnv * env;
uint16_t * pc; uint16_t * pc;
}; };
/* The size of a StackFrame in units of Values. */ /* The size of a StackFrame in units of Values. */
static size_t FRAME_SIZE() { #define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value))
return ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value));
}
/* Get the stack frame pointer for a thread */ /* Get the stack frame pointer for a thread */
static StackFrame * ThreadFrame(Array * 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 */ /* 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)->color = vm->black;
GCHeader(x->data.array->data)->color = vm->black; GCHeader(x->data.array->data)->color = vm->black;
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
VMMark(vm, x->data.array->data + i); VMMark(vm, x->data.array->data + i);
} }
break; break;
@ -102,19 +100,19 @@ static void VMMark(VM * vm, Value * x) {
uint32_t i; uint32_t i;
Array * thread = x->data.array; Array * thread = x->data.array;
StackFrame * frame = (StackFrame *)thread->data; 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)->color = vm->black;
GCHeader(thread->data)->color = vm->black; GCHeader(thread->data)->color = vm->black;
while (frame <= end) { while (frame <= end) {
Value * stack = (Value *)frame + FRAME_SIZE(); Value * stack = (Value *)frame + FRAME_SIZE;
VMMark(vm, &frame->callee); VMMark(vm, &frame->callee);
if (frame->env) if (frame->env)
VMMarkFuncEnv(vm, frame->env); VMMarkFuncEnv(vm, frame->env);
for (i = 0; i < frame->size; ++i) { for (i = 0; i < frame->size; ++i) {
VMMark(vm, stack + i); VMMark(vm, stack + i);
} }
frame = (StackFrame *)(stack + frame->size); frame = (StackFrame *)(stack + frame->size);
} }
} }
break; break;
@ -165,9 +163,9 @@ static void VMMark(VM * vm, Value * x) {
} }
break; break;
case TYPE_FUNCENV: case TYPE_FUNCENV:
VMMarkFuncEnv(vm, x->data.funcenv); VMMarkFuncEnv(vm, x->data.funcenv);
break; break;
} }
@ -224,20 +222,23 @@ void * VMZalloc(VM * vm, uint32_t size) {
/* Run garbage collection */ /* Run garbage collection */
void VMCollect(VM * vm) { void VMCollect(VM * vm) {
if (vm->lock > 0) return; if (vm->lock > 0) return;
Value thread; /* Thread can be null */
thread.type = TYPE_THREAD; if (vm->thread) {
thread.data.array = vm->thread; Value thread;
VMMark(vm, &thread); thread.type = TYPE_THREAD;
VMMark(vm, &vm->tempRoot); thread.data.array = vm->thread;
VMMark(vm, &thread);
}
VMMark(vm, &vm->ret);
VMMark(vm, &vm->root);
VMSweep(vm); VMSweep(vm);
vm->nextCollection = 0; vm->nextCollection = 0;
} }
/* Run garbage collection if needed */ /* Run garbage collection if needed */
void VMMaybeCollect(VM * vm) { void VMMaybeCollect(VM * vm) {
if (vm->nextCollection >= vm->memoryInterval) { if (vm->nextCollection >= vm->memoryInterval)
VMCollect(vm); VMCollect(vm);
}
} }
/* Push a stack frame onto a thread */ /* 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; uint16_t oldSize;
uint32_t nextCount, i; uint32_t nextCount, i;
StackFrame * frame; StackFrame * frame;
if (thread->count) { if (thread->count) {
frame = ThreadFrame(thread); frame = ThreadFrame(thread);
oldSize = frame->size; oldSize = frame->size;
} else { } else {
oldSize = 0; oldSize = 0;
} }
nextCount = thread->count + oldSize + FRAME_SIZE(); nextCount = thread->count + oldSize + FRAME_SIZE;
ArrayEnsure(vm, thread, nextCount + size); ArrayEnsure(vm, thread, nextCount + size);
thread->count = nextCount; thread->count = nextCount;
/* Ensure values start out as nil so as to not confuse /* Ensure values start out as nil so as to not confuse
* the garabage collector */ * the garabage collector */
for (i = nextCount; i < nextCount + size; ++i) for (i = nextCount; i < nextCount + size; ++i)
thread->data[i].type = TYPE_NIL; thread->data[i].type = TYPE_NIL;
frame = ThreadFrame(thread); frame = ThreadFrame(thread);
/* Set up the new stack frame */ /* Set up the new stack frame */
frame->prevSize = oldSize; frame->prevSize = oldSize;
@ -271,28 +272,28 @@ static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) {
environment */ environment */
static void VMThreadSplitStack(VM * vm, Array * thread) { static void VMThreadSplitStack(VM * vm, Array * thread) {
StackFrame * frame = ThreadFrame(thread); StackFrame * frame = ThreadFrame(thread);
FuncEnv * env = frame->env; FuncEnv * env = frame->env;
/* Check for closures */ /* Check for closures */
if (env) { if (env) {
uint32_t size = frame->size; uint32_t size = frame->size;
env->thread = NULL; env->thread = NULL;
env->stackOffset = size; env->stackOffset = size;
env->values = VMAlloc(vm, sizeof(Value) * size); env->values = VMAlloc(vm, sizeof(Value) * size);
memcpy(env->values, thread->data + thread->count, size * sizeof(Value)); memcpy(env->values, thread->data + thread->count, size * sizeof(Value));
} }
} }
/* Pop the top-most stack frame from stack */ /* Pop the top-most stack frame from stack */
static void VMThreadPop(VM * vm, Array * thread) { static void VMThreadPop(VM * vm, Array * thread) {
StackFrame * frame = ThreadFrame(thread); StackFrame * frame = ThreadFrame(thread);
uint32_t delta = FRAME_SIZE() + frame->prevSize; uint32_t delta = FRAME_SIZE + frame->prevSize;
if (thread->count) { if (thread->count) {
VMThreadSplitStack(vm, thread); VMThreadSplitStack(vm, thread);
} else { } else {
VMError(vm, "Nothing to pop from stack."); VMError(vm, "Nothing to pop from stack.");
} }
thread->count -= delta; thread->count -= delta;
vm->base -= delta; vm->base -= delta;
} }
/* Get an upvalue */ /* Get an upvalue */
@ -300,7 +301,7 @@ static Value * GetUpValue(VM * vm, Func * fn, uint16_t level, uint16_t index) {
FuncEnv * env; FuncEnv * env;
Value * stack; Value * stack;
if (!level) { if (!level) {
return vm->base + index; return vm->base + index;
} }
while (fn && --level) while (fn && --level)
fn = fn->parent; fn = fn->parent;
@ -330,7 +331,7 @@ static int truthy(Value v) {
static void VMReturn(VM * vm, Value ret) { static void VMReturn(VM * vm, Value ret) {
Array * thread = vm->thread; Array * thread = vm->thread;
StackFrame * frame = ThreadFrame(thread); StackFrame * frame = ThreadFrame(thread);
VMThreadPop(vm, thread); VMThreadPop(vm, thread);
if (thread->count == 0) { if (thread->count == 0) {
VMExit(vm, ret); VMExit(vm, ret);
} }
@ -348,7 +349,7 @@ static void VMCallOp(VM * vm) {
uint32_t oldCount = thread->count; uint32_t oldCount = thread->count;
uint32_t i; uint32_t i;
Value * oldBase; Value * oldBase;
frame->pc = vm->pc + 4 + arity; frame->pc = vm->pc + 4 + arity;
frame->ret = vm->pc[2]; frame->ret = vm->pc[2];
if (callee.type == TYPE_FUNCTION) { if (callee.type == TYPE_FUNCTION) {
Func * fn = callee.data.func; Func * fn = callee.data.func;
@ -365,15 +366,15 @@ static void VMCallOp(VM * vm) {
++vm->lock; ++vm->lock;
VMReturn(vm, callee.data.cfunction(vm)); VMReturn(vm, callee.data.cfunction(vm));
--vm->lock; --vm->lock;
} else { } else {
Func * f = callee.data.func; Func * f = callee.data.func;
uint32_t locals = f->def->locals; uint32_t locals = f->def->locals;
for (i = 0; i < arity; ++i) for (i = 0; i < arity; ++i)
vm->base[i] = oldBase[vm->pc[4 + i]]; vm->base[i] = oldBase[vm->pc[4 + i]];
for (; i < locals; ++i) for (; i < locals; ++i)
vm->base[i].type = TYPE_NIL; vm->base[i].type = TYPE_NIL;
vm->pc = f->def->byteCode; vm->pc = f->def->byteCode;
} }
VMMaybeCollect(vm); VMMaybeCollect(vm);
} }
@ -386,42 +387,42 @@ static void VMTailCallOp(VM * vm) {
uint16_t newFrameSize, currentFrameSize; uint16_t newFrameSize, currentFrameSize;
uint32_t i; uint32_t i;
/* Check for closures */ /* Check for closures */
VMThreadSplitStack(vm, thread); VMThreadSplitStack(vm, thread);
if (callee.type == TYPE_CFUNCTION) { if (callee.type == TYPE_CFUNCTION) {
newFrameSize = arity; newFrameSize = arity;
} else if (callee.type == TYPE_FUNCTION) { } else if (callee.type == TYPE_FUNCTION) {
Func * f = callee.data.func; Func * f = callee.data.func;
newFrameSize = f->def->locals; newFrameSize = f->def->locals;
} else { } else {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
} }
/* Ensure stack has enough space for copies of arguments */ /* Ensure stack has enough space for copies of arguments */
currentFrameSize = frame->size; currentFrameSize = frame->size;
ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity);
frame = ThreadFrame(thread); frame = ThreadFrame(thread);
vm->base = thread->data + thread->count; vm->base = thread->data + thread->count;
/* Copy the arguments into the extra space */ /* Copy the arguments into the extra space */
for (i = 0; i < arity; ++i) { 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 */ /* Copy the end of the stack to the parameter position */
memcpy(vm->base, vm->base + currentFrameSize, arity * sizeof(Value)); 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) { for (i = arity; i < newFrameSize; ++i) {
vm->base[i].type = TYPE_NIL; vm->base[i].type = TYPE_NIL;
} }
/* Update the stack frame */ /* Update the stack frame */
frame->size = newFrameSize; frame->size = newFrameSize;
frame->callee = callee; frame->callee = callee;
frame->env = NULL; frame->env = NULL;
if (callee.type == TYPE_CFUNCTION) { if (callee.type == TYPE_CFUNCTION) {
++vm->lock; ++vm->lock;
VMReturn(vm, callee.data.cfunction(vm)); VMReturn(vm, callee.data.cfunction(vm));
--vm->lock; --vm->lock;
} else { } else {
Func * f = callee.data.func; Func * f = callee.data.func;
vm->pc = f->def->byteCode; vm->pc = f->def->byteCode;
} }
VMMaybeCollect(vm); VMMaybeCollect(vm);
} }
@ -440,7 +441,7 @@ static Value VMMakeClosure(VM * vm, uint16_t literal) {
env->thread = thread; env->thread = thread;
env->stackOffset = thread->count; env->stackOffset = thread->count;
env->values = NULL; env->values = NULL;
frame->env = env; frame->env = env;
} }
current = frame->callee.data.func; current = frame->callee.data.func;
constant = LoadConstant(vm, current, literal); constant = LoadConstant(vm, current, literal);
@ -482,29 +483,29 @@ int VMStart(VM * vm) {
Value temp, v1, v2; Value temp, v1, v2;
#define DO_BINARY_MATH(op) \ #define DO_BINARY_MATH(op) \
v1 = vm->base[vm->pc[2]]; \ v1 = vm->base[vm->pc[2]]; \
v2 = vm->base[vm->pc[3]]; \ v2 = vm->base[vm->pc[3]]; \
VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \ VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \
VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \ VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \
temp.type = TYPE_NUMBER; \ temp.type = TYPE_NUMBER; \
temp.data.number = v1.data.number op v2.data.number; \ temp.data.number = v1.data.number op v2.data.number; \
vm->base[vm->pc[1]] = temp; \ vm->base[vm->pc[1]] = temp; \
vm->pc += 4; \ vm->pc += 4; \
break; break;
case VM_OP_ADD: /* Addition */ case VM_OP_ADD: /* Addition */
DO_BINARY_MATH(+) DO_BINARY_MATH(+)
case VM_OP_SUB: /* Subtraction */ case VM_OP_SUB: /* Subtraction */
DO_BINARY_MATH(-) DO_BINARY_MATH(-)
case VM_OP_MUL: /* Multiplication */ case VM_OP_MUL: /* Multiplication */
DO_BINARY_MATH(*) DO_BINARY_MATH(*)
case VM_OP_DIV: /* Division */ 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) */ case VM_OP_NOT: /* Boolean unary (Boolean not) */
temp.type = TYPE_BOOLEAN; temp.type = TYPE_BOOLEAN;
@ -528,22 +529,22 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_FLS: /* Load False */ case VM_OP_FLS: /* Load False */
temp.type = TYPE_BOOLEAN; temp.type = TYPE_BOOLEAN;
temp.data.boolean = 0; temp.data.boolean = 0;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_TRU: /* Load True */ case VM_OP_TRU: /* Load True */
temp.type = TYPE_BOOLEAN; temp.type = TYPE_BOOLEAN;
temp.data.boolean = 1; temp.data.boolean = 1;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_NIL: /* Load Nil */ case VM_OP_NIL: /* Load Nil */
temp.type = TYPE_NIL; temp.type = TYPE_NIL;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
@ -578,7 +579,7 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_RET: /* Return */ case VM_OP_RET: /* Return */
VMReturn(vm, vm->base[vm->pc[1]]); VMReturn(vm, vm->base[vm->pc[1]]);
break; break;
case VM_OP_SUV: /* Set Up Value */ case VM_OP_SUV: /* Set Up Value */
@ -641,46 +642,46 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_ARR: /* Array literal */ case VM_OP_ARR: /* Array literal */
{ {
uint32_t i; uint32_t i;
uint32_t arrayLen = vm->pc[2]; uint32_t arrayLen = vm->pc[2];
Array * array = ArrayNew(vm, arrayLen); Array * array = ArrayNew(vm, arrayLen);
array->count = arrayLen; array->count = arrayLen;
for (i = 0; i < arrayLen; ++i) for (i = 0; i < arrayLen; ++i)
array->data[i] = vm->base[vm->pc[3 + i]]; array->data[i] = vm->base[vm->pc[3 + i]];
temp.type = TYPE_ARRAY; temp.type = TYPE_ARRAY;
temp.data.array = array; temp.data.array = array;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += 3 + arrayLen; vm->pc += 3 + arrayLen;
VMMaybeCollect(vm); VMMaybeCollect(vm);
} }
break; break;
case VM_OP_DIC: /* Dictionary literal */ case VM_OP_DIC: /* Dictionary literal */
{ {
uint32_t i = 3; uint32_t i = 3;
uint32_t kvs = vm->pc[2]; uint32_t kvs = vm->pc[2];
Dictionary * dict = DictNew(vm, kvs); Dictionary * dict = DictNew(vm, kvs);
kvs = kvs + 3; kvs = kvs + 3;
while (i < kvs) { while (i < kvs) {
v1 = vm->base[vm->pc[i++]]; v1 = vm->base[vm->pc[i++]];
v2 = 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.type = TYPE_DICTIONARY;
temp.data.dict = dict; temp.data.dict = dict;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += kvs; vm->pc += kvs;
VMMaybeCollect(vm); VMMaybeCollect(vm);
} }
break; break;
case VM_OP_TCL: /* Tail call */ case VM_OP_TCL: /* Tail call */
VMTailCallOp(vm); VMTailCallOp(vm);
break; break;
/* Macro for generating some math operators */ /* 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 count = vm->pc[2]; \
uint16_t i; \ uint16_t i; \
Number accum = start; \ Number accum = start; \
@ -709,7 +710,7 @@ int VMStart(VM * vm) {
case VM_OP_DVM: case VM_OP_DVM:
DO_MULTI_MATH(/, 1) DO_MULTI_MATH(/, 1)
#undef DO_MULTI_MATH #undef DO_MULTI_MATH
case VM_OP_RTN: /* Return nil */ case VM_OP_RTN: /* Return nil */
temp.type = TYPE_NIL; temp.type = TYPE_NIL;
@ -731,14 +732,14 @@ int VMStart(VM * vm) {
Value VMGetArg(VM * vm, uint16_t index) { Value VMGetArg(VM * vm, uint16_t index) {
uint16_t frameSize = ThreadFrame(vm->thread)->size; uint16_t frameSize = ThreadFrame(vm->thread)->size;
VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); 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 */ /* Put a value on the stack */
void VMSetArg(VM * vm, uint16_t index, Value x) { void VMSetArg(VM * vm, uint16_t index, Value x) {
uint16_t frameSize = ThreadFrame(vm->thread)->size; uint16_t frameSize = ThreadFrame(vm->thread)->size;
VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); 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 */ /* Get the size of the VMStack */
@ -748,29 +749,36 @@ uint16_t VMCountArgs(VM * vm) {
/* Initialize the VM */ /* Initialize the VM */
void VMInit(VM * vm) { void VMInit(VM * vm) {
vm->tempRoot.type = TYPE_NIL; vm->ret.type = TYPE_NIL;
vm->root.type = TYPE_NIL;
vm->base = NULL; vm->base = NULL;
vm->pc = NULL; vm->pc = NULL;
vm->error = NULL; vm->error = NULL;
/* Garbage collection */ /* Garbage collection */
vm->blocks = NULL; vm->blocks = NULL;
vm->nextCollection = 0; vm->nextCollection = 0;
vm->memoryInterval = 1024 * 256; vm->memoryInterval = 0;
vm->black = 0; vm->black = 0;
vm->lock = 0; vm->lock = 0;
/* Create new thread */ /* Set to empty thread */
vm->thread = ArrayNew(vm, 32); vm->thread = NULL;
} }
/* Load a function into the VM. The function will be called with /* Load a function into the VM. The function will be called with
* no arguments when run */ * no arguments when run */
void VMLoad(VM * vm, Func * func) { void VMLoad(VM * vm, Value func) {
Value callee; Array * thread = ArrayNew(vm, 100);
callee.type = TYPE_FUNCTION; vm->thread = thread;
callee.data.func = func; if (func.type == TYPE_FUNCTION) {
vm->thread = ArrayNew(vm, 32); Func * fn = func.data.func;
VMThreadPush(vm, vm->thread, callee, func->def->locals); VMThreadPush(vm, thread, func, fn->def->locals);
vm->pc = func->def->byteCode; 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 */ /* Clear all memory associated with the VM */

11
vm.h
View File

@ -4,7 +4,7 @@
#include "datatypes.h" #include "datatypes.h"
/* Exit from the VM normally */ /* 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. */ /* Bail from the VM with an error. */
#define VMError(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2)) #define VMError(vm, e) ((vm)->error = (e), longjmp((vm)->jump, 2))
@ -16,6 +16,10 @@
#define VMAssert(vm, cond, e) do \ #define VMAssert(vm, cond, e) do \
{ if (!(cond)) { VMError((vm), (e)); } } while (0) { 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 */ /* Initialize the VM */
void VMInit(VM * vm); void VMInit(VM * vm);
@ -23,14 +27,11 @@ void VMInit(VM * vm);
void VMDeinit(VM * vm); void VMDeinit(VM * vm);
/* Load a function to be run on the 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 */ /* Start running the VM */
int VMStart(VM * vm); int VMStart(VM * vm);
/* Get the result after VMStart returns */
#define VMResult(vm) ((vm)->tempRoot)
/* Run garbage collection */ /* Run garbage collection */
void VMCollect(VM * vm); void VMCollect(VM * vm);