refactor: encapsulate compact syntax tree storage
This commit is contained in:
+42
-176
@@ -1,202 +1,68 @@
|
||||
import "@std/mem"
|
||||
import "@std/testing"
|
||||
|
||||
import "@source/diagnostics"
|
||||
import "@source/strpool"
|
||||
import "@source/lexer"
|
||||
import "@source/ast"
|
||||
|
||||
ast_renderer :: import "@source/ast/renderer"
|
||||
|
||||
handles_package_declarations test {
|
||||
parses_expression_precedence_through_tree_views test {
|
||||
strpool.STRINGS = strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strpool.STRINGS)
|
||||
|
||||
source ::
|
||||
`first int :: 42
|
||||
`second float :: 2.15 + 3
|
||||
`message :: "hello"
|
||||
|
||||
diagnostic_store := diagnostics.init(mem.c_allocator)
|
||||
defer diagnostics.deinit(&diagnostic_store)
|
||||
source :: "value :: 1 + 2 * 3\n"
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source)
|
||||
try lexer.scan(&scan_state, source, &diagnostic_store)
|
||||
|
||||
parse_state := init(mem.c_allocator)
|
||||
defer deinit(&parse_state)
|
||||
root :: try parse(&parse_state, scan_state.tokens.items)
|
||||
tree := try parse(scan_state.tokens.items, source, &diagnostic_store, mem.c_allocator)
|
||||
defer ast.deinit(&tree)
|
||||
|
||||
renderer := ast_renderer.init(mem.c_allocator)
|
||||
defer ast_renderer.deinit(&renderer)
|
||||
try ast_renderer.render_token_stream(&renderer, root, &parse_state, scan_state.tokens.items)
|
||||
|
||||
try testing.expect_equal(scan_state.tokens.items.len, renderer.tokens.items.len)
|
||||
for scan_state.tokens.items |expected, i| {
|
||||
actual :: renderer.tokens.items[i]
|
||||
try testing.expect_equal(expected.kind, actual.kind)
|
||||
try testing.expect_equal(expected.start, actual.start)
|
||||
try testing.expect_equal(expected.str_id, actual.str_id)
|
||||
}
|
||||
try testing.expect_equal(1, ast.package_decl_count(&tree))
|
||||
declaration :: ast.package_decl(&tree, 0)
|
||||
statement :: ast.statement_decl(&tree, declaration)
|
||||
try testing.expect_equal("value", ast.source_text(&tree, statement.name))
|
||||
try testing.expect_equal(ast.ExprKind.binary, ast.expr_kind(&tree, statement.initializer))
|
||||
add :: ast.binary_expr(&tree, statement.initializer)
|
||||
try testing.expect_equal(ast.BinaryOperator.add, add.operator)
|
||||
try testing.expect_equal(ast.ExprKind.literal_int, ast.expr_kind(&tree, add.left))
|
||||
try testing.expect_equal(ast.ExprKind.binary, ast.expr_kind(&tree, add.right))
|
||||
multiply :: ast.binary_expr(&tree, add.right)
|
||||
try testing.expect_equal(ast.BinaryOperator.multiply, multiply.operator)
|
||||
try testing.expect_equal(0, diagnostics.len(&diagnostic_store))
|
||||
}
|
||||
|
||||
handles_unary_arithmetic_prefix_expression test {
|
||||
parses_function_structure_through_tree_views test {
|
||||
strpool.STRINGS = strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strpool.STRINGS)
|
||||
|
||||
diagnostic_store := diagnostics.init(mem.c_allocator)
|
||||
defer diagnostics.deinit(&diagnostic_store)
|
||||
source ::
|
||||
`first :: -42 + 1
|
||||
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source)
|
||||
|
||||
parse_state := init(mem.c_allocator)
|
||||
defer deinit(&parse_state)
|
||||
root :: try parse(&parse_state, scan_state.tokens.items)
|
||||
|
||||
renderer := ast_renderer.init(mem.c_allocator)
|
||||
defer ast_renderer.deinit(&renderer)
|
||||
try ast_renderer.render_token_stream(&renderer, root, &parse_state, scan_state.tokens.items)
|
||||
|
||||
try testing.expect_equal(scan_state.tokens.items.len, renderer.tokens.items.len)
|
||||
for scan_state.tokens.items |expected, i| {
|
||||
actual :: renderer.tokens.items[i]
|
||||
try testing.expect_equal(expected.kind, actual.kind)
|
||||
try testing.expect_equal(expected.start, actual.start)
|
||||
try testing.expect_equal(expected.str_id, actual.str_id)
|
||||
}
|
||||
}
|
||||
|
||||
handles_binary_arithmetic_expression test {
|
||||
strpool.STRINGS = strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strpool.STRINGS)
|
||||
|
||||
source ::
|
||||
`first int :: 42 + 3
|
||||
`second :: 134 + 5
|
||||
`third float :: 1.35 + 2
|
||||
`fourth :: first + second
|
||||
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source)
|
||||
|
||||
parse_state := init(mem.c_allocator)
|
||||
defer deinit(&parse_state)
|
||||
root :: try parse(&parse_state, scan_state.tokens.items)
|
||||
|
||||
renderer := ast_renderer.init(mem.c_allocator)
|
||||
defer ast_renderer.deinit(&renderer)
|
||||
try ast_renderer.render_token_stream(&renderer, root, &parse_state, scan_state.tokens.items)
|
||||
|
||||
try testing.expect_equal(scan_state.tokens.items.len, renderer.tokens.items.len)
|
||||
for scan_state.tokens.items |expected, i| {
|
||||
actual :: renderer.tokens.items[i]
|
||||
try testing.expect_equal(expected.kind, actual.kind)
|
||||
try testing.expect_equal(expected.start, actual.start)
|
||||
try testing.expect_equal(expected.str_id, actual.str_id)
|
||||
}
|
||||
}
|
||||
|
||||
handles_statement_declaration test {
|
||||
strpool.STRINGS = strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strpool.STRINGS)
|
||||
|
||||
source ::
|
||||
`value int :: 42
|
||||
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source)
|
||||
|
||||
parse_state := init(mem.c_allocator)
|
||||
defer deinit(&parse_state)
|
||||
root :: try parse(&parse_state, scan_state.tokens.items)
|
||||
|
||||
renderer := ast_renderer.init(mem.c_allocator)
|
||||
defer ast_renderer.deinit(&renderer)
|
||||
try ast_renderer.render_token_stream(&renderer, root, &parse_state, scan_state.tokens.items)
|
||||
|
||||
try testing.expect_equal(scan_state.tokens.items.len, renderer.tokens.items.len)
|
||||
for scan_state.tokens.items |expected, i| {
|
||||
actual :: renderer.tokens.items[i]
|
||||
try testing.expect_equal(expected.kind, actual.kind)
|
||||
try testing.expect_equal(expected.start, actual.start)
|
||||
try testing.expect_equal(expected.str_id, actual.str_id)
|
||||
}
|
||||
}
|
||||
|
||||
handles_function_declarations test {
|
||||
strpool.STRINGS = strpool.init(mem.c_allocator)
|
||||
defer strpool.deinit(&strpool.STRINGS)
|
||||
|
||||
source ::
|
||||
`empty proc() void {}
|
||||
`grouped proc(a, b T, c U) void {
|
||||
` value int :: 1
|
||||
`}
|
||||
|
||||
scan_state := lexer.init(mem.c_allocator)
|
||||
defer lexer.deinit(&scan_state)
|
||||
try lexer.scan(&scan_state, source)
|
||||
try lexer.scan(&scan_state, source, &diagnostic_store)
|
||||
|
||||
parse_state := init(mem.c_allocator)
|
||||
defer deinit(&parse_state)
|
||||
root_id :: try parse(&parse_state, scan_state.tokens.items)
|
||||
root :: parse_state.nodes.items[usize(root_id)]
|
||||
tree := try parse(scan_state.tokens.items, source, &diagnostic_store, mem.c_allocator)
|
||||
defer ast.deinit(&tree)
|
||||
|
||||
package_start :: usize(root.data0.extra_id)
|
||||
package_end :: usize(root.data1.extra_id)
|
||||
try testing.expect_equal(usize(2), package_end - package_start)
|
||||
|
||||
empty_id :: ast.node_id(parse_state.extra.items[package_start])
|
||||
empty :: parse_state.nodes.items[usize(empty_id)]
|
||||
empty_payload :: usize(empty.data1.extra_id)
|
||||
empty_block :: parse_state.nodes.items[usize(empty.data0.node_id)]
|
||||
try testing.expect_equal(ast.NodeKind.func_decl, empty.kind)
|
||||
try testing.expect_equal(u32(0), parse_state.extra.items[empty_payload + 1])
|
||||
try testing.expect_equal(
|
||||
usize(empty_block.data0.extra_id),
|
||||
usize(empty_block.data1.extra_id),
|
||||
)
|
||||
|
||||
grouped_id :: ast.node_id(parse_state.extra.items[package_start + 1])
|
||||
grouped :: parse_state.nodes.items[usize(grouped_id)]
|
||||
grouped_payload :: usize(grouped.data1.extra_id)
|
||||
try testing.expect_equal(ast.NodeKind.func_decl, grouped.kind)
|
||||
try testing.expect_equal(u32(3), parse_state.extra.items[grouped_payload + 1])
|
||||
|
||||
param_a_id :: ast.node_id(parse_state.extra.items[grouped_payload + 2])
|
||||
param_b_id :: ast.node_id(parse_state.extra.items[grouped_payload + 3])
|
||||
param_c_id :: ast.node_id(parse_state.extra.items[grouped_payload + 4])
|
||||
param_a :: parse_state.nodes.items[usize(param_a_id)]
|
||||
param_b :: parse_state.nodes.items[usize(param_b_id)]
|
||||
param_c :: parse_state.nodes.items[usize(param_c_id)]
|
||||
try testing.expect_equal(ast.NodeKind.param_decl, param_a.kind)
|
||||
try testing.expect_equal(ast.NodeKind.param_decl, param_b.kind)
|
||||
try testing.expect_equal(ast.NodeKind.param_decl, param_c.kind)
|
||||
try testing.expect(param_a.data0.node_id == param_b.data0.node_id)
|
||||
try testing.expect(param_a.data0.node_id != param_c.data0.node_id)
|
||||
|
||||
grouped_block :: parse_state.nodes.items[usize(grouped.data0.node_id)]
|
||||
try testing.expect_equal(ast.NodeKind.block, grouped_block.kind)
|
||||
try testing.expect_equal(
|
||||
usize(1),
|
||||
usize(grouped_block.data1.extra_id) - usize(grouped_block.data0.extra_id),
|
||||
)
|
||||
|
||||
renderer := ast_renderer.init(mem.c_allocator)
|
||||
defer ast_renderer.deinit(&renderer)
|
||||
try ast_renderer.render_token_stream(
|
||||
&renderer,
|
||||
root_id,
|
||||
&parse_state,
|
||||
scan_state.tokens.items,
|
||||
)
|
||||
|
||||
try testing.expect_equal(scan_state.tokens.items.len, renderer.tokens.items.len)
|
||||
for scan_state.tokens.items |expected, i| {
|
||||
actual :: renderer.tokens.items[i]
|
||||
try testing.expect_equal(expected.kind, actual.kind)
|
||||
try testing.expect_equal(expected.start, actual.start)
|
||||
try testing.expect_equal(expected.str_id, actual.str_id)
|
||||
}
|
||||
declaration :: ast.package_decl(&tree, 0)
|
||||
try testing.expect_equal(ast.DeclKind.function, ast.decl_kind(&tree, declaration))
|
||||
function :: ast.function_decl(&tree, declaration)
|
||||
try testing.expect_equal("grouped", ast.source_text(&tree, function.name))
|
||||
try testing.expect_equal(3, ast.function_param_count(&tree, declaration))
|
||||
first :: ast.param(&tree, ast.function_param(&tree, declaration, 0))
|
||||
second :: ast.param(&tree, ast.function_param(&tree, declaration, 1))
|
||||
third :: ast.param(&tree, ast.function_param(&tree, declaration, 2))
|
||||
try testing.expect_equal("a", ast.source_text(&tree, first.name))
|
||||
try testing.expect_equal("b", ast.source_text(&tree, second.name))
|
||||
try testing.expect_equal("c", ast.source_text(&tree, third.name))
|
||||
try testing.expect_equal(first.type, second.type)
|
||||
try testing.expect(first.type != third.type)
|
||||
try testing.expect_equal(1, ast.block_statement_count(&tree, function.body))
|
||||
try testing.expect_equal(0, diagnostics.len(&diagnostic_store))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user