blob: 90902120a286d013e961959bdca15d30b66ed41d (
plain)
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
import { Token, TokenType } from "./Token";
export class ParseTree {
/**
* Create a tree from tokens. This consumes the tokens.
* @param tokens The tokens to create a tree for.
* @param inNested If currently allready nesting.
*/
public static CreateTree(tokens: Token[], inNested: boolean = false): ParseTree {
const tree: ParseTree = new ParseTree();
while (tokens.length > 0) {
const token: Token = tokens.shift();
switch (token.Type) {
case TokenType.OpenParenthesis:
tree.nodes.push(this.CreateTree(tokens, true));
break;
case TokenType.CloseParenthesis:
if (inNested === false) {
throw new Error("Unmatched closing parenthesis.");
}
return tree;
default:
tree.nodes.push(token);
break;
}
}
if (inNested === true) {
throw new Error("No match found for an opening parenthesis.");
}
return tree;
}
public nodes: Array<Token | ParseTree> = [];
/**
* Compact empty branches. Example ((foo))(((bar))) will become (foo)(bar)
* @param tree The ParseTree to compact. Defaults to the current tree.
*/
public Compact(tree: ParseTree = this): ParseTree {
const newTree: ParseTree = new ParseTree();
newTree.nodes = tree.nodes.map((n) => n);
const isNotCompact = (n) => n instanceof ParseTree && n.nodes.length === 1 && n.nodes[0] instanceof ParseTree;
// Compact current level of nodes to the maximum amount.
while (newTree.nodes.some((n) => isNotCompact(n))) {
newTree.nodes = newTree.nodes
.map((n) => n instanceof ParseTree && isNotCompact(n) ? n.nodes[0] : n);
}
// Compact all nested parsetrees and filter out empty branches.
newTree.nodes = newTree.nodes
.map((n) => n instanceof ParseTree ? this.Compact(n) : n);
return newTree;
}
/**
* Create string from the parsetree which is a representation of the original code.
*/
public ToString(tree: ParseTree = this): string {
let code: string = "";
for (const node of tree.nodes) {
if (node instanceof ParseTree) {
code += "(" + this.ToString(node) + ")";
continue;
}
switch (node.Type) {
case TokenType.Symbol:
code += code === "" ? node.Value : " " + node.Value;
break;
case TokenType.Pointer:
code += node.Value;
break;
case TokenType.Reference:
code += node.Value;
break;
case TokenType.ArraySubscript:
code += node.Value;
break;
case TokenType.CurlyBlock:
code += node.Value;
break;
case TokenType.Assignment:
code += " " + node.Value + " ";
break;
case TokenType.Comma:
code += node.Value;
break;
case TokenType.Arrow:
code += " " + node.Value + " ";
break;
case TokenType.Ellipsis:
code += node.Value;
break;
case TokenType.Attribute:
code += code === "" ? node.Value : " " + node.Value;
break;
}
}
return code;
}
/**
* Get the tree for the return.
*/
public GetReturnTree(): ParseTree {
const returnTree: ParseTree = new ParseTree();
const indexTrailingReturn: number = this.nodes
.findIndex((t) => t instanceof Token ? t.Type === TokenType.Arrow : false);
const isFuncPtr: boolean = this.nodes
.slice(0, indexTrailingReturn === -1 ? this.nodes.length : indexTrailingReturn)
.filter((n) => n instanceof ParseTree)
.length === 2;
if (isFuncPtr === true) {
const trees: ParseTree[] = this.nodes
.filter((n) => n instanceof ParseTree)
.map((n) => n as ParseTree);
// Add left most part to the return tokens.
for (const node of this.nodes) {
if (node instanceof ParseTree) {
break;
}
returnTree.nodes.push(node);
}
// add left and right parse tree to return tokens
const leftTree: ParseTree = new ParseTree();
for (const node of trees[0].nodes) {
if (node instanceof ParseTree) {
break;
}
leftTree.nodes.push(node);
}
returnTree.nodes.push(leftTree);
returnTree.nodes.push(trees[1]);
} else if (indexTrailingReturn !== -1) {
returnTree.nodes = this.nodes
.slice(indexTrailingReturn + 1, this.nodes.length);
// Don't include the auto so start from index 1.
for (let i: number = 1; i < this.nodes.length; i++) {
if (this.nodes[i] instanceof ParseTree) {
break;
}
returnTree.nodes.push(this.nodes[i]);
}
} else {
for (const node of this.nodes) {
if (node instanceof ParseTree) {
break;
}
returnTree.nodes.push(node);
}
}
return returnTree;
}
/**
* Get the arguments of the function and create a new ParseTree for each one.
*/
public GetArgTrees(): ParseTree[] {
const args: ParseTree[] = [];
const indexTrailingReturn: number = this.nodes
.findIndex((t) => t instanceof Token ? t.Type === TokenType.Arrow : false);
const isFuncPtr: boolean = this.nodes
.slice(0, indexTrailingReturn === -1 ? this.nodes.length : indexTrailingReturn)
.filter((n) => n instanceof ParseTree)
.length === 2;
let argsTree: ParseTree = this.nodes
.filter((n) => n instanceof ParseTree)
.map((t) => t as ParseTree)[0];
// If it is a func ptr get the nested tree.
if (isFuncPtr === true) {
argsTree = argsTree.nodes
.filter((n) => n instanceof ParseTree)
.map((t) => t as ParseTree)[0];
}
if (argsTree === undefined) {
throw new Error("Couldn't find arguments tree");
}
// split args at command and create a tree for each one.
let lastComma: number = 0;
for (let i = 0; i < argsTree.nodes.length; i++) {
const node = argsTree.nodes[i];
if (node instanceof Token && node.Type === TokenType.Comma) {
const tree: ParseTree = new ParseTree();
tree.nodes = argsTree.nodes.slice(lastComma, i);
args.push(tree);
lastComma = i + 1;
}
}
const lastArgTree: ParseTree = new ParseTree();
lastArgTree.nodes = argsTree.nodes.slice(lastComma, argsTree.nodes.length);
if (lastArgTree.nodes.length > 0) {
args.push(lastArgTree);
}
return args;
}
}
|