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 = { class Foo {
var b = 234 bar {
3 123
b }
} }
a.call var a = Foo.new
a.bar

View File

@ -97,6 +97,7 @@ typedef struct sCompiler
static ObjBlock* compileBlock(Parser* parser, Compiler* parent, static ObjBlock* compileBlock(Parser* parser, Compiler* parent,
TokenType endToken); TokenType endToken);
static int addConstant(Compiler* compiler, Value constant);
// Grammar: // Grammar:
static void statement(Compiler* compiler); static void statement(Compiler* compiler);
@ -185,6 +186,12 @@ ObjBlock* compileBlock(Parser* parser, Compiler* parent, TokenType endToken)
return parser->hasError ? NULL : compiler.block; 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) void statement(Compiler* compiler)
{ {
if (match(compiler, TOKEN_CLASS)) if (match(compiler, TOKEN_CLASS))
@ -215,13 +222,20 @@ void statement(Compiler* compiler)
{ {
// Method name. // Method name.
consume(compiler, TOKEN_NAME); consume(compiler, TOKEN_NAME);
//int symbol = internSymbol(compiler); int symbol = internSymbol(compiler);
consume(compiler, TOKEN_LEFT_BRACE); consume(compiler, TOKEN_LEFT_BRACE);
// TODO(bob): Parse body. ObjBlock* method = compileBlock(compiler->parser, compiler,
consume(compiler, TOKEN_RIGHT_BRACE); TOKEN_RIGHT_BRACE);
consume(compiler, TOKEN_LINE); 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; return;
@ -335,14 +349,11 @@ void number(Compiler* compiler)
} }
// Define a constant for the literal. // Define a constant for the literal.
// TODO(bob): See if constant with same value already exists. int constant = addConstant(compiler, (Value)makeNum((double)value));
Value constant = (Value)makeNum((double)value);
compiler->block->constants[compiler->block->numConstants++] = constant;
// Compile the code to load the constant. // Compile the code to load the constant.
emit(compiler, CODE_CONSTANT); emit(compiler, CODE_CONSTANT);
emit(compiler, compiler->block->numConstants - 1); emit(compiler, constant);
} }
TokenType peek(Compiler* compiler) 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 callBlock(Fiber* fiber, ObjBlock* block, int firstLocal);
static void push(Fiber* fiber, Value value); static void push(Fiber* fiber, Value value);
static Value pop(Fiber* fiber); 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() VM* newVM()
{ {
@ -66,7 +67,7 @@ void freeVM(VM* vm)
free(vm); free(vm);
} }
ObjClass* makeClass() ObjClass* makeSingleClass()
{ {
ObjClass* obj = malloc(sizeof(ObjClass)); ObjClass* obj = malloc(sizeof(ObjClass));
obj->obj.type = OBJ_CLASS; obj->obj.type = OBJ_CLASS;
@ -80,6 +81,17 @@ ObjClass* makeClass()
return obj; 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* makeBlock()
{ {
ObjBlock* block = malloc(sizeof(ObjBlock)); ObjBlock* block = malloc(sizeof(ObjBlock));
@ -97,6 +109,16 @@ ObjNum* makeNum(double number)
return num; 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) void initSymbolTable(SymbolTable* symbols)
{ {
symbols->count = 0; symbols->count = 0;
@ -150,6 +172,11 @@ int findSymbol(SymbolTable* symbols, const char* name, size_t length)
return -1; return -1;
} }
const char* getSymbolName(SymbolTable* symbols, int symbol)
{
return symbols->names[symbol];
}
Value interpret(VM* vm, ObjBlock* block) Value interpret(VM* vm, ObjBlock* block)
{ {
Fiber fiber; Fiber fiber;
@ -176,9 +203,37 @@ Value interpret(VM* vm, ObjBlock* block)
} }
case CODE_CLASS: 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); printf("push class at %d\n", fiber.stackSize - 1);
break; 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: case CODE_LOAD_LOCAL:
{ {
@ -222,14 +277,22 @@ Value interpret(VM* vm, ObjBlock* block)
break; break;
case OBJ_CLASS: case OBJ_CLASS:
classObj = vm->classClass; classObj = ((ObjClass*)receiver)->metaclass;
break; break;
case OBJ_NUM: case OBJ_NUM:
classObj = vm->numClass; classObj = vm->numClass;
break; break;
case OBJ_INSTANCE:
classObj = ((ObjInstance*)receiver)->classObj;
break;
} }
printf("call %d on ", symbol);
printValue(receiver);
printf("\n");
Method* method = &classObj->methods[symbol]; Method* method = &classObj->methods[symbol];
switch (method->type) switch (method->type)
{ {
@ -262,11 +325,23 @@ Value interpret(VM* vm, ObjBlock* block)
fiber.numFrames--; fiber.numFrames--;
// If we are returning from the top-level block, just return the value. // 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 // Store the result of the block in the first slot, which is where the
// caller expects it. // caller expects it.
printf("return and store result ");
printValue(result);
printf(" in %d\n", frame->locals);
fiber.stack[frame->locals] = result; 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) void printValue(Value value)
{ {
// TODO(bob): Do more useful stuff here.
switch (value->type) switch (value->type)
{ {
case OBJ_NUM: case OBJ_NUM:
@ -287,6 +363,10 @@ void printValue(Value value)
case OBJ_CLASS: case OBJ_CLASS:
printf("[class]"); printf("[class]");
break; break;
case OBJ_INSTANCE:
printf("[instance]");
break;
} }
} }
@ -318,9 +398,16 @@ Value pop(Fiber* fiber)
return fiber->stack[--fiber->stackSize]; 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; if (value < 0) value = -value;
return (Value)makeNum(value); return (Value)makeNum(value);

View File

@ -9,7 +9,8 @@
typedef enum { typedef enum {
OBJ_NUM, OBJ_NUM,
OBJ_BLOCK, OBJ_BLOCK,
OBJ_CLASS OBJ_CLASS,
OBJ_INSTANCE
} ObjType; } ObjType;
typedef enum typedef enum
@ -61,13 +62,21 @@ typedef struct
}; };
} Method; } Method;
typedef struct typedef struct sObjClass
{ {
Obj obj; Obj obj;
struct sObjClass* metaclass;
// TODO(bob): Hack. Probably don't want to use this much space. // TODO(bob): Hack. Probably don't want to use this much space.
Method methods[MAX_SYMBOLS]; Method methods[MAX_SYMBOLS];
} ObjClass; } ObjClass;
typedef struct
{
Obj obj;
ObjClass* classObj;
// TODO(bob): Fields.
} ObjInstance;
typedef enum typedef enum
{ {
CODE_CONSTANT, CODE_CONSTANT,
@ -76,6 +85,10 @@ typedef enum
CODE_CLASS, CODE_CLASS,
// Define a new empty class and push it. // 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, CODE_DUP,
// Push a copy of the top of stack. // Push a copy of the top of stack.
@ -118,6 +131,7 @@ void freeVM(VM* vm);
ObjClass* makeClass(); ObjClass* makeClass();
ObjBlock* makeBlock(); ObjBlock* makeBlock();
ObjNum* makeNum(double number); ObjNum* makeNum(double number);
ObjInstance* makeInstance(ObjClass* classObj);
// Initializes the symbol table. // Initializes the symbol table.
void initSymbolTable(SymbolTable* symbols); 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. // 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); 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); Value interpret(VM* vm, ObjBlock* block);
void printValue(Value value); void printValue(Value value);