Skip to content

Commit 47ea3c2

Browse files
Merge pull request #691 from fkleuver/remove-chain
refactor(ast/parser): remove Chain
2 parents 27b0325 + 1628d43 commit 47ea3c2

File tree

5 files changed

+50
-103
lines changed

5 files changed

+50
-103
lines changed

src/ast.js

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {connectBindingToSignal} from './signals';
44

55
export class Expression {
66
constructor() {
7-
this.isChain = false;
87
this.isAssignable = false;
98
}
109

@@ -23,35 +22,6 @@ export class Expression {
2322
}
2423
}
2524

26-
export class Chain extends Expression {
27-
constructor(expressions) {
28-
super();
29-
30-
this.expressions = expressions;
31-
this.isChain = true;
32-
}
33-
34-
evaluate(scope, lookupFunctions) {
35-
let result;
36-
let expressions = this.expressions;
37-
let last;
38-
39-
for (let i = 0, length = expressions.length; i < length; ++i) {
40-
last = expressions[i].evaluate(scope, lookupFunctions);
41-
42-
if (last !== null) {
43-
result = last;
44-
}
45-
}
46-
47-
return result;
48-
}
49-
50-
accept(visitor) {
51-
return visitor.visitChain(this);
52-
}
53-
}
54-
5525
export class BindingBehavior extends Expression {
5626
constructor(expression, name, args) {
5727
super();

src/expression-cloner.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
Chain, ValueConverter, Assign, Conditional,
2+
ValueConverter, Assign, Conditional,
33
AccessThis, AccessScope, AccessMember, AccessKeyed,
44
CallScope, CallFunction, CallMember,
55
Unary, BindingBehavior, Binary,
@@ -16,10 +16,6 @@ export class ExpressionCloner {
1616
return clonedArray;
1717
}
1818

19-
visitChain(chain) {
20-
return new Chain(this.cloneExpressionArray(chain.expressions));
21-
}
22-
2319
visitBindingBehavior(behavior) {
2420
return new BindingBehavior(
2521
behavior.expression.accept(this),

src/parser.js

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
Chain, ValueConverter, Assign, Conditional,
2+
ValueConverter, Assign, Conditional,
33
AccessThis, AccessScope, AccessMember, AccessKeyed,
44
CallScope, CallFunction, CallMember,
55
Unary, BindingBehavior, Binary,
@@ -14,8 +14,7 @@ export class Parser {
1414
parse(src) {
1515
src = src || '';
1616

17-
return this.cache[src]
18-
|| (this.cache[src] = new ParserImplementation(src).parseChain());
17+
return this.cache[src] || (this.cache[src] = new ParserImplementation(src).parseBindingBehavior());
1918
}
2019
}
2120

@@ -44,29 +43,18 @@ export class ParserImplementation {
4443
this.ch = src.charCodeAt(0);
4544
}
4645

47-
parseChain() {
46+
parseBindingBehavior() {
4847
this.nextToken();
49-
const expressions = [];
50-
51-
while (!(this.tkn & T$ExpressionTerminal)) {
52-
expressions.push(this.parseBindingBehavior());
53-
}
54-
if (this.tkn !== T$EOF) {
55-
if (this.opt(T$Semicolon)) {
56-
this.err('Multiple expressions are not allowed.');
57-
}
58-
if (this.tkn & T$ClosingToken) {
59-
this.err(`Unconsumed token ${this.raw}`);
60-
}
48+
if (this.tkn & T$ExpressionTerminal) {
49+
this.err('Invalid start of expression');
6150
}
62-
return (expressions.length === 1) ? expressions[0] : new Chain(expressions);
63-
}
64-
65-
parseBindingBehavior() {
6651
let result = this.parseValueConverter();
6752
while (this.opt(T$Ampersand)) {
6853
result = new BindingBehavior(result, this.val, this.parseVariadicArgs());
6954
}
55+
if (this.tkn !== T$EOF) {
56+
this.err(`Unconsumed token ${this.raw}`);
57+
}
7058
return result;
7159
}
7260

@@ -640,38 +628,37 @@ const T$TemplateContinuation = 1 << 26 | T$MemberOrCallExpression;
640628
/** '.' */ const T$Period = 8 | T$MemberExpression | T$MemberOrCallExpression;
641629
/** '}' */ const T$RBrace = 9 | T$AccessScopeTerminal | T$ClosingToken | T$ExpressionTerminal;
642630
/** ')' */ const T$RParen = 10 | T$AccessScopeTerminal | T$ClosingToken | T$ExpressionTerminal;
643-
/** ';' */ const T$Semicolon = 11 | T$ExpressionTerminal;
644-
/** ',' */ const T$Comma = 12 | T$AccessScopeTerminal;
645-
/** '[' */ const T$LBracket = 13 | T$OpeningToken | T$AccessScopeTerminal | T$MemberExpression | T$MemberOrCallExpression;
646-
/** ']' */ const T$RBracket = 14 | T$ClosingToken | T$ExpressionTerminal;
647-
/** ':' */ const T$Colon = 15 | T$AccessScopeTerminal;
648-
/** '?' */ const T$Question = 16;
631+
/** ',' */ const T$Comma = 11 | T$AccessScopeTerminal;
632+
/** '[' */ const T$LBracket = 12 | T$OpeningToken | T$AccessScopeTerminal | T$MemberExpression | T$MemberOrCallExpression;
633+
/** ']' */ const T$RBracket = 13 | T$ClosingToken | T$ExpressionTerminal;
634+
/** ':' */ const T$Colon = 14 | T$AccessScopeTerminal;
635+
/** '?' */ const T$Question = 15;
649636

650637
// Operator precedence: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table
651-
/** '&' */ const T$Ampersand = 19 | T$AccessScopeTerminal;
652-
/** '|' */ const T$Bar = 20 | T$AccessScopeTerminal;
653-
/** '||' */ const T$BarBar = 21/* 5*/ | 1 << T$PrecShift | T$BinaryOp;
654-
/** '&&' */ const T$AmpersandAmpersand = 22/* 6*/ | 2 << T$PrecShift | T$BinaryOp;
655-
/** '^' */ const T$Caret = 23/* 8*/ | 3 << T$PrecShift | T$BinaryOp;
656-
/** '==' */ const T$EqEq = 24/*10*/ | 4 << T$PrecShift | T$BinaryOp;
657-
/** '!=' */ const T$BangEq = 25/*10*/ | 4 << T$PrecShift | T$BinaryOp;
658-
/** '===' */ const T$EqEqEq = 26/*10*/ | 4 << T$PrecShift | T$BinaryOp;
659-
/** '!== '*/ const T$BangEqEq = 27/*10*/ | 4 << T$PrecShift | T$BinaryOp;
660-
/** '<' */ const T$Lt = 28/*11*/ | 5 << T$PrecShift | T$BinaryOp;
661-
/** '>' */ const T$Gt = 29/*11*/ | 5 << T$PrecShift | T$BinaryOp;
662-
/** '<=' */ const T$LtEq = 30/*11*/ | 5 << T$PrecShift | T$BinaryOp;
663-
/** '>=' */ const T$GtEq = 31/*11*/ | 5 << T$PrecShift | T$BinaryOp;
664-
/** 'in' */ const T$InKeyword = 32/*11*/ | 5 << T$PrecShift | T$BinaryOp | T$Keyword;
665-
/** 'instanceof' */const T$InstanceOfKeyword = 33/*11*/ | 5 << T$PrecShift | T$BinaryOp | T$Keyword;
666-
/** '+' */ const T$Plus = 34/*13*/ | 6 << T$PrecShift | T$BinaryOp | T$UnaryOp;
667-
/** '-' */ const T$Minus = 35/*13*/ | 6 << T$PrecShift | T$BinaryOp | T$UnaryOp;
668-
/** 'typeof' */ const T$TypeofKeyword = 36/*16*/ | T$UnaryOp | T$Keyword;
669-
/** 'void' */ const T$VoidKeyword = 37/*16*/ | T$UnaryOp | T$Keyword;
670-
/** '*' */ const T$Star = 38/*14*/ | 7 << T$PrecShift | T$BinaryOp;
671-
/** '%' */ const T$Percent = 39/*14*/ | 7 << T$PrecShift | T$BinaryOp;
672-
/** '/' */ const T$Slash = 40/*14*/ | 7 << T$PrecShift | T$BinaryOp;
673-
/** '=' */ const T$Eq = 41;
674-
/** '!' */ const T$Bang = 42 | T$UnaryOp;
638+
/** '&' */ const T$Ampersand = 18 | T$AccessScopeTerminal;
639+
/** '|' */ const T$Bar = 19 | T$AccessScopeTerminal;
640+
/** '||' */ const T$BarBar = 20/* 5*/ | 1 << T$PrecShift | T$BinaryOp;
641+
/** '&&' */ const T$AmpersandAmpersand = 21/* 6*/ | 2 << T$PrecShift | T$BinaryOp;
642+
/** '^' */ const T$Caret = 22/* 8*/ | 3 << T$PrecShift | T$BinaryOp;
643+
/** '==' */ const T$EqEq = 23/*10*/ | 4 << T$PrecShift | T$BinaryOp;
644+
/** '!=' */ const T$BangEq = 24/*10*/ | 4 << T$PrecShift | T$BinaryOp;
645+
/** '===' */ const T$EqEqEq = 25/*10*/ | 4 << T$PrecShift | T$BinaryOp;
646+
/** '!== '*/ const T$BangEqEq = 26/*10*/ | 4 << T$PrecShift | T$BinaryOp;
647+
/** '<' */ const T$Lt = 27/*11*/ | 5 << T$PrecShift | T$BinaryOp;
648+
/** '>' */ const T$Gt = 28/*11*/ | 5 << T$PrecShift | T$BinaryOp;
649+
/** '<=' */ const T$LtEq = 29/*11*/ | 5 << T$PrecShift | T$BinaryOp;
650+
/** '>=' */ const T$GtEq = 30/*11*/ | 5 << T$PrecShift | T$BinaryOp;
651+
/** 'in' */ const T$InKeyword = 31/*11*/ | 5 << T$PrecShift | T$BinaryOp | T$Keyword;
652+
/** 'instanceof' */const T$InstanceOfKeyword = 32/*11*/ | 5 << T$PrecShift | T$BinaryOp | T$Keyword;
653+
/** '+' */ const T$Plus = 33/*13*/ | 6 << T$PrecShift | T$BinaryOp | T$UnaryOp;
654+
/** '-' */ const T$Minus = 34/*13*/ | 6 << T$PrecShift | T$BinaryOp | T$UnaryOp;
655+
/** 'typeof' */ const T$TypeofKeyword = 35/*16*/ | T$UnaryOp | T$Keyword;
656+
/** 'void' */ const T$VoidKeyword = 36/*16*/ | T$UnaryOp | T$Keyword;
657+
/** '*' */ const T$Star = 37/*14*/ | 7 << T$PrecShift | T$BinaryOp;
658+
/** '%' */ const T$Percent = 38/*14*/ | 7 << T$PrecShift | T$BinaryOp;
659+
/** '/' */ const T$Slash = 39/*14*/ | 7 << T$PrecShift | T$BinaryOp;
660+
/** '=' */ const T$Eq = 40;
661+
/** '!' */ const T$Bang = 41 | T$UnaryOp;
675662

676663
const KeywordLookup = Object.create(null);
677664
KeywordLookup.true = T$TrueKeyword;
@@ -695,7 +682,7 @@ KeywordLookup.void = T$VoidKeyword;
695682
const TokenValues = [
696683
false, true, null, undefined, '$this', '$parent',
697684

698-
'(', '{', '.', '}', ')', ';', ',', '[', ']', ':', '?', '\'', '"',
685+
'(', '{', '.', '}', ')', ',', '[', ']', ':', '?', '\'', '"',
699686

700687
'&', '|', '||', '&&', '^', '==', '!=', '===', '!==', '<', '>',
701688
'<=', '>=', 'in', 'instanceof', '+', '-', 'typeof', 'void', '*', '%', '/', '=', '!'
@@ -855,7 +842,6 @@ CharScanners[/*, 44*/0x2C] = returnToken(T$Comma);
855842
CharScanners[/*- 45*/0x2D] = returnToken(T$Minus);
856843
CharScanners[/*/ 47*/0x2F] = returnToken(T$Slash);
857844
CharScanners[/*: 58*/0x3A] = returnToken(T$Colon);
858-
CharScanners[/*; 59*/0x3B] = returnToken(T$Semicolon);
859845
CharScanners[/*? 63*/0x3F] = returnToken(T$Question);
860846
CharScanners[/*[ 91*/0x5B] = returnToken(T$LBracket);
861847
CharScanners[/*] 93*/0x5D] = returnToken(T$RBracket);

src/unparser.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,6 @@ if (typeof FEATURE_NO_UNPARSER === 'undefined') {
3333
this.write(')');
3434
}
3535

36-
visitChain(chain) {
37-
let expressions = chain.expressions;
38-
39-
for (let i = 0, length = expressions.length; i < length; ++i) {
40-
if (i !== 0) {
41-
this.write(';');
42-
}
43-
44-
expressions[i].accept(this);
45-
}
46-
}
47-
4836
visitBindingBehavior(behavior) {
4937
let args = behavior.args;
5038

test/parser.spec.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -642,16 +642,13 @@ describe('Parser', () => {
642642

643643
for (const expr of expressions) {
644644
it(expr, () => {
645-
_verifyError(expr, 'Multiple expressions are not allowed');
645+
_verifyError(expr, 'Unexpected character [;]');
646646
});
647647
}
648648
});
649649

650650
describe('extra closing token', () => {
651651
const tests = [
652-
{ expr: ')', token: ')' },
653-
{ expr: ']', token: ']' },
654-
{ expr: '}', token: '}' },
655652
{ expr: 'foo())', token: ')' },
656653
{ expr: 'foo[x]]', token: ']' },
657654
{ expr: '{foo}}', token: '}' }
@@ -664,6 +661,16 @@ describe('Parser', () => {
664661
}
665662
});
666663

664+
describe('invalid expression start', () => {
665+
const tests = [')', ']', '}', ''];
666+
667+
for (const expr of tests) {
668+
it(expr, () => {
669+
_verifyError(expr, `Invalid start of expression`);
670+
});
671+
}
672+
});
673+
667674
describe('missing expected token', () => {
668675
const tests = [
669676
{ expr: '(foo', token: ')' },

0 commit comments

Comments
 (0)