diff --git a/clox/src/compiler.c b/clox/src/compiler.c index 44eede8..bd835f2 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -46,7 +46,8 @@ typedef struct { typedef enum { TYPE_FUNCTION, TYPE_SCRIPT } FunctionType; -typedef struct { +typedef struct Compiler { + struct Compiler *enclosing; ObjFunction *function; FunctionType type; @@ -171,12 +172,17 @@ static void patchJump(int offset) { } static void initCompiler(Compiler *compiler, FunctionType type) { + compiler->enclosing = current; compiler->function = NULL; compiler->type = type; compiler->localCount = 0; compiler->scopeDepth = 0; compiler->function = newFunction(); current = compiler; + if (type != TYPE_SCRIPT) { + current->function->name = + copyString(parser.previous.start, parser.previous.length); + } Local *local = ¤t->locals[current->localCount++]; local->depth = 0; @@ -196,6 +202,7 @@ static ObjFunction *endCompiler() { } #endif + current = current->enclosing; return function; } @@ -288,6 +295,43 @@ static void block() { consume(TOKEN_RIGHT_BRACE, "Expect '}' after block."); } +static void function(FunctionType type) { + Compiler compiler; + initCompiler(&compiler, type); + beginScope(); + + consume(TOKEN_LEFT_PAREN, "Expect '(' after function name."); + if (!check(TOKEN_RIGHT_PAREN)) { + do { + current->function->arity++; + if (current->function->arity > 255) { + errorAtCurrent("Can't have more than 250 parameters."); + } + uint8_t constant = parseVariable("Expect parameter name."); + defineVariable(constant); + } while (match(TOKEN_COMMA)); + } + consume(TOKEN_RIGHT_PAREN, "Expect ')' after parameters."); + consume(TOKEN_LEFT_BRACE, "Expect '{' before function body."); + block(); + + ObjFunction *function = endCompiler(); + emitBytes(OP_CONSTANT, makeConstant(OBJ_VAL(function))); +} + +static void markInitialized() { + if (current->scopeDepth == 0) + return; + current->locals[current->localCount - 1].depth = current->scopeDepth; +} + +static void funDeclaration() { + uint8_t global = parseVariable("Expect function name."); + markInitialized(); + function(TYPE_FUNCTION); + defineVariable(global); +} + static void varDeclaration() { uint8_t global = parseVariable("Expect variable name."); @@ -417,7 +461,9 @@ static void synchronize() { } static void declaration() { - if (match(TOKEN_VAR)) { + if (match(TOKEN_FUN)) { + funDeclaration(); + } else if (match(TOKEN_VAR)) { varDeclaration(); } else { statement(); @@ -653,10 +699,6 @@ static uint8_t parseVariable(const char *errorMessage) { return identifierConstant(&parser.previous); } -static void markInitialized() { - current->locals[current->localCount - 1].depth = current->scopeDepth; -} - static void defineVariable(uint8_t global) { if (current->scopeDepth > 0) { markInitialized();