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.
- package/dist/bobe.cjs.js +130 -53
- package/dist/bobe.cjs.js.map +1 -1
- package/dist/bobe.compiler.cjs.js +130 -53
- package/dist/bobe.compiler.cjs.js.map +1 -1
- package/dist/bobe.compiler.esm.js +130 -53
- package/dist/bobe.compiler.esm.js.map +1 -1
- package/dist/bobe.esm.js +130 -53
- package/dist/bobe.esm.js.map +1 -1
- package/dist/index.d.ts +32 -5
- package/dist/index.umd.js +130 -53
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -133,7 +133,12 @@ declare enum TokenType {
|
|
|
133
133
|
InsertionExp = 128,
|
|
134
134
|
Semicolon = 256,
|
|
135
135
|
/** 仅编译时可解析 */
|
|
136
|
-
StaticInsExp = 512
|
|
136
|
+
StaticInsExp = 512,
|
|
137
|
+
String = 1024,
|
|
138
|
+
Number = 2048,
|
|
139
|
+
Boolean = 4096,
|
|
140
|
+
Null = 8192,
|
|
141
|
+
Undefined = 16384
|
|
137
142
|
}
|
|
138
143
|
declare enum FakeType {
|
|
139
144
|
If = 1,
|
|
@@ -174,7 +179,24 @@ type TerpConf = Partial<Pick<Interpreter, 'createNode' | 'setProp' | 'insertAfte
|
|
|
174
179
|
type CustomRenderConf = Pick<TerpConf, 'createNode' | 'setProp' | 'insertAfter' | 'remove' | 'createAnchor' | 'firstChild' | 'nextSib'>;
|
|
175
180
|
type Hook = (props: HookProps) => any;
|
|
176
181
|
type HookType = 'dynamic' | 'static';
|
|
177
|
-
|
|
182
|
+
declare enum ParseErrorCode {
|
|
183
|
+
UNCLOSED_BRACE = 9001,
|
|
184
|
+
UNCLOSED_STRING = 9002,
|
|
185
|
+
UNCLOSED_STATIC_INS = 9003,
|
|
186
|
+
INCONSISTENT_INDENT = 9004,
|
|
187
|
+
INDENT_MISMATCH = 9005,
|
|
188
|
+
MISSING_ASSIGN = 9006,
|
|
189
|
+
INVALID_TAG_NAME = 9007,
|
|
190
|
+
INVALID_PROP_KEY = 9008,
|
|
191
|
+
ELSE_WITHOUT_IF = 9009,
|
|
192
|
+
EMPTY_IF_BODY = 9010,
|
|
193
|
+
EMPTY_FOR_BODY = 9011,
|
|
194
|
+
MISSING_FOR_COLLECTION = 9012,
|
|
195
|
+
MISSING_FOR_SEMICOLON = 9013,
|
|
196
|
+
MISSING_FOR_ITEM = 9014,
|
|
197
|
+
MISSING_PROP_ASSIGNMENT = 9015,
|
|
198
|
+
PIPE_IN_WRONG_CONTEXT = 9016
|
|
199
|
+
}
|
|
178
200
|
type ParseError = {
|
|
179
201
|
code: ParseErrorCode;
|
|
180
202
|
message: string;
|
|
@@ -310,6 +332,7 @@ declare class Tokenizer {
|
|
|
310
332
|
private brace;
|
|
311
333
|
private newLine;
|
|
312
334
|
private getDentValue;
|
|
335
|
+
emptyLoc(): SourceLocation;
|
|
313
336
|
private dent;
|
|
314
337
|
private shorterThanBaseDentEof;
|
|
315
338
|
private identifier;
|
|
@@ -344,6 +367,7 @@ type ASTNodeType = NodeType;
|
|
|
344
367
|
interface BaseNode {
|
|
345
368
|
type: ASTNodeType;
|
|
346
369
|
loc?: SourceLocation;
|
|
370
|
+
hasError?: boolean;
|
|
347
371
|
}
|
|
348
372
|
interface Program extends BaseNode {
|
|
349
373
|
type: NodeType.Program;
|
|
@@ -413,7 +437,6 @@ declare class Compiler {
|
|
|
413
437
|
errors: ParseError[];
|
|
414
438
|
constructor(tokenizer: Tokenizer, hooks?: ParseHooks);
|
|
415
439
|
private addError;
|
|
416
|
-
private emptyLoc;
|
|
417
440
|
/**
|
|
418
441
|
* 编译程序入口,生成AST
|
|
419
442
|
*/
|
|
@@ -452,6 +475,10 @@ declare class Compiler {
|
|
|
452
475
|
* 根据值类型创建属性 key 节点
|
|
453
476
|
*/
|
|
454
477
|
parsePropertyKey(node?: PropertyKeyNode): PropertyKeyNode;
|
|
478
|
+
/**
|
|
479
|
+
* 根据值类型创建属性值节点
|
|
480
|
+
*/
|
|
481
|
+
parseJsExp(node?: PropertyValue): PropertyValue;
|
|
455
482
|
/**
|
|
456
483
|
* 根据值类型创建属性值节点
|
|
457
484
|
*/
|
|
@@ -476,5 +503,5 @@ type ParseHooks = Partial<{
|
|
|
476
503
|
declare function bobe(fragments: TemplateStringsArray, ...values: any[]): BobeUI;
|
|
477
504
|
declare function customRender(option: CustomRenderConf): <T>(Ctor: typeof Store, root: any) => (ComponentNode$1 | Store)[];
|
|
478
505
|
|
|
479
|
-
export { Compiler, NodeType, ParseSyntaxError, Tokenizer, bobe, customRender };
|
|
480
|
-
export type { ASTNodeType, BaseNode, ComponentNode, ConditionalNode, DynamicValue, ElementNode, FragmentNode, InterpolationNode, LoopNode, ParseError,
|
|
506
|
+
export { Compiler, NodeType, ParseErrorCode, ParseSyntaxError, Tokenizer, bobe, customRender };
|
|
507
|
+
export type { ASTNodeType, BaseNode, ComponentNode, ConditionalNode, DynamicValue, ElementNode, FragmentNode, InterpolationNode, LoopNode, ParseError, Program, Property, PropertyKeyNode, PropertyValue, SourceLocation, StaticValue, TemplateNode, TextNode };
|
package/dist/index.umd.js
CHANGED
|
@@ -15,8 +15,15 @@
|
|
|
15
15
|
TokenType[TokenType["InsertionExp"] = 128] = "InsertionExp";
|
|
16
16
|
TokenType[TokenType["Semicolon"] = 256] = "Semicolon";
|
|
17
17
|
TokenType[TokenType["StaticInsExp"] = 512] = "StaticInsExp";
|
|
18
|
+
TokenType[TokenType["String"] = 1024] = "String";
|
|
19
|
+
TokenType[TokenType["Number"] = 2048] = "Number";
|
|
20
|
+
TokenType[TokenType["Boolean"] = 4096] = "Boolean";
|
|
21
|
+
TokenType[TokenType["Null"] = 8192] = "Null";
|
|
22
|
+
TokenType[TokenType["Undefined"] = 16384] = "Undefined";
|
|
18
23
|
return TokenType;
|
|
19
24
|
}({});
|
|
25
|
+
const BaseTokenType = TokenType.String | TokenType.Number | TokenType.Boolean | TokenType.Null | TokenType.Undefined;
|
|
26
|
+
const ValueTokenType = BaseTokenType | TokenType.InsertionExp | TokenType.StaticInsExp;
|
|
20
27
|
let FakeType = function (FakeType) {
|
|
21
28
|
FakeType[FakeType["If"] = 1] = "If";
|
|
22
29
|
FakeType[FakeType["Fail"] = 2] = "Fail";
|
|
@@ -44,6 +51,25 @@
|
|
|
44
51
|
TerpEvt["HandledComponentNode"] = "handled-component-node";
|
|
45
52
|
return TerpEvt;
|
|
46
53
|
})({});
|
|
54
|
+
let ParseErrorCode = function (ParseErrorCode) {
|
|
55
|
+
ParseErrorCode[ParseErrorCode["UNCLOSED_BRACE"] = 9001] = "UNCLOSED_BRACE";
|
|
56
|
+
ParseErrorCode[ParseErrorCode["UNCLOSED_STRING"] = 9002] = "UNCLOSED_STRING";
|
|
57
|
+
ParseErrorCode[ParseErrorCode["UNCLOSED_STATIC_INS"] = 9003] = "UNCLOSED_STATIC_INS";
|
|
58
|
+
ParseErrorCode[ParseErrorCode["INCONSISTENT_INDENT"] = 9004] = "INCONSISTENT_INDENT";
|
|
59
|
+
ParseErrorCode[ParseErrorCode["INDENT_MISMATCH"] = 9005] = "INDENT_MISMATCH";
|
|
60
|
+
ParseErrorCode[ParseErrorCode["MISSING_ASSIGN"] = 9006] = "MISSING_ASSIGN";
|
|
61
|
+
ParseErrorCode[ParseErrorCode["INVALID_TAG_NAME"] = 9007] = "INVALID_TAG_NAME";
|
|
62
|
+
ParseErrorCode[ParseErrorCode["INVALID_PROP_KEY"] = 9008] = "INVALID_PROP_KEY";
|
|
63
|
+
ParseErrorCode[ParseErrorCode["ELSE_WITHOUT_IF"] = 9009] = "ELSE_WITHOUT_IF";
|
|
64
|
+
ParseErrorCode[ParseErrorCode["EMPTY_IF_BODY"] = 9010] = "EMPTY_IF_BODY";
|
|
65
|
+
ParseErrorCode[ParseErrorCode["EMPTY_FOR_BODY"] = 9011] = "EMPTY_FOR_BODY";
|
|
66
|
+
ParseErrorCode[ParseErrorCode["MISSING_FOR_COLLECTION"] = 9012] = "MISSING_FOR_COLLECTION";
|
|
67
|
+
ParseErrorCode[ParseErrorCode["MISSING_FOR_SEMICOLON"] = 9013] = "MISSING_FOR_SEMICOLON";
|
|
68
|
+
ParseErrorCode[ParseErrorCode["MISSING_FOR_ITEM"] = 9014] = "MISSING_FOR_ITEM";
|
|
69
|
+
ParseErrorCode[ParseErrorCode["MISSING_PROP_ASSIGNMENT"] = 9015] = "MISSING_PROP_ASSIGNMENT";
|
|
70
|
+
ParseErrorCode[ParseErrorCode["PIPE_IN_WRONG_CONTEXT"] = 9016] = "PIPE_IN_WRONG_CONTEXT";
|
|
71
|
+
return ParseErrorCode;
|
|
72
|
+
}({});
|
|
47
73
|
class ParseSyntaxError extends SyntaxError {
|
|
48
74
|
constructor(code, message, loc) {
|
|
49
75
|
super(message);
|
|
@@ -161,7 +187,7 @@
|
|
|
161
187
|
const expLen = this.dentStack[i];
|
|
162
188
|
if (currLen === expLen) break;
|
|
163
189
|
if (currLen > expLen) {
|
|
164
|
-
throw
|
|
190
|
+
throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
|
|
165
191
|
}
|
|
166
192
|
if (this.shorterThanBaseDentEof()) {
|
|
167
193
|
break;
|
|
@@ -352,7 +378,7 @@
|
|
|
352
378
|
while (1) {
|
|
353
379
|
nextC = this.code[this.i + 1];
|
|
354
380
|
if (nextC === undefined) {
|
|
355
|
-
this.throwUnclosed(
|
|
381
|
+
this.throwUnclosed(ParseErrorCode.UNCLOSED_STATIC_INS, '未闭合的 "${...}"', startOffset, startLine, startCol);
|
|
356
382
|
}
|
|
357
383
|
value += nextC;
|
|
358
384
|
this.next();
|
|
@@ -381,7 +407,7 @@
|
|
|
381
407
|
while (1) {
|
|
382
408
|
const char = this.code[this.i];
|
|
383
409
|
if (char === undefined) {
|
|
384
|
-
this.throwUnclosed(
|
|
410
|
+
this.throwUnclosed(ParseErrorCode.UNCLOSED_BRACE, '未闭合的 "{"', startOffset, startLine, startCol);
|
|
385
411
|
}
|
|
386
412
|
const nextChar = this.code[this.i + 1];
|
|
387
413
|
if (inComment === 'single' && char === '\n') {
|
|
@@ -470,6 +496,18 @@
|
|
|
470
496
|
isEmptyLine
|
|
471
497
|
};
|
|
472
498
|
}
|
|
499
|
+
emptyLoc() {
|
|
500
|
+
const pos = this.getCurrentPos();
|
|
501
|
+
return {
|
|
502
|
+
start: pos,
|
|
503
|
+
end: {
|
|
504
|
+
offset: pos.offset + 1,
|
|
505
|
+
line: pos.line,
|
|
506
|
+
column: pos.column + 1
|
|
507
|
+
},
|
|
508
|
+
source: ' '
|
|
509
|
+
};
|
|
510
|
+
}
|
|
473
511
|
dent() {
|
|
474
512
|
const _this$getDentValue2 = this.getDentValue(),
|
|
475
513
|
value = _this$getDentValue2.value,
|
|
@@ -496,7 +534,7 @@
|
|
|
496
534
|
const expLen = this.dentStack[i];
|
|
497
535
|
if (currLen === expLen) break;
|
|
498
536
|
if (currLen > expLen) {
|
|
499
|
-
throw
|
|
537
|
+
throw new ParseSyntaxError(ParseErrorCode.INCONSISTENT_INDENT, '缩进大小不统一', this.emptyLoc());
|
|
500
538
|
}
|
|
501
539
|
if (this.shorterThanBaseDentEof()) {
|
|
502
540
|
return;
|
|
@@ -561,8 +599,30 @@
|
|
|
561
599
|
this.setToken(TokenType.Dedent, '');
|
|
562
600
|
return;
|
|
563
601
|
}
|
|
564
|
-
let realValue
|
|
565
|
-
|
|
602
|
+
let realValue, tokenType;
|
|
603
|
+
switch (value) {
|
|
604
|
+
case 'null':
|
|
605
|
+
realValue = null;
|
|
606
|
+
tokenType = TokenType.Null;
|
|
607
|
+
break;
|
|
608
|
+
case 'undefined':
|
|
609
|
+
realValue = undefined;
|
|
610
|
+
tokenType = TokenType.Undefined;
|
|
611
|
+
break;
|
|
612
|
+
case 'false':
|
|
613
|
+
realValue = false;
|
|
614
|
+
tokenType = TokenType.Boolean;
|
|
615
|
+
break;
|
|
616
|
+
case 'true':
|
|
617
|
+
realValue = true;
|
|
618
|
+
tokenType = TokenType.Boolean;
|
|
619
|
+
break;
|
|
620
|
+
default:
|
|
621
|
+
realValue = value;
|
|
622
|
+
tokenType = TokenType.Identifier;
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
this.setToken(tokenType, realValue);
|
|
566
626
|
}
|
|
567
627
|
str(char) {
|
|
568
628
|
const startOffset = this.preI,
|
|
@@ -574,7 +634,7 @@
|
|
|
574
634
|
while (1) {
|
|
575
635
|
nextC = this.code[this.i + 1];
|
|
576
636
|
if (nextC === undefined) {
|
|
577
|
-
this.throwUnclosed(
|
|
637
|
+
this.throwUnclosed(ParseErrorCode.UNCLOSED_STRING, '未闭合的字符串字面量', startOffset, startLine, startCol);
|
|
578
638
|
}
|
|
579
639
|
const memoCount = continuousBackslashCount;
|
|
580
640
|
if (nextC === '\\') {
|
|
@@ -588,7 +648,7 @@
|
|
|
588
648
|
}
|
|
589
649
|
value += nextC;
|
|
590
650
|
}
|
|
591
|
-
this.setToken(TokenType.
|
|
651
|
+
this.setToken(TokenType.String, value);
|
|
592
652
|
}
|
|
593
653
|
number(char) {
|
|
594
654
|
let value = char;
|
|
@@ -601,7 +661,7 @@
|
|
|
601
661
|
value += nextC;
|
|
602
662
|
this.next();
|
|
603
663
|
}
|
|
604
|
-
this.setToken(TokenType.
|
|
664
|
+
this.setToken(TokenType.Number, Number(value));
|
|
605
665
|
}
|
|
606
666
|
eof() {
|
|
607
667
|
this.setToken(TokenType.Eof, 'End Of File');
|
|
@@ -880,7 +940,7 @@
|
|
|
880
940
|
let _initProto;
|
|
881
941
|
class Compiler {
|
|
882
942
|
static {
|
|
883
|
-
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);
|
|
943
|
+
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);
|
|
884
944
|
_initProto = _applyDecs$e[0];
|
|
885
945
|
}
|
|
886
946
|
errors = (_initProto(this), []);
|
|
@@ -888,25 +948,16 @@
|
|
|
888
948
|
this.tokenizer = tokenizer;
|
|
889
949
|
this.hooks = hooks;
|
|
890
950
|
}
|
|
891
|
-
addError(code, message, loc) {
|
|
951
|
+
addError(code, message, loc, node) {
|
|
952
|
+
if (node) {
|
|
953
|
+
node.hasError = true;
|
|
954
|
+
}
|
|
892
955
|
this.errors.push({
|
|
893
956
|
code,
|
|
894
957
|
message,
|
|
895
958
|
loc
|
|
896
959
|
});
|
|
897
960
|
}
|
|
898
|
-
emptyLoc() {
|
|
899
|
-
const pos = this.tokenizer.getCurrentPos();
|
|
900
|
-
return {
|
|
901
|
-
start: pos,
|
|
902
|
-
end: {
|
|
903
|
-
offset: pos.offset + 1,
|
|
904
|
-
line: pos.line,
|
|
905
|
-
column: pos.column + 1
|
|
906
|
-
},
|
|
907
|
-
source: ' '
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
961
|
parseProgram() {
|
|
911
962
|
const body = [];
|
|
912
963
|
try {
|
|
@@ -920,10 +971,8 @@
|
|
|
920
971
|
} catch (error) {
|
|
921
972
|
if (error instanceof ParseSyntaxError) {
|
|
922
973
|
this.addError(error.code, error.message, error.loc);
|
|
923
|
-
} else
|
|
924
|
-
|
|
925
|
-
const code = knownCodes.includes(error.message) ? error.message : 'INCONSISTENT_INDENT';
|
|
926
|
-
this.addError(code, error.message, this.emptyLoc());
|
|
974
|
+
} else {
|
|
975
|
+
this.addError(error.toString(), '未知错误', this.tokenizer.emptyLoc());
|
|
927
976
|
}
|
|
928
977
|
}
|
|
929
978
|
return {
|
|
@@ -963,7 +1012,7 @@
|
|
|
963
1012
|
templateNode(siblings) {
|
|
964
1013
|
const token = this.tokenizer.token;
|
|
965
1014
|
if (token.type & TokenType.Pipe) {
|
|
966
|
-
this.addError(
|
|
1015
|
+
this.addError(ParseErrorCode.PIPE_IN_WRONG_CONTEXT, '"|" 只能出现在元素属性扩展行中', token.loc ?? this.tokenizer.emptyLoc());
|
|
967
1016
|
this.tokenizer.nextToken();
|
|
968
1017
|
return null;
|
|
969
1018
|
}
|
|
@@ -971,12 +1020,13 @@
|
|
|
971
1020
|
_this$tokenizer$_hook2 = _slicedToArray(_this$tokenizer$_hook, 2),
|
|
972
1021
|
hookType = _this$tokenizer$_hook2[0],
|
|
973
1022
|
value = _this$tokenizer$_hook2[1];
|
|
974
|
-
|
|
975
|
-
|
|
1023
|
+
const isElseOrFail = value === 'else' || value === 'fail';
|
|
1024
|
+
if (value === 'if' || isElseOrFail) {
|
|
1025
|
+
if (isElseOrFail) {
|
|
976
1026
|
const lastSibling = siblings[siblings.length - 1];
|
|
977
1027
|
const lastType = lastSibling?.type;
|
|
978
1028
|
if (lastType !== NodeType.If && lastType !== NodeType.Else && lastType !== NodeType.Fail) {
|
|
979
|
-
this.addError(
|
|
1029
|
+
this.addError(ParseErrorCode.ELSE_WITHOUT_IF, `"${value}" 前必须有 "if" 或 "else" 节点`, token.loc ?? this.tokenizer.emptyLoc());
|
|
980
1030
|
}
|
|
981
1031
|
}
|
|
982
1032
|
return this.parseConditionalNode();
|
|
@@ -1004,7 +1054,7 @@
|
|
|
1004
1054
|
parseElementNode(node) {
|
|
1005
1055
|
const tagToken = this.tokenizer.token;
|
|
1006
1056
|
if (!(tagToken.type & TokenType.Identifier)) {
|
|
1007
|
-
this.addError(
|
|
1057
|
+
this.addError(ParseErrorCode.INVALID_TAG_NAME, `无效的标签名,期望标识符但得到 "${tagToken.value}"`, tagToken.loc ?? this.tokenizer.emptyLoc(), node);
|
|
1008
1058
|
while (!(this.tokenizer.token.type & TokenType.NewLine) && !this.tokenizer.isEof()) {
|
|
1009
1059
|
this.tokenizer.nextToken();
|
|
1010
1060
|
}
|
|
@@ -1024,7 +1074,7 @@
|
|
|
1024
1074
|
parseConditionalNode(node) {
|
|
1025
1075
|
const keyword = this.tokenizer.token.value;
|
|
1026
1076
|
this.tokenizer.condExp();
|
|
1027
|
-
const condition = this.
|
|
1077
|
+
const condition = this.parseJsExp();
|
|
1028
1078
|
this.tokenizer.nextToken();
|
|
1029
1079
|
this.tokenizer.nextToken();
|
|
1030
1080
|
node.type = keyword === 'if' ? NodeType.If : keyword === 'else' ? NodeType.Else : NodeType.Fail;
|
|
@@ -1035,24 +1085,24 @@
|
|
|
1035
1085
|
return node;
|
|
1036
1086
|
}
|
|
1037
1087
|
parseLoopNode(node) {
|
|
1038
|
-
const forLoc = this.tokenizer.token.loc ?? this.emptyLoc();
|
|
1088
|
+
const forLoc = this.tokenizer.token.loc ?? this.tokenizer.emptyLoc();
|
|
1039
1089
|
this.tokenizer.nextToken();
|
|
1040
|
-
const collection = this.
|
|
1090
|
+
const collection = this.parseJsExp();
|
|
1041
1091
|
if (!collection.value && collection.value !== 0) {
|
|
1042
|
-
this.addError(
|
|
1092
|
+
this.addError(ParseErrorCode.MISSING_FOR_COLLECTION, '"for" 缺少集合表达式', forLoc, node);
|
|
1043
1093
|
}
|
|
1044
1094
|
const semicolonToken = this.tokenizer.nextToken();
|
|
1045
1095
|
if (!(semicolonToken.type & TokenType.Semicolon)) {
|
|
1046
|
-
this.addError(
|
|
1096
|
+
this.addError(ParseErrorCode.MISSING_FOR_SEMICOLON, '"for" 语法:for <集合>; <item> [index][; key],缺少第一个 ";"', semicolonToken.loc ?? this.tokenizer.emptyLoc(), node);
|
|
1047
1097
|
}
|
|
1048
1098
|
const itemToken = this.tokenizer.nextToken();
|
|
1049
1099
|
const isDestruct = itemToken.type === TokenType.InsertionExp;
|
|
1050
1100
|
if (isDestruct) {
|
|
1051
1101
|
itemToken.value = '{' + itemToken.value + '}';
|
|
1052
1102
|
}
|
|
1053
|
-
const item = this.
|
|
1103
|
+
const item = this.parseJsExp();
|
|
1054
1104
|
if (!item.value && item.value !== 0) {
|
|
1055
|
-
this.addError(
|
|
1105
|
+
this.addError(ParseErrorCode.MISSING_FOR_ITEM, '"for" 缺少 item 变量名', itemToken.loc ?? this.tokenizer.emptyLoc(), node);
|
|
1056
1106
|
}
|
|
1057
1107
|
let char = this.tokenizer.peekChar(),
|
|
1058
1108
|
key,
|
|
@@ -1061,16 +1111,16 @@
|
|
|
1061
1111
|
this.tokenizer.nextToken();
|
|
1062
1112
|
if (this.tokenizer.peekChar() !== '\n') {
|
|
1063
1113
|
this.tokenizer.jsExp();
|
|
1064
|
-
key = this.
|
|
1114
|
+
key = this.parseJsExp();
|
|
1065
1115
|
}
|
|
1066
1116
|
} else if (char === '\n') ; else {
|
|
1067
1117
|
this.tokenizer.nextToken();
|
|
1068
|
-
index = this.
|
|
1118
|
+
index = this.parseJsExp();
|
|
1069
1119
|
if (this.tokenizer.peekChar() === ';') {
|
|
1070
1120
|
this.tokenizer.nextToken();
|
|
1071
1121
|
if (this.tokenizer.peekChar() !== '\n') {
|
|
1072
1122
|
this.tokenizer.jsExp();
|
|
1073
|
-
key = this.
|
|
1123
|
+
key = this.parseJsExp();
|
|
1074
1124
|
}
|
|
1075
1125
|
}
|
|
1076
1126
|
}
|
|
@@ -1104,23 +1154,41 @@
|
|
|
1104
1154
|
attributeList() {
|
|
1105
1155
|
const props = [];
|
|
1106
1156
|
while (!(this.tokenizer.token.type & TokenType.NewLine) && !(this.tokenizer.token.type & TokenType.Pipe) && !this.tokenizer.isEof()) {
|
|
1107
|
-
|
|
1157
|
+
const prop = this.parseProperty();
|
|
1158
|
+
if (prop) {
|
|
1159
|
+
props.push(prop);
|
|
1160
|
+
}
|
|
1108
1161
|
}
|
|
1109
1162
|
return props;
|
|
1110
1163
|
}
|
|
1111
1164
|
parseProperty(node) {
|
|
1112
1165
|
node.type = NodeType.Property;
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (token.value === '=') {
|
|
1116
|
-
this.tokenizer.nextToken();
|
|
1117
|
-
node.value = this.parsePropertyValue();
|
|
1166
|
+
if (this.tokenizer.token.type !== TokenType.Identifier) {
|
|
1167
|
+
this.addError(ParseErrorCode.INVALID_PROP_KEY, `属性名 "${this.tokenizer.token.value}" 不合法`, this.tokenizer.token.loc ?? this.tokenizer.emptyLoc(), node);
|
|
1118
1168
|
this.tokenizer.nextToken();
|
|
1119
|
-
|
|
1120
|
-
this.addError('MISSING_ASSIGN', `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.emptyLoc());
|
|
1169
|
+
return null;
|
|
1121
1170
|
}
|
|
1171
|
+
node.key = this.parsePropertyKey();
|
|
1172
|
+
const token = this.tokenizer.nextToken();
|
|
1173
|
+
if (token.value !== '=') {
|
|
1174
|
+
this.addError(ParseErrorCode.MISSING_ASSIGN, `属性 "${node.key.key}" 缺少 "=" 赋值符号`, node.key.loc ?? this.tokenizer.emptyLoc(), node);
|
|
1175
|
+
node.loc.start = node.key.loc.start;
|
|
1176
|
+
node.loc.end = node.key.loc.end;
|
|
1177
|
+
node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
|
|
1178
|
+
return node;
|
|
1179
|
+
}
|
|
1180
|
+
const valueToken = this.tokenizer.nextToken();
|
|
1181
|
+
if ((valueToken.type & ValueTokenType) === 0) {
|
|
1182
|
+
this.addError(ParseErrorCode.MISSING_PROP_ASSIGNMENT, `属性值不合法, "${valueToken.value}" 不合法`, valueToken.loc ?? this.tokenizer.emptyLoc(), node);
|
|
1183
|
+
node.loc.start = node.key.loc.start;
|
|
1184
|
+
node.loc.end = node.key.loc.end;
|
|
1185
|
+
node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
|
|
1186
|
+
return node;
|
|
1187
|
+
}
|
|
1188
|
+
node.value = this.parsePropertyValue();
|
|
1189
|
+
this.tokenizer.nextToken();
|
|
1122
1190
|
node.loc.start = node.key.loc.start;
|
|
1123
|
-
node.loc.end = node.value
|
|
1191
|
+
node.loc.end = node.value.loc.end;
|
|
1124
1192
|
node.loc.source = this.tokenizer.code.slice(node.loc.start.offset, node.loc.end.offset);
|
|
1125
1193
|
return node;
|
|
1126
1194
|
}
|
|
@@ -1129,7 +1197,7 @@
|
|
|
1129
1197
|
node.key = this.tokenizer.token.value;
|
|
1130
1198
|
return node;
|
|
1131
1199
|
}
|
|
1132
|
-
|
|
1200
|
+
parseJsExp(node) {
|
|
1133
1201
|
const _this$tokenizer$_hook3 = this.tokenizer._hook({}),
|
|
1134
1202
|
_this$tokenizer$_hook4 = _slicedToArray(_this$tokenizer$_hook3, 2),
|
|
1135
1203
|
hookType = _this$tokenizer$_hook4[0],
|
|
@@ -1138,7 +1206,7 @@
|
|
|
1138
1206
|
node.value = value;
|
|
1139
1207
|
return node;
|
|
1140
1208
|
}
|
|
1141
|
-
|
|
1209
|
+
parsePropertyValue(node) {
|
|
1142
1210
|
const _this$tokenizer$_hook5 = this.tokenizer._hook({}),
|
|
1143
1211
|
_this$tokenizer$_hook6 = _slicedToArray(_this$tokenizer$_hook5, 2),
|
|
1144
1212
|
hookType = _this$tokenizer$_hook6[0],
|
|
@@ -1147,6 +1215,15 @@
|
|
|
1147
1215
|
node.value = value;
|
|
1148
1216
|
return node;
|
|
1149
1217
|
}
|
|
1218
|
+
parseName(node) {
|
|
1219
|
+
const _this$tokenizer$_hook7 = this.tokenizer._hook({}),
|
|
1220
|
+
_this$tokenizer$_hook8 = _slicedToArray(_this$tokenizer$_hook7, 2),
|
|
1221
|
+
hookType = _this$tokenizer$_hook8[0],
|
|
1222
|
+
value = _this$tokenizer$_hook8[1];
|
|
1223
|
+
node.type = hookType === 'dynamic' ? NodeType.DynamicValue : NodeType.StaticValue;
|
|
1224
|
+
node.value = value;
|
|
1225
|
+
return node;
|
|
1226
|
+
}
|
|
1150
1227
|
}
|
|
1151
1228
|
function NodeLoc(target, context) {
|
|
1152
1229
|
return function (_node) {
|