lib/chant/src/parse/state/object.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const ast = @import("../../ast/root.zig");
3 const chant = @import("../../root.zig");
4 const types = @import("types.zig");
5 const Error = @import("../root.zig").Error;
6
7 const Token = chant.token.Token;
8 const Parser = types.Parser;
9
10 pub fn push(parser: *Parser) Error!void {
11 try parser.object_scopes.append(parser.arena, parser.objects.items.len);
12 }
13
14 pub fn pop(parser: *Parser) void {
15 const mark = parser.object_scopes.pop().?;
16 parser.objects.shrinkRetainingCapacity(mark);
17 }
18
19 pub fn register(parser: *Parser, name: []const u8, resolved: *const ast.Type) Error!void {
20 try parser.objects.append(parser.arena, .{ .name = name, .type = resolved });
21 }
22
23 pub fn registerConstant(parser: *Parser, name: []const u8, resolved: *const ast.Type, value: i128) Error!void {
24 try parser.objects.append(parser.arena, .{ .name = name, .type = resolved, .value = value });
25 }
26
27 pub fn lookup(parser: *const Parser, name: []const u8) ?*const ast.Type {
28 const binding = lookupBinding(parser, name) orelse return null;
29 return binding.type;
30 }
31
32 pub fn constantValue(parser: *const Parser, name: []const u8) ?i128 {
33 const binding = lookupBinding(parser, name) orelse return null;
34 return binding.value;
35 }
36
37 fn lookupBinding(parser: *const Parser, name: []const u8) ?types.ObjectBinding {
38 var index = parser.objects.items.len;
39 while (index > 0) {
40 index -= 1;
41 const binding = parser.objects.items[index];
42 if (std.mem.eql(u8, binding.name, name)) return binding;
43 }
44 return null;
45 }
46
47 test "objects resolve through nested scopes" {
48 var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);
49 defer arena_state.deinit();
50 const arena = arena_state.allocator();
51
52 const tokens = [_]Token{
53 .{ .kind = .eof, .text = "", .file = "test.c", .line = 1, .column = 1 },
54 };
55 var parser = try @import("test.zig").initParser(arena, &tokens);
56
57 try push(&parser);
58 try register(&parser, "x", &ast.types.int_type);
59 try registerConstant(&parser, "C", &ast.types.int_type, 42);
60 try std.testing.expectEqual(ast.types.Kind.int_type, lookup(&parser, "x").?.kind);
61 try std.testing.expectEqual(@as(i128, 42), constantValue(&parser, "C").?);
62
63 try push(&parser);
64 try register(&parser, "x", &ast.types.double_type);
65 try std.testing.expectEqual(ast.types.Kind.double_type, lookup(&parser, "x").?.kind);
66 pop(&parser);
67
68 try std.testing.expectEqual(ast.types.Kind.int_type, lookup(&parser, "x").?.kind);
69 pop(&parser);
70 try std.testing.expect(lookup(&parser, "x") == null);
71 }