mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Dynamic import (#5169)
* dynamic import * updated grammar * specify callable * DynamicImportCall * Fix from code review Co-Authored-By: helixbass <julian@helixbass.net> * recompile
This commit is contained in:
parent
ca275c2a1c
commit
ff24e5ce52
10 changed files with 302 additions and 196 deletions
|
@ -332,6 +332,11 @@
|
|||
false,
|
||||
$1);
|
||||
}),
|
||||
o('DYNAMIC_IMPORT Arguments',
|
||||
function() {
|
||||
return new DynamicImportCall(LOC(1)(new DynamicImport),
|
||||
$2);
|
||||
}),
|
||||
o('SimpleObjAssignable Arguments',
|
||||
function() {
|
||||
return new Call(new Value($1),
|
||||
|
@ -941,6 +946,11 @@
|
|||
$3,
|
||||
$2,
|
||||
$1);
|
||||
}),
|
||||
o('DYNAMIC_IMPORT Arguments',
|
||||
function() {
|
||||
return new DynamicImportCall(LOC(1)(new DynamicImport),
|
||||
$2);
|
||||
})
|
||||
],
|
||||
// An optional existence check on a function.
|
||||
|
@ -2113,7 +2123,7 @@
|
|||
// And not:
|
||||
|
||||
// (2 + 3) * 4
|
||||
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT'], ['left', 'POST_IF']];
|
||||
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT'], ['left', 'POST_IF']];
|
||||
|
||||
// Wrapping Up
|
||||
// -----------
|
||||
|
|
|
@ -889,6 +889,9 @@
|
|||
return value.length;
|
||||
}
|
||||
}
|
||||
if (value === '(' && (prev != null ? prev[0] : void 0) === 'IMPORT') {
|
||||
prev[0] = 'DYNAMIC_IMPORT';
|
||||
}
|
||||
if (value === '{' && this.seenImport) {
|
||||
this.importSpecifierList = true;
|
||||
} else if (this.importSpecifierList && value === '}') {
|
||||
|
@ -1685,7 +1688,7 @@
|
|||
// Tokens which could legitimately be invoked or indexed. An opening
|
||||
// parentheses or bracket following these tokens will be recorded as the start
|
||||
// of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER'];
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER', 'DYNAMIC_IMPORT'];
|
||||
|
||||
INDEXABLE = CALLABLE.concat(['NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END', 'BOOL', 'NULL', 'UNDEFINED', '}', '::']);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// nodes are created as the result of actions in the [grammar](grammar.html),
|
||||
// but some are created by other nodes as a method of code generation. To convert
|
||||
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
|
||||
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, moveComments, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
||||
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, DynamicImport, DynamicImportCall, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, JS_FORBIDDEN, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, SIMPLENUM, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, hasLineComments, indentInitial, isLiteralArguments, isLiteralThis, isUnassignable, locationDataToString, merge, moveComments, multident, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
|
||||
indexOf = [].indexOf,
|
||||
splice = [].splice,
|
||||
slice1 = [].slice;
|
||||
|
@ -3262,6 +3262,23 @@
|
|||
|
||||
};
|
||||
|
||||
exports.DynamicImport = DynamicImport = class DynamicImport extends Base {
|
||||
compileNode() {
|
||||
return [this.makeCode('import')];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.DynamicImportCall = DynamicImportCall = class DynamicImportCall extends Call {
|
||||
compileNode(o) {
|
||||
if (this.args.length !== 1) {
|
||||
this.error('import() requires exactly one argument');
|
||||
}
|
||||
return super.compileNode(o);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//### Assign
|
||||
|
||||
// The **Assign** is used to assign a local variable to value, or to set the
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -240,6 +240,7 @@ grammar =
|
|||
o 'Super'
|
||||
o 'This'
|
||||
o 'SUPER Arguments', -> new SuperCall LOC(1)(new Super), $2, no, $1
|
||||
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
|
||||
o 'SimpleObjAssignable Arguments', -> new Call (new Value $1), $2
|
||||
o 'ObjSpreadExpr Arguments', -> new Call $1, $2
|
||||
]
|
||||
|
@ -485,6 +486,7 @@ grammar =
|
|||
o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2
|
||||
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
|
||||
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2, $1
|
||||
o 'DYNAMIC_IMPORT Arguments', -> new DynamicImportCall LOC(1)(new DynamicImport), $2
|
||||
]
|
||||
|
||||
# An optional existence check on a function.
|
||||
|
@ -891,7 +893,7 @@ operators = [
|
|||
['right', 'YIELD']
|
||||
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
|
||||
['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT']
|
||||
['left', 'POST_IF']
|
||||
]
|
||||
|
||||
|
|
|
@ -667,6 +667,9 @@ exports.Lexer = class Lexer
|
|||
@error message, origin[2] if message
|
||||
return value.length if skipToken
|
||||
|
||||
if value is '(' and prev?[0] is 'IMPORT'
|
||||
prev[0] = 'DYNAMIC_IMPORT'
|
||||
|
||||
if value is '{' and @seenImport
|
||||
@importSpecifierList = yes
|
||||
else if @importSpecifierList and value is '}'
|
||||
|
@ -1356,7 +1359,7 @@ BOOL = ['TRUE', 'FALSE']
|
|||
# Tokens which could legitimately be invoked or indexed. An opening
|
||||
# parentheses or bracket following these tokens will be recorded as the start
|
||||
# of a function invocation or indexing operation.
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER']
|
||||
CALLABLE = ['IDENTIFIER', 'PROPERTY', ')', ']', '?', '@', 'THIS', 'SUPER', 'DYNAMIC_IMPORT']
|
||||
INDEXABLE = CALLABLE.concat [
|
||||
'NUMBER', 'INFINITY', 'NAN', 'STRING', 'STRING_END', 'REGEX', 'REGEX_END'
|
||||
'BOOL', 'NULL', 'UNDEFINED', '}', '::'
|
||||
|
|
|
@ -2172,6 +2172,16 @@ exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier
|
|||
constructor: (local, exported) ->
|
||||
super local, exported, 'export'
|
||||
|
||||
exports.DynamicImport = class DynamicImport extends Base
|
||||
compileNode: ->
|
||||
[@makeCode 'import']
|
||||
|
||||
exports.DynamicImportCall = class DynamicImportCall extends Call
|
||||
compileNode: (o) ->
|
||||
unless @args.length is 1
|
||||
@error 'import() requires exactly one argument'
|
||||
super o
|
||||
|
||||
#### Assign
|
||||
|
||||
# The **Assign** is used to assign a local variable to value, or to set the
|
||||
|
|
|
@ -1925,3 +1925,29 @@ test "`new.target` is only allowed meta property", ->
|
|||
-> new.something
|
||||
^^^^^^^^^^^^^
|
||||
'''
|
||||
|
||||
test "#4834: dynamic import requires exactly one argument", ->
|
||||
assertErrorFormat '''
|
||||
import()
|
||||
''', '''
|
||||
[stdin]:1:1: error: import() requires exactly one argument
|
||||
import()
|
||||
^^^^^^^^
|
||||
'''
|
||||
|
||||
assertErrorFormat '''
|
||||
import('x', {})
|
||||
''', '''
|
||||
[stdin]:1:1: error: import() requires exactly one argument
|
||||
import('x', {})
|
||||
^^^^^^^^^^^^^^^
|
||||
'''
|
||||
|
||||
test "#4834: dynamic import requires explicit call parentheses", ->
|
||||
assertErrorFormat '''
|
||||
promise = import 'foo'
|
||||
''', '''
|
||||
[stdin]:1:23: error: unexpected end of input
|
||||
promise = import 'foo'
|
||||
^
|
||||
'''
|
||||
|
|
|
@ -920,3 +920,24 @@ test "#4874: backslash `export`", ->
|
|||
min
|
||||
} from 'underscore';
|
||||
"""
|
||||
|
||||
test "#4834: dynamic import", ->
|
||||
eqJS """
|
||||
import('module').then ->
|
||||
""",
|
||||
"""
|
||||
import('module').then(function() {});
|
||||
"""
|
||||
|
||||
eqJS """
|
||||
foo = ->
|
||||
bar = await import('bar')
|
||||
""",
|
||||
"""
|
||||
var foo;
|
||||
|
||||
foo = async function() {
|
||||
var bar;
|
||||
return bar = (await import('bar'));
|
||||
};
|
||||
"""
|
||||
|
|
|
@ -418,3 +418,13 @@ test "#4673: complex destructured object spread variables", ->
|
|||
g = ({@y...}) ->
|
||||
eq @y.b, 1
|
||||
g b: 1
|
||||
|
||||
test "#4834: dynamic import can technically be object spread", ->
|
||||
eqJS """
|
||||
x = {...import('module')}
|
||||
""",
|
||||
"""
|
||||
var x;
|
||||
|
||||
x = {...import('module')};
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue