feat: support enums, distinct types, unions and matching
This commit is contained in:
@@ -940,7 +940,6 @@ recovers_missing_logical_operands_and_preserves_enclosing_nodes test {
|
||||
tree := try parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
|
||||
defer ast.deinit(&tree)
|
||||
|
||||
try testing.expect_equal(6, diagnostics.count(&diagnostic_store))
|
||||
try testing.expect_equal(2, ast.package_decl_count(&tree))
|
||||
function :: ast.function_decl(&tree, ast.package_decl(&tree, 0))
|
||||
try testing.expect_equal(5, ast.block_statement_count(&tree, function.body))
|
||||
@@ -952,6 +951,11 @@ recovers_missing_logical_operands_and_preserves_enclosing_nodes test {
|
||||
try testing.expect_equal(ast.BinaryOperator.logical_or, second_or.operator)
|
||||
second_and :: ast.binary_expr(&tree, second_or.left)
|
||||
try testing.expect_equal(ast.ExprKind.invalid, ast.expr_kind(&tree, second_and.right))
|
||||
missing :: ast.invalid(&tree, second_and.right)
|
||||
diagnostic :: diagnostics.get(&diagnostic_store, missing.diagnostic)?
|
||||
try testing.expect_equal(diagnostics.Code.unexpected_token, diagnostic.code)
|
||||
try testing.expect_equal(missing.span.start, diagnostic.span.start)
|
||||
try testing.expect_equal(missing.span.end, diagnostic.span.end)
|
||||
try testing.expect_equal(ast.ExprKind.literal_bool, ast.expr_kind(&tree, second_or.right))
|
||||
third :: ast.statement_decl(&tree, ast.block_statement(&tree, function.body, 2))
|
||||
try testing.expect_equal(2, ast.call_arg_count(&tree, third.initializer))
|
||||
@@ -1036,13 +1040,17 @@ rejects_control_tails_and_preserves_following_declarations test {
|
||||
try lexer.scan(&scan_state, source, &strings, &diagnostic_store)
|
||||
tree := try parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
|
||||
defer ast.deinit(&tree)
|
||||
try testing.expect_equal(9, diagnostics.count(&diagnostic_store))
|
||||
try testing.expect_equal(6, ast.package_decl_count(&tree))
|
||||
for (usize(0)..usize(2)) |index| try testing.expect_equal(ast.DeclKind.invalid, ast.decl_kind(&tree, ast.package_decl(&tree, index)))
|
||||
for (usize(2)..usize(4)) |index| {
|
||||
declaration :: ast.package_decl(&tree, index)
|
||||
try testing.expect_equal(ast.DeclKind.statement, ast.decl_kind(&tree, declaration))
|
||||
try testing.expect_equal(ast.ExprKind.invalid, ast.expr_kind(&tree, ast.statement_decl(&tree, declaration).initializer))
|
||||
invalid :: ast.invalid(&tree, ast.statement_decl(&tree, declaration).initializer)
|
||||
diagnostic :: diagnostics.get(&diagnostic_store, invalid.diagnostic)?
|
||||
try testing.expect_equal(diagnostics.Code.unexpected_token, diagnostic.code)
|
||||
try testing.expect_equal(invalid.span.start, diagnostic.span.start)
|
||||
try testing.expect_equal(invalid.span.end, diagnostic.span.end)
|
||||
}
|
||||
body :: ast.function_decl(&tree, ast.package_decl(&tree, 4)).body
|
||||
try testing.expect_equal(2, ast.block_statement_count(&tree, body))
|
||||
@@ -1588,3 +1596,117 @@ rolls_back_shared_nodes_extra_spans_and_diagnostics_on_allocation_failure test {
|
||||
}
|
||||
try testing.expect(failures > 0)
|
||||
}
|
||||
|
||||
parses_enum_union_wrappers_and_keyword_variants test {
|
||||
strings := strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strings)
|
||||
diagnostic_store := diagnostics.init(mem.c_allocator)
|
||||
defer diagnostics.deinit(&diagnostic_store)
|
||||
source ::
|
||||
`Tag :: enum(i32) { if = -2, else = 3 # preserve the member boundary
|
||||
` return
|
||||
`}
|
||||
`Payload :: union(Tag) { if i32, else void, return struct { value i32 } }
|
||||
`Auto :: union(enum) { value i32, empty void }
|
||||
`Raw :: union { integer i32, real f64 }
|
||||
`Id :: distinct i32
|
||||
`Other :: alias Id
|
||||
`value Payload :: Payload{ if = 4 }
|
||||
`context Payload :: .return{value = 5}
|
||||
`empty Payload :: .else
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source, &strings, &diagnostic_store)
|
||||
tree := try parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
|
||||
defer ast.deinit(&tree)
|
||||
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
||||
try testing.expect_equal(9, ast.package_decl_count(&tree))
|
||||
enumeration :: ast.statement_decl(&tree, ast.package_decl(&tree, 0)).initializer
|
||||
try testing.expect(ast.enum_type(&tree, enumeration).backing != null)
|
||||
try testing.expect_equal(3, ast.enum_member_count(&tree, enumeration))
|
||||
member :: ast.field(&tree, ast.enum_member(&tree, enumeration, 0))
|
||||
try testing.expect_equal("if", strpool.get_str(&strings, ast.name_id(&tree, member.name?))?)
|
||||
try testing.expect_equal(ast.ExprKind.unary, ast.expr_kind(&tree, member.value?))
|
||||
tagged :: ast.statement_decl(&tree, ast.package_decl(&tree, 1)).initializer
|
||||
automatic :: ast.statement_decl(&tree, ast.package_decl(&tree, 2)).initializer
|
||||
raw :: ast.statement_decl(&tree, ast.package_decl(&tree, 3)).initializer
|
||||
try testing.expect(ast.union_type(&tree, tagged).tag != null)
|
||||
try testing.expect(ast.union_type(&tree, automatic).auto_tag)
|
||||
try testing.expect(!ast.union_type(&tree, raw).auto_tag)
|
||||
try testing.expect_equal(2, ast.record_field_count(&tree, raw))
|
||||
distinct_type :: ast.statement_decl(&tree, ast.package_decl(&tree, 4)).initializer
|
||||
alias_value :: ast.statement_decl(&tree, ast.package_decl(&tree, 5)).initializer
|
||||
try testing.expect_equal(ast.ExprKind.distinct_type, ast.expr_kind(&tree, distinct_type))
|
||||
try testing.expect_equal(ast.ExprKind.alias_expr, ast.expr_kind(&tree, alias_value))
|
||||
contextual :: ast.statement_decl(&tree, ast.package_decl(&tree, 7)).initializer
|
||||
variant :: ast.record_literal(&tree, contextual).type?
|
||||
try testing.expect_equal(ast.ExprKind.enum_literal, ast.expr_kind(&tree, variant))
|
||||
try testing.expect_equal("return", strpool.get_str(&strings, ast.name_id(&tree, ast.enum_literal(&tree, variant)))?)
|
||||
}
|
||||
|
||||
parses_match_patterns_payload_captures_and_statement_arms test {
|
||||
strings := strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strings)
|
||||
diagnostic_store := diagnostics.init(mem.c_allocator)
|
||||
defer diagnostics.deinit(&diagnostic_store)
|
||||
source ::
|
||||
`choose proc(value int) int {
|
||||
` return match value {
|
||||
` 0, 1..=3: 10,
|
||||
` 4: 20 # preserve the arm boundary
|
||||
` else: 30
|
||||
` }
|
||||
`}
|
||||
`use proc(value int) void {
|
||||
` match value {
|
||||
` .if, .return |payload|: { local :: payload }
|
||||
` .else: return,
|
||||
` else: {}
|
||||
` }
|
||||
`}
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source, &strings, &diagnostic_store)
|
||||
tree := try parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
|
||||
defer ast.deinit(&tree)
|
||||
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
||||
choose :: ast.function_decl(&tree, ast.package_decl(&tree, 0))
|
||||
value_match :: ast.return_stmt(&tree, ast.block_statement(&tree, choose.body, 0)).value?
|
||||
try testing.expect_equal(3, ast.match_arm_count(&tree, value_match))
|
||||
first :: ast.match_arm(&tree, value_match, 0)
|
||||
try testing.expect_equal(2, ast.match_pattern_count(&tree, first))
|
||||
try testing.expect_equal(ast.ExprKind.range, ast.expr_kind(&tree, ast.match_pattern(&tree, first, 1)))
|
||||
try testing.expect(ast.match_arm_view(&tree, first).expression)
|
||||
use :: ast.function_decl(&tree, ast.package_decl(&tree, 1))
|
||||
statement_match :: ast.statement_expr(&tree, ast.block_statement(&tree, use.body, 0))
|
||||
captured :: ast.match_arm_view(&tree, ast.match_arm(&tree, statement_match, 0))
|
||||
try testing.expect(captured.capture != null)
|
||||
try testing.expect(!captured.expression)
|
||||
try testing.expect(ast.match_arm_view(&tree, ast.match_arm(&tree, statement_match, 2)).catch_all)
|
||||
}
|
||||
|
||||
rejects_pointer_match_captures_and_preserves_siblings test {
|
||||
strings := strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strings)
|
||||
diagnostic_store := diagnostics.init(mem.c_allocator)
|
||||
defer diagnostics.deinit(&diagnostic_store)
|
||||
source ::
|
||||
`broken :: enum { first
|
||||
`after :: 1
|
||||
`use proc(value int) void {
|
||||
` match value {
|
||||
` .item |@payload|: payload
|
||||
` else: {}
|
||||
` }
|
||||
`}
|
||||
`last :: 2
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source, &strings, &diagnostic_store)
|
||||
tree := try parse(mem.c_allocator, scan_state.tokens.items, source, &diagnostic_store)
|
||||
defer ast.deinit(&tree)
|
||||
try testing.expect(diagnostics.count(&diagnostic_store) > 0)
|
||||
try testing.expect_equal(4, ast.package_decl_count(&tree))
|
||||
try testing.expect_equal("after", ast.source_text(&tree, ast.statement_decl(&tree, ast.package_decl(&tree, 1)).name))
|
||||
try testing.expect_equal("last", ast.source_text(&tree, ast.statement_decl(&tree, ast.package_decl(&tree, 3)).name))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user