this.tryContext = null;
this.loopContext = null;
this.breakContext = null;
+ this.chainContext = null;
this.currentSegments = [];
this.initialSegment = this.forkContext.head[0];
//--------------------------------------------------------------------------
/**
- * Creates a context for ConditionalExpression, LogicalExpression,
+ * Creates a context for ConditionalExpression, LogicalExpression, AssignmentExpression (logical assignments only),
* IfStatement, WhileStatement, DoWhileStatement, or ForStatement.
*
* LogicalExpressions have cases that it goes different paths between the
* a -> b -> foo();
* a -> b -> bar();
* @param {string} kind A kind string.
- * If the new context is LogicalExpression's, this is `"&&"` or `"||"`.
+ * If the new context is LogicalExpression's or AssignmentExpression's, this is `"&&"` or `"||"` or `"??"`.
* If it's IfStatement's or ConditionalExpression's, this is `"test"`.
* Otherwise, this is `"loop"`.
* @param {boolean} isForkingAsResult A flag that shows that goes different
);
}
+ //--------------------------------------------------------------------------
+ // ChainExpression
+ //--------------------------------------------------------------------------
+
+ /**
+ * Push a new `ChainExpression` context to the stack.
+ * This method is called on entering to each `ChainExpression` node.
+ * This context is used to count forking in the optional chain then merge them on the exiting from the `ChainExpression` node.
+ * @returns {void}
+ */
+ pushChainContext() {
+ this.chainContext = {
+ upper: this.chainContext,
+ countChoiceContexts: 0
+ };
+ }
+
+ /**
+ * Pop a `ChainExpression` context from the stack.
+ * This method is called on exiting from each `ChainExpression` node.
+ * This merges all forks of the last optional chaining.
+ * @returns {void}
+ */
+ popChainContext() {
+ const context = this.chainContext;
+
+ this.chainContext = context.upper;
+
+ // pop all choice contexts of this.
+ for (let i = context.countChoiceContexts; i > 0; --i) {
+ this.popChoiceContext();
+ }
+ }
+
+ /**
+ * Create a choice context for optional access.
+ * This method is called on entering to each `(Call|Member)Expression[optional=true]` node.
+ * This creates a choice context as similar to `LogicalExpression[operator="??"]` node.
+ * @returns {void}
+ */
+ makeOptionalNode() {
+ if (this.chainContext) {
+ this.chainContext.countChoiceContexts += 1;
+ this.pushChoiceContext("??", false);
+ }
+ }
+
+ /**
+ * Create a fork.
+ * This method is called on entering to the `arguments|property` property of each `(Call|Member)Expression` node.
+ * @returns {void}
+ */
+ makeOptionalRight() {
+ if (this.chainContext) {
+ this.makeLogicalRight();
+ }
+ }
+
//--------------------------------------------------------------------------
// SwitchStatement
//--------------------------------------------------------------------------