feat: support enums, distinct types, unions and matching

This commit is contained in:
2026-10-25 23:16:09 +01:00
parent 280059d83d
commit 9966a1f523
23 changed files with 3049 additions and 176 deletions
+123
View File
@@ -809,3 +809,126 @@ resolves_interleaved_compilations_with_independent_identifier_orders test {
try testing.expect_equal(usize(0), diagnostics.count(&first_diagnostics))
try testing.expect_equal(usize(0), diagnostics.count(&second_diagnostics))
}
resolves_match_capture_scopes_without_looking_up_member_names test {
pool := strpool.init(mem.c_allocator)
defer strpool.deinit(&pool)
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
source ::
`Tag :: enum { if, else }
`Value :: union(Tag) { if i32, else void }
`inspect proc(value Value) void {
` match value {
` .if |payload|: { local :: payload }
` .else: { local :: 1 }
` }
` payload
` local
`}
scan_state := lexer.init(mem.c_allocator)
defer lexer.deinit(&scan_state)
try lexer.scan(&scan_state, source, &pool, &diagnostic_store)
tree := try parser.parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
defer ast.deinit(&tree)
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
resolution := try resolve(mem.c_allocator, &tree, &pool, &diagnostic_store)
defer deinit(&resolution)
try testing.expect_equal(2, diagnostics.count(&diagnostic_store))
body :: ast.function_decl(&tree, ast.package_decl(&tree, 2)).body
matched :: ast.statement_expr(&tree, ast.block_statement(&tree, body, 0))
first :: ast.match_arm(&tree, matched, 0)
arm :: ast.match_arm_view(&tree, first)
local :: ast.statement_decl(&tree, ast.block_statement(&tree, arm.body, 0))
try testing.expect_equal(arm.capture?, binding(&resolution, local.initializer).data.declaration)
member :: ast.enum_literal(&tree, ast.match_pattern(&tree, first, 0))
try testing.expect_equal(BindingKind.none, binding(&resolution, member).kind)
for (usize(1)..usize(3)) |index| {
reference :: ast.statement_expr(&tree, ast.block_statement(&tree, body, index))
try testing.expect_equal(BindingKind.invalid, binding(&resolution, reference).kind)
}
}
canonicalizes_forward_function_global_and_builtin_aliases test {
pool := strpool.init(mem.c_allocator)
defer strpool.deinit(&pool)
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
source ::
`invoke :: alias call
`copy :: alias storage
`Number :: alias i32
`call :: alias original
`original proc() i32 { return storage }
`storage i32 := 1
`main proc() Number {
` copy = invoke()
` return copy
`}
scan_state := lexer.init(mem.c_allocator)
defer lexer.deinit(&scan_state)
try lexer.scan(&scan_state, source, &pool, &diagnostic_store)
tree := try parser.parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
defer ast.deinit(&tree)
resolution := try resolve(mem.c_allocator, &tree, &pool, &diagnostic_store)
defer deinit(&resolution)
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
original :: ast.package_decl(&tree, 4)
storage :: ast.package_decl(&tree, 5)
main :: ast.function_decl(&tree, ast.package_decl(&tree, 6))
assignment :: ast.assignment_stmt(&tree, ast.block_statement(&tree, main.body, 0))
try testing.expect_equal(storage, binding(&resolution, assignment.target).data.declaration)
try testing.expect_equal(original, binding(&resolution, ast.call_expr(&tree, assignment.value).callee).data.declaration)
try testing.expect_equal(BindingKind.builtin, binding(&resolution, main.return_type).kind)
try testing.expect_equal(BuiltinType.i32, binding(&resolution, main.return_type).data.builtin)
try testing.expect_equal(original, binding(&resolution, ast.package_decl(&tree, 0)).data.declaration)
}
canonicalizes_imported_aliases_and_namespace_alias_selections test {
pool := strpool.init(mem.c_allocator)
defer strpool.deinit(&pool)
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
builder := ast.init_builder(mem.c_allocator, "")
defer ast.deinit_builder(&builder)
library_source :: "original proc() i32 { return storage }\nstorage i32 := 1\nexported :: alias original\n"
library_id :: try ast.set_source(&builder, "library.hon", library_source)
library_scan := lexer.init(mem.c_allocator)
defer lexer.deinit(&library_scan)
library_scan.source_id = library_id
try lexer.scan(&library_scan, library_source, &pool, &diagnostic_store)
library :: try parser.parse_source(&builder, library_scan.tokens.items, &diagnostic_store)
main_source ::
`lib :: import "library"
`invoke :: alias namespace.exported
`copy :: alias namespace.storage
`namespace :: alias lib
`main proc() i32 { copy = invoke()
` return copy
`}
main_id :: try ast.set_source(&builder, "main.hon", main_source)
main_scan := lexer.init(mem.c_allocator)
defer lexer.deinit(&main_scan)
main_scan.source_id = main_id
try lexer.scan(&main_scan, main_source, &pool, &diagnostic_store)
root :: try parser.parse_source(&builder, main_scan.tokens.items, &diagnostic_store)
tree := ast.finish(&builder, root)
defer ast.deinit(&tree)
roots [2]ast.NodeId :: [root, library]
imports [1]Import :: [Import{
node = ast.package_decl_at(&tree, root, 0),
name = strpool.get_id(&pool, "lib")?,
target = library,
}]
resolution := try resolve_packages(mem.c_allocator, &tree, roots[..], imports[..], &pool, &diagnostic_store)
defer deinit(&resolution)
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
original :: ast.package_decl_at(&tree, library, 0)
storage :: ast.package_decl_at(&tree, library, 1)
main :: ast.function_decl(&tree, ast.package_decl_at(&tree, root, 4))
assignment :: ast.assignment_stmt(&tree, ast.block_statement(&tree, main.body, 0))
try testing.expect_equal(storage, binding(&resolution, assignment.target).data.declaration)
try testing.expect_equal(original, binding(&resolution, ast.call_expr(&tree, assignment.value).callee).data.declaration)
namespace :: ast.package_decl_at(&tree, root, 3)
try testing.expect_equal(BindingKind.namespace, binding(&resolution, namespace).kind)
}