Index: lib/src/js/nodes.dart |
diff --git a/lib/src/js/nodes.dart b/lib/src/js/nodes.dart |
index 92446fa8bf48b3d4faeefcfa0a2013d7b8ec4343..bac9b1a7132bb413ff347c818ff8c19732cf2fb8 100644 |
--- a/lib/src/js/nodes.dart |
+++ b/lib/src/js/nodes.dart |
@@ -13,6 +13,7 @@ abstract class NodeVisitor<T> { |
T visitIf(If node); |
T visitFor(For node); |
T visitForIn(ForIn node); |
+ T visitForOf(ForOf node); |
T visitWhile(While node); |
T visitDo(Do node); |
T visitContinue(Continue node); |
@@ -42,12 +43,14 @@ abstract class NodeVisitor<T> { |
T visitVariableUse(VariableUse node); |
T visitThis(This node); |
+ T visitSuper(Super node); |
T visitVariableDeclaration(VariableDeclaration node); |
T visitParameter(Parameter node); |
T visitAccess(PropertyAccess node); |
T visitNamedFunction(NamedFunction node); |
T visitFun(Fun node); |
+ T visitArrowFun(ArrowFun node); |
T visitLiteralBool(LiteralBool node); |
T visitLiteralString(LiteralString node); |
@@ -59,16 +62,27 @@ abstract class NodeVisitor<T> { |
T visitObjectInitializer(ObjectInitializer node); |
T visitProperty(Property node); |
T visitRegExpLiteral(RegExpLiteral node); |
+ T visitTemplateString(TemplateString node); |
+ T visitTaggedTemplate(TaggedTemplate node); |
T visitAwait(Await node); |
+ T visitClassDeclaration(ClassDeclaration node); |
+ T visitClassExpression(ClassExpression node); |
+ T visitMethod(Method node); |
+ T visitPropertyName(PropertyName node); |
+ |
T visitComment(Comment node); |
+ T visitCommentExpression(CommentExpression node); |
T visitInterpolatedExpression(InterpolatedExpression node); |
T visitInterpolatedLiteral(InterpolatedLiteral node); |
T visitInterpolatedParameter(InterpolatedParameter node); |
T visitInterpolatedSelector(InterpolatedSelector node); |
T visitInterpolatedStatement(InterpolatedStatement node); |
+ T visitInterpolatedMethod(InterpolatedMethod node); |
+ T visitInterpolatedPropertyName(InterpolatedPropertyName node); |
+ T visitInterpolatedVariableDeclaration(InterpolatedVariableDeclaration node); |
} |
class BaseVisitor<T> implements NodeVisitor<T> { |
@@ -90,6 +104,7 @@ class BaseVisitor<T> implements NodeVisitor<T> { |
T visitIf(If node) => visitStatement(node); |
T visitFor(For node) => visitLoop(node); |
T visitForIn(ForIn node) => visitLoop(node); |
+ T visitForOf(ForOf node) => visitLoop(node); |
T visitWhile(While node) => visitLoop(node); |
T visitDo(Do node) => visitLoop(node); |
T visitContinue(Continue node) => visitJump(node); |
@@ -134,9 +149,12 @@ class BaseVisitor<T> implements NodeVisitor<T> { |
=> visitVariableReference(node); |
T visitParameter(Parameter node) => visitVariableDeclaration(node); |
T visitThis(This node) => visitParameter(node); |
+ T visitSuper(Super node) => visitParameter(node); |
T visitNamedFunction(NamedFunction node) => visitExpression(node); |
- T visitFun(Fun node) => visitExpression(node); |
+ T visitFunctionExpression(FunctionExpression node) => visitExpression(node); |
+ T visitFun(Fun node) => visitFunctionExpression(node); |
+ T visitArrowFun(ArrowFun node) => visitFunctionExpression(node); |
T visitLiteral(Literal node) => visitExpression(node); |
@@ -150,6 +168,13 @@ class BaseVisitor<T> implements NodeVisitor<T> { |
T visitObjectInitializer(ObjectInitializer node) => visitExpression(node); |
T visitProperty(Property node) => visitNode(node); |
T visitRegExpLiteral(RegExpLiteral node) => visitExpression(node); |
+ T visitTemplateString(TemplateString node) => visitExpression(node); |
+ T visitTaggedTemplate(TaggedTemplate node) => visitExpression(node); |
+ |
+ T visitClassDeclaration(ClassDeclaration node) => visitStatement(node); |
+ T visitClassExpression(ClassExpression node) => visitExpression(node); |
+ T visitMethod(Method node) => visitProperty(node); |
+ T visitPropertyName(PropertyName node) => visitExpression(node); |
T visitInterpolatedNode(InterpolatedNode node) => visitNode(node); |
@@ -163,9 +188,16 @@ class BaseVisitor<T> implements NodeVisitor<T> { |
=> visitInterpolatedNode(node); |
T visitInterpolatedStatement(InterpolatedStatement node) |
=> visitInterpolatedNode(node); |
+ T visitInterpolatedMethod(InterpolatedMethod node) |
+ => visitInterpolatedNode(node); |
+ T visitInterpolatedPropertyName(InterpolatedPropertyName node) |
+ => visitInterpolatedNode(node); |
+ T visitInterpolatedVariableDeclaration(InterpolatedVariableDeclaration node) |
+ => visitInterpolatedNode(node); |
// Ignore comments by default. |
T visitComment(Comment node) => null; |
+ T visitCommentExpression(CommentExpression node) => null; |
T visitAwait(Await node) => visitExpression(node); |
T visitDartYield(DartYield node) => visitStatement(node); |
@@ -227,7 +259,9 @@ abstract class Statement extends Node { |
class Block extends Statement { |
final List<Statement> statements; |
- Block(this.statements); |
+ Block(this.statements) { |
+ assert(!statements.any((s) => s is! Statement)); |
+ } |
Block.empty() : this.statements = <Statement>[]; |
accept(NodeVisitor visitor) => visitor.visitBlock(this); |
@@ -318,6 +352,25 @@ class ForIn extends Loop { |
ForIn _clone() => new ForIn(leftHandSide, object, body); |
} |
+class ForOf extends Loop { |
+ // Note that [VariableDeclarationList] is a subclass of [Expression]. |
+ // Therefore we can type the leftHandSide as [Expression]. |
+ final Expression leftHandSide; |
+ final Expression iterable; |
+ |
+ ForOf(this.leftHandSide, this.iterable, Statement body) : super(body); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitForOf(this); |
+ |
+ void visitChildren(NodeVisitor visitor) { |
+ leftHandSide.accept(visitor); |
+ iterable.accept(visitor); |
+ body.accept(visitor); |
+ } |
+ |
+ ForIn _clone() => new ForIn(leftHandSide, iterable, body); |
+} |
+ |
class While extends Loop { |
final Node condition; |
@@ -577,9 +630,11 @@ class LiteralExpression extends Expression { |
* AST. |
*/ |
class VariableDeclarationList extends Expression { |
+ /** The `var` or `let` keyword used for this variable declaration list. */ |
+ final String keyword; |
final List<VariableInitialization> declarations; |
- VariableDeclarationList(this.declarations); |
+ VariableDeclarationList(this.keyword, this.declarations); |
accept(NodeVisitor visitor) => visitor.visitVariableDeclarationList(this); |
@@ -589,7 +644,8 @@ class VariableDeclarationList extends Expression { |
} |
} |
- VariableDeclarationList _clone() => new VariableDeclarationList(declarations); |
+ VariableDeclarationList _clone() => |
+ new VariableDeclarationList(keyword, declarations); |
int get precedenceLevel => EXPRESSION; |
} |
@@ -806,6 +862,16 @@ class VariableDeclaration extends VariableReference { |
VariableDeclaration _clone() => new VariableDeclaration(name); |
} |
+class PropertyName extends Expression { |
+ final String name; |
+ PropertyName(this.name); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitPropertyName(this); |
+ visitChildren(NodeVisitor visitor) {} |
+ int get precedenceLevel => PRIMARY; |
+ PropertyName _clone() => new PropertyName(name); |
+} |
+ |
class Parameter extends VariableDeclaration { |
Parameter(String name) : super(name); |
@@ -820,6 +886,15 @@ class This extends Parameter { |
This _clone() => new This(); |
} |
+// `super` is more restricted in the ES6 spec, but for simplicity we accept |
+// it anywhere that `this` is accepted. |
+class Super extends Parameter { |
+ Super() : super("super"); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitSuper(this); |
+ Super _clone() => new Super(); |
+} |
+ |
class NamedFunction extends Expression { |
final VariableDeclaration name; |
final Fun function; |
@@ -837,7 +912,12 @@ class NamedFunction extends Expression { |
int get precedenceLevel => CALL; |
} |
-class Fun extends Expression { |
+abstract class FunctionExpression extends Expression { |
+ List<Parameter> get params; |
+ get body; // Expression or block |
+} |
+ |
+class Fun extends FunctionExpression { |
final List<Parameter> params; |
final Block body; |
final AsyncModifier asyncModifier; |
@@ -856,6 +936,27 @@ class Fun extends Expression { |
int get precedenceLevel => CALL; |
} |
+class ArrowFun extends FunctionExpression { |
+ final List<Parameter> params; |
+ final body; // Expression or Block |
+ |
+ ArrowFun(this.params, this.body); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitArrowFun(this); |
+ |
+ void visitChildren(NodeVisitor visitor) { |
+ for (Parameter param in params) param.accept(visitor); |
+ body.accept(visitor); |
+ } |
+ |
+ ArrowFun _clone() => new ArrowFun(params, body); |
+ |
+ /// Ensure parens always get generated if necessary. |
+ // TODO(jmesserly): I'm not sure the printer is handling this correctly for |
+ // function() { ... } either. |
+ int get precedenceLevel => ASSIGNMENT; |
+} |
+ |
class AsyncModifier { |
final bool isAsync; |
final bool isYielding; |
@@ -985,16 +1086,11 @@ class ArrayHole extends Expression { |
class ObjectInitializer extends Expression { |
final List<Property> properties; |
- final bool isOneLiner; |
/** |
* Constructs a new object-initializer containing the given [properties]. |
- * |
- * [isOneLiner] describes the behaviour when pretty-printing (non-minified). |
- * If true print all properties on the same line. |
- * If false print each property on a seperate line. |
*/ |
- ObjectInitializer(this.properties, {this.isOneLiner: true}); |
+ ObjectInitializer(this.properties); |
accept(NodeVisitor visitor) => visitor.visitObjectInitializer(this); |
@@ -1002,17 +1098,18 @@ class ObjectInitializer extends Expression { |
for (Property init in properties) init.accept(visitor); |
} |
- ObjectInitializer _clone() => |
- new ObjectInitializer(properties, isOneLiner: isOneLiner); |
+ ObjectInitializer _clone() => new ObjectInitializer(properties); |
int get precedenceLevel => PRIMARY; |
} |
class Property extends Node { |
- final Literal name; |
+ final Expression name; |
final Expression value; |
- Property(this.name, this.value); |
+ Property(this.name, this.value) { |
+ assert(name is! VariableDeclaration); |
+ } |
accept(NodeVisitor visitor) => visitor.visitProperty(this); |
@@ -1024,6 +1121,106 @@ class Property extends Node { |
Property _clone() => new Property(name, value); |
} |
+// TODO(jmesserly): parser does not support this yet. |
+class TemplateString extends Expression { |
+ /** |
+ * The parts of this template string: a sequence of [String]s and |
+ * [Expression]s. Strings and expressions will alternate, for example: |
+ * |
+ * `foo${1 + 2} bar ${'hi'}` |
+ * |
+ * would be represented by: |
+ * |
+ * ['foo', new JS.Binary('+', js.number(1), js.number(2)), |
+ * ' bar ', new JS.LiteralString("'hi'")] |
+ */ |
+ final List elements; |
+ TemplateString(this.elements); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitTemplateString(this); |
+ |
+ void visitChildren(NodeVisitor visitor) { |
+ for (var element in elements) { |
+ if (element is Expression) element.accept(visitor); |
+ } |
+ } |
+ |
+ TemplateString _clone() => new TemplateString(elements); |
+ |
+ int get precedenceLevel => PRIMARY; |
+} |
+ |
+// TODO(jmesserly): parser does not support this yet. |
+class TaggedTemplate extends Expression { |
+ final Expression tag; |
+ final TemplateString template; |
+ |
+ TaggedTemplate(this.tag, this.template); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitTaggedTemplate(this); |
+ |
+ void visitChildren(NodeVisitor visitor) { |
+ tag.accept(visitor); |
+ template.accept(visitor); |
+ } |
+ |
+ TaggedTemplate _clone() => new TaggedTemplate(tag, template); |
+ |
+ int get precedenceLevel => CALL; |
+} |
+ |
+class ClassDeclaration extends Statement { |
+ final ClassExpression classExpr; |
+ |
+ ClassDeclaration(this.classExpr); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitClassDeclaration(this); |
+ visitChildren(NodeVisitor visitor) => classExpr.accept(visitor); |
+ ClassDeclaration _clone() => new ClassDeclaration(classExpr); |
+} |
+ |
+class ClassExpression extends Expression { |
+ final VariableDeclaration name; |
+ final Expression heritage; // Can be null. |
+ final List<Method> methods; |
+ |
+ ClassExpression(this.name, this.heritage, this.methods); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitClassExpression(this); |
+ |
+ void visitChildren(NodeVisitor visitor) { |
+ name.accept(visitor); |
+ heritage.accept(visitor); |
+ for (Method element in methods) element.accept(visitor); |
+ } |
+ |
+ ClassExpression _clone() => new ClassExpression(name, heritage, methods); |
+ |
+ int get precedenceLevel => PRIMARY; |
+} |
+ |
+class Method extends Property { |
+ final bool isGetter; |
+ final bool isSetter; |
+ final bool isStatic; |
+ |
+ Method(Expression name, Fun function, |
+ {this.isGetter: false, this.isSetter: false, this.isStatic: false}) |
+ : super(name, function); |
+ |
+ Fun get function => super.value; |
+ |
+ accept(NodeVisitor visitor) => visitor.visitMethod(this); |
+ |
+ void visitChildren(NodeVisitor visitor) { |
+ name.accept(visitor); |
+ function.accept(visitor); |
+ } |
+ |
+ Method _clone() => new Method(name, function, |
+ isGetter: isGetter, isSetter: isSetter, isStatic: isStatic); |
+} |
+ |
/// Tag class for all interpolated positions. |
abstract class InterpolatedNode implements Node { |
get nameOrPosition; |
@@ -1093,6 +1290,60 @@ class InterpolatedStatement extends Statement with InterpolatedNode { |
InterpolatedStatement _clone() => new InterpolatedStatement(nameOrPosition); |
} |
+// TODO(jmesserly): generalize this to InterpolatedProperty? |
+class InterpolatedMethod extends Expression with InterpolatedNode |
+ implements Method { |
+ final nameOrPosition; |
+ |
+ InterpolatedMethod(this.nameOrPosition); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitInterpolatedMethod(this); |
+ void visitChildren(NodeVisitor visitor) {} |
+ InterpolatedMethod _clone() => new InterpolatedMethod(nameOrPosition); |
+ |
+ int get precedenceLevel => PRIMARY; |
+ Expression get name => _unsupported; |
+ Expression get value => _unsupported; |
+ bool get isGetter => _unsupported; |
+ bool get isSetter => _unsupported; |
+ bool get isStatic => _unsupported; |
+ Fun get function => _unsupported; |
+ get _unsupported => throw '$runtimeType does not support this member.'; |
+} |
+ |
+class InterpolatedPropertyName extends Expression with InterpolatedNode |
+ implements PropertyName { |
+ final nameOrPosition; |
+ |
+ InterpolatedPropertyName(this.nameOrPosition); |
+ |
+ accept(NodeVisitor visitor) => visitor.visitInterpolatedPropertyName(this); |
+ void visitChildren(NodeVisitor visitor) {} |
+ InterpolatedPropertyName _clone() => |
+ new InterpolatedPropertyName(nameOrPosition); |
+ |
+ int get precedenceLevel => PRIMARY; |
+ String get name => throw '$runtimeType does not support this member.'; |
+ bool get allowRename => false; |
+} |
+ |
+class InterpolatedVariableDeclaration extends Expression with InterpolatedNode |
+ implements VariableDeclaration { |
+ final nameOrPosition; |
+ |
+ InterpolatedVariableDeclaration(this.nameOrPosition); |
+ |
+ accept(NodeVisitor visitor) => |
+ visitor.visitInterpolatedVariableDeclaration(this); |
+ void visitChildren(NodeVisitor visitor) {} |
+ InterpolatedVariableDeclaration _clone() => |
+ new InterpolatedVariableDeclaration(nameOrPosition); |
+ |
+ int get precedenceLevel => PRIMARY; |
+ String get name => throw '$runtimeType does not support this member.'; |
+ bool get allowRename => false; |
+} |
+ |
/** |
* [RegExpLiteral]s, despite being called "Literal", do not inherit from |
* [Literal]. Indeed, regular expressions in JavaScript have a side-effect and |
@@ -1146,3 +1397,22 @@ class Comment extends Statement { |
void visitChildren(NodeVisitor visitor) {} |
} |
+ |
+/** |
+ * A comment for expressions. |
+ * |
+ * Extends [Expression] so we can add comments before expressions. |
+ * Has the highest possible precedence, so we don't add parentheses around it. |
+ */ |
+class CommentExpression extends Expression { |
+ final String comment; |
+ final Expression expression; |
+ |
+ CommentExpression(this.comment, this.expression); |
+ |
+ int get precedenceLevel => PRIMARY; |
+ accept(NodeVisitor visitor) => visitor.visitCommentExpression(this); |
+ CommentExpression _clone() => new CommentExpression(comment, expression); |
+ |
+ void visitChildren(NodeVisitor visitor) => expression.accept(visitor); |
+} |