-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparselet.ts
144 lines (125 loc) · 3.9 KB
/
parselet.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { Expression, Statement, Token } from "./ast.ts";
import { lambda } from "./ast_builder.ts";
import { Parser, Precedence } from "./parser.ts";
import * as ast from "./ast.ts";
export interface PrefixParselet {
parse(parser: Parser, token: Token): Expression;
}
export interface InfixParselet {
parse(parser: Parser, left: Expression, token: Token): Expression;
precedence(): number;
}
export class NumberParselet implements PrefixParselet {
parse(_parser: Parser, token: Token): Expression {
return new ast.NumberLiteral(+token.lexeme);
}
}
export class BinaryExpressionParselet implements InfixParselet {
private _precedence: number;
constructor(precedence: number) {
this._precedence = precedence;
}
parse(parser: Parser, left: Expression, token: Token): Expression {
const right = parser.parse_expression(this.precedence());
return new ast.Binary(
this.to_operator(token),
left,
right,
);
}
precedence(): number {
return this._precedence;
}
private to_operator(
token: Token,
): ast.BinaryOperator {
switch (token.type) {
case "Minus":
case "LessThan":
case "GreaterThan":
case "Plus":
case "LessThanEqual":
case "GreaterThanEqual":
return token.type;
default:
throw new Error(`Unexpected token: ${token.type}`);
}
}
}
export class ChannelReceive implements PrefixParselet {
parse(parser: Parser, _token: Token): Expression {
const channel = parser.parse_expression();
return new ast.ChannelReceive(channel);
}
}
export class IdentifierParselet implements PrefixParselet {
parse(_parser: Parser, token: Token): Expression {
return new ast.Identifier(token.lexeme);
}
}
export class StringParselet implements PrefixParselet {
parse(_parser: Parser, token: Token): Expression {
const value = token.lexeme.substring(1, token.lexeme.length - 1);
return new ast.StringLiteral(value);
}
}
export class NilParselet implements PrefixParselet {
parse(_parser: Parser, _token: Token): Expression {
return new ast.NilLiteral();
}
}
export class PropertyAccessParselet implements InfixParselet {
parse(parser: Parser, left: Expression, _token: Token): Expression {
const property = parser.consume("Identifier");
return new ast.PropertyAccess(left, property.lexeme);
}
precedence(): number {
return Precedence.MEMBER_ACCESS;
}
}
export class CallParselet implements InfixParselet {
parse(parser: Parser, left: Expression, _token: Token): Expression {
const args = parser.parse_delimited("Comma", "RightParen", () => {
return parser.parse_expression();
});
return new ast.Call(left, args);
}
precedence(): number {
return Precedence.CALL;
}
}
export class LambdaParselet implements PrefixParselet {
parse(parser: Parser, _token: Token): Expression {
const params = parser.parse_delimited("Comma", "Pipe", () => {
return parser.consume("Identifier").lexeme;
});
parser.consume("LeftBrace");
const body: Statement[] = [];
while (parser.peek().type !== "RightBrace") {
body.push(parser.parse_statement());
}
parser.consume("RightBrace");
return lambda(params, body);
}
}
export class ObjectLiteralParselet implements PrefixParselet {
parse(parser: Parser, _token: Token): Expression {
const properties = parser.parse_delimited("Comma", "RightBrace", () => {
const name = parser.consume("Identifier").lexeme;
parser.consume("Colon");
const value = parser.parse_expression();
return { name, value };
});
return new ast.ObjectLiteral(properties);
}
}
export class TrueLiteralParselet implements PrefixParselet {
parse(_parser: Parser, _token: Token): Expression {
return ast.BooleanLiteral.TRUE;
}
}
export class FalseLiteralParselet implements PrefixParselet {
parse(_parser: Parser, _token: Token): Expression {
return ast.BooleanLiteral.FALSE;
}
}