@eagleoutice/flowr 2.1.9 → 2.1.11
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/README.md +3 -0
- package/cli/flowr.js +8 -0
- package/cli/repl/commands/repl-query.js +13 -2
- package/config.d.ts +21 -0
- package/config.js +19 -2
- package/dataflow/environments/built-in.d.ts +2 -0
- package/dataflow/environments/built-in.js +2 -0
- package/dataflow/environments/default-builtin-config.js +3 -2
- package/dataflow/environments/define.js +78 -0
- package/dataflow/environments/identifier.d.ts +11 -3
- package/dataflow/environments/resolve-by-name.d.ts +12 -6
- package/dataflow/environments/resolve-by-name.js +105 -6
- package/dataflow/graph/vertex.d.ts +56 -1
- package/dataflow/graph/vertex.js +4 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +11 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +144 -49
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +7 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +47 -16
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-list.d.ts +15 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-list.js +50 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +30 -1
- package/dataflow/internal/process/functions/call/common.js +15 -1
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +2 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +3 -2
- package/documentation/print-interface-wiki.js +13 -3
- package/documentation/print-query-wiki.js +13 -0
- package/package.json +1 -1
- package/queries/catalog/config-query/config-query-executor.d.ts +3 -0
- package/queries/catalog/config-query/config-query-executor.js +18 -0
- package/queries/catalog/config-query/config-query-format.d.ts +16 -0
- package/queries/catalog/config-query/config-query-format.js +24 -0
- package/queries/catalog/location-map-query/location-map-query-format.js +1 -1
- package/queries/query.d.ts +7 -1
- package/queries/query.js +2 -0
- package/util/list-access.d.ts +48 -0
- package/util/list-access.js +115 -0
- package/util/version.js +1 -1
package/README.md
CHANGED
|
@@ -47,6 +47,9 @@ We welcome every contribution! Please check out the [contributing guidelines](ht
|
|
|
47
47
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Core5563"><img src="https://avatars.githubusercontent.com/u/140061253?v=4?s=100" width="100px;" alt="Core5563"/><br /><sub><b>Core5563</b></sub></a><br /><a href="https://github.com/flowr-analysis/flowr/commits?author=Core5563" title="Code">💻</a> <a href="https://github.com/flowr-analysis/flowr/commits?author=Core5563" title="Tests">⚠️</a></td>
|
|
48
48
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ehcsan"><img src="https://avatars.githubusercontent.com/u/68707578?v=4?s=100" width="100px;" alt="Ehcsan"/><br /><sub><b>Ehcsan</b></sub></a><br /><a href="https://github.com/flowr-analysis/flowr/commits?author=Ehcsan" title="Code">💻</a> <a href="https://github.com/flowr-analysis/flowr/commits?author=Ehcsan" title="Tests">⚠️</a></td>
|
|
49
49
|
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Slartibartfass2"><img src="https://avatars.githubusercontent.com/u/40503329?v=4?s=100" width="100px;" alt="Felix Schlegel"/><br /><sub><b>Felix Schlegel</b></sub></a><br /><a href="https://github.com/flowr-analysis/flowr/commits?author=Slartibartfass2" title="Code">💻</a> <a href="https://github.com/flowr-analysis/flowr/commits?author=Slartibartfass2" title="Tests">⚠️</a></td>
|
|
52
|
+
</tr>
|
|
50
53
|
</tbody>
|
|
51
54
|
<tfoot>
|
|
52
55
|
<tr>
|
package/cli/flowr.js
CHANGED
|
@@ -21,6 +21,7 @@ const core_1 = require("./repl/core");
|
|
|
21
21
|
const repl_version_1 = require("./repl/commands/repl-version");
|
|
22
22
|
const print_version_1 = require("./repl/print-version");
|
|
23
23
|
const flowr_main_options_1 = require("./flowr-main-options");
|
|
24
|
+
const fs_1 = __importDefault(require("fs"));
|
|
24
25
|
exports.toolName = 'flowr';
|
|
25
26
|
exports.optionHelp = [
|
|
26
27
|
{
|
|
@@ -59,6 +60,13 @@ if (options['config-json']) {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
if (!usedConfig) {
|
|
63
|
+
if (options['config-file']) {
|
|
64
|
+
// validate it exists
|
|
65
|
+
if (!fs_1.default.existsSync(options['config-file'])) {
|
|
66
|
+
log_1.log.error(`Config file '${options['config-file']}' does not exist`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
62
70
|
(0, config_1.setConfigFile)(options['config-file'] ?? flowr_main_options_1.defaultConfigFile, undefined, true);
|
|
63
71
|
}
|
|
64
72
|
function retrieveShell() {
|
|
@@ -21,8 +21,10 @@ function printHelp(output) {
|
|
|
21
21
|
output.stdout('The query is an array of query objects to represent multiple queries. Each query object may have the following properties:');
|
|
22
22
|
output.stdout((0, schema_1.describeSchema)((0, query_1.AnyQuerySchema)(), output.formatter));
|
|
23
23
|
output.stdout(`\n\nThe example ${(0, ansi_1.italic)(':query "[{\\"type\\": \\"call-context\\", \\"callName\\": \\"mean\\" }]" mean(1:10)', output.formatter)} would return the call context of the mean function.`);
|
|
24
|
-
output.stdout('As a convenience, we interpret any (non-help) string not starting with \'[\' as a regex for the simple call-context query.');
|
|
24
|
+
output.stdout('As a convenience, we interpret any (non-help, non-@) string not starting with \'[\' as a regex for the simple call-context query.');
|
|
25
25
|
output.stdout(`Hence, ${(0, ansi_1.italic)(':query "mean" mean(1:10)', output.formatter)} is equivalent to the above example.`);
|
|
26
|
+
output.stdout(`Similarly, '@<type>' is interpreted as a query of the given type.`);
|
|
27
|
+
output.stdout(`With this, ${(0, ansi_1.italic)(':query @config', output.formatter)} prints the result of the config query.`);
|
|
26
28
|
}
|
|
27
29
|
async function processQueryArgs(line, shell, output) {
|
|
28
30
|
const args = (0, args_1.splitAtEscapeSensitive)(line);
|
|
@@ -36,7 +38,16 @@ async function processQueryArgs(line, shell, output) {
|
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
40
|
let parsedQuery = [];
|
|
39
|
-
if (query.startsWith('
|
|
41
|
+
if (query.startsWith('@')) {
|
|
42
|
+
parsedQuery = [{ type: query.slice(1) }];
|
|
43
|
+
const validationResult = (0, query_1.QueriesSchema)().validate(parsedQuery);
|
|
44
|
+
if (validationResult.error) {
|
|
45
|
+
output.stderr(`Invalid query: ${validationResult.error.message}`);
|
|
46
|
+
printHelp(output);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (query.startsWith('[')) {
|
|
40
51
|
parsedQuery = JSON.parse(query);
|
|
41
52
|
const validationResult = (0, query_1.QueriesSchema)().validate(parsedQuery);
|
|
42
53
|
if (validationResult.error) {
|
package/config.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { MergeableRecord } from './util/objects';
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import type { BuiltInDefinitions } from './dataflow/environments/built-in-config';
|
|
4
|
+
export declare enum VariableResolve {
|
|
5
|
+
/** Don't resolve constants at all */
|
|
6
|
+
Disabled = "disabled",
|
|
7
|
+
/** Use alias tracking to resolve */
|
|
8
|
+
Alias = "alias",
|
|
9
|
+
/** Only resolve directly assigned builtin constants */
|
|
10
|
+
Builtin = "builtin"
|
|
11
|
+
}
|
|
4
12
|
export interface FlowrConfigOptions extends MergeableRecord {
|
|
5
13
|
/**
|
|
6
14
|
* Whether source calls should be ignored, causing {@link processSourceCall}'s behavior to be skipped
|
|
@@ -23,6 +31,19 @@ export interface FlowrConfigOptions extends MergeableRecord {
|
|
|
23
31
|
};
|
|
24
32
|
};
|
|
25
33
|
};
|
|
34
|
+
/** How to resolve constants, constraints, cells, ... */
|
|
35
|
+
readonly solver: {
|
|
36
|
+
/**
|
|
37
|
+
* How to resolve variables and their values
|
|
38
|
+
*/
|
|
39
|
+
readonly variables: VariableResolve;
|
|
40
|
+
/**
|
|
41
|
+
* Whether to track pointers in the dataflow graph,
|
|
42
|
+
* if not, the graph will be over-approximated wrt.
|
|
43
|
+
* containers and accesses
|
|
44
|
+
*/
|
|
45
|
+
readonly pointerTracking: boolean;
|
|
46
|
+
};
|
|
26
47
|
}
|
|
27
48
|
export declare const defaultConfigOptions: FlowrConfigOptions;
|
|
28
49
|
export declare const flowrConfigFileSchema: Joi.ObjectSchema<any>;
|
package/config.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.flowrConfigFileSchema = exports.defaultConfigOptions = void 0;
|
|
6
|
+
exports.flowrConfigFileSchema = exports.defaultConfigOptions = exports.VariableResolve = void 0;
|
|
7
7
|
exports.setConfigFile = setConfigFile;
|
|
8
8
|
exports.parseConfig = parseConfig;
|
|
9
9
|
exports.setConfig = setConfig;
|
|
@@ -14,6 +14,15 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
14
14
|
const log_1 = require("./util/log");
|
|
15
15
|
const files_1 = require("./util/files");
|
|
16
16
|
const joi_1 = __importDefault(require("joi"));
|
|
17
|
+
var VariableResolve;
|
|
18
|
+
(function (VariableResolve) {
|
|
19
|
+
/** Don't resolve constants at all */
|
|
20
|
+
VariableResolve["Disabled"] = "disabled";
|
|
21
|
+
/** Use alias tracking to resolve */
|
|
22
|
+
VariableResolve["Alias"] = "alias";
|
|
23
|
+
/** Only resolve directly assigned builtin constants */
|
|
24
|
+
VariableResolve["Builtin"] = "builtin";
|
|
25
|
+
})(VariableResolve || (exports.VariableResolve = VariableResolve = {}));
|
|
17
26
|
exports.defaultConfigOptions = {
|
|
18
27
|
ignoreSourceCalls: false,
|
|
19
28
|
rPath: undefined,
|
|
@@ -24,6 +33,10 @@ exports.defaultConfigOptions = {
|
|
|
24
33
|
definitions: []
|
|
25
34
|
}
|
|
26
35
|
}
|
|
36
|
+
},
|
|
37
|
+
solver: {
|
|
38
|
+
variables: VariableResolve.Alias,
|
|
39
|
+
pointerTracking: true
|
|
27
40
|
}
|
|
28
41
|
};
|
|
29
42
|
exports.flowrConfigFileSchema = joi_1.default.object({
|
|
@@ -36,7 +49,11 @@ exports.flowrConfigFileSchema = joi_1.default.object({
|
|
|
36
49
|
definitions: joi_1.default.array().items(joi_1.default.object()).optional().description('The definitions to load/overwrite.')
|
|
37
50
|
}).optional().description('Do you want to overwrite (parts) of the builtin definition?')
|
|
38
51
|
}).optional().description('Semantics regarding the handlings of the environment.')
|
|
39
|
-
}).description('Configure language semantics and how flowR handles them.')
|
|
52
|
+
}).description('Configure language semantics and how flowR handles them.'),
|
|
53
|
+
solver: joi_1.default.object({
|
|
54
|
+
variables: joi_1.default.string().valid(...Object.values(VariableResolve)).description('How to resolve variables and their values.'),
|
|
55
|
+
pointerTracking: joi_1.default.boolean().description('Whether to track pointers in the dataflow graph, if not, the graph will be over-approximated wrt. containers and accesses.')
|
|
56
|
+
}).description('How to resolve constants, constraints, cells, ...')
|
|
40
57
|
}).description('The configuration file format for flowR.');
|
|
41
58
|
// we don't load from a config file at all by default unless setConfigFile is called
|
|
42
59
|
let configFile = undefined;
|
|
@@ -24,6 +24,7 @@ import { processSourceCall } from '../internal/process/functions/call/built-in/b
|
|
|
24
24
|
import type { ForceArguments } from '../internal/process/functions/call/common';
|
|
25
25
|
import { processApply } from '../internal/process/functions/call/built-in/built-in-apply';
|
|
26
26
|
import type { LinkTo } from '../../queries/catalog/call-context-query/call-context-query-format';
|
|
27
|
+
import { processList } from '../internal/process/functions/call/built-in/built-in-list';
|
|
27
28
|
export declare const BuiltIn = "built-in";
|
|
28
29
|
export type BuiltInIdentifierProcessor = <OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>) => DataflowInformation;
|
|
29
30
|
export type BuiltInIdentifierProcessorWithConfig<Config> = <OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: Config) => DataflowInformation;
|
|
@@ -63,6 +64,7 @@ export declare const BuiltInProcessorMapper: {
|
|
|
63
64
|
readonly 'builtin:repeat-loop': typeof processRepeatLoop;
|
|
64
65
|
readonly 'builtin:while-loop': typeof processWhileLoop;
|
|
65
66
|
readonly 'builtin:replacement': typeof processReplacementFunction;
|
|
67
|
+
readonly 'builtin:list': typeof processList;
|
|
66
68
|
};
|
|
67
69
|
export type BuiltInMappingName = keyof typeof BuiltInProcessorMapper;
|
|
68
70
|
export type ConfigOfBuiltInMappingName<N extends BuiltInMappingName> = Parameters<typeof BuiltInProcessorMapper[N]>[4];
|
|
@@ -24,6 +24,7 @@ const built_in_source_1 = require("../internal/process/functions/call/built-in/b
|
|
|
24
24
|
const built_in_apply_1 = require("../internal/process/functions/call/built-in/built-in-apply");
|
|
25
25
|
const built_in_config_1 = require("./built-in-config");
|
|
26
26
|
const default_builtin_config_1 = require("./default-builtin-config");
|
|
27
|
+
const built_in_list_1 = require("../internal/process/functions/call/built-in/built-in-list");
|
|
27
28
|
exports.BuiltIn = 'built-in';
|
|
28
29
|
function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
29
30
|
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
|
|
@@ -88,6 +89,7 @@ exports.BuiltInProcessorMapper = {
|
|
|
88
89
|
'builtin:repeat-loop': built_in_repeat_loop_1.processRepeatLoop,
|
|
89
90
|
'builtin:while-loop': built_in_while_loop_1.processWhileLoop,
|
|
90
91
|
'builtin:replacement': built_in_replacement_1.processReplacementFunction,
|
|
92
|
+
'builtin:list': built_in_list_1.processList,
|
|
91
93
|
};
|
|
92
94
|
exports.BuiltInMemory = new Map();
|
|
93
95
|
exports.EmptyBuiltInMemory = new Map();
|
|
@@ -14,7 +14,7 @@ exports.DefaultBuiltinConfig = [
|
|
|
14
14
|
{
|
|
15
15
|
type: 'function',
|
|
16
16
|
names: [
|
|
17
|
-
'~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':',
|
|
17
|
+
'~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':',
|
|
18
18
|
'rep', 'seq', 'seq_len', 'seq_along', 'seq.int', 'gsub', 'which', 'class', 'dimnames', 'min', 'max',
|
|
19
19
|
'intersect', 'subset', 'match', 'sqrt', 'abs', 'round', 'floor', 'ceiling', 'signif', 'trunc', 'log', 'log10', 'log2', 'sum', 'mean',
|
|
20
20
|
'unique', 'paste', 'paste0', 'read.csv', 'stop', 'is.null', 'numeric', 'as.character', 'as.integer', 'as.logical', 'as.numeric', 'as.matrix',
|
|
@@ -29,7 +29,7 @@ exports.DefaultBuiltinConfig = [
|
|
|
29
29
|
{
|
|
30
30
|
type: 'function',
|
|
31
31
|
names: [
|
|
32
|
-
'c', 't'
|
|
32
|
+
'c', 't', 'aperm' /* vector construction, concatenation, transpose function, permutation generation */
|
|
33
33
|
],
|
|
34
34
|
processor: 'builtin:default',
|
|
35
35
|
config: { readAllArguments: true },
|
|
@@ -113,6 +113,7 @@ exports.DefaultBuiltinConfig = [
|
|
|
113
113
|
{ type: 'function', names: ['repeat'], processor: 'builtin:repeat-loop', config: {}, assumePrimitive: true },
|
|
114
114
|
{ type: 'function', names: ['while'], processor: 'builtin:while-loop', config: {}, assumePrimitive: true },
|
|
115
115
|
{ type: 'function', names: ['do.call'], processor: 'builtin:apply', config: { indexOfFunction: 0, unquoteFunction: true }, assumePrimitive: true },
|
|
116
|
+
{ type: 'function', names: ['list'], processor: 'builtin:list', config: {}, assumePrimitive: true },
|
|
116
117
|
{
|
|
117
118
|
type: 'function',
|
|
118
119
|
names: [
|
|
@@ -4,8 +4,15 @@ exports.define = define;
|
|
|
4
4
|
const assert_1 = require("../../util/assert");
|
|
5
5
|
const environment_1 = require("./environment");
|
|
6
6
|
const clone_1 = require("./clone");
|
|
7
|
+
const vertex_1 = require("../graph/vertex");
|
|
7
8
|
function defInEnv(newEnvironments, name, definition) {
|
|
8
9
|
const existing = newEnvironments.memory.get(name);
|
|
10
|
+
// When there are defined indices, merge the definitions
|
|
11
|
+
const inGraphDefinition = definition;
|
|
12
|
+
if (existing !== undefined && inGraphDefinition.indicesCollection !== undefined && inGraphDefinition.controlDependencies === undefined) {
|
|
13
|
+
newEnvironments.memory.set(name, mergeDefinitions(existing, inGraphDefinition));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
9
16
|
// check if it is maybe or not
|
|
10
17
|
if (existing === undefined || definition.controlDependencies === undefined) {
|
|
11
18
|
newEnvironments.memory.set(name, [definition]);
|
|
@@ -14,6 +21,77 @@ function defInEnv(newEnvironments, name, definition) {
|
|
|
14
21
|
existing.push(definition);
|
|
15
22
|
}
|
|
16
23
|
}
|
|
24
|
+
function mergeDefinitions(existing, definition) {
|
|
25
|
+
// When new definition is not a single index, e.g., a list redefinition, then reset existing definition
|
|
26
|
+
if (definition.indicesCollection?.some(indices => indices.isContainer)) {
|
|
27
|
+
return [definition];
|
|
28
|
+
}
|
|
29
|
+
const existingDefs = existing.map((def) => def).filter((def) => def !== undefined);
|
|
30
|
+
const overwriteIndices = definition.indicesCollection?.flatMap(indices => indices.indices) ?? [];
|
|
31
|
+
// Compare existing and new definitions,
|
|
32
|
+
// add new definitions and remove existing definitions that are overwritten by new definition
|
|
33
|
+
const newExistingDefs = [];
|
|
34
|
+
for (const overwriteIndex of overwriteIndices) {
|
|
35
|
+
for (const existingDef of existingDefs) {
|
|
36
|
+
if (existingDef.indicesCollection === undefined) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const newIndicesCollection = overwriteContainerIndices(existingDef.indicesCollection, overwriteIndex);
|
|
40
|
+
// if indices are now empty list, don't keep empty definition
|
|
41
|
+
if (newIndicesCollection.length > 0) {
|
|
42
|
+
newExistingDefs.push({
|
|
43
|
+
...existingDef,
|
|
44
|
+
indicesCollection: newIndicesCollection,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// store changed existing definitions and add new one
|
|
50
|
+
return [...newExistingDefs, definition];
|
|
51
|
+
}
|
|
52
|
+
function overwriteContainerIndices(existingIndices, overwriteIndex) {
|
|
53
|
+
const newIndicesCollection = [];
|
|
54
|
+
for (const indices of existingIndices) {
|
|
55
|
+
let newIndices;
|
|
56
|
+
// When overwrite index is container itself, then only overwrite sub-index
|
|
57
|
+
if ((0, vertex_1.isParentContainerIndex)(overwriteIndex)) {
|
|
58
|
+
newIndices = [];
|
|
59
|
+
for (const index of indices.indices) {
|
|
60
|
+
if (index.lexeme === overwriteIndex.lexeme && (0, vertex_1.isParentContainerIndex)(index)) {
|
|
61
|
+
const overwriteSubIndices = overwriteIndex.subIndices.flatMap(a => a.indices);
|
|
62
|
+
let newSubIndices = index.subIndices;
|
|
63
|
+
for (const overwriteSubIndex of overwriteSubIndices) {
|
|
64
|
+
newSubIndices = overwriteContainerIndices(newSubIndices, overwriteSubIndex);
|
|
65
|
+
}
|
|
66
|
+
if (newSubIndices.length > 0) {
|
|
67
|
+
newIndices.push({
|
|
68
|
+
...index,
|
|
69
|
+
subIndices: newSubIndices,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (index.lexeme !== overwriteIndex.lexeme || !(0, vertex_1.isParentContainerIndex)(index)) {
|
|
74
|
+
newIndices.push(index);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (indices.isContainer) {
|
|
79
|
+
// If indices are not a single, e.g., a list, take the whole definition
|
|
80
|
+
newIndices = indices.indices;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Filter existing indices with the same name
|
|
84
|
+
newIndices = indices.indices.filter(def => def.lexeme !== overwriteIndex.lexeme);
|
|
85
|
+
}
|
|
86
|
+
if (indices.isContainer || newIndices.length > 0) {
|
|
87
|
+
newIndicesCollection.push({
|
|
88
|
+
...indices,
|
|
89
|
+
indices: newIndices,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return newIndicesCollection;
|
|
94
|
+
}
|
|
17
95
|
/**
|
|
18
96
|
* Insert the given `definition` --- defined within the given scope --- into the passed along `environments` will take care of propagation.
|
|
19
97
|
* Does not modify the passed along `environments` in-place! It returns the new reference.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BuiltInIdentifierConstant, BuiltInIdentifierDefinition } from './built-in';
|
|
2
2
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
3
|
import type { ControlDependency } from '../info';
|
|
4
|
+
import type { ContainerIndicesCollection } from '../graph/vertex';
|
|
4
5
|
export type Identifier = string & {
|
|
5
6
|
__brand?: 'identifier';
|
|
6
7
|
};
|
|
@@ -90,10 +91,18 @@ export interface IdentifierReference {
|
|
|
90
91
|
*
|
|
91
92
|
* @see {@link IdentifierReference}
|
|
92
93
|
*/
|
|
93
|
-
interface InGraphIdentifierDefinition extends IdentifierReference {
|
|
94
|
+
export interface InGraphIdentifierDefinition extends IdentifierReference {
|
|
94
95
|
readonly type: InGraphReferenceType;
|
|
95
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* The assignment node which ultimately defined this identifier
|
|
98
|
+
* (the arrow operator for e.g. `x <- 3`, or `assign` call in `assign("x", 3)`)
|
|
99
|
+
*/
|
|
96
100
|
readonly definedAt: NodeId;
|
|
101
|
+
readonly value?: NodeId[];
|
|
102
|
+
/**
|
|
103
|
+
* this attribute links a definition to indices (pointer links) it may be affected by or related to
|
|
104
|
+
*/
|
|
105
|
+
indicesCollection?: ContainerIndicesCollection;
|
|
97
106
|
}
|
|
98
107
|
/**
|
|
99
108
|
* Stores the definition of an identifier within an {@link IEnvironment}.
|
|
@@ -102,4 +111,3 @@ interface InGraphIdentifierDefinition extends IdentifierReference {
|
|
|
102
111
|
* so the most important one for your day-to-day R script is the {@link InGraphIdentifierDefinition}.
|
|
103
112
|
*/
|
|
104
113
|
export type IdentifierDefinition = InGraphIdentifierDefinition | BuiltInIdentifierDefinition | BuiltInIdentifierConstant;
|
|
105
|
-
export {};
|
|
@@ -2,6 +2,8 @@ import type { REnvironmentInformation } from './environment';
|
|
|
2
2
|
import { Ternary } from '../../util/logic';
|
|
3
3
|
import type { Identifier, IdentifierDefinition } from './identifier';
|
|
4
4
|
import { ReferenceType } from './identifier';
|
|
5
|
+
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
6
|
+
import type { DataflowGraph } from '../graph/graph';
|
|
5
7
|
/**
|
|
6
8
|
* Resolves a given identifier name to a list of its possible definition location using R scoping and resolving rules.
|
|
7
9
|
*
|
|
@@ -9,12 +11,16 @@ import { ReferenceType } from './identifier';
|
|
|
9
11
|
* @param environment - The current environment used for name resolution
|
|
10
12
|
* @param target - The target (meta) type of the identifier to resolve
|
|
11
13
|
*
|
|
12
|
-
* @returns A list of possible definitions
|
|
14
|
+
* @returns A list of possible identifier definitions (one if the definition location is exactly and always known), or `undefined`
|
|
15
|
+
* if the identifier is undefined in the current scope/with the current environment information.
|
|
13
16
|
*/
|
|
14
17
|
export declare function resolveByName(name: Identifier, environment: REnvironmentInformation, target?: ReferenceType): IdentifierDefinition[] | undefined;
|
|
15
18
|
export declare function resolvesToBuiltInConstant(name: Identifier | undefined, environment: REnvironmentInformation, wantedValue: unknown): Ternary;
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
export declare function resolveToConstants(name: Identifier | undefined, environment: REnvironmentInformation): unknown[] | undefined;
|
|
20
|
+
export declare function getAliases(sourceIds: readonly NodeId[], dataflow: DataflowGraph, environment: REnvironmentInformation): NodeId[] | undefined;
|
|
21
|
+
export declare function resolveToValues(identifier: Identifier | undefined, environment: REnvironmentInformation, graph: DataflowGraph): unknown[] | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Convenience function using the variable resolver as specified within the configuration file
|
|
24
|
+
* In the future we may want to have this set once at the start of the analysis
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveValueOfVariable(identifier: Identifier | undefined, environment: REnvironmentInformation, graph: DataflowGraph): unknown[] | undefined;
|
|
@@ -3,9 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resolveByName = resolveByName;
|
|
4
4
|
exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
|
|
5
5
|
exports.resolveToConstants = resolveToConstants;
|
|
6
|
+
exports.getAliases = getAliases;
|
|
7
|
+
exports.resolveToValues = resolveToValues;
|
|
8
|
+
exports.resolveValueOfVariable = resolveValueOfVariable;
|
|
6
9
|
const environment_1 = require("./environment");
|
|
7
10
|
const identifier_1 = require("./identifier");
|
|
8
11
|
const info_1 = require("../info");
|
|
12
|
+
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
13
|
+
const vertex_1 = require("../graph/vertex");
|
|
14
|
+
const config_1 = require("../../config");
|
|
15
|
+
const assert_1 = require("../../util/assert");
|
|
9
16
|
const FunctionTargetTypes = identifier_1.ReferenceType.Function | identifier_1.ReferenceType.BuiltInFunction | identifier_1.ReferenceType.Unknown | identifier_1.ReferenceType.Argument | identifier_1.ReferenceType.Parameter;
|
|
10
17
|
const VariableTargetTypes = identifier_1.ReferenceType.Variable | identifier_1.ReferenceType.Parameter | identifier_1.ReferenceType.Argument | identifier_1.ReferenceType.Unknown;
|
|
11
18
|
const ConstantTargetTypes = identifier_1.ReferenceType.Constant | identifier_1.ReferenceType.BuiltInConstant | identifier_1.ReferenceType.Unknown;
|
|
@@ -28,7 +35,8 @@ const TargetTypePredicate = {
|
|
|
28
35
|
* @param environment - The current environment used for name resolution
|
|
29
36
|
* @param target - The target (meta) type of the identifier to resolve
|
|
30
37
|
*
|
|
31
|
-
* @returns A list of possible definitions
|
|
38
|
+
* @returns A list of possible identifier definitions (one if the definition location is exactly and always known), or `undefined`
|
|
39
|
+
* if the identifier is undefined in the current scope/with the current environment information.
|
|
32
40
|
*/
|
|
33
41
|
function resolveByName(name, environment, target = identifier_1.ReferenceType.Unknown) {
|
|
34
42
|
let current = environment.current;
|
|
@@ -86,12 +94,103 @@ function resolveToConstants(name, environment) {
|
|
|
86
94
|
return undefined;
|
|
87
95
|
}
|
|
88
96
|
const definitions = resolveByName(name, environment, identifier_1.ReferenceType.Constant);
|
|
89
|
-
|
|
97
|
+
return definitions?.map(def => def.value);
|
|
98
|
+
}
|
|
99
|
+
const AliasHandler = {
|
|
100
|
+
[vertex_1.VertexType.Value]: (sourceId) => [sourceId],
|
|
101
|
+
[vertex_1.VertexType.Use]: getUseAlias,
|
|
102
|
+
[vertex_1.VertexType.FunctionCall]: () => undefined,
|
|
103
|
+
[vertex_1.VertexType.FunctionDefinition]: () => undefined,
|
|
104
|
+
[vertex_1.VertexType.VariableDefinition]: () => undefined
|
|
105
|
+
};
|
|
106
|
+
function getUseAlias(sourceId, dataflow, environment) {
|
|
107
|
+
const definitions = [];
|
|
108
|
+
// Source is Symbol -> resolve definitions of symbol
|
|
109
|
+
const identifier = (0, node_id_1.recoverName)(sourceId, dataflow.idMap);
|
|
110
|
+
if (identifier === undefined) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
const defs = resolveByName(identifier, environment);
|
|
114
|
+
if (defs === undefined) {
|
|
90
115
|
return undefined;
|
|
91
116
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
for (const def of defs) {
|
|
118
|
+
// If one definition is not constant (or a variable aliasing a constant)
|
|
119
|
+
// we can't say for sure what value the source has
|
|
120
|
+
if (def.type === identifier_1.ReferenceType.Variable) {
|
|
121
|
+
if (def.value === undefined) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
definitions.push(...def.value);
|
|
125
|
+
}
|
|
126
|
+
else if (def.type === identifier_1.ReferenceType.Constant || def.type === identifier_1.ReferenceType.BuiltInConstant) {
|
|
127
|
+
definitions.push(def.nodeId);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return definitions;
|
|
134
|
+
}
|
|
135
|
+
function getAliases(sourceIds, dataflow, environment) {
|
|
136
|
+
const definitions = new Set();
|
|
137
|
+
for (const sourceId of sourceIds) {
|
|
138
|
+
const info = dataflow.getVertex(sourceId);
|
|
139
|
+
if (info === undefined) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
const defs = AliasHandler[info.tag](sourceId, dataflow, environment);
|
|
143
|
+
for (const def of defs ?? []) {
|
|
144
|
+
definitions.add(def);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return [...definitions];
|
|
148
|
+
}
|
|
149
|
+
function resolveToValues(identifier, environment, graph) {
|
|
150
|
+
if (identifier === undefined) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const defs = resolveByName(identifier, environment);
|
|
154
|
+
if (defs === undefined) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
const values = [];
|
|
158
|
+
for (const def of defs) {
|
|
159
|
+
if (def.type === identifier_1.ReferenceType.BuiltInConstant) {
|
|
160
|
+
values.push(def.value);
|
|
161
|
+
}
|
|
162
|
+
else if (def.type === identifier_1.ReferenceType.BuiltInFunction) {
|
|
163
|
+
// Tracked in #1207
|
|
164
|
+
}
|
|
165
|
+
else if (def.value !== undefined) {
|
|
166
|
+
/* if there is at least one location for which we have no idea, we have to give up for now! */
|
|
167
|
+
if (def.value.length === 0) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
for (const id of def.value) {
|
|
171
|
+
const value = graph.idMap?.get(id)?.content;
|
|
172
|
+
if (value !== undefined) {
|
|
173
|
+
values.push(value);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (values.length == 0) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
return values;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Convenience function using the variable resolver as specified within the configuration file
|
|
185
|
+
* In the future we may want to have this set once at the start of the analysis
|
|
186
|
+
*/
|
|
187
|
+
function resolveValueOfVariable(identifier, environment, graph) {
|
|
188
|
+
const resolve = (0, config_1.getConfig)().solver.variables;
|
|
189
|
+
switch (resolve) {
|
|
190
|
+
case config_1.VariableResolve.Alias: return resolveToValues(identifier, environment, graph);
|
|
191
|
+
case config_1.VariableResolve.Builtin: return resolveToConstants(identifier, environment);
|
|
192
|
+
case config_1.VariableResolve.Disabled: return [];
|
|
193
|
+
default: (0, assert_1.assertUnreachable)(resolve);
|
|
194
|
+
}
|
|
96
195
|
}
|
|
97
196
|
//# sourceMappingURL=resolve-by-name.js.map
|
|
@@ -10,6 +10,57 @@ export declare enum VertexType {
|
|
|
10
10
|
VariableDefinition = "variable-definition",
|
|
11
11
|
FunctionDefinition = "function-definition"
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* A single index of a container, which is not a container itself.
|
|
15
|
+
*
|
|
16
|
+
* This can be e.g. a string, number or boolean index.
|
|
17
|
+
*/
|
|
18
|
+
export interface ContainerLeafIndex {
|
|
19
|
+
/**
|
|
20
|
+
* Destinctive lexeme of index e.g 'name' for `list(name = 'John')`
|
|
21
|
+
*/
|
|
22
|
+
readonly lexeme: string;
|
|
23
|
+
/**
|
|
24
|
+
* NodeId of index in graph.
|
|
25
|
+
*/
|
|
26
|
+
readonly nodeId: NodeId;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A single index of a container, which is a container itself.
|
|
30
|
+
*
|
|
31
|
+
* This can be, e.g., a list, vector, or data frame.
|
|
32
|
+
*
|
|
33
|
+
* @see {@link ContainerLeafIndex} - for a single index of a container which is not a container itself
|
|
34
|
+
* @see {@link isParentContainerIndex} - to check if an index is a parent container index
|
|
35
|
+
*/
|
|
36
|
+
export interface ContainerParentIndex extends ContainerLeafIndex {
|
|
37
|
+
/**
|
|
38
|
+
* Sub-indices of index.
|
|
39
|
+
*/
|
|
40
|
+
readonly subIndices: ContainerIndices[];
|
|
41
|
+
}
|
|
42
|
+
export declare function isParentContainerIndex(index: ContainerIndex): index is ContainerParentIndex;
|
|
43
|
+
/**
|
|
44
|
+
* A single index of a container.
|
|
45
|
+
*/
|
|
46
|
+
export type ContainerIndex = ContainerLeafIndex | ContainerParentIndex;
|
|
47
|
+
/**
|
|
48
|
+
* List of indices of a single statement like `list(a=3, b=2)`
|
|
49
|
+
*/
|
|
50
|
+
export interface ContainerIndices {
|
|
51
|
+
readonly indices: ContainerIndex[];
|
|
52
|
+
/**
|
|
53
|
+
* Differentiate between single and multiple indices.
|
|
54
|
+
*
|
|
55
|
+
* For `list(name = 'John')` `isContainer` would be true, because a list may define more than one index.
|
|
56
|
+
* `isContainer` is true for e.g. single index assignments like `person$name <- 'John'`.
|
|
57
|
+
*/
|
|
58
|
+
readonly isContainer: boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Collection of Indices of several statements.
|
|
62
|
+
*/
|
|
63
|
+
export type ContainerIndicesCollection = ContainerIndices[] | undefined;
|
|
13
64
|
/**
|
|
14
65
|
* Arguments required to construct a vertex in the {@link DataflowGraph|dataflow graph}.
|
|
15
66
|
*
|
|
@@ -31,11 +82,15 @@ interface DataflowGraphVertexBase extends MergeableRecord {
|
|
|
31
82
|
/**
|
|
32
83
|
* The environment in which the vertex is set.
|
|
33
84
|
*/
|
|
34
|
-
environment?: REnvironmentInformation
|
|
85
|
+
environment?: REnvironmentInformation;
|
|
35
86
|
/**
|
|
36
87
|
* @see {@link ControlDependency} - the collection of control dependencies which have an influence on whether the vertex is executed.
|
|
37
88
|
*/
|
|
38
89
|
controlDependencies: ControlDependency[] | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* this attribute links a vertex to indices (pointer links) it may be affected by or related to
|
|
92
|
+
*/
|
|
93
|
+
indicesCollection?: ContainerIndicesCollection;
|
|
39
94
|
}
|
|
40
95
|
/**
|
|
41
96
|
* Marker vertex for a value in the dataflow of the program.
|
package/dataflow/graph/vertex.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.VertexType = void 0;
|
|
4
|
+
exports.isParentContainerIndex = isParentContainerIndex;
|
|
4
5
|
exports.isValueVertex = isValueVertex;
|
|
5
6
|
exports.isUseVertex = isUseVertex;
|
|
6
7
|
exports.isFunctionCallVertex = isFunctionCallVertex;
|
|
@@ -14,6 +15,9 @@ var VertexType;
|
|
|
14
15
|
VertexType["VariableDefinition"] = "variable-definition";
|
|
15
16
|
VertexType["FunctionDefinition"] = "function-definition";
|
|
16
17
|
})(VertexType || (exports.VertexType = VertexType = {}));
|
|
18
|
+
function isParentContainerIndex(index) {
|
|
19
|
+
return 'subIndices' in index;
|
|
20
|
+
}
|
|
17
21
|
/**
|
|
18
22
|
* Check if the given vertex is a {@link DataflowGraphVertexValue|value vertex}.
|
|
19
23
|
*/
|
|
@@ -5,6 +5,17 @@ import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/
|
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
7
|
import type { ForceArguments } from '../common';
|
|
8
|
+
/**
|
|
9
|
+
* Processes different types of access operations.
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* ```r
|
|
13
|
+
* a[i]
|
|
14
|
+
* a$foo
|
|
15
|
+
* a[[i]]
|
|
16
|
+
* a@foo
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
8
19
|
export declare function processAccess<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: {
|
|
9
20
|
treatIndicesAsString: boolean;
|
|
10
21
|
} & ForceArguments): DataflowInformation;
|