X-Git-Url: https://git.ayoreis.com/zlox.git/blobdiff_plain/6ae8b98923f9b393fbfa25db8af61a9bd6f1b0f6..60ca4a9e7c56ac47f67add12ec7d2edf5bd89e5a:/src/Environment.zig?ds=inline diff --git a/src/Environment.zig b/src/Environment.zig index 25744a7..8cc7e2b 100644 --- a/src/Environment.zig +++ b/src/Environment.zig @@ -2,29 +2,45 @@ const std = @import("std"); const StringHashMapUnmanaged = std.StringHashMapUnmanaged; const Allocator = std.mem.Allocator; const Token = @import("Token.zig"); -const Literal = Token.Literal; +const Object = @import("object.zig").Object; const Environment = @This(); const ErrorPayload = @import("Interpreter.zig").ErrorPayload; -values: StringHashMapUnmanaged(Literal) = .empty, +enclosing: ?*Environment, +values: StringHashMapUnmanaged(Object) = .empty, -pub fn define(self: *Environment, allocator: Allocator, name: []const u8, value: Literal) !void { +pub fn init(enclosing: ?*Environment) Environment { + return .{ + .enclosing = enclosing, + }; +} + +pub fn define(self: *Environment, allocator: Allocator, name: []const u8, value: Object) !void { try self.values.put(allocator, name, value); } -pub fn get(self: *Environment, allocator: Allocator, name: Token, err_payload: *ErrorPayload) !Literal { - return self.values.get(name.lexeme) orelse { - err_payload.* = .{ .token = name, .message = try std.fmt.allocPrint(allocator, "Undefined variable '{s}'.", .{name.lexeme}) }; - return error.RuntimeError; - }; +pub fn get(self: *Environment, allocator: Allocator, name: Token, err_payload: *ErrorPayload) !Object { + if (self.values.contains(name.lexeme)) { + return self.values.get(name.lexeme).?; + } + + if (self.enclosing) |enclosing| return enclosing.get(allocator, name, err_payload); + + err_payload.* = .{ .runtime_error = .init(name, try std.fmt.allocPrint(allocator, "Undefined variable '{s}'.", .{name.lexeme})) }; + return error.RuntimeError; } -pub fn assign(self: *Environment, allocator: Allocator, name: Token, value: Literal, err_payload: *ErrorPayload) !void { +pub fn assign(self: *Environment, allocator: Allocator, name: Token, value: Object, err_payload: *ErrorPayload) !void { if (self.values.contains(name.lexeme)) { try self.values.put(allocator, name.lexeme, value); return; } - err_payload.* = .{ .token = name, .message = try std.fmt.allocPrint(allocator, "Undefined variable '{s}'.", .{name.lexeme}) }; + if (self.enclosing) |enclosing| { + try enclosing.assign(allocator, name, value, err_payload); + return; + } + + err_payload.* = .{ .runtime_error = .init(name, try std.fmt.allocPrint(allocator, "Undefined variable '{s}'.", .{name.lexeme})) }; return error.RuntimeError; }