@eagleoutice/flowr 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dataflow/environments/resolve-by-name.js +5 -4
- package/documentation/print-query-wiki.js +24 -0
- package/package.json +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-executor.d.ts +3 -0
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +36 -0
- package/queries/catalog/happens-before-query/happens-before-query-format.d.ts +71 -0
- package/queries/catalog/happens-before-query/happens-before-query-format.js +27 -0
- package/queries/catalog/search-query/search-query-executor.js +0 -4
- package/queries/query.d.ts +60 -1
- package/queries/query.js +3 -1
- package/util/cfg/cfg.d.ts +2 -0
- package/util/cfg/cfg.js +8 -8
- package/util/cfg/happens-before.d.ts +7 -0
- package/util/cfg/happens-before.js +32 -0
- package/util/logic.d.ts +4 -4
- package/util/logic.js +8 -0
- package/util/version.js +1 -1
|
@@ -7,6 +7,7 @@ exports.getAliases = getAliases;
|
|
|
7
7
|
exports.resolveToValues = resolveToValues;
|
|
8
8
|
exports.resolveValueOfVariable = resolveValueOfVariable;
|
|
9
9
|
const environment_1 = require("./environment");
|
|
10
|
+
const logic_1 = require("../../util/logic");
|
|
10
11
|
const identifier_1 = require("./identifier");
|
|
11
12
|
const info_1 = require("../info");
|
|
12
13
|
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
@@ -66,11 +67,11 @@ function resolveByName(name, environment, target = identifier_1.ReferenceType.Un
|
|
|
66
67
|
}
|
|
67
68
|
function resolvesToBuiltInConstant(name, environment, wantedValue) {
|
|
68
69
|
if (name === undefined) {
|
|
69
|
-
return
|
|
70
|
+
return logic_1.Ternary.Never;
|
|
70
71
|
}
|
|
71
72
|
const definition = resolveByName(name, environment, identifier_1.ReferenceType.Constant);
|
|
72
73
|
if (definition === undefined) {
|
|
73
|
-
return
|
|
74
|
+
return logic_1.Ternary.Never;
|
|
74
75
|
}
|
|
75
76
|
let all = true;
|
|
76
77
|
let some = false;
|
|
@@ -83,10 +84,10 @@ function resolvesToBuiltInConstant(name, environment, wantedValue) {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
if (all) {
|
|
86
|
-
return
|
|
87
|
+
return logic_1.Ternary.Always;
|
|
87
88
|
}
|
|
88
89
|
else {
|
|
89
|
-
return some ?
|
|
90
|
+
return some ? logic_1.Ternary.Maybe : logic_1.Ternary.Never;
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
function resolveToConstants(name, environment) {
|
|
@@ -213,6 +213,30 @@ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
|
213
213
|
`;
|
|
214
214
|
}
|
|
215
215
|
});
|
|
216
|
+
(0, doc_query_1.registerQueryDocumentation)('happens-before', {
|
|
217
|
+
name: 'Happens-Before Query',
|
|
218
|
+
type: 'active',
|
|
219
|
+
shortDescription: 'Check whether one normalized AST node happens before another in the CFG.',
|
|
220
|
+
functionName: search_query_executor_1.executeSearch.name,
|
|
221
|
+
functionFile: '../queries/catalog/happens-before-query/happens-before-query-executor.ts',
|
|
222
|
+
buildExplanation: async (shell) => {
|
|
223
|
+
const exampleCode = 'x <- 1\ny <- 2';
|
|
224
|
+
return `
|
|
225
|
+
With this query you can analyze the control flow graph:
|
|
226
|
+
|
|
227
|
+
Using the example code:
|
|
228
|
+
|
|
229
|
+
${(0, doc_code_1.codeBlock)('r', exampleCode)}
|
|
230
|
+
|
|
231
|
+
the following query returns that the first assignment happens always before the other:
|
|
232
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
233
|
+
type: 'happens-before',
|
|
234
|
+
a: '1@x',
|
|
235
|
+
b: '2@y'
|
|
236
|
+
}], { showCode: true, collapseQuery: false })}
|
|
237
|
+
`;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
216
240
|
(0, doc_query_1.registerQueryDocumentation)('id-map', {
|
|
217
241
|
name: 'Id-Map Query',
|
|
218
242
|
type: 'active',
|
package/package.json
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { BasicQueryData } from '../../base-query-format';
|
|
2
|
+
import type { HappensBeforeQuery, HappensBeforeQueryResult } from './happens-before-query-format';
|
|
3
|
+
export declare function executeHappensBefore({ ast }: BasicQueryData, queries: readonly HappensBeforeQuery[]): HappensBeforeQueryResult;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeHappensBefore = executeHappensBefore;
|
|
4
|
+
const logic_1 = require("../../../util/logic");
|
|
5
|
+
const log_1 = require("../../../util/log");
|
|
6
|
+
const cfg_1 = require("../../../util/cfg/cfg");
|
|
7
|
+
const happens_before_1 = require("../../../util/cfg/happens-before");
|
|
8
|
+
const parse_1 = require("../../../slicing/criterion/parse");
|
|
9
|
+
function executeHappensBefore({ ast }, queries) {
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
const results = {};
|
|
12
|
+
const cfg = (0, cfg_1.extractCFG)(ast);
|
|
13
|
+
for (const query of queries) {
|
|
14
|
+
const { a, b } = query;
|
|
15
|
+
const fingerprint = `${a}<${b}`;
|
|
16
|
+
if (fingerprint in results) {
|
|
17
|
+
log_1.log.warn('Duplicate happens-before query', query, 'ignoring');
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const resolvedA = (0, parse_1.slicingCriterionToId)(a, ast.idMap);
|
|
21
|
+
const resolvedB = (0, parse_1.slicingCriterionToId)(b, ast.idMap);
|
|
22
|
+
results[fingerprint] = (0, happens_before_1.happensBefore)(cfg.graph, resolvedA, resolvedB);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
log_1.log.error('Error while executing happens-before query', query, e);
|
|
26
|
+
results[fingerprint] = logic_1.Ternary.Maybe;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
'.meta': {
|
|
31
|
+
timing: Date.now() - start
|
|
32
|
+
},
|
|
33
|
+
results
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=happens-before-query-executor.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
|
|
2
|
+
import Joi from 'joi';
|
|
3
|
+
import { executeHappensBefore } from './happens-before-query-executor';
|
|
4
|
+
import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse';
|
|
5
|
+
import type { Ternary } from '../../../util/logic';
|
|
6
|
+
export interface HappensBeforeQuery extends BaseQueryFormat {
|
|
7
|
+
readonly type: 'happens-before';
|
|
8
|
+
readonly a: SingleSlicingCriterion;
|
|
9
|
+
readonly b: SingleSlicingCriterion;
|
|
10
|
+
}
|
|
11
|
+
export interface HappensBeforeQueryResult extends BaseQueryResult {
|
|
12
|
+
readonly results: Record<string, Ternary>;
|
|
13
|
+
}
|
|
14
|
+
export declare const HappensBeforeQueryDefinition: {
|
|
15
|
+
readonly executor: typeof executeHappensBefore;
|
|
16
|
+
readonly asciiSummarizer: (formatter: import("../../../util/ansi").OutputFormatter, _processed: import("../../../core/steps/pipeline/pipeline").PipelineOutput<import("../../../core/steps/pipeline/pipeline").Pipeline<{
|
|
17
|
+
readonly name: "parse";
|
|
18
|
+
readonly humanReadableName: "parse with R shell";
|
|
19
|
+
readonly description: "Parse the given R code into an AST";
|
|
20
|
+
readonly processor: (_results: unknown, input: Partial<import("../../../r-bridge/parser").ParseRequiredInput<string>>) => Promise<import("../../../r-bridge/parser").ParseStepOutput<string>>;
|
|
21
|
+
readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
22
|
+
readonly printer: {
|
|
23
|
+
readonly 0: typeof import("../../../core/print/print").internalPrinter;
|
|
24
|
+
readonly 2: {
|
|
25
|
+
(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
|
|
26
|
+
(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
|
|
27
|
+
};
|
|
28
|
+
readonly 5: ({ parsed }: import("../../../r-bridge/parser").ParseStepOutput<string>, config: import("../../../util/quads").QuadSerializationConfiguration) => string;
|
|
29
|
+
};
|
|
30
|
+
readonly dependencies: readonly [];
|
|
31
|
+
readonly requiredInput: import("../../../r-bridge/parser").ParseRequiredInput<string>;
|
|
32
|
+
} | {
|
|
33
|
+
readonly name: "normalize";
|
|
34
|
+
readonly humanReadableName: "normalize";
|
|
35
|
+
readonly description: "Normalize the AST to flowR's AST";
|
|
36
|
+
readonly processor: (results: {
|
|
37
|
+
parse?: import("../../../r-bridge/parser").ParseStepOutput<string>;
|
|
38
|
+
}, input: Partial<import("../../../core/steps/all/core/10-normalize").NormalizeRequiredInput>) => import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst<import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../../r-bridge/lang-4.x/ast/model/model").RNode<import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>>;
|
|
39
|
+
readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
40
|
+
readonly printer: {
|
|
41
|
+
readonly 0: typeof import("../../../core/print/print").internalPrinter;
|
|
42
|
+
readonly 2: typeof import("../../../core/print/normalize-printer").normalizedAstToJson;
|
|
43
|
+
readonly 5: typeof import("../../../core/print/normalize-printer").normalizedAstToQuads;
|
|
44
|
+
readonly 3: typeof import("../../../core/print/normalize-printer").printNormalizedAstToMermaid;
|
|
45
|
+
readonly 4: typeof import("../../../core/print/normalize-printer").printNormalizedAstToMermaidUrl;
|
|
46
|
+
};
|
|
47
|
+
readonly dependencies: readonly ["parse"];
|
|
48
|
+
readonly requiredInput: import("../../../core/steps/all/core/10-normalize").NormalizeRequiredInput;
|
|
49
|
+
} | {
|
|
50
|
+
readonly humanReadableName: "dataflow";
|
|
51
|
+
readonly processor: (results: {
|
|
52
|
+
normalize?: import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
53
|
+
}, input: {
|
|
54
|
+
request?: import("../../../r-bridge/retriever").RParseRequests;
|
|
55
|
+
parser?: import("../../../r-bridge/parser").Parser<import("../../../r-bridge/parser").KnownParserType>;
|
|
56
|
+
}) => import("../../../dataflow/info").DataflowInformation;
|
|
57
|
+
readonly requiredInput: {};
|
|
58
|
+
readonly name: "dataflow";
|
|
59
|
+
readonly description: "Construct the dataflow graph";
|
|
60
|
+
readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
61
|
+
readonly printer: {
|
|
62
|
+
readonly 0: typeof import("../../../core/print/print").internalPrinter;
|
|
63
|
+
readonly 2: typeof import("../../../core/print/dataflow-printer").dataflowGraphToJson;
|
|
64
|
+
readonly 5: typeof import("../../../core/print/dataflow-printer").dataflowGraphToQuads;
|
|
65
|
+
readonly 3: typeof import("../../../core/print/dataflow-printer").dataflowGraphToMermaid;
|
|
66
|
+
readonly 4: typeof import("../../../core/print/dataflow-printer").dataflowGraphToMermaidUrl;
|
|
67
|
+
};
|
|
68
|
+
readonly dependencies: readonly ["normalize"];
|
|
69
|
+
}>>, queryResults: BaseQueryResult, result: string[]) => true;
|
|
70
|
+
readonly schema: Joi.ObjectSchema<any>;
|
|
71
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HappensBeforeQueryDefinition = void 0;
|
|
7
|
+
const ansi_1 = require("../../../util/ansi");
|
|
8
|
+
const time_1 = require("../../../util/time");
|
|
9
|
+
const joi_1 = __importDefault(require("joi"));
|
|
10
|
+
const happens_before_query_executor_1 = require("./happens-before-query-executor");
|
|
11
|
+
exports.HappensBeforeQueryDefinition = {
|
|
12
|
+
executor: happens_before_query_executor_1.executeHappensBefore,
|
|
13
|
+
asciiSummarizer: (formatter, _processed, queryResults, result) => {
|
|
14
|
+
const out = queryResults;
|
|
15
|
+
result.push(`Query: ${(0, ansi_1.bold)('happens-before', formatter)} (${(0, time_1.printAsMs)(out['.meta'].timing, 0)})`);
|
|
16
|
+
for (const [key, value] of Object.entries(out.results)) {
|
|
17
|
+
result.push(` ╰ ${key}: ${value}`);
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
},
|
|
21
|
+
schema: joi_1.default.object({
|
|
22
|
+
type: joi_1.default.string().valid('happens-before').required().description('The type of the query.'),
|
|
23
|
+
a: joi_1.default.string().required().description('The first slicing criterion.'),
|
|
24
|
+
b: joi_1.default.string().required().description('The second slicing criterion.')
|
|
25
|
+
}).description('The id map query retrieves the id map from the normalized AST.')
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=happens-before-query-format.js.map
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.executeSearch = executeSearch;
|
|
4
|
-
const log_1 = require("../../../util/log");
|
|
5
4
|
const flowr_search_executor_1 = require("../../../search/flowr-search-executor");
|
|
6
5
|
function executeSearch({ ast, dataflow }, queries) {
|
|
7
6
|
const start = Date.now();
|
|
8
|
-
if (queries.length !== 1) {
|
|
9
|
-
log_1.log.warn('Id-Map query expects only up to one query, but got', queries.length);
|
|
10
|
-
}
|
|
11
7
|
const results = [];
|
|
12
8
|
for (const query of queries) {
|
|
13
9
|
const { search } = query;
|
package/queries/query.d.ts
CHANGED
|
@@ -16,7 +16,8 @@ import Joi from 'joi';
|
|
|
16
16
|
import type { LocationMapQuery } from './catalog/location-map-query/location-map-query-format';
|
|
17
17
|
import type { ConfigQuery } from './catalog/config-query/config-query-format';
|
|
18
18
|
import type { SearchQuery } from './catalog/search-query/search-query-format';
|
|
19
|
-
|
|
19
|
+
import type { HappensBeforeQuery } from './catalog/happens-before-query/happens-before-query-format';
|
|
20
|
+
export type Query = CallContextQuery | ConfigQuery | SearchQuery | DataflowQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery | LineageQuery | DependenciesQuery | LocationMapQuery | HappensBeforeQuery;
|
|
20
21
|
export type QueryArgumentsWithType<QueryType extends BaseQueryFormat['type']> = Query & {
|
|
21
22
|
type: QueryType;
|
|
22
23
|
};
|
|
@@ -509,6 +510,64 @@ export declare const SupportedQueries: {
|
|
|
509
510
|
}>>, queryResults: BaseQueryResult, result: string[]) => true;
|
|
510
511
|
readonly schema: Joi.ObjectSchema<any>;
|
|
511
512
|
};
|
|
513
|
+
readonly 'happens-before': {
|
|
514
|
+
readonly executor: typeof import("./catalog/happens-before-query/happens-before-query-executor").executeHappensBefore;
|
|
515
|
+
readonly asciiSummarizer: (formatter: OutputFormatter, _processed: PipelineOutput<import("../core/steps/pipeline/pipeline").Pipeline<{
|
|
516
|
+
readonly name: "parse";
|
|
517
|
+
readonly humanReadableName: "parse with R shell";
|
|
518
|
+
readonly description: "Parse the given R code into an AST";
|
|
519
|
+
readonly processor: (_results: unknown, input: Partial<import("../r-bridge/parser").ParseRequiredInput<string>>) => Promise<import("../r-bridge/parser").ParseStepOutput<string>>;
|
|
520
|
+
readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
521
|
+
readonly printer: {
|
|
522
|
+
readonly 0: typeof import("../core/print/print").internalPrinter;
|
|
523
|
+
readonly 2: {
|
|
524
|
+
(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
|
|
525
|
+
(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
|
|
526
|
+
};
|
|
527
|
+
readonly 5: ({ parsed }: import("../r-bridge/parser").ParseStepOutput<string>, config: import("../util/quads").QuadSerializationConfiguration) => string;
|
|
528
|
+
};
|
|
529
|
+
readonly dependencies: readonly [];
|
|
530
|
+
readonly requiredInput: import("../r-bridge/parser").ParseRequiredInput<string>;
|
|
531
|
+
} | {
|
|
532
|
+
readonly name: "normalize";
|
|
533
|
+
readonly humanReadableName: "normalize";
|
|
534
|
+
readonly description: "Normalize the AST to flowR's AST";
|
|
535
|
+
readonly processor: (results: {
|
|
536
|
+
parse?: import("../r-bridge/parser").ParseStepOutput<string>;
|
|
537
|
+
}, input: Partial<import("../core/steps/all/core/10-normalize").NormalizeRequiredInput>) => import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../r-bridge/lang-4.x/ast/model/model").RNode<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>>;
|
|
538
|
+
readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
539
|
+
readonly printer: {
|
|
540
|
+
readonly 0: typeof import("../core/print/print").internalPrinter;
|
|
541
|
+
readonly 2: typeof import("../core/print/normalize-printer").normalizedAstToJson;
|
|
542
|
+
readonly 5: typeof import("../core/print/normalize-printer").normalizedAstToQuads;
|
|
543
|
+
readonly 3: typeof import("../core/print/normalize-printer").printNormalizedAstToMermaid;
|
|
544
|
+
readonly 4: typeof import("../core/print/normalize-printer").printNormalizedAstToMermaidUrl;
|
|
545
|
+
};
|
|
546
|
+
readonly dependencies: readonly ["parse"];
|
|
547
|
+
readonly requiredInput: import("../core/steps/all/core/10-normalize").NormalizeRequiredInput;
|
|
548
|
+
} | {
|
|
549
|
+
readonly humanReadableName: "dataflow";
|
|
550
|
+
readonly processor: (results: {
|
|
551
|
+
normalize?: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
552
|
+
}, input: {
|
|
553
|
+
request?: import("../r-bridge/retriever").RParseRequests;
|
|
554
|
+
parser?: import("../r-bridge/parser").Parser<import("../r-bridge/parser").KnownParserType>;
|
|
555
|
+
}) => import("../dataflow/info").DataflowInformation;
|
|
556
|
+
readonly requiredInput: {};
|
|
557
|
+
readonly name: "dataflow";
|
|
558
|
+
readonly description: "Construct the dataflow graph";
|
|
559
|
+
readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
560
|
+
readonly printer: {
|
|
561
|
+
readonly 0: typeof import("../core/print/print").internalPrinter;
|
|
562
|
+
readonly 2: typeof import("../core/print/dataflow-printer").dataflowGraphToJson;
|
|
563
|
+
readonly 5: typeof import("../core/print/dataflow-printer").dataflowGraphToQuads;
|
|
564
|
+
readonly 3: typeof import("../core/print/dataflow-printer").dataflowGraphToMermaid;
|
|
565
|
+
readonly 4: typeof import("../core/print/dataflow-printer").dataflowGraphToMermaidUrl;
|
|
566
|
+
};
|
|
567
|
+
readonly dependencies: readonly ["normalize"];
|
|
568
|
+
}>>, queryResults: BaseQueryResult, result: string[]) => true;
|
|
569
|
+
readonly schema: Joi.ObjectSchema<any>;
|
|
570
|
+
};
|
|
512
571
|
};
|
|
513
572
|
export type SupportedQueryTypes = keyof typeof SupportedQueries;
|
|
514
573
|
export type QueryResult<Type extends Query['type']> = ReturnType<typeof SupportedQueries[Type]['executor']>;
|
package/queries/query.js
CHANGED
|
@@ -24,6 +24,7 @@ const joi_1 = __importDefault(require("joi"));
|
|
|
24
24
|
const location_map_query_format_1 = require("./catalog/location-map-query/location-map-query-format");
|
|
25
25
|
const config_query_format_1 = require("./catalog/config-query/config-query-format");
|
|
26
26
|
const search_query_format_1 = require("./catalog/search-query/search-query-format");
|
|
27
|
+
const happens_before_query_format_1 = require("./catalog/happens-before-query/happens-before-query-format");
|
|
27
28
|
exports.SupportedQueries = {
|
|
28
29
|
'call-context': call_context_query_format_1.CallContextQueryDefinition,
|
|
29
30
|
'config': config_query_format_1.ConfigQueryDefinition,
|
|
@@ -35,7 +36,8 @@ exports.SupportedQueries = {
|
|
|
35
36
|
'lineage': lineage_query_format_1.LineageQueryDefinition,
|
|
36
37
|
'dependencies': dependencies_query_format_1.DependenciesQueryDefinition,
|
|
37
38
|
'location-map': location_map_query_format_1.LocationMapQueryDefinition,
|
|
38
|
-
'search': search_query_format_1.SearchQueryDefinition
|
|
39
|
+
'search': search_query_format_1.SearchQueryDefinition,
|
|
40
|
+
'happens-before': happens_before_query_format_1.HappensBeforeQueryDefinition
|
|
39
41
|
};
|
|
40
42
|
function executeQueriesOfSameType(data, ...queries) {
|
|
41
43
|
(0, assert_1.guard)(queries.length > 0, 'At least one query must be provided');
|
package/util/cfg/cfg.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ interface CfgFlowDependencyEdge extends MergeableRecord {
|
|
|
25
25
|
}
|
|
26
26
|
interface CfgControlDependencyEdge extends MergeableRecord {
|
|
27
27
|
label: 'CD';
|
|
28
|
+
/** the id which caused the control dependency */
|
|
29
|
+
caused: NodeId;
|
|
28
30
|
when: typeof RTrue | typeof RFalse;
|
|
29
31
|
}
|
|
30
32
|
export type CfgEdge = CfgFlowDependencyEdge | CfgControlDependencyEdge;
|
package/util/cfg/cfg.js
CHANGED
|
@@ -134,10 +134,10 @@ function cfgIfThenElse(ifNode, condition, then, otherwise) {
|
|
|
134
134
|
}
|
|
135
135
|
for (const exitPoint of condition.exitPoints) {
|
|
136
136
|
for (const entryPoint of then.entryPoints) {
|
|
137
|
-
graph.addEdge(entryPoint, exitPoint, { label: 'CD', when: convert_values_1.RTrue });
|
|
137
|
+
graph.addEdge(entryPoint, exitPoint, { label: 'CD', when: convert_values_1.RTrue, caused: ifNode.info.id });
|
|
138
138
|
}
|
|
139
139
|
for (const entryPoint of otherwise?.entryPoints ?? []) {
|
|
140
|
-
graph.addEdge(entryPoint, exitPoint, { label: 'CD', when: convert_values_1.RFalse });
|
|
140
|
+
graph.addEdge(entryPoint, exitPoint, { label: 'CD', when: convert_values_1.RFalse, caused: ifNode.info.id });
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
for (const entryPoint of condition.entryPoints) {
|
|
@@ -148,7 +148,7 @@ function cfgIfThenElse(ifNode, condition, then, otherwise) {
|
|
|
148
148
|
}
|
|
149
149
|
if (!otherwise) {
|
|
150
150
|
for (const exitPoint of condition.exitPoints) {
|
|
151
|
-
graph.addEdge(ifNode.info.id + '-exit', exitPoint, { label: 'CD', when: convert_values_1.RFalse });
|
|
151
|
+
graph.addEdge(ifNode.info.id + '-exit', exitPoint, { label: 'CD', when: convert_values_1.RFalse, caused: ifNode.info.id });
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
return {
|
|
@@ -165,7 +165,7 @@ function cfgRepeat(repeat, body) {
|
|
|
165
165
|
graph.addVertex({ id: repeat.info.id, name: repeat.type, type: identifyMayStatementType(repeat) });
|
|
166
166
|
graph.addVertex({ id: repeat.info.id + '-exit', name: 'repeat-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
|
|
167
167
|
for (const entryPoint of body.entryPoints) {
|
|
168
|
-
graph.addEdge(repeat.info.id,
|
|
168
|
+
graph.addEdge(entryPoint, repeat.info.id, { label: 'FD' });
|
|
169
169
|
}
|
|
170
170
|
// loops automatically
|
|
171
171
|
for (const next of [...body.nexts, ...body.exitPoints]) {
|
|
@@ -186,7 +186,7 @@ function cfgWhile(whileLoop, condition, body) {
|
|
|
186
186
|
}
|
|
187
187
|
for (const exit of condition.exitPoints) {
|
|
188
188
|
for (const entry of body.entryPoints) {
|
|
189
|
-
graph.addEdge(entry, exit, { label: 'CD', when: convert_values_1.RTrue });
|
|
189
|
+
graph.addEdge(entry, exit, { label: 'CD', when: convert_values_1.RTrue, caused: whileLoop.info.id });
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
for (const entryPoint of body.entryPoints) {
|
|
@@ -200,7 +200,7 @@ function cfgWhile(whileLoop, condition, body) {
|
|
|
200
200
|
}
|
|
201
201
|
// while can break on the condition as well
|
|
202
202
|
for (const exit of condition.exitPoints) {
|
|
203
|
-
graph.addEdge(whileLoop.info.id + '-exit', exit, { label: 'CD', when: convert_values_1.RFalse });
|
|
203
|
+
graph.addEdge(whileLoop.info.id + '-exit', exit, { label: 'CD', when: convert_values_1.RFalse, caused: whileLoop.info.id });
|
|
204
204
|
}
|
|
205
205
|
return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [whileLoop.info.id + '-exit'], entryPoints: [whileLoop.info.id] };
|
|
206
206
|
}
|
|
@@ -220,7 +220,7 @@ function cfgFor(forLoop, variable, vector, body) {
|
|
|
220
220
|
}
|
|
221
221
|
for (const exit of variable.exitPoints) {
|
|
222
222
|
for (const entry of body.entryPoints) {
|
|
223
|
-
graph.addEdge(entry, exit, { label: 'CD', when: convert_values_1.RTrue });
|
|
223
|
+
graph.addEdge(entry, exit, { label: 'CD', when: convert_values_1.RTrue, caused: forLoop.info.id });
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
for (const next of [...body.nexts, ...body.exitPoints]) {
|
|
@@ -231,7 +231,7 @@ function cfgFor(forLoop, variable, vector, body) {
|
|
|
231
231
|
}
|
|
232
232
|
// while can break on the condition as well
|
|
233
233
|
for (const exit of variable.exitPoints) {
|
|
234
|
-
graph.addEdge(forLoop.info.id + '-exit', exit, { label: 'CD', when: convert_values_1.RFalse });
|
|
234
|
+
graph.addEdge(forLoop.info.id + '-exit', exit, { label: 'CD', when: convert_values_1.RFalse, caused: forLoop.info.id });
|
|
235
235
|
}
|
|
236
236
|
return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [forLoop.info.id + '-exit'], entryPoints: [forLoop.info.id] };
|
|
237
237
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ControlFlowGraph } from './cfg';
|
|
2
|
+
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
|
+
import { Ternary } from '../logic';
|
|
4
|
+
/**
|
|
5
|
+
* Determines if node `a` happens before node `b` in the control flow graph.
|
|
6
|
+
*/
|
|
7
|
+
export declare function happensBefore(cfg: ControlFlowGraph, a: NodeId, b: NodeId): Ternary;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.happensBefore = happensBefore;
|
|
4
|
+
const logic_1 = require("../logic");
|
|
5
|
+
/**
|
|
6
|
+
* Determines if node `a` happens before node `b` in the control flow graph.
|
|
7
|
+
*/
|
|
8
|
+
function happensBefore(cfg, a, b) {
|
|
9
|
+
const visited = new Set();
|
|
10
|
+
/* the first is the id we are currently at, the second one the exit marker of the current largest cd scope */
|
|
11
|
+
const stack = [[b, undefined]];
|
|
12
|
+
while (stack.length > 0) {
|
|
13
|
+
const [current, cd] = stack.pop();
|
|
14
|
+
let useCd = cd;
|
|
15
|
+
if (current === a) {
|
|
16
|
+
return cd ? logic_1.Ternary.Maybe : logic_1.Ternary.Always;
|
|
17
|
+
}
|
|
18
|
+
else if (visited.has(current)) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
else if (cd && (current === cd || visited.has(cd))) {
|
|
22
|
+
useCd = undefined;
|
|
23
|
+
}
|
|
24
|
+
visited.add(current);
|
|
25
|
+
for (const [id, t] of cfg.outgoing(current) ?? []) {
|
|
26
|
+
const marker = t.label === 'CD' ? `${t.caused}-exit` : useCd;
|
|
27
|
+
stack.push([id, useCd ?? marker]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return logic_1.Ternary.Never;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=happens-before.js.map
|
package/util/logic.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare
|
|
2
|
-
Always =
|
|
3
|
-
Maybe =
|
|
4
|
-
Never =
|
|
1
|
+
export declare enum Ternary {
|
|
2
|
+
Always = "always",
|
|
3
|
+
Maybe = "maybe",
|
|
4
|
+
Never = "never"
|
|
5
5
|
}
|
package/util/logic.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Ternary = void 0;
|
|
4
|
+
// diverging from boolean | maybe requires explicit handling
|
|
5
|
+
var Ternary;
|
|
6
|
+
(function (Ternary) {
|
|
7
|
+
Ternary["Always"] = "always";
|
|
8
|
+
Ternary["Maybe"] = "maybe";
|
|
9
|
+
Ternary["Never"] = "never";
|
|
10
|
+
})(Ternary || (exports.Ternary = Ternary = {}));
|
|
3
11
|
//# sourceMappingURL=logic.js.map
|
package/util/version.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.flowrVersion = flowrVersion;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
5
|
// this is automatically replaced with the current version by release-it
|
|
6
|
-
const version = '2.2.
|
|
6
|
+
const version = '2.2.1';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|