]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/linter/code-path-analysis/fork-context.js
2e872b5c0dbf5a9a779554ed858a9fb4f9484bab
2 * @fileoverview A class to operate forking.
4 * This is state of forking.
5 * This has a fork list and manages it.
7 * @author Toru Nagashima
12 //------------------------------------------------------------------------------
14 //------------------------------------------------------------------------------
16 const assert
= require("assert"),
17 CodePathSegment
= require("./code-path-segment");
19 //------------------------------------------------------------------------------
21 //------------------------------------------------------------------------------
24 * Gets whether or not a given segment is reachable.
25 * @param {CodePathSegment} segment A segment to get.
26 * @returns {boolean} `true` if the segment is reachable.
28 function isReachable(segment
) {
29 return segment
.reachable
;
33 * Creates new segments from the specific range of `context.segmentsList`.
35 * When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and
36 * `end` is `-1`, this creates `[g, h]`. This `g` is from `a`, `c`, and `e`.
37 * This `h` is from `b`, `d`, and `f`.
38 * @param {ForkContext} context An instance.
39 * @param {number} begin The first index of the previous segments.
40 * @param {number} end The last index of the previous segments.
41 * @param {Function} create A factory function of new segments.
42 * @returns {CodePathSegment[]} New segments.
44 function makeSegments(context
, begin
, end
, create
) {
45 const list
= context
.segmentsList
;
47 const normalizedBegin
= begin
>= 0 ? begin
: list
.length
+ begin
;
48 const normalizedEnd
= end
>= 0 ? end
: list
.length
+ end
;
52 for (let i
= 0; i
< context
.count
; ++i
) {
53 const allPrevSegments
= [];
55 for (let j
= normalizedBegin
; j
<= normalizedEnd
; ++j
) {
56 allPrevSegments
.push(list
[j
][i
]);
59 segments
.push(create(context
.idGenerator
.next(), allPrevSegments
));
66 * `segments` becomes doubly in a `finally` block. Then if a code path exits by a
67 * control statement (such as `break`, `continue`) from the `finally` block, the
68 * destination's segments may be half of the source segments. In that case, this
70 * @param {ForkContext} context An instance.
71 * @param {CodePathSegment[]} segments Segments to merge.
72 * @returns {CodePathSegment[]} The merged segments.
74 function mergeExtraSegments(context
, segments
) {
75 let currentSegments
= segments
;
77 while (currentSegments
.length
> context
.count
) {
80 for (let i
= 0, length
= currentSegments
.length
/ 2 | 0; i
< length
; ++i
) {
81 merged
.push(CodePathSegment
.newNext(
82 context
.idGenerator
.next(),
83 [currentSegments
[i
], currentSegments
[i
+ length
]]
86 currentSegments
= merged
;
88 return currentSegments
;
91 //------------------------------------------------------------------------------
93 //------------------------------------------------------------------------------
96 * A class to manage forking.
100 // eslint-disable-next-line jsdoc/require-description
102 * @param {IdGenerator} idGenerator An identifier generator for segments.
103 * @param {ForkContext|null} upper An upper fork context.
104 * @param {number} count A number of parallel segments.
106 constructor(idGenerator
, upper
, count
) {
107 this.idGenerator
= idGenerator
;
110 this.segmentsList
= [];
115 * @type {CodePathSegment[]}
118 const list
= this.segmentsList
;
120 return list
.length
=== 0 ? [] : list
[list
.length
- 1];
124 * A flag which shows empty.
128 return this.segmentsList
.length
=== 0;
132 * A flag which shows reachable.
136 const segments
= this.head
;
138 return segments
.length
> 0 && segments
.some(isReachable
);
142 * Creates new segments from this context.
143 * @param {number} begin The first index of previous segments.
144 * @param {number} end The last index of previous segments.
145 * @returns {CodePathSegment[]} New segments.
147 makeNext(begin
, end
) {
148 return makeSegments(this, begin
, end
, CodePathSegment
.newNext
);
152 * Creates new segments from this context.
153 * The new segments is always unreachable.
154 * @param {number} begin The first index of previous segments.
155 * @param {number} end The last index of previous segments.
156 * @returns {CodePathSegment[]} New segments.
158 makeUnreachable(begin
, end
) {
159 return makeSegments(this, begin
, end
, CodePathSegment
.newUnreachable
);
163 * Creates new segments from this context.
164 * The new segments don't have connections for previous segments.
165 * But these inherit the reachable flag from this context.
166 * @param {number} begin The first index of previous segments.
167 * @param {number} end The last index of previous segments.
168 * @returns {CodePathSegment[]} New segments.
170 makeDisconnected(begin
, end
) {
171 return makeSegments(this, begin
, end
, CodePathSegment
.newDisconnected
);
175 * Adds segments into this context.
176 * The added segments become the head.
177 * @param {CodePathSegment[]} segments Segments to add.
181 assert(segments
.length
>= this.count
, `${segments.length} >= ${this.count}`);
183 this.segmentsList
.push(mergeExtraSegments(this, segments
));
187 * Replaces the head segments with given segments.
188 * The current head segments are removed.
189 * @param {CodePathSegment[]} segments Segments to add.
192 replaceHead(segments
) {
193 assert(segments
.length
>= this.count
, `${segments.length} >= ${this.count}`);
195 this.segmentsList
.splice(-1, 1, mergeExtraSegments(this, segments
));
199 * Adds all segments of a given fork context into this context.
200 * @param {ForkContext} context A fork context to add.
204 assert(context
.count
=== this.count
);
206 const source
= context
.segmentsList
;
208 for (let i
= 0; i
< source
.length
; ++i
) {
209 this.segmentsList
.push(source
[i
]);
214 * Clears all segments in this context.
218 this.segmentsList
= [];
222 * Creates the root fork context.
223 * @param {IdGenerator} idGenerator An identifier generator for segments.
224 * @returns {ForkContext} New fork context.
226 static newRoot(idGenerator
) {
227 const context
= new ForkContext(idGenerator
, null, 1);
229 context
.add([CodePathSegment
.newRoot(idGenerator
.next())]);
235 * Creates an empty fork context preceded by a given context.
236 * @param {ForkContext} parentContext The parent fork context.
237 * @param {boolean} forkLeavingPath A flag which shows inside of `finally` block.
238 * @returns {ForkContext} New fork context.
240 static newEmpty(parentContext
, forkLeavingPath
) {
241 return new ForkContext(
242 parentContext
.idGenerator
,
244 (forkLeavingPath
? 2 : 1) * parentContext
.count
249 module
.exports
= ForkContext
;