Chapter 28.4

This commit is contained in:
Tom Willemse 2022-08-14 16:11:39 -07:00
parent 7871383a40
commit cb42c81121
4 changed files with 34 additions and 2 deletions

View file

@ -51,7 +51,12 @@ typedef struct {
bool isLocal; bool isLocal;
} Upvalue; } Upvalue;
typedef enum { TYPE_FUNCTION, TYPE_METHOD, TYPE_SCRIPT } FunctionType; typedef enum {
TYPE_FUNCTION,
TYPE_INITIALIZER,
TYPE_METHOD,
TYPE_SCRIPT
} FunctionType;
typedef struct Compiler { typedef struct Compiler {
struct Compiler *enclosing; struct Compiler *enclosing;
@ -159,7 +164,12 @@ static int emitJump(uint8_t instruction) {
} }
static void emitReturn() { static void emitReturn() {
emitByte(OP_NIL); if (current->type == TYPE_INITIALIZER) {
emitBytes(OP_GET_LOCAL, 0);
} else {
emitByte(OP_NIL);
}
emitByte(OP_RETURN); emitByte(OP_RETURN);
} }
@ -389,6 +399,11 @@ static void method() {
uint8_t constant = identifierConstant(&parser.previous); uint8_t constant = identifierConstant(&parser.previous);
FunctionType type = TYPE_METHOD; FunctionType type = TYPE_METHOD;
if (parser.previous.length == 4 &&
memcmp(parser.previous.start, "init", 4) == 0) {
type = TYPE_INITIALIZER;
}
function(type); function(type);
emitBytes(OP_METHOD, constant); emitBytes(OP_METHOD, constant);
} }
@ -588,6 +603,10 @@ static void returnStatement() {
if (match(TOKEN_SEMICOLON)) { if (match(TOKEN_SEMICOLON)) {
emitReturn(); emitReturn();
} else { } else {
if (current->type == TYPE_INITIALIZER) {
error("Can't return a value from an initializer.");
}
expression(); expression();
consume(TOKEN_SEMICOLON, "Expect ';' after return value."); consume(TOKEN_SEMICOLON, "Expect ';' after return value.");
emitByte(OP_RETURN); emitByte(OP_RETURN);

View file

@ -180,6 +180,7 @@ static void markRoots() {
markTable(&vm.globals); markTable(&vm.globals);
markCompilerRoots(); markCompilerRoots();
markObject((Obj *)vm.initString);
} }
static void traceReferences() { static void traceReferences() {

View file

@ -65,12 +65,16 @@ void initVM() {
initTable(&vm.globals); initTable(&vm.globals);
initTable(&vm.strings); initTable(&vm.strings);
vm.initString = NULL;
vm.initString = copyString("init", 4);
defineNative("clock", clockNative); defineNative("clock", clockNative);
} }
void freeVM() { void freeVM() {
freeTable(&vm.globals); freeTable(&vm.globals);
freeTable(&vm.strings); freeTable(&vm.strings);
vm.initString = NULL;
freeObjects(); freeObjects();
} }
@ -116,6 +120,13 @@ static bool callValue(Value callee, int argCount) {
case OBJ_CLASS: { case OBJ_CLASS: {
ObjClass *klass = AS_CLASS(callee); ObjClass *klass = AS_CLASS(callee);
vm.stackTop[-argCount - 1] = OBJ_VAL(newInstance(klass)); vm.stackTop[-argCount - 1] = OBJ_VAL(newInstance(klass));
Value initializer;
if (tableGet(&klass->methods, vm.initString, &initializer)) {
return call(AS_CLOSURE(initializer), argCount);
} else if (argCount != 0) {
runtimeError("Expected 0 arguments but got %d.", argCount);
return false;
}
return true; return true;
} }
case OBJ_CLOSURE: case OBJ_CLOSURE:

View file

@ -23,6 +23,7 @@ typedef struct {
Value *stackTop; Value *stackTop;
Table globals; Table globals;
Table strings; Table strings;
ObjString *initString;
ObjUpvalue *openUpvalues; ObjUpvalue *openUpvalues;
size_t bytesAllocated; size_t bytesAllocated;