Make blocks callable.

This commit is contained in:
Bob Nystrom
2013-10-24 13:01:24 -07:00
parent 911f586e7b
commit 2f930f727e
5 changed files with 66 additions and 14 deletions

View File

@ -1,6 +1,6 @@
{
123
var a = {
var b = 234
3
b
}
var a = 123
var b = 345
a
a.call

View File

@ -110,8 +110,15 @@ static void consume(Compiler* compiler, TokenType expected);
static void advance(Parser* parser);
// Tokens:
// Lex the next token in the source file and store it in parser.current. Omits
// newlines that aren't meaningful.
static void readNextToken(Parser* parser);
// Lex the next token and store it in parser.current. Does not do any newline
// filtering.
static void readRawToken(Parser* parser);
static void readName(Parser* parser);
static void readNumber(Parser* parser);
static void readString(Parser* parser);

View File

@ -27,9 +27,14 @@ int main(int argc, const char * argv[])
char* source = readFile(argv[1], &length);
VM* vm = newVM();
ObjBlock* block = compile(vm, source, length);
Value value = interpret(vm, block);
printValue(value);
printf("\n");
if (block)
{
Value value = interpret(vm, block);
printValue(value);
printf("\n");
}
freeVM(vm);
free(source);

View File

@ -4,6 +4,13 @@
#include "vm.h"
#define PRIMITIVE(cls, prim) \
{ \
int symbol = ensureSymbol(&vm->symbols, #prim, strlen(#prim)); \
vm->cls##Class->methods[symbol].type = METHOD_PRIMITIVE; \
vm->cls##Class->methods[symbol].primitive = primitive_##cls##_##prim; \
}
typedef struct
{
// Index of the current (really next-to-be-executed) instruction in the
@ -29,17 +36,26 @@ typedef struct
static void callBlock(Fiber* fiber, ObjBlock* block, int firstLocal);
static void push(Fiber* fiber, Value value);
static Value pop(Fiber* fiber);
static Value primitiveNumAbs(Value number);
static Value primitive_num_abs(Value block);
VM* newVM()
{
VM* vm = malloc(sizeof(VM));
initSymbolTable(&vm->symbols);
vm->blockClass = makeClass();
// The call method is special: neither a primitive nor a user-defined one.
// This is because it mucks with the fiber itself.
{
int symbol = ensureSymbol(&vm->symbols, "call", strlen("call"));
vm->blockClass->methods[symbol].type = METHOD_CALL;
}
vm->classClass = makeClass();
vm->numClass = makeClass();
int symbol = ensureSymbol(&vm->symbols, "abs", 3);
vm->numClass->methods[symbol].type = METHOD_PRIMITIVE;
vm->numClass->methods[symbol].primitive = primitiveNumAbs;
PRIMITIVE(num, abs);
return vm;
}
@ -198,7 +214,22 @@ Value interpret(VM* vm, ObjBlock* block)
int symbol = frame->block->bytecode[frame->ip++];
// TODO(bob): Support classes for other object types.
ObjClass* classObj = vm->numClass;
ObjClass* classObj;
switch (receiver->type)
{
case OBJ_BLOCK:
classObj = vm->blockClass;
break;
case OBJ_CLASS:
classObj = vm->classClass;
break;
case OBJ_NUM:
classObj = vm->numClass;
break;
}
Method* method = &classObj->methods[symbol];
switch (method->type)
{
@ -208,6 +239,11 @@ Value interpret(VM* vm, ObjBlock* block)
exit(1);
break;
case METHOD_CALL:
// TODO(bob): Should pass in correct index for locals.
callBlock(&fiber, (ObjBlock*)receiver, fiber.stackSize);
break;
case METHOD_PRIMITIVE:
push(&fiber, method->primitive(receiver));
break;
@ -282,7 +318,7 @@ Value pop(Fiber* fiber)
return fiber->stack[--fiber->stackSize];
}
Value primitiveNumAbs(Value number)
Value primitive_num_abs(Value number)
{
double value = ((ObjNum*)number)->value;
if (value < 0) value = -value;

View File

@ -46,6 +46,7 @@ typedef Value (*Primitive)(Value receiver);
typedef enum
{
METHOD_NONE,
METHOD_CALL,
METHOD_PRIMITIVE,
METHOD_BLOCK
} MethodType;
@ -105,6 +106,9 @@ typedef struct
typedef struct
{
SymbolTable symbols;
ObjClass* blockClass;
ObjClass* classClass;
ObjClass* numClass;
} VM;