diff --git a/include/hermes/AST/ESTree.def b/include/hermes/AST/ESTree.def index 4a47c41f768..d0446e74d2a 100644 --- a/include/hermes/AST/ESTree.def +++ b/include/hermes/AST/ESTree.def @@ -372,16 +372,13 @@ ESTREE_NODE_3_ARGS( ESTREE_NODE_1_ARGS(Directive, Base, NodePtr, value, false) ESTREE_NODE_1_ARGS(DirectiveLiteral, Base, NodeLabel, value, false) -ESTREE_NODE_2_ARGS( - Identifier, - Base, - NodeLabel, - name, - false, - NodePtr, - typeAnnotation, - true) +ESTREE_NODE_3_ARGS( + Identifier, Base, + NodeLabel, name, false, + NodePtr, typeAnnotation, true, + NodeBoolean, optional, false) ESTREE_IGNORE_IF_EMPTY(Identifier, typeAnnotation) +ESTREE_IGNORE_IF_EMPTY(Identifier, optional) ESTREE_NODE_2_ARGS( MetaProperty, @@ -942,10 +939,11 @@ ESTREE_NODE_1_ARGS( // 'right' is the type which is either the cast target or the type annotation, // which may be null if the identifier was simply given a '?' and no ':' // with a type annotation. -ESTREE_NODE_2_ARGS( +ESTREE_NODE_3_ARGS( CoverTypedIdentifier, Cover, NodePtr, left, false, - NodePtr, right, true) + NodePtr, right, true, + NodeBoolean, optional, false) ESTREE_LAST(Cover) diff --git a/lib/AST/CommonJS.cpp b/lib/AST/CommonJS.cpp index cb929b0d4fd..ae54cc9b90b 100644 --- a/lib/AST/CommonJS.cpp +++ b/lib/AST/CommonJS.cpp @@ -21,11 +21,11 @@ ESTree::FunctionExpressionNode *wrapCJSModule( // Identifiers for function arguments. auto *exports = new (*context) ESTree::IdentifierNode( - context->getIdentifier("exports").getUnderlyingPointer(), nullptr); + context->getIdentifier("exports").getUnderlyingPointer(), nullptr, false); auto *require = new (*context) ESTree::IdentifierNode( - context->getIdentifier("require").getUnderlyingPointer(), nullptr); + context->getIdentifier("require").getUnderlyingPointer(), nullptr, false); auto *module = new (*context) ESTree::IdentifierNode( - context->getIdentifier("module").getUnderlyingPointer(), nullptr); + context->getIdentifier("module").getUnderlyingPointer(), nullptr, false); argNames.push_back(*exports); argNames.push_back(*require); argNames.push_back(*module); diff --git a/lib/AST/ESTreeJSONDumper.cpp b/lib/AST/ESTreeJSONDumper.cpp index 2a3a61e600c..f508037b18b 100644 --- a/lib/AST/ESTreeJSONDumper.cpp +++ b/lib/AST/ESTreeJSONDumper.cpp @@ -133,7 +133,7 @@ class ESTreeJSONDumper { } static bool isEmpty(NodeBoolean val) { - return false; + return !val; } static bool isEmpty(NodeNumber num) { diff --git a/lib/Parser/JSParserImpl-flow.cpp b/lib/Parser/JSParserImpl-flow.cpp index 840cbf37bf8..fec18da166c 100644 --- a/lib/Parser/JSParserImpl-flow.cpp +++ b/lib/Parser/JSParserImpl-flow.cpp @@ -129,7 +129,8 @@ Optional JSParserImpl::parseTypeAlias( ESTree::Node *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); SMLoc end = id->getEndLoc(); advance(JSLexer::GrammarContext::Flow); @@ -210,7 +211,8 @@ Optional JSParserImpl::parseInterfaceDeclaration(bool declare) { auto *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(JSLexer::GrammarContext::Flow); ESTree::Node *typeParams = nullptr; @@ -349,7 +351,7 @@ Optional JSParserImpl::parseDeclareFunction(SMLoc start) { new (context_) ESTree::FunctionTypeAnnotationNode( std::move(params), returnType, *optRest, typeParams)))); auto *ident = setLocation( - idStart, func, new (context_) ESTree::IdentifierNode(id, func)); + idStart, func, new (context_) ESTree::IdentifierNode(id, func, false)); return setLocation( start, ident, @@ -401,7 +403,8 @@ Optional JSParserImpl::parseDeclareModule(SMLoc start) { id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); } advance(JSLexer::GrammarContext::Flow); @@ -511,7 +514,8 @@ Optional JSParserImpl::parseDeclareClass(SMLoc start) { auto *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(JSLexer::GrammarContext::Flow); ESTree::Node *typeParams = nullptr; @@ -1463,8 +1467,8 @@ bool JSParserImpl::parsePropertyTypeAnnotation( ESTree::IdentifierNode *id = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); advance(JSLexer::GrammarContext::Flow); if (!eat( @@ -1552,7 +1556,7 @@ bool JSParserImpl::parsePropertyTypeAnnotation( key = setLocation( startRange, startRange, - new (context_) ESTree::IdentifierNode(staticIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(staticIdent_, nullptr, false)); auto optProp = parseTypeProperty(start, variance, isStatic, key); if (!optProp) return false; @@ -2023,8 +2027,8 @@ Optional JSParserImpl::parseGenericType() { ESTree::Node *id = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); advance(JSLexer::GrammarContext::Flow); while (checkAndEat(TokenKind::period, JSLexer::GrammarContext::Flow)) { @@ -2039,8 +2043,8 @@ Optional JSParserImpl::parseGenericType() { ESTree::Node *next = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); advance(JSLexer::GrammarContext::Flow); id = setLocation( id, next, new (context_) ESTree::QualifiedTypeIdentifierNode(id, next)); @@ -2069,7 +2073,8 @@ Optional JSParserImpl::parseClassImplements() { ESTree::Node *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); SMLoc end = advance(JSLexer::GrammarContext::Flow).End; ESTree::Node *typeParams = nullptr; @@ -2137,7 +2142,7 @@ JSParserImpl::reparseTypeAnnotationAsIdentifier(ESTree::Node *typeAnnotation) { return setLocation( typeAnnotation, typeAnnotation, - new (context_) ESTree::IdentifierNode(id, nullptr)); + new (context_) ESTree::IdentifierNode(id, nullptr, false)); } Optional JSParserImpl::parseEnumDeclaration() { @@ -2314,7 +2319,8 @@ Optional JSParserImpl::parseEnumMember() { ESTree::Node *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(); ESTree::Node *member = nullptr; diff --git a/lib/Parser/JSParserImpl.cpp b/lib/Parser/JSParserImpl.cpp index 00db3bee6ec..264c7841825 100644 --- a/lib/Parser/JSParserImpl.cpp +++ b/lib/Parser/JSParserImpl.cpp @@ -874,12 +874,10 @@ Optional JSParserImpl::parseBindingIdentifier( advance(); ESTree::Node *type = nullptr; + bool optional = false; #if HERMES_PARSE_FLOW if (context_.getParseFlow()) { - if (checkAndEat(TokenKind::question)) { - // TODO: Store `optional` to the IdentifierNode. - } - + optional = checkAndEat(TokenKind::question); if (check(TokenKind::colon)) { SMLoc annotStart = advance(JSLexer::GrammarContext::Flow).Start; auto optType = parseTypeAnnotation(annotStart); @@ -893,7 +891,7 @@ Optional JSParserImpl::parseBindingIdentifier( return setLocation( identRng, type ? type->getSourceRange() : identRng, - new (context_) ESTree::IdentifierNode(id, type)); + new (context_) ESTree::IdentifierNode(id, type, optional)); } Optional @@ -1283,7 +1281,7 @@ Optional JSParserImpl::parseBindingProperty( auto *left = setLocation( ident, ident, - new (context_) ESTree::IdentifierNode(ident->_name, nullptr)); + new (context_) ESTree::IdentifierNode(ident->_name, nullptr, false)); auto optInit = parseBindingInitializer(param + ParamIn, left); if (!optInit) return None; @@ -1296,7 +1294,7 @@ Optional JSParserImpl::parseBindingProperty( value = setLocation( ident, ident, - new (context_) ESTree::IdentifierNode(ident->_name, nullptr)); + new (context_) ESTree::IdentifierNode(ident->_name, nullptr, false)); } } @@ -1727,7 +1725,8 @@ JSParserImpl::parseContinueStatement() { auto *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(); loc.End = id->getEndLoc(); @@ -1755,7 +1754,8 @@ Optional JSParserImpl::parseBreakStatement() { auto *id = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + new (context_) + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(); loc.End = id->getEndLoc(); @@ -2112,7 +2112,7 @@ Optional JSParserImpl::parsePrimaryExpression() { tok_, tok_, new (context_) - ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(JSLexer::AllowDiv); return res; } @@ -2208,7 +2208,7 @@ Optional JSParserImpl::parsePrimaryExpression() { #if HERMES_PARSE_FLOW if (context_.getParseFlow()) { if (auto *cover = dyn_cast(expr)) { - if (cover->_right) { + if (cover->_right && !cover->_optional) { expr = setLocation( expr, expr, @@ -2419,7 +2419,7 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); #if HERMES_PARSE_FLOW } else if (context_.getParseFlow() && check(TokenKind::less)) { // This is a method definition. @@ -2427,7 +2427,7 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); #endif } else if (check(TokenKind::comma, TokenKind::r_brace)) { // If the next token is "," or "}", this is a shorthand property @@ -2435,9 +2435,11 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); auto *value = setLocation( - key, key, new (context_) ESTree::IdentifierNode(ident, nullptr)); + key, + key, + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); return setLocation( startLoc, value, @@ -2515,7 +2517,7 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); #if HERMES_PARSE_FLOW } else if (context_.getParseFlow() && check(TokenKind::less)) { // This is a method definition. @@ -2523,7 +2525,7 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); #endif } else if (check(TokenKind::comma, TokenKind::r_brace)) { // If the next token is "," or "}", this is a shorthand property @@ -2531,9 +2533,11 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); auto *value = setLocation( - key, key, new (context_) ESTree::IdentifierNode(ident, nullptr)); + key, + key, + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); return setLocation( startLoc, value, @@ -2617,7 +2621,7 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); #if HERMES_PARSE_FLOW } else if (context_.getParseFlow() && check(TokenKind::less)) { // This is a method definition. @@ -2625,7 +2629,7 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); #endif } else if (check(TokenKind::comma, TokenKind::r_brace)) { // If the next token is "," or "}", this is a shorthand property @@ -2633,9 +2637,11 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { key = setLocation( identRng, identRng, - new (context_) ESTree::IdentifierNode(ident, nullptr)); + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); auto *value = setLocation( - key, key, new (context_) ESTree::IdentifierNode(ident, nullptr)); + key, + key, + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); return setLocation( startLoc, value, @@ -2656,12 +2662,16 @@ Optional JSParserImpl::parsePropertyAssignment(bool eagerly) { } else if (check(TokenKind::identifier)) { auto *ident = tok_->getIdentifier(); key = setLocation( - tok_, tok_, new (context_) ESTree::IdentifierNode(ident, nullptr)); + tok_, + tok_, + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); advance(); // If the next token is "," or "}", this is a shorthand property definition. if (check(TokenKind::comma, TokenKind::r_brace)) { auto *value = setLocation( - key, key, new (context_) ESTree::IdentifierNode(ident, nullptr)); + key, + key, + new (context_) ESTree::IdentifierNode(ident, nullptr, false)); return setLocation( startLoc, @@ -2817,7 +2827,7 @@ Optional JSParserImpl::parsePropertyName() { tok_, tok_, new (context_) - ESTree::IdentifierNode(tok_->getIdentifier(), nullptr)); + ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false)); advance(); return res; } @@ -2844,8 +2854,8 @@ Optional JSParserImpl::parsePropertyName() { auto *res = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordIdentifier(), nullptr, false)); advance(); return res; } else { @@ -3161,8 +3171,8 @@ Optional JSParserImpl::parseMemberSelect( auto *id = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); advance(JSLexer::AllowDiv); if (optional || seenOptionalChain) { @@ -3354,11 +3364,11 @@ Optional JSParserImpl::parseNewExpressionOrOptionalExpression( auto *meta = setLocation( newRange, newRange, - new (context_) ESTree::IdentifierNode(newIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(newIdent_, nullptr, false)); auto *prop = setLocation( tok_, tok_, - new (context_) ESTree::IdentifierNode(targetIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(targetIdent_, nullptr, false)); advance(); auto *expr = setLocation( meta, prop, new (context_) ESTree::MetaPropertyNode(meta, prop)); @@ -3699,7 +3709,7 @@ Optional JSParserImpl::parseConditionalExpression( #if HERMES_PARSE_FLOW if (context_.getParseFlow() && coverTypedParameters == CoverTypedParameters::Yes) { - auto optCover = tryParseCoverTypedIdentifierNode(test); + auto optCover = tryParseCoverTypedIdentifierNode(test, false); if (!optCover) return None; if (*optCover) @@ -3727,7 +3737,7 @@ Optional JSParserImpl::parseConditionalExpression( // in which case the '?' was part of an optional parameter, not a // conditional expression. if (coverTypedParameters == CoverTypedParameters::Yes) { - auto optCover = tryParseCoverTypedIdentifierNode(test); + auto optCover = tryParseCoverTypedIdentifierNode(test, true); if (!optCover) return None; if (*optCover) @@ -3742,11 +3752,10 @@ Optional JSParserImpl::parseConditionalExpression( // The tokens which can come here are limited to ',', '=', and ')'. if (coverTypedParameters == CoverTypedParameters::Yes && checkN(TokenKind::comma, TokenKind::r_paren, TokenKind::equal)) { - // TODO: Store `optional` to the IdentifierNode. return setLocation( test, questionLoc, - new (context_) ESTree::CoverTypedIdentifierNode(test, nullptr)); + new (context_) ESTree::CoverTypedIdentifierNode(test, nullptr, true)); } // Now we're in the real backtracking stage. @@ -3812,7 +3821,8 @@ Optional JSParserImpl::parseConditionalExpression( #if HERMES_PARSE_FLOW Optional JSParserImpl::tryParseCoverTypedIdentifierNode( - ESTree::Node *test) { + ESTree::Node *test, + bool optional) { assert(context_.getParseFlow() && "must be parsing Flow"); // In the case of flow types in arrow function parameters, we may have // optional parameters which look like: @@ -3825,29 +3835,18 @@ Optional JSParserImpl::tryParseCoverTypedIdentifierNode( if (isa(test) || isa(test) || isa(test)) { - ESTree::Node *type = nullptr; - bool optional = false; - if (check(TokenKind::question)) { - auto optNext = lexer_.lookahead1(None); - if (optNext.hasValue() && - (*optNext == TokenKind::colon || *optNext == TokenKind::comma || - *optNext == TokenKind::r_paren)) { - optional = true; - } - } - if (check(TokenKind::colon)) { - // Deliberately wrap the type annotation later when reparsing. - SMLoc annotStart = advance(JSLexer::GrammarContext::Flow).Start; - auto optRet = parseTypeAnnotation(annotStart); - if (!optRet) - return None; - type = *optRet; - } - // TODO: Store `optional` to the IdentifierNode. + // Deliberately wrap the type annotation later when reparsing. + SMLoc annotStart = advance(JSLexer::GrammarContext::Flow).Start; + auto optRet = parseTypeAnnotation(annotStart); + if (!optRet) + return None; + ESTree::Node *type = *optRet; + return setLocation( test, type, - new (context_) ESTree::CoverTypedIdentifierNode(test, type)); + new (context_) + ESTree::CoverTypedIdentifierNode(test, type, optional)); } // The colon must indicate something another than the typeAnnotation for // the parameter. Continue as usual. @@ -4175,7 +4174,7 @@ Optional JSParserImpl::parseClassElement( prop = setLocation( range, range, - new (context_) ESTree::IdentifierNode(getIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(getIdent_, nullptr, false)); doParsePropertyName = false; } } else if (check(setIdent_)) { @@ -4193,7 +4192,7 @@ Optional JSParserImpl::parseClassElement( prop = setLocation( range, range, - new (context_) ESTree::IdentifierNode(setIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(setIdent_, nullptr, false)); doParsePropertyName = false; } } else if (check(asyncIdent_)) { @@ -4215,7 +4214,7 @@ Optional JSParserImpl::parseClassElement( prop = setLocation( range, range, - new (context_) ESTree::IdentifierNode(asyncIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(asyncIdent_, nullptr, false)); doParsePropertyName = false; } } else if (checkAndEat(TokenKind::star)) { @@ -4227,7 +4226,7 @@ Optional JSParserImpl::parseClassElement( prop = setLocation( startRange, startRange, - new (context_) ESTree::IdentifierNode(staticIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(staticIdent_, nullptr, false)); isStatic = false; doParsePropertyName = false; } @@ -4647,6 +4646,7 @@ Optional JSParserImpl::reparseAssignmentPattern( } if (auto *id = dyn_cast(*optAssn)) { id->_typeAnnotation = type; + id->_optional = cover->_optional; return id; } } @@ -4819,8 +4819,8 @@ Optional JSParserImpl::reparseObjectAssignmentPattern( "CoverInitializedName must start with an identifier"); // Clone the key. auto *ident = cast(propNode->_key); - value = new (context_) - ESTree::IdentifierNode(ident->_name, ident->_typeAnnotation); + value = new (context_) ESTree::IdentifierNode( + ident->_name, ident->_typeAnnotation, ident->_optional); value->copyLocationFrom(propNode->_key); init = coverInitializer->_init; @@ -5278,7 +5278,7 @@ Optional JSParserImpl::parseImportClause( auto *defaultBinding = setLocation( kindRange, kindRange, - new (context_) ESTree::IdentifierNode(typeIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(typeIdent_, nullptr, false)); specifiers.push_back(*setLocation( defaultBinding, defaultBinding, @@ -5438,7 +5438,7 @@ Optional JSParserImpl::parseImportSpecifier( imported = setLocation( typeRange, typeRange, - new (context_) ESTree::IdentifierNode(typeIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(typeIdent_, nullptr, false)); local = imported; localKind = TokenKind::identifier; endLoc = imported->getEndLoc(); @@ -5450,7 +5450,7 @@ Optional JSParserImpl::parseImportSpecifier( imported = setLocation( asRange, asRange, - new (context_) ESTree::IdentifierNode(asIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(asIdent_, nullptr, false)); local = imported; localKind = TokenKind::identifier; endLoc = advance().End; @@ -5469,12 +5469,12 @@ Optional JSParserImpl::parseImportSpecifier( imported = setLocation( asRange, asRange, - new (context_) ESTree::IdentifierNode(asIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(asIdent_, nullptr, false)); local = setLocation( tok_, tok_, new (context_) ESTree::IdentifierNode( - tok_->getResWordOrIdentifier(), nullptr)); + tok_->getResWordOrIdentifier(), nullptr, false)); localKind = TokenKind::identifier; endLoc = advance().End; } else { @@ -5491,12 +5491,12 @@ Optional JSParserImpl::parseImportSpecifier( imported = setLocation( typeRange, typeRange, - new (context_) ESTree::IdentifierNode(typeIdent_, nullptr)); + new (context_) ESTree::IdentifierNode(typeIdent_, nullptr, false)); local = setLocation( tok_, tok_, new (context_) ESTree::IdentifierNode( - tok_->getResWordOrIdentifier(), nullptr)); + tok_->getResWordOrIdentifier(), nullptr, false)); localKind = TokenKind::identifier; endLoc = advance().End; } @@ -5515,8 +5515,8 @@ Optional JSParserImpl::parseImportSpecifier( imported = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); local = imported; localKind = tok_->getKind(); endLoc = advance().End; @@ -5535,7 +5535,7 @@ Optional JSParserImpl::parseImportSpecifier( tok_, tok_, new (context_) ESTree::IdentifierNode( - tok_->getResWordOrIdentifier(), nullptr)); + tok_->getResWordOrIdentifier(), nullptr, false)); localKind = tok_->getKind(); endLoc = advance().End; } @@ -5553,8 +5553,8 @@ Optional JSParserImpl::parseImportSpecifier( imported = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); local = imported; localKind = tok_->getKind(); endLoc = advance().End; @@ -5571,8 +5571,8 @@ Optional JSParserImpl::parseImportSpecifier( local = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); localKind = tok_->getKind(); endLoc = advance().End; } @@ -5814,8 +5814,8 @@ Optional JSParserImpl::parseExportSpecifier( auto *local = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); advance(); ESTree::Node *exported; if (checkAndEat(asIdent_)) { @@ -5831,8 +5831,8 @@ Optional JSParserImpl::parseExportSpecifier( exported = setLocation( tok_, tok_, - new (context_) - ESTree::IdentifierNode(tok_->getResWordOrIdentifier(), nullptr)); + new (context_) ESTree::IdentifierNode( + tok_->getResWordOrIdentifier(), nullptr, false)); advance(); } else { // IdentifierName diff --git a/lib/Parser/JSParserImpl.h b/lib/Parser/JSParserImpl.h index dbde587f7bd..8fcda4a32bc 100644 --- a/lib/Parser/JSParserImpl.h +++ b/lib/Parser/JSParserImpl.h @@ -865,10 +865,14 @@ class JSParserImpl { /// Attempt to parse a CoverTypedIdentifierNode which consists of a /// node which may be an arrow parameter, a colon, and a type. /// \param test the LHS of the potential CoverTypedIdentifierNode. + /// \param optional whether the potential CoverTypedIdentifierNode is + /// optional, meaning there was a question mark preceding the type annotation /// \return nullptr if there was no error but attempting to parse the /// node is not possible because \p test can't be a formal parameter, /// or there wasn't a colon in the first place, None on error. - Optional tryParseCoverTypedIdentifierNode(ESTree::Node *test); + Optional tryParseCoverTypedIdentifierNode( + ESTree::Node *test, + bool optional); #endif /// Reparse an ArrayExpression into an ArrayPattern. diff --git a/test/AST/dump-ast.js b/test/AST/dump-ast.js index 8d81026795f..ef93990dcdc 100644 --- a/test/AST/dump-ast.js +++ b/test/AST/dump-ast.js @@ -767,7 +767,8 @@ switch (foo()) { // CHECK-FULL: "id": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "foo", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "params": [], // CHECK-FULL: "body": { @@ -782,12 +783,14 @@ switch (foo()) { // CHECK-FULL: "object": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "Math", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "property": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "random", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "computed": false // CHECK-FULL: }, @@ -809,7 +812,8 @@ switch (foo()) { // CHECK-FULL: "callee": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "foo", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "typeArguments": null, // CHECK-FULL: "arguments": [] @@ -830,7 +834,8 @@ switch (foo()) { // CHECK-FULL: "callee": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "print", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "typeArguments": null, // CHECK-FULL: "arguments": [ @@ -863,7 +868,8 @@ switch (foo()) { // CHECK-FULL: "callee": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "print", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "typeArguments": null, // CHECK-FULL: "arguments": [ @@ -892,7 +898,8 @@ switch (foo()) { // CHECK-FULL: "callee": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "print", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "typeArguments": null, // CHECK-FULL: "arguments": [ @@ -901,7 +908,8 @@ switch (foo()) { // CHECK-FULL: "callee": { // CHECK-FULL: "type": "Identifier", // CHECK-FULL: "name": "foo", -// CHECK-FULL: "typeAnnotation": null +// CHECK-FULL: "typeAnnotation": null, +// CHECK-FULL: "optional": false // CHECK-FULL: }, // CHECK-FULL: "typeArguments": null, // CHECK-FULL: "arguments": [] diff --git a/test/Parser/flow/function-params.js b/test/Parser/flow/function-params.js index 41ca2241b34..e7ec73756a6 100644 --- a/test/Parser/flow/function-params.js +++ b/test/Parser/flow/function-params.js @@ -43,7 +43,8 @@ // CHECK-NEXT: "params": [ // CHECK-NEXT: { // CHECK-NEXT: "type": "Identifier", -// CHECK-NEXT: "name": "foo" +// CHECK-NEXT: "name": "foo", +// CHECK-NEXT: "optional": true // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "body": { @@ -72,7 +73,8 @@ // CHECK-NEXT: "typeAnnotation": { // CHECK-NEXT: "type": "NumberTypeAnnotation" // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "optional": true // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "body": { @@ -97,7 +99,8 @@ // CHECK-NEXT: "type": "AssignmentPattern", // CHECK-NEXT: "left": { // CHECK-NEXT: "type": "Identifier", -// CHECK-NEXT: "name": "foo" +// CHECK-NEXT: "name": "foo", +// CHECK-NEXT: "optional": true // CHECK-NEXT: }, // CHECK-NEXT: "right": { // CHECK-NEXT: "type": "NumericLiteral", @@ -134,7 +137,8 @@ // CHECK-NEXT: "typeAnnotation": { // CHECK-NEXT: "type": "NumberTypeAnnotation" // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "optional": true // CHECK-NEXT: }, // CHECK-NEXT: "right": { // CHECK-NEXT: "type": "NumericLiteral", diff --git a/test/Parser/flow/function-ret.js b/test/Parser/flow/function-ret.js index 82a0371f22a..8191d40b1d0 100644 --- a/test/Parser/flow/function-ret.js +++ b/test/Parser/flow/function-ret.js @@ -128,7 +128,36 @@ function foo(a?: number): number {} // CHECK-NEXT: "typeAnnotation": { // CHECK-NEXT: "type": "NumberTypeAnnotation" // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "optional": true +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "body": { +// CHECK-NEXT: "type": "BlockStatement", +// CHECK-NEXT: "body": [] +// CHECK-NEXT: }, +// CHECK-NEXT: "returnType": { +// CHECK-NEXT: "type": "TypeAnnotation", +// CHECK-NEXT: "typeAnnotation": { +// CHECK-NEXT: "type": "NumberTypeAnnotation" +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "generator": false, +// CHECK-NEXT: "async": false +// CHECK-NEXT: }, + +function foo(a?): number {} +// CHECK-NEXT: { +// CHECK-NEXT: "type": "FunctionDeclaration", +// CHECK-NEXT: "id": { +// CHECK-NEXT: "type": "Identifier", +// CHECK-NEXT: "name": "foo" +// CHECK-NEXT: }, +// CHECK-NEXT: "params": [ +// CHECK-NEXT: { +// CHECK-NEXT: "type": "Identifier", +// CHECK-NEXT: "name": "a", +// CHECK-NEXT: "optional": true // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "body": { @@ -341,7 +370,8 @@ function foo(a?: number): number {} // CHECK-NEXT: "typeAnnotation": { // CHECK-NEXT: "type": "NumberTypeAnnotation" // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "optional": true // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "body": { @@ -376,7 +406,8 @@ function foo(a?: number): number {} // CHECK-NEXT: "typeAnnotation": { // CHECK-NEXT: "type": "NumberTypeAnnotation" // CHECK-NEXT: } -// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "optional": true // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "body": { diff --git a/unittests/AST/ESTreeTest.cpp b/unittests/AST/ESTreeTest.cpp index 8dc530544b3..084aa76fc03 100644 --- a/unittests/AST/ESTreeTest.cpp +++ b/unittests/AST/ESTreeTest.cpp @@ -29,7 +29,8 @@ const char *SimpleESTreeProgram = " \"type\": \"FunctionDeclaration\"," " \"id\": {" " \"type\": \"Identifier\"," - " \"name\": \"my_name_is_foo\"" + " \"name\": \"my_name_is_foo\"," + " \"optional\": false" " }, " " \"params\": [], " " \"body\": {"