v / vlib / v2 / ast / flat_signature.v
56 lines · 52 sloc · 2.09 KB · f3c5760b8838272e4789c38a1be9e03f9ceac351
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. 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
6import strings
7
8// signature returns a canonical, content-addressed string representation of
9// the flat AST. Two flat ASTs produced from the same legacy AST must produce
10// identical signatures — this is the round-trip lossless invariant.
11//
12// The signature includes per-node fields (kind, flags, aux, extra, pos) and
13// resolves all interned strings to their text content, so signatures are
14// independent of the order in which the intern table was populated.
15pub fn (flat &FlatAst) signature() string {
16 mut sb := strings.new_builder(flat.nodes.len * 16)
17 for ff in flat.files {
18 sb.write_string('FILE name=${flat.string_at(ff.name_idx)} mod=${flat.string_at(ff.mod_idx)} root=')
19 flat.write_node_sig(mut sb, ff.file_id, 0)
20 sb.write_string('\n')
21 }
22 return sb.str()
23}
24
25// subtree_signature returns the same canonical, content-addressed string as
26// `signature()` but rooted at a single node id rather than the file roots.
27// Useful for tests that want to pin the shape of a specific subtree (e.g.
28// the `FlatBuilder.prepend_to_fn_body` bit-equality test) without managing
29// a file root or worrying about intern-order leakage in the `.file` node's
30// `extra` slot.
31pub fn (flat &FlatAst) subtree_signature(node_id FlatNodeId) string {
32 mut sb := strings.new_builder(128)
33 flat.write_node_sig(mut sb, node_id, 0)
34 return sb.str()
35}
36
37fn (flat &FlatAst) write_node_sig(mut sb strings.Builder, id FlatNodeId, depth int) {
38 if id < 0 || id >= flat.nodes.len {
39 sb.write_string('<nil>')
40 return
41 }
42 n := flat.nodes[id]
43 sb.write_string('(')
44 sb.write_string(n.kind.str())
45 sb.write_string(' flags=${n.flags:x} aux=${n.aux:x} extra=${n.extra} pos=${n.pos.offset}:${n.pos.id}')
46 if n.name_id >= 0 {
47 sb.write_string(' name="')
48 sb.write_string(flat.string_at(n.name_id))
49 sb.write_string('"')
50 }
51 for i in 0 .. n.edge_count {
52 sb.write_string(' ')
53 flat.write_node_sig(mut sb, flat.edges[n.first_edge + i].child_id, depth + 1)
54 }
55 sb.write_string(')')
56}
57