Skip to content

Commit 3a18df7

Browse files
committed
Remove runtime dependency from ast.Value
1 parent d3cb036 commit 3a18df7

15 files changed

Lines changed: 216 additions & 85 deletions

src/ast.zig

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ const std = @import("std");
22
const activeTag = std.meta.activeTag;
33

44
const Token = @import("token.zig").Token;
5-
const Callable = @import("interpreter/callable.zig").Callable;
65

76
pub const Statement = union(enum) {
87
// Expressions
@@ -209,29 +208,9 @@ pub const Value = union(enum) {
209208
int: i64,
210209
string: []const u8,
211210
boolean: bool,
212-
function: Callable,
213211
null,
214212
unit,
215213

216-
// pointer so that copies of a value share identity (u2 = u1 means u1.field == u2.field)
217-
// var u1 = User("Bob");
218-
// var u2 = u1;
219-
// if (u1.name == u2.name) { ... } // true
220-
struct_instance: *StructInstance,
221-
222-
// Index of the VM function
223-
// Stored in the function table in Program
224-
vm_function: u16,
225-
226-
pub const StructInstance = struct {
227-
type_name: []const u8,
228-
field_names: []const []const u8,
229-
body_field_values: []Value,
230-
body_field_names: []const []const u8,
231-
field_values: []Value,
232-
kind: StructKind,
233-
};
234-
235214
pub fn eql(self: Value, other: Value) bool {
236215
const self_tag = activeTag(self);
237216
const other_tag = activeTag(other);
@@ -244,23 +223,6 @@ pub const Value = union(enum) {
244223
.string => |a| std.mem.eql(u8, a, other.string),
245224
.boolean => |a| a == other.boolean,
246225
.null, .unit => true,
247-
.vm_function => |a| a == other.vm_function,
248-
.struct_instance => |a| {
249-
const b = other.struct_instance;
250-
if (a.kind == .plain) {
251-
return a == b;
252-
}
253-
if (!std.mem.eql(u8, a.type_name, b.type_name)) {
254-
return false;
255-
}
256-
for (a.field_values, b.field_values) |av, bv| {
257-
if (!av.eql(bv)) {
258-
return false;
259-
}
260-
}
261-
return true;
262-
},
263-
else => false,
264226
};
265227
}
266228

@@ -277,10 +239,7 @@ pub const Value = union(enum) {
277239
.null, .unit => false,
278240
.boolean => |b| b,
279241
.int => |n| n != 0,
280-
.function => true,
281242
.string => |s| s.len > 0,
282-
.vm_function => true,
283-
.struct_instance => |_| true,
284243
};
285244
}
286245

@@ -296,31 +255,8 @@ pub const Value = union(enum) {
296255
.int => |n| try writer.print("{d}", .{n}),
297256
.string => |s| try writer.print("\"{s}\"", .{s}),
298257
.boolean => |b| try writer.print("{any}", .{b}),
299-
.function => |f| switch (f) {
300-
.user => |u| try writer.print("fn<{s}>", .{u.declaration.name.lexeme}),
301-
.builtin => |bi| try writer.print("fn<{s}>", .{bi.name}),
302-
.struct_constructor => |sc| try writer.print("fn<{s}>", .{sc.name}),
303-
},
304-
.vm_function => try writer.writeAll("fn"),
305258
.null => try writer.writeAll("null"),
306259
.unit => try writer.writeAll("unit"),
307-
.struct_instance => |si_ptr| {
308-
const si = si_ptr.*;
309-
switch (si.kind) {
310-
.plain => try writer.print("<{s}>", .{si.type_name}),
311-
.case => {
312-
try writer.print("{s}(", .{si.type_name});
313-
for (si.field_names, si.field_values, 0..) |name, value, i| {
314-
if (i > 0) {
315-
try writer.writeAll(", ");
316-
}
317-
try writer.print("{s}=", .{name});
318-
try value.format(writer);
319-
}
320-
try writer.writeAll(")");
321-
},
322-
}
323-
},
324260
}
325261
}
326262
};

src/interpreter/builtins.zig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const std = @import("std");
2-
const BuiltinFn = @import("callable.zig").Callable.BuiltinFn;
3-
const Environment = @import("environment.zig").Environment;
2+
43
const RuntimeContext = @import("../runtime.zig").RuntimeContext;
5-
const Value = @import("../ast.zig").Value;
4+
const Environment = @import("environment.zig").Environment;
5+
const BuiltinFn = @import("callable.zig").Callable.BuiltinFn;
6+
const Value = @import("value.zig").Value;
67

