-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnameAnalysis.ts
71 lines (66 loc) · 2.36 KB
/
nameAnalysis.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* Helper functions that are used during namy analysis
*/
import type { RA } from '../utils/types.js';
import type { AstNode } from './definitions/AstNode.js';
import type { FunctionDeclaration } from './definitions/FunctionDeclaration.js';
import type { GlobalsNode } from './definitions/GlobalsNode.js';
import type { ForNode } from './definitions/statement/block/ForNode.js';
import type { IfNode } from './definitions/statement/block/IfNode.js';
import type { WhileNode } from './definitions/statement/block/WhileNode.js';
import type { VariableDeclaration } from './definitions/statement/VariableDeclaration.js';
import type { IdNode } from './definitions/term/IdNode.js';
export type Scope = {
readonly items: RA<FunctionDeclaration | VariableDeclaration>;
readonly node:
| ForNode
| FunctionDeclaration
| GlobalsNode
| IfNode
| WhileNode;
readonly addItem: (
item: FunctionDeclaration | VariableDeclaration,
dry?: boolean
) => void;
};
export type NameAnalysisContext = {
readonly symbolTable: RA<Scope>;
// If IdNode is used inside a declaration, supress undefined identifier errors
readonly isDeclaration: boolean;
readonly reportError: (idNode: IdNode, message: string) => void;
};
export function getScope(node: AstNode) {
const currentScope = node.nameAnalysisContext.symbolTable.at(-1);
if (currentScope === undefined)
throw new Error('Trying to declare a function outside of scope');
else return currentScope;
}
export const findDeclaration = (
name: string,
context: NameAnalysisContext
): FunctionDeclaration | VariableDeclaration | undefined =>
Array.from(context.symbolTable)
.reverse()
.flatMap(({ items }) => items)
.find((item) => item.id.getName() === name);
/**
* Call this to receive a new scope that can be added to the SymbolTable.
*/
export const createScope = (
node: ForNode | FunctionDeclaration | GlobalsNode | IfNode | WhileNode
): Scope => ({
items: node.declarations,
node,
addItem: (item, dry) => {
const itemName = item.id.getName();
const duplicateIdentifier = node.declarations.find(
(declaration) => declaration.id.getName() === itemName
);
if (typeof duplicateIdentifier === 'object')
node.nameAnalysisContext.reportError(
item.id,
'Multiply declared identifier'
);
else if (dry !== true) node.declarations.push(item);
},
});