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