bobe 0.0.11 → 0.0.13
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/bobe.cjs.js +297 -74
- package/dist/bobe.cjs.js.map +1 -1
- package/dist/bobe.esm.js +298 -75
- package/dist/bobe.esm.js.map +1 -1
- package/dist/index.d.ts +59 -18
- package/dist/index.umd.js +297 -74
- package/dist/index.umd.js.map +1 -1
- package/package.json +4 -5
package/dist/bobe.cjs.js
CHANGED
|
@@ -16,19 +16,101 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
|
16
16
|
})(TokenType || {});
|
|
17
17
|
var LogicType = /* @__PURE__ */ ((LogicType2) => {
|
|
18
18
|
LogicType2[LogicType2["If"] = 1] = "If";
|
|
19
|
-
LogicType2[LogicType2["
|
|
19
|
+
LogicType2[LogicType2["Fail"] = 2] = "Fail";
|
|
20
20
|
LogicType2[LogicType2["Else"] = 4] = "Else";
|
|
21
21
|
LogicType2[LogicType2["For"] = 8] = "For";
|
|
22
22
|
LogicType2[LogicType2["Component"] = 16] = "Component";
|
|
23
23
|
LogicType2[LogicType2["Fragment"] = 32] = "Fragment";
|
|
24
24
|
LogicType2[LogicType2["Root"] = 64] = "Root";
|
|
25
|
+
LogicType2[LogicType2["Real"] = 128] = "Real";
|
|
25
26
|
return LogicType2;
|
|
26
27
|
})(LogicType || {});
|
|
28
|
+
const Logical = 1 /* If */ | 2 /* Fail */ | 4 /* Else */ | 8 /* For */;
|
|
29
|
+
const CondType = 1 /* If */ | 2 /* Fail */ | 4 /* Else */;
|
|
30
|
+
var NodeType = /* @__PURE__ */ ((NodeType2) => {
|
|
31
|
+
NodeType2[NodeType2["Logic"] = Logical] = "Logic";
|
|
32
|
+
NodeType2[NodeType2["Real"] = 128 /* Real */] = "Real";
|
|
33
|
+
NodeType2[NodeType2["Component"] = 16 /* Component */] = "Component";
|
|
34
|
+
return NodeType2;
|
|
35
|
+
})(NodeType || {});
|
|
27
36
|
var TerpEvt = /* @__PURE__ */ ((TerpEvt2) => {
|
|
28
37
|
TerpEvt2["AllAttrGot"] = "all-attr-got";
|
|
29
38
|
TerpEvt2["HandledComponentNode"] = "handled-component-node";
|
|
30
39
|
return TerpEvt2;
|
|
31
40
|
})(TerpEvt || {});
|
|
41
|
+
const IsAnchor = /* @__PURE__ */ Symbol("is-anchor");
|
|
42
|
+
|
|
43
|
+
class TypedStack {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.top = null;
|
|
46
|
+
// 存储每种类型最近一次出现的包装单元引用
|
|
47
|
+
// 使用 Record 来动态支持不同的类型标签
|
|
48
|
+
this.lastNodes = {};
|
|
49
|
+
this.length = 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* @param rawNode 原始节点数据
|
|
53
|
+
* @param type 节点类型
|
|
54
|
+
*/
|
|
55
|
+
push(rawNode, type) {
|
|
56
|
+
var _a;
|
|
57
|
+
const newNode = {
|
|
58
|
+
data: rawNode,
|
|
59
|
+
type,
|
|
60
|
+
prev: this.top,
|
|
61
|
+
prevSameType: (_a = this.lastNodes[type]) != null ? _a : null
|
|
62
|
+
};
|
|
63
|
+
this.top = newNode;
|
|
64
|
+
this.length++;
|
|
65
|
+
this.lastNodes[type] = newNode;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 出栈操作
|
|
69
|
+
* @returns 原始节点数据或 null
|
|
70
|
+
*/
|
|
71
|
+
pop() {
|
|
72
|
+
if (!this.top) return null;
|
|
73
|
+
const popped = this.top;
|
|
74
|
+
this.lastNodes[popped.type] = popped.prevSameType;
|
|
75
|
+
this.top = popped.prev;
|
|
76
|
+
this.length--;
|
|
77
|
+
return popped.data;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* O(1) 获取栈顶节点的前一个同类型节点
|
|
81
|
+
*/
|
|
82
|
+
getPrevSameType() {
|
|
83
|
+
if (!this.top || !this.top.prevSameType) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
return this.top.prevSameType.data;
|
|
87
|
+
}
|
|
88
|
+
findPrevSameType(cb) {
|
|
89
|
+
if (!this.top) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
let point = this.top.prevSameType;
|
|
93
|
+
while (point) {
|
|
94
|
+
if (cb(point.data)) {
|
|
95
|
+
return point.data;
|
|
96
|
+
}
|
|
97
|
+
point = point.prevSameType;
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 获取当前栈顶的类型
|
|
103
|
+
*/
|
|
104
|
+
get peekType() {
|
|
105
|
+
return this.top ? this.top.type : null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 获取栈顶元素
|
|
109
|
+
*/
|
|
110
|
+
peek() {
|
|
111
|
+
return this.top.data;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
32
114
|
|
|
33
115
|
var __defProp$1 = Object.defineProperty;
|
|
34
116
|
var __defProps$1 = Object.defineProperties;
|
|
@@ -78,61 +160,96 @@ class Interpreter {
|
|
|
78
160
|
return [hookType, value];
|
|
79
161
|
};
|
|
80
162
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// anchor: any;
|
|
163
|
+
isLogicNode(node) {
|
|
164
|
+
return node && node.__logicType & Logical;
|
|
165
|
+
}
|
|
85
166
|
program(root, before) {
|
|
167
|
+
var _a;
|
|
86
168
|
const componentNode = {
|
|
87
169
|
__logicType: LogicType.Component,
|
|
88
170
|
realParent: root,
|
|
89
171
|
store: new aoye.Store()
|
|
90
172
|
};
|
|
91
173
|
this.tokenizer.consume();
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
174
|
+
const stack = new TypedStack();
|
|
175
|
+
stack.push({ node: root, prev: null }, NodeType.Real);
|
|
176
|
+
const ctx = {
|
|
177
|
+
realParent: root,
|
|
178
|
+
prevSibling: before,
|
|
179
|
+
current: null,
|
|
180
|
+
stack,
|
|
181
|
+
before
|
|
182
|
+
};
|
|
183
|
+
const rootPulling = aoye.getPulling();
|
|
95
184
|
while (1) {
|
|
96
185
|
if (this.tokenizer.isEof()) {
|
|
97
|
-
|
|
186
|
+
if (!ctx.prevSibling) ctx.prevSibling = before;
|
|
187
|
+
this.handleInsert(root, ctx.current, ctx.prevSibling, componentNode);
|
|
98
188
|
break;
|
|
99
189
|
}
|
|
100
190
|
const token = this.tokenizer.token;
|
|
101
191
|
if (token.type & TokenType.Indent) {
|
|
102
192
|
this.tokenizer.consume();
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
193
|
+
const isLogicNode = this.isLogicNode(ctx.current);
|
|
194
|
+
stack.push(
|
|
195
|
+
{
|
|
196
|
+
node: ctx.current,
|
|
197
|
+
prev: ctx.prevSibling
|
|
198
|
+
},
|
|
199
|
+
ctx.current.__logicType ? isLogicNode ? NodeType.Logic : NodeType.Component : NodeType.Real
|
|
200
|
+
);
|
|
201
|
+
if (ctx.current.__logicType) {
|
|
202
|
+
if (isLogicNode) {
|
|
203
|
+
aoye.setPulling(ctx.current.effect.ins);
|
|
204
|
+
}
|
|
115
205
|
} else {
|
|
116
|
-
if (
|
|
117
|
-
|
|
206
|
+
if (ctx.current) {
|
|
207
|
+
ctx.realParent = ctx.current;
|
|
118
208
|
}
|
|
119
|
-
|
|
209
|
+
ctx.prevSibling = null;
|
|
120
210
|
}
|
|
211
|
+
ctx.current = this.declaration(ctx);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (ctx.current) {
|
|
215
|
+
if (stack.length === 1 && !ctx.prevSibling) {
|
|
216
|
+
ctx.prevSibling = before;
|
|
217
|
+
}
|
|
218
|
+
this.handleInsert(ctx.realParent, ctx.current, ctx.prevSibling);
|
|
121
219
|
}
|
|
122
220
|
if (this.tokenizer.token.type & TokenType.Dedent) {
|
|
123
221
|
this.tokenizer.consume();
|
|
124
|
-
const { node: parent, prev } = stack.
|
|
125
|
-
|
|
126
|
-
|
|
222
|
+
const { node: parent, prev } = stack.peek();
|
|
223
|
+
if (!parent.__logicType) {
|
|
224
|
+
const prevSameType = stack.getPrevSameType();
|
|
225
|
+
ctx.realParent = (prevSameType == null ? void 0 : prevSameType.node) || root;
|
|
226
|
+
} else {
|
|
227
|
+
if (this.isLogicNode(parent)) {
|
|
228
|
+
const parentLogic = (_a = stack.getPrevSameType()) == null ? void 0 : _a.node;
|
|
229
|
+
if (parentLogic) {
|
|
230
|
+
aoye.setPulling(parentLogic.effect.ins);
|
|
231
|
+
} else {
|
|
232
|
+
aoye.setPulling(rootPulling);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
stack.pop();
|
|
237
|
+
ctx.prevSibling = prev;
|
|
238
|
+
ctx.current = parent;
|
|
127
239
|
} else {
|
|
128
|
-
prevSibling = current;
|
|
129
|
-
current = this.declaration(
|
|
240
|
+
ctx.prevSibling = ctx.current || ctx.prevSibling;
|
|
241
|
+
ctx.current = this.declaration(ctx);
|
|
130
242
|
}
|
|
131
243
|
}
|
|
132
|
-
componentNode.lastInserted = this.lastInserted;
|
|
133
|
-
this.lastInserted = null;
|
|
134
244
|
return componentNode;
|
|
135
245
|
}
|
|
246
|
+
insertAfterAnchor(ctx) {
|
|
247
|
+
const { realParent, prevSibling, stack, before } = ctx;
|
|
248
|
+
const afterAnchor = this.createAnchor();
|
|
249
|
+
ctx.prevSibling = stack.length === 1 && !prevSibling ? before : prevSibling;
|
|
250
|
+
this.handleInsert(realParent, afterAnchor, prevSibling);
|
|
251
|
+
return afterAnchor;
|
|
252
|
+
}
|
|
136
253
|
/** 处理
|
|
137
254
|
* 是逻辑 是普通
|
|
138
255
|
* 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
|
|
@@ -144,25 +261,14 @@ class Interpreter {
|
|
|
144
261
|
if (!prev || !prev.__logicType) {
|
|
145
262
|
this.insertAfter(parent, child, prev);
|
|
146
263
|
} else {
|
|
147
|
-
const before = prev.
|
|
264
|
+
const before = prev.realAfter;
|
|
148
265
|
this.insertAfter(parent, child, before);
|
|
149
|
-
prev.realAfter = child;
|
|
150
266
|
}
|
|
151
267
|
} else {
|
|
152
268
|
const childCmp = child;
|
|
153
269
|
childCmp.realParent = parent;
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
this.insertAfter(parent, anchor, prev);
|
|
157
|
-
this.insertAfter(parent, child, anchor);
|
|
158
|
-
childCmp.realBefore = anchor;
|
|
159
|
-
} else if (prev.__logicType) {
|
|
160
|
-
const before = prev.lastInserted;
|
|
161
|
-
const anchor = this.createAnchor();
|
|
162
|
-
this.insertAfter(parent, anchor, before);
|
|
163
|
-
this.insertAfter(parent, child, anchor);
|
|
164
|
-
childCmp.realBefore = anchor;
|
|
165
|
-
prev.realAfter = anchor;
|
|
270
|
+
if (prev == null ? void 0 : prev.__logicType) {
|
|
271
|
+
childCmp.realBefore = prev.realAfter;
|
|
166
272
|
} else {
|
|
167
273
|
childCmp.realBefore = prev;
|
|
168
274
|
}
|
|
@@ -189,8 +295,8 @@ class Interpreter {
|
|
|
189
295
|
declaration(ctx) {
|
|
190
296
|
const [hookType, value] = this._hook({});
|
|
191
297
|
let _node;
|
|
192
|
-
if (value === "if") {
|
|
193
|
-
return this.
|
|
298
|
+
if (value === "if" || value === "else" || value === "fail") {
|
|
299
|
+
return this.condDeclaration(ctx);
|
|
194
300
|
} else if (hookType) {
|
|
195
301
|
if (hookType === "static") {
|
|
196
302
|
if (typeof value === "function" && value.prototype instanceof aoye.Store) {
|
|
@@ -264,37 +370,127 @@ class Interpreter {
|
|
|
264
370
|
child[aoye.Keys.Raw][key] = value;
|
|
265
371
|
}
|
|
266
372
|
};
|
|
373
|
+
const afterAnchor = this.insertAfterAnchor(ctx);
|
|
374
|
+
const { realParent, prevSibling } = ctx;
|
|
267
375
|
tap.once(TerpEvt.AllAttrGot, () => {
|
|
268
|
-
const parent =
|
|
269
|
-
const prev =
|
|
376
|
+
const parent = realParent;
|
|
377
|
+
const prev = prevSibling;
|
|
270
378
|
this.onePropParsed = prevOnePropParsed;
|
|
271
379
|
const componentNode = child["ui"](this.opt, { data: child }, parent, prev);
|
|
380
|
+
componentNode.realAfter = afterAnchor;
|
|
272
381
|
tap.emit(TerpEvt.HandledComponentNode, componentNode);
|
|
273
382
|
});
|
|
274
383
|
return { __logicType: LogicType.Component };
|
|
275
384
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
385
|
+
// TODO: 优化代码逻辑,拆分 if elseif else
|
|
386
|
+
condDeclaration(ctx) {
|
|
387
|
+
const { prevSibling } = ctx;
|
|
388
|
+
const snapbackUp = this.tokenizer.snapshot();
|
|
389
|
+
const keyWord = this.tokenizer.consume();
|
|
390
|
+
const noSelfCond = this.tokenizer.token.type === TokenType.NewLine;
|
|
391
|
+
const [hookType, value] = this._hook({});
|
|
392
|
+
const isElse = keyWord.value === "else";
|
|
393
|
+
const isIf = keyWord.value === "if";
|
|
394
|
+
const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondType;
|
|
395
|
+
const needCalcWithPrevIf = isElse && preIsCond;
|
|
279
396
|
const ifNode = {
|
|
280
|
-
__logicType: LogicType.If,
|
|
281
|
-
|
|
397
|
+
__logicType: isElse ? LogicType.Else : isIf ? LogicType.If : LogicType.Fail,
|
|
398
|
+
snapshot: noSelfCond ? snapbackUp : this.tokenizer.snapshot(),
|
|
399
|
+
condition: null,
|
|
282
400
|
realParent: null,
|
|
283
|
-
|
|
401
|
+
preCond: preIsCond ? prevSibling : null,
|
|
284
402
|
isFirstRender: true,
|
|
285
|
-
|
|
286
|
-
anchor: null
|
|
403
|
+
effect: null
|
|
287
404
|
};
|
|
288
|
-
|
|
405
|
+
let signal;
|
|
406
|
+
if (noSelfCond) {
|
|
407
|
+
if (isElse) {
|
|
408
|
+
signal = aoye.$(() => {
|
|
409
|
+
let point = ifNode.preCond;
|
|
410
|
+
while (point) {
|
|
411
|
+
if (point.condition.v) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
if (point.__logicType === LogicType.If) {
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
point = point.preCond;
|
|
418
|
+
}
|
|
419
|
+
return true;
|
|
420
|
+
});
|
|
421
|
+
} else {
|
|
422
|
+
signal = aoye.$(() => {
|
|
423
|
+
let point = ifNode.preCond;
|
|
424
|
+
while (point) {
|
|
425
|
+
if (point.condition.v) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
point = point.preCond;
|
|
429
|
+
}
|
|
430
|
+
return true;
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
const valueIsMapKey = Reflect.has(this.data[aoye.Keys.Raw], value);
|
|
435
|
+
if (valueIsMapKey && !needCalcWithPrevIf) {
|
|
436
|
+
aoye.runWithPulling(() => this.data[value], null);
|
|
437
|
+
const { cells } = this.data[aoye.Keys.Meta];
|
|
438
|
+
signal = cells.get(value);
|
|
439
|
+
} else {
|
|
440
|
+
const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, this.data);
|
|
441
|
+
if (needCalcWithPrevIf) {
|
|
442
|
+
signal = aoye.$(() => {
|
|
443
|
+
let point = ifNode.preCond;
|
|
444
|
+
while (point) {
|
|
445
|
+
if (point.condition.v) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
if (point.__logicType === LogicType.If) {
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
point = point.preCond;
|
|
452
|
+
}
|
|
453
|
+
return fn();
|
|
454
|
+
});
|
|
455
|
+
} else {
|
|
456
|
+
signal = aoye.$(fn);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
ifNode.condition = signal;
|
|
461
|
+
ifNode.realAfter = this.insertAfterAnchor(ctx);
|
|
462
|
+
ifNode.effect = aoye.effect(
|
|
289
463
|
({ val }) => {
|
|
290
464
|
if (val) {
|
|
291
|
-
|
|
292
|
-
|
|
465
|
+
if (ifNode.isFirstRender) {
|
|
466
|
+
if (!noSelfCond) {
|
|
467
|
+
this.tokenizer.consume();
|
|
468
|
+
}
|
|
469
|
+
this.tokenizer.consume();
|
|
470
|
+
} else {
|
|
471
|
+
this.tokenizer.resume(ifNode.snapshot);
|
|
472
|
+
this.program(ifNode.realParent, ifNode.realBefore);
|
|
473
|
+
}
|
|
293
474
|
} else {
|
|
294
|
-
|
|
475
|
+
if (ifNode.isFirstRender) {
|
|
476
|
+
if (noSelfCond) {
|
|
477
|
+
this.tokenizer.i = this.tokenizer.i - 1;
|
|
478
|
+
this.tokenizer.needIndent = false;
|
|
479
|
+
}
|
|
480
|
+
this.tokenizer.skip();
|
|
481
|
+
} else {
|
|
482
|
+
const { realBefore, realAfter, realParent } = ifNode;
|
|
483
|
+
let point = realBefore ? this.nextSib(realBefore) : this.kid(realParent);
|
|
484
|
+
while (point !== realAfter) {
|
|
485
|
+
const next = this.nextSib(point);
|
|
486
|
+
this.remove(point, realParent, realBefore);
|
|
487
|
+
point = next;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
295
490
|
}
|
|
491
|
+
ifNode.isFirstRender = false;
|
|
296
492
|
},
|
|
297
|
-
[
|
|
493
|
+
[signal]
|
|
298
494
|
);
|
|
299
495
|
return ifNode;
|
|
300
496
|
}
|
|
@@ -372,6 +568,14 @@ class Interpreter {
|
|
|
372
568
|
nextSib(node) {
|
|
373
569
|
return node.nextSibling;
|
|
374
570
|
}
|
|
571
|
+
kid(node) {
|
|
572
|
+
return node.firstChild;
|
|
573
|
+
}
|
|
574
|
+
_createAnchor() {
|
|
575
|
+
const anchor = this.createAnchor();
|
|
576
|
+
anchor[IsAnchor] = true;
|
|
577
|
+
return anchor;
|
|
578
|
+
}
|
|
375
579
|
createAnchor() {
|
|
376
580
|
return {
|
|
377
581
|
name: "anchor",
|
|
@@ -379,7 +583,6 @@ class Interpreter {
|
|
|
379
583
|
};
|
|
380
584
|
}
|
|
381
585
|
insertAfter(parent, node, prev) {
|
|
382
|
-
this.lastInserted = node;
|
|
383
586
|
return this.defaultInsert(parent, node, prev);
|
|
384
587
|
}
|
|
385
588
|
defaultInsert(parent, node, prev) {
|
|
@@ -388,14 +591,16 @@ class Interpreter {
|
|
|
388
591
|
prev.nextSibling = node;
|
|
389
592
|
node.nextSibling = next;
|
|
390
593
|
} else {
|
|
594
|
+
const next = parent.firstChild;
|
|
391
595
|
parent.firstChild = node;
|
|
596
|
+
node.nextSibling = next;
|
|
392
597
|
}
|
|
393
598
|
}
|
|
394
|
-
remove(
|
|
395
|
-
return this.defaultRemove(
|
|
599
|
+
remove(node, parent, prev) {
|
|
600
|
+
return this.defaultRemove(node, parent, prev);
|
|
396
601
|
}
|
|
397
602
|
// TODO: 默认改成 prevItem
|
|
398
|
-
defaultRemove(
|
|
603
|
+
defaultRemove(node, parent, prevSibling) {
|
|
399
604
|
const next = node.nextSibling;
|
|
400
605
|
if (prevSibling) {
|
|
401
606
|
prevSibling.nextSibling = next;
|
|
@@ -468,7 +673,7 @@ const _Tokenizer = class _Tokenizer {
|
|
|
468
673
|
};
|
|
469
674
|
}
|
|
470
675
|
skip() {
|
|
471
|
-
const
|
|
676
|
+
const logicDentLen = this.dentStack[this.dentStack.length - 1];
|
|
472
677
|
let needIndent = false;
|
|
473
678
|
let skipFragment = ``;
|
|
474
679
|
this.token = void 0;
|
|
@@ -489,7 +694,7 @@ const _Tokenizer = class _Tokenizer {
|
|
|
489
694
|
const { value, isEmptyLine } = this.getDentValue();
|
|
490
695
|
const currLen = value.length;
|
|
491
696
|
if (isEmptyLine) continue;
|
|
492
|
-
if (
|
|
697
|
+
if (currLen > logicDentLen) {
|
|
493
698
|
skipFragment += value;
|
|
494
699
|
} else {
|
|
495
700
|
for (let i = this.dentStack.length - 1; i >= 0; i--) {
|
|
@@ -498,6 +703,9 @@ const _Tokenizer = class _Tokenizer {
|
|
|
498
703
|
if (currLen > expLen) {
|
|
499
704
|
throw SyntaxError(`\u7F29\u8FDB\u9519\u8BEF\uFF0C\u7F29\u8FDB\u957F\u5EA6\u4E0D\u5339\u914D`);
|
|
500
705
|
}
|
|
706
|
+
if (this.shorterThanBaseDentEof()) {
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
501
709
|
this.dentStack.pop();
|
|
502
710
|
if (!this.token) {
|
|
503
711
|
this.setToken(TokenType.Dedent, String(expLen));
|
|
@@ -762,12 +970,15 @@ ${_Tokenizer.EofId}`;
|
|
|
762
970
|
return indentHasLen;
|
|
763
971
|
}
|
|
764
972
|
if (currLen < prevLen) {
|
|
765
|
-
for (let i = this.dentStack.length
|
|
973
|
+
for (let i = this.dentStack.length; i--; ) {
|
|
766
974
|
const expLen = this.dentStack[i];
|
|
767
|
-
|
|
768
|
-
if (currLen > expLen
|
|
975
|
+
if (currLen === expLen) break;
|
|
976
|
+
if (currLen > expLen) {
|
|
769
977
|
throw SyntaxError("\u7F29\u8FDB\u5927\u5C0F\u4E0D\u7EDF\u4E00");
|
|
770
978
|
}
|
|
979
|
+
if (this.shorterThanBaseDentEof()) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
771
982
|
this.dentStack.pop();
|
|
772
983
|
if (!this.token) {
|
|
773
984
|
this.setToken(TokenType.Dedent, String(expLen));
|
|
@@ -778,14 +989,26 @@ ${_Tokenizer.EofId}`;
|
|
|
778
989
|
value: String(expLen)
|
|
779
990
|
});
|
|
780
991
|
}
|
|
781
|
-
if (currLen === expLen) {
|
|
782
|
-
break;
|
|
783
|
-
}
|
|
784
992
|
}
|
|
785
993
|
return indentHasLen;
|
|
786
994
|
}
|
|
787
995
|
return indentHasLen;
|
|
788
996
|
}
|
|
997
|
+
shorterThanBaseDentEof() {
|
|
998
|
+
const yes = this.dentStack.length === 1;
|
|
999
|
+
if (yes) {
|
|
1000
|
+
if (!this.token) {
|
|
1001
|
+
this.setToken(TokenType.Identifier, _Tokenizer.EofId);
|
|
1002
|
+
} else {
|
|
1003
|
+
this.waitingTokens.push({
|
|
1004
|
+
type: TokenType.Identifier,
|
|
1005
|
+
typeName: TokenType[TokenType.Identifier],
|
|
1006
|
+
value: _Tokenizer.EofId
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
return yes;
|
|
1011
|
+
}
|
|
789
1012
|
identifier(char) {
|
|
790
1013
|
let value = char;
|
|
791
1014
|
let nextC;
|