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