bobe 0.0.23 → 0.0.25
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 +213 -327
- package/dist/bobe.cjs.js.map +1 -1
- package/dist/bobe.esm.js +215 -329
- package/dist/bobe.esm.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.umd.js +213 -327
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
package/dist/index.umd.js
CHANGED
|
@@ -73,54 +73,50 @@
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
const CondBit =
|
|
99
|
-
const LogicalBit =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
76
|
+
let TokenType = function (TokenType) {
|
|
77
|
+
TokenType[TokenType["NewLine"] = 1] = "NewLine";
|
|
78
|
+
TokenType[TokenType["Indent"] = 2] = "Indent";
|
|
79
|
+
TokenType[TokenType["Dedent"] = 4] = "Dedent";
|
|
80
|
+
TokenType[TokenType["Identifier"] = 8] = "Identifier";
|
|
81
|
+
TokenType[TokenType["Assign"] = 16] = "Assign";
|
|
82
|
+
TokenType[TokenType["Pipe"] = 32] = "Pipe";
|
|
83
|
+
TokenType[TokenType["Eof"] = 64] = "Eof";
|
|
84
|
+
TokenType[TokenType["InsertionExp"] = 128] = "InsertionExp";
|
|
85
|
+
TokenType[TokenType["Semicolon"] = 256] = "Semicolon";
|
|
86
|
+
return TokenType;
|
|
87
|
+
}({});
|
|
88
|
+
let FakeType = function (FakeType) {
|
|
89
|
+
FakeType[FakeType["If"] = 1] = "If";
|
|
90
|
+
FakeType[FakeType["Fail"] = 2] = "Fail";
|
|
91
|
+
FakeType[FakeType["Else"] = 4] = "Else";
|
|
92
|
+
FakeType[FakeType["For"] = 8] = "For";
|
|
93
|
+
FakeType[FakeType["Component"] = 16] = "Component";
|
|
94
|
+
FakeType[FakeType["Fragment"] = 32] = "Fragment";
|
|
95
|
+
FakeType[FakeType["ForItem"] = 64] = "ForItem";
|
|
96
|
+
return FakeType;
|
|
97
|
+
}({});
|
|
98
|
+
const CondBit = FakeType.If | FakeType.Fail | FakeType.Else;
|
|
99
|
+
const LogicalBit = FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem;
|
|
100
|
+
FakeType.If | FakeType.Fail | FakeType.Else | FakeType.For | FakeType.ForItem | FakeType.Component | FakeType.Fragment;
|
|
101
|
+
const TokenizerSwitcherBit = FakeType.Component | FakeType.Fragment;
|
|
102
|
+
let NodeSort = function (NodeSort) {
|
|
103
|
+
NodeSort[NodeSort["Logic"] = 1] = "Logic";
|
|
104
|
+
NodeSort[NodeSort["Real"] = 2] = "Real";
|
|
105
|
+
NodeSort[NodeSort["Component"] = 4] = "Component";
|
|
106
|
+
NodeSort[NodeSort["CtxProvider"] = 8] = "CtxProvider";
|
|
107
|
+
NodeSort[NodeSort["TokenizerSwitcher"] = 16] = "TokenizerSwitcher";
|
|
108
|
+
return NodeSort;
|
|
109
|
+
}({});
|
|
110
|
+
(function (TerpEvt) {
|
|
111
|
+
TerpEvt["AllAttrGot"] = "all-attr-got";
|
|
112
|
+
TerpEvt["HandledComponentNode"] = "handled-component-node";
|
|
113
|
+
return TerpEvt;
|
|
114
|
+
})({});
|
|
109
115
|
|
|
110
116
|
class MultiTypeStack {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// 记录每个类别的当前最新节点(各分类的“栈顶”)
|
|
115
|
-
this.typeTops = {};
|
|
116
|
-
this.length = 0;
|
|
117
|
-
this.stack = [];
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* 入栈操作
|
|
121
|
-
* @param value 数据
|
|
122
|
-
* @param bits 该节点所属的类别数组
|
|
123
|
-
*/
|
|
117
|
+
typeTops = {};
|
|
118
|
+
length = 0;
|
|
119
|
+
stack = [];
|
|
124
120
|
push(value, bits) {
|
|
125
121
|
const newNode = {
|
|
126
122
|
value,
|
|
@@ -132,18 +128,15 @@
|
|
|
132
128
|
bit = bits & ~bits + 1;
|
|
133
129
|
if (!bit) break;
|
|
134
130
|
bits &= ~bit;
|
|
135
|
-
newNode.prevByType[bit] = this.typeTops[bit] ||
|
|
131
|
+
newNode.prevByType[bit] = this.typeTops[bit] || undefined;
|
|
136
132
|
this.typeTops[bit] = newNode;
|
|
137
133
|
}
|
|
138
134
|
this.stack[this.length++] = newNode;
|
|
139
135
|
}
|
|
140
|
-
/**
|
|
141
|
-
* 出栈操作
|
|
142
|
-
*/
|
|
143
136
|
pop() {
|
|
144
137
|
const poppedNode = this.stack[this.length - 1];
|
|
145
138
|
this.stack[--this.length] = null;
|
|
146
|
-
if (!poppedNode) return
|
|
139
|
+
if (!poppedNode) return undefined;
|
|
147
140
|
let bits = poppedNode.types;
|
|
148
141
|
let bit;
|
|
149
142
|
while (1) {
|
|
@@ -154,63 +147,26 @@
|
|
|
154
147
|
}
|
|
155
148
|
return [poppedNode.value, poppedNode.types];
|
|
156
149
|
}
|
|
157
|
-
/**
|
|
158
|
-
* 获取某个类别的当前“顶部”元素
|
|
159
|
-
*/
|
|
160
150
|
peekByType(cat) {
|
|
161
151
|
return this.typeTops[cat]?.value;
|
|
162
152
|
}
|
|
163
153
|
peekType() {
|
|
164
154
|
return this.stack.at(-1).types;
|
|
165
155
|
}
|
|
166
|
-
/**
|
|
167
|
-
* 获取全局栈顶
|
|
168
|
-
*/
|
|
169
156
|
peek() {
|
|
170
157
|
return this.stack.at(-1).value;
|
|
171
158
|
}
|
|
172
|
-
// /**
|
|
173
|
-
// * 1. 全局向前遍历 (不分类)
|
|
174
|
-
// * 从栈顶开始,沿着全局链条向栈底遍历
|
|
175
|
-
// */
|
|
176
|
-
// forEach(callback: (value: T, types: number) => any): void {
|
|
177
|
-
// let current = this.top;
|
|
178
|
-
// while (current !== null) {
|
|
179
|
-
// // 执行回调,如果返回 false 则立即停止
|
|
180
|
-
// const shouldBreak = callback(current.value, current.types);
|
|
181
|
-
// if (shouldBreak) break;
|
|
182
|
-
// current = current.prevGlobal;
|
|
183
|
-
// }
|
|
184
|
-
// }
|
|
185
|
-
// /**
|
|
186
|
-
// * 2. 按类别向前遍历
|
|
187
|
-
// * 仅遍历属于指定类别 cat 的节点
|
|
188
|
-
// */
|
|
189
|
-
// forEachByType(cat: number, callback: (value: T) => any): void {
|
|
190
|
-
// // 从该类别的当前“顶端”节点开始
|
|
191
|
-
// let current = this.typeTops[cat];
|
|
192
|
-
// while (current) {
|
|
193
|
-
// const shouldBreak = callback(current.value);
|
|
194
|
-
// if (shouldBreak) break;
|
|
195
|
-
// // 关键点:直接跳向该节点记录的“上一个同类节点”
|
|
196
|
-
// // 这比遍历全局栈再筛选类别要快得多 (O(m) vs O(n))
|
|
197
|
-
// current = current.prevByType[cat];
|
|
198
|
-
// }
|
|
199
|
-
// }
|
|
200
159
|
}
|
|
201
160
|
|
|
202
161
|
const _excluded = ["dentStack", "isFirstToken"];
|
|
203
|
-
new bobeShared.BaseEvent();
|
|
204
162
|
class Interpreter {
|
|
205
163
|
constructor(tokenizer) {
|
|
206
164
|
this.tokenizer = tokenizer;
|
|
207
|
-
this.rootComponent = null;
|
|
208
|
-
this.forItemId = 0;
|
|
209
|
-
this.oneRealPropParsed = this.onePropParsed.bind(this);
|
|
210
165
|
}
|
|
211
166
|
isLogicNode(node) {
|
|
212
167
|
return node && node.__logicType & LogicalBit;
|
|
213
168
|
}
|
|
169
|
+
rootComponent = null;
|
|
214
170
|
program(root, componentNode, before, ctxProvider) {
|
|
215
171
|
this.rootComponent = componentNode;
|
|
216
172
|
this.tokenizer.nextToken();
|
|
@@ -253,7 +209,7 @@
|
|
|
253
209
|
}, !ctx.current.__logicType ? NodeSort.Real : (ctx.current.__logicType & LogicalBit ? NodeSort.Logic : 0) | (ctx.current.__logicType & TokenizerSwitcherBit ? NodeSort.TokenizerSwitcher : 0) | (ctx.current.__logicType === FakeType.Component ? NodeSort.Component : 0) | NodeSort.CtxProvider);
|
|
254
210
|
if (ctx.current.__logicType) {
|
|
255
211
|
if (isLogicNode) {
|
|
256
|
-
aoye.setPulling(ctx.current.effect
|
|
212
|
+
aoye.setPulling(ctx.current.effect);
|
|
257
213
|
}
|
|
258
214
|
} else {
|
|
259
215
|
if (ctx.current) {
|
|
@@ -285,7 +241,7 @@
|
|
|
285
241
|
if (sort & NodeSort.Logic) {
|
|
286
242
|
const parentLogic = stack.peekByType(NodeSort.Logic)?.node;
|
|
287
243
|
if (parentLogic) {
|
|
288
|
-
aoye.setPulling(parentLogic.effect
|
|
244
|
+
aoye.setPulling(parentLogic.effect);
|
|
289
245
|
} else {
|
|
290
246
|
aoye.setPulling(rootPulling);
|
|
291
247
|
}
|
|
@@ -295,7 +251,8 @@
|
|
|
295
251
|
this.tokenizer = switcher.tokenizer;
|
|
296
252
|
}
|
|
297
253
|
if (parent.__logicType === FakeType.ForItem) {
|
|
298
|
-
const
|
|
254
|
+
const _ref = parent,
|
|
255
|
+
forNode = _ref.forNode;
|
|
299
256
|
const i = forNode.i,
|
|
300
257
|
arr = forNode.arr,
|
|
301
258
|
snapshot = forNode.snapshot;
|
|
@@ -321,7 +278,7 @@
|
|
|
321
278
|
}
|
|
322
279
|
return componentNode;
|
|
323
280
|
}
|
|
324
|
-
insertAfterAnchor(name =
|
|
281
|
+
insertAfterAnchor(name = 'anchor') {
|
|
325
282
|
const _this$ctx = this.ctx,
|
|
326
283
|
realParent = _this$ctx.realParent,
|
|
327
284
|
prevSibling = _this$ctx.prevSibling,
|
|
@@ -332,12 +289,6 @@
|
|
|
332
289
|
this.handleInsert(realParent, afterAnchor, prevSibling);
|
|
333
290
|
return afterAnchor;
|
|
334
291
|
}
|
|
335
|
-
/** 处理
|
|
336
|
-
* 是逻辑 是普通
|
|
337
|
-
* 父节点 将子节点加入 directList 调用 insert 方法挨个插入子节点
|
|
338
|
-
* 子节点 仅插入到父逻辑节点 将本节点插入父节点
|
|
339
|
-
* 理论上父节点不能是一个 逻辑节点,遇到if 时 Terp 会重新执行 program 这种情况下,会指定 root 为真实 dom
|
|
340
|
-
*/
|
|
341
292
|
handleInsert(parent, child, prev, parentComponent) {
|
|
342
293
|
if (!child.__logicType) {
|
|
343
294
|
if (!prev || !prev.__logicType) {
|
|
@@ -356,7 +307,6 @@
|
|
|
356
307
|
}
|
|
357
308
|
}
|
|
358
309
|
}
|
|
359
|
-
/** 考虑到同级 逻辑模块 */
|
|
360
310
|
getPrevRealSibling(prevSibling) {
|
|
361
311
|
if (!prevSibling || !prevSibling.__logicType) {
|
|
362
312
|
return prevSibling;
|
|
@@ -369,38 +319,33 @@
|
|
|
369
319
|
point = point.anchor;
|
|
370
320
|
}
|
|
371
321
|
}
|
|
372
|
-
/**
|
|
373
|
-
* 声明部分:
|
|
374
|
-
* 包含首行定义和(可选的)多行属性扩展
|
|
375
|
-
* <declaration> ::= <tagName=token> <headerLine> <extensionLines>
|
|
376
|
-
* */
|
|
377
322
|
declaration(ctx) {
|
|
378
323
|
const _this$tokenizer$_hook = this.tokenizer._hook({}),
|
|
379
324
|
_this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
|
|
380
325
|
hookType = _this$tokenizer$_hook2[0],
|
|
381
326
|
value = _this$tokenizer$_hook2[1];
|
|
382
327
|
let _node;
|
|
383
|
-
if (value ===
|
|
328
|
+
if (value === 'if' || value === 'else' || value === 'fail') {
|
|
384
329
|
return this.condDeclaration(ctx);
|
|
385
|
-
} else if (value ===
|
|
330
|
+
} else if (value === 'for') {
|
|
386
331
|
return this.forDeclaration();
|
|
387
332
|
} else if (hookType) {
|
|
388
333
|
const data = this.getData();
|
|
389
|
-
if (hookType ===
|
|
390
|
-
if (typeof value ===
|
|
334
|
+
if (hookType === 'static') {
|
|
335
|
+
if (typeof value === 'function') {
|
|
391
336
|
_node = this.componentOrFragmentDeclaration(value, ctx);
|
|
392
337
|
} else {
|
|
393
|
-
throw new SyntaxError(`declaration
|
|
338
|
+
throw new SyntaxError(`declaration 不支持 ${value} 类型的静态插值`);
|
|
394
339
|
}
|
|
395
340
|
} else {
|
|
396
341
|
const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
|
|
397
342
|
const val = data[aoye.Keys.Raw][value];
|
|
398
|
-
if (typeof val ===
|
|
343
|
+
if (typeof val === 'function') {
|
|
399
344
|
_node = this.componentOrFragmentDeclaration(val, ctx);
|
|
400
345
|
} else {
|
|
401
346
|
const str = valueIsMapKey ? value : this.getFn(data, value);
|
|
402
|
-
_node = this.createNode(
|
|
403
|
-
this.onePropParsed(data, _node,
|
|
347
|
+
_node = this.createNode('text');
|
|
348
|
+
this.onePropParsed(data, _node, 'text', str, valueIsMapKey, false);
|
|
404
349
|
}
|
|
405
350
|
}
|
|
406
351
|
} else {
|
|
@@ -422,12 +367,12 @@
|
|
|
422
367
|
const isDestruct = itemToken.type === TokenType.InsertionExp;
|
|
423
368
|
let itemExp = itemToken.value;
|
|
424
369
|
if (isDestruct) {
|
|
425
|
-
itemExp =
|
|
426
|
-
const vars = itemExp.match(bobeShared.jsVarRegexp).join(
|
|
427
|
-
itemExp = new Function(
|
|
370
|
+
itemExp = '{' + itemExp + '}';
|
|
371
|
+
const vars = itemExp.match(bobeShared.jsVarRegexp).join(',');
|
|
372
|
+
itemExp = new Function('item', `let ${vars}; (${itemExp}=item); return {${vars}};`);
|
|
428
373
|
}
|
|
429
374
|
let indexName, keyExp;
|
|
430
|
-
while (this.tokenizer.code[this.tokenizer.i] !==
|
|
375
|
+
while (this.tokenizer.code[this.tokenizer.i] !== '\n') {
|
|
431
376
|
const next = this.tokenizer.nextToken();
|
|
432
377
|
if (next.type !== TokenType.Semicolon) {
|
|
433
378
|
if (!indexName) {
|
|
@@ -441,7 +386,7 @@
|
|
|
441
386
|
const prevSibling = this.ctx.prevSibling;
|
|
442
387
|
const forNode = {
|
|
443
388
|
__logicType: FakeType.For,
|
|
444
|
-
snapshot: this.tokenizer.snapshot([
|
|
389
|
+
snapshot: this.tokenizer.snapshot(['dentStack', 'isFirstToken']),
|
|
445
390
|
realParent: this.ctx.realParent,
|
|
446
391
|
prevSibling,
|
|
447
392
|
realBefore: prevSibling?.realAfter || prevSibling,
|
|
@@ -456,25 +401,21 @@
|
|
|
456
401
|
i: 0
|
|
457
402
|
};
|
|
458
403
|
if (keyExp) {
|
|
459
|
-
forNode.getKey = new Function(
|
|
404
|
+
forNode.getKey = new Function('data', `let v;with(data){v=${keyExp}};return v;`);
|
|
460
405
|
}
|
|
461
|
-
window[
|
|
406
|
+
window['for1'] = forNode;
|
|
462
407
|
const data = this.getData();
|
|
463
408
|
const cells = data[aoye.Keys.Meta].cells;
|
|
464
409
|
const hasArrExpKey = Reflect.has(data[aoye.Keys.Raw], arrExp);
|
|
465
|
-
const arrSignal = hasArrExpKey ? (
|
|
466
|
-
|
|
467
|
-
data[arrExp], cells.get(arrExp)) :
|
|
468
|
-
// 无key
|
|
469
|
-
aoye.$(this.getFn(data, arrExp));
|
|
470
|
-
forNode.realAfter = this.insertAfterAnchor("for-after");
|
|
410
|
+
const arrSignal = hasArrExpKey ? (data[arrExp], cells.get(arrExp)) : new aoye.Computed(this.getFn(data, arrExp));
|
|
411
|
+
forNode.realAfter = this.insertAfterAnchor('for-after');
|
|
471
412
|
const _forNode$snapshot = forNode.snapshot;
|
|
472
413
|
_forNode$snapshot.dentStack;
|
|
473
414
|
_forNode$snapshot.isFirstToken;
|
|
474
415
|
const snapshotForUpdate = _objectWithoutProperties(_forNode$snapshot, _excluded);
|
|
475
416
|
let isFirstRender = true;
|
|
476
|
-
forNode.effect = aoye.
|
|
477
|
-
let arr = forNode.arr = arrSignal.
|
|
417
|
+
forNode.effect = new aoye.Effect(() => {
|
|
418
|
+
let arr = forNode.arr = arrSignal.get();
|
|
478
419
|
arr[aoye.Keys.Iterator];
|
|
479
420
|
arr = aoye.toRaw(arr);
|
|
480
421
|
const children = forNode.children;
|
|
@@ -483,7 +424,7 @@
|
|
|
483
424
|
for (let i = len; i--;) {
|
|
484
425
|
const nextItem = children[i + 1];
|
|
485
426
|
const item = this.createForItem(forNode, i, data);
|
|
486
|
-
const anchor = this.insertAfterAnchor(
|
|
427
|
+
const anchor = this.insertAfterAnchor('for-item-after');
|
|
487
428
|
item.realAfter = anchor;
|
|
488
429
|
if (nextItem) {
|
|
489
430
|
nextItem.realBefore = anchor;
|
|
@@ -510,7 +451,7 @@
|
|
|
510
451
|
const child = children[i];
|
|
511
452
|
this.removeLogicNode(child);
|
|
512
453
|
this.remove(child.realAfter);
|
|
513
|
-
child.effect();
|
|
454
|
+
child.effect.dispose();
|
|
514
455
|
}
|
|
515
456
|
}
|
|
516
457
|
if (oldLen < newLen) {
|
|
@@ -519,7 +460,7 @@
|
|
|
519
460
|
const item = this.createForItem(forNode, i, data);
|
|
520
461
|
newChildren[i] = item;
|
|
521
462
|
const nextItem = newChildren[i + 1];
|
|
522
|
-
const anchor = this.createAnchor(
|
|
463
|
+
const anchor = this.createAnchor('for-item-after');
|
|
523
464
|
this.insertAfter(forNode.realParent, anchor, lastAfter);
|
|
524
465
|
item.realAfter = anchor;
|
|
525
466
|
if (nextItem) {
|
|
@@ -531,7 +472,7 @@
|
|
|
531
472
|
this.tokenizer.useDedentAsEof = false;
|
|
532
473
|
aoye.runWithPulling(() => {
|
|
533
474
|
this.program(forNode.realParent, forNode.owner, lastAfter, item);
|
|
534
|
-
}, item.effect
|
|
475
|
+
}, item.effect);
|
|
535
476
|
}
|
|
536
477
|
const firstInsert = newChildren[oldLen];
|
|
537
478
|
if (firstInsert) {
|
|
@@ -541,7 +482,7 @@
|
|
|
541
482
|
for (let i = minLen; i--;) {
|
|
542
483
|
const child = children[i];
|
|
543
484
|
newChildren[i] = child;
|
|
544
|
-
if (typeof itemExp ===
|
|
485
|
+
if (typeof itemExp === 'string') {
|
|
545
486
|
child.data[itemExp] = arr[i];
|
|
546
487
|
} else {
|
|
547
488
|
Object.assign(child.data, itemExp(arr[i]));
|
|
@@ -554,27 +495,32 @@
|
|
|
554
495
|
});
|
|
555
496
|
return forNode.children[0] || forNode;
|
|
556
497
|
}
|
|
498
|
+
forItemId = 0;
|
|
557
499
|
createForItem(forNode, i, parentData) {
|
|
558
500
|
let forItemNode;
|
|
559
|
-
const
|
|
501
|
+
const scope = new aoye.Scope(() => {});
|
|
502
|
+
scope.scope = null;
|
|
503
|
+
aoye.runWithPulling(() => {
|
|
504
|
+
scope.get();
|
|
505
|
+
}, null);
|
|
560
506
|
const arr = forNode.arr,
|
|
561
507
|
itemExp = forNode.itemExp,
|
|
562
508
|
indexName = forNode.indexName,
|
|
563
509
|
getKey = forNode.getKey;
|
|
564
510
|
let data;
|
|
565
|
-
if (typeof itemExp ===
|
|
566
|
-
data = aoye
|
|
511
|
+
if (typeof itemExp === 'string') {
|
|
512
|
+
data = aoye.deepSignal(indexName ? {
|
|
567
513
|
[itemExp]: arr[i],
|
|
568
514
|
[indexName]: i
|
|
569
515
|
} : {
|
|
570
516
|
[itemExp]: arr[i]
|
|
571
|
-
});
|
|
517
|
+
}, aoye.getPulling());
|
|
572
518
|
} else {
|
|
573
519
|
const rawData = itemExp(arr[i]);
|
|
574
520
|
if (indexName) {
|
|
575
521
|
rawData[indexName] = i;
|
|
576
522
|
}
|
|
577
|
-
data = aoye
|
|
523
|
+
data = aoye.deepSignal(rawData, aoye.getPulling());
|
|
578
524
|
}
|
|
579
525
|
Object.setPrototypeOf(data, parentData);
|
|
580
526
|
forItemNode = {
|
|
@@ -588,7 +534,7 @@
|
|
|
588
534
|
effect: null,
|
|
589
535
|
data
|
|
590
536
|
};
|
|
591
|
-
forItemNode.effect =
|
|
537
|
+
forItemNode.effect = scope;
|
|
592
538
|
return forItemNode;
|
|
593
539
|
}
|
|
594
540
|
getData() {
|
|
@@ -596,24 +542,16 @@
|
|
|
596
542
|
node = _this$ctx$stack$peekB.node;
|
|
597
543
|
return node.data || node.owner.data;
|
|
598
544
|
}
|
|
599
|
-
/**
|
|
600
|
-
* key 元素,组件的 key
|
|
601
|
-
* value
|
|
602
|
-
* 1. 静态类型值
|
|
603
|
-
* 2. 插值计算 函数,可以考虑 使用 effect 或 computed 做处理
|
|
604
|
-
*
|
|
605
|
-
* mapKey 映射, 对应子组件的属性
|
|
606
|
-
* */
|
|
607
545
|
onePropParsed(data, node, key, value, valueIsMapKey, isFn, hookI) {
|
|
608
546
|
if (isFn) {
|
|
609
547
|
this.setProp(node, key, value, hookI);
|
|
610
|
-
} else if (typeof value ===
|
|
611
|
-
aoye.
|
|
548
|
+
} else if (typeof value === 'function') {
|
|
549
|
+
new aoye.Effect(() => {
|
|
612
550
|
const res = value();
|
|
613
551
|
this.setProp(node, key, res, hookI);
|
|
614
552
|
});
|
|
615
553
|
} else if (valueIsMapKey) {
|
|
616
|
-
aoye.
|
|
554
|
+
new aoye.Effect(() => {
|
|
617
555
|
const res = data[value];
|
|
618
556
|
this.setProp(node, key, res, hookI);
|
|
619
557
|
});
|
|
@@ -621,6 +559,7 @@
|
|
|
621
559
|
this.setProp(node, key, value, hookI);
|
|
622
560
|
}
|
|
623
561
|
}
|
|
562
|
+
oneRealPropParsed = this.onePropParsed.bind(this);
|
|
624
563
|
componentOrFragmentDeclaration(ComponentOrRender, ctx) {
|
|
625
564
|
let Component, render, child;
|
|
626
565
|
const isCC = ComponentOrRender.prototype instanceof aoye.Store;
|
|
@@ -639,7 +578,7 @@
|
|
|
639
578
|
realBefore: null,
|
|
640
579
|
realAfter: null,
|
|
641
580
|
data: child,
|
|
642
|
-
tokenizer: render ? render(true) : child[
|
|
581
|
+
tokenizer: render ? render(true) : child['ui'](true)
|
|
643
582
|
};
|
|
644
583
|
this.onePropParsed = (data, _, key, value, valueIsMapKey, isFn, hookI) => {
|
|
645
584
|
if (isFn) {
|
|
@@ -649,32 +588,31 @@
|
|
|
649
588
|
} else {
|
|
650
589
|
const meta = child[aoye.Keys.Meta];
|
|
651
590
|
const cells = meta.cells;
|
|
652
|
-
if (typeof value ===
|
|
653
|
-
const computed = aoye
|
|
591
|
+
if (typeof value === 'function') {
|
|
592
|
+
const computed = new aoye.Computed(value);
|
|
654
593
|
cells.set(key, computed);
|
|
655
|
-
child[aoye.Keys.Raw][key] =
|
|
594
|
+
child[aoye.Keys.Raw][key] = undefined;
|
|
656
595
|
} else {
|
|
657
596
|
cells.set(key, {
|
|
658
|
-
|
|
597
|
+
get: () => value
|
|
659
598
|
});
|
|
660
599
|
child[aoye.Keys.Raw][key] = value;
|
|
661
600
|
}
|
|
662
601
|
}
|
|
663
602
|
};
|
|
664
|
-
node.realAfter = this.insertAfterAnchor(
|
|
603
|
+
node.realAfter = this.insertAfterAnchor('component-after');
|
|
665
604
|
return node;
|
|
666
605
|
}
|
|
667
606
|
getFn(data, expression) {
|
|
668
|
-
return new Function(
|
|
607
|
+
return new Function('data', `let v;with(data){v=${expression}};return v;`).bind(undefined, data);
|
|
669
608
|
}
|
|
670
|
-
// TODO: 优化代码逻辑,拆分 if elseif else
|
|
671
609
|
condDeclaration(ctx) {
|
|
672
610
|
const prevSibling = ctx.prevSibling;
|
|
673
611
|
const keyWord = this.tokenizer.token;
|
|
674
612
|
const expToken = this.tokenizer.condExp();
|
|
675
613
|
const value = expToken.value;
|
|
676
|
-
const isElse = keyWord.value ===
|
|
677
|
-
const isIf = keyWord.value ===
|
|
614
|
+
const isElse = keyWord.value === 'else';
|
|
615
|
+
const isIf = keyWord.value === 'if';
|
|
678
616
|
const preIsCond = prevSibling?.__logicType & CondBit;
|
|
679
617
|
const data = this.getData();
|
|
680
618
|
const noCond = value === true;
|
|
@@ -682,7 +620,6 @@
|
|
|
682
620
|
const owner = ctx.stack.peekByType(NodeSort.TokenizerSwitcher)?.node;
|
|
683
621
|
const ifNode = {
|
|
684
622
|
__logicType: isElse ? FakeType.Else : isIf ? FakeType.If : FakeType.Fail,
|
|
685
|
-
// 此时 token 是 exp, 下次解析 从 \n 开始
|
|
686
623
|
snapshot: this.tokenizer.snapshot(),
|
|
687
624
|
realParent: null,
|
|
688
625
|
realBefore: null,
|
|
@@ -695,22 +632,22 @@
|
|
|
695
632
|
};
|
|
696
633
|
let signal;
|
|
697
634
|
switch (keyWord.value) {
|
|
698
|
-
case
|
|
635
|
+
case 'if':
|
|
699
636
|
if (valueIsMapKey) {
|
|
700
637
|
aoye.runWithPulling(() => data[value], null);
|
|
701
638
|
const cells = data[aoye.Keys.Meta].cells;
|
|
702
639
|
signal = cells.get(value);
|
|
703
640
|
} else {
|
|
704
641
|
const fn = this.getFn(data, value);
|
|
705
|
-
signal = aoye
|
|
642
|
+
signal = new aoye.Computed(fn);
|
|
706
643
|
}
|
|
707
644
|
break;
|
|
708
|
-
case
|
|
645
|
+
case 'else':
|
|
709
646
|
if (noCond) {
|
|
710
|
-
signal = aoye
|
|
647
|
+
signal = new aoye.Computed(() => {
|
|
711
648
|
let point = ifNode.preCond;
|
|
712
649
|
while (point) {
|
|
713
|
-
if (point.condition.
|
|
650
|
+
if (point.condition.get()) {
|
|
714
651
|
return false;
|
|
715
652
|
}
|
|
716
653
|
if (point.__logicType === FakeType.If) {
|
|
@@ -722,10 +659,10 @@
|
|
|
722
659
|
});
|
|
723
660
|
} else {
|
|
724
661
|
const fn = valueIsMapKey ? null : this.getFn(data, value);
|
|
725
|
-
signal = aoye
|
|
662
|
+
signal = new aoye.Computed(() => {
|
|
726
663
|
let point = ifNode.preCond;
|
|
727
664
|
while (point) {
|
|
728
|
-
if (point.condition.
|
|
665
|
+
if (point.condition.get()) {
|
|
729
666
|
return false;
|
|
730
667
|
}
|
|
731
668
|
if (point.__logicType === FakeType.If) {
|
|
@@ -737,11 +674,11 @@
|
|
|
737
674
|
});
|
|
738
675
|
}
|
|
739
676
|
break;
|
|
740
|
-
case
|
|
741
|
-
signal = aoye
|
|
677
|
+
case 'fail':
|
|
678
|
+
signal = new aoye.Computed(() => {
|
|
742
679
|
let point = ifNode.preCond;
|
|
743
680
|
while (point) {
|
|
744
|
-
if (point.condition.
|
|
681
|
+
if (point.condition.get()) {
|
|
745
682
|
return false;
|
|
746
683
|
}
|
|
747
684
|
point = point.preCond;
|
|
@@ -752,7 +689,7 @@
|
|
|
752
689
|
}
|
|
753
690
|
ifNode.condition = signal;
|
|
754
691
|
ifNode.realAfter = this.insertAfterAnchor(`${keyWord.value}-after`);
|
|
755
|
-
|
|
692
|
+
const ef = aoye.effect(({
|
|
756
693
|
val
|
|
757
694
|
}) => {
|
|
758
695
|
if (val) {
|
|
@@ -774,6 +711,7 @@
|
|
|
774
711
|
}
|
|
775
712
|
ifNode.isFirstRender = false;
|
|
776
713
|
}, [signal]);
|
|
714
|
+
ifNode.effect = ef.ins;
|
|
777
715
|
return ifNode;
|
|
778
716
|
}
|
|
779
717
|
removeLogicNode(node) {
|
|
@@ -787,10 +725,6 @@
|
|
|
787
725
|
point = next;
|
|
788
726
|
}
|
|
789
727
|
}
|
|
790
|
-
/**
|
|
791
|
-
* <extensionLines> ::= PIPE <attributeList> NEWLINE <extensionLines>
|
|
792
|
-
* | ε
|
|
793
|
-
*/
|
|
794
728
|
extensionLines(_node) {
|
|
795
729
|
while (1) {
|
|
796
730
|
if ((this.tokenizer.token.type & TokenType.Pipe) === 0) {
|
|
@@ -804,25 +738,10 @@
|
|
|
804
738
|
this.tokenizer.nextToken();
|
|
805
739
|
}
|
|
806
740
|
}
|
|
807
|
-
/**
|
|
808
|
-
* 首行:
|
|
809
|
-
* 节点名称 + 属性列表 + 换行
|
|
810
|
-
* <headerLine> ::= <attributeList> NEWLINE
|
|
811
|
-
*/
|
|
812
741
|
headerLine(_node) {
|
|
813
742
|
this.attributeList(_node);
|
|
814
743
|
this.tokenizer.nextToken();
|
|
815
744
|
}
|
|
816
|
-
/**
|
|
817
|
-
* 属性列表:
|
|
818
|
-
* 可以是空的,或者包含多个属性
|
|
819
|
-
* <attributeList> ::= <attribute> <attributeList>
|
|
820
|
-
* | ε
|
|
821
|
-
*
|
|
822
|
-
* <attribute> ::= <key> = <value>
|
|
823
|
-
* 1. 普通节点 执行 setProps 🪝
|
|
824
|
-
* 2. 组件节点 收集映射关系,或 产生 computed
|
|
825
|
-
*/
|
|
826
745
|
attributeList(_node) {
|
|
827
746
|
let key, eq;
|
|
828
747
|
const data = this.getData();
|
|
@@ -830,7 +749,7 @@
|
|
|
830
749
|
if (key == null) {
|
|
831
750
|
key = this.tokenizer.token.value;
|
|
832
751
|
} else if (eq == null) {
|
|
833
|
-
eq =
|
|
752
|
+
eq = '=';
|
|
834
753
|
} else {
|
|
835
754
|
const _this$tokenizer$_hook3 = this.tokenizer._hook({}),
|
|
836
755
|
_this$tokenizer$_hook4 = _slicedToArray(_this$tokenizer$_hook3, 3),
|
|
@@ -838,12 +757,12 @@
|
|
|
838
757
|
value = _this$tokenizer$_hook4[1],
|
|
839
758
|
hookI = _this$tokenizer$_hook4[2];
|
|
840
759
|
const rawVal = data[aoye.Keys.Raw][value];
|
|
841
|
-
const isFn = typeof rawVal ===
|
|
842
|
-
if (hookType ===
|
|
760
|
+
const isFn = typeof rawVal === 'function';
|
|
761
|
+
if (hookType === 'dynamic') {
|
|
843
762
|
const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
|
|
844
763
|
const fn = isFn ? rawVal : valueIsMapKey ? value : this.getFn(data, value);
|
|
845
764
|
this.onePropParsed(data, _node, key, fn, valueIsMapKey, isFn, hookI);
|
|
846
|
-
} else if (hookType ===
|
|
765
|
+
} else if (hookType === 'static') {
|
|
847
766
|
this.onePropParsed(data, _node, key, value, false, isFn, hookI);
|
|
848
767
|
} else {
|
|
849
768
|
this.onePropParsed(data, _node, key, value, false, isFn, hookI);
|
|
@@ -894,7 +813,6 @@
|
|
|
894
813
|
remove(node, parent, prev) {
|
|
895
814
|
return this.defaultRemove(node, parent, prev);
|
|
896
815
|
}
|
|
897
|
-
// TODO: 默认改成 prevItem
|
|
898
816
|
defaultRemove(node, parent, prevSibling) {
|
|
899
817
|
const next = node.nextSibling;
|
|
900
818
|
if (prevSibling) {
|
|
@@ -910,76 +828,33 @@
|
|
|
910
828
|
}
|
|
911
829
|
|
|
912
830
|
class Tokenizer {
|
|
831
|
+
TabSize = 2;
|
|
832
|
+
Tab = Array.from({
|
|
833
|
+
length: this.TabSize
|
|
834
|
+
}, () => ' ').join('');
|
|
835
|
+
static EofId = `__EOF__${Date.now()}`;
|
|
836
|
+
static DedentId = `__DEDENT__${Date.now()}`;
|
|
837
|
+
needIndent = false;
|
|
838
|
+
isFirstToken = true;
|
|
839
|
+
dentStack = [0];
|
|
840
|
+
i = 0;
|
|
841
|
+
handledTokens = [];
|
|
842
|
+
waitingTokens = new bobeShared.Queue();
|
|
913
843
|
constructor(hook, useDedentAsEof) {
|
|
914
844
|
this.hook = hook;
|
|
915
845
|
this.useDedentAsEof = useDedentAsEof;
|
|
916
|
-
/** 缩进大小 默认 2 */
|
|
917
|
-
this.TabSize = 2;
|
|
918
|
-
/** 缩进字符 */
|
|
919
|
-
this.Tab = Array.from({
|
|
920
|
-
length: this.TabSize
|
|
921
|
-
}, () => " ").join("");
|
|
922
|
-
/** 回车后需要判断缩进 */
|
|
923
|
-
this.needIndent = false;
|
|
924
|
-
/** 用于跳过第一个节点前的空白字符串,以及生成基础缩进 */
|
|
925
|
-
this.isFirstToken = true;
|
|
926
|
-
/** 记录历史缩进的长度,相对于行首 */
|
|
927
|
-
this.dentStack = [0];
|
|
928
|
-
/** 当前字符 index */
|
|
929
|
-
this.i = 0;
|
|
930
|
-
// TODO: 生产环境不需要这个,导致不必要的内存占用
|
|
931
|
-
this.handledTokens = [];
|
|
932
|
-
/**
|
|
933
|
-
* 有些标识符能产生多个 token
|
|
934
|
-
* 例如 dedent
|
|
935
|
-
* parent1
|
|
936
|
-
* child
|
|
937
|
-
* subChild
|
|
938
|
-
* parent2 <- 产生两个 dedent
|
|
939
|
-
*/
|
|
940
|
-
this.waitingTokens = new bobeShared.Queue();
|
|
941
|
-
/** 模板字符串动态节点的占位符 */
|
|
942
|
-
this.HookId = "_h_o_o_k_";
|
|
943
|
-
/** 模板字符串动态节点索引 */
|
|
944
|
-
this.hookI = 0;
|
|
945
|
-
this._hook = props => {
|
|
946
|
-
const value = this.token.value;
|
|
947
|
-
const isDynamicHook = this.token.type & TokenType.InsertionExp;
|
|
948
|
-
const isStaticHook = typeof value === "string" && value.indexOf(this.HookId) === 0;
|
|
949
|
-
const hookType = isDynamicHook ? "dynamic" : isStaticHook ? "static" : void 0;
|
|
950
|
-
if (this.hook && isStaticHook) {
|
|
951
|
-
const hookI = Number(value.slice(this.HookId.length));
|
|
952
|
-
const res = this.hook({
|
|
953
|
-
...props,
|
|
954
|
-
HookId: this.HookId,
|
|
955
|
-
i: hookI
|
|
956
|
-
});
|
|
957
|
-
return [hookType, res, hookI];
|
|
958
|
-
} else if (isDynamicHook) {
|
|
959
|
-
return [hookType, value];
|
|
960
|
-
}
|
|
961
|
-
return [hookType, value];
|
|
962
|
-
};
|
|
963
846
|
if (useDedentAsEof) {
|
|
964
|
-
this.setToken(TokenType.Indent,
|
|
847
|
+
this.setToken(TokenType.Indent, '');
|
|
965
848
|
this.isFirstToken = true;
|
|
966
849
|
}
|
|
967
850
|
}
|
|
968
|
-
static {
|
|
969
|
-
/** Eof 标识符的值 */
|
|
970
|
-
this.EofId = `__EOF__${Date.now()}`;
|
|
971
|
-
}
|
|
972
|
-
static {
|
|
973
|
-
this.DedentId = `__DEDENT__${Date.now()}`;
|
|
974
|
-
}
|
|
975
851
|
consume() {
|
|
976
852
|
const token = this.token;
|
|
977
853
|
this.nextToken();
|
|
978
854
|
return token;
|
|
979
855
|
}
|
|
980
|
-
// /** 恢复至某一个现场,进行 token 重算 */
|
|
981
856
|
resume(_snapshot) {
|
|
982
|
-
this.token =
|
|
857
|
+
this.token = undefined;
|
|
983
858
|
this.needIndent = false;
|
|
984
859
|
this.isFirstToken = true;
|
|
985
860
|
this.dentStack = [0];
|
|
@@ -993,7 +868,7 @@
|
|
|
993
868
|
if (keys) {
|
|
994
869
|
for (const k of keys) {
|
|
995
870
|
snap[k] = this[k];
|
|
996
|
-
if (k ===
|
|
871
|
+
if (k === 'dentStack') {
|
|
997
872
|
snap[k] = this[k].slice();
|
|
998
873
|
}
|
|
999
874
|
}
|
|
@@ -1004,10 +879,10 @@
|
|
|
1004
879
|
const logicDentLen = this.dentStack[this.dentStack.length - 1];
|
|
1005
880
|
let needIndent = false;
|
|
1006
881
|
let skipFragment = ``;
|
|
1007
|
-
this.token =
|
|
882
|
+
this.token = undefined;
|
|
1008
883
|
while (1) {
|
|
1009
884
|
const char = this.code[this.i];
|
|
1010
|
-
if (char ===
|
|
885
|
+
if (char === '\n') {
|
|
1011
886
|
needIndent = true;
|
|
1012
887
|
skipFragment += char;
|
|
1013
888
|
this.i++;
|
|
@@ -1031,7 +906,7 @@
|
|
|
1031
906
|
const expLen = this.dentStack[i];
|
|
1032
907
|
if (currLen === expLen) break;
|
|
1033
908
|
if (currLen > expLen) {
|
|
1034
|
-
throw SyntaxError(
|
|
909
|
+
throw SyntaxError(`缩进错误,缩进长度不匹配`);
|
|
1035
910
|
}
|
|
1036
911
|
if (this.shorterThanBaseDentEof()) {
|
|
1037
912
|
break;
|
|
@@ -1056,13 +931,12 @@
|
|
|
1056
931
|
return skipFragment;
|
|
1057
932
|
}
|
|
1058
933
|
setCode(code) {
|
|
1059
|
-
this.code =
|
|
1060
|
-
${Tokenizer.EofId}`;
|
|
934
|
+
this.code = '\n' + code.trimEnd() + `\n${Tokenizer.EofId}`;
|
|
1061
935
|
}
|
|
1062
936
|
tokenize() {
|
|
1063
937
|
do {
|
|
1064
938
|
this.nextToken();
|
|
1065
|
-
console.log(
|
|
939
|
+
console.log('token:', TokenType[this.token?.type], JSON.stringify(this.token?.value || ''));
|
|
1066
940
|
} while (!this.isEof());
|
|
1067
941
|
}
|
|
1068
942
|
isEof() {
|
|
@@ -1082,7 +956,7 @@ ${Tokenizer.EofId}`;
|
|
|
1082
956
|
if (this.isEof()) {
|
|
1083
957
|
return this.token;
|
|
1084
958
|
}
|
|
1085
|
-
this.token =
|
|
959
|
+
this.token = undefined;
|
|
1086
960
|
if (this.waitingTokens.len) {
|
|
1087
961
|
const item = this.waitingTokens.shift();
|
|
1088
962
|
this.setToken(item.type, item.value);
|
|
@@ -1094,40 +968,39 @@ ${Tokenizer.EofId}`;
|
|
|
1094
968
|
} else {
|
|
1095
969
|
const char = this.code[this.i];
|
|
1096
970
|
switch (char) {
|
|
1097
|
-
case
|
|
1098
|
-
case
|
|
971
|
+
case '\t':
|
|
972
|
+
case ' ':
|
|
1099
973
|
break;
|
|
1100
|
-
|
|
1101
|
-
case "\n":
|
|
974
|
+
case '\n':
|
|
1102
975
|
this.newLine();
|
|
1103
976
|
this.needIndent = true;
|
|
1104
977
|
break;
|
|
1105
|
-
case
|
|
978
|
+
case '=':
|
|
1106
979
|
this.assignment();
|
|
1107
980
|
break;
|
|
1108
|
-
case
|
|
981
|
+
case '|':
|
|
1109
982
|
this.pipe();
|
|
1110
983
|
break;
|
|
1111
984
|
case "'":
|
|
1112
985
|
case '"':
|
|
1113
986
|
this.str(char);
|
|
1114
987
|
break;
|
|
1115
|
-
case
|
|
988
|
+
case '{':
|
|
1116
989
|
const braceToken = this.brace();
|
|
1117
990
|
this.setToken(TokenType.InsertionExp, braceToken);
|
|
1118
991
|
break;
|
|
1119
|
-
case
|
|
992
|
+
case '$':
|
|
1120
993
|
const handled = this.dynamic(char);
|
|
1121
994
|
if (handled) break;
|
|
1122
|
-
case
|
|
1123
|
-
this.setToken(TokenType.Semicolon,
|
|
995
|
+
case ';':
|
|
996
|
+
this.setToken(TokenType.Semicolon, ';');
|
|
1124
997
|
break;
|
|
1125
998
|
default:
|
|
1126
999
|
if (bobeShared.isNum(char)) {
|
|
1127
1000
|
this.number(char);
|
|
1128
1001
|
break;
|
|
1129
1002
|
}
|
|
1130
|
-
if (typeof char ===
|
|
1003
|
+
if (typeof char === 'string' && bobeShared.matchIdStart2(char, 0)) {
|
|
1131
1004
|
this.identifier(char);
|
|
1132
1005
|
}
|
|
1133
1006
|
break;
|
|
@@ -1147,11 +1020,11 @@ ${Tokenizer.EofId}`;
|
|
|
1147
1020
|
}
|
|
1148
1021
|
}
|
|
1149
1022
|
condExp() {
|
|
1150
|
-
let value =
|
|
1023
|
+
let value = '';
|
|
1151
1024
|
this.token = null;
|
|
1152
1025
|
while (1) {
|
|
1153
1026
|
const char = this.code[this.i];
|
|
1154
|
-
if (char ===
|
|
1027
|
+
if (char === '\n') {
|
|
1155
1028
|
break;
|
|
1156
1029
|
}
|
|
1157
1030
|
value += char;
|
|
@@ -1161,21 +1034,14 @@ ${Tokenizer.EofId}`;
|
|
|
1161
1034
|
this.setToken(TokenType.Identifier, value || true);
|
|
1162
1035
|
return this.token;
|
|
1163
1036
|
}
|
|
1164
|
-
/**
|
|
1165
|
-
* 解析到 for 时使用这个方法获取 for 后方的子表达式
|
|
1166
|
-
* 表达式通过 “;” 分割
|
|
1167
|
-
* // 最多可有三个表达式
|
|
1168
|
-
* for arr ; item index; item.key
|
|
1169
|
-
* @returns {boolean} 是否含有 key
|
|
1170
|
-
*/
|
|
1171
1037
|
forLoopSubExp() {
|
|
1172
1038
|
this.token = null;
|
|
1173
|
-
let value =
|
|
1039
|
+
let value = '';
|
|
1174
1040
|
let count = 0;
|
|
1175
1041
|
while (1) {
|
|
1176
1042
|
const char = this.code[this.i];
|
|
1177
|
-
const isSemicolon = char ===
|
|
1178
|
-
if (isSemicolon || char ===
|
|
1043
|
+
const isSemicolon = char === ';';
|
|
1044
|
+
if (isSemicolon || char === '\n') {
|
|
1179
1045
|
value = value.trim();
|
|
1180
1046
|
if (!this.token) {
|
|
1181
1047
|
this.setToken(TokenType.Identifier, value);
|
|
@@ -1186,10 +1052,10 @@ ${Tokenizer.EofId}`;
|
|
|
1186
1052
|
value
|
|
1187
1053
|
});
|
|
1188
1054
|
}
|
|
1189
|
-
value =
|
|
1055
|
+
value = '';
|
|
1190
1056
|
count++;
|
|
1191
1057
|
if (count > 3) {
|
|
1192
|
-
throw SyntaxError(`for
|
|
1058
|
+
throw SyntaxError(`for 循环最多可包含三个表达式, 分别为 arr ; item index [; key]`);
|
|
1193
1059
|
}
|
|
1194
1060
|
if (!isSemicolon) return count === 3;
|
|
1195
1061
|
} else {
|
|
@@ -1199,27 +1065,27 @@ ${Tokenizer.EofId}`;
|
|
|
1199
1065
|
}
|
|
1200
1066
|
}
|
|
1201
1067
|
assignment() {
|
|
1202
|
-
this.setToken(TokenType.Assign,
|
|
1068
|
+
this.setToken(TokenType.Assign, '=');
|
|
1203
1069
|
}
|
|
1204
1070
|
pipe() {
|
|
1205
|
-
this.setToken(TokenType.Pipe,
|
|
1071
|
+
this.setToken(TokenType.Pipe, '|');
|
|
1206
1072
|
}
|
|
1207
1073
|
dynamic(char) {
|
|
1208
1074
|
let nextC = this.code[this.i + 1];
|
|
1209
|
-
if (nextC !==
|
|
1075
|
+
if (nextC !== '{') {
|
|
1210
1076
|
return false;
|
|
1211
1077
|
}
|
|
1212
1078
|
this.i++;
|
|
1213
|
-
let value =
|
|
1079
|
+
let value = '${';
|
|
1214
1080
|
let innerBrace = 0;
|
|
1215
1081
|
while (1) {
|
|
1216
1082
|
nextC = this.code[this.i + 1];
|
|
1217
1083
|
value += nextC;
|
|
1218
1084
|
this.i++;
|
|
1219
|
-
if (nextC ===
|
|
1085
|
+
if (nextC === '{') {
|
|
1220
1086
|
innerBrace++;
|
|
1221
1087
|
}
|
|
1222
|
-
if (nextC ===
|
|
1088
|
+
if (nextC === '}') {
|
|
1223
1089
|
if (!innerBrace) {
|
|
1224
1090
|
break;
|
|
1225
1091
|
}
|
|
@@ -1233,14 +1099,14 @@ ${Tokenizer.EofId}`;
|
|
|
1233
1099
|
let inComment,
|
|
1234
1100
|
inString,
|
|
1235
1101
|
count = 0,
|
|
1236
|
-
value =
|
|
1102
|
+
value = '',
|
|
1237
1103
|
backslashCount = 0;
|
|
1238
1104
|
while (1) {
|
|
1239
1105
|
const char = this.code[this.i];
|
|
1240
1106
|
const nextChar = this.code[this.i + 1];
|
|
1241
|
-
if (inComment ===
|
|
1107
|
+
if (inComment === 'single' && char === '\n') {
|
|
1242
1108
|
inComment = null;
|
|
1243
|
-
} else if (inComment ===
|
|
1109
|
+
} else if (inComment === 'multi' && char === '*' && nextChar === '/') {
|
|
1244
1110
|
inComment = null;
|
|
1245
1111
|
value += this.code[this.i];
|
|
1246
1112
|
this.i++;
|
|
@@ -1248,21 +1114,21 @@ ${Tokenizer.EofId}`;
|
|
|
1248
1114
|
if (char === inString && backslashCount % 2 === 0) {
|
|
1249
1115
|
inString = null;
|
|
1250
1116
|
}
|
|
1251
|
-
backslashCount = char ===
|
|
1117
|
+
backslashCount = char === '\\' ? backslashCount + 1 : 0;
|
|
1252
1118
|
} else {
|
|
1253
|
-
if (char ===
|
|
1254
|
-
inComment =
|
|
1119
|
+
if (char === '/' && nextChar === '/') {
|
|
1120
|
+
inComment = 'single';
|
|
1255
1121
|
value += this.code[this.i];
|
|
1256
1122
|
this.i++;
|
|
1257
|
-
} else if (char ===
|
|
1258
|
-
inComment =
|
|
1123
|
+
} else if (char === '/' && nextChar === '*') {
|
|
1124
|
+
inComment = 'multi';
|
|
1259
1125
|
value += this.code[this.i];
|
|
1260
1126
|
this.i++;
|
|
1261
|
-
} else if (char === "'" || char === '"' || char ===
|
|
1127
|
+
} else if (char === "'" || char === '"' || char === '`') {
|
|
1262
1128
|
inString = char;
|
|
1263
|
-
} else if (char ===
|
|
1129
|
+
} else if (char === '{') {
|
|
1264
1130
|
count++;
|
|
1265
|
-
} else if (char ===
|
|
1131
|
+
} else if (char === '}') {
|
|
1266
1132
|
count--;
|
|
1267
1133
|
}
|
|
1268
1134
|
}
|
|
@@ -1274,11 +1140,11 @@ ${Tokenizer.EofId}`;
|
|
|
1274
1140
|
}
|
|
1275
1141
|
}
|
|
1276
1142
|
newLine() {
|
|
1277
|
-
let value =
|
|
1143
|
+
let value = '\n';
|
|
1278
1144
|
let nextC;
|
|
1279
1145
|
while (1) {
|
|
1280
1146
|
nextC = this.code[this.i + 1];
|
|
1281
|
-
if (nextC !==
|
|
1147
|
+
if (nextC !== '\n') {
|
|
1282
1148
|
break;
|
|
1283
1149
|
}
|
|
1284
1150
|
value += nextC;
|
|
@@ -1290,26 +1156,26 @@ ${Tokenizer.EofId}`;
|
|
|
1290
1156
|
this.setToken(TokenType.NewLine, value);
|
|
1291
1157
|
}
|
|
1292
1158
|
getDentValue() {
|
|
1293
|
-
let value =
|
|
1159
|
+
let value = '';
|
|
1294
1160
|
let nextC;
|
|
1295
1161
|
let isEmptyLine = false;
|
|
1296
1162
|
while (1) {
|
|
1297
1163
|
const nextChar = this.code[this.i];
|
|
1298
1164
|
switch (nextChar) {
|
|
1299
|
-
case
|
|
1165
|
+
case '\t':
|
|
1300
1166
|
nextC = this.Tab;
|
|
1301
1167
|
break;
|
|
1302
|
-
case
|
|
1303
|
-
nextC =
|
|
1168
|
+
case ' ':
|
|
1169
|
+
nextC = ' ';
|
|
1304
1170
|
break;
|
|
1305
|
-
case
|
|
1306
|
-
nextC =
|
|
1171
|
+
case '\n':
|
|
1172
|
+
nextC = '\n';
|
|
1307
1173
|
break;
|
|
1308
1174
|
default:
|
|
1309
|
-
nextC =
|
|
1175
|
+
nextC = '';
|
|
1310
1176
|
break;
|
|
1311
1177
|
}
|
|
1312
|
-
if (nextC ===
|
|
1178
|
+
if (nextC === '\n') {
|
|
1313
1179
|
isEmptyLine = true;
|
|
1314
1180
|
break;
|
|
1315
1181
|
}
|
|
@@ -1350,7 +1216,7 @@ ${Tokenizer.EofId}`;
|
|
|
1350
1216
|
const expLen = this.dentStack[i];
|
|
1351
1217
|
if (currLen === expLen) break;
|
|
1352
1218
|
if (currLen > expLen) {
|
|
1353
|
-
throw SyntaxError(
|
|
1219
|
+
throw SyntaxError('缩进大小不统一');
|
|
1354
1220
|
}
|
|
1355
1221
|
if (this.shorterThanBaseDentEof()) {
|
|
1356
1222
|
return;
|
|
@@ -1375,7 +1241,7 @@ ${Tokenizer.EofId}`;
|
|
|
1375
1241
|
if (yes) {
|
|
1376
1242
|
if (!this.token) {
|
|
1377
1243
|
if (this.useDedentAsEof) {
|
|
1378
|
-
this.setToken(TokenType.Dedent,
|
|
1244
|
+
this.setToken(TokenType.Dedent, '');
|
|
1379
1245
|
} else {
|
|
1380
1246
|
this.setToken(TokenType.Identifier, Tokenizer.EofId);
|
|
1381
1247
|
}
|
|
@@ -1384,7 +1250,7 @@ ${Tokenizer.EofId}`;
|
|
|
1384
1250
|
this.waitingTokens.push({
|
|
1385
1251
|
type: TokenType.Dedent,
|
|
1386
1252
|
typeName: TokenType[TokenType.Dedent],
|
|
1387
|
-
value:
|
|
1253
|
+
value: ''
|
|
1388
1254
|
});
|
|
1389
1255
|
} else {
|
|
1390
1256
|
this.waitingTokens.push({
|
|
@@ -1402,27 +1268,27 @@ ${Tokenizer.EofId}`;
|
|
|
1402
1268
|
let nextC;
|
|
1403
1269
|
while (1) {
|
|
1404
1270
|
nextC = this.code[this.i + 1];
|
|
1405
|
-
if (typeof nextC !==
|
|
1271
|
+
if (typeof nextC !== 'string' || !bobeShared.matchIdStart2(nextC, 0)) {
|
|
1406
1272
|
break;
|
|
1407
1273
|
}
|
|
1408
1274
|
value += nextC;
|
|
1409
1275
|
this.i++;
|
|
1410
1276
|
}
|
|
1411
1277
|
if (value === Tokenizer.EofId && this.useDedentAsEof) {
|
|
1412
|
-
this.setToken(TokenType.Dedent,
|
|
1278
|
+
this.setToken(TokenType.Dedent, '');
|
|
1413
1279
|
return;
|
|
1414
1280
|
}
|
|
1415
|
-
let realValue = value ===
|
|
1281
|
+
let realValue = value === 'null' ? null : value === 'undefined' ? undefined : value === 'false' ? false : value === 'true' ? true : value;
|
|
1416
1282
|
this.setToken(TokenType.Identifier, realValue);
|
|
1417
1283
|
}
|
|
1418
1284
|
str(char) {
|
|
1419
|
-
let value =
|
|
1285
|
+
let value = '';
|
|
1420
1286
|
let nextC;
|
|
1421
1287
|
let continuousBackslashCount = 0;
|
|
1422
1288
|
while (1) {
|
|
1423
1289
|
nextC = this.code[this.i + 1];
|
|
1424
1290
|
const memoCount = continuousBackslashCount;
|
|
1425
|
-
if (nextC ===
|
|
1291
|
+
if (nextC === '\\') {
|
|
1426
1292
|
continuousBackslashCount++;
|
|
1427
1293
|
} else {
|
|
1428
1294
|
continuousBackslashCount = 0;
|
|
@@ -1449,13 +1315,33 @@ ${Tokenizer.EofId}`;
|
|
|
1449
1315
|
this.setToken(TokenType.Identifier, Number(value));
|
|
1450
1316
|
}
|
|
1451
1317
|
eof() {
|
|
1452
|
-
this.setToken(TokenType.Eof,
|
|
1453
|
-
}
|
|
1318
|
+
this.setToken(TokenType.Eof, 'End Of File');
|
|
1319
|
+
}
|
|
1320
|
+
HookId = '_h_o_o_k_';
|
|
1321
|
+
hookI = 0;
|
|
1322
|
+
_hook = props => {
|
|
1323
|
+
const value = this.token.value;
|
|
1324
|
+
const isDynamicHook = this.token.type & TokenType.InsertionExp;
|
|
1325
|
+
const isStaticHook = typeof value === 'string' && value.indexOf(this.HookId) === 0;
|
|
1326
|
+
const hookType = isDynamicHook ? 'dynamic' : isStaticHook ? 'static' : undefined;
|
|
1327
|
+
if (this.hook && isStaticHook) {
|
|
1328
|
+
const hookI = Number(value.slice(this.HookId.length));
|
|
1329
|
+
const res = this.hook({
|
|
1330
|
+
...props,
|
|
1331
|
+
HookId: this.HookId,
|
|
1332
|
+
i: hookI
|
|
1333
|
+
});
|
|
1334
|
+
return [hookType, res, hookI];
|
|
1335
|
+
} else if (isDynamicHook) {
|
|
1336
|
+
return [hookType, value];
|
|
1337
|
+
}
|
|
1338
|
+
return [hookType, value];
|
|
1339
|
+
};
|
|
1454
1340
|
init(fragments) {
|
|
1455
|
-
if (typeof fragments ===
|
|
1341
|
+
if (typeof fragments === 'string') {
|
|
1456
1342
|
this.setCode(fragments);
|
|
1457
1343
|
} else {
|
|
1458
|
-
let code =
|
|
1344
|
+
let code = '';
|
|
1459
1345
|
for (let i = 0; i < fragments.length - 1; i++) {
|
|
1460
1346
|
const fragment = fragments[i];
|
|
1461
1347
|
code += fragment + `${this.HookId}${i}`;
|
|
@@ -1466,7 +1352,7 @@ ${Tokenizer.EofId}`;
|
|
|
1466
1352
|
}
|
|
1467
1353
|
|
|
1468
1354
|
function bobe(fragments, ...values) {
|
|
1469
|
-
const ui = function
|
|
1355
|
+
const ui = function ui(isSub) {
|
|
1470
1356
|
const tokenizer = new Tokenizer(({
|
|
1471
1357
|
i
|
|
1472
1358
|
}) => {
|
|
@@ -1481,7 +1367,7 @@ ${Tokenizer.EofId}`;
|
|
|
1481
1367
|
function customRender(option) {
|
|
1482
1368
|
return function render(Ctor, root) {
|
|
1483
1369
|
const store = Ctor.new();
|
|
1484
|
-
const tokenizer = store[
|
|
1370
|
+
const tokenizer = store['ui'](false);
|
|
1485
1371
|
const terp = new Interpreter(tokenizer);
|
|
1486
1372
|
terp.config(option);
|
|
1487
1373
|
const componentNode = {
|