summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorGaming4JC <g4jc@hyperbola.info>2019-12-13 20:55:24 -0500
committerGaming4JC <g4jc@hyperbola.info>2019-12-17 06:25:25 -0500
commit79b5eb14bc5f8495d20147957cda5f4e5fc8186a (patch)
tree9a87a9dc31037cc09d2d84bdd0850048595dba64 /js
parentcba3f6142704ce228aaf54b5c98c6ef5b3f871be (diff)
downloaduxp-79b5eb14bc5f8495d20147957cda5f4e5fc8186a.tar.gz
Bug 1343481 - Part 7: Add BytecodeEmitter::emitDotGenerator and make yield/await nodes unary.
Tag #1287
Diffstat (limited to 'js')
-rw-r--r--js/src/builtin/ReflectParse.cpp12
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp77
-rw-r--r--js/src/frontend/BytecodeEmitter.h5
-rw-r--r--js/src/frontend/FoldConstants.cpp25
-rw-r--r--js/src/frontend/FullParseHandler.h21
-rw-r--r--js/src/frontend/NameFunctions.cpp21
-rw-r--r--js/src/frontend/ParseNode.cpp28
-rw-r--r--js/src/frontend/ParseNode.h6
-rw-r--r--js/src/frontend/Parser.cpp33
-rw-r--r--js/src/frontend/Parser.h2
-rw-r--r--js/src/frontend/SyntaxParseHandler.h6
11 files changed, 124 insertions, 112 deletions
diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
index 120970196a..22c958d4ca 100644
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2800,11 +2800,11 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
next->pn_kid->isKind(PNK_YIELD) &&
- next->pn_kid->pn_left);
+ next->pn_kid->pn_kid);
RootedValue body(cx);
- return expression(next->pn_kid->pn_left, &body) &&
+ return expression(next->pn_kid->pn_kid, &body) &&
builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
}
@@ -3146,7 +3146,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_YIELD_STAR:
{
- MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
+ MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue arg(cx);
return expression(pn->pn_left, &arg) &&
@@ -3155,10 +3155,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_YIELD:
{
- MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
+ MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
RootedValue arg(cx);
- return optExpression(pn->pn_left, &arg) &&
+ return optExpression(pn->pn_kid, &arg) &&
builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
}
@@ -3480,7 +3480,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
ParseNode* pnstart = pnbody->pn_head;
// Skip over initial yield in generator.
- if (pnstart && pnstart->isKind(PNK_YIELD)) {
+ if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
pnstart = pnstart->pn_next;
}
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 6a6deed12f..77a480bff6 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3175,10 +3175,11 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = true;
return true;
+ case PNK_INITIALYIELD:
case PNK_YIELD_STAR:
case PNK_YIELD:
case PNK_AWAIT:
- MOZ_ASSERT(pn->isArity(PN_BINARY));
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
@@ -8526,45 +8527,61 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
}
bool
+BytecodeEmitter::emitGetDotGenerator()
+{
+ NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
+ return emitGetNameAtLocation(cx->names().dotGenerator, loc);
+}
+
+bool
+BytecodeEmitter::emitInitialYield(ParseNode* pn)
+{
+ if (!emitTree(pn->pn_kid))
+ return false;
+
+ if (!emitYieldOp(JSOP_INITIALYIELD))
+ return false;
+
+ if (!emit1(JSOP_POP))
+ return false;
+
+ return true;
+}
+
+bool
BytecodeEmitter::emitYield(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
+ MOZ_ASSERT(pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT);
- if (pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT) {
- bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
- if (needsIteratorResult) {
- if (!emitPrepareIteratorResult())
- return false;
- }
- if (pn->pn_left) {
- if (!emitTree(pn->pn_left))
- return false;
- } else {
- if (!emit1(JSOP_UNDEFINED))
- return false;
- }
- if (needsIteratorResult) {
- if (!emitFinishIteratorResult(false))
- return false;
- }
+ bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
+ if (needsIteratorResult) {
+ if (!emitPrepareIteratorResult())
+ return false;
+ }
+ if (pn->pn_kid) {
+ if (!emitTree(pn->pn_kid))
+ return false;
} else {
- MOZ_ASSERT(pn->getOp() == JSOP_INITIALYIELD);
+ if (!emit1(JSOP_UNDEFINED))
+ return false;
+ }
+ if (needsIteratorResult) {
+ if (!emitFinishIteratorResult(false))
+ return false;
}
- if (!emitTree(pn->pn_right))
+ if (!emitGetDotGenerator())
return false;
if (!emitYieldOp(pn->getOp()))
return false;
- if (pn->getOp() == JSOP_INITIALYIELD && !emit1(JSOP_POP))
- return false;
-
return true;
}
bool
-BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
+BytecodeEmitter::emitYieldStar(ParseNode* iter)
{
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(sc->asFunctionBox()->isStarGenerator());
@@ -8594,7 +8611,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter, ParseNode* gen)
MOZ_ASSERT(this->stackDepth == startDepth);
// Load the generator object.
- if (!emitTree(gen)) // ITER RESULT GENOBJ
+ if (!emitGetDotGenerator()) // ITER RESULT GENOBJ
return false;
// Yield RESULT as-is, without re-boxing.
@@ -10338,8 +10355,7 @@ BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
if (!emit1(JSOP_SETRVAL))
return false;
- NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
- if (!emitGetNameAtLocation(cx->names().dotGenerator, loc))
+ if (!emitGetDotGenerator())
return false;
// No need to check for finally blocks, etc as in EmitReturn.
@@ -10599,7 +10615,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break;
case PNK_YIELD_STAR:
- if (!emitYieldStar(pn->pn_left, pn->pn_right))
+ if (!emitYieldStar(pn->pn_kid))
return false;
break;
@@ -10608,6 +10624,11 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
return false;
break;
+ case PNK_INITIALYIELD:
+ if (!emitInitialYield(pn))
+ return false;
+ break;
+
case PNK_YIELD:
case PNK_AWAIT:
if (!emitYield(pn))
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 7f2dddfed1..08638f48a7 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -607,9 +607,12 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
+ MOZ_MUST_USE bool emitGetDotGenerator();
+
+ MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
MOZ_MUST_USE bool emitYield(ParseNode* pn);
MOZ_MUST_USE bool emitYieldOp(JSOp op);
- MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen);
+ MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
index 689fa02b4b..16294c4a81 100644
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -117,9 +117,10 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
// These two aren't statements in the spec, but we sometimes insert them
// in statement lists anyway.
+ case PNK_INITIALYIELD:
case PNK_YIELD_STAR:
case PNK_YIELD:
- MOZ_ASSERT(node->isArity(PN_BINARY));
+ MOZ_ASSERT(node->isArity(PN_UNARY));
*result = false;
return true;
@@ -1775,21 +1776,23 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_GENEXP:
return FoldList(cx, pn, parser, inGenexpLambda);
+ case PNK_INITIALYIELD:
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
+ pn->pn_kid->pn_left->isKind(PNK_NAME) &&
+ pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
+ return true;
+
case PNK_YIELD_STAR:
- MOZ_ASSERT(pn->isArity(PN_BINARY));
- MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
- return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
case PNK_YIELD:
case PNK_AWAIT:
- MOZ_ASSERT(pn->isArity(PN_BINARY));
- MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
- (pn->pn_right->isKind(PNK_ASSIGN) &&
- pn->pn_right->pn_left->isKind(PNK_NAME) &&
- pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
- if (!pn->pn_left)
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ if (!pn->pn_kid)
return true;
- return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
+ return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
case PNK_RETURN:
return FoldReturn(cx, pn, parser, inGenexpLambda);
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index 6ab93f3f9d..44694298bd 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -440,20 +440,24 @@ class FullParseHandler
return true;
}
- ParseNode* newYieldExpression(uint32_t begin, ParseNode* value, ParseNode* gen,
- JSOp op = JSOP_YIELD) {
+ ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
+ TokenPos pos(begin, begin + 1);
+ return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
+ }
+
+ ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
- return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
+ return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
}
- ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
+ ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value->pn_pos.end);
- return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
+ return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
}
- ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
+ ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
- return new_<BinaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value, gen);
+ return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
}
// Statements
@@ -506,8 +510,7 @@ class FullParseHandler
if (!genInit)
return false;
- ParseNode* initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
- JSOP_INITIALYIELD);
+ ParseNode* initialYield = newInitialYieldExpression(yieldPos.begin, genInit);
if (!initialYield)
return false;
diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp
index dc54d0a88f..376be76242 100644
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -501,24 +501,25 @@ class NameResolver
return false;
break;
+ case PNK_INITIALYIELD:
+ MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
+ cur->pn_kid->pn_left->isKind(PNK_NAME) &&
+ cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
+ break;
+
case PNK_YIELD_STAR:
- MOZ_ASSERT(cur->isArity(PN_BINARY));
- MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME));
- if (!resolve(cur->pn_left, prefix))
+ MOZ_ASSERT(cur->isArity(PN_UNARY));
+ if (!resolve(cur->pn_kid, prefix))
return false;
break;
case PNK_YIELD:
case PNK_AWAIT:
- MOZ_ASSERT(cur->isArity(PN_BINARY));
- if (cur->pn_left) {
- if (!resolve(cur->pn_left, prefix))
+ MOZ_ASSERT(cur->isArity(PN_UNARY));
+ if (cur->pn_kid) {
+ if (!resolve(cur->pn_kid, prefix))
return false;
}
- MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME) ||
- (cur->pn_right->isKind(PNK_ASSIGN) &&
- cur->pn_right->pn_left->isKind(PNK_NAME) &&
- cur->pn_right->pn_right->isKind(PNK_GENERATOR)));
break;
case PNK_RETURN:
diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp
index 5fe64e3d36..42ae9451a3 100644
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -286,22 +286,24 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushResult::Recyclable;
}
- // The left half is the expression being yielded. The right half is
- // internal goop: a name reference to the invisible '.generator' local
- // variable, or an assignment of a PNK_GENERATOR node to the '.generator'
- // local, for a synthesized, prepended initial yield. Yum!
+ // The child is an assignment of a PNK_GENERATOR node to the
+ // '.generator' local, for a synthesized, prepended initial yield.
+ case PNK_INITIALYIELD: {
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
+ pn->pn_kid->pn_left->isKind(PNK_NAME) &&
+ pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
+ stack->push(pn->pn_kid);
+ return PushResult::Recyclable;
+ }
+
+ // The child is the expression being yielded.
case PNK_YIELD_STAR:
case PNK_YIELD:
case PNK_AWAIT: {
- MOZ_ASSERT(pn->isArity(PN_BINARY));
- MOZ_ASSERT(pn->pn_right);
- MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
- (pn->pn_right->isKind(PNK_ASSIGN) &&
- pn->pn_right->pn_left->isKind(PNK_NAME) &&
- pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
- if (pn->pn_left)
- stack->push(pn->pn_left);
- stack->push(pn->pn_right);
+ MOZ_ASSERT(pn->isArity(PN_UNARY));
+ if (pn->pn_kid)
+ stack->push(pn->pn_kid);
return PushResult::Recyclable;
}
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index 1f20f39887..9a435e2701 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -83,6 +83,7 @@ class ObjectBox;
F(THROW) \
F(DEBUGGER) \
F(GENERATOR) \
+ F(INITIALYIELD) \
F(YIELD) \
F(YIELD_STAR) \
F(GENEXP) \
@@ -418,8 +419,9 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings
* pn_u.scope.body: scope body
* PNK_GENERATOR nullary
- * PNK_YIELD, binary pn_left: expr or null; pn_right: generator object
- * PNK_YIELD_STAR
+ * PNK_INITIALYIELD unary pn_kid: generator object
+ * PNK_YIELD, unary pn_kid: expr or null
+ * PNK_YIELD_STAR,
* PNK_ARRAYCOMP list pn_count: 1
* pn_head: list of 1 element, which is block
* enclosing for loop(s) and optionally
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 406d377258..3ae5890ac5 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6548,29 +6548,6 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
- bool isYieldStar)
-{
- Node generator = newDotGeneratorName();
- if (!generator)
- return null();
- if (isYieldStar)
- return handler.newYieldStarExpression(begin, expr, generator);
- return handler.newYieldExpression(begin, expr, generator);
-}
-
-template <typename ParseHandler>
-typename ParseHandler::Node
-Parser<ParseHandler>::newAwaitExpression(uint32_t begin, typename ParseHandler::Node expr)
-{
- Node generator = newDotGeneratorName();
- if (!generator)
- return null();
- return handler.newAwaitExpression(begin, expr, generator);
-}
-
-template <typename ParseHandler>
-typename ParseHandler::Node
Parser<ParseHandler>::yieldExpression(InHandling inHandling)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
@@ -6617,7 +6594,9 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
if (!exprNode)
return null();
}
- return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
+ if (kind == PNK_YIELD_STAR)
+ return handler.newYieldStarExpression(begin, exprNode);
+ return handler.newYieldExpression(begin, exprNode);
}
case NotGenerator:
@@ -6694,7 +6673,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
return null();
}
- return newYieldExpression(begin, exprNode);
+ return handler.newYieldExpression(begin, exprNode);
}
}
@@ -8449,7 +8428,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
if (!kid)
return null();
pc->lastAwaitOffset = begin;
- return newAwaitExpression(begin, kid);
+ return handler.newAwaitExpression(begin, kid);
}
}
@@ -8707,7 +8686,7 @@ Parser<ParseHandler>::comprehensionTail(GeneratorKind comprehensionKind)
return handler.newArrayPush(begin, bodyExpr);
MOZ_ASSERT(comprehensionKind == StarGenerator);
- Node yieldExpr = newYieldExpression(begin, bodyExpr);
+ Node yieldExpr = handler.newYieldExpression(begin, bodyExpr);
if (!yieldExpr)
return null();
yieldExpr = handler.parenthesize(yieldExpr);
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index 33fe345d63..73c2817f45 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1110,8 +1110,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
inline Node newName(PropertyName* name);
inline Node newName(PropertyName* name, TokenPos pos);
- inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
- inline Node newAwaitExpression(uint32_t begin, Node expr);
inline bool abortIfSyntaxParser();
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index a604b599fb..d919f1354d 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -301,9 +301,9 @@ class SyntaxParseHandler
MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; }
MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
- Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
- Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
- Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+ Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
+ Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
+ Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
// Statements