v / vlib / v2 / ast / flat_replace_fn_body_stmts_test.v
83 lines · 73 sloc · 2.81 KB · f3c5760b8838272e4789c38a1be9e03f9ceac351
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module ast
5
6// Tests for `FlatBuilder.replace_fn_body_stmts`. The companion primitive to
7// `prepend_to_fn_body`: replaces the FnDecl's body entirely (vs prepending
8// to it). Needed by `inject_live_reload` which builds a fully-rewritten
9// FnDecl body in one shot (preamble + rewritten for-stmts + rewritten calls).
10
11fn make_assert_stmt_value(value string) Stmt {
12 return Stmt(AssertStmt{
13 expr: Expr(BasicLiteral{
14 kind: .number
15 value: value
16 })
17 })
18}
19
20fn build_fn_decl(body_stmts []Stmt) (FlatBuilder, FlatNodeId) {
21 mut b := new_flat_builder()
22 fn_stmt := Stmt(FnDecl{
23 name: 'f'
24 stmts: body_stmts
25 })
26 fn_id := b.emit_stmt(fn_stmt)
27 return b, fn_id
28}
29
30fn ref_sig_for_fn_body(body_stmts []Stmt) string {
31 mut b, fn_id := build_fn_decl(body_stmts)
32 return b.flat.subtree_signature(fn_id)
33}
34
35fn sub_sig_for_replace(initial_body []Stmt, new_body_values []string) string {
36 mut b, fn_id := build_fn_decl(initial_body)
37 mut new_ids := []FlatNodeId{}
38 for v in new_body_values {
39 new_ids << b.emit_stmt(make_assert_stmt_value(v))
40 }
41 new_fn_id := b.replace_fn_body_stmts(fn_id, new_ids)
42 return b.flat.subtree_signature(new_fn_id)
43}
44
45fn test_replace_fn_body_stmts_signature_matches_reference() {
46 ref_sig := ref_sig_for_fn_body([make_assert_stmt_value('7'),
47 make_assert_stmt_value('8'), make_assert_stmt_value('9')])
48 sub_sig := sub_sig_for_replace([make_assert_stmt_value('1'),
49 make_assert_stmt_value('2')], ['7', '8', '9'])
50 assert ref_sig == sub_sig
51}
52
53fn test_replace_fn_body_stmts_empty_new_body() {
54 // Replacing with an empty body — the fn becomes bodyless.
55 ref_sig := ref_sig_for_fn_body([]Stmt{})
56 sub_sig := sub_sig_for_replace([make_assert_stmt_value('1')], []string{})
57 assert ref_sig == sub_sig
58}
59
60fn test_replace_fn_body_stmts_invalid_id_returns_invalid() {
61 mut b := new_flat_builder()
62 x_id := b.emit_stmt(make_assert_stmt_value('1'))
63 returned_id := b.replace_fn_body_stmts(FlatNodeId(-1), [x_id])
64 assert returned_id == invalid_flat_node_id
65}
66
67fn test_replace_fn_body_stmts_non_fn_kind_returns_invalid() {
68 mut b := new_flat_builder()
69 // stmt_assert, not stmt_fn_decl — kind check must reject it.
70 assert_id := b.emit_stmt(make_assert_stmt_value('1'))
71 x_id := b.emit_stmt(make_assert_stmt_value('2'))
72 returned_id := b.replace_fn_body_stmts(assert_id, [x_id])
73 assert returned_id == invalid_flat_node_id
74}
75
76fn test_replace_fn_body_stmts_returns_new_id() {
77 mut b, fn_id := build_fn_decl([make_assert_stmt_value('1')])
78 x_id := b.emit_stmt(make_assert_stmt_value('2'))
79 new_fn_id := b.replace_fn_body_stmts(fn_id, [x_id])
80 // New id must differ from the original — the old fn is unreachable garbage.
81 assert new_fn_id != fn_id
82 assert new_fn_id != invalid_flat_node_id
83}
84