78
pub fn registerAll(env: *Environment) !void {
89
try registerFn(env, "print", printFn);

src/interpreter/callable.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const ast = @import("../ast.zig");
2-
const Environment = @import("environment.zig").Environment;
32
const RuntimeContext = @import("../runtime.zig").RuntimeContext;
3+
const Environment = @import("environment.zig").Environment;
4+
const Value = @import("value.zig").Value;
45

56
pub const Callable = union(enum) {
67
user: UserFn,
@@ -16,7 +17,7 @@ pub const Callable = union(enum) {
1617
};
1718

1819
pub const BuiltinFn = struct {
19-
pub const Func = *const fn (args: []const ast.Value, ctx: RuntimeContext) ast.Value;
20+
pub const Func = *const fn (args: []const Value, ctx: RuntimeContext) Value;
2021

2122
name: []const u8,
2223
func: Func,

src/interpreter/environment.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const std = @import("std");
22

3-
const ast = @import("../ast.zig");
4-
const Value = ast.Value;
3+
const Value = @import("value.zig").Value;
54

65
pub const Environment = struct {
76
enclosing: ?*Environment,

src/interpreter/interpreter.zig

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ const utils = @import("../utils.zig");
88
const RuntimeContext = @import("../runtime.zig").RuntimeContext;
99
const Environment = @import("environment.zig").Environment;
1010
const Callable = @import("callable.zig").Callable;
11+
const Value = @import("value.zig").Value;
12+
1113
const Expression = ast.Expression;
12-
const Value = ast.Value;
1314
const Token = token.Token;
1415
const TokenType = token.TokenType;
1516

@@ -185,7 +186,13 @@ pub const Interpreter = struct {
185186

186187
pub fn evaluate(self: *Interpreter, expr: ast.Expression) InterpreterError!Value {
187188
return switch (expr) {
188-
.literal => |e| e.value,
189+
.literal => |e| switch (e.value) {
190+
.int => |n| .{ .int = n },
191+
.string => |s| .{ .string = s },
192+
.boolean => |b| .{ .boolean = b },
193+
.null => .null,
194+
.unit => .unit,
195+
},
189196
.variable => |e| self.env.get(e.token.lexeme),
190197
.var_assignment => |e| self.evaluateVarAssignment(e),
191198
.unary => |e| self.evaluateUnary(e),
@@ -444,7 +451,7 @@ pub const Interpreter = struct {
444451
return error.UndefinedField;
445452
}
446453

447-
fn evaluateBlock(self: *Interpreter, statements: []const ast.Statement, env: *Environment) !ast.Value {
454+
fn evaluateBlock(self: *Interpreter, statements: []const ast.Statement, env: *Environment) !Value {
448455
const previous = self.env;
449456
self.env = env;
450457
defer self.env = previous;

src/interpreter/root.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub const Interpreter = @import("interpreter.zig").Interpreter;
22
pub const Environment = @import("environment.zig").Environment;
33
pub const Callable = @import("callable.zig").Callable;
4+
pub const Value = @import("value.zig").Value;
45
pub const builtins = @import("builtins.zig");

src/interpreter/value.zig

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
const std = @import("std");
2+
const activeTag = std.meta.activeTag;
3+
4+
const Callable = @import("callable.zig").Callable;
5+
const StructKind = @import("../ast.zig").StructKind;
6+
7+
pub const Value = union(enum) {
8+
int: i64,
9+
string: []const u8,
10+
boolean: bool,
11+
function: Callable,
12+
null,
13+
unit,
14+
15+
// pointer so that copies of a value share identity (u2 = u1 means u1.field == u2.field)
16+
// var u1 = User("Bob");
17+
// var u2 = u1;
18+
// if (u1.name == u2.name) { ... } // true
19+
struct_instance: *StructInstance,
20+
21+
pub const StructInstance = struct {
22+
type_name: []const u8,
23+
field_names: []const []const u8,
24+
body_field_values: []Value,
25+
body_field_names: []const []const u8,
26+
field_values: []Value,
27+
kind: StructKind,
28+
};
29+
30+
pub fn eql(self: Value, other: Value) bool {
31+
const self_tag = activeTag(self);
32+
const other_tag = activeTag(other);
33+
if (self_tag != other_tag) {
34+
return false;
35+
}
36+
37+
return switch (self) {
38+
.int => |a| a == other.int,
39+
.string => |a| std.mem.eql(u8, a, other.string),
40+
.boolean => |a| a == other.boolean,
41+
.null, .unit => true,
42+
.struct_instance => |a| {
43+
const b = other.struct_instance;
44+
if (a.kind == .plain) {
45+
return a == b;
46+
}
47+
if (!std.mem.eql(u8, a.type_name, b.type_name)) {
48+
return false;
49+
}
50+
for (a.field_values, b.field_values) |av, bv| {
51+
if (!av.eql(bv)) {
52+
return false;
53+
}
54+
}
55+
return true;
56+
},
57+
else => false,
58+
};
59+
}
60+
61+
pub fn asInt(self: Value) !i64 {
62+
switch (self) {
63+
.int => |n| return n,
64+
else => return error.TypeError,
65+
}
66+
}
67+
68+
// Returns true if the value is truthy
69+
pub fn isTruthy(self: Value) bool {
70+
return switch (self) {
71+
.null, .unit => false,
72+
.boolean => |b| b,
73+
.int => |n| n != 0,
74+
.function => true,
75+
.string => |s| s.len > 0,
76+
.struct_instance => |_| true,
77+
};
78+
}
79+
80+
pub fn isNumber(self: Value) bool {
81+
return switch (self) {
82+
.int => true,
83+
else => false,
84+
};
85+
}
86+
87+
pub fn format(self: Value, writer: *std.Io.Writer) std.Io.Writer.Error!void {
88+
switch (self) {
89+
.int => |n| try writer.print("{d}", .{n}),
90+
.string => |s| try writer.print("\"{s}\"", .{s}),
91+
.boolean => |b| try writer.print("{any}", .{b}),
92+
.function => |f| switch (f) {
93+
.user => |u| try writer.print("fn<{s}>", .{u.declaration.name.lexeme}),
94+
.builtin => |bi| try writer.print("fn<{s}>", .{bi.name}),
95+
.struct_constructor => |sc| try writer.print("fn<{s}>", .{sc.name}),
96+
},
97+
.null => try writer.writeAll("null"),
98+
.unit => try writer.writeAll("unit"),
99+
.struct_instance => |si_ptr| {
100+
const si = si_ptr.*;
101+
switch (si.kind) {
102+
.plain => try writer.print("<{s}>", .{si.type_name}),
103+
.case => {
104+
try writer.print("{s}(", .{si.type_name});
105+
for (si.field_names, si.field_values, 0..) |name, value, i| {
106+
if (i > 0) {
107+
try writer.writeAll(", ");
108+
}
109+
try writer.print("{s}=", .{name});
110+
try value.format(writer);
111+
}
112+
try writer.writeAll(")");
113+
},
114+
}
115+
},
116+
}
117+
}
118+
};

src/tests/bytecode_vm_test.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const Chunk = vm_pkg.Chunk;
44
const OpCode = vm_pkg.OpCode;
55
const Vm = vm_pkg.Vm;
66
const Program = vm_pkg.Program;
7-
const Value = @import("pipe").ast.Value;
7+
const Value = vm_pkg.Value;
88

99
// ---------------------------------------------------------------------------
1010
// Helpers

src/tests/helpers.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn parse(source: []const u8, allocator: std.mem.Allocator) ![]const pipe.ast
1313
}
1414

1515
pub const EvalResult = struct {
16-
value: pipe.ast.Value,
16+
value: pipe.interpreter.Value,
1717
output: []const u8,
1818
allocating: std.Io.Writer.Allocating,
1919

@@ -32,7 +32,7 @@ pub fn typeCheck(source: []const u8, allocator: std.mem.Allocator) !void {
3232
}
3333

3434
pub const VmEvalResult = struct {
35-
value: pipe.ast.Value,
35+
value: pipe.vm.Value,
3636

3737
pub fn deinit(self: *VmEvalResult) void {
3838
_ = self;
@@ -78,7 +78,7 @@ pub fn evaluate(source: []const u8, allocator: std.mem.Allocator) !EvalResult {
7878
var interpreter = try pipe.interpreter.Interpreter.init(ctx, allocator);
7979
defer interpreter.deinit();
8080

81-
var result: pipe.ast.Value = .null;
81+
var result: pipe.interpreter.Value = .null;
8282
for (statements) |statement| {
8383
switch (statement) {
8484
.expression => |expr| result = try interpreter.evaluate(expr),

src/type_checker.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ pub const TypeChecker = struct {
408408
.int => .int,
409409
.string => .string,
410410
.null, .unit => .unit,
411-
.function, .struct_instance, .vm_function => return error.TypeMismatch,
411+
412412
};
413413
return .{ .variable = .{ .pipe_type = pipe_type, .mutability = .constant } };
414414
}

0 commit comments

Comments
 (0)