Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Unified Diff: lib/src/js/nodes.dart

Issue 1458243002: implement ES6 modules in JS AST. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/js/module_transform.dart ('k') | lib/src/js/printer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/js/nodes.dart
diff --git a/lib/src/js/nodes.dart b/lib/src/js/nodes.dart
index 2f32feb0cfd8faa544e98ce718c8b92ea127956e..879f9fa0634e74358f388b25d6936890cf8ec8c9 100644
--- a/lib/src/js/nodes.dart
+++ b/lib/src/js/nodes.dart
@@ -72,6 +72,12 @@ abstract class NodeVisitor<T> {
T visitClassExpression(ClassExpression node);
T visitMethod(Method node);
+ T visitImportDeclaration(ImportDeclaration node);
+ T visitExportDeclaration(ExportDeclaration node);
+ T visitExportClause(ExportClause node);
+ T visitNameSpecifier(NameSpecifier node);
+ T visitModule(Module node);
+
T visitComment(Comment node);
T visitCommentExpression(CommentExpression node);
@@ -92,7 +98,7 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitProgram(Program node) => visitNode(node);
- T visitStatement(Statement node) => visitNode(node);
+ T visitStatement(Statement node) => visitModuleItem(node);
T visitLoop(Loop node) => visitStatement(node);
T visitJump(Statement node) => visitStatement(node);
@@ -174,6 +180,13 @@ class BaseVisitor<T> implements NodeVisitor<T> {
T visitClassExpression(ClassExpression node) => visitExpression(node);
T visitMethod(Method node) => visitProperty(node);
+ T visitModuleItem(ModuleItem node) => visitNode(node);
+ T visitImportDeclaration(ImportDeclaration node) => visitModuleItem(node);
+ T visitExportDeclaration(ExportDeclaration node) => visitModuleItem(node);
+ T visitExportClause(ExportClause node) => visitNode(node);
+ T visitNameSpecifier(NameSpecifier node) => visitNode(node);
+ T visitModule(Module node) => visitNode(node);
+
T visitInterpolatedNode(InterpolatedNode node) => visitNode(node);
T visitInterpolatedExpression(InterpolatedExpression node)
@@ -271,7 +284,7 @@ class Program extends Node {
Program _clone() => new Program(body);
}
-abstract class Statement extends Node {
+abstract class Statement extends ModuleItem {
Statement toStatement() => this;
Statement toReturn() => new Block([this, new Return()]);
}
@@ -1574,3 +1587,121 @@ class CommentExpression extends Expression {
void visitChildren(NodeVisitor visitor) => expression.accept(visitor);
}
+
+/**
+ * Represents allowed module items:
+ * [Statement], [ImportDeclaration], and [ExportDeclaration].
+ */
+abstract class ModuleItem extends Node {}
+
+class ImportDeclaration extends ModuleItem {
+ final Identifier defaultBinding; // Can be null.
+
+ // Can be null, a single specifier of `* as name`, or a list.
+ final List<NameSpecifier> namedImports;
+
+ final LiteralString from;
+
+ ImportDeclaration({this.defaultBinding, this.namedImports, this.from});
+
+ /** The `import "name.js"` form of import */
+ ImportDeclaration.all(LiteralString module) : this(from: module);
+
+ /** If this import has `* as name` returns the name, otherwise null. */
+ String get importStarAs {
ochafik 2015/11/20 00:06:35 nit: should this be an Identifier?
+ if (namedImports != null && namedImports.length == 1 &&
+ namedImports[0].name == '*') {
+ return namedImports[0].asName;
+ }
+ return null;
+ }
+
+ accept(NodeVisitor visitor) => visitor.visitImportDeclaration(this);
+ void visitChildren(NodeVisitor visitor) {
+ if (namedImports != null) {
+ for (NameSpecifier name in namedImports) name.accept(visitor);
+ }
+ from.accept(visitor);
+ }
+ ImportDeclaration _clone() => new ImportDeclaration(
+ defaultBinding: defaultBinding, namedImports: namedImports, from: from);
+}
+
+class ExportDeclaration extends ModuleItem {
+ /**
+ * Exports a name from this module.
+ *
+ * This can be a [ClassDeclaration] or [FunctionDeclaration].
+ * If [isDefault] is true, it can also be an [Expression].
+ * Otherwise it can be a [VariableDeclarationList] or an [ExportClause].
+ */
+ final Node exported;
+
+ /** True if this is an `export default`. */
+ final bool isDefault;
+
+ ExportDeclaration(this.exported, {this.isDefault: false}) {
+ assert(exported is ClassDeclaration ||
+ exported is FunctionDeclaration ||
+ isDefault
+ ? exported is Expression
+ : exported is VariableDeclarationList ||
+ exported is ExportClause);
+ }
+
+ accept(NodeVisitor visitor) => visitor.visitExportDeclaration(this);
+ visitChildren(NodeVisitor visitor) => exported.accept(visitor);
+ ExportDeclaration _clone() =>
+ new ExportDeclaration(exported, isDefault: isDefault);
+}
+
+class ExportClause extends Node {
+ final List<NameSpecifier> exports;
+ final LiteralString from; // Can be null.
+
+ ExportClause(this.exports, {this.from});
+
+ /** The `export * from 'name.js'` form. */
+ ExportClause.star(LiteralString from)
+ : this([new NameSpecifier('*')], from: from);
+
+ /** True if this is an `export *`. */
+ bool get exportStar => exports.length == 1 && exports[0].name == '*';
+
+ accept(NodeVisitor visitor) => visitor.visitExportClause(this);
+ void visitChildren(NodeVisitor visitor) {
+ for (NameSpecifier name in exports) name.accept(visitor);
+ if (from != null) from.accept(visitor);
+ }
+ ExportClause _clone() => new ExportClause(exports, from: from);
+}
+
+/** An import or export specifier. */
+class NameSpecifier extends Node {
+ // TODO(jmesserly): should we wrap this in a node of some sort?
ochafik 2015/11/20 00:06:35 (we'd need a special node for *, but otherwise Ide
Jennifer Messerly 2015/11/23 22:08:12 yup, that's the main issue. The other one is that
+ final String name;
+ final String asName; // Can be null.
+
+ NameSpecifier(this.name, {this.asName});
+
+ accept(NodeVisitor visitor) => visitor.visitNameSpecifier(this);
+ void visitChildren(NodeVisitor visitor) {}
+ NameSpecifier _clone() => new NameSpecifier(name, asName: asName);
+}
+
+// TODO(jmesserly): should this be related to [Program]?
+class Module extends Node {
+ /// The module's name
+ // TODO(jmesserly): this is not declared in ES6, but is known by the loader.
+ // We use this because some ES5 desugarings require it.
+ final String name;
+
+ final List<ModuleItem> body;
+ Module(this.body, {this.name});
+
+ accept(NodeVisitor visitor) => visitor.visitModule(this);
+ void visitChildren(NodeVisitor visitor) {
+ for (ModuleItem item in body) item.accept(visitor);
+ }
+ Module _clone() => new Module(body);
+}
« no previous file with comments | « lib/src/js/module_transform.dart ('k') | lib/src/js/printer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698