Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
Add optional property to Identifier node
Browse files Browse the repository at this point in the history
Summary:
Hermes currently parses optional function parameters (e.g. `function foo(a?) {}` or `(a?: string) => {}`), however it does not store whether a parameter is optional in the AST. Flow and Babel store this information as a boolean `optional` property on `Identifier` nodes which is `true` if the identifier is an optional function parameter, otherwise `optional` is false. Let's update Hermes' AST definition to now store an `optional` property on identifiers, just like Flow and Babel.

Almost all places where `IdentifierNodes` are created, optional is set to be false. In fact the only place where an `IdentifierNode` is directly created with `optional` set to true is within `parseBindingIdentifier` when we encounter a question mark directly following the identifier. There is only one other path through which optional identifiers are created: when reparsing arrow function parameters. To handle this case we also need to add an optional property to the `CoverTypedIdentifierNode`. Then when unwrapping a `CoverTypedIdentifierNode` in `reparseAssignmentPattern`, we pass the value of `optional` from the `CoverTypedIdentifierNode` to the `IdentifierNode`.

In addition, as per avp's suggestion we now allow declaring `ESTREE_IGNORE_IF_EMPTY` on boolean node properties. If the boolean is false, such as the new `optional` property for non-optional identifiers, then it will not be included in the JSON output. Without this we would have to update every single parser test that contains an identifier, instead of only the tests that contain optional parameters.

Reviewed By: avp

Differential Revision: D24210171

fbshipit-source-id: 2bb860ba2876d28100f17286bbb74e46dabf3cbc
  • Loading branch information
Hans Halverson authored and facebook-github-bot committed Oct 28, 2020
1 parent d91e0e3 commit a7f424c
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 128 deletions.
20 changes: 9 additions & 11 deletions include/hermes/AST/ESTree.def
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)

Expand Down
6 changes: 3 additions & 3 deletions lib/AST/CommonJS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ESTreeJSONDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class ESTreeJSONDumper {
}

static bool isEmpty(NodeBoolean val) {
return false;
return !val;
}

static bool isEmpty(NodeNumber num) {
Expand Down
36 changes: 21 additions & 15 deletions lib/Parser/JSParserImpl-flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ Optional<ESTree::Node *> 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);

Expand Down Expand Up @@ -210,7 +211,8 @@ Optional<ESTree::Node *> 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;
Expand Down Expand Up @@ -349,7 +351,7 @@ Optional<ESTree::Node *> 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,
Expand Down Expand Up @@ -401,7 +403,8 @@ Optional<ESTree::Node *> 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);

Expand Down Expand Up @@ -511,7 +514,8 @@ Optional<ESTree::Node *> 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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2023,8 +2027,8 @@ Optional<ESTree::GenericTypeAnnotationNode *> 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)) {
Expand All @@ -2039,8 +2043,8 @@ Optional<ESTree::GenericTypeAnnotationNode *> 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));
Expand Down Expand Up @@ -2069,7 +2073,8 @@ Optional<ESTree::ClassImplementsNode *> 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;
Expand Down Expand Up @@ -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<ESTree::Node *> JSParserImpl::parseEnumDeclaration() {
Expand Down Expand Up @@ -2314,7 +2319,8 @@ Optional<ESTree::Node *> 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;
Expand Down
Loading

0 comments on commit a7f424c

Please sign in to comment.