bobe 0.0.36 → 0.0.38

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.
@@ -13,8 +13,15 @@ let TokenType = function (TokenType) {
13
13
  TokenType[TokenType["InsertionExp"] = 128] = "InsertionExp";
14
14
  TokenType[TokenType["Semicolon"] = 256] = "Semicolon";
15
15
  TokenType[TokenType["StaticInsExp"] = 512] = "StaticInsExp";
16
+ TokenType[TokenType["String"] = 1024] = "String";
17
+ TokenType[TokenType["Number"] = 2048] = "Number";
18
+ TokenType[TokenType["Boolean"] = 4096] = "Boolean";
19
+ TokenType[TokenType["Null"] = 8192] = "Null";
20
+ TokenType[TokenType["Undefined"] = 16384] = "Undefined";
16
21
  return TokenType;
17
22
  }({});
23
+ const BaseTokenType = TokenType.String | TokenType.Number | TokenType.Boolean | TokenType.Null | TokenType.Undefined;
24
+ const ValueTokenType = BaseTokenType | TokenType.InsertionExp | TokenType.StaticInsExp;
18
25
  let FakeType = function (FakeType) {
19
26
  FakeType[FakeType["If"] = 1] = "If";
20
27
  FakeType[FakeType["Fail"] = 2] = "Fail";
@@ -42,6 +49,25 @@ let NodeSort = function (NodeSort) {
42
49
  TerpEvt["HandledComponentNode"] = "handled-component-node";
43
50
  return TerpEvt;
44
51
  })({});
52
+ let ParseErrorCode = function (ParseErrorCode) {
53
+ ParseErrorCode[ParseErrorCode["UNCLOSED_BRACE"] = 9001] = "UNCLOSED_BRACE";
54
+ ParseErrorCode[ParseErrorCode["UNCLOSED_STRING"] = 9002] = "UNCLOSED_STRING";
55
+ ParseErrorCode[ParseErrorCode["UNCLOSED_STATIC_INS"] = 9003] = "UNCLOSED_STATIC_INS";
56
+ ParseErrorCode[ParseErrorCode["INCONSISTENT_INDENT"] = 9004] = "INCONSISTENT_INDENT";
57
+ ParseErrorCode[ParseErrorCode["INDENT_MISMATCH"] = 9005] = "INDENT_MISMATCH";
58
+ ParseErrorCode[ParseErrorCode["MISSING_ASSIGN"] = 9006] = "MISSING_ASSIGN";
59
+ ParseErrorCode[ParseErrorCode["INVALID_TAG_NAME"] = 9007] = "INVALID_TAG_NAME";
60
+ ParseErrorCode[ParseErrorCode["INVALID_PROP_KEY"] = 9008] = "INVALID_PROP_KEY";
61
+ ParseErrorCode[ParseErrorCode["ELSE_WITHOUT_IF"] = 9009] = "ELSE_WITHOUT_IF";
62
+ ParseErrorCode[ParseErrorCode["EMPTY_IF_BODY"] = 9010] = "EMPTY_IF_BODY";
63
+ ParseErrorCode[ParseErrorCode["EMPTY_FOR_BODY"] = 9011] = "EMPTY_FOR_BODY";
64
+ ParseErrorCode[ParseErrorCode["MISSING_FOR_COLLECTION"] = 9012] = "MISSING_FOR_COLLECTION";
65
+ ParseErrorCode[ParseErrorCode["MISSING_FOR_SEMICOLON"] = 9013] = "MISSING_FOR_SEMICOLON";
66
+ ParseErrorCode[ParseErrorCode["MISSING_FOR_ITEM"] = 9014] = "MISSING_FOR_ITEM";
67
+ ParseErrorCode[ParseErrorCode["MISSING_PROP_ASSIGNMENT"] = 9015] = "MISSING_PROP_ASSIGNMENT";
68
+ ParseErrorCode[ParseErrorCode["PIPE_IN_WRONG_CONTEXT"] = 9016] = "PIPE_IN_WRONG_CONTEXT";
69
+ return ParseErrorCode;
70
+ }({});
45
71
  class ParseSyntaxError extends SyntaxError {
46
72
  constructor(code, message, loc) {
47
73
  super(message);
@@ -168,7 +194,7 @@ class Tokenizer {
168
194
  const expLen = this.dentStack[i];
169
195
  if (currLen === expLen) break;
170
196
  if (currLen > expLen) {
171
- throw SyntaxError(`缩进错误,缩进长度不匹配`);
197
+ throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
172
198
  }
173
199
  if (this.shorterThanBaseDentEof()) {
174
200
  break;
@@ -393,7 +419,7 @@ class Tokenizer {
393
419
  while (1) {
394
420
  nextC = this.code[this.i + 1];
395
421
  if (nextC === undefined) {
396
- this.throwUnclosed('UNCLOSED_STATIC_INS', '未闭合的 "${...}"', startOffset, startLine, startCol);
422
+ this.throwUnclosed(ParseErrorCode.UNCLOSED_STATIC_INS, '未闭合的 "${...}"', startOffset, startLine, startCol);
397
423
  }
398
424
  value += nextC;
399
425
  this.next();
@@ -422,7 +448,7 @@ class Tokenizer {
422
448
  while (1) {
423
449
  const char = this.code[this.i];
424
450
  if (char === undefined) {
425
- this.throwUnclosed('UNCLOSED_BRACE', '未闭合的 "{"', startOffset, startLine, startCol);
451
+ this.throwUnclosed(ParseErrorCode.UNCLOSED_BRACE, '未闭合的 "{"', startOffset, startLine, startCol);
426
452
  }
427
453
  const nextChar = this.code[this.i + 1];
428
454
  if (inComment === 'single' && char === '\n') {
@@ -511,6 +537,18 @@ class Tokenizer {
511
537
  isEmptyLine
512
538
  };
513
539
  }
540
+ emptyLoc() {
541
+ const pos = this.getCurrentPos();
542
+ return {
543
+ start: pos,
544
+ end: {
545
+ offset: pos.offset + 1,
546
+ line: pos.line,
547
+ column: pos.column + 1
548
+ },
549
+ source: ' '
550
+ };
551
+ }
514
552
  dent() {
515
553
  const _this$getDentValue2 = this.getDentValue(),
516
554
  value = _this$getDentValue2.value,
@@ -537,7 +575,7 @@ class Tokenizer {
537
575
  const expLen = this.dentStack[i];
538
576
  if (currLen === expLen) break;
539
577
  if (currLen > expLen) {
540
- throw SyntaxError('缩进大小不统一');
578
+ throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
541
579
  }
542
580
  if (this.shorterThanBaseDentEof()) {
543
581
  return;
@@ -602,8 +640,30 @@ class Tokenizer {
602
640
  this.setToken(TokenType.Dedent, '');
603
641
  return;
604
642
  }
605
- let realValue = value === 'null' ? null : value === 'undefined' ? undefined : value === 'false' ? false : value === 'true' ? true : value;
606
- this.setToken(TokenType.Identifier, realValue);
643
+ let realValue, tokenType;
644
+ switch (value) {
645
+ case 'null':
646
+ realValue = null;
647
+ tokenType = TokenType.Null;
648
+ break;
649
+ case 'undefined':
650
+ realValue = undefined;
651
+ tokenType = TokenType.Undefined;
652
+ break;
653
+ case 'false':
654
+ realValue = false;
655
+ tokenType = TokenType.Boolean;
656
+ break;
657
+ case 'true':
658
+ realValue = true;
659
+ tokenType = TokenType.Boolean;
660
+ break;
661
+ default:
662
+ realValue = value;
663
+ tokenType = TokenType.Identifier;
664
+ break;
665
+ }
666
+ this.setToken(tokenType, realValue);
607
667
  }
608
668
  str(char) {
609
669
  const startOffset = this.preI,
@@ -615,7 +675,7 @@ class Tokenizer {
615
675
  while (1) {
616
676
  nextC = this.code[this.i + 1];
617
677
  if (nextC === undefined) {
618
- this.throwUnclosed('UNCLOSED_STRING', '未闭合的字符串字面量', startOffset, startLine, startCol);
678
+ this.throwUnclosed(ParseErrorCode.UNCLOSED_STRING, '未闭合的字符串字面量', startOffset, startLine, startCol);
619
679
  }
620
680
  const memoCount = continuousBackslashCount;
621
681
  if (nextC === '\\') {
@@ -629,7 +689,7 @@ class Tokenizer {
629
689
  }
630
690
  value += nextC;
631
691
  }
632
- this.setToken(TokenType.Identifier, value);
692
+ this.setToken(TokenType.String, value);
633
693
  }
634
694
  number(char) {
635
695
  let value = char;
@@ -642,7 +702,7 @@ class Tokenizer {
642
702
  value += nextC;
643
703
  this.next();
644
704
  }
645
- this.setToken(TokenType.Identifier, Number(value));
705
+ this.setToken(TokenType.Number, Number(value));
646
706
  }
647
707
  eof() {
648
708
  this.setToken(TokenType.Eof, 'End Of File');
@@ -921,7 +981,7 @@ var NodeType = function (NodeType) {
921
981
  let _initProto;
922
982
  class Compiler {
923
983
  static {
924
- var _applyDecs$e = _slicedToArray(_applyDecs2311(this, [], [[NodeHook, 2, "parseProgram"], [[NodeHook, NodeLoc], 2, "parseComponentNode"], [[NodeHook, NodeLoc], 2, "parseElementNode"], [[NodeHook, NodeLoc], 2, "parseConditionalNode"], [[NodeHook, NodeLoc], 2, "parseLoopNode"], [NodeHook, 2, "parseProperty"], [[NodeHook, TokenLoc], 2, "parsePropertyKey"], [[NodeHook, TokenLoc], 2, "parsePropertyValue"], [[NodeHook, TokenLoc], 2, "parseName"]]).e, 1);
984
+ var _applyDecs$e = _slicedToArray(_applyDecs2311(this, [], [[NodeHook, 2, "parseProgram"], [[NodeHook, NodeLoc], 2, "parseComponentNode"], [[NodeHook, NodeLoc], 2, "parseElementNode"], [[NodeHook, NodeLoc], 2, "parseConditionalNode"], [[NodeHook, NodeLoc], 2, "parseLoopNode"], [NodeHook, 2, "parseProperty"], [[NodeHook, TokenLoc], 2, "parsePropertyKey"], [[NodeHook, TokenLoc], 2, "parseJsExp"], [[NodeHook, TokenLoc], 2, "parsePropertyValue"], [[NodeHook, TokenLoc], 2, "parseName"]]).e, 1);
925
985
  _initProto = _applyDecs$e[0];
926
986
  }
927
987
  errors = (_initProto(this), []);
@@ -929,25 +989,16 @@ class Compiler {
929
989
  this.tokenizer = tokenizer;
930
990
  this.hooks = hooks;
931
991
  }
932
- addError(code, message, loc) {
992
+ addError(code, message, loc, node) {
993
+ if (node) {
994
+ node.hasError = true;
995
+ }
933
996
  this.errors.push({
934
997
  code,
935
998
  message,
936
999
  loc
937
1000
  });
938
1001
  }
939
- emptyLoc() {
940
- const pos = this.tokenizer.getCurrentPos();
941
- return {
942
- start: pos,
943
- end: {
944
- offset: pos.offset + 1,
945
- line: pos.line,
946
- column: pos.column + 1
947
- },
948
- source: ' '
949
- };
950
- }
951
1002
  parseProgram() {
952
1003
  const body = [];
953
1004
  try {
@@ -961,10 +1012,8 @@ class Compiler {
961
1012
  } catch (error) {
962
1013
  if (error instanceof ParseSyntaxError) {
963
1014
  this.addError(error.code, error.message, error.loc);
964
- } else if (error instanceof SyntaxError) {
965
- const knownCodes = ['INCONSISTENT_INDENT', 'INDENT_MISMATCH'];
966
- const code = knownCodes.includes(error.message) ? error.message : 'INCONSISTENT_INDENT';
967
- this.addError(code, error.message, this.emptyLoc());
1015
+ } else {
1016
+ this.addError(error.toString(), '未知错误', this.tokenizer.emptyLoc());
968
1017
  }
969
1018
  }
970
1019
  return {
@@ -1004,7 +1053,7 @@ class Compiler {
1004
1053
  templateNode(siblings) {
1005
1054
  const token = this.tokenizer.token;
1006
1055
  if (token.type & TokenType.Pipe) {
1007
- this.addError('PIPE_IN_WRONG_CONTEXT', '"|" 只能出现在元素属性扩展行中', token.loc ?? this.emptyLoc());
1056
+ this.addError(ParseErrorCode.PIPE_IN_WRONG_CONTEXT, '"|" 只能出现在元素属性扩展行中', token.loc ?? this.tokenizer.emptyLoc());
1008
1057
  this.tokenizer.nextToken();
1009
1058
  return null;
1010
1059
  }
@@ -1012,12 +1061,13 @@ class Compiler {
1012
1061
  _this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
1013
1062
  hookType = _this$tokenizer$_hook2[0],
1014
1063
  value = _this$tokenizer$_hook2[1];
1015
- if (value === 'if' || value === 'else' || value === 'fail') {
1016
- if (value === 'else' || value === 'fail') {
1064
+ const isElseOrFail = value === 'else' || value === 'fail';
1065
+ if (value === 'if' || isElseOrFail) {
1066
+ if (isElseOrFail) {
1017
1067
  const lastSibling = siblings[siblings.length - 1];
1018
1068
  const lastType = lastSibling?.type;
1019
1069
  if (lastType !== NodeType.If && lastType !== NodeType.Else && lastType !== NodeType.Fail) {
1020
- this.addError('ELSE_WITHOUT_IF', `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.emptyLoc());
1070
+ this.addError(ParseErrorCode.ELSE_WITHOUT_IF, `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.tokenizer.emptyLoc());
1021
1071
  }
1022
1072
  }
1023
1073
  return this.parseConditionalNode();
@@ -1045,7 +1095,7 @@ class Compiler {
1045
1095
  parseElementNode(node) {
1046
1096
  const tagToken = this.tokenizer.token;
1047
1097
  if (!(tagToken.type & TokenType.Identifier)) {
1048
- this.addError('INVALID_TAG_NAME', `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.emptyLoc());
1098
+ this.addError(ParseErrorCode.INVALID_TAG_NAME, `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.tokenizer.emptyLoc(), node);
1049
1099
  while (!(this.tokenizer.token.type & TokenType.NewLine) && !this.tokenizer.isEof()) {
1050
1100
  this.tokenizer.nextToken();
1051
1101
  }
@@ -1065,7 +1115,7 @@ class Compiler {
1065
1115
  parseConditionalNode(node) {
1066
1116
  const keyword = this.tokenizer.token.value;
1067
1117
  this.tokenizer.condExp();
1068
- const condition = this.parsePropertyValue();
1118
+ const condition = this.parseJsExp();
1069
1119
  this.tokenizer.nextToken();
1070
1120
  this.tokenizer.nextToken();
1071
1121
  node.type = keyword === 'if' ? NodeType.If : keyword === 'else' ? NodeType.Else : NodeType.Fail;
@@ -1076,24 +1126,24 @@ class Compiler {
1076
1126
  return node;
1077
1127
  }
1078
1128
  parseLoopNode(node) {
1079
- const forLoc = this.tokenizer.token.loc ?? this.emptyLoc();
1129
+ const forLoc = this.tokenizer.token.loc ?? this.tokenizer.emptyLoc();
1080
1130
  this.tokenizer.nextToken();
1081
- const collection = this.parsePropertyValue();
1131
+ const collection = this.parseJsExp();
1082
1132
  if (!collection.value && collection.value !== 0) {
1083
- this.addError('MISSING_FOR_COLLECTION', '"for" 缺少集合表达式', forLoc);
1133
+ this.addError(ParseErrorCode.MISSING_FOR_COLLECTION, '"for" 缺少集合表达式', forLoc, node);
1084
1134
  }
1085
1135
  const semicolonToken = this.tokenizer.nextToken();
1086
1136
  if (!(semicolonToken.type & TokenType.Semicolon)) {
1087
- this.addError('MISSING_FOR_SEMICOLON', '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.emptyLoc());
1137
+ this.addError(ParseErrorCode.MISSING_FOR_SEMICOLON, '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.tokenizer.emptyLoc(), node);
1088
1138
  }
1089
1139
  const itemToken = this.tokenizer.nextToken();
1090
1140
  const isDestruct = itemToken.type === TokenType.InsertionExp;
1091
1141
  if (isDestruct) {
1092
1142
  itemToken.value = '{' + itemToken.value + '}';
1093
1143
  }
1094
- const item = this.parsePropertyValue();
1144
+ const item = this.parseJsExp();
1095
1145
  if (!item.value && item.value !== 0) {
1096
- this.addError('MISSING_FOR_ITEM', '"for" 缺少 item 变量名', itemToken.loc ?? this.emptyLoc());
1146
+ this.addError(ParseErrorCode.MISSING_FOR_ITEM, '"for" 缺少 item 变量名', itemToken.loc ?? this.tokenizer.emptyLoc(), node);
1097
1147
  }
1098
1148
  let char = this.tokenizer.peekChar(),
1099
1149
  key,
@@ -1102,16 +1152,16 @@ class Compiler {
1102
1152
  this.tokenizer.nextToken();
1103
1153
  if (this.tokenizer.peekChar() !== '\n') {
1104
1154
  this.tokenizer.jsExp();
1105
- key = this.parsePropertyValue();
1155
+ key = this.parseJsExp();
1106
1156
  }
1107
1157
  } else if (char === '\n') ; else {
1108
1158
  this.tokenizer.nextToken();
1109
- index = this.parsePropertyValue();
1159
+ index = this.parseJsExp();
1110
1160
  if (this.tokenizer.peekChar() === ';') {
1111
1161
  this.tokenizer.nextToken();
1112
1162
  if (this.tokenizer.peekChar() !== '\n') {
1113
1163
  this.tokenizer.jsExp();
1114
- key = this.parsePropertyValue();
1164
+ key = this.parseJsExp();
1115
1165
  }
1116
1166
  }
1117
1167
  }
@@ -1145,23 +1195,41 @@ class Compiler {
1145
1195
  attributeList() {
1146
1196
  const props = [];
1147
1197
  while (!(this.tokenizer.token.type & TokenType.NewLine) && !(this.tokenizer.token.type & TokenType.Pipe) && !this.tokenizer.isEof()) {
1148
- props.push(this.parseProperty());
1198
+ const prop = this.parseProperty();
1199
+ if (prop) {
1200
+ props.push(prop);
1201
+ }
1149
1202
  }
1150
1203
  return props;
1151
1204
  }
1152
1205
  parseProperty(node) {
1153
1206
  node.type = NodeType.Property;
1154
- node.key = this.parsePropertyKey();
1155
- const token = this.tokenizer.nextToken();
1156
- if (token.value === '=') {
1157
- this.tokenizer.nextToken();
1158
- node.value = this.parsePropertyValue();
1207
+ if (this.tokenizer.token.type !== TokenType.Identifier) {
1208
+ this.addError(ParseErrorCode.INVALID_PROP_KEY, `属性名 "${this.tokenizer.token.value}" 不合法`, this.tokenizer.token.loc ?? this.tokenizer.emptyLoc(), node);
1159
1209
  this.tokenizer.nextToken();
1160
- } else {
1161
- this.addError('MISSING_ASSIGN', `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.emptyLoc());
1210
+ return null;
1162
1211
  }
1212
+ node.key = this.parsePropertyKey();
1213
+ const token = this.tokenizer.nextToken();
1214
+ if (token.value !== '=') {
1215
+ this.addError(ParseErrorCode.MISSING_ASSIGN, `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.tokenizer.emptyLoc(), node);
1216
+ node.loc.start = node.key.loc.start;
1217
+ node.loc.end = node.key.loc.end;
1218
+ node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
1219
+ return node;
1220
+ }
1221
+ const valueToken = this.tokenizer.nextToken();
1222
+ if ((valueToken.type & ValueTokenType) === 0) {
1223
+ this.addError(ParseErrorCode.MISSING_PROP_ASSIGNMENT, `属性值不合法, "${valueToken.value}" 不合法`, valueToken.loc ?? this.tokenizer.emptyLoc(), node);
1224
+ node.loc.start = node.key.loc.start;
1225
+ node.loc.end = node.key.loc.end;
1226
+ node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
1227
+ return node;
1228
+ }
1229
+ node.value = this.parsePropertyValue();
1230
+ this.tokenizer.nextToken();
1163
1231
  node.loc.start = node.key.loc.start;
1164
- node.loc.end = node.value ? node.value.loc.end : node.key.loc.end;
1232
+ node.loc.end = node.value.loc.end;
1165
1233
  node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
1166
1234
  return node;
1167
1235
  }
@@ -1170,7 +1238,7 @@ class Compiler {
1170
1238
  node.key = this.tokenizer.token.value;
1171
1239
  return node;
1172
1240
  }
1173
- parsePropertyValue(node) {
1241
+ parseJsExp(node) {
1174
1242
  const _this$tokenizer$_hook3 = this.tokenizer._hook({}),
1175
1243
  _this$tokenizer$_hook4 = _slicedToArray(_this$tokenizer$_hook3, 2),
1176
1244
  hookType = _this$tokenizer$_hook4[0],
@@ -1179,7 +1247,7 @@ class Compiler {
1179
1247
  node.value = value;
1180
1248
  return node;
1181
1249
  }
1182
- parseName(node) {
1250
+ parsePropertyValue(node) {
1183
1251
  const _this$tokenizer$_hook5 = this.tokenizer._hook({}),
1184
1252
  _this$tokenizer$_hook6 = _slicedToArray(_this$tokenizer$_hook5, 2),
1185
1253
  hookType = _this$tokenizer$_hook6[0],
@@ -1188,6 +1256,15 @@ class Compiler {
1188
1256
  node.value = value;
1189
1257
  return node;
1190
1258
  }
1259
+ parseName(node) {
1260
+ const _this$tokenizer$_hook7 = this.tokenizer._hook({}),
1261
+ _this$tokenizer$_hook8 = _slicedToArray(_this$tokenizer$_hook7, 2),
1262
+ hookType = _this$tokenizer$_hook8[0],
1263
+ value = _this$tokenizer$_hook8[1];
1264
+ node.type = hookType === 'dynamic' ? NodeType.DynamicValue : NodeType.StaticValue;
1265
+ node.value = value;
1266
+ return node;
1267
+ }
1191
1268
  }
1192
1269
  function NodeLoc(target, context) {
1193
1270
  return function (_node) {