bobe 0.0.19 → 0.0.21

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 CHANGED
@@ -12,6 +12,7 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
12
12
  TokenType2[TokenType2["Pipe"] = 32] = "Pipe";
13
13
  TokenType2[TokenType2["Eof"] = 64] = "Eof";
14
14
  TokenType2[TokenType2["InsertionExp"] = 128] = "InsertionExp";
15
+ TokenType2[TokenType2["Semicolon"] = 256] = "Semicolon";
15
16
  return TokenType2;
16
17
  })(TokenType || {});
17
18
  var FakeType = /* @__PURE__ */ ((FakeType2) => {
@@ -35,7 +36,6 @@ var NodeSort = /* @__PURE__ */ ((NodeSort2) => {
35
36
  NodeSort2[NodeSort2["TokenizerSwitcher"] = 16] = "TokenizerSwitcher";
36
37
  return NodeSort2;
37
38
  })(NodeSort || {});
38
- const IsAnchor = /* @__PURE__ */ Symbol("is-anchor");
39
39
 
40
40
  class MultiTypeStack {
41
41
  constructor() {
@@ -130,17 +130,33 @@ class MultiTypeStack {
130
130
  // }
131
131
  }
132
132
 
133
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
134
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
135
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
136
+ var __objRest = (source, exclude) => {
137
+ var target = {};
138
+ for (var prop in source)
139
+ if (__hasOwnProp$1.call(source, prop) && exclude.indexOf(prop) < 0)
140
+ target[prop] = source[prop];
141
+ if (source != null && __getOwnPropSymbols$1)
142
+ for (var prop of __getOwnPropSymbols$1(source)) {
143
+ if (exclude.indexOf(prop) < 0 && __propIsEnum$1.call(source, prop))
144
+ target[prop] = source[prop];
145
+ }
146
+ return target;
147
+ };
133
148
  new bobeShared.BaseEvent();
134
149
  class Interpreter {
135
150
  constructor(tokenizer) {
136
151
  this.tokenizer = tokenizer;
137
152
  this.rootComponent = null;
153
+ this.forItemId = 0;
138
154
  this.oneRealPropParsed = this.onePropParsed.bind(this);
139
155
  }
140
156
  isLogicNode(node) {
141
157
  return node && node.__logicType & LogicalBit;
142
158
  }
143
- program(root, componentNode, before) {
159
+ program(root, componentNode, before, ctxProvider) {
144
160
  var _a, _b;
145
161
  this.rootComponent = componentNode;
146
162
  this.tokenizer.nextToken();
@@ -150,6 +166,12 @@ class Interpreter {
150
166
  { node: componentNode, prev: null },
151
167
  NodeSort.Component | NodeSort.CtxProvider | NodeSort.TokenizerSwitcher
152
168
  );
169
+ if (ctxProvider) {
170
+ stack.push(
171
+ { node: ctxProvider, prev: null },
172
+ (ctxProvider.__logicType & LogicalBit ? NodeSort.Logic : 0) | NodeSort.CtxProvider
173
+ );
174
+ }
153
175
  const ctx = this.ctx = {
154
176
  realParent: root,
155
177
  prevSibling: before,
@@ -213,6 +235,21 @@ class Interpreter {
213
235
  const switcher = (_b = stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _b.node;
214
236
  this.tokenizer = switcher.tokenizer;
215
237
  }
238
+ if (parent.__logicType === FakeType.ForItem) {
239
+ const { forNode } = parent;
240
+ const { i, arr, snapshot } = forNode;
241
+ if (i + 1 < arr.length) {
242
+ this.tokenizer.resume(snapshot);
243
+ this.tokenizer.nextToken();
244
+ this.tokenizer.nextToken();
245
+ ctx.prevSibling = parent;
246
+ ctx.current = forNode.children[++forNode.i];
247
+ continue;
248
+ }
249
+ ctx.prevSibling = forNode.prevSibling;
250
+ ctx.current = forNode;
251
+ continue;
252
+ }
216
253
  }
217
254
  ctx.prevSibling = prev;
218
255
  ctx.current = parent;
@@ -223,15 +260,10 @@ class Interpreter {
223
260
  }
224
261
  return componentNode;
225
262
  }
226
- switcherIsRootComponent() {
227
- var _a;
228
- const currentSwitcher = (_a = this.ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
229
- return currentSwitcher === this.rootComponent;
230
- }
231
- insertAfterAnchor(ctx) {
232
- const { realParent, prevSibling, stack, before } = ctx;
233
- const afterAnchor = this.createAnchor();
234
- ctx.prevSibling = stack.length === 2 && !prevSibling ? before : prevSibling;
263
+ insertAfterAnchor(name = "anchor") {
264
+ const { realParent, prevSibling, stack, before } = this.ctx;
265
+ const afterAnchor = this.createAnchor(name);
266
+ this.ctx.prevSibling = stack.length === 2 && !prevSibling ? before : prevSibling;
235
267
  this.handleInsert(realParent, afterAnchor, prevSibling);
236
268
  return afterAnchor;
237
269
  }
@@ -253,7 +285,7 @@ class Interpreter {
253
285
  const childCmp = child;
254
286
  childCmp.realParent = parent;
255
287
  if (prev == null ? void 0 : prev.__logicType) {
256
- childCmp.realBefore = prev.realAfter;
288
+ childCmp.realBefore = prev.forNode ? prev.forNode.realAfter : prev.realAfter;
257
289
  } else {
258
290
  childCmp.realBefore = prev;
259
291
  }
@@ -282,7 +314,10 @@ class Interpreter {
282
314
  let _node;
283
315
  if (value === "if" || value === "else" || value === "fail") {
284
316
  return this.condDeclaration(ctx);
317
+ } else if (value === "for") {
318
+ return this.forDeclaration();
285
319
  } else if (hookType) {
320
+ const data = this.getData();
286
321
  if (hookType === "static") {
287
322
  if (typeof value === "function") {
288
323
  _node = this.componentOrFragmentDeclaration(value, ctx);
@@ -290,7 +325,15 @@ class Interpreter {
290
325
  throw new SyntaxError(`declaration \u4E0D\u652F\u6301 ${value} \u7C7B\u578B\u7684\u9759\u6001\u63D2\u503C`);
291
326
  }
292
327
  } else {
293
- _node = this.componentOrFragmentDeclaration(value, ctx);
328
+ const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
329
+ const val = data[aoye.Keys.Raw][value];
330
+ if (typeof val === "function") {
331
+ _node = this.componentOrFragmentDeclaration(val, ctx);
332
+ } else {
333
+ const str = valueIsMapKey ? value : this.getFn(data, value);
334
+ _node = this.createNode("text");
335
+ this.onePropParsed(data, _node, "text", str, valueIsMapKey, false);
336
+ }
294
337
  }
295
338
  } else {
296
339
  _node = this.createNode(value);
@@ -304,6 +347,183 @@ class Interpreter {
304
347
  }
305
348
  return _node;
306
349
  }
350
+ forDeclaration() {
351
+ var _a;
352
+ const arrExp = this.tokenizer.nextToken().value;
353
+ this.tokenizer.nextToken();
354
+ const itemToken = this.tokenizer.nextToken();
355
+ const isDestruct = itemToken.type === TokenType.InsertionExp;
356
+ let itemExp = itemToken.value;
357
+ if (isDestruct) {
358
+ itemExp = "{" + itemExp + "}";
359
+ const vars = itemExp.match(bobeShared.jsVarRegexp).join(",");
360
+ itemExp = new Function("item", `let ${vars}; (${itemExp}=item); return {${vars}};`);
361
+ }
362
+ let indexName, keyExp;
363
+ while (this.tokenizer.code[this.tokenizer.i] !== "\n") {
364
+ const next = this.tokenizer.nextToken();
365
+ if (next.type !== TokenType.Semicolon) {
366
+ if (!indexName) {
367
+ indexName = next.value;
368
+ } else {
369
+ keyExp = next.value;
370
+ }
371
+ }
372
+ }
373
+ const owner = (_a = this.ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
374
+ const prevSibling = this.ctx.prevSibling;
375
+ const forNode = {
376
+ __logicType: FakeType.For,
377
+ snapshot: this.tokenizer.snapshot(["dentStack", "isFirstToken"]),
378
+ realParent: this.ctx.realParent,
379
+ prevSibling,
380
+ realBefore: (prevSibling == null ? void 0 : prevSibling.realAfter) || prevSibling,
381
+ realAfter: null,
382
+ arr: null,
383
+ itemExp,
384
+ indexName,
385
+ getKey: null,
386
+ children: [],
387
+ effect: null,
388
+ owner,
389
+ i: 0
390
+ };
391
+ if (keyExp) {
392
+ forNode.getKey = new Function("data", `let v;with(data){v=${keyExp}};return v;`);
393
+ }
394
+ window["for1"] = forNode;
395
+ const data = this.getData();
396
+ const cells = data[aoye.Keys.Meta].cells;
397
+ const hasArrExpKey = Reflect.has(data[aoye.Keys.Raw], arrExp);
398
+ const arrSignal = hasArrExpKey ? (
399
+ // 有 key 直接拿
400
+ (data[arrExp], cells.get(arrExp))
401
+ ) : (
402
+ // 无key
403
+ aoye.$(this.getFn(data, arrExp))
404
+ );
405
+ forNode.realAfter = this.insertAfterAnchor("for-after");
406
+ const _b = forNode.snapshot, { dentStack, isFirstToken } = _b, snapshotForUpdate = __objRest(_b, ["dentStack", "isFirstToken"]);
407
+ let isFirstRender = true;
408
+ forNode.effect = aoye.effect(() => {
409
+ var _a2;
410
+ let arr = forNode.arr = arrSignal.v;
411
+ arr[aoye.Keys.Iterator];
412
+ arr = aoye.toRaw(arr);
413
+ const children = forNode.children;
414
+ if (isFirstRender) {
415
+ const len = arr.length;
416
+ for (let i = len; i--; ) {
417
+ const nextItem = children[i + 1];
418
+ const item = this.createForItem(forNode, i, data);
419
+ const anchor = this.insertAfterAnchor("for-item-after");
420
+ item.realAfter = anchor;
421
+ if (nextItem) {
422
+ nextItem.realBefore = anchor;
423
+ }
424
+ item.realParent = forNode.realParent;
425
+ children[i] = item;
426
+ }
427
+ const firstInsert = children[0];
428
+ if (firstInsert) {
429
+ firstInsert.realBefore = forNode.realBefore;
430
+ this.tokenizer.nextToken();
431
+ this.tokenizer.nextToken();
432
+ } else {
433
+ this.tokenizer.skip();
434
+ }
435
+ } else {
436
+ const oldLen = children.length;
437
+ const newLen = arr.length;
438
+ const minLen = Math.min(oldLen, newLen);
439
+ const newChildren = [];
440
+ if (!forNode.getKey) {
441
+ if (newLen < oldLen) {
442
+ for (let i = oldLen - 1; i >= newLen; i--) {
443
+ const child = children[i];
444
+ this.removeLogicNode(child);
445
+ this.remove(child.realAfter);
446
+ child.effect();
447
+ }
448
+ }
449
+ if (oldLen < newLen) {
450
+ const lastAfter = ((_a2 = children.at(-1)) == null ? void 0 : _a2.realAfter) || forNode.realBefore;
451
+ for (let i = newLen - 1; i >= oldLen; i--) {
452
+ const item = this.createForItem(forNode, i, data);
453
+ newChildren[i] = item;
454
+ const nextItem = newChildren[i + 1];
455
+ const anchor = this.createAnchor("for-item-after");
456
+ this.insertAfter(forNode.realParent, anchor, lastAfter);
457
+ item.realAfter = anchor;
458
+ if (nextItem) {
459
+ nextItem.realBefore = anchor;
460
+ }
461
+ item.realParent = forNode.realParent;
462
+ this.tokenizer = owner.tokenizer;
463
+ this.tokenizer.resume(snapshotForUpdate);
464
+ this.tokenizer.useDedentAsEof = false;
465
+ aoye.runWithPulling(() => {
466
+ this.program(forNode.realParent, forNode.owner, lastAfter, item);
467
+ }, item.effect.ins);
468
+ }
469
+ const firstInsert = newChildren[oldLen];
470
+ if (firstInsert) {
471
+ firstInsert.realBefore = lastAfter;
472
+ }
473
+ }
474
+ for (let i = minLen; i--; ) {
475
+ const child = children[i];
476
+ newChildren[i] = child;
477
+ if (typeof itemExp === "string") {
478
+ child.data[itemExp] = arr[i];
479
+ } else {
480
+ Object.assign(child.data, itemExp(arr[i]));
481
+ }
482
+ }
483
+ forNode.children = newChildren;
484
+ }
485
+ }
486
+ isFirstRender = false;
487
+ });
488
+ return forNode.children[0] || forNode;
489
+ }
490
+ createForItem(forNode, i, parentData) {
491
+ let forItemNode;
492
+ const effect2 = aoye.scope(() => {
493
+ }, null);
494
+ const { arr, itemExp, indexName, getKey } = forNode;
495
+ let data;
496
+ if (typeof itemExp === "string") {
497
+ data = aoye.$(
498
+ indexName ? {
499
+ [itemExp]: arr[i],
500
+ [indexName]: i
501
+ } : {
502
+ [itemExp]: arr[i]
503
+ }
504
+ );
505
+ } else {
506
+ const rawData = itemExp(arr[i]);
507
+ if (indexName) {
508
+ rawData[indexName] = i;
509
+ }
510
+ data = aoye.$(rawData);
511
+ }
512
+ Object.setPrototypeOf(data, parentData);
513
+ forItemNode = {
514
+ id: this.forItemId++,
515
+ __logicType: FakeType.ForItem,
516
+ realParent: null,
517
+ realBefore: null,
518
+ realAfter: null,
519
+ forNode,
520
+ key: getKey == null ? void 0 : getKey(data),
521
+ effect: null,
522
+ data
523
+ };
524
+ forItemNode.effect = effect2;
525
+ return forItemNode;
526
+ }
307
527
  getData() {
308
528
  const { node } = this.ctx.stack.peekByType(NodeSort.CtxProvider);
309
529
  return node.data || node.owner.data;
@@ -335,10 +555,6 @@ class Interpreter {
335
555
  }
336
556
  componentOrFragmentDeclaration(ComponentOrRender, ctx) {
337
557
  let Component, render, child;
338
- const data = this.getData();
339
- if (typeof ComponentOrRender === "string") {
340
- ComponentOrRender = data[ComponentOrRender];
341
- }
342
558
  const isCC = ComponentOrRender.prototype instanceof aoye.Store;
343
559
  if (isCC) {
344
560
  Component = ComponentOrRender;
@@ -352,89 +568,76 @@ class Interpreter {
352
568
  const node = {
353
569
  __logicType: isCC ? FakeType.Component : FakeType.Fragment,
354
570
  realParent: ctx.realParent,
571
+ realBefore: null,
572
+ realAfter: null,
355
573
  data: child,
356
574
  tokenizer: render ? render(true) : child["ui"](true)
357
575
  };
358
- this.onePropParsed = (data2, _, key, value, valueIsMapKey, isFn, hookI) => {
576
+ this.onePropParsed = (data, _, key, value, valueIsMapKey, isFn, hookI) => {
359
577
  if (isFn) {
360
578
  child[aoye.Keys.Raw][key] = value;
361
579
  } else if (valueIsMapKey) {
362
- aoye.shareSignal(data2, value, child, key);
363
- } else if (typeof value === "function") {
580
+ aoye.shareSignal(data, value, child, key);
581
+ } else {
364
582
  const meta = child[aoye.Keys.Meta];
365
583
  const cells = meta.cells;
366
- const computed = aoye.$(value);
367
- cells.set(key, computed);
368
- child[aoye.Keys.Raw][key] = void 0;
369
- } else {
370
- child[aoye.Keys.Raw][key] = value;
584
+ if (typeof value === "function") {
585
+ const computed = aoye.$(value);
586
+ cells.set(key, computed);
587
+ child[aoye.Keys.Raw][key] = void 0;
588
+ } else {
589
+ cells.set(key, { v: value });
590
+ child[aoye.Keys.Raw][key] = value;
591
+ }
371
592
  }
372
593
  };
373
- node.realAfter = this.insertAfterAnchor(ctx);
594
+ node.realAfter = this.insertAfterAnchor("component-after");
374
595
  return node;
375
596
  }
597
+ getFn(data, expression) {
598
+ return new Function("data", `let v;with(data){v=${expression}};return v;`).bind(void 0, data);
599
+ }
376
600
  // TODO: 优化代码逻辑,拆分 if elseif else
377
601
  condDeclaration(ctx) {
378
602
  var _a;
379
603
  const { prevSibling } = ctx;
380
- const snapbackUp = this.tokenizer.snapshot();
381
604
  const keyWord = this.tokenizer.token;
382
- this.tokenizer.nextToken();
383
- const noSelfCond = this.tokenizer.token.type === TokenType.NewLine;
384
- const [hookType, value] = this.tokenizer._hook({});
605
+ const expToken = this.tokenizer.condExp();
606
+ const value = expToken.value;
385
607
  const isElse = keyWord.value === "else";
386
608
  const isIf = keyWord.value === "if";
387
609
  const preIsCond = (prevSibling == null ? void 0 : prevSibling.__logicType) & CondBit;
388
- const needCalcWithPrevIf = isElse && preIsCond;
389
610
  const data = this.getData();
611
+ const noCond = value === true;
612
+ const valueIsMapKey = !noCond && Reflect.has(data[aoye.Keys.Raw], value);
390
613
  const owner = (_a = ctx.stack.peekByType(NodeSort.TokenizerSwitcher)) == null ? void 0 : _a.node;
391
614
  const ifNode = {
392
615
  __logicType: isElse ? FakeType.Else : isIf ? FakeType.If : FakeType.Fail,
393
- snapshot: noSelfCond ? snapbackUp : this.tokenizer.snapshot(),
394
- condition: null,
616
+ // 此时 token exp, 下次解析 从 \n 开始
617
+ snapshot: this.tokenizer.snapshot(),
395
618
  realParent: null,
619
+ realBefore: null,
620
+ realAfter: null,
621
+ condition: null,
396
622
  preCond: preIsCond ? prevSibling : null,
397
623
  isFirstRender: true,
398
624
  effect: null,
399
625
  owner
400
626
  };
401
627
  let signal;
402
- if (noSelfCond) {
403
- if (isElse) {
404
- signal = aoye.$(() => {
405
- let point = ifNode.preCond;
406
- while (point) {
407
- if (point.condition.v) {
408
- return false;
409
- }
410
- if (point.__logicType === FakeType.If) {
411
- break;
412
- }
413
- point = point.preCond;
414
- }
415
- return true;
416
- });
417
- } else {
418
- signal = aoye.$(() => {
419
- let point = ifNode.preCond;
420
- while (point) {
421
- if (point.condition.v) {
422
- return false;
423
- }
424
- point = point.preCond;
425
- }
426
- return true;
427
- });
428
- }
429
- } else {
430
- const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
431
- if (valueIsMapKey && !needCalcWithPrevIf) {
432
- aoye.runWithPulling(() => data[value], null);
433
- const { cells } = data[aoye.Keys.Meta];
434
- signal = cells.get(value);
435
- } else {
436
- const fn = new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, data);
437
- if (needCalcWithPrevIf) {
628
+ switch (keyWord.value) {
629
+ case "if":
630
+ if (valueIsMapKey) {
631
+ aoye.runWithPulling(() => data[value], null);
632
+ const { cells } = data[aoye.Keys.Meta];
633
+ signal = cells.get(value);
634
+ } else {
635
+ const fn = this.getFn(data, value);
636
+ signal = aoye.$(fn);
637
+ }
638
+ break;
639
+ case "else":
640
+ if (noCond) {
438
641
  signal = aoye.$(() => {
439
642
  let point = ifNode.preCond;
440
643
  while (point) {
@@ -446,43 +649,57 @@ class Interpreter {
446
649
  }
447
650
  point = point.preCond;
448
651
  }
449
- return fn();
652
+ return true;
450
653
  });
451
654
  } else {
452
- signal = aoye.$(fn);
655
+ const fn = valueIsMapKey ? null : this.getFn(data, value);
656
+ signal = aoye.$(() => {
657
+ let point = ifNode.preCond;
658
+ while (point) {
659
+ if (point.condition.v) {
660
+ return false;
661
+ }
662
+ if (point.__logicType === FakeType.If) {
663
+ break;
664
+ }
665
+ point = point.preCond;
666
+ }
667
+ return valueIsMapKey ? data[value] : fn();
668
+ });
453
669
  }
454
- }
670
+ break;
671
+ case "fail":
672
+ signal = aoye.$(() => {
673
+ let point = ifNode.preCond;
674
+ while (point) {
675
+ if (point.condition.v) {
676
+ return false;
677
+ }
678
+ point = point.preCond;
679
+ }
680
+ return true;
681
+ });
682
+ break;
455
683
  }
456
684
  ifNode.condition = signal;
457
- ifNode.realAfter = this.insertAfterAnchor(ctx);
685
+ ifNode.realAfter = this.insertAfterAnchor(`${keyWord.value}-after`);
458
686
  ifNode.effect = aoye.effect(
459
687
  ({ val }) => {
460
688
  if (val) {
461
689
  if (ifNode.isFirstRender) {
462
- if (!noSelfCond) {
463
- this.tokenizer.nextToken();
464
- }
690
+ this.tokenizer.nextToken();
465
691
  this.tokenizer.nextToken();
466
692
  } else {
467
693
  this.tokenizer = ifNode.owner.tokenizer;
468
694
  this.tokenizer.resume(ifNode.snapshot);
469
- this.program(ifNode.realParent, ifNode.owner, ifNode.realBefore);
695
+ this.tokenizer.useDedentAsEof = false;
696
+ this.program(ifNode.realParent, ifNode.owner, ifNode.realBefore, ifNode);
470
697
  }
471
698
  } else {
472
699
  if (ifNode.isFirstRender) {
473
- if (noSelfCond) {
474
- this.tokenizer.i = this.tokenizer.i - 1;
475
- this.tokenizer.needIndent = false;
476
- }
477
700
  this.tokenizer.skip();
478
701
  } else {
479
- const { realBefore, realAfter, realParent } = ifNode;
480
- let point = realBefore ? this.nextSib(realBefore) : this.firstChild(realParent);
481
- while (point !== realAfter) {
482
- const next = this.nextSib(point);
483
- this.remove(point, realParent, realBefore);
484
- point = next;
485
- }
702
+ this.removeLogicNode(ifNode);
486
703
  }
487
704
  }
488
705
  ifNode.isFirstRender = false;
@@ -491,6 +708,15 @@ class Interpreter {
491
708
  );
492
709
  return ifNode;
493
710
  }
711
+ removeLogicNode(node) {
712
+ const { realBefore, realAfter, realParent } = node;
713
+ let point = realBefore ? this.nextSib(realBefore) : this.firstChild(realParent);
714
+ while (point !== realAfter) {
715
+ const next = this.nextSib(point);
716
+ this.remove(point, realParent, realBefore);
717
+ point = next;
718
+ }
719
+ }
494
720
  /**
495
721
  * <extensionLines> ::= PIPE <attributeList> NEWLINE <extensionLines>
496
722
  * | ε
@@ -541,7 +767,7 @@ class Interpreter {
541
767
  const isFn = typeof rawVal === "function";
542
768
  if (hookType === "dynamic") {
543
769
  const valueIsMapKey = Reflect.has(data[aoye.Keys.Raw], value);
544
- const fn = isFn ? rawVal : valueIsMapKey ? value : new Function("data", `let v;with(data){v=${value}};return v;`).bind(void 0, data);
770
+ const fn = isFn ? rawVal : valueIsMapKey ? value : this.getFn(data, value);
545
771
  this.onePropParsed(data, _node, key, fn, valueIsMapKey, isFn, hookI);
546
772
  } else if (hookType === "static") {
547
773
  this.onePropParsed(data, _node, key, value, false, isFn, hookI);
@@ -571,14 +797,9 @@ class Interpreter {
571
797
  firstChild(node) {
572
798
  return node.firstChild;
573
799
  }
574
- _createAnchor() {
575
- const anchor = this.createAnchor();
576
- anchor[IsAnchor] = true;
577
- return anchor;
578
- }
579
- createAnchor() {
800
+ createAnchor(name) {
580
801
  return {
581
- name: "anchor",
802
+ name,
582
803
  nextSibling: null
583
804
  };
584
805
  }
@@ -634,9 +855,9 @@ var __spreadValues = (a, b) => {
634
855
  };
635
856
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
636
857
  const _Tokenizer = class _Tokenizer {
637
- constructor(hook, isSubToken) {
858
+ constructor(hook, useDedentAsEof) {
638
859
  this.hook = hook;
639
- this.isSubToken = isSubToken;
860
+ this.useDedentAsEof = useDedentAsEof;
640
861
  /** 缩进大小 默认 2 */
641
862
  this.TabSize = 2;
642
863
  /** 缩进字符 */
@@ -681,7 +902,7 @@ const _Tokenizer = class _Tokenizer {
681
902
  }
682
903
  return [hookType, value];
683
904
  };
684
- if (isSubToken) {
905
+ if (useDedentAsEof) {
685
906
  this.setToken(TokenType.Indent, "");
686
907
  this.isFirstToken = true;
687
908
  }
@@ -699,11 +920,20 @@ const _Tokenizer = class _Tokenizer {
699
920
  this.dentStack = [0];
700
921
  Object.assign(this, _snapshot);
701
922
  }
702
- snapshot() {
703
- return {
923
+ snapshot(keys) {
924
+ const snap = {
704
925
  i: this.i,
705
926
  waitingTokens: this.waitingTokens.clone()
706
927
  };
928
+ if (keys) {
929
+ for (const k of keys) {
930
+ snap[k] = this[k];
931
+ if (k === "dentStack") {
932
+ snap[k] = this[k].slice();
933
+ }
934
+ }
935
+ }
936
+ return snap;
707
937
  }
708
938
  skip() {
709
939
  const logicDentLen = this.dentStack[this.dentStack.length - 1];
@@ -817,17 +1047,21 @@ ${_Tokenizer.EofId}`;
817
1047
  this.str(char);
818
1048
  break;
819
1049
  case "{":
820
- this.brace();
1050
+ const braceToken = this.brace();
1051
+ this.setToken(TokenType.InsertionExp, braceToken);
821
1052
  break;
822
1053
  case "$":
823
1054
  const handled = this.dynamic(char);
824
1055
  if (handled) break;
1056
+ case ";":
1057
+ this.setToken(TokenType.Semicolon, ";");
1058
+ break;
825
1059
  default:
826
1060
  if (bobeShared.isNum(char)) {
827
1061
  this.number(char);
828
1062
  break;
829
1063
  }
830
- if (typeof char === "string" && bobeShared.matchIdStart(char)) {
1064
+ if (typeof char === "string" && bobeShared.matchIdStart2(char, 0)) {
831
1065
  this.identifier(char);
832
1066
  }
833
1067
  break;
@@ -846,6 +1080,58 @@ ${_Tokenizer.EofId}`;
846
1080
  this.handledTokens.push(this.token);
847
1081
  }
848
1082
  }
1083
+ condExp() {
1084
+ let value = "";
1085
+ this.token = null;
1086
+ while (1) {
1087
+ const char = this.code[this.i];
1088
+ if (char === "\n") {
1089
+ break;
1090
+ }
1091
+ value += char;
1092
+ this.i++;
1093
+ }
1094
+ value = value.trim();
1095
+ this.setToken(TokenType.Identifier, value || true);
1096
+ return this.token;
1097
+ }
1098
+ /**
1099
+ * 解析到 for 时使用这个方法获取 for 后方的子表达式
1100
+ * 表达式通过 “;” 分割
1101
+ * // 最多可有三个表达式
1102
+ * for arr ; item index; item.key
1103
+ * @returns {boolean} 是否含有 key
1104
+ */
1105
+ forLoopSubExp() {
1106
+ this.token = null;
1107
+ let value = "";
1108
+ let count = 0;
1109
+ while (1) {
1110
+ const char = this.code[this.i];
1111
+ const isSemicolon = char === ";";
1112
+ if (isSemicolon || char === "\n") {
1113
+ value = value.trim();
1114
+ if (!this.token) {
1115
+ this.setToken(TokenType.Identifier, value);
1116
+ } else {
1117
+ this.waitingTokens.push({
1118
+ type: TokenType.Identifier,
1119
+ typeName: TokenType[TokenType.Identifier],
1120
+ value
1121
+ });
1122
+ }
1123
+ value = "";
1124
+ count++;
1125
+ if (count > 3) {
1126
+ throw SyntaxError(`for \u5FAA\u73AF\u6700\u591A\u53EF\u5305\u542B\u4E09\u4E2A\u8868\u8FBE\u5F0F, \u5206\u522B\u4E3A arr ; item index [; key]`);
1127
+ }
1128
+ if (!isSemicolon) return count === 3;
1129
+ } else {
1130
+ value += char;
1131
+ }
1132
+ this.i++;
1133
+ }
1134
+ }
849
1135
  assignment() {
850
1136
  this.setToken(TokenType.Assign, "=");
851
1137
  }
@@ -911,8 +1197,7 @@ ${_Tokenizer.EofId}`;
911
1197
  }
912
1198
  }
913
1199
  if (count === 0 && inString == null && inComment == null) {
914
- this.setToken(TokenType.InsertionExp, value.slice(1));
915
- return;
1200
+ return value.slice(1);
916
1201
  }
917
1202
  value += this.code[this.i];
918
1203
  this.i++;
@@ -1017,13 +1302,13 @@ ${_Tokenizer.EofId}`;
1017
1302
  const yes = this.dentStack.length === 1;
1018
1303
  if (yes) {
1019
1304
  if (!this.token) {
1020
- if (this.isSubToken) {
1305
+ if (this.useDedentAsEof) {
1021
1306
  this.setToken(TokenType.Dedent, "");
1022
1307
  } else {
1023
1308
  this.setToken(TokenType.Identifier, _Tokenizer.EofId);
1024
1309
  }
1025
1310
  } else {
1026
- if (this.isSubToken) {
1311
+ if (this.useDedentAsEof) {
1027
1312
  this.waitingTokens.push({
1028
1313
  type: TokenType.Dedent,
1029
1314
  typeName: TokenType[TokenType.Dedent],
@@ -1045,13 +1330,13 @@ ${_Tokenizer.EofId}`;
1045
1330
  let nextC;
1046
1331
  while (1) {
1047
1332
  nextC = this.code[this.i + 1];
1048
- if (typeof nextC !== "string" || !bobeShared.matchIdStart(nextC)) {
1333
+ if (typeof nextC !== "string" || !bobeShared.matchIdStart2(nextC, 0)) {
1049
1334
  break;
1050
1335
  }
1051
1336
  value += nextC;
1052
1337
  this.i++;
1053
1338
  }
1054
- if (value === _Tokenizer.EofId && this.isSubToken) {
1339
+ if (value === _Tokenizer.EofId && this.useDedentAsEof) {
1055
1340
  this.setToken(TokenType.Dedent, "");
1056
1341
  return;
1057
1342
  }