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