1
0
forked from Mirror/wren

Method calls.

This commit is contained in:
Bob Nystrom
2013-10-24 21:32:17 -07:00
parent 2f930f727e
commit 32f8c412c7
4 changed files with 139 additions and 23 deletions

View File

@ -1,6 +1,7 @@
var a = {
var b = 234
3
b
class Foo {
bar {
123
}
}
a.call
var a = Foo.new
a.bar

View File

@ -97,6 +97,7 @@ typedef struct sCompiler
static ObjBlock* compileBlock(Parser* parser, Compiler* parent,
TokenType endToken);
static int addConstant(Compiler* compiler, Value constant);
// Grammar:
static void statement(Compiler* compiler);
@ -185,6 +186,12 @@ ObjBlock* compileBlock(Parser* parser, Compiler* parent, TokenType endToken)
return parser->hasError ? NULL : compiler.block;
}
int addConstant(Compiler* compiler, Value constant)
{
compiler->block->constants[compiler->block->numConstants++] = constant;
return compiler->block->numConstants - 1;
}
void statement(Compiler* compiler)
{
if (match(compiler, TOKEN_CLASS))
@ -215,13 +222,20 @@ void statement(Compiler* compiler)
{
// Method name.
consume(compiler, TOKEN_NAME);
//int symbol = internSymbol(compiler);
int symbol = internSymbol(compiler);
consume(compiler, TOKEN_LEFT_BRACE);
// TODO(bob): Parse body.
consume(compiler, TOKEN_RIGHT_BRACE);
ObjBlock* method = compileBlock(compiler->parser, compiler,
TOKEN_RIGHT_BRACE);
consume(compiler, TOKEN_LINE);
// Add the block to the constant table.
int constant = addConstant(compiler, (Value)method);
// Compile the code to define the method it.
emit(compiler, CODE_METHOD);
emit(compiler, symbol);
emit(compiler, constant);
}
return;
@ -335,14 +349,11 @@ void number(Compiler* compiler)
}
// Define a constant for the literal.
// TODO(bob): See if constant with same value already exists.
Value constant = (Value)makeNum((double)value);
compiler->block->constants[compiler->block->numConstants++] = constant;
int constant = addConstant(compiler, (Value)makeNum((double)value));
// Compile the code to load the constant.
emit(compiler, CODE_CONSTANT);
emit(compiler, compiler->block->numConstants - 1);
emit(compiler, constant);
}
TokenType peek(Compiler* compiler)

101
src/vm.c
View File

@ -36,7 +36,8 @@ 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 primitive_num_abs(Value block);
static Value primitive_metaclass_new(Value receiver);
static Value primitive_num_abs(Value receiver);
VM* newVM()
{
@ -66,7 +67,7 @@ void freeVM(VM* vm)
free(vm);
}
ObjClass* makeClass()
ObjClass* makeSingleClass()
{
ObjClass* obj = malloc(sizeof(ObjClass));
obj->obj.type = OBJ_CLASS;
@ -80,6 +81,17 @@ ObjClass* makeClass()
return obj;
}
ObjClass* makeClass()
{
ObjClass* classObj = makeSingleClass();
// Make its metaclass.
// TODO(bob): What is the metaclass's metaclass?
classObj->metaclass = makeSingleClass();
return classObj;
}
ObjBlock* makeBlock()
{
ObjBlock* block = malloc(sizeof(ObjBlock));
@ -97,6 +109,16 @@ ObjNum* makeNum(double number)
return num;
}
ObjInstance* makeInstance(ObjClass* classObj)
{
ObjInstance* instance = malloc(sizeof(ObjInstance));
instance->obj.type = OBJ_INSTANCE;
instance->obj.flags = 0;
instance->classObj = classObj;
return instance;
}
void initSymbolTable(SymbolTable* symbols)
{
symbols->count = 0;
@ -150,6 +172,11 @@ int findSymbol(SymbolTable* symbols, const char* name, size_t length)
return -1;
}
const char* getSymbolName(SymbolTable* symbols, int symbol)
{
return symbols->names[symbol];
}
Value interpret(VM* vm, ObjBlock* block)
{
Fiber fiber;
@ -176,9 +203,37 @@ Value interpret(VM* vm, ObjBlock* block)
}
case CODE_CLASS:
push(&fiber, (Value)makeClass());
{
ObjClass* classObj = makeClass();
// Define a "new" method on the metaclass.
// TODO(bob): Can this be inherited?
int newSymbol = ensureSymbol(&vm->symbols, "new", strlen("new"));
printf("define new %d\n", newSymbol);
classObj->metaclass->methods[newSymbol].type = METHOD_PRIMITIVE;
classObj->metaclass->methods[newSymbol].primitive =
primitive_metaclass_new;
push(&fiber, (Value)classObj);
printf("push class at %d\n", fiber.stackSize - 1);
break;
}
case CODE_METHOD:
{
int symbol = frame->block->bytecode[frame->ip++];
int constant = frame->block->bytecode[frame->ip++];
ObjClass* classObj = (ObjClass*)fiber.stack[fiber.stackSize - 1];
ObjBlock* body = (ObjBlock*)frame->block->constants[constant];
classObj->methods[symbol].type = METHOD_BLOCK;
classObj->methods[symbol].block = body;
printf("define method %d using constant %d on ", symbol, constant);
printValue((Value)classObj);
printf("\n");
break;
}
case CODE_LOAD_LOCAL:
{
@ -222,14 +277,22 @@ Value interpret(VM* vm, ObjBlock* block)
break;
case OBJ_CLASS:
classObj = vm->classClass;
classObj = ((ObjClass*)receiver)->metaclass;
break;
case OBJ_NUM:
classObj = vm->numClass;
break;
case OBJ_INSTANCE:
classObj = ((ObjInstance*)receiver)->classObj;
break;
}
printf("call %d on ", symbol);
printValue(receiver);
printf("\n");
Method* method = &classObj->methods[symbol];
switch (method->type)
{
@ -262,11 +325,23 @@ Value interpret(VM* vm, ObjBlock* block)
fiber.numFrames--;
// If we are returning from the top-level block, just return the value.
if (fiber.numFrames == 0) return result;
if (fiber.numFrames == 0)
{
printf("done with result ");
printValue(result);
printf("\n");
return result;
}
// Store the result of the block in the first slot, which is where the
// caller expects it.
printf("return and store result ");
printValue(result);
printf(" in %d\n", frame->locals);
fiber.stack[frame->locals] = result;
// Discard the stack slots for the locals.
fiber.stackSize = frame->locals + 1;
}
}
}
@ -274,6 +349,7 @@ Value interpret(VM* vm, ObjBlock* block)
void printValue(Value value)
{
// TODO(bob): Do more useful stuff here.
switch (value->type)
{
case OBJ_NUM:
@ -287,6 +363,10 @@ void printValue(Value value)
case OBJ_CLASS:
printf("[class]");
break;
case OBJ_INSTANCE:
printf("[instance]");
break;
}
}
@ -318,9 +398,16 @@ Value pop(Fiber* fiber)
return fiber->stack[--fiber->stackSize];
}
Value primitive_num_abs(Value number)
Value primitive_metaclass_new(Value receiver)
{
double value = ((ObjNum*)number)->value;
ObjClass* classObj = (ObjClass*)receiver;
// TODO(bob): Invoke initializer method.
return (Value)makeInstance(classObj);
}
Value primitive_num_abs(Value receiver)
{
double value = ((ObjNum*)receiver)->value;
if (value < 0) value = -value;
return (Value)makeNum(value);

View File

@ -9,7 +9,8 @@
typedef enum {
OBJ_NUM,
OBJ_BLOCK,
OBJ_CLASS
OBJ_CLASS,
OBJ_INSTANCE
} ObjType;
typedef enum
@ -61,13 +62,21 @@ typedef struct
};
} Method;
typedef struct
typedef struct sObjClass
{
Obj obj;
struct sObjClass* metaclass;
// TODO(bob): Hack. Probably don't want to use this much space.
Method methods[MAX_SYMBOLS];
} ObjClass;
typedef struct
{
Obj obj;
ObjClass* classObj;
// TODO(bob): Fields.
} ObjInstance;
typedef enum
{
CODE_CONSTANT,
@ -76,6 +85,10 @@ typedef enum
CODE_CLASS,
// Define a new empty class and push it.
CODE_METHOD,
// Add a method for symbol [arg1] with body stored in constant [arg2] to the
// class on the top of stack. Does not modify the stack.
CODE_DUP,
// Push a copy of the top of stack.
@ -118,6 +131,7 @@ void freeVM(VM* vm);
ObjClass* makeClass();
ObjBlock* makeBlock();
ObjNum* makeNum(double number);
ObjInstance* makeInstance(ObjClass* classObj);
// Initializes the symbol table.
void initSymbolTable(SymbolTable* symbols);
@ -137,6 +151,9 @@ int ensureSymbol(SymbolTable* symbols, const char* name, size_t length);
// Looks up name in the symbol table. Returns its index if found or -1 if not.
int findSymbol(SymbolTable* symbols, const char* name, size_t length);
// Given an index in the symbol table, returns its name.
const char* getSymbolName(SymbolTable* symbols, int symbol);
Value interpret(VM* vm, ObjBlock* block);
void printValue(Value value);