Chapter 21

This commit is contained in:
Tom Willemse 2021-10-21 19:51:01 -07:00
parent 7bd9934a4b
commit 26b418d254
4 changed files with 38 additions and 15 deletions

View file

@ -12,6 +12,7 @@ typedef enum {
OP_POP, OP_POP,
OP_GET_GLOBAL, OP_GET_GLOBAL,
OP_DEFINE_GLOBAL, OP_DEFINE_GLOBAL,
OP_SET_GLOBAL,
OP_EQUAL, OP_EQUAL,
OP_GREATER, OP_GREATER,
OP_LESS, OP_LESS,

View file

@ -30,7 +30,7 @@ typedef enum {
PREC_PRIMARY PREC_PRIMARY
} Precedence; } Precedence;
typedef void (*ParseFn)(); typedef void (*ParseFn)(bool canAssign);
typedef struct { typedef struct {
ParseFn prefix; ParseFn prefix;
@ -140,7 +140,7 @@ static uint8_t parseVariable(const char *name);
static void defineVariable(uint8_t global); static void defineVariable(uint8_t global);
static uint8_t identifierConstant(Token *name); static uint8_t identifierConstant(Token *name);
static void binary() { static void binary(bool canAssign) {
TokenType operatorType = parser.previous.type; TokenType operatorType = parser.previous.type;
ParseRule *rule = getRule(operatorType); ParseRule *rule = getRule(operatorType);
parsePrecedence((Precedence)(rule->precedence + 1)); parsePrecedence((Precedence)(rule->precedence + 1));
@ -181,7 +181,7 @@ static void binary() {
} }
} }
static void literal() { static void literal(bool canAssign) {
switch (parser.previous.type) { switch (parser.previous.type) {
case TOKEN_FALSE: case TOKEN_FALSE:
emitByte(OP_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); double value = strtod(parser.previous.start, NULL);
emitConstant(NUMBER_VAL(value)); emitConstant(NUMBER_VAL(value));
} }
static void string() { static void string(bool canAssign) {
emitConstant(OBJ_VAL( emitConstant(OBJ_VAL(
copyString(parser.previous.start + 1, parser.previous.length - 2))); 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); 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() { static void variable(bool canAssign) {
namedVariable(parser.previous); namedVariable(parser.previous, canAssign);
} }
static void unary() { static void unary(bool canAssign) {
TokenType operatorType = parser.previous.type; TokenType operatorType = parser.previous.type;
// Compile the operand. // Compile the operand.
@ -305,7 +311,7 @@ static void unary() {
} }
} }
static void grouping() { static void grouping(bool canAssign) {
expression(); expression();
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression."); consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
} }
@ -361,12 +367,17 @@ static void parsePrecedence(Precedence precedence) {
return; return;
} }
prefixRule(); bool canAssign = precedence <= PREC_ASSIGNMENT;
prefixRule(canAssign);
while (precedence <= getRule(parser.current.type)->precedence) { while (precedence <= getRule(parser.current.type)->precedence) {
advance(); advance();
ParseFn infixRule = getRule(parser.previous.type)->infix; ParseFn infixRule = getRule(parser.previous.type)->infix;
infixRule(); infixRule(canAssign);
}
if (canAssign && match(TOKEN_EQUAL)) {
error("Invalid assignment target.");
} }
} }

View file

@ -48,6 +48,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
return constantInstruction("OP_GET_GLOBAL", chunk, offset); return constantInstruction("OP_GET_GLOBAL", chunk, offset);
case OP_DEFINE_GLOBAL: case OP_DEFINE_GLOBAL:
return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset); return constantInstruction("OP_DEFINE_GLOBAL", chunk, offset);
case OP_SET_GLOBAL:
return constantInstruction("OP_SET_GLOBAL", chunk, offset);
case OP_EQUAL: case OP_EQUAL:
return simpleInstruction("OP_EQUAL", offset); return simpleInstruction("OP_EQUAL", offset);
case OP_GREATER: case OP_GREATER:

View file

@ -119,8 +119,8 @@ static InterpretResult run() {
ObjString *name = READ_STRING(); ObjString *name = READ_STRING();
Value value; Value value;
if (!tableGet(&vm.globals, name, &value)) { if (!tableGet(&vm.globals, name, &value)) {
runtimeError("Undefined variable '%s'.", name->chars); runtimeError("Undefined variable '%s'.", name->chars);
return INTERPRET_RUNTIME_ERROR; return INTERPRET_RUNTIME_ERROR;
} }
push(value); push(value);
break; break;
@ -131,6 +131,15 @@ static InterpretResult run() {
pop(); pop();
break; break;
} }
case OP_SET_GLOBAL: {
ObjString *name = READ_STRING();
if (tableSet(&vm.globals, name, peek(0))) {
tableDelete(&vm.globals, name);
runtimeError("Undefined variable '%s'.", name->chars);
return INTERPRET_RUNTIME_ERROR;
}
break;
}
case OP_EQUAL: { case OP_EQUAL: {
Value b = pop(); Value b = pop();
Value a = pop(); Value a = pop();