Files
honey/source/compilation/compilation.test.hon
T

182 lines
8.0 KiB
Plaintext

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 { return value }
`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 } }
`main proc() i16 {
` box Box(i16) :: { value = identity(i16, 40) }
` fixed Fixed(count()) :: { values = [box.value, 2] }
` same Fixed(2) :: fixed
` return identity(same.values[0]) + same.values[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?)
}
}
}