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_GET_GLOBAL,
OP_DEFINE_GLOBAL,
OP_SET_GLOBAL,
OP_EQUAL,
OP_GREATER,
OP_LESS,

View file

@ -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);
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.");
}
}

View file

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

View file

@ -131,6 +131,15 @@ static InterpretResult run() {
pop();
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: {
Value b = pop();
Value a = pop();