bobe 0.0.3 → 0.0.6

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
@@ -1,425 +1,66 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
3
+ var TokenType = /* @__PURE__ */ ((TokenType2) => {
4
+ TokenType2[TokenType2["NewLine"] = 1] = "NewLine";
5
+ TokenType2[TokenType2["Indent"] = 2] = "Indent";
6
+ TokenType2[TokenType2["Dedent"] = 4] = "Dedent";
7
+ TokenType2[TokenType2["Identifier"] = 8] = "Identifier";
8
+ TokenType2[TokenType2["Assign"] = 16] = "Assign";
9
+ TokenType2[TokenType2["Pipe"] = 32] = "Pipe";
10
+ TokenType2[TokenType2["Eof"] = 64] = "Eof";
11
+ return TokenType2;
12
+ })(TokenType || {});
13
+ var LogicType = /* @__PURE__ */ ((LogicType2) => {
14
+ LogicType2[LogicType2["If"] = 1] = "If";
15
+ LogicType2[LogicType2["ElseIf"] = 2] = "ElseIf";
16
+ LogicType2[LogicType2["Else"] = 4] = "Else";
17
+ LogicType2[LogicType2["For"] = 8] = "For";
18
+ return LogicType2;
19
+ })(LogicType || {});
4
20
 
5
- class Queue {
6
- constructor() {
7
- this.len = 0;
8
- }
9
- get first() {
10
- var _a;
11
- return (_a = this._first) === null || _a === void 0 ? void 0 : _a.v;
12
- }
13
- get last() {
14
- var _a;
15
- return (_a = this._last) === null || _a === void 0 ? void 0 : _a.v;
16
- }
17
- push(it) {
18
- this.len++;
19
- const {
20
- _last: last
21
- } = this;
22
- const item = {
23
- v: it
24
- };
25
- if (!last) {
26
- this._first = this._last = item;
27
- return;
28
- }
29
- item.prev = this._last;
30
- last.next = item;
31
- this._last = item;
32
- }
33
- shift() {
34
- const {
35
- _first: first
36
- } = this;
37
- if (!first) return undefined;
38
- this.len--;
39
- const {
40
- next
41
- } = first;
42
- first.next = undefined;
43
- if (next) {
44
- next.prev = undefined;
45
- } else {
46
- this._last = undefined;
47
- }
48
- this._first = next;
49
- return first.v;
50
- }
51
- }
52
- function isNum(char) {
53
- return char === '0' || char === '1' || char === '2' || char === '3' || char === '4' || char === '5' || char === '6' || char === '7' || char === '8' || char === '9';
54
- }
55
- // const queue = new Queue([1,2,3,4]);
56
- // queue.shift()
57
- // queue.pop()
58
- // // @ts-ignore
59
- // queue.unshift('a')
60
- // // @ts-ignore
61
- // queue.push('b')
62
- // queue.shift()
63
- // queue.pop()
64
- // queue.shift()
65
- // queue.pop()
66
- // queue.shift()
67
- // queue.pop()
68
- // queue.push(10)
69
- // queue.array();
70
-
71
- exports.TokenType = void 0;
72
- (function (TokenType) {
73
- TokenType[TokenType["NewLine"] = 0] = "NewLine";
74
- TokenType[TokenType["Indent"] = 1] = "Indent";
75
- TokenType[TokenType["Dedent"] = 2] = "Dedent";
76
- TokenType[TokenType["Identifier"] = 3] = "Identifier";
77
- TokenType[TokenType["Assign"] = 4] = "Assign";
78
- TokenType[TokenType["Pipe"] = 5] = "Pipe";
79
- TokenType[TokenType["Eof"] = 6] = "Eof";
80
- })(exports.TokenType || (exports.TokenType = {}));
81
- class Compiler {
82
- get char() {
83
- return this.code[this.i];
84
- }
85
- get prev() {
86
- return this.code[this.i - 1];
87
- }
88
- get after() {
89
- return this.code[this.i + 1];
90
- }
91
- at(i) {
92
- return this.code[i];
93
- }
94
- next() {
95
- const prev = this.code[this.i];
96
- this.i++;
97
- const curr = this.code[this.i];
98
- return [prev, curr];
99
- }
100
- nextToken() {
101
- // 已遍历到文件结尾
102
- if (this.isEof()) {
103
- return this.token;
21
+ var __defProp = Object.defineProperty;
22
+ var __defProps = Object.defineProperties;
23
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
24
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
25
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
26
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
27
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
28
+ var __spreadValues = (a, b) => {
29
+ for (var prop in b || (b = {}))
30
+ if (__hasOwnProp.call(b, prop))
31
+ __defNormalProp(a, prop, b[prop]);
32
+ if (__getOwnPropSymbols)
33
+ for (var prop of __getOwnPropSymbols(b)) {
34
+ if (__propIsEnum.call(b, prop))
35
+ __defNormalProp(a, prop, b[prop]);
104
36
  }
105
- this.token = undefined;
106
- if (this.waitingTokens.len) {
107
- const item = this.waitingTokens.shift();
108
- this.setToken(item.type, item.value);
109
- return this.token;
110
- }
111
- while (1) {
112
- if (this.needIndent) {
113
- this.tokenCreator.dent();
114
- // 遍历到当前标识符非 空白为止
115
- } else {
116
- let {
117
- char
118
- } = this;
119
- switch (char) {
120
- case '\t':
121
- case ' ':
122
- // skip, 缩进通过 \n 匹配来激活 needIndent
123
- break;
124
- // 找后续所有 newLine
125
- case '\n':
126
- this.tokenCreator.newLine();
127
- // 回车后需要判断缩进
128
- this.needIndent = true;
129
- break;
130
- case '=':
131
- this.tokenCreator.assignment();
132
- break;
133
- case '|':
134
- this.tokenCreator.pipe();
135
- break;
136
- case "'":
137
- case '"':
138
- this.tokenCreator.str(char);
139
- break;
140
- case '$':
141
- const handled = this.tokenCreator.dynamic(char);
142
- if (handled) break;
143
- default:
144
- if (isNum(char)) {
145
- this.tokenCreator.number(char);
146
- break;
147
- }
148
- if (this.testId(char)) {
149
- this.tokenCreator.identifier(char);
150
- }
151
- break;
152
- }
153
- // 指向下一个字符
154
- this.next();
155
- }
156
- // 找到 token 即可停止
157
- if (this.token) {
158
- break;
159
- }
160
- }
161
- return this.token;
162
- }
163
- consume() {
164
- const token = this.token;
165
- this.nextToken();
166
- return token;
167
- }
168
- tokenize() {
169
- var _a, _b;
170
- do {
171
- this.nextToken();
172
- console.log('token:', exports.TokenType[(_a = this.token) === null || _a === void 0 ? void 0 : _a.type], JSON.stringify(((_b = this.token) === null || _b === void 0 ? void 0 : _b.value) || ''));
173
- } while (!this.isEof());
174
- }
175
- constructor() {
176
- this.i = 0;
177
- this.tokenIs = (...types) => {
178
- if (types.length === 1) return types[0] === this.token.type;
179
- return types.includes(this.token.type);
180
- };
181
- this.isEof = () => {
182
- // 刚开始时 token 不存在
183
- if (!this.token) return false;
184
- return this.tokenIs(exports.TokenType.Identifier) && this.token.value === this.EofId;
185
- };
186
- this.setToken = (type, value) => {
187
- this.token = {
188
- type,
189
- typeName: exports.TokenType[type],
190
- value
191
- };
192
- this.isFirstToken = false;
193
- };
194
- this.TabSize = 2;
195
- this.Tab = Array.from({
196
- length: this.TabSize
197
- }, () => ' ').join('');
198
- this.IdExp = /[\d\w\/]/;
199
- this.EofId = `__EOF__${Date.now()}`;
200
- this.testId = value => {
201
- if (typeof value !== 'string') return false;
202
- return this.IdExp.test(value);
203
- };
204
- /** 记录历史缩进的长度,相对于行首 */
205
- this.dentStack = [0];
206
- this.needIndent = false;
207
- this.isFirstToken = true;
208
- /**
209
- * 有些标识符能产生多个 token
210
- * 例如 dedent
211
- * parent1
212
- * child
213
- * subChild
214
- * parent2 <- 产生两个 dedent
215
- */
216
- this.waitingTokens = new Queue();
217
- this.tokenCreator = {
218
- assignment: () => {
219
- this.setToken(exports.TokenType.Assign, '=');
220
- },
221
- pipe: () => {
222
- this.setToken(exports.TokenType.Pipe, '|');
223
- },
224
- dynamic: char => {
225
- let nextC = this.after;
226
- // 不是动态插值
227
- if (nextC !== '{') {
228
- return false;
229
- }
230
- this.next();
231
- let value = '${';
232
- let innerBrace = 0;
233
- while (1) {
234
- nextC = this.after;
235
- value += nextC;
236
- // 下一个属于本标识符再前进
237
- this.next();
238
- if (nextC === '{') {
239
- innerBrace++;
240
- }
241
- if (nextC === '}') {
242
- // 内部无左括号,说明完成匹配 TODO: 考虑js注释中的括号可能导致匹配错误
243
- if (!innerBrace) {
244
- break;
245
- }
246
- innerBrace--;
247
- }
248
- }
249
- this.setToken(exports.TokenType.Identifier, value);
250
- return true;
251
- },
252
- newLine: () => {
253
- let value = '\n';
254
- let nextC;
255
- while (1) {
256
- nextC = this.after;
257
- if (nextC !== '\n') {
258
- break;
259
- }
260
- value += nextC;
261
- // 下一个属于本标识符再前进
262
- this.next();
263
- }
264
- // Program 希望第一个 token 一定是 node 节点
265
- if (this.isFirstToken) {
266
- return;
267
- }
268
- this.setToken(exports.TokenType.NewLine, value);
269
- },
270
- dent: () => {
271
- const handleDent = v => {
272
- switch (v) {
273
- case '\t':
274
- return this.Tab;
275
- case ' ':
276
- return ' ';
277
- case '\n':
278
- return '\n';
279
- default:
280
- return '';
281
- }
282
- };
283
- let value = '';
284
- let nextC;
285
- while (1) {
286
- const nextChar = this.char;
287
- nextC = handleDent(nextChar);
288
- // \n 空白 \n 的情况,这行不算
289
- if (nextC === '\n') {
290
- this.needIndent = true;
291
- // 这种情况下需要 next ,即后续从 \n 重新开始匹配
292
- return true;
293
- }
294
- // 比较长度,比上个 indent 长,缩进,比上个 indent 短,dedent
295
- if (!nextC) {
296
- this.needIndent = false;
297
- // 期望 firstToken 是 node,所以这里只要修改第一个节点的基础偏移值即可
298
- if (this.isFirstToken) {
299
- this.dentStack[0] = value.length;
300
- return;
301
- }
302
- let currLen = value.length;
303
- const indentHasLen = currLen > 0;
304
- const prevLen = this.dentStack[this.dentStack.length - 1];
305
- if (currLen > prevLen) {
306
- this.dentStack.push(currLen);
307
- this.setToken(exports.TokenType.Indent, String(currLen));
308
- return indentHasLen;
309
- }
310
- if (currLen < prevLen) {
311
- // 一直找到最小
312
- for (let i = this.dentStack.length - 2; i >= 0; i--) {
313
- const expLen = this.dentStack[i];
314
- const prevExpLen = this.dentStack[i + 1];
315
- // 夹在两者说明缩进大小有问题
316
- if (currLen > expLen && currLen < prevExpLen) {
317
- throw SyntaxError('缩进大小不统一');
318
- }
319
- // current <= expLen 反缩进
320
- this.dentStack.pop();
321
- if (!this.token) {
322
- this.setToken(exports.TokenType.Dedent, String(expLen));
323
- }
324
- // 多余的 dent 缓存在 waitingTokens
325
- else {
326
- this.waitingTokens.push({
327
- type: exports.TokenType.Dedent,
328
- typeName: exports.TokenType[exports.TokenType.Dedent],
329
- value: String(expLen)
330
- });
331
- }
332
- if (currLen === expLen) {
333
- break;
334
- }
335
- }
336
- return indentHasLen;
337
- }
338
- // 同级则无视
339
- return indentHasLen;
340
- }
341
- value += nextC;
342
- this.next();
343
- }
344
- },
345
- identifier: char => {
346
- let value = char;
347
- let nextC;
348
- while (1) {
349
- nextC = this.after;
350
- if (!this.testId(nextC)) {
351
- break;
352
- }
353
- value += nextC;
354
- this.next();
355
- }
356
- let realValue = value === 'null' ? null : value === 'undefined' ? undefined : value === 'false' || value === 'true' ? Boolean(value) : value;
357
- this.setToken(exports.TokenType.Identifier, realValue);
358
- },
359
- str: char => {
360
- let value = '"';
361
- let nextC;
362
- let continuousBackslashCount = 0;
363
- while (1) {
364
- nextC = this.after;
365
- value += nextC;
366
- const memoCount = continuousBackslashCount;
367
- if (nextC === '\\') {
368
- continuousBackslashCount++;
369
- } else {
370
- continuousBackslashCount = 0;
371
- }
372
- this.next();
373
- /**
374
- * 引号前 \ 为双数时,全都是字符 \
375
- * */
376
- if (nextC === char && memoCount % 2 === 0) {
377
- break;
378
- }
379
- }
380
- this.setToken(exports.TokenType.Identifier, JSON.parse(value.slice(0, -1) + '"'));
381
- },
382
- number: char => {
383
- let value = char;
384
- let nextC;
385
- while (1) {
386
- nextC = this.after;
387
- if (!isNum(nextC)) {
388
- break;
389
- }
390
- value += nextC;
391
- this.next();
392
- }
393
- this.setToken(exports.TokenType.Identifier, Number(value));
394
- },
395
- eof: () => {
396
- this.setToken(exports.TokenType.Eof, 'End Of File');
397
- }
398
- };
399
- this.HookId = '_h_o_o_k_';
37
+ return a;
38
+ };
39
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
40
+ class Interpreter {
41
+ constructor(tokenizer) {
42
+ this.tokenizer = tokenizer;
43
+ /** 模板字符串动态节点的占位符 */
44
+ this.HookId = "_h_o_o_k_";
45
+ /** 用于渲染的数据 */
400
46
  this.data = {};
401
- this._hook = props => {
402
- const value = this.token.value;
403
- const isHook = value === this.HookId;
47
+ /** 模板字符串动态节点索引 */
48
+ this.hookI = 0;
49
+ this.stack = [];
50
+ this._hook = (props) => {
51
+ const value = this.tokenizer.token.value;
52
+ const isHook = typeof value === "string" && value.indexOf(this.HookId) === 0;
404
53
  if (this.hook && isHook) {
405
- const res = this.hook({
406
- ...props,
54
+ const hookI = Number(value.slice(this.HookId.length));
55
+ const res = this.hook(__spreadProps(__spreadValues({}, props), {
407
56
  HookId: this.HookId,
408
- i: this.hookI
409
- });
57
+ i: hookI
58
+ }));
410
59
  this.hookI++;
411
60
  return [isHook, res];
412
61
  }
413
62
  return [isHook, value];
414
63
  };
415
- this.hookI = 0;
416
- }
417
- preprocess() {
418
- // 保证开头能通过 换行进行 indent 计算
419
- this.code = '\n' + this.code;
420
- // 保证结尾 dedent 能正常配对
421
- this.code = this.code.trimEnd() + `\n${this.EofId}`;
422
- // console.log(this.code);
423
64
  }
424
65
  /**
425
66
  * 根节点:
@@ -427,9 +68,51 @@ class Compiler {
427
68
  * <program> ::= <nodeList>
428
69
  */
429
70
  program() {
430
- // 初始化第一个 token
431
- this.consume();
432
- return this.nodeList();
71
+ this.tokenizer.consume();
72
+ const _program = this.createRoot();
73
+ this.nodeList(_program);
74
+ return _program;
75
+ }
76
+ experimentalProgram() {
77
+ this.tokenizer.consume();
78
+ let current;
79
+ let prevSibling;
80
+ const rootList = [];
81
+ while (1) {
82
+ if (this.tokenizer.isEof()) {
83
+ rootList.push(current);
84
+ break;
85
+ }
86
+ const token = this.tokenizer.token;
87
+ if (token.type & TokenType.Indent) {
88
+ this.tokenizer.consume();
89
+ this.stack.push({
90
+ prevSibling,
91
+ node: current
92
+ });
93
+ prevSibling = null;
94
+ current = this.declaration();
95
+ } else {
96
+ if (current) {
97
+ if (this.stack.length) {
98
+ const parent = this.stack[this.stack.length - 1].node;
99
+ this.insert(parent, current, prevSibling);
100
+ } else {
101
+ rootList.push(current);
102
+ }
103
+ }
104
+ if (this.tokenizer.token.type & TokenType.Dedent) {
105
+ this.tokenizer.consume();
106
+ const { node: parent, prevSibling: prevParent } = this.stack.pop();
107
+ prevSibling = prevParent;
108
+ current = parent;
109
+ } else {
110
+ prevSibling = current;
111
+ current = this.declaration();
112
+ }
113
+ }
114
+ }
115
+ return rootList;
433
116
  }
434
117
  /**
435
118
  * 节点列表:
@@ -437,24 +120,59 @@ class Compiler {
437
120
  * <nodeList> ::= <node> <nodeList> <EOF|Dedent>
438
121
  * |
439
122
  */
440
- nodeList() {
441
- const {
442
- tokenIs
443
- } = this;
444
- const nodes = [];
123
+ nodeList(parent) {
445
124
  let _node;
125
+ let prevSibling;
126
+ let prevItem;
446
127
  while (1) {
447
- // 对于 Program EOF 表示 list 遍历完成
448
- if (this.isEof()) {
449
- return nodes;
128
+ if (this.tokenizer.isEof()) {
129
+ return;
450
130
  }
451
- // 对于 childList Dedent 表示 childList 遍历完成
452
- if (tokenIs(exports.TokenType.Dedent)) {
453
- this.consume();
454
- return nodes;
131
+ if (this.tokenizer.token.type & TokenType.Dedent) {
132
+ this.tokenizer.consume();
133
+ return;
455
134
  }
456
135
  _node = this.node();
457
- nodes.push(_node);
136
+ const insert = parent.__logicType ? this.defaultInsert : this.insert.bind(this);
137
+ parent.__logicType ? this.defaultRemove : this.remove.bind(this);
138
+ if (!_node.__logicType) {
139
+ const realPrev = this.getPrevRealSibling(prevSibling);
140
+ const currItem = insert(parent, _node, realPrev, prevItem);
141
+ prevItem = currItem;
142
+ prevSibling = _node;
143
+ continue;
144
+ }
145
+ if (prevSibling) {
146
+ _node.anchor = prevSibling;
147
+ } else if (parent.__logicType) {
148
+ _node.anchor = parent;
149
+ } else ;
150
+ this.effect(() => {
151
+ if (_node.child && _node.condition()) {
152
+ let item = _node.child;
153
+ while (item != null) {
154
+ const { value: child } = item;
155
+ const realPrev = this.getPrevRealSibling(prevSibling);
156
+ const currItem = insert(parent, child, realPrev, prevItem);
157
+ item = item.next;
158
+ prevItem = currItem;
159
+ prevSibling = child;
160
+ }
161
+ }
162
+ });
163
+ }
164
+ }
165
+ /** 考虑到同级 逻辑模块 */
166
+ getPrevRealSibling(prevSibling) {
167
+ if (!prevSibling || !prevSibling.__logicType) {
168
+ return prevSibling;
169
+ }
170
+ let point = prevSibling;
171
+ while (point != null) {
172
+ if (point.lastChild) {
173
+ return point.lastChild.value;
174
+ }
175
+ point = point.anchor;
458
176
  }
459
177
  }
460
178
  /**
@@ -464,7 +182,10 @@ class Compiler {
464
182
  * */
465
183
  node() {
466
184
  const _declaration = this.declaration();
467
- _declaration.children = this.childrenBlockOpt();
185
+ if (_declaration.__logicType & LogicType.If && !_declaration.condition()) {
186
+ return _declaration;
187
+ }
188
+ this.childrenBlockOpt(_declaration);
468
189
  return _declaration;
469
190
  }
470
191
  /**
@@ -473,44 +194,60 @@ class Compiler {
473
194
  * <declaration> ::= <tagName=token> <headerLine> <extensionLines>
474
195
  * */
475
196
  declaration() {
476
- this.consume();
477
197
  const [isHook, value] = this._hook({});
478
198
  let _node;
479
199
  if (isHook) {
480
- const {
481
- tree,
482
- data
483
- } = value();
200
+ const { tree, data } = value();
484
201
  _node = tree;
202
+ } else if (value === "if") {
203
+ return this.ifDeclaration();
485
204
  } else {
486
205
  _node = this.createNode(value);
487
206
  }
207
+ this.tokenizer.consume();
488
208
  this.headerLine(_node);
489
209
  this.extensionLines(_node);
490
210
  return _node;
491
211
  }
212
+ ifDeclaration() {
213
+ this.tokenizer.consume();
214
+ const [isHook, value] = this._hook({});
215
+ const ifNode = {
216
+ __logicType: LogicType.If,
217
+ condition: value,
218
+ child: null,
219
+ lastChild: null,
220
+ anchor: null,
221
+ skip: null
222
+ };
223
+ this.effect(() => {
224
+ const needMount = value();
225
+ if (needMount) {
226
+ this.tokenizer.consume();
227
+ this.tokenizer.consume();
228
+ } else {
229
+ ifNode.skip = this.tokenizer.skip();
230
+ console.log("skip");
231
+ console.log(ifNode.skip);
232
+ }
233
+ });
234
+ return ifNode;
235
+ }
492
236
  /**
493
237
  * <extensionLines> ::= PIPE <attributeList> NEWLINE <extensionLines>
494
238
  * | ε
495
239
  */
496
240
  extensionLines(_node) {
497
- const {
498
- tokenIs
499
- } = this;
500
241
  while (1) {
501
- // 终止条件,下一行不是 pipe
502
- if (!tokenIs(exports.TokenType.Pipe)) {
242
+ if (!(this.tokenizer.token.type & TokenType.Pipe)) {
503
243
  return;
504
244
  }
505
- // 开始解析 attributeList
506
- this.consume();
245
+ this.tokenizer.consume();
507
246
  this.attributeList(_node);
508
- // 文件结束了,通常不会发生
509
- if (!tokenIs(exports.TokenType.NewLine)) {
247
+ if (!(this.tokenizer.token.type & TokenType.NewLine)) {
510
248
  return;
511
249
  }
512
- // 换行
513
- this.consume();
250
+ this.tokenizer.consume();
514
251
  }
515
252
  }
516
253
  /**
@@ -520,7 +257,7 @@ class Compiler {
520
257
  */
521
258
  headerLine(_node) {
522
259
  this.attributeList(_node);
523
- this.consume();
260
+ this.tokenizer.consume();
524
261
  }
525
262
  /**
526
263
  * 属性列表:
@@ -529,53 +266,57 @@ class Compiler {
529
266
  * | ε
530
267
  *
531
268
  * <attribute> ::= <key> <=> <value or dataKey> <=> <value>
269
+ *
532
270
  */
533
271
  attributeList(_node) {
534
- let key = '';
535
- let dataKey = '';
536
- let defaultValue = undefined;
537
- let prevIsAssign = false;
538
- // 是标识符 赋值 继续累积 props
539
- while (this.tokenIs(exports.TokenType.Identifier, exports.TokenType.Assign)) {
540
- const [isHook, value] = this._hook({});
541
- if (value === '=') {
542
- prevIsAssign = true;
543
- }
544
- // 前一个不是等号,说明是 key
545
- else if (!prevIsAssign) {
546
- /*----------------- 开始下一个属性前进行赋值操作 -----------------*/
547
- // 只声明 key 时 dataKey === key
548
- if (!dataKey) {
272
+ let values = [];
273
+ let prevToken = void 0;
274
+ while (1) {
275
+ if ((prevToken == null ? void 0 : prevToken.type) === TokenType.Identifier && this.tokenizer.token.type !== TokenType.Assign) {
276
+ const [v1, v2, v3] = values;
277
+ const key = v1;
278
+ let dataKey, defaultVal;
279
+ if (v3 !== void 0) {
280
+ defaultVal = v3;
281
+ dataKey = v2;
282
+ } else if (v2 !== void 0) {
283
+ if (typeof v2 === "string" && v2[0] === "$" && v2[1] !== "{") {
284
+ dataKey = v2.slice(1);
285
+ } else {
286
+ defaultVal = v2;
287
+ }
288
+ } else {
549
289
  dataKey = key;
550
290
  }
551
- // 三者都有
552
- else if (defaultValue != null) ;
553
- // 第二个值是 dataKey 或 defaultValue,看其是否是 $ 开头
554
- else {
555
- const valueOrKey = dataKey;
556
- if (valueOrKey[0] === '$') {
557
- dataKey = dataKey.slice(1);
558
- }
559
- // 值
560
- else {
561
- defaultValue = dataKey;
562
- dataKey = undefined;
563
- }
291
+ let val = defaultVal;
292
+ if (dataKey) {
293
+ val = this.setDataProp(this.data, dataKey, defaultVal);
564
294
  }
565
- this.setDataProp(this.data, dataKey, defaultValue);
566
- this.setProp(_node, key, this.data[dataKey], this.hookI - 1);
567
- key = value;
295
+ this.setProp(_node, key, val, this.hookI - 1);
296
+ const [isHook, value] = this._hook({});
297
+ values = [value];
298
+ } else if (this.tokenizer.token.type !== TokenType.Assign) {
299
+ const [isHook, value] = this._hook({});
300
+ values.push(value);
568
301
  }
569
- // 前一个是等号
570
- else {
571
- if (!dataKey) {
572
- dataKey = value;
573
- } else {
574
- defaultValue = value;
575
- }
302
+ if (!(this.tokenizer.token.type & (TokenType.Identifier | TokenType.Assign))) {
303
+ break;
576
304
  }
577
- this.consume();
305
+ prevToken = this.tokenizer.consume();
306
+ }
307
+ }
308
+ /** 子节点块:
309
+ * 必须被缩进包裹
310
+ * <childrenBlockOpt> ::= INDENT <nodeList>
311
+ * | ε /* 空(表示叶子节点,没有孩子)
312
+ * */
313
+ childrenBlockOpt(parent) {
314
+ if (!(this.tokenizer.token.type & TokenType.Indent)) {
315
+ return [];
578
316
  }
317
+ this.tokenizer.consume();
318
+ const list = this.nodeList(parent);
319
+ return list;
579
320
  }
580
321
  config(opt) {
581
322
  Object.assign(this, opt);
@@ -586,96 +327,80 @@ class Compiler {
586
327
  setDataProp(data, key, value) {
587
328
  return data[key] = value;
588
329
  }
330
+ setChildren(node, children) {
331
+ node.children = children;
332
+ }
589
333
  createNode(name) {
590
334
  return {
591
335
  name,
592
336
  props: {}
593
337
  };
594
338
  }
339
+ createRoot() {
340
+ return this.createNode("root");
341
+ }
342
+ insert(parent, node, prevSibling, prevItem) {
343
+ return this.defaultInsert(parent, node, prevSibling, prevItem);
344
+ }
345
+ defaultInsert(parent, node, prevSibling, prevItem) {
346
+ if (!parent.child) {
347
+ return parent.child = parent.lastChild = {
348
+ value: node,
349
+ next: null
350
+ };
351
+ }
352
+ const nextItem = prevItem.next;
353
+ const item = {
354
+ value: node,
355
+ next: nextItem
356
+ };
357
+ prevItem.next = item;
358
+ if (!nextItem) {
359
+ parent.lastChild = item;
360
+ }
361
+ return item;
362
+ }
363
+ remove(parent, node, prevSibling, prevItem) {
364
+ return this.defaultRemove(parent, node, prevSibling, prevItem);
365
+ }
366
+ // TODO: 默认改成 prevItem
367
+ defaultRemove(parent, node, prevSibling, prevItem) {
368
+ const currItem = prevItem.next;
369
+ const nextItem = currItem.next;
370
+ if (prevItem) {
371
+ if (nextItem) {
372
+ prevItem.next = nextItem;
373
+ } else {
374
+ prevItem.next = null;
375
+ parent.lastChild = prevItem;
376
+ }
377
+ } else {
378
+ if (nextItem) {
379
+ parent.child = nextItem;
380
+ } else {
381
+ parent.child = null;
382
+ parent.lastChild = null;
383
+ }
384
+ }
385
+ currItem.next = null;
386
+ }
595
387
  setProp(node, key, value, hookI) {
596
388
  node.props[key] = value;
597
389
  }
598
390
  init(fragments) {
599
391
  this.data = this.createData(this.data);
600
- if (typeof fragments === 'string') {
601
- this.code = fragments;
392
+ if (typeof fragments === "string") {
393
+ this.tokenizer.setCode(fragments);
602
394
  } else {
603
- this.code = fragments.join(this.HookId);
604
- }
605
- return this.preprocess();
606
- }
607
- /** 子节点块:
608
- * 必须被缩进包裹
609
- * <childrenBlockOpt> ::= INDENT <nodeList>
610
- * | ε /* 空(表示叶子节点,没有孩子)
611
- * */
612
- childrenBlockOpt() {
613
- // 无 children
614
- if (!this.tokenIs(exports.TokenType.Indent)) {
615
- return;
616
- }
617
- this.consume();
618
- const list = this.nodeList();
619
- return list;
620
- }
621
- }
622
- let ast;
623
- const updateList = [];
624
- const cmp = new Compiler();
625
- function bobe(fragments, ...values) {
626
- // 增量更新
627
- if (ast) {
628
- updateList.forEach(({
629
- old,
630
- fn
631
- }, i) => {
632
- const val = values[i];
633
- if (val !== old) {
634
- console.log('增量更新', val);
635
- fn(val);
395
+ let code = "";
396
+ for (let i = 0; i < fragments.length - 1; i++) {
397
+ const fragment = fragments[i];
398
+ code += fragment + `${this.HookId}${i}`;
636
399
  }
637
- });
638
- console.log(JSON.stringify(ast, undefined, 2));
639
- return ast;
640
- }
641
- // 初始化
642
- cmp.config({
643
- hook({
644
- i
645
- }) {
646
- return values[i];
647
- },
648
- setProp(node, key, value, hookI) {
649
- const fn = v => {
650
- node.props[key] = v;
651
- if (hookI != null) {
652
- updateList[hookI] = {
653
- fn,
654
- old: v
655
- };
656
- }
657
- };
658
- fn(value);
400
+ this.tokenizer.setCode(code + fragments[fragments.length - 1]);
659
401
  }
660
- });
661
- cmp.init(Array.from(fragments));
662
- ast = cmp.program();
663
- console.log(JSON.stringify(ast, undefined, 2));
664
- return ast;
402
+ }
665
403
  }
666
- // bobe`
667
- // node1 k1=1
668
- // node1_1 k2=false k3=3
669
- // node1_1_1 k6=null
670
- // node2
671
- // | p1=1
672
- // | p2=2 p3='你好'
673
- // node2_1
674
- // | p4=4 p5=${{ v: '🤡' }} p6=6
675
- // node2_2
676
- // | p7=7 p8=\${{ v: '🤡' }} p9=aaa
677
- // node3 v1=1 v2=2 v3=undefined
678
- // `;
679
404
 
680
- exports.Compiler = Compiler;
681
- exports.bobe = bobe;
405
+ exports.Interpreter = Interpreter;
406
+ //# sourceMappingURL=bobe.cjs.js.map