|
@ -9,7 +9,7 @@ |
|
|
// Requirements
|
|
|
// Requirements
|
|
|
//------------------------------------------------------------------------------
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
let CodePathSegment = require("./code-path-segment"), |
|
|
const CodePathSegment = require("./code-path-segment"), |
|
|
ForkContext = require("./fork-context"); |
|
|
ForkContext = require("./fork-context"); |
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
//------------------------------------------------------------------------------
|
|
@ -31,7 +31,7 @@ let CodePathSegment = require("./code-path-segment"), |
|
|
*/ |
|
|
*/ |
|
|
function addToReturnedOrThrown(dest, others, all, segments) { |
|
|
function addToReturnedOrThrown(dest, others, all, segments) { |
|
|
for (let i = 0; i < segments.length; ++i) { |
|
|
for (let i = 0; i < segments.length; ++i) { |
|
|
let segment = segments[i]; |
|
|
const segment = segments[i]; |
|
|
|
|
|
|
|
|
dest.push(segment); |
|
|
dest.push(segment); |
|
|
if (others.indexOf(segment) === -1) { |
|
|
if (others.indexOf(segment) === -1) { |
|
@ -150,8 +150,8 @@ function remove(xs, x) { |
|
|
*/ |
|
|
*/ |
|
|
function removeConnection(prevSegments, nextSegments) { |
|
|
function removeConnection(prevSegments, nextSegments) { |
|
|
for (let i = 0; i < prevSegments.length; ++i) { |
|
|
for (let i = 0; i < prevSegments.length; ++i) { |
|
|
let prevSegment = prevSegments[i]; |
|
|
const prevSegment = prevSegments[i]; |
|
|
let nextSegment = nextSegments[i]; |
|
|
const nextSegment = nextSegments[i]; |
|
|
|
|
|
|
|
|
remove(prevSegment.nextSegments, nextSegment); |
|
|
remove(prevSegment.nextSegments, nextSegment); |
|
|
remove(prevSegment.allNextSegments, nextSegment); |
|
|
remove(prevSegment.allNextSegments, nextSegment); |
|
@ -169,11 +169,11 @@ function removeConnection(prevSegments, nextSegments) { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
function makeLooped(state, fromSegments, toSegments) { |
|
|
function makeLooped(state, fromSegments, toSegments) { |
|
|
let end = Math.min(fromSegments.length, toSegments.length); |
|
|
const end = Math.min(fromSegments.length, toSegments.length); |
|
|
|
|
|
|
|
|
for (let i = 0; i < end; ++i) { |
|
|
for (let i = 0; i < end; ++i) { |
|
|
let fromSegment = fromSegments[i]; |
|
|
const fromSegment = fromSegments[i]; |
|
|
let toSegment = toSegments[i]; |
|
|
const toSegment = toSegments[i]; |
|
|
|
|
|
|
|
|
if (toSegment.reachable) { |
|
|
if (toSegment.reachable) { |
|
|
fromSegment.nextSegments.push(toSegment); |
|
|
fromSegment.nextSegments.push(toSegment); |
|
@ -241,9 +241,9 @@ function CodePathState(idGenerator, onLooped) { |
|
|
this.initialSegment = this.forkContext.head[0]; |
|
|
this.initialSegment = this.forkContext.head[0]; |
|
|
|
|
|
|
|
|
// returnedSegments and thrownSegments push elements into finalSegments also.
|
|
|
// returnedSegments and thrownSegments push elements into finalSegments also.
|
|
|
let final = this.finalSegments = []; |
|
|
const final = this.finalSegments = []; |
|
|
let returned = this.returnedForkContext = []; |
|
|
const returned = this.returnedForkContext = []; |
|
|
let thrown = this.thrownForkContext = []; |
|
|
const thrown = this.thrownForkContext = []; |
|
|
|
|
|
|
|
|
returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final); |
|
|
returned.add = addToReturnedOrThrown.bind(null, returned, thrown, final); |
|
|
thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final); |
|
|
thrown.add = addToReturnedOrThrown.bind(null, thrown, returned, final); |
|
@ -266,7 +266,7 @@ CodePathState.prototype = { |
|
|
* @type {ForkContext} |
|
|
* @type {ForkContext} |
|
|
*/ |
|
|
*/ |
|
|
get parentForkContext() { |
|
|
get parentForkContext() { |
|
|
let current = this.forkContext; |
|
|
const current = this.forkContext; |
|
|
|
|
|
|
|
|
return current && current.upper; |
|
|
return current && current.upper; |
|
|
}, |
|
|
}, |
|
@ -292,7 +292,7 @@ CodePathState.prototype = { |
|
|
* @returns {ForkContext} The last context. |
|
|
* @returns {ForkContext} The last context. |
|
|
*/ |
|
|
*/ |
|
|
popForkContext: function() { |
|
|
popForkContext: function() { |
|
|
let lastContext = this.forkContext; |
|
|
const lastContext = this.forkContext; |
|
|
|
|
|
|
|
|
this.forkContext = lastContext.upper; |
|
|
this.forkContext = lastContext.upper; |
|
|
this.forkContext.replaceHead(lastContext.makeNext(0, -1)); |
|
|
this.forkContext.replaceHead(lastContext.makeNext(0, -1)); |
|
@ -370,12 +370,12 @@ CodePathState.prototype = { |
|
|
* @returns {ChoiceContext} The popped context. |
|
|
* @returns {ChoiceContext} The popped context. |
|
|
*/ |
|
|
*/ |
|
|
popChoiceContext: function() { |
|
|
popChoiceContext: function() { |
|
|
let context = this.choiceContext; |
|
|
const context = this.choiceContext; |
|
|
|
|
|
|
|
|
this.choiceContext = context.upper; |
|
|
this.choiceContext = context.upper; |
|
|
|
|
|
|
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let headSegments = forkContext.head; |
|
|
const headSegments = forkContext.head; |
|
|
|
|
|
|
|
|
switch (context.kind) { |
|
|
switch (context.kind) { |
|
|
case "&&": |
|
|
case "&&": |
|
@ -396,7 +396,7 @@ CodePathState.prototype = { |
|
|
* test chunk. |
|
|
* test chunk. |
|
|
*/ |
|
|
*/ |
|
|
if (context.isForkingAsResult) { |
|
|
if (context.isForkingAsResult) { |
|
|
let parentContext = this.choiceContext; |
|
|
const parentContext = this.choiceContext; |
|
|
|
|
|
|
|
|
parentContext.trueForkContext.addAll(context.trueForkContext); |
|
|
parentContext.trueForkContext.addAll(context.trueForkContext); |
|
|
parentContext.falseForkContext.addAll(context.falseForkContext); |
|
|
parentContext.falseForkContext.addAll(context.falseForkContext); |
|
@ -443,7 +443,7 @@ CodePathState.prototype = { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Merges all paths.
|
|
|
// Merges all paths.
|
|
|
let prevForkContext = context.trueForkContext; |
|
|
const prevForkContext = context.trueForkContext; |
|
|
|
|
|
|
|
|
prevForkContext.addAll(context.falseForkContext); |
|
|
prevForkContext.addAll(context.falseForkContext); |
|
|
forkContext.replaceHead(prevForkContext.makeNext(0, -1)); |
|
|
forkContext.replaceHead(prevForkContext.makeNext(0, -1)); |
|
@ -458,8 +458,8 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeLogicalRight: function() { |
|
|
makeLogicalRight: function() { |
|
|
let context = this.choiceContext; |
|
|
const context = this.choiceContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (context.processed) { |
|
|
if (context.processed) { |
|
|
|
|
|
|
|
@ -467,7 +467,7 @@ CodePathState.prototype = { |
|
|
* This got segments already from the child choice context. |
|
|
* This got segments already from the child choice context. |
|
|
* Creates the next path from own true/false fork context. |
|
|
* Creates the next path from own true/false fork context. |
|
|
*/ |
|
|
*/ |
|
|
let prevForkContext = |
|
|
const prevForkContext = |
|
|
context.kind === "&&" ? context.trueForkContext : |
|
|
context.kind === "&&" ? context.trueForkContext : |
|
|
/* kind === "||" */ context.falseForkContext; |
|
|
/* kind === "||" */ context.falseForkContext; |
|
|
|
|
|
|
|
@ -502,8 +502,8 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeIfConsequent: function() { |
|
|
makeIfConsequent: function() { |
|
|
let context = this.choiceContext; |
|
|
const context = this.choiceContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* If any result were not transferred from child contexts, |
|
|
* If any result were not transferred from child contexts, |
|
@ -529,8 +529,8 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeIfAlternate: function() { |
|
|
makeIfAlternate: function() { |
|
|
let context = this.choiceContext; |
|
|
const context = this.choiceContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* The head segments are the path of the `if` block. |
|
|
* The head segments are the path of the `if` block. |
|
@ -583,12 +583,12 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
popSwitchContext: function() { |
|
|
popSwitchContext: function() { |
|
|
let context = this.switchContext; |
|
|
const context = this.switchContext; |
|
|
|
|
|
|
|
|
this.switchContext = context.upper; |
|
|
this.switchContext = context.upper; |
|
|
|
|
|
|
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let brokenForkContext = this.popBreakContext().brokenForkContext; |
|
|
const brokenForkContext = this.popBreakContext().brokenForkContext; |
|
|
|
|
|
|
|
|
if (context.countForks === 0) { |
|
|
if (context.countForks === 0) { |
|
|
|
|
|
|
|
@ -605,10 +605,10 @@ CodePathState.prototype = { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let lastSegments = forkContext.head; |
|
|
const lastSegments = forkContext.head; |
|
|
|
|
|
|
|
|
this.forkBypassPath(); |
|
|
this.forkBypassPath(); |
|
|
let lastCaseSegments = forkContext.head; |
|
|
const lastCaseSegments = forkContext.head; |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
* `brokenForkContext` is used to make the next segment. |
|
|
* `brokenForkContext` is used to make the next segment. |
|
@ -659,7 +659,7 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeSwitchCaseBody: function(isEmpty, isDefault) { |
|
|
makeSwitchCaseBody: function(isEmpty, isDefault) { |
|
|
let context = this.switchContext; |
|
|
const context = this.switchContext; |
|
|
|
|
|
|
|
|
if (!context.hasCase) { |
|
|
if (!context.hasCase) { |
|
|
return; |
|
|
return; |
|
@ -670,8 +670,8 @@ CodePathState.prototype = { |
|
|
* The parent fork context has two segments. |
|
|
* The parent fork context has two segments. |
|
|
* Those are from the current case and the body of the previous case. |
|
|
* Those are from the current case and the body of the previous case. |
|
|
*/ |
|
|
*/ |
|
|
let parentForkContext = this.forkContext; |
|
|
const parentForkContext = this.forkContext; |
|
|
let forkContext = this.pushForkContext(); |
|
|
const forkContext = this.pushForkContext(); |
|
|
|
|
|
|
|
|
forkContext.add(parentForkContext.makeNext(0, -1)); |
|
|
forkContext.add(parentForkContext.makeNext(0, -1)); |
|
|
|
|
|
|
|
@ -731,7 +731,7 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
popTryContext: function() { |
|
|
popTryContext: function() { |
|
|
let context = this.tryContext; |
|
|
const context = this.tryContext; |
|
|
|
|
|
|
|
|
this.tryContext = context.upper; |
|
|
this.tryContext = context.upper; |
|
|
|
|
|
|
|
@ -747,19 +747,19 @@ CodePathState.prototype = { |
|
|
* block. |
|
|
* block. |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
let returned = context.returnedForkContext; |
|
|
const returned = context.returnedForkContext; |
|
|
let thrown = context.thrownForkContext; |
|
|
const thrown = context.thrownForkContext; |
|
|
|
|
|
|
|
|
if (returned.empty && thrown.empty) { |
|
|
if (returned.empty && thrown.empty) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Separate head to normal paths and leaving paths.
|
|
|
// Separate head to normal paths and leaving paths.
|
|
|
let headSegments = this.forkContext.head; |
|
|
const headSegments = this.forkContext.head; |
|
|
|
|
|
|
|
|
this.forkContext = this.forkContext.upper; |
|
|
this.forkContext = this.forkContext.upper; |
|
|
let normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); |
|
|
const normalSegments = headSegments.slice(0, headSegments.length / 2 | 0); |
|
|
let leavingSegments = headSegments.slice(headSegments.length / 2 | 0); |
|
|
const leavingSegments = headSegments.slice(headSegments.length / 2 | 0); |
|
|
|
|
|
|
|
|
// Forwards the leaving path to upper contexts.
|
|
|
// Forwards the leaving path to upper contexts.
|
|
|
if (!returned.empty) { |
|
|
if (!returned.empty) { |
|
@ -785,9 +785,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeCatchBlock: function() { |
|
|
makeCatchBlock: function() { |
|
|
let context = this.tryContext; |
|
|
const context = this.tryContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let thrown = context.thrownForkContext; |
|
|
const thrown = context.thrownForkContext; |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
context.position = "catch"; |
|
|
context.position = "catch"; |
|
@ -796,7 +796,7 @@ CodePathState.prototype = { |
|
|
|
|
|
|
|
|
// Merge thrown paths.
|
|
|
// Merge thrown paths.
|
|
|
thrown.add(forkContext.head); |
|
|
thrown.add(forkContext.head); |
|
|
let thrownSegments = thrown.makeNext(0, -1); |
|
|
const thrownSegments = thrown.makeNext(0, -1); |
|
|
|
|
|
|
|
|
// Fork to a bypass and the merged thrown path.
|
|
|
// Fork to a bypass and the merged thrown path.
|
|
|
this.pushForkContext(); |
|
|
this.pushForkContext(); |
|
@ -814,11 +814,11 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeFinallyBlock: function() { |
|
|
makeFinallyBlock: function() { |
|
|
let context = this.tryContext; |
|
|
const context = this.tryContext; |
|
|
let forkContext = this.forkContext; |
|
|
let forkContext = this.forkContext; |
|
|
let returned = context.returnedForkContext; |
|
|
const returned = context.returnedForkContext; |
|
|
let thrown = context.thrownForkContext; |
|
|
const thrown = context.thrownForkContext; |
|
|
let headOfLeavingSegments = forkContext.head; |
|
|
const headOfLeavingSegments = forkContext.head; |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
if (context.position === "catch") { |
|
|
if (context.position === "catch") { |
|
@ -843,11 +843,11 @@ CodePathState.prototype = { |
|
|
* Create a parallel segment from merging returned and thrown. |
|
|
* Create a parallel segment from merging returned and thrown. |
|
|
* This segment will leave at the end of this finally block. |
|
|
* This segment will leave at the end of this finally block. |
|
|
*/ |
|
|
*/ |
|
|
let segments = forkContext.makeNext(-1, -1); |
|
|
const segments = forkContext.makeNext(-1, -1); |
|
|
let j; |
|
|
let j; |
|
|
|
|
|
|
|
|
for (let i = 0; i < forkContext.count; ++i) { |
|
|
for (let i = 0; i < forkContext.count; ++i) { |
|
|
let prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; |
|
|
const prevSegsOfLeavingSegment = [headOfLeavingSegments[i]]; |
|
|
|
|
|
|
|
|
for (j = 0; j < returned.segmentsList.length; ++j) { |
|
|
for (j = 0; j < returned.segmentsList.length; ++j) { |
|
|
prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]); |
|
|
prevSegsOfLeavingSegment.push(returned.segmentsList[j][i]); |
|
@ -872,13 +872,13 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeFirstThrowablePathInTryBlock: function() { |
|
|
makeFirstThrowablePathInTryBlock: function() { |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (!forkContext.reachable) { |
|
|
if (!forkContext.reachable) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let context = getThrowContext(this); |
|
|
const context = getThrowContext(this); |
|
|
|
|
|
|
|
|
if (context === this || |
|
|
if (context === this || |
|
|
context.position !== "try" || |
|
|
context.position !== "try" || |
|
@ -905,8 +905,8 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
pushLoopContext: function(type, label) { |
|
|
pushLoopContext: function(type, label) { |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let breakContext = this.pushBreakContext(true, label); |
|
|
const breakContext = this.pushBreakContext(true, label); |
|
|
|
|
|
|
|
|
switch (type) { |
|
|
switch (type) { |
|
|
case "WhileStatement": |
|
|
case "WhileStatement": |
|
@ -977,12 +977,12 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
popLoopContext: function() { |
|
|
popLoopContext: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
|
|
|
|
|
|
this.loopContext = context.upper; |
|
|
this.loopContext = context.upper; |
|
|
|
|
|
|
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let brokenForkContext = this.popBreakContext().brokenForkContext; |
|
|
const brokenForkContext = this.popBreakContext().brokenForkContext; |
|
|
let choiceContext; |
|
|
let choiceContext; |
|
|
|
|
|
|
|
|
// Creates a looped path.
|
|
|
// Creates a looped path.
|
|
@ -1048,9 +1048,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeWhileTest: function(test) { |
|
|
makeWhileTest: function(test) { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let testSegments = forkContext.makeNext(0, -1); |
|
|
const testSegments = forkContext.makeNext(0, -1); |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
context.test = test; |
|
|
context.test = test; |
|
@ -1064,9 +1064,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeWhileBody: function() { |
|
|
makeWhileBody: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let choiceContext = this.choiceContext; |
|
|
const choiceContext = this.choiceContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (!choiceContext.processed) { |
|
|
if (!choiceContext.processed) { |
|
|
choiceContext.trueForkContext.add(forkContext.head); |
|
|
choiceContext.trueForkContext.add(forkContext.head); |
|
@ -1086,9 +1086,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeDoWhileBody: function() { |
|
|
makeDoWhileBody: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let bodySegments = forkContext.makeNext(-1, -1); |
|
|
const bodySegments = forkContext.makeNext(-1, -1); |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
context.entrySegments = bodySegments; |
|
|
context.entrySegments = bodySegments; |
|
@ -1102,15 +1102,15 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeDoWhileTest: function(test) { |
|
|
makeDoWhileTest: function(test) { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
context.test = test; |
|
|
context.test = test; |
|
|
|
|
|
|
|
|
// Creates paths of `continue` statements.
|
|
|
// Creates paths of `continue` statements.
|
|
|
if (!context.continueForkContext.empty) { |
|
|
if (!context.continueForkContext.empty) { |
|
|
context.continueForkContext.add(forkContext.head); |
|
|
context.continueForkContext.add(forkContext.head); |
|
|
let testSegments = context.continueForkContext.makeNext(0, -1); |
|
|
const testSegments = context.continueForkContext.makeNext(0, -1); |
|
|
|
|
|
|
|
|
forkContext.replaceHead(testSegments); |
|
|
forkContext.replaceHead(testSegments); |
|
|
} |
|
|
} |
|
@ -1123,10 +1123,10 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeForTest: function(test) { |
|
|
makeForTest: function(test) { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let endOfInitSegments = forkContext.head; |
|
|
const endOfInitSegments = forkContext.head; |
|
|
let testSegments = forkContext.makeNext(-1, -1); |
|
|
const testSegments = forkContext.makeNext(-1, -1); |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
context.test = test; |
|
|
context.test = test; |
|
@ -1141,9 +1141,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeForUpdate: function() { |
|
|
makeForUpdate: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let choiceContext = this.choiceContext; |
|
|
const choiceContext = this.choiceContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
// Make the next paths of the test.
|
|
|
// Make the next paths of the test.
|
|
|
if (context.testSegments) { |
|
|
if (context.testSegments) { |
|
@ -1156,7 +1156,7 @@ CodePathState.prototype = { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
let updateSegments = forkContext.makeDisconnected(-1, -1); |
|
|
const updateSegments = forkContext.makeDisconnected(-1, -1); |
|
|
|
|
|
|
|
|
context.continueDestSegments = context.updateSegments = updateSegments; |
|
|
context.continueDestSegments = context.updateSegments = updateSegments; |
|
|
forkContext.replaceHead(updateSegments); |
|
|
forkContext.replaceHead(updateSegments); |
|
@ -1168,9 +1168,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeForBody: function() { |
|
|
makeForBody: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let choiceContext = this.choiceContext; |
|
|
const choiceContext = this.choiceContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
if (context.updateSegments) { |
|
|
if (context.updateSegments) { |
|
@ -1200,7 +1200,7 @@ CodePathState.prototype = { |
|
|
* If there is not the `test` part, the `body` path comes from the |
|
|
* If there is not the `test` part, the `body` path comes from the |
|
|
* `init` part and the `update` part. |
|
|
* `init` part and the `update` part. |
|
|
*/ |
|
|
*/ |
|
|
let prevForkContext = ForkContext.newEmpty(forkContext); |
|
|
const prevForkContext = ForkContext.newEmpty(forkContext); |
|
|
|
|
|
|
|
|
prevForkContext.add(context.endOfInitSegments); |
|
|
prevForkContext.add(context.endOfInitSegments); |
|
|
if (context.endOfUpdateSegments) { |
|
|
if (context.endOfUpdateSegments) { |
|
@ -1220,9 +1220,9 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeForInOfLeft: function() { |
|
|
makeForInOfLeft: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let leftSegments = forkContext.makeDisconnected(-1, -1); |
|
|
const leftSegments = forkContext.makeDisconnected(-1, -1); |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
context.prevSegments = forkContext.head; |
|
|
context.prevSegments = forkContext.head; |
|
@ -1237,12 +1237,12 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeForInOfRight: function() { |
|
|
makeForInOfRight: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let temp = ForkContext.newEmpty(forkContext); |
|
|
const temp = ForkContext.newEmpty(forkContext); |
|
|
|
|
|
|
|
|
temp.add(context.prevSegments); |
|
|
temp.add(context.prevSegments); |
|
|
let rightSegments = temp.makeNext(-1, -1); |
|
|
const rightSegments = temp.makeNext(-1, -1); |
|
|
|
|
|
|
|
|
// Update state.
|
|
|
// Update state.
|
|
|
context.endOfLeftSegments = forkContext.head; |
|
|
context.endOfLeftSegments = forkContext.head; |
|
@ -1256,12 +1256,12 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeForInOfBody: function() { |
|
|
makeForInOfBody: function() { |
|
|
let context = this.loopContext; |
|
|
const context = this.loopContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
let temp = ForkContext.newEmpty(forkContext); |
|
|
const temp = ForkContext.newEmpty(forkContext); |
|
|
|
|
|
|
|
|
temp.add(context.endOfLeftSegments); |
|
|
temp.add(context.endOfLeftSegments); |
|
|
let bodySegments = temp.makeNext(-1, -1); |
|
|
const bodySegments = temp.makeNext(-1, -1); |
|
|
|
|
|
|
|
|
// Make a path: `right` -> `left`.
|
|
|
// Make a path: `right` -> `left`.
|
|
|
makeLooped(this, forkContext.head, context.leftSegments); |
|
|
makeLooped(this, forkContext.head, context.leftSegments); |
|
@ -1299,14 +1299,14 @@ CodePathState.prototype = { |
|
|
* @returns {Object} The removed context. |
|
|
* @returns {Object} The removed context. |
|
|
*/ |
|
|
*/ |
|
|
popBreakContext: function() { |
|
|
popBreakContext: function() { |
|
|
let context = this.breakContext; |
|
|
const context = this.breakContext; |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
this.breakContext = context.upper; |
|
|
this.breakContext = context.upper; |
|
|
|
|
|
|
|
|
// Process this context here for other than switches and loops.
|
|
|
// Process this context here for other than switches and loops.
|
|
|
if (!context.breakable) { |
|
|
if (!context.breakable) { |
|
|
let brokenForkContext = context.brokenForkContext; |
|
|
const brokenForkContext = context.brokenForkContext; |
|
|
|
|
|
|
|
|
if (!brokenForkContext.empty) { |
|
|
if (!brokenForkContext.empty) { |
|
|
brokenForkContext.add(forkContext.head); |
|
|
brokenForkContext.add(forkContext.head); |
|
@ -1327,13 +1327,13 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeBreak: function(label) { |
|
|
makeBreak: function(label) { |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (!forkContext.reachable) { |
|
|
if (!forkContext.reachable) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let context = getBreakContext(this, label); |
|
|
const context = getBreakContext(this, label); |
|
|
|
|
|
|
|
|
/* istanbul ignore else: foolproof (syntax error) */ |
|
|
/* istanbul ignore else: foolproof (syntax error) */ |
|
|
if (context) { |
|
|
if (context) { |
|
@ -1353,13 +1353,13 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeContinue: function(label) { |
|
|
makeContinue: function(label) { |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (!forkContext.reachable) { |
|
|
if (!forkContext.reachable) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let context = getContinueContext(this, label); |
|
|
const context = getContinueContext(this, label); |
|
|
|
|
|
|
|
|
/* istanbul ignore else: foolproof (syntax error) */ |
|
|
/* istanbul ignore else: foolproof (syntax error) */ |
|
|
if (context) { |
|
|
if (context) { |
|
@ -1388,7 +1388,7 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeReturn: function() { |
|
|
makeReturn: function() { |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (forkContext.reachable) { |
|
|
if (forkContext.reachable) { |
|
|
getReturnContext(this).returnedForkContext.add(forkContext.head); |
|
|
getReturnContext(this).returnedForkContext.add(forkContext.head); |
|
@ -1405,7 +1405,7 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeThrow: function() { |
|
|
makeThrow: function() { |
|
|
let forkContext = this.forkContext; |
|
|
const forkContext = this.forkContext; |
|
|
|
|
|
|
|
|
if (forkContext.reachable) { |
|
|
if (forkContext.reachable) { |
|
|
getThrowContext(this).thrownForkContext.add(forkContext.head); |
|
|
getThrowContext(this).thrownForkContext.add(forkContext.head); |
|
@ -1418,7 +1418,7 @@ CodePathState.prototype = { |
|
|
* @returns {void} |
|
|
* @returns {void} |
|
|
*/ |
|
|
*/ |
|
|
makeFinal: function() { |
|
|
makeFinal: function() { |
|
|
let segments = this.currentSegments; |
|
|
const segments = this.currentSegments; |
|
|
|
|
|
|
|
|
if (segments.length > 0 && segments[0].reachable) { |
|
|
if (segments.length > 0 && segments[0].reachable) { |
|
|
this.returnedForkContext.add(segments); |
|
|
this.returnedForkContext.add(segments); |
|
|