Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion lib/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -1504,9 +1504,10 @@ var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", function AST_N

var AST_Import = DEFNODE(
"Import",
"imported_name imported_names module_name assert_clause",
"phase imported_name imported_names module_name assert_clause",
function AST_Import(props) {
if (props) {
this.phase = props.phase;
this.imported_name = props.imported_name;
this.imported_names = props.imported_names;
this.module_name = props.module_name;
Expand All @@ -1520,6 +1521,7 @@ var AST_Import = DEFNODE(
{
$documentation: "An `import` statement",
$propdoc: {
phase: "[string?] Phase keyword: 'source', 'defer', or null.",
imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
imported_names: "[AST_NameMapping*] The names of non-default imported variables",
module_name: "[AST_String] String literal describing where this module came from",
Expand Down Expand Up @@ -1560,6 +1562,40 @@ var AST_ImportMeta = DEFNODE("ImportMeta", null, function AST_ImportMeta(props)
$documentation: "A reference to import.meta",
});

var AST_DynamicImport = DEFNODE(
"DynamicImport",
"phase args",
function AST_DynamicImport(props) {
if (props) {
this.phase = props.phase;
this.args = props.args;
this.start = props.start;
this.end = props.end;
}

this.flags = 0;
},
{
$documentation: "A phased dynamic import expression: `import.source(specifier [, options])` or `import.defer(specifier [, options])`. Plain `import(x)` continues to be parsed as an AST_Call with a synthetic `import` SymbolRef callee.",
$propdoc: {
phase: "[string] Phase keyword ('source' or 'defer').",
args: "[AST_Node*] specifier followed by optional options argument"
},
_walk: function(visitor) {
return visitor._visit(this, function() {
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
});
},
_children_backwards(push) {
let i = this.args.length;
while (i--) push(this.args[i]);
},
}
);

var AST_Export = DEFNODE(
"Export",
"exported_definition exported_value is_default exported_names module_name assert_clause",
Expand Down Expand Up @@ -3264,6 +3300,7 @@ export {
AST_Function,
AST_Hole,
AST_If,
AST_DynamicImport,
AST_Import,
AST_ImportMeta,
AST_Infinity,
Expand Down
7 changes: 7 additions & 0 deletions lib/compress/drop-side-effect-free.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
AST_Constant,
AST_DefClass,
AST_Dot,
AST_DynamicImport,
AST_Expansion,
AST_Function,
AST_Node,
Expand Down Expand Up @@ -147,6 +148,12 @@ def_drop_side_effect_free(AST_Call, function (compressor, first_in_statement) {
return args && make_sequence(this, args);
});

def_drop_side_effect_free(AST_DynamicImport, function (compressor, first_in_statement) {
if (this.phase !== "source") return this;
var args = trim(this.args, compressor, first_in_statement);
return args && make_sequence(this, args);
});

def_drop_side_effect_free(AST_Accessor, return_null);

def_drop_side_effect_free(AST_Function, return_null);
Expand Down
5 changes: 5 additions & 0 deletions lib/compress/inference.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
AST_Function,
AST_If,
AST_Import,
AST_DynamicImport,
AST_ImportMeta,
AST_Jump,
AST_LabeledStatement,
Expand Down Expand Up @@ -314,6 +315,10 @@ export function is_nullish(node, compressor) {
|| this.alternative && this.alternative.has_side_effects(compressor);
});
def_has_side_effects(AST_ImportMeta, return_false);
def_has_side_effects(AST_DynamicImport, function() {
// `import.source(x)` only compiles the module, which is side-effect free
return this.phase !== "source";
});
def_has_side_effects(AST_LabeledStatement, function(compressor) {
return this.body.has_side_effects(compressor);
});
Expand Down
9 changes: 8 additions & 1 deletion lib/equivalent-to.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
AST_ForOf,
AST_If,
AST_Import,
AST_DynamicImport,
AST_ImportMeta,
AST_Jump,
AST_LabeledStatement,
Expand Down Expand Up @@ -190,11 +191,17 @@ AST_VarDef.prototype.shallow_cmp = function(other) {
AST_NameMapping.prototype.shallow_cmp = pass_through;

AST_Import.prototype.shallow_cmp = function(other) {
return (this.imported_name == null ? other.imported_name == null : this.imported_name === other.imported_name) && (this.imported_names == null ? other.imported_names == null : this.imported_names === other.imported_names);
return (this.imported_name || null) === (other.imported_name || null)
&& (this.imported_names || null) === (other.imported_names || null)
&& (this.phase || null) === (other.phase || null);
};

AST_ImportMeta.prototype.shallow_cmp = pass_through;

AST_DynamicImport.prototype.shallow_cmp = function(other) {
return (this.phase || null) === (other.phase || null) && this.args.length === other.args.length;
};

AST_Export.prototype.shallow_cmp = function(other) {
return (this.exported_definition == null ? other.exported_definition == null : this.exported_definition === other.exported_definition) && (this.exported_value == null ? other.exported_value == null : this.exported_value === other.exported_value) && (this.exported_names == null ? other.exported_names == null : this.exported_names === other.exported_names) && this.module_name === other.module_name && this.is_default === other.is_default;
};
Expand Down
56 changes: 41 additions & 15 deletions lib/mozilla-ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import {
AST_Function,
AST_Hole,
AST_If,
AST_DynamicImport,
AST_Import,
AST_ImportMeta,
AST_Label,
Expand Down Expand Up @@ -590,7 +591,8 @@ import { is_basic_identifier_string } from "./parse.js";
imported_name: imported_name,
imported_names : imported_names,
module_name : from_moz(M.source),
assert_clause: assert_clause_from_moz(M.assertions)
assert_clause: assert_clause_from_moz(M.assertions),
phase: M.phase || null
});
},

Expand All @@ -616,6 +618,31 @@ import { is_basic_identifier_string } from "./parse.js";
});
},

ImportExpression: function(M) {
const args = [from_moz(M.source)];
if (M.options) {
args.push(from_moz(M.options));
}
if (M.phase) {
return new AST_DynamicImport({
start: my_start_token(M),
end: my_end_token(M),
phase: M.phase,
args: args
});
}
return new AST_Call({
start: my_start_token(M),
end: my_end_token(M),
expression: from_moz({
type: "Identifier",
name: "import"
}),
optional: false,
args
});
},

ExportAllDeclaration: function(M) {
var foreign_name = M.exported == null ?
new AST_SymbolExportForeign({ name: "*" }) :
Expand Down Expand Up @@ -1028,19 +1055,6 @@ import { is_basic_identifier_string } from "./parse.js";
});
},

ImportExpression: function(M) {
let import_token = my_start_token(M);
return new AST_Call({
start : import_token,
end : my_end_token(M),
expression : new AST_SymbolRef({
start : import_token,
end : import_token,
name : "import"
}),
args : [from_moz(M.source)]
});
}
};

MOZ_TO_ME.UpdateExpression =
Expand Down Expand Up @@ -1261,6 +1275,16 @@ import { is_basic_identifier_string } from "./parse.js";
};
});

def_to_moz(AST_DynamicImport, function To_Moz_ImportExpression(M) {
const [source, options] = M.args.map(to_moz);
return {
type: "ImportExpression",
source,
options: options || null,
phase: M.phase
};
});

def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
return to_moz_scope("Program", M);
});
Expand Down Expand Up @@ -1488,12 +1512,14 @@ import { is_basic_identifier_string } from "./parse.js";
});
}
}
return {
var moz = {
type: "ImportDeclaration",
specifiers: specifiers,
source: to_moz(M.module_name),
assertions: assert_clause_to_moz(M.assert_clause)
};
if (M.phase) moz.phase = M.phase;
return moz;
});

def_to_moz(AST_ImportMeta, function To_Moz_MetaProperty() {
Expand Down
14 changes: 14 additions & 0 deletions lib/output.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import {
AST_Function,
AST_Hole,
AST_If,
AST_DynamicImport,
AST_Import,
AST_ImportMeta,
AST_Jump,
Expand Down Expand Up @@ -1697,6 +1698,10 @@ function OutputStream(options) {
DEFPRINT(AST_Import, function(self, output) {
output.print("import");
output.space();
if (self.phase) {
output.print(self.phase);
output.space();
}
if (self.imported_name) {
self.imported_name.print(output);
}
Expand Down Expand Up @@ -1737,6 +1742,15 @@ function OutputStream(options) {
DEFPRINT(AST_ImportMeta, function(self, output) {
output.print("import.meta");
});
DEFPRINT(AST_DynamicImport, function(self, output) {
output.print("import." + self.phase);
output.with_parens(function() {
self.args.forEach(function(arg, i) {
if (i) output.comma();
arg.print(output);
});
});
});

DEFPRINT(AST_NameMapping, function(self, output) {
var is_import = output.parent() instanceof AST_Import;
Expand Down
35 changes: 33 additions & 2 deletions lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import {
AST_Function,
AST_Hole,
AST_If,
AST_DynamicImport,
AST_Import,
AST_ImportMeta,
AST_IterationStatement,
Expand Down Expand Up @@ -2311,7 +2312,7 @@ function parse($TEXT, options) {
return new_(allow_calls);
}
if (is("name", "import") && is_token(peek(), "punc", ".")) {
return import_meta(allow_calls);
return parse_import_expr(allow_calls);
}
var start = S.token;
var peeked;
Expand Down Expand Up @@ -2771,6 +2772,17 @@ function parse($TEXT, options) {
function import_statement() {
var start = prev();

// import source x from "..."
// import defer * as x from "..."
var phase = null;
if (is("name", "source") || is("name", "defer")) {
var peeked = peek();
if (!is_token(peeked, "name", "from") && !is_token(peeked, "punc", ",")) {
phase = S.token.value;
next();
}
}

var imported_name;
var imported_names;
if (is("name")) {
Expand Down Expand Up @@ -2805,14 +2817,33 @@ function parse($TEXT, options) {
end: mod_str,
}),
assert_clause,
phase,
end: S.token,
});
}

function import_meta(allow_calls) {
// import.meta
// import.source("module")
// import.defer("module")
function parse_import_expr(allow_calls) {
var start = S.token;
expect_token("name", "import");
expect_token("punc", ".");
if (is("name", "source") || is("name", "defer")) {
var phase = S.token.value;
next();
if (!is("punc", "(")) {
croak("'import." + phase + "' can only be used in a dynamic import");
}
next();
var args = expr_list(")");
return subscripts(new AST_DynamicImport({
start: start,
phase: phase,
args: args,
end: prev()
}), allow_calls);
}
expect_token("name", "meta");
return subscripts(new AST_ImportMeta({
start: start,
Expand Down
6 changes: 6 additions & 0 deletions lib/size.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
AST_Hole,
AST_If,
AST_Import,
AST_DynamicImport,
AST_ImportMeta,
AST_Infinity,
AST_LabeledStatement,
Expand Down Expand Up @@ -270,6 +271,11 @@ AST_Import.prototype._size = function () {

AST_ImportMeta.prototype._size = () => 11;

AST_DynamicImport.prototype._size = function () {
// `import.` + phase + `()` + arg overhead
return 9 + this.phase.length + list_overhead(this.args);
};

AST_Export.prototype._size = function () {
let size = 7 + (this.is_default ? 8 : 0);

Expand Down
Loading
Loading