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