Skip to content
← Back

src/syntax/process/interface_signature.ghul

1
namespace Syntax is
2
use System.Text.StringBuilder
3
4
use Trees
5
6
// Walks a parsed file's declaration syntax tree nodes — every node except
7
// the code inside method, function and accessor bodies — and builds a
8
// signature string from them. Two parses of a file with the same
9
// signature have the same interface: anything another file could resolve
10
// against (a name, a type, a modifier, the declaration structure) is
11
// folded in, while body code is skipped. The analyser compares signatures
12
// across an EDIT to tell whether the edit could affect any other file.
13
class INTERFACE_SIGNATURE: StrictVisitor is
14
_builder: StringBuilder
15
16
init() is
17
super.init()
18
19
_builder = StringBuilder()
20
si
21
22
signature: string => _builder.to_string()
23
24
// StrictVisitor routes every node it has no specific handler for to
25
// throw_not_implemented; nothing here overrides a visit, so every node
26
// arrives here. Fold the node kind, plus the salient text of the
27
// content-bearing leaves (identifiers, modifiers, literals) — node
28
// kind alone would miss a rename or a changed literal.
29
throw_not_implemented(name: string, node: Node) is
30
_builder.append(name)
31
32
let identifier = cast Identifiers.Identifier?(node)
33
let modifier = cast Modifiers.Modifier?(node)
34
let literal = cast Expressions.Literals.Literal?(node)
35
36
if identifier? then
37
for part in identifier.names do
38
_builder.append(':').append(part)
39
od
40
elif modifier? then
41
_builder.append(':').append(modifier.name)
42
elif literal? then
43
_builder.append(':').append(literal.value_string)
44
fi
45
46
_builder.append(';')
47
si
48
49
// Reached only by a node type with no visit handler at all — fold its
50
// kind so structure is still captured rather than throwing.
51
visit(node: Node) is
52
_builder.append("node;")
53
si
54
55
// Skip the code inside method, function and accessor bodies: an edit
56
// confined to a body must not change the signature. The pre/accept
57
// split means the body node itself is still visited (its kind
58
// folded), so making a method abstract vs concrete is still caught —
59
// only the body interior is excluded.
60
pre(block: Bodies.BLOCK) -> bool => true
61
pre(expression: Bodies.EXPRESSION) -> bool => true
62
pre(innate_body: Bodies.INNATE) -> bool => true
63
pre(null_body: Bodies.NULL) -> bool => true
64
si
65
si