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 }