/
buildExpression.ts
97 lines (93 loc) · 4.05 KB
/
buildExpression.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
import { BinaryExpression } from "./BinaryExpression.ts";
import { buildNumericLiteralExpression } from "./buildNumericLiteralExpression.ts";
import { buildParenthesizedExpression } from "./buildParenthesizedExpression.ts";
import { Expression } from "./Expression.ts";
import { ExpressionOperator } from "./ExpressionOperator.ts";
import { ExpressionType } from "./ExpressionType.ts";
import { getTokenType } from "./getTokenType.ts";
import { State } from "./State.ts";
import { Tokens } from "./Tokens.ts";
import { TokenType } from "./TokenType.ts";
import { transform } from "./transform.ts";
import { UnaryExpression } from "./UnaryExpression.ts";
import { valid_end_states } from "./valid_end_states.ts";
export function buildExpression(tokens: Tokens): Expression {
if (tokens.length === 0) {
throw Error("empty expression");
}
let state = State.initial;
const pendingtype: ExpressionType[] = [];
const pendingoperator: ExpressionOperator[] = [];
const pendingleft: Expression[] = [];
for (const token of tokens) {
const tokentype: TokenType = getTokenType(token);
if (tokentype === TokenType.unknown) throw Error("unknown token");
state = transform[state][tokentype] ?? State.unknown;
if (state === State.unknown) throw Error("unknown state");
if (state === State.unary) {
pendingtype.push("UnaryExpression");
if (typeof token === "string") {
pendingoperator.push(token as ExpressionOperator);
} else {
throw Error("accident token type");
}
}
if ([State.parentheses, State.number].includes(state)) {
const current_expression: Expression = State.number === state
? buildNumericLiteralExpression(token)
: buildParenthesizedExpression(token);
if (pendingtype.length === 0 && pendingoperator.length === 0) {
pendingleft.push(current_expression);
} else {
const type = pendingtype[pendingtype.length - 1];
pendingtype.pop();
const operator = pendingoperator[pendingoperator.length - 1];
pendingoperator.pop();
if (type === "BinaryExpression") {
//优先级更高
const left = pendingleft[pendingleft.length - 1];
if (
left.type === "BinaryExpression" &&
["*", "/"].includes(operator) &&
["+", "-"].includes(left.operator)
) {
left.right = {
type: "BinaryExpression",
operator: operator as BinaryExpression["operator"],
left: left.right,
right: current_expression,
};
} else {
pendingleft.pop();
pendingleft.push({
operator: operator as BinaryExpression["operator"],
type: "BinaryExpression",
left,
right: current_expression,
});
}
}
if (type === "UnaryExpression") {
pendingleft.push({
operator: operator as UnaryExpression["operator"],
type: "UnaryExpression",
argument: current_expression,
});
}
}
}
if (state === State.binary) {
pendingtype.push("BinaryExpression");
if (typeof token === "string") {
pendingoperator.push(token as ExpressionOperator);
} else {
throw Error("accident token type");
}
}
}
if (valid_end_states.includes(state) && pendingleft.length) {
return pendingleft[0];
} else {
throw new Error("unexpected end state or empty expression");
}
}