diff --git a/src/chunk.zig b/src/chunk.zig index a244bd2..5ce7062 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -35,9 +35,6 @@ const AllOpcodes = struct { pub GetGlobalLong: u8 = 20, pub SetGlobal: u8 = 21, pub SetGlobalLong: u8 = 22, - - pub GetLocal: u8 = 23, - pub SetLocal: u8 = 24, }; pub const OpCode = AllOpcodes{}; @@ -88,17 +85,6 @@ fn constantLongInstruction( return offset + 4; } -fn byteInstruction( - stdout: var, - name: []const u8, - chunk: *Chunk, - index: usize, -) !usize { - var slot: u8 = chunk.code[index + 1]; - try stdout.print("{} {}", name, slot); - return index + 2; -} - pub const ConstantIndexTag = enum { Small, Long, @@ -265,10 +251,6 @@ pub const Chunk = struct { return try constantInstruction(stdout, "OP_SETGLOBAL", self, index); } else if (instruction == OpCode.SetGlobalLong) { return try constantLongInstruction(stdout, "OP_SETGLOBAL_LONG", self, index); - } else if (instruction == OpCode.GetLocal) { - return try byteInstruction(stdout, "OP_GETLOCAL", self, index); - } else if (instruction == OpCode.SetLocal) { - return try byteInstruction(stdout, "OP_GETLOCAL", self, index); } else { try stdout.print("Unknown opcode: {}\n", instruction); return index + 1; diff --git a/src/compiler.zig b/src/compiler.zig index 398741b..ac6030a 100644 --- a/src/compiler.zig +++ b/src/compiler.zig @@ -113,11 +113,6 @@ var rules = []ParseRule{ ParseRule{}, }; -pub const Local = struct { - name: tokens.Token, - depth: i32, -}; - pub const Compiler = struct { src: []const u8, stdout: vm.StdOut, @@ -128,10 +123,6 @@ pub const Compiler = struct { debug_flag: bool = false, vmach: *vm.VM, - locals: [256]Local, - localCount: i32 = 0, - scopeDepth: i32 = 0, - pub fn init( allocator: *Allocator, chunk: *chunks.Chunk, @@ -148,12 +139,6 @@ pub const Compiler = struct { .parser = Parser{}, .debug_flag = debug_flag, .vmach = vmach, - - // local variable resolution - .locals = []Local{Local{ - .name = Token{}, - .depth = -1, - }} ** 256, }; } @@ -244,20 +229,6 @@ pub const Compiler = struct { } } - fn beginScope(self: *Compiler) void { - self.scopeDepth += 1; - } - - fn endScope(self: *Compiler) !void { - self.scopeDepth -= 1; - - // clear the current scope in the stack - while (self.localCount > 0 and self.locals[@intCast(usize, self.localCount - 1)].depth > self.scopeDepth) { - try self.emitByte(chunks.OpCode.Pop); - self.localCount -= 1; - } - } - fn grouping(self: *Compiler, canAssign: bool) !void { try self.expression(); try self.consume(.RIGHT_PAREN, "Expect ')' after expression."); @@ -281,48 +252,27 @@ pub const Compiler = struct { ))); } - fn resolveLocal(self: *Compiler, name: *Token) i32 { - var i = self.localCount - 1; - while (i >= 0) : (i -= 1) { - var idx = @intCast(usize, i); - var local = &self.locals[idx]; - if (std.mem.eql(u8, name.lexeme, local.name.lexeme)) { - if (local.depth == -1) { - self.errorCurrent("Cannot read local variable in its own initializer."); - } - return i; - } - } - - return -1; - } - fn namedVariable(self: *Compiler, tok: *Token, canAssign: bool) !void { // writeConstant always writes OP_CODE which may be not // what we want, so. - var getOp: u8 = undefined; - var setOp: u8 = undefined; - - // we try to resolve the local. depending if it gets resolved - // or not, we select the necessary get/set op codes. - var arg: i32 = self.resolveLocal(tok); - - if (arg != -1) { - getOp = chunks.OpCode.GetLocal; - setOp = chunks.OpCode.SetLocal; - } else { - arg = (try self.identifierConstant(tok)).Small; - getOp = chunks.OpCode.GetGlobal; - setOp = chunks.OpCode.SetGlobal; - } - - var idx: u8 = @intCast(u8, arg); + var idx = try self.currentChunk().writeConstantRaw(values.ObjVal(try objects.copyString( + self.vmach, + tok.lexeme, + )), tok.line); if (canAssign and try self.match(.EQUAL)) { try self.expression(); - try self.emitBytes(setOp, idx); + try self.emitConstWithIndex( + chunks.OpCode.SetGlobal, + chunks.OpCode.SetGlobalLong, + idx, + ); } else { - try self.emitBytes(getOp, idx); + try self.emitConstWithIndex( + chunks.OpCode.GetGlobal, + chunks.OpCode.GetGlobalLong, + idx, + ); } } @@ -447,44 +397,8 @@ pub const Compiler = struct { )), token.line); } - fn addLocal(self: *Compiler, name: Token) void { - if (self.localCount == 256) { - self.errorCurrent("Too many variables in function."); - return; - } - - self.localCount += 1; - var local: *Local = &self.locals[@intCast(usize, self.localCount)]; - local.name = name; - //local.depth = self.scopeDepth; - local.depth = -1; - } - - fn declareVariable(self: *Compiler) void { - if (self.scopeDepth == 0) return; - var name: *Token = &self.parser.previous; - - // check if we're redeclaring an existing variable - // in the *CURRENT* scope. - - // go from current down to global - var i = self.localCount; - while (i >= 0) : (i -= 1) { - var local = self.locals[@intCast(usize, i)]; - if (local.depth == -1 and local.depth < self.scopeDepth) break; - - if (std.mem.eql(u8, name.lexeme, local.name.lexeme)) { - self.errorCurrent("Variable with this name already declared in this scope."); - } - } - - self.addLocal(name.*); - } - fn parseVariable(self: *Compiler, msg: []const u8) !chunks.ConstantIndex { try self.consume(.IDENTIFIER, msg); - self.declareVariable(); - if (self.scopeDepth > 0) return chunks.ConstantIndex{ .Small = 0 }; return try self.identifierConstant(&self.parser.previous); } @@ -506,18 +420,7 @@ pub const Compiler = struct { } } - fn markInitialized(self: *Compiler) void { - if (self.scopeDepth == 0) return; - var idx = @intCast(usize, self.localCount); - self.locals[idx].depth = self.scopeDepth; - } - fn defineVariable(self: *Compiler, global: chunks.ConstantIndex) !void { - if (self.scopeDepth > 0) { - self.markInitialized(); - return; - } - try self.emitConstWithIndex( chunks.OpCode.DefineGlobal, chunks.OpCode.DefineGlobalLong, @@ -534,13 +437,11 @@ pub const Compiler = struct { try self.emitByte(chunks.OpCode.Nil); } - // check scopeDepth here - try self.consume(.SEMICOLON, "Expect ';' after variable declaration."); try self.defineVariable(global); } - fn declaration(self: *Compiler) anyerror!void { + fn declaration(self: *Compiler) !void { if (try self.match(.VAR)) { try self.varDecl(); } else { @@ -549,21 +450,9 @@ pub const Compiler = struct { if (self.parser.panicMode) try self.synchronize(); } - fn block(self: *Compiler) anyerror!void { - while (!self.check(.RIGHT_BRACE) and !self.check(.EOF)) { - try self.declaration(); - } - - try self.consume(.RIGHT_BRACE, "Expect '}' after block."); - } - fn statement(self: *Compiler) !void { if (try self.match(.PRINT)) { try self.printStmt(); - } else if (try self.match(.LEFT_BRACE)) { - self.beginScope(); - try self.block(); - try self.endScope(); } else { try self.exprStmt(); } diff --git a/src/vm.zig b/src/vm.zig index b3e3942..d2b923d 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -294,24 +294,26 @@ pub const VM = struct { chunk.OpCode.Pop => blk: { _ = self.pop(); - }, - - chunk.OpCode.GetLocal => blk: { - var slot = self.readByte(); - try self.push(self.stack[slot]); - }, - chunk.OpCode.SetLocal => blk: { - var slot = self.readByte(); - self.stack[slot] = self.peek(0); + break :blk; }, chunk.OpCode.GetGlobal => blk: { try self.doGetGlobal(self.readString()); + break :blk; }, + chunk.OpCode.GetGlobalLong => blk: { + try self.doGetGlobal(self.readStringLong()); + break :blk; + }, + chunk.OpCode.SetGlobal => blk: { try self.doSetGlobal(self.readString()); break :blk; }, + chunk.OpCode.SetGlobalLong => blk: { + try self.doSetGlobal(self.readStringLong()); + break :blk; + }, // extracting the name is different depending of the // op code since one just uses a single byte, the other