put precedence logic on expression

pull/1367/head
Rich Harris 7 years ago
parent 7224ef4eff
commit 4c8a5c598d

@ -1,7 +1,6 @@
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';
import { stringify } from '../../utils/stringify'; import { stringify } from '../../utils/stringify';
import fixAttributeCasing from '../../utils/fixAttributeCasing'; import fixAttributeCasing from '../../utils/fixAttributeCasing';
import getExpressionPrecedence from '../../utils/getExpressionPrecedence';
import addToSet from '../../utils/addToSet'; import addToSet from '../../utils/addToSet';
import { DomGenerator } from '../dom/index'; import { DomGenerator } from '../dom/index';
import Node from './shared/Node'; import Node from './shared/Node';
@ -85,11 +84,11 @@ export default class Attribute extends Node {
return (this.chunks[0].type === 'Text' ? '' : `"" + `) + return (this.chunks[0].type === 'Text' ? '' : `"" + `) +
this.chunks this.chunks
.map((chunk: Node) => { .map(chunk => {
if (chunk.type === 'Text') { if (chunk.type === 'Text') {
return stringify(chunk.data); return stringify(chunk.data);
} else { } else {
return getExpressionPrecedence(chunk.node) <= 13 ? `(${chunk.snippet})` : chunk.snippet; return chunk.getPrecedence() <= 13 ? `(${chunk.snippet})` : chunk.snippet;
} }
}) })
.join(' + '); .join(' + ');
@ -183,7 +182,7 @@ export default class Attribute extends Node {
allDependencies.add(d); allDependencies.add(d);
}); });
return getExpressionPrecedence(chunk.node) <= 13 ? `(${snippet})` : snippet; return chunk.getPrecedence() <= 13 ? `(${snippet})` : snippet;
} }
}) })
.join(' + '); .join(' + ');
@ -332,7 +331,7 @@ export default class Attribute extends Node {
allDependencies.add(d); allDependencies.add(d);
}); });
return getExpressionPrecedence(chunk.node) <= 13 ? `(${snippet})` : snippet; return chunk.getPrecedence() <= 13 ? `(${snippet})` : snippet;
} }
}) })
.join(' + '); .join(' + ');

@ -1,5 +1,4 @@
import { stringify } from '../../utils/stringify'; import { stringify } from '../../utils/stringify';
import getExpressionPrecedence from '../../utils/getExpressionPrecedence';
import Node from './shared/Node'; import Node from './shared/Node';
import Block from '../dom/Block'; import Block from '../dom/Block';
import mapChildren from './shared/mapChildren'; import mapChildren from './shared/mapChildren';
@ -57,7 +56,7 @@ export default class Title extends Node {
allDependencies.add(d); allDependencies.add(d);
}); });
return getExpressionPrecedence(chunk.expression.node) <= 13 ? `(${snippet})` : snippet; return chunk.expression.getPrecedence() <= 13 ? `(${snippet})` : snippet;
} }
}) })
.join(' + '); .join(' + ');

@ -3,6 +3,55 @@ import { walk } from 'estree-walker';
import isReference from 'is-reference'; import isReference from 'is-reference';
import flattenReference from '../../../utils/flattenReference'; import flattenReference from '../../../utils/flattenReference';
import { createScopes } from '../../../utils/annotateWithScopes'; import { createScopes } from '../../../utils/annotateWithScopes';
import { Node } from '../../../interfaces';
const binaryOperators: Record<string, number> = {
'**': 15,
'*': 14,
'/': 14,
'%': 14,
'+': 13,
'-': 13,
'<<': 12,
'>>': 12,
'>>>': 12,
'<': 11,
'<=': 11,
'>': 11,
'>=': 11,
'in': 11,
'instanceof': 11,
'==': 10,
'!=': 10,
'===': 10,
'!==': 10,
'&': 9,
'^': 8,
'|': 7
};
const logicalOperators: Record<string, number> = {
'&&': 6,
'||': 5
};
const precedence: Record<string, (node?: Node) => number> = {
Literal: () => 21,
Identifier: () => 21,
ParenthesizedExpression: () => 20,
MemberExpression: () => 19,
NewExpression: () => 19, // can be 18 (if no args) but makes no practical difference
CallExpression: () => 19,
UpdateExpression: () => 17,
UnaryExpression: () => 16,
BinaryExpression: (node: Node) => binaryOperators[node.operator],
LogicalExpression: (node: Node) => logicalOperators[node.operator],
ConditionalExpression: () => 4,
AssignmentExpression: () => 3,
YieldExpression: () => 2,
SpreadElement: () => 1,
SequenceExpression: () => 0
};
export default class Expression { export default class Expression {
compiler: Generator; compiler: Generator;
@ -117,6 +166,10 @@ export default class Expression {
this.indexes = new Set(); // TODO... this.indexes = new Set(); // TODO...
} }
getPrecedence() {
return this.node.type in precedence ? precedence[this.node.type](this.node) : 0;
}
overwriteThis(name) { overwriteThis(name) {
this.thisReferences.forEach(ref => { this.thisReferences.forEach(ref => {
this.compiler.code.overwrite(ref.start, ref.end, name, { this.compiler.code.overwrite(ref.start, ref.end, name, {

@ -1,54 +0,0 @@
import { Node } from '../interfaces';
const binaryOperators: Record<string, number> = {
'**': 15,
'*': 14,
'/': 14,
'%': 14,
'+': 13,
'-': 13,
'<<': 12,
'>>': 12,
'>>>': 12,
'<': 11,
'<=': 11,
'>': 11,
'>=': 11,
'in': 11,
'instanceof': 11,
'==': 10,
'!=': 10,
'===': 10,
'!==': 10,
'&': 9,
'^': 8,
'|': 7
};
const logicalOperators: Record<string, number> = {
'&&': 6,
'||': 5
};
const precedence: Record<string, (expression?: Node) => number> = {
Literal: () => 21,
Identifier: () => 21,
ParenthesizedExpression: () => 20,
MemberExpression: () => 19,
NewExpression: () => 19, // can be 18 (if no args) but makes no practical difference
CallExpression: () => 19,
UpdateExpression: () => 17,
UnaryExpression: () => 16,
BinaryExpression: (expression: Node) => binaryOperators[expression.operator],
LogicalExpression: (expression: Node) => logicalOperators[expression.operator],
ConditionalExpression: () => 4,
AssignmentExpression: () => 3,
YieldExpression: () => 2,
SpreadElement: () => 1,
SequenceExpression: () => 0
};
// TODO make this a method of Expression
export default function getExpressionPrecedence(expression: Node) {
return expression.type in precedence ? precedence[expression.type](expression) : 0;
}
Loading…
Cancel
Save