meaoiu 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/execution.d.ts +1 -1
- package/dist/api/execution.d.ts.map +1 -1
- package/dist/api/execution.js +3 -3
- package/dist/api/execution.js.map +1 -1
- package/dist/api/serviceState.d.ts.map +1 -1
- package/dist/api/serviceState.js +4 -7
- package/dist/api/serviceState.js.map +1 -1
- package/dist/api/services/completions.js +1 -1
- package/dist/api/services/completions.js.map +1 -1
- package/dist/api/services/formatting.d.ts.map +1 -1
- package/dist/api/services/formatting.js +27 -38
- package/dist/api/services/formatting.js.map +1 -1
- package/dist/api/services/inlayHints.d.ts +2 -2
- package/dist/api/services/inlayHints.d.ts.map +1 -1
- package/dist/api/services/inlayHints.js +2 -2
- package/dist/api/utils/astUtils.js +6 -6
- package/dist/api/utils/symbolAnalyzer.d.ts +1 -2
- package/dist/api/utils/symbolAnalyzer.d.ts.map +1 -1
- package/dist/api/utils/symbolAnalyzer.js +62 -47
- package/dist/api/utils/symbolAnalyzer.js.map +1 -1
- package/dist/api/utils/symbolTable.d.ts +3 -3
- package/dist/api/utils/symbolTable.d.ts.map +1 -1
- package/dist/cli/main.js +1 -1
- package/dist/cli/tools/completer.js +8 -4
- package/dist/cli/tools/completer.js.map +1 -1
- package/dist/cli/tools/diagnoser.js +2 -1
- package/dist/cli/tools/diagnoser.js.map +1 -1
- package/dist/cli/tools/starter.js +2 -1
- package/dist/cli/tools/starter.js.map +1 -1
- package/dist/core/ast.d.ts +14 -22
- package/dist/core/ast.d.ts.map +1 -1
- package/dist/core/builtIns.d.ts +4 -3
- package/dist/core/builtIns.d.ts.map +1 -1
- package/dist/core/builtIns.js +4 -6
- package/dist/core/builtIns.js.map +1 -1
- package/dist/core/error.d.ts +5 -12
- package/dist/core/error.d.ts.map +1 -1
- package/dist/core/error.js +9 -20
- package/dist/core/error.js.map +1 -1
- package/dist/core/lexer/preprocessor.d.ts.map +1 -0
- package/dist/core/{preprocessor.js → lexer/preprocessor.js} +1 -1
- package/dist/core/lexer/preprocessor.js.map +1 -0
- package/dist/core/lexer/tokenizer.d.ts +115 -0
- package/dist/core/lexer/tokenizer.d.ts.map +1 -0
- package/dist/core/lexer/tokenizer.js +295 -0
- package/dist/core/lexer/tokenizer.js.map +1 -0
- package/dist/core/parser.d.ts +2 -78
- package/dist/core/parser.d.ts.map +1 -1
- package/dist/core/parser.js +116 -104
- package/dist/core/parser.js.map +1 -1
- package/dist/core/run/environment.d.ts +3 -2
- package/dist/core/run/environment.d.ts.map +1 -1
- package/dist/core/run/environment.js +6 -7
- package/dist/core/run/environment.js.map +1 -1
- package/dist/core/run/interpreter.d.ts.map +1 -1
- package/dist/core/run/interpreter.js +60 -54
- package/dist/core/run/interpreter.js.map +1 -1
- package/dist/core/typedef.d.ts +19 -9
- package/dist/core/typedef.d.ts.map +1 -1
- package/dist/core/typedef.js +26 -20
- package/dist/core/typedef.js.map +1 -1
- package/package.json +3 -3
- package/dist/core/preprocessor.d.ts.map +0 -1
- package/dist/core/preprocessor.js.map +0 -1
- package/dist/core/tokenizer.d.ts +0 -82
- package/dist/core/tokenizer.d.ts.map +0 -1
- package/dist/core/tokenizer.js +0 -277
- package/dist/core/tokenizer.js.map +0 -1
- /package/dist/core/{preprocessor.d.ts → lexer/preprocessor.d.ts} +0 -0
package/dist/core/parser.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as AST from './ast.js';
|
|
2
2
|
import { MeaoiuError } from './error.js';
|
|
3
|
-
import { type Token } from './tokenizer.js';
|
|
3
|
+
import { type Token } from './lexer/tokenizer.js';
|
|
4
4
|
export declare const enum ParseMode {
|
|
5
5
|
STRICT = 0,
|
|
6
6
|
TOLERANT = 1
|
|
@@ -9,81 +9,5 @@ export type ParseResult = {
|
|
|
9
9
|
program: AST.Program;
|
|
10
10
|
errors: MeaoiuError[];
|
|
11
11
|
};
|
|
12
|
-
export declare
|
|
13
|
-
private readonly tokens;
|
|
14
|
-
private readonly MODE;
|
|
15
|
-
private readonly MAX_POS;
|
|
16
|
-
private readonly blockDepth;
|
|
17
|
-
private readonly errors;
|
|
18
|
-
private position;
|
|
19
|
-
private commentBuffer;
|
|
20
|
-
constructor(tokens: Token[], mode?: ParseMode);
|
|
21
|
-
private current;
|
|
22
|
-
private peek;
|
|
23
|
-
/**
|
|
24
|
-
* 返回当前位置的「非悄悄话 token」,并将位置推进到下一个 token(非悄悄话或 EOF),
|
|
25
|
-
* 同时把遇到的悄悄话收集到 commentBuffer
|
|
26
|
-
* @returns 当前位置的 token(非 COMMENT)
|
|
27
|
-
*/
|
|
28
|
-
private advance;
|
|
29
|
-
/**
|
|
30
|
-
* 推进位置(同时掠取悄悄话)并取得下一 token
|
|
31
|
-
* @returns 悄悄话之后一个 token 的再下一 token
|
|
32
|
-
*/
|
|
33
|
-
private next;
|
|
34
|
-
/**
|
|
35
|
-
* 返回上一个非悄悄话 token(不动位置)
|
|
36
|
-
* @returns 上一个非悄悄话 token
|
|
37
|
-
*/
|
|
38
|
-
private lookBack;
|
|
39
|
-
/**
|
|
40
|
-
* 取得当前非悄悄话 token,若当前为悄悄话则连续推进至目标(同时收集悄悄话到 commentBuffer)
|
|
41
|
-
* @returns 当前 token 或其后第一个非悄悄话 token(或 EOF)
|
|
42
|
-
*/
|
|
43
|
-
private drainCommentsAhead;
|
|
44
|
-
/**
|
|
45
|
-
* 从缓存中拿走所有待分配的 leading 悄悄话(并清空缓存)
|
|
46
|
-
* @returns 所有待分配的悄悄话
|
|
47
|
-
*/
|
|
48
|
-
private takeLeadingComments;
|
|
49
|
-
/**
|
|
50
|
-
* 把缓存里的悄悄话按是否与 anchorToken 同一行分离:
|
|
51
|
-
* - 同行的视为 trailing(尾随悄悄话),附给 node
|
|
52
|
-
* - 不同的保留为未来节点的 leading(放回 commentBuffer)
|
|
53
|
-
*/
|
|
54
|
-
private collectTrailingComments;
|
|
55
|
-
private endLoc;
|
|
56
|
-
private reportError;
|
|
57
|
-
/**
|
|
58
|
-
* 虚构尾随词元并报告错误。
|
|
59
|
-
* @param kind 虚构词元种类,若无预期则可传 TokenKind.ERROR
|
|
60
|
-
* @returns 虚构 token
|
|
61
|
-
*/
|
|
62
|
-
private makeErrorTail;
|
|
63
|
-
private expect;
|
|
64
|
-
private synchronize;
|
|
65
|
-
private consumeToRecoveryPoint;
|
|
66
|
-
parse(): ParseResult;
|
|
67
|
-
private parseStatement;
|
|
68
|
-
private parseVariableDeclaration;
|
|
69
|
-
private parseAssignmentStatement;
|
|
70
|
-
private parseFunctionDeclaration;
|
|
71
|
-
private parseReturnOrAmbushStatement;
|
|
72
|
-
private parseIdentifier;
|
|
73
|
-
private parseExpression;
|
|
74
|
-
private parseLogicalExpression;
|
|
75
|
-
private parseSequenceExpression;
|
|
76
|
-
private parseComparisonExpression;
|
|
77
|
-
private parseAdditiveExpression;
|
|
78
|
-
private parseMultiplicativeExpression;
|
|
79
|
-
private parseUnaryExpression;
|
|
80
|
-
private parseMemberAccessExpression;
|
|
81
|
-
private parsePrimaryExpression;
|
|
82
|
-
private parseBlockOrIfExpression;
|
|
83
|
-
private parseBlockExpression;
|
|
84
|
-
private parseCollectionElement;
|
|
85
|
-
private parseIfExpression;
|
|
86
|
-
private parseLoopExpression;
|
|
87
|
-
private parseCallExpression;
|
|
88
|
-
}
|
|
12
|
+
export declare function parse(tokens: Token[], mode?: ParseMode): ParseResult;
|
|
89
13
|
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,WAAW,EAAoB,MAAM,YAAY,CAAC;AAC3D,OAAO,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,WAAW,EAAoB,MAAM,YAAY,CAAC;AAC3D,OAAO,EAMN,KAAK,KAAK,EACV,MAAM,sBAAsB,CAAC;AAE9B,0BAAkB,SAAS;IAC1B,MAAM,IAAA;IACN,QAAQ,IAAA;CACR;AAED,MAAM,MAAM,WAAW,GAAG;IACzB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC;IACrB,MAAM,EAAE,WAAW,EAAE,CAAC;CACtB,CAAC;AAkqBF,wBAAgB,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,GAAE,SAA4B,GAAG,WAAW,CAEtF"}
|
package/dist/core/parser.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
// src/core/parser.ts
|
|
2
2
|
import { MeaoiuError, errorFrom } from './error.js';
|
|
3
|
-
import {
|
|
4
|
-
const assignMap = {
|
|
5
|
-
[2 /* TokenKind.KEYWORD_IS */]: 0 /* AssignmentOperator.REFERENCE */,
|
|
6
|
-
[3 /* TokenKind.KEYWORD_LIKE */]: 1 /* AssignmentOperator.COPY */,
|
|
7
|
-
[4 /* TokenKind.KEYWORD_ONLY */]: 2 /* AssignmentOperator.MOVE */,
|
|
8
|
-
};
|
|
3
|
+
import { newToken, } from './lexer/tokenizer.js';
|
|
9
4
|
const blockKindInfo = [
|
|
10
5
|
{
|
|
11
6
|
name: '想法',
|
|
@@ -19,18 +14,34 @@ const blockKindInfo = [
|
|
|
19
14
|
name: '纸箱',
|
|
20
15
|
startKind: 20 /* TokenKind.COLLECTION_START */,
|
|
21
16
|
startValue: '[=',
|
|
22
|
-
separatorKind:
|
|
17
|
+
separatorKind: 36 /* TokenKind.COMMA */,
|
|
23
18
|
endKind: 21 /* TokenKind.COLLECTION_END */,
|
|
24
19
|
endValue: '=]',
|
|
25
20
|
},
|
|
26
21
|
]; // 0: 想法, 1: 纸箱
|
|
27
22
|
const syntaxErrorFrom = (ele, message) => errorFrom(ele, message, 3 /* Phase.SYNTACTIC */);
|
|
28
|
-
function tokenTrailing({ line, col: prevCol, value: prevValue }, kind, value = '') {
|
|
29
|
-
return { kind, value, line, col: prevCol + prevValue.length };
|
|
30
|
-
}
|
|
31
23
|
function errorNodeWith({ message, line, col, endLine, endCol }) {
|
|
32
24
|
return { kind: 0 /* NodeKind.ErrorNode */, message, line, col, endLine, endCol };
|
|
33
25
|
}
|
|
26
|
+
function isAdditiveToken(token) {
|
|
27
|
+
return token.kind === 26 /* TokenKind.ARITHMETIC_PLUS */ || token.kind === 27 /* TokenKind.ARITHMETIC_MINUS */;
|
|
28
|
+
}
|
|
29
|
+
function isMultiplicativeToken(token) {
|
|
30
|
+
return token.kind === 28 /* TokenKind.ARITHMETIC_MULTIPLY */ || token.kind === 29 /* TokenKind.ARITHMETIC_DIVIDE */;
|
|
31
|
+
}
|
|
32
|
+
function isComparisonToken(token) {
|
|
33
|
+
switch (token.kind) {
|
|
34
|
+
case 32 /* TokenKind.COMPARISON_GREATER */:
|
|
35
|
+
case 33 /* TokenKind.COMPARISON_LESS */:
|
|
36
|
+
case 34 /* TokenKind.COMPARISON_GREATER_EQUAL */:
|
|
37
|
+
case 35 /* TokenKind.COMPARISON_LESS_EQUAL */:
|
|
38
|
+
case 30 /* TokenKind.COMPARISON_EQUAL */:
|
|
39
|
+
case 31 /* TokenKind.COMPARISON_NOT_EQUAL */:
|
|
40
|
+
return true;
|
|
41
|
+
default:
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
34
45
|
function isStartToken(kind) {
|
|
35
46
|
switch (kind) {
|
|
36
47
|
case 1 /* TokenKind.KEYWORD_USE */:
|
|
@@ -47,9 +58,9 @@ function isStartToken(kind) {
|
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
60
|
function isAssignmentOperator(kind) {
|
|
50
|
-
return kind === 2 /* TokenKind.
|
|
61
|
+
return kind === 2 /* TokenKind.ASSIGNMENT_IS */ || kind === 3 /* TokenKind.ASSIGNMENT_LIKE */ || kind === 4 /* TokenKind.ASSIGNMENT_ONLY */;
|
|
51
62
|
}
|
|
52
|
-
|
|
63
|
+
class Parser {
|
|
53
64
|
tokens;
|
|
54
65
|
MODE;
|
|
55
66
|
MAX_POS;
|
|
@@ -59,13 +70,14 @@ export class Parser {
|
|
|
59
70
|
// 悄悄话缓存:advance / drainCommentsAhead 会把遇到的 COMMENT 放进这里
|
|
60
71
|
commentBuffer = [];
|
|
61
72
|
constructor(tokens, mode = 0 /* ParseMode.STRICT */) {
|
|
73
|
+
this.MODE = mode;
|
|
62
74
|
// 确保有 EOF 哨兵,避免边界问题
|
|
63
|
-
if (!tokens.length || tokens[tokens.length - 1]
|
|
64
|
-
|
|
75
|
+
if (!tokens.length || tokens[tokens.length - 1].kind !== 44 /* TokenKind.EOF */) {
|
|
76
|
+
const EOF = newToken(44 /* TokenKind.EOF */, 'EndOfFile', -1, -1, -1, -1);
|
|
77
|
+
tokens.push((this.reportError(errorFrom(EOF, '分词器可能坏了喵~', 1 /* Phase.INVARIANT */)), EOF));
|
|
65
78
|
}
|
|
66
79
|
this.tokens = tokens;
|
|
67
80
|
this.MAX_POS = tokens.length - 1;
|
|
68
|
-
this.MODE = mode;
|
|
69
81
|
}
|
|
70
82
|
// 当前 token(安全!)
|
|
71
83
|
current() {
|
|
@@ -73,7 +85,7 @@ export class Parser {
|
|
|
73
85
|
}
|
|
74
86
|
// 安全前视 n 个 token
|
|
75
87
|
peek(n = 1) {
|
|
76
|
-
return this.tokens[this.position + n
|
|
88
|
+
return this.tokens[Math.min(this.position + n, this.MAX_POS)];
|
|
77
89
|
}
|
|
78
90
|
/**
|
|
79
91
|
* 返回当前位置的「非悄悄话 token」,并将位置推进到下一个 token(非悄悄话或 EOF),
|
|
@@ -102,7 +114,7 @@ export class Parser {
|
|
|
102
114
|
if (this.position < 1)
|
|
103
115
|
return this.current();
|
|
104
116
|
let token;
|
|
105
|
-
for (let pos = this.position; (token = this.tokens[--pos]).kind ===
|
|
117
|
+
for (let pos = this.position; (token = this.tokens[--pos]).kind === 43 /* TokenKind.COMMENT */ && pos > 0;)
|
|
106
118
|
;
|
|
107
119
|
return token;
|
|
108
120
|
}
|
|
@@ -112,7 +124,7 @@ export class Parser {
|
|
|
112
124
|
*/
|
|
113
125
|
drainCommentsAhead() {
|
|
114
126
|
let token = this.current();
|
|
115
|
-
while (token.kind ===
|
|
127
|
+
while (token.kind === 43 /* TokenKind.COMMENT */ && this.position < this.MAX_POS) {
|
|
116
128
|
this.commentBuffer.push(token);
|
|
117
129
|
token = this.tokens[++this.position];
|
|
118
130
|
}
|
|
@@ -138,18 +150,16 @@ export class Parser {
|
|
|
138
150
|
return;
|
|
139
151
|
const trailing = [];
|
|
140
152
|
const remaining = [];
|
|
141
|
-
|
|
142
|
-
|
|
153
|
+
// 同一行的视为 trailing,不同一行的留作下一节点的 leading
|
|
154
|
+
for (const comment of this.commentBuffer)
|
|
143
155
|
(comment.line === anchorToken.line ? trailing : remaining).push(comment);
|
|
144
|
-
}
|
|
145
156
|
if (trailing.length)
|
|
146
157
|
(node.trailingComments ??= []).push(...trailing);
|
|
147
158
|
// 将非 trailing 的悄悄话保留为新的 commentBuffer
|
|
148
159
|
this.commentBuffer = remaining;
|
|
149
160
|
}
|
|
150
|
-
endLoc(
|
|
151
|
-
|
|
152
|
-
return { endLine: token.line, endCol: token.col + token.value.length };
|
|
161
|
+
endLoc({ endLine, endCol } = this.lookBack()) {
|
|
162
|
+
return { endLine, endCol };
|
|
153
163
|
}
|
|
154
164
|
reportError(error) {
|
|
155
165
|
if (this.MODE !== 1 /* ParseMode.TOLERANT */)
|
|
@@ -163,9 +173,9 @@ export class Parser {
|
|
|
163
173
|
*/
|
|
164
174
|
makeErrorTail(kind, why, where) {
|
|
165
175
|
// 找到前一个 token 做锚点
|
|
166
|
-
const
|
|
167
|
-
const fakeTermToken =
|
|
168
|
-
const errMsg = `${where ?? `在「${
|
|
176
|
+
const { endLine, endCol, value } = this.lookBack();
|
|
177
|
+
const fakeTermToken = newToken(kind, '', endLine, endCol, endLine, endCol);
|
|
178
|
+
const errMsg = `${where ?? `在「${value}」后`}${why}`;
|
|
169
179
|
this.reportError(syntaxErrorFrom(fakeTermToken, errMsg));
|
|
170
180
|
return fakeTermToken;
|
|
171
181
|
}
|
|
@@ -177,32 +187,31 @@ export class Parser {
|
|
|
177
187
|
return this.makeErrorTail(kind, why, where);
|
|
178
188
|
}
|
|
179
189
|
synchronize() {
|
|
180
|
-
// 首先尝试找到 TERMINATOR
|
|
181
|
-
for (let tokenKind = this.current().kind; tokenKind !==
|
|
190
|
+
// 首先尝试找到 TERMINATOR 或语句开始,跳过闭块符,顺便捕获块配对问题
|
|
191
|
+
for (let tokenKind = this.current().kind; tokenKind !== 44 /* TokenKind.EOF */; tokenKind = this.next().kind) {
|
|
182
192
|
if (tokenKind === 24 /* TokenKind.TERMINATOR */)
|
|
183
193
|
return void this.advance();
|
|
184
194
|
if (isStartToken(tokenKind))
|
|
185
195
|
return;
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
196
|
+
const depthIndex = +(tokenKind === 21 /* TokenKind.COLLECTION_END */);
|
|
197
|
+
if (!depthIndex && tokenKind !== 23 /* TokenKind.BLOCK_END */)
|
|
198
|
+
continue;
|
|
199
|
+
if (this.blockDepth[depthIndex] > 0)
|
|
200
|
+
return;
|
|
201
|
+
const token = this.current();
|
|
202
|
+
this.reportError(syntaxErrorFrom(token, `这个「${token.value}」被孤立了喵!`));
|
|
203
|
+
this.blockDepth[depthIndex] = 0; // 龟苓膏之术,对症下药喵
|
|
194
204
|
}
|
|
195
205
|
}
|
|
196
206
|
// 用于 parseExpression 内部:跳到 terminator / statement start / EOF
|
|
197
207
|
consumeToRecoveryPoint() {
|
|
198
|
-
for (let tokenKind = this.current().kind; tokenKind !==
|
|
208
|
+
for (let tokenKind = this.current().kind; tokenKind !== 44 /* TokenKind.EOF */ && tokenKind !== 24 /* TokenKind.TERMINATOR */ && !isStartToken(tokenKind); tokenKind = this.next().kind)
|
|
199
209
|
;
|
|
200
210
|
}
|
|
201
211
|
parse() {
|
|
202
|
-
const
|
|
203
|
-
const { kind:
|
|
204
|
-
|
|
205
|
-
for (let tokenKind = startKind; tokenKind !== 35 /* TokenKind.EOF */; tokenKind = this.current().kind) {
|
|
212
|
+
const { kind: startKind, line, col, endLine, endCol } = this.current();
|
|
213
|
+
const program = { kind: 1 /* NodeKind.Program */, body: [], line, col, endLine, endCol };
|
|
214
|
+
for (let tokenKind = startKind; tokenKind !== 44 /* TokenKind.EOF */; tokenKind = this.current().kind) {
|
|
206
215
|
if (tokenKind === 24 /* TokenKind.TERMINATOR */)
|
|
207
216
|
this.advance();
|
|
208
217
|
else
|
|
@@ -214,9 +223,7 @@ export class Parser {
|
|
|
214
223
|
(lastStatement.trailingComments ??= []).push(...this.commentBuffer);
|
|
215
224
|
this.commentBuffer = [];
|
|
216
225
|
}
|
|
217
|
-
|
|
218
|
-
program.endLine = endLine;
|
|
219
|
-
program.endCol = endCol + endValue.length;
|
|
226
|
+
({ endLine: program.endLine, endCol: program.endCol } = this.tokens[Math.max(0, this.position - 1)]);
|
|
220
227
|
return { program, errors: this.errors };
|
|
221
228
|
}
|
|
222
229
|
parseStatement() {
|
|
@@ -268,7 +275,7 @@ export class Parser {
|
|
|
268
275
|
return node;
|
|
269
276
|
}
|
|
270
277
|
catch (e) {
|
|
271
|
-
const error = e instanceof MeaoiuError ? e :
|
|
278
|
+
const error = e instanceof MeaoiuError ? e : errorFrom(startToken, String(e), 0 /* Phase.UNKNOWN */);
|
|
272
279
|
this.reportError(error);
|
|
273
280
|
this.synchronize();
|
|
274
281
|
return errorNodeWith(error);
|
|
@@ -284,10 +291,9 @@ export class Parser {
|
|
|
284
291
|
: undefined;
|
|
285
292
|
return { kind: 2 /* NodeKind.VariableDeclaration */, identifier, initialization, line, col, ...this.endLoc() };
|
|
286
293
|
}
|
|
287
|
-
parseAssignmentStatement(assignee,
|
|
294
|
+
parseAssignmentStatement(assignee, operator) {
|
|
288
295
|
this.advance();
|
|
289
296
|
const value = this.parseExpression();
|
|
290
|
-
const operator = assignMap[operatorKind]; // 调用前已检查词元类型
|
|
291
297
|
const { line, col } = assignee;
|
|
292
298
|
return { kind: 3 /* NodeKind.AssignmentStatement */, assignee, value, operator, line, col, ...this.endLoc() };
|
|
293
299
|
}
|
|
@@ -326,34 +332,30 @@ export class Parser {
|
|
|
326
332
|
parseLogicalExpression() {
|
|
327
333
|
let left = this.parseSequenceExpression();
|
|
328
334
|
// 循环处理连续的逻辑操作:A 和 B 都好 或 C 不坏
|
|
329
|
-
for (let tokenKind = this.current().kind, isOr; (isOr = tokenKind ===
|
|
335
|
+
for (let tokenKind = this.current().kind, isOr; (isOr = tokenKind === 38 /* TokenKind.LOGIC_OR */) || tokenKind === 37 /* TokenKind.LOGIC_AND */; tokenKind = this.current().kind) {
|
|
330
336
|
this.advance();
|
|
331
337
|
const right = this.parseLogicalExpression();
|
|
332
338
|
const closeToken = this.current();
|
|
333
|
-
|
|
334
|
-
switch (
|
|
335
|
-
case
|
|
336
|
-
operator = 1 /* LogicalOperator.OR */;
|
|
339
|
+
const operator = closeToken.kind;
|
|
340
|
+
switch (operator) {
|
|
341
|
+
case 40 /* TokenKind.LOGIC_CLOSE_OR */:
|
|
337
342
|
if (!isOr)
|
|
338
343
|
this.reportError(syntaxErrorFrom(closeToken, '逻辑「和」不能用「不坏」闭合喵!'));
|
|
339
344
|
break;
|
|
340
|
-
case
|
|
341
|
-
operator = 2 /* LogicalOperator.NAND */;
|
|
345
|
+
case 42 /* TokenKind.LOGIC_CLOSE_NAND */:
|
|
342
346
|
if (!isOr)
|
|
343
347
|
this.reportError(syntaxErrorFrom(closeToken, '逻辑「和」不能用「不好」闭合喵!'));
|
|
344
348
|
break;
|
|
345
|
-
case
|
|
346
|
-
operator = 0 /* LogicalOperator.AND */;
|
|
349
|
+
case 39 /* TokenKind.LOGIC_CLOSE_AND */:
|
|
347
350
|
if (isOr)
|
|
348
351
|
this.reportError(syntaxErrorFrom(closeToken, '逻辑「或」不能用「都好」闭合喵!'));
|
|
349
352
|
break;
|
|
350
|
-
case
|
|
351
|
-
operator = 3 /* LogicalOperator.NOR */;
|
|
353
|
+
case 41 /* TokenKind.LOGIC_CLOSE_NOR */:
|
|
352
354
|
if (isOr)
|
|
353
355
|
this.reportError(syntaxErrorFrom(closeToken, '逻辑「或」不能用「都坏」闭合喵!'));
|
|
354
356
|
break;
|
|
355
|
-
case
|
|
356
|
-
case
|
|
357
|
+
case 38 /* TokenKind.LOGIC_OR */:
|
|
358
|
+
case 37 /* TokenKind.LOGIC_AND */:
|
|
357
359
|
throw errorFrom(closeToken, '你不该看到这个喵!', 1 /* Phase.INVARIANT */);
|
|
358
360
|
default:
|
|
359
361
|
const [logic, close, nClose] = isOr ? ['或', '不坏', '不好'] : ['和', '都好', '都坏'];
|
|
@@ -362,7 +364,7 @@ export class Parser {
|
|
|
362
364
|
}
|
|
363
365
|
this.advance();
|
|
364
366
|
const { line, col } = left;
|
|
365
|
-
left = { kind:
|
|
367
|
+
left = { kind: 23 /* NodeKind.LogicalExpression */, left, right, operator, line, col, ...this.endLoc() };
|
|
366
368
|
}
|
|
367
369
|
return left;
|
|
368
370
|
}
|
|
@@ -370,43 +372,44 @@ export class Parser {
|
|
|
370
372
|
const { line, col } = this.current();
|
|
371
373
|
const sections = [this.parseComparisonExpression()];
|
|
372
374
|
const operators = [];
|
|
373
|
-
let
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
case
|
|
379
|
-
case
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
375
|
+
sequence: for (let isArithmeticMode = true; this.peek().kind === 36 /* TokenKind.COMMA */;) {
|
|
376
|
+
const token = this.current();
|
|
377
|
+
switch (token.kind) {
|
|
378
|
+
case 26 /* TokenKind.ARITHMETIC_PLUS */:
|
|
379
|
+
case 27 /* TokenKind.ARITHMETIC_MINUS */:
|
|
380
|
+
case 28 /* TokenKind.ARITHMETIC_MULTIPLY */:
|
|
381
|
+
case 29 /* TokenKind.ARITHMETIC_DIVIDE */:
|
|
382
|
+
if (isArithmeticMode)
|
|
383
|
+
break; // 模式正确
|
|
384
|
+
throw syntaxErrorFrom(token, '比较之后就不能做算术了喵!');
|
|
385
|
+
case 30 /* TokenKind.COMPARISON_EQUAL */:
|
|
386
|
+
case 31 /* TokenKind.COMPARISON_NOT_EQUAL */:
|
|
387
|
+
isArithmeticMode = false; // 禁用算术模式
|
|
384
388
|
break;
|
|
385
|
-
case
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
case
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
case 0b011: // 0 算术模式|1 有算术|1 有比较
|
|
393
|
-
case 0b111: // 1 比较模式|1 有算术|1 有比较
|
|
394
|
-
throw errorFrom(token, '物理学不存在了喵!', 1 /* Phase.INVARIANT */);
|
|
389
|
+
case 32 /* TokenKind.COMPARISON_GREATER */:
|
|
390
|
+
case 33 /* TokenKind.COMPARISON_LESS */:
|
|
391
|
+
case 34 /* TokenKind.COMPARISON_GREATER_EQUAL */:
|
|
392
|
+
case 35 /* TokenKind.COMPARISON_LESS_EQUAL */:
|
|
393
|
+
throw syntaxErrorFrom(token, `'${token.value}' 不能用在节之间喵!`);
|
|
394
|
+
default:
|
|
395
|
+
break sequence;
|
|
395
396
|
}
|
|
396
|
-
|
|
397
|
+
this.advance(); // 消费操作符
|
|
397
398
|
this.advance(); // 跳过逗号
|
|
399
|
+
operators.push(token);
|
|
398
400
|
sections.push(this.parseComparisonExpression());
|
|
399
401
|
}
|
|
400
402
|
if (sections.length === 1)
|
|
401
403
|
return sections[0];
|
|
402
|
-
return { kind:
|
|
404
|
+
return { kind: 22 /* NodeKind.SequenceExpression */, sections, operators, line, col, ...this.endLoc() };
|
|
403
405
|
}
|
|
404
406
|
parseComparisonExpression() {
|
|
405
407
|
const { line, col } = this.current();
|
|
406
408
|
const expressions = [this.parseAdditiveExpression()];
|
|
407
409
|
const operators = [];
|
|
408
|
-
|
|
409
|
-
|
|
410
|
+
for (let token; isComparisonToken((token = this.current())) && this.peek().kind !== 36 /* TokenKind.COMMA */;) {
|
|
411
|
+
this.advance();
|
|
412
|
+
operators.push(token);
|
|
410
413
|
expressions.push(this.parseAdditiveExpression());
|
|
411
414
|
}
|
|
412
415
|
// 如果没有比较(只有一个操作数),就返回那个操作数本身
|
|
@@ -417,21 +420,19 @@ export class Parser {
|
|
|
417
420
|
}
|
|
418
421
|
parseAdditiveExpression() {
|
|
419
422
|
let left = this.parseMultiplicativeExpression();
|
|
420
|
-
for (let token = this.current()
|
|
421
|
-
this.advance();
|
|
423
|
+
for (let token; isAdditiveToken((token = this.current())) && this.peek().kind !== 36 /* TokenKind.COMMA */;) {
|
|
424
|
+
const { line, col } = this.advance();
|
|
422
425
|
const right = this.parseMultiplicativeExpression();
|
|
423
|
-
|
|
424
|
-
left = { kind: 17 /* NodeKind.ArithmeticExpression */, left, operator, right, line, col, ...this.endLoc(token) };
|
|
426
|
+
left = { kind: 20 /* NodeKind.ArithmeticExpression */, left, operator: token, right, line, col, ...this.endLoc(token) };
|
|
425
427
|
}
|
|
426
428
|
return left;
|
|
427
429
|
}
|
|
428
430
|
parseMultiplicativeExpression() {
|
|
429
431
|
let left = this.parseUnaryExpression();
|
|
430
|
-
for (let token = this.current()
|
|
431
|
-
this.advance();
|
|
432
|
+
for (let token; isMultiplicativeToken((token = this.current())) && this.peek().kind !== 36 /* TokenKind.COMMA */;) {
|
|
433
|
+
const { line, col } = this.advance();
|
|
432
434
|
const right = this.parseUnaryExpression();
|
|
433
|
-
|
|
434
|
-
left = { kind: 17 /* NodeKind.ArithmeticExpression */, left, operator, right, line, col, ...this.endLoc(token) };
|
|
435
|
+
left = { kind: 20 /* NodeKind.ArithmeticExpression */, left, operator: token, right, line, col, ...this.endLoc(token) };
|
|
435
436
|
}
|
|
436
437
|
return left;
|
|
437
438
|
}
|
|
@@ -440,10 +441,10 @@ export class Parser {
|
|
|
440
441
|
let operator;
|
|
441
442
|
switch (tokenKind) {
|
|
442
443
|
case 5 /* TokenKind.KEYWORD_CLONE */:
|
|
443
|
-
operator =
|
|
444
|
+
operator = 3 /* TokenKind.ASSIGNMENT_LIKE */;
|
|
444
445
|
break;
|
|
445
446
|
case 6 /* TokenKind.KEYWORD_MOVE */:
|
|
446
|
-
operator =
|
|
447
|
+
operator = 4 /* TokenKind.ASSIGNMENT_ONLY */;
|
|
447
448
|
break;
|
|
448
449
|
default:
|
|
449
450
|
return this.parseMemberAccessExpression();
|
|
@@ -451,7 +452,7 @@ export class Parser {
|
|
|
451
452
|
this.advance();
|
|
452
453
|
// 递归调用,这样就可以处理像“高仿 高仿 a”这样的写法
|
|
453
454
|
const argument = this.parseUnaryExpression();
|
|
454
|
-
return { kind:
|
|
455
|
+
return { kind: 19 /* NodeKind.UnaryExpression */, operator, argument, line, col, ...this.endLoc() };
|
|
455
456
|
}
|
|
456
457
|
parseMemberAccessExpression() {
|
|
457
458
|
let object = this.parsePrimaryExpression();
|
|
@@ -464,7 +465,7 @@ export class Parser {
|
|
|
464
465
|
}
|
|
465
466
|
const property = this.parsePrimaryExpression();
|
|
466
467
|
const { line, col } = startToken;
|
|
467
|
-
object = { kind:
|
|
468
|
+
object = { kind: 18 /* NodeKind.MemberAccessExpression */, object, property, line, col, ...this.endLoc() };
|
|
468
469
|
}
|
|
469
470
|
return object;
|
|
470
471
|
}
|
|
@@ -475,7 +476,13 @@ export class Parser {
|
|
|
475
476
|
let node;
|
|
476
477
|
switch (tokenKind) {
|
|
477
478
|
case 15 /* TokenKind.NUMBER */:
|
|
478
|
-
node = {
|
|
479
|
+
node = {
|
|
480
|
+
kind: 9 /* NodeKind.NumericLiteral */,
|
|
481
|
+
value: Number.parseFloat(value),
|
|
482
|
+
line,
|
|
483
|
+
col,
|
|
484
|
+
...this.endLoc(startToken),
|
|
485
|
+
};
|
|
479
486
|
break;
|
|
480
487
|
case 16 /* TokenKind.STRING */:
|
|
481
488
|
node = { kind: 10 /* NodeKind.StringLiteral */, value, line, col, ...this.endLoc(startToken) };
|
|
@@ -498,10 +505,12 @@ export class Parser {
|
|
|
498
505
|
case 9 /* TokenKind.KEYWORD_LOOP */:
|
|
499
506
|
return this.parseLoopExpression();
|
|
500
507
|
case 24 /* TokenKind.TERMINATOR */:
|
|
501
|
-
case
|
|
508
|
+
case 44 /* TokenKind.EOF */:
|
|
502
509
|
throw syntaxErrorFrom(startToken, '只说半句看不懂喵!');
|
|
510
|
+
case 0 /* TokenKind.ERROR */:
|
|
511
|
+
throw errorFrom(startToken, `这个词不对劲喵:${value}`, 2 /* Phase.LEXICAL */);
|
|
503
512
|
default:
|
|
504
|
-
throw syntaxErrorFrom(startToken,
|
|
513
|
+
throw syntaxErrorFrom(startToken, `看不懂的把戏喵:${value}`);
|
|
505
514
|
}
|
|
506
515
|
this.advance();
|
|
507
516
|
if (leading.length)
|
|
@@ -519,7 +528,7 @@ export class Parser {
|
|
|
519
528
|
const statementParser = isCollection ? () => this.parseCollectionElement() : () => this.parseStatement();
|
|
520
529
|
const body = [];
|
|
521
530
|
this.blockDepth[modeSwitch]++;
|
|
522
|
-
for (let tokenKind = this.current().kind; tokenKind !== endKind && tokenKind !==
|
|
531
|
+
for (let tokenKind = this.current().kind; tokenKind !== endKind && tokenKind !== 44 /* TokenKind.EOF */; tokenKind = this.next().kind) {
|
|
523
532
|
if (tokenKind === separatorKind) {
|
|
524
533
|
if (isCollection)
|
|
525
534
|
this.makeErrorTail(0 /* TokenKind.ERROR */, `这个「${this.current().value}」是多余的喵!`);
|
|
@@ -572,7 +581,10 @@ export class Parser {
|
|
|
572
581
|
const { line, col } = this.advance();
|
|
573
582
|
const args = this.parseExpression();
|
|
574
583
|
const callee = this.parseIdentifier();
|
|
575
|
-
return { kind:
|
|
584
|
+
return { kind: 17 /* NodeKind.CallExpression */, args, callee, line, col, ...this.endLoc() };
|
|
576
585
|
}
|
|
577
586
|
}
|
|
587
|
+
export function parse(tokens, mode = 0 /* ParseMode.STRICT */) {
|
|
588
|
+
return new Parser(tokens, mode).parse();
|
|
589
|
+
}
|
|
578
590
|
//# sourceMappingURL=parser.js.map
|