зеркало из https://github.com/mozilla/gecko-dev.git
Bug 927116 - Implement parser support for import declarations; r=jorendorff
This commit is contained in:
Родитель
f5eea02b5b
Коммит
a30d2750e1
|
@ -6447,6 +6447,11 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
: EmitVariables(cx, bce, pn, InitializeVars);
|
||||
break;
|
||||
|
||||
case PNK_IMPORT:
|
||||
// TODO: Implement emitter support for modules
|
||||
bce->reportError(nullptr, JSMSG_MODULES_NOT_IMPLEMENTED);
|
||||
return false;
|
||||
|
||||
case PNK_ARRAYPUSH: {
|
||||
int slot;
|
||||
|
||||
|
|
|
@ -295,6 +295,16 @@ class FullParseHandler
|
|||
return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr);
|
||||
}
|
||||
|
||||
ParseNode *newImportDeclaration(ParseNode *importSpecSet,
|
||||
ParseNode *moduleSpec, const TokenPos &pos)
|
||||
{
|
||||
ParseNode *pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos,
|
||||
importSpecSet, moduleSpec);
|
||||
if (!pn)
|
||||
return null();
|
||||
return pn;
|
||||
}
|
||||
|
||||
ParseNode *newExprStatement(ParseNode *expr, uint32_t end) {
|
||||
JS_ASSERT(expr->pn_pos.end <= end);
|
||||
return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr);
|
||||
|
|
|
@ -128,6 +128,9 @@ class UpvarCookie
|
|||
F(ARRAYPUSH) \
|
||||
F(LEXICALSCOPE) \
|
||||
F(LET) \
|
||||
F(IMPORT) \
|
||||
F(IMPORT_SPEC_LIST) \
|
||||
F(IMPORT_SPEC) \
|
||||
F(SEQ) \
|
||||
F(FORIN) \
|
||||
F(FOROF) \
|
||||
|
|
|
@ -3628,6 +3628,134 @@ Parser<SyntaxParseHandler>::letStatement()
|
|||
return SyntaxParseHandler::NodeFailure;
|
||||
}
|
||||
|
||||
template<typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::importDeclaration()
|
||||
{
|
||||
JS_ASSERT(tokenStream.currentToken().type == TOK_IMPORT);
|
||||
|
||||
if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) {
|
||||
report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
|
||||
return null();
|
||||
}
|
||||
|
||||
uint32_t begin = pos().begin;
|
||||
TokenKind tt = tokenStream.getToken();
|
||||
|
||||
Node importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST);
|
||||
if (!importSpecSet)
|
||||
return null();
|
||||
|
||||
if (tt == TOK_NAME || tt == TOK_LC) {
|
||||
if (tt == TOK_NAME) {
|
||||
// Handle the form |import a from 'b'|, by adding a single import
|
||||
// specifier to the list, with 'default' as the import name and
|
||||
// 'a' as the binding name. This is equivalent to
|
||||
// |import { default as a } from 'b'|.
|
||||
Node importName = newName(context->names().default_);
|
||||
if (!importName)
|
||||
return null();
|
||||
|
||||
Node bindingName = newName(tokenStream.currentName());
|
||||
if (!bindingName)
|
||||
return null();
|
||||
|
||||
Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importName, bindingName);
|
||||
if (!importSpec)
|
||||
return null();
|
||||
|
||||
handler.addList(importSpecSet, importSpec);
|
||||
} else {
|
||||
do {
|
||||
// Handle the forms |import {} from 'a'| and
|
||||
// |import { ..., } from 'a'| (where ... is non empty), by
|
||||
// escaping the loop early if the next token is }.
|
||||
tt = tokenStream.peekToken(TokenStream::KeywordIsName);
|
||||
if (tt == TOK_ERROR)
|
||||
return null();
|
||||
if (tt == TOK_RC)
|
||||
break;
|
||||
|
||||
// If the next token is a keyword, the previous call to
|
||||
// peekToken matched it as a TOK_NAME, and put it in the
|
||||
// lookahead buffer, so this call will match keywords as well.
|
||||
MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
|
||||
Node importName = newName(tokenStream.currentName());
|
||||
if (!importName)
|
||||
return null();
|
||||
|
||||
if (tokenStream.getToken() == TOK_NAME &&
|
||||
tokenStream.currentName() == context->names().as)
|
||||
{
|
||||
if (tokenStream.getToken() != TOK_NAME) {
|
||||
report(ParseError, false, null(), JSMSG_NO_BINDING_NAME);
|
||||
return null();
|
||||
}
|
||||
} else {
|
||||
// Keywords cannot be bound to themselves, so an import name
|
||||
// that is a keyword is a syntax error if it is not followed
|
||||
// by the keyword 'as'.
|
||||
if (IsKeyword(importName->name())) {
|
||||
JSAutoByteString bytes;
|
||||
if (!AtomToPrintableString(context, importName->name(), &bytes))
|
||||
return null();
|
||||
report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr());
|
||||
return null();
|
||||
}
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
Node bindingName = newName(tokenStream.currentName());
|
||||
if (!bindingName)
|
||||
return null();
|
||||
|
||||
Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importName, bindingName);
|
||||
if (!importSpec)
|
||||
return null();
|
||||
|
||||
handler.addList(importSpecSet, importSpec);
|
||||
} while (tokenStream.matchToken(TOK_COMMA));
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
|
||||
}
|
||||
|
||||
if (tokenStream.getToken() != TOK_NAME ||
|
||||
tokenStream.currentName() != context->names().from)
|
||||
{
|
||||
report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_SPEC_SET);
|
||||
return null();
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
|
||||
} else {
|
||||
if (tt != TOK_STRING) {
|
||||
report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT);
|
||||
return null();
|
||||
}
|
||||
|
||||
// Handle the form |import 'a'| by leaving the list empty. This is
|
||||
// equivalent to |import {} from 'a'|.
|
||||
importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
|
||||
}
|
||||
|
||||
Node moduleSpec = stringLiteral();
|
||||
if (!moduleSpec)
|
||||
return null();
|
||||
|
||||
if (!MatchOrInsertSemicolon(tokenStream))
|
||||
return null();
|
||||
|
||||
return handler.newImportDeclaration(importSpecSet, moduleSpec,
|
||||
TokenPos(begin, pos().end));
|
||||
}
|
||||
|
||||
template<>
|
||||
SyntaxParseHandler::Node
|
||||
Parser<SyntaxParseHandler>::importDeclaration()
|
||||
{
|
||||
JS_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return SyntaxParseHandler::NodeFailure;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::expressionStatement()
|
||||
|
@ -4907,6 +5035,8 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
|
|||
|
||||
case TOK_LET:
|
||||
return letStatement();
|
||||
case TOK_IMPORT:
|
||||
return importDeclaration();
|
||||
case TOK_SEMI:
|
||||
return handler.newEmptyStatement(pos());
|
||||
case TOK_IF:
|
||||
|
|
|
@ -512,6 +512,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter
|
|||
Node debuggerStatement();
|
||||
|
||||
Node letStatement();
|
||||
Node importDeclaration();
|
||||
Node expressionStatement();
|
||||
Node variables(ParseNodeKind kind, bool *psimple = nullptr,
|
||||
StaticBlockObject *blockObj = nullptr,
|
||||
|
|
|
@ -417,3 +417,13 @@ MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 363, 1, JSEXN_TYPEERR, "No such property
|
|||
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 364, 2, JSEXN_TYPEERR, "argument {0} invalid: expected {1}")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 365, 0, JSEXN_TYPEERR, "handle unattached")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 366, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type")
|
||||
|
||||
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 367, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level")
|
||||
MSG_DEF(JSMSG_NO_IMPORT_NAME, 368, 0, JSEXN_SYNTAXERR, "missing import name")
|
||||
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 369, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
|
||||
MSG_DEF(JSMSG_NO_BINDING_NAME, 370, 0, JSEXN_SYNTAXERR, "missing binding name")
|
||||
MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 371, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
|
||||
MSG_DEF(JSMSG_FROM_AFTER_IMPORT_SPEC_SET, 372, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import specifier set")
|
||||
MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT, 373, 0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword")
|
||||
MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM, 374, 0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword")
|
||||
MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED, 375, 0, JSEXN_SYNTAXERR, "modules are not implemented yet")
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
macro(anonymous, anonymous, "anonymous") \
|
||||
macro(apply, apply, "apply") \
|
||||
macro(arguments, arguments, "arguments") \
|
||||
macro(as, as, "as") \
|
||||
macro(ArrayType, ArrayType, "ArrayType") \
|
||||
macro(buffer, buffer, "buffer") \
|
||||
macro(builder, builder, "builder") \
|
||||
|
@ -43,6 +44,7 @@
|
|||
macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \
|
||||
macro(decodeURI, decodeURI, "decodeURI") \
|
||||
macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
|
||||
macro(default_, default_, "default") \
|
||||
macro(defineProperty, defineProperty, "defineProperty") \
|
||||
macro(defineGetter, defineGetter, "__defineGetter__") \
|
||||
macro(defineSetter, defineSetter, "__defineSetter__") \
|
||||
|
@ -68,6 +70,7 @@
|
|||
macro(float32, float32, "float32") \
|
||||
macro(float64, float64, "float64") \
|
||||
macro(format, format, "format") \
|
||||
macro(from, from, "from") \
|
||||
macro(get, get, "get") \
|
||||
macro(getInternals, getInternals, "getInternals") \
|
||||
macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
|
||||
|
|
|
@ -41,12 +41,12 @@
|
|||
macro(void, void_, TOK_VOID, JSVERSION_DEFAULT) \
|
||||
macro(while, while_, TOK_WHILE, JSVERSION_DEFAULT) \
|
||||
macro(with, with, TOK_WITH, JSVERSION_DEFAULT) \
|
||||
macro(import, import, TOK_IMPORT, JSVERSION_DEFAULT) \
|
||||
/* Reserved keywords. */ \
|
||||
macro(class, class_, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(enum, enum_, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(export, export, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(extends, extends, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(import, import, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
macro(super, super, TOK_RESERVED, JSVERSION_DEFAULT) \
|
||||
/* Future reserved keywords, but only in strict mode. */ \
|
||||
macro(implements, implements, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче