import "@std/mem" import "@std/arraylist" import "@std/testing" import "@source/ast" import "@source/diagnostics" import "@source/ir" import "@source/interpreter" @hide:file owned_text proc(text []u8) arraylist.ArrayList(u8) ! mem.AllocError { bytes := arraylist.init(u8, mem.c_allocator) errdefer arraylist.deinit(&bytes) try arraylist.reserve(&bytes, text.len) for (text) |byte| try arraylist.append(&bytes, byte) return bytes } keeps_package_declarations_distinct_and_ir_independent test { diagnostic_store := diagnostics.init(mem.c_allocator) defer diagnostics.deinit(&diagnostic_store) first := try owned_text("value :: 21\nmain proc() int { return value * 2 }") defer arraylist.deinit(&first) second := try owned_text("value :: 3\nmain proc() int { return value * 2 }") defer arraylist.deinit(&second) sibling := try owned_text("helper proc() int { return 7 }") defer arraylist.deinit(&sibling) path [9]mut u8 := undefined memcopy!(path[..], "first.hon") session := init(mem.c_allocator) # the IR must outlive the compilation, including source buffers and interned names. modules [2]mut ir.Module := undefined { defer deinit(&session) root :: try add_package(&session) dependency :: try add_package(&session) left :: try add_source(&session, root, path[..], &first, &diagnostic_store) right :: try add_source(&session, dependency, "second.hon", &second, &diagnostic_store) third :: try add_source(&session, root, "sibling.hon", &sibling, &diagnostic_store) path[0] = 'X' try testing.expect_equal(0, first.capacity) try testing.expect_equal(0, first.items.len) try testing.expect(mem.eql(source(&session, left).path, "first.hon")) try testing.expect_equal(root, source(&session, left).package) try testing.expect_equal(dependency, source(&session, right).package) try testing.expect_equal(root, source(&session, third).package) try testing.expect_equal(left, session.packages.items[usize(root)].sources.items[0]) try testing.expect_equal(third, session.packages.items[usize(root)].sources.items[1]) a :: declaration(&session, left, 0) b :: declaration(&session, right, 0) try testing.expect(a.source != b.source) tree :: ast.view(&session.builder, source(&session, left).root) try testing.expect_equal(ast.name_id(&tree, a.node), ast.name_id(&tree, b.node)) try testing.expect(mem.eql(ast.source_text(&tree, ast.statement_decl(&tree, a.node).span), "value :: 21")) try testing.expect(mem.eql(ast.source_text(&tree, ast.statement_decl(&tree, b.node).span), "value :: 3")) modules[0] = try compile(&session, root, &diagnostic_store) errdefer ir.deinit(&modules[0]) modules[1] = try compile(&session, dependency, &diagnostic_store) } defer ir.deinit(&modules[0]) defer ir.deinit(&modules[1]) try testing.expect_equal(0, diagnostics.count(&diagnostic_store)) left_result := try interpreter.run(mem.c_allocator, &modules[0], &diagnostic_store) defer interpreter.deinit(&left_result) right_result := try interpreter.run(mem.c_allocator, &modules[1], &diagnostic_store) defer interpreter.deinit(&right_result) try testing.expect(left_result.trap == null and right_result.trap == null) try testing.expect_equal(i64(42), left_result.value.data.integer) try testing.expect_equal(i64(6), right_result.value.data.integer) } recompiles_specialized_calls_without_borrowing_previous_ir test { diagnostic_store := diagnostics.init(mem.c_allocator) defer diagnostics.deinit(&diagnostic_store) modules [2]mut ir.Module := undefined { session := init(mem.c_allocator) defer deinit(&session) root :: try add_package(&session) bytes := try owned_text( `identity proc($T type, value T) T { ` if (T == i16) return value else return value.missing `} `Box proc($T type) type { return struct { value T } } `count proc() usize { ` result := 0 ` while (result < 2) result = result + 1 ` return result `} `Fixed proc($N usize) type { return struct { values [N]i16 } } `data proc() [2]i16 { return [40, 2] } `main proc() i16 { ` if $(i16 != i16) { return $(i8(128)) } ` values :: $(data()) ` box Box(i16) :: { value = identity(i16, values[0]) } ` fixed Fixed(count()) :: { values = [box.value, 2] } ` same Fixed(2) :: fixed ` return identity(same.values[0]) + same.values[$(usize(1))] `} , ) defer arraylist.deinit(&bytes) _ = try add_source(&session, root, "generic.hon", &bytes, &diagnostic_store) modules[0] = try compile(&session, root, &diagnostic_store) errdefer ir.deinit(&modules[0]) modules[1] = try compile(&session, root, &diagnostic_store) } defer ir.deinit(&modules[0]) defer ir.deinit(&modules[1]) try testing.expect_equal(0, diagnostics.count(&diagnostic_store)) for (0..modules.len) |index| { outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store) defer interpreter.deinit(&outcome) try testing.expect(outcome.trap == null) try testing.expect_equal(i64(42), outcome.value.data.integer) } } dependency_traps_keep_original_spans_and_remain_demand_driven test { mains [2][]u8 :: [ `dep :: import "../dependency" `main proc() int { return dep.fail(false) } ` , `dep :: import "../dependency" `main proc() int { return dep.fail(true) } ` , ] prefix :: ` `fail proc(take bool) int { ` if take { ` for (mains) |main, index| { diagnostic_store := diagnostics.init(mem.c_allocator) defer diagnostics.deinit(&diagnostic_store) module ir.Module := undefined dependency_source SourceId := undefined original diagnostics.DiagnosticId := undefined { session := init(mem.c_allocator) defer deinit(&session) root :: try add_package(&session) dependency :: try add_package(&session) root_bytes := try owned_text(main) defer arraylist.deinit(&root_bytes) dependency_bytes := try owned_text( ` `fail proc(take bool) int { ` if take { ` return missing ` } ` return 42 `} ` , ) defer arraylist.deinit(&dependency_bytes) root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store) dependency_source = try add_source(&session, dependency, "dependency/fail.hon", &dependency_bytes, &diagnostic_store) try arraylist.append(&session.imports, Import{ node = declaration(&session, root_source, 0).node, target = dependency, }) module = try compile(&session, root, &diagnostic_store) } defer ir.deinit(&module) try testing.expect_equal(1, diagnostics.count(&diagnostic_store)) original = diagnostics.DiagnosticId(0) diagnostic :: diagnostics.get(&diagnostic_store, original)? try testing.expect_equal(diagnostics.Code.unknown_name, diagnostic.code) try testing.expect_equal(dependency_source, diagnostic.span.source) start :: u32(prefix.len + " return ".len) try testing.expect_equal(start, diagnostic.span.start) try testing.expect_equal(start + 7, diagnostic.span.end) outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store) defer interpreter.deinit(&outcome) try testing.expect_equal(1, diagnostics.count(&diagnostic_store)) if (index == 0) { try testing.expect(outcome.trap == null) try testing.expect_equal(i64(42), outcome.value.data.integer) } else { try testing.expect_equal(original, outcome.trap?) } } }