fix: simple knot tests

This commit is contained in:
Brett Broadhurst 2026-03-26 00:42:08 -06:00
parent 9ca2200448
commit cd94a43cc9
Failed to generate hash of commit
7 changed files with 75 additions and 41 deletions

View file

@ -1410,11 +1410,11 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
.data = .{ .payload = undefined },
});
var node_index: usize = 0;
var child_block = gi.makeSubBlock();
defer child_block.unstack();
const knot_inst = try gi.makePayloadNode(.decl_knot);
var child_scope = parent_scope.makeChild();
defer child_scope.deinit();
@ -1432,18 +1432,18 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
});
}
}
var start_index: usize = 0;
const first_child = nested_decls_list[0];
if (first_child.tag == .block_stmt) {
try blockStmt(&child_block, &child_scope, first_child);
start_index += 1;
if (nested_decls_list.len > 0) {
const first_child = nested_decls_list[0];
if (first_child.tag == .block_stmt) {
try blockStmt(&child_block, &child_scope, first_child);
node_index += 1;
}
}
var nested_block = child_block.makeSubBlock();
defer nested_block.unstack();
for (nested_decls_list[start_index..]) |nested_decl_node| {
for (nested_decls_list[node_index..]) |nested_decl_node| {
switch (nested_decl_node.tag) {
.stitch_decl => try stitchDecl(&nested_block, &child_scope, nested_decl_node),
.function_decl => try functionDecl(&nested_block, &child_scope, nested_decl_node),
@ -1469,18 +1469,20 @@ fn file(gi: *GenIr, scope: *Scope, file_node: *const Ast.Node) InnerError!void {
},
});
var node_index: usize = 0;
var file_scope = gi.makeSubBlock();
defer file_scope.unstack();
// TODO: Make sure this is non-nullable.
const nested_decls_list = file_node.data.list.items orelse return;
if (nested_decls_list.len == 0) return;
const first_child = nested_decls_list[0];
if (first_child.tag == .block_stmt) {
try defaultBlock(&file_scope, scope, first_child);
if (nested_decls_list.len > 0) {
const first_child = nested_decls_list[0];
if (first_child.tag == .block_stmt) {
try defaultBlock(&file_scope, scope, first_child);
node_index += 1;
}
}
for (nested_decls_list[1..]) |child_node| {
for (nested_decls_list[node_index..]) |child_node| {
switch (child_node.tag) {
.knot_decl => try knotDecl(gi, scope, child_node),
.stitch_decl => try stitchDecl(gi, scope, child_node),

View file

@ -247,7 +247,7 @@ fn popScratch(p: *Parse, context: *const StmtContext) *Ast.Node {
fn nodeListFromScratch(p: *Parse, start_offset: usize, end_offset: usize) Error![]*Ast.Node {
const span = end_offset - start_offset;
assert(span > 0);
assert(span >= 0);
const list = try p.arena.alloc(*Ast.Node, span);
defer p.scratch.shrinkRetainingCapacity(start_offset);

View file

@ -90,7 +90,7 @@ pub fn lookupInNamespace(
var scope: ?*Module.Namespace = namespace;
while (scope) |s| : (scope = s.parent) {
if (s.decls.get(ident)) |decl| switch (decl.tag) {
.knot => return .{ .knot = .{
.knot, .stitch => return .{ .knot = .{
.namespace = decl.namespace.?,
.const_index = ident,
} },
@ -814,6 +814,27 @@ pub fn analyzeTopLevelDecl(
try analyzeNestedDecl(sema, child_namespace, st);
}
},
.decl_stitch => {
const child_namespace = try sema.module.createNamespace(namespace);
const gop = try namespace.decls.getOrPut(sema.arena, decl_name);
if (gop.found_existing) {
return sema.fail(src_loc, "duplicate identifier", .{});
} else {
gop.value_ptr.* = .{
.tag = .stitch,
.decl_inst = extra.value,
.args_count = 0,
.namespace = child_namespace,
};
}
try sema.module.queueWorkItem(.{
.tag = .stitch,
.decl_name = decl_name,
.inst_index = extra.value,
.namespace = child_namespace,
});
},
else => unreachable,
}
}

View file

@ -205,6 +205,7 @@ pub const Module = struct {
pub const Tag = enum {
knot,
stitch,
variable,
};
};

View file

@ -93,6 +93,41 @@ test "parser: temporary assignment" {
);
}
test "parser: simple knot" {
try testEqual(
\\=== knot ===
\\Hello, world!
,
\\File "<STDIN>"
\\`--KnotDecl <line:1, line:2>
\\ |--KnotProto <col:1, col:13>
\\ | `--Identifier `knot` <col:5, col:9>
\\ `--BlockStmt <line:2, line:2>
\\ `--ContentStmt <line:2, col:1:14>
\\ `--Content <col:1, col:14>
\\ `--StringLiteral `Hello, world!` <col:1, col:14>
\\
,
);
}
test "parser: empty knot declarations" {
try testEqual(
\\== a
\\== b
,
\\File "<STDIN>"
\\|--KnotDecl <line:1, line:1>
\\| `--KnotProto <col:1, col:5>
\\| `--Identifier `a` <col:4, col:5>
\\`--KnotDecl <line:2, line:2>
\\ `--KnotProto <col:1, col:5>
\\ `--Identifier `b` <col:4, col:5>
\\
,
);
}
fn testEqual(source_bytes: [:0]const u8, expected_ast: []const u8) !void {
const gpa = std.testing.allocator;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);

View file

@ -1,12 +0,0 @@
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
// CHECK: File "<STDIN>"
// CHECK-NEXT: |--KnotDecl <line:11, line:11>
// CHECK-NEXT: | `--KnotProto <col:1, col:5>
// CHECK-NEXT: | `--Identifier `a` <col:4, col:5>
// CHECK-NEXT: `--KnotDecl <line:12, line:12>
// CHECK-NEXT: `--KnotProto <col:1, col:5>
// CHECK-NEXT: `--Identifier `b` <col:4, col:5>
== a
== b

View file

@ -1,13 +0,0 @@
// RUN: %ink-compiler --stdin --compile-only --dump-ast < %s | FileCheck %s
// CHECK: File "<STDIN>"
// CHECK-NEXT: `--KnotDecl <line:12, line:13>
// CHECK-NEXT: |--KnotProto <col:1, col:13>
// CHECK-NEXT: | `--Identifier `knot` <col:5, col:9>
// CHECK-NEXT: `--BlockStmt <line:13, line:13>
// CHECK-NEXT: `--ContentStmt <line:13, col:1:14>
// CHECK-NEXT: `--Content <col:1, col:14>
// CHECK-NEXT: `--StringLiteral `Hello, world!` <col:1, col:14>
=== knot ===
Hello, world!