-
Notifications
You must be signed in to change notification settings - Fork 1
/
codegen.ts
120 lines (114 loc) · 2.2 KB
/
codegen.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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import {
FunctionDeclaration,
SwitchCase,
SwitchStatement,
Identifier,
Literal,
UnaryExpression,
ReturnStatement
} from 'estree';
import { Dfa, Transitions } from './dfa';
function stateId(): Identifier {
return {
type: 'Identifier',
name: 'state'
};
}
function charId(): Identifier {
return {
type: 'Identifier',
name: 'char'
};
}
function numberLit(value: number): Literal | UnaryExpression {
if (value < 0) {
return {
type: 'UnaryExpression',
operator: '-',
prefix: true,
argument: numberLit(-value)
};
}
return {
type: 'Literal',
value
};
}
function transitionsToAst(transitions: Transitions): SwitchStatement {
let cases: SwitchCase[] = [];
for (let [target, chars] of transitions) {
if (chars === null) {
cases.push({
type: 'SwitchCase',
test: null,
consequent: []
});
} else {
if (chars.isEmpty()) {
throw new TypeError(`Unexpected transition from empty set of chars.`);
}
for (let ch of chars) {
cases.push({
type: 'SwitchCase',
test: Object.assign(numberLit(ch), {
trailingComments: [
{
type: 'Block',
value: ` ${ch !== -1
? JSON.stringify(String.fromCharCode(ch))
: 'final'} `
}
]
}),
consequent: []
});
}
}
let returnStmt: ReturnStatement = {
type: 'ReturnStatement',
argument: numberLit(target)
};
if (target < 0) {
returnStmt.trailingComments = [
{
type: 'Line',
value: ` ${target === -1 ? 'error' : 'success'}`
}
];
}
cases[cases.length - 1].consequent.push(returnStmt);
}
return {
type: 'SwitchStatement',
discriminant: charId(),
cases
};
}
function dfaToAst(dfa: Dfa): SwitchStatement {
return {
type: 'SwitchStatement',
discriminant: stateId(),
cases: dfa
.entrySeq()
.map(([id, transitions]): SwitchCase => ({
type: 'SwitchCase',
test: numberLit(id),
consequent: [transitionsToAst(transitions)]
}))
.toArray()
};
}
export function toAst(name: string, dfa: Dfa): FunctionDeclaration {
return {
type: 'FunctionDeclaration',
id: {
type: 'Identifier',
name
},
params: [stateId(), charId()],
body: {
type: 'BlockStatement',
body: [dfaToAst(dfa)]
}
};
}