diff options
Diffstat (limited to 'clox/src/compiler.c')
-rw-r--r-- | clox/src/compiler.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/clox/src/compiler.c b/clox/src/compiler.c index f125c10..0fc41b8 100644 --- a/clox/src/compiler.c +++ b/clox/src/compiler.c @@ -30,7 +30,7 @@ typedef enum { PREC_PRIMARY } Precedence; -typedef void (*ParseFn)(); +typedef void (*ParseFn)(bool canAssign); typedef struct { ParseFn prefix; @@ -140,7 +140,7 @@ static uint8_t parseVariable(const char *name); static void defineVariable(uint8_t global); static uint8_t identifierConstant(Token *name); -static void binary() { +static void binary(bool canAssign) { TokenType operatorType = parser.previous.type; ParseRule *rule = getRule(operatorType); parsePrecedence((Precedence)(rule->precedence + 1)); @@ -181,7 +181,7 @@ static void binary() { } } -static void literal() { +static void literal(bool canAssign) { switch (parser.previous.type) { case TOKEN_FALSE: emitByte(OP_FALSE); @@ -267,26 +267,32 @@ static void statement() { } } -static void number() { +static void number(bool canAssign) { double value = strtod(parser.previous.start, NULL); emitConstant(NUMBER_VAL(value)); } -static void string() { +static void string(bool canAssign) { emitConstant(OBJ_VAL( copyString(parser.previous.start + 1, parser.previous.length - 2))); } -static void namedVariable(Token name) { +static void namedVariable(Token name, bool canAssign) { uint8_t arg = identifierConstant(&name); - emitBytes(OP_GET_GLOBAL, arg); + + if (canAssign && match(TOKEN_EQUAL)) { + expression(); + emitBytes(OP_SET_GLOBAL, arg); + } else { + emitBytes(OP_GET_GLOBAL, arg); + } } -static void variable() { - namedVariable(parser.previous); +static void variable(bool canAssign) { + namedVariable(parser.previous, canAssign); } -static void unary() { +static void unary(bool canAssign) { TokenType operatorType = parser.previous.type; // Compile the operand. @@ -305,7 +311,7 @@ static void unary() { } } -static void grouping() { +static void grouping(bool canAssign) { expression(); consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression."); } @@ -361,12 +367,17 @@ static void parsePrecedence(Precedence precedence) { return; } - prefixRule(); + bool canAssign = precedence <= PREC_ASSIGNMENT; + prefixRule(canAssign); while (precedence <= getRule(parser.current.type)->precedence) { advance(); ParseFn infixRule = getRule(parser.previous.type)->infix; - infixRule(); + infixRule(canAssign); + } + + if (canAssign && match(TOKEN_EQUAL)) { + error("Invalid assignment target."); } } |