aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clox/src/chunk.h1
-rw-r--r--clox/src/compiler.c37
-rw-r--r--clox/src/debug.c2
-rw-r--r--clox/src/vm.c13
4 files changed, 38 insertions, 15 deletions
diff --git a/clox/src/chunk.h b/clox/src/chunk.h
index dda2b31..2807d30 100644
--- a/clox/src/chunk.h
+++ b/clox/src/chunk.h
@@ -12,6 +12,7 @@ typedef enum {
OP_POP,
OP_GET_GLOBAL,
OP_DEFINE_GLOBAL,
+ OP_SET_GLOBAL,
OP_EQUAL,
OP_GREATER,
OP_LESS,
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.");
}
}
diff --git a/clox/src/debug.c b/clox/src/debug.c
index 669fc78..61deb52 100644
--- a/clox/src/debug.c
+++ b/clox/src/debug.c
@@ -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:
diff --git a/clox/src/vm.c b/clox/src/vm.c
index 5e35abd..80e11c3 100644
--- a/clox/src/vm.c
+++ b/clox/src/vm.c
@@ -119,8 +119,8 @@ static InterpretResult run() {
ObjString *name = READ_STRING();
Value value;
if (!tableGet(&vm.globals, name, &value)) {
- runtimeError("Undefined variable '%s'.", name->chars);
- return INTERPRET_RUNTIME_ERROR;
+ runtimeError("Undefined variable '%s'.", name->chars);
+ return INTERPRET_RUNTIME_ERROR;
}
push(value);
break;
@@ -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();