Bug 927116 - Implement parser support for import declarations; r=jorendorff

This commit is contained in:
Eddy Bruel 2013-11-06 20:04:12 +01:00
Родитель f5eea02b5b
Коммит a30d2750e1
8 изменённых файлов: 163 добавлений и 1 удалений

Просмотреть файл

@ -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) \