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.
Files changed (69) hide show
  1. package/dist/api/execution.d.ts +1 -1
  2. package/dist/api/execution.d.ts.map +1 -1
  3. package/dist/api/execution.js +3 -3
  4. package/dist/api/execution.js.map +1 -1
  5. package/dist/api/serviceState.d.ts.map +1 -1
  6. package/dist/api/serviceState.js +4 -7
  7. package/dist/api/serviceState.js.map +1 -1
  8. package/dist/api/services/completions.js +1 -1
  9. package/dist/api/services/completions.js.map +1 -1
  10. package/dist/api/services/formatting.d.ts.map +1 -1
  11. package/dist/api/services/formatting.js +27 -38
  12. package/dist/api/services/formatting.js.map +1 -1
  13. package/dist/api/services/inlayHints.d.ts +2 -2
  14. package/dist/api/services/inlayHints.d.ts.map +1 -1
  15. package/dist/api/services/inlayHints.js +2 -2
  16. package/dist/api/utils/astUtils.js +6 -6
  17. package/dist/api/utils/symbolAnalyzer.d.ts +1 -2
  18. package/dist/api/utils/symbolAnalyzer.d.ts.map +1 -1
  19. package/dist/api/utils/symbolAnalyzer.js +62 -47
  20. package/dist/api/utils/symbolAnalyzer.js.map +1 -1
  21. package/dist/api/utils/symbolTable.d.ts +3 -3
  22. package/dist/api/utils/symbolTable.d.ts.map +1 -1
  23. package/dist/cli/main.js +1 -1
  24. package/dist/cli/tools/completer.js +8 -4
  25. package/dist/cli/tools/completer.js.map +1 -1
  26. package/dist/cli/tools/diagnoser.js +2 -1
  27. package/dist/cli/tools/diagnoser.js.map +1 -1
  28. package/dist/cli/tools/starter.js +2 -1
  29. package/dist/cli/tools/starter.js.map +1 -1
  30. package/dist/core/ast.d.ts +14 -22
  31. package/dist/core/ast.d.ts.map +1 -1
  32. package/dist/core/builtIns.d.ts +4 -3
  33. package/dist/core/builtIns.d.ts.map +1 -1
  34. package/dist/core/builtIns.js +4 -6
  35. package/dist/core/builtIns.js.map +1 -1
  36. package/dist/core/error.d.ts +5 -12
  37. package/dist/core/error.d.ts.map +1 -1
  38. package/dist/core/error.js +9 -20
  39. package/dist/core/error.js.map +1 -1
  40. package/dist/core/lexer/preprocessor.d.ts.map +1 -0
  41. package/dist/core/{preprocessor.js → lexer/preprocessor.js} +1 -1
  42. package/dist/core/lexer/preprocessor.js.map +1 -0
  43. package/dist/core/lexer/tokenizer.d.ts +115 -0
  44. package/dist/core/lexer/tokenizer.d.ts.map +1 -0
  45. package/dist/core/lexer/tokenizer.js +295 -0
  46. package/dist/core/lexer/tokenizer.js.map +1 -0
  47. package/dist/core/parser.d.ts +2 -78
  48. package/dist/core/parser.d.ts.map +1 -1
  49. package/dist/core/parser.js +116 -104
  50. package/dist/core/parser.js.map +1 -1
  51. package/dist/core/run/environment.d.ts +3 -2
  52. package/dist/core/run/environment.d.ts.map +1 -1
  53. package/dist/core/run/environment.js +6 -7
  54. package/dist/core/run/environment.js.map +1 -1
  55. package/dist/core/run/interpreter.d.ts.map +1 -1
  56. package/dist/core/run/interpreter.js +60 -54
  57. package/dist/core/run/interpreter.js.map +1 -1
  58. package/dist/core/typedef.d.ts +19 -9
  59. package/dist/core/typedef.d.ts.map +1 -1
  60. package/dist/core/typedef.js +26 -20
  61. package/dist/core/typedef.js.map +1 -1
  62. package/package.json +3 -3
  63. package/dist/core/preprocessor.d.ts.map +0 -1
  64. package/dist/core/preprocessor.js.map +0 -1
  65. package/dist/core/tokenizer.d.ts +0 -82
  66. package/dist/core/tokenizer.d.ts.map +0 -1
  67. package/dist/core/tokenizer.js +0 -277
  68. package/dist/core/tokenizer.js.map +0 -1
  69. /package/dist/core/{preprocessor.d.ts → lexer/preprocessor.d.ts} +0 -0
@@ -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 class Parser {
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,EAAgC,KAAK,KAAK,EAAa,MAAM,gBAAgB,CAAC;AAErF,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;AAkEF,qBAAa,MAAM;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAK;IAGrB,OAAO,CAAC,aAAa,CAAe;gBAExB,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,GAAE,SAA4B;IAW/D,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,IAAI;IAIZ;;;;OAIG;IACH,OAAO,CAAC,OAAO;IAMf;;;OAGG;IACH,OAAO,CAAC,IAAI;IAKZ;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAOhB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,WAAW;IAKnB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,sBAAsB;IAQvB,KAAK,IAAI,WAAW;IAwB3B,OAAO,CAAC,cAAc;IA2DtB,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,uBAAuB;IAuC/B,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,6BAA6B;IAgBrC,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,sBAAsB;IA2C9B,OAAO,CAAC,wBAAwB;IAKhC,OAAO,CAAC,oBAAoB;IA4B5B,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,mBAAmB;CAM3B"}
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"}
@@ -1,11 +1,6 @@
1
1
  // src/core/parser.ts
2
2
  import { MeaoiuError, errorFrom } from './error.js';
3
- import { OP_ARITH, OP_COMP, OP_COMP_E } from './tokenizer.js';
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: 27 /* TokenKind.COMMA */,
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.KEYWORD_IS */ || kind === 3 /* TokenKind.KEYWORD_LIKE */ || kind === 4 /* TokenKind.KEYWORD_ONLY */;
61
+ return kind === 2 /* TokenKind.ASSIGNMENT_IS */ || kind === 3 /* TokenKind.ASSIGNMENT_LIKE */ || kind === 4 /* TokenKind.ASSIGNMENT_ONLY */;
51
62
  }
52
- export class Parser {
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]?.kind !== 35 /* TokenKind.EOF */) {
64
- tokens = tokens.concat([{ kind: 35 /* TokenKind.EOF */, value: 'EndOfFile', line: -1, col: -1 }]);
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] ?? this.tokens[this.MAX_POS];
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 === 34 /* TokenKind.COMMENT */ && pos > 0;)
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 === 34 /* TokenKind.COMMENT */ && this.position < this.MAX_POS) {
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
- for (const comment of this.commentBuffer) {
142
- // 同一行的视为 trailing,不同一行的留作下一节点的 leading
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(token) {
151
- token ??= this.lookBack();
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 prevToken = this.lookBack();
167
- const fakeTermToken = tokenTrailing(prevToken, kind);
168
- const errMsg = `${where ?? `在「${prevToken.value}」后`}${why}`;
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 !== 35 /* TokenKind.EOF */; tokenKind = this.next().kind) {
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
- if (tokenKind === 23 /* TokenKind.BLOCK_END */ || tokenKind === 21 /* TokenKind.COLLECTION_END */) {
187
- const depthIndex = +(tokenKind === 21 /* TokenKind.COLLECTION_END */);
188
- if (this.blockDepth[depthIndex] > 0)
189
- return;
190
- const token = this.current();
191
- this.errors.push(syntaxErrorFrom(token, `这个「${token.value}」被孤立了喵!`));
192
- this.blockDepth[depthIndex] = 0; // 龟苓膏之术,对症下药喵
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 !== 35 /* TokenKind.EOF */ && tokenKind !== 24 /* TokenKind.TERMINATOR */ && !isStartToken(tokenKind); tokenKind = this.next().kind)
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 startToken = this.current();
203
- const { kind: startKind, line, col } = startToken;
204
- const program = { kind: 1 /* NodeKind.Program */, body: [], line, col, endLine: line, endCol: col };
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
- const { line: endLine, col: endCol, value: endValue } = this.tokens[this.position - 1] ?? startToken;
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 : syntaxErrorFrom(startToken, e instanceof Error ? e.message : String(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, operatorKind) {
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 === 29 /* TokenKind.LOGIC_OR */) || tokenKind === 28 /* TokenKind.LOGIC_AND */; tokenKind = this.current().kind) {
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
- let operator;
334
- switch (closeToken.kind) {
335
- case 31 /* TokenKind.LOGIC_CLOSE_OR */:
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 33 /* TokenKind.LOGIC_CLOSE_NAND */:
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 30 /* TokenKind.LOGIC_CLOSE_AND */:
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 32 /* TokenKind.LOGIC_CLOSE_NOR */:
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 29 /* TokenKind.LOGIC_OR */:
356
- case 28 /* TokenKind.LOGIC_AND */:
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: 20 /* NodeKind.LogicalExpression */, left, right, operator, line, col, ...this.endLoc() };
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 modeMask = 0b0_00; // 000 算术模式 | 100 比较模式
374
- for (let token; (token = this.current()).kind === 26 /* TokenKind.OPERATOR */ && this.peek().kind === 27 /* TokenKind.COMMA */;) {
375
- const op = token.value;
376
- switch (modeMask | (+OP_ARITH.has(op) << 1 || +OP_COMP_E.has(op))) {
377
- // 模式对应:
378
- case 0b101: // 1 比较模式|0 无算术|1 有比较
379
- case 0b010: // 0 算术模式|1 有算术|0 无比较
380
- break;
381
- // 模式变换:
382
- case 0b001: // 0 算术模式|0 无算术|1 有比较
383
- modeMask = 0b1_00; // 切为比较模式
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 0b110: // 1 比较模式|1 有算术|0 无比较
386
- throw syntaxErrorFrom(token, '比较之后就不能做算术了喵!');
387
- // 符号非法:
388
- case 0b000: // 0 算术模式|0 无算术|0 无比较
389
- case 0b100: // 1 比较模式|0 无算术|0 无比较
390
- throw syntaxErrorFrom(token, `'${op}' 不能用在节之间喵!`);
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
- operators.push(this.advance());
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: 19 /* NodeKind.SequenceExpression */, sections, operators, line, col, ...this.endLoc() };
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
- while (OP_COMP.has(this.current().value) && this.peek().kind !== 27 /* TokenKind.COMMA */) {
409
- operators.push(this.advance());
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(); (token.value === '+' || token.value === '-') && this.peek().kind !== 27 /* TokenKind.COMMA */; 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
- const { line, col, value: operator } = token;
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(); (token.value === '*' || token.value === '/') && this.peek().kind !== 27 /* TokenKind.COMMA */; 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
- const { line, col, value: operator } = token;
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 = 1 /* AssignmentOperator.COPY */;
444
+ operator = 3 /* TokenKind.ASSIGNMENT_LIKE */;
444
445
  break;
445
446
  case 6 /* TokenKind.KEYWORD_MOVE */:
446
- operator = 2 /* AssignmentOperator.MOVE */;
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: 23 /* NodeKind.UnaryExpression */, operator, argument, line, col, ...this.endLoc() };
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: 22 /* NodeKind.MemberAccessExpression */, object, property, line, col, ...this.endLoc() };
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 = { kind: 9 /* NodeKind.NumericLiteral */, value: parseFloat(value), line, col, ...this.endLoc(startToken) };
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 35 /* TokenKind.EOF */:
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, `看不懂的把戏喵: ${value}`);
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 !== 35 /* TokenKind.EOF */; tokenKind = this.next().kind) {
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: 18 /* NodeKind.CallExpression */, args, callee, line, col, ...this.endLoc() };
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