Skip to content

Commit 0216e11

Browse files
wip
1 parent 98af78b commit 0216e11

File tree

12 files changed

+315
-128
lines changed

12 files changed

+315
-128
lines changed

.vscode/launch.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Launch Program",
11+
"skipFiles": [
12+
"node_modules/**"
13+
],
14+
"program": "${workspaceFolder}/src/cli/flowr.ts",
15+
"preLaunchTask": "npm: build:bundle-flowr",
16+
"console": "integratedTerminal",
17+
},
18+
{
19+
"type": "node",
20+
"request": "attach",
21+
"name": "Attach to Process",
22+
"port": 9229
23+
}
24+
]
25+
}

example1.r

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# algebra_grades <- list(test = 1.0, exam = 3.0)
2+
# algebra_grades$test <- 4.0
3+
# grades <- list(algebra = algebra_grades, sports = 1.7)
4+
# grades$sports <- 1.0
5+
# person <- list(name = "John", grades = grades)
6+
# person$name <- "Jane"
7+
# result <- person$grades$algebra$exam
8+
# print(result)
9+
10+
# grades <- list(algebra = 1.3, sports = 1.7)
11+
# grades$algebra <- 1.0
12+
# person <- list(name = "John", grades = grades)
13+
# result <- person$grades$algebra
14+
15+
grades <- list(algebra = 1.3, german = 2.0, english = 2.3, sports = 1.7)
16+
grades$algebra <- 1.0
17+
grades$sports <- 1.0
18+
person <- list(age = 24, name = "John", height = 164, is_male = FALSE, grades = grades)
19+
person$name <- "Jane"
20+
person$height <- 177
21+
result <- person$grades$algebra
22+
23+
# grades <- list(algebra = 1.3, german = 2.0, english = 2.3, sports = 1.7)
24+
# grades$algebra <- 1.0
25+
# person <- list(age = 24, name = "John", height = 164, is_male = FALSE, grades = grades)
26+
# result <- person$grades$algebra

example2.r

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
person <- list(age = 24, name = "John")
2+
person$is_male <- TRUE
3+
4+
if (length(person) >= 3) {
5+
person$name <- "Jane"
6+
} else {
7+
person$name <- "Lorane"
8+
}
9+
10+
result <- person$name
11+
result

src/dataflow/environments/define.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ import { cloneEnvironmentInformation } from './clone';
66
import type { IdentifierDefinition, InGraphIdentifierDefinition } from './identifier';
77
import type { ContainerIndex, ContainerIndicesCollection } from '../graph/vertex';
88

9+
function printDefChanges(newEnvironments: IEnvironment, name: string) {
10+
const defs = newEnvironments.memory.get(name);
11+
console.log(`def for ${name} after redefinition:`);
12+
for(const element of defs ?? []) {
13+
const def = element as InGraphIdentifierDefinition;
14+
for(const index of def.indicesCollection ?? []) {
15+
console.log(index.indices, index.isSingleIndex);
16+
}
17+
}
18+
}
919

1020
function defInEnv(newEnvironments: IEnvironment, name: string, definition: IdentifierDefinition) {
1121
const existing = newEnvironments.memory.get(name);
@@ -14,6 +24,7 @@ function defInEnv(newEnvironments: IEnvironment, name: string, definition: Ident
1424
const inGraphDefinition = definition as InGraphIdentifierDefinition;
1525
if(existing !== undefined && inGraphDefinition.indicesCollection !== undefined && inGraphDefinition.controlDependencies === undefined) {
1626
newEnvironments.memory.set(name, mergeIndices(existing, inGraphDefinition));
27+
// printDefChanges(newEnvironments, name);
1728
return;
1829
}
1930

@@ -42,6 +53,7 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
4253
if(existingDef.indicesCollection === undefined) {
4354
continue;
4455
}
56+
// console.log(existingDef);
4557
const newIndicesCollection: ContainerIndicesCollection = [];
4658
for(const indices of existingDef.indicesCollection) {
4759
let newIndices: ContainerIndex[];
@@ -59,6 +71,7 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
5971
});
6072
}
6173
}
74+
// console.log('newIndicesCollection', newIndicesCollection);
6275

6376
// if indices are now empty list, don't keep empty definition
6477
if(newIndicesCollection.length > 0) {
@@ -69,6 +82,7 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
6982
}
7083
}
7184
}
85+
// console.log('newExistingDefs', newExistingDefs);
7286
// store changed existing definitons and add new one
7387
return [...newExistingDefs, definition];
7488
}
@@ -79,6 +93,8 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
7993
*/
8094
export function define(definition: IdentifierDefinition, superAssign: boolean | undefined, environment: REnvironmentInformation): REnvironmentInformation {
8195
const name = definition.name;
96+
// console.log('defining:', name);
97+
// console.log('definition:', definition);
8298
guard(name !== undefined, () => `Name must be defined, but isn't for ${JSON.stringify(definition)}`);
8399
let newEnvironment;
84100
if(superAssign) {

src/dataflow/graph/vertex.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface ContainerParentIndex extends ContainerLeafIndex {
3939
/**
4040
* Sub-indices of index.
4141
*/
42-
readonly subIndices: ContainerIndex[],
42+
readonly subIndices: ContainerIndices[],
4343
}
4444

4545
/**

src/dataflow/internal/process/functions/call/built-in/built-in-access.ts

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { markAsAssignment } from './built-in-assignment';
1919
import { ReferenceType } from '../../../../../environments/identifier';
2020
import type { InGraphIdentifierDefinition } from '../../../../../environments/identifier';
2121
import { resolveByName } from '../../../../../environments/resolve-by-name';
22-
import type { ContainerIndex, ContainerIndicesCollection, ContainerParentIndex } from '../../../../../graph/vertex';
22+
import type { ContainerIndices, ContainerIndicesCollection } from '../../../../../graph/vertex';
2323
import type { RArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument';
2424
import { RoleInParent } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/role';
2525
import type { RAccess } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-access';
@@ -126,7 +126,7 @@ function processNumberBasedAccess<OtherInfo>(
126126
name: RSymbol<OtherInfo & ParentInformation, string>,
127127
args: readonly RFunctionArgument<OtherInfo & ParentInformation>[],
128128
rootId: NodeId,
129-
config: { treatIndicesAsString: boolean; } & ForceArguments,
129+
config: ForceArguments,
130130
head: RArgument<OtherInfo & ParentInformation>,
131131
) {
132132
const existing = data.environment.current.memory.get(':=');
@@ -169,7 +169,7 @@ function processStringBasedAccess<OtherInfo>(
169169
data: DataflowProcessorInformation<OtherInfo & ParentInformation>,
170170
name: RSymbol<OtherInfo & ParentInformation, string>,
171171
rootId: NodeId,
172-
config: { treatIndicesAsString: boolean; } & ForceArguments,
172+
config: ForceArguments,
173173
) {
174174
const newArgs = [...args];
175175
// if the argument is a symbol, we convert it to a string for this perspective
@@ -191,18 +191,23 @@ function processStringBasedAccess<OtherInfo>(
191191
};
192192
}
193193
}
194-
194+
195195
const nonEmptyArgs = newArgs.filter(arg => arg !== EmptyArgument);
196196
const accessedArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.Accessed);
197197
const accessArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.IndexAccess);
198+
199+
const isNestedAccess = accessedArg?.value?.type === RType.Access;
200+
const isTopMostNestedAccess = isNestedAccess && accessedArg?.lexeme === '$';
201+
const shouldResolveIndices = !isNestedAccess || (isTopMostNestedAccess);
198202
let accessedIndicesCollection: ContainerIndicesCollection;
199-
if(accessArg !== undefined && accessedArg != undefined) {
203+
// wenn accessed arg lexem == $ -> top most
204+
if(shouldResolveIndices && accessArg !== undefined && accessedArg != undefined) {
200205
accessedIndicesCollection = resolveAccess(accessedArg, [accessArg], data.environment);
206+
console.log('fully resolved' , `${accessedArg.info.fullLexeme}$${accessArg.lexeme}`, 'to', accessedIndicesCollection?.flatMap(indices => indices.indices));
201207
}
202208

203-
const fnCall = processKnownFunctionCall({ name, args: [], rootId, data, forceArgs: config.forceArgs }, accessedIndicesCollection);
204-
const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);
205-
referenceIndices(accessedIndices, fnCall, name.info.id);
209+
const fnCall = processKnownFunctionCall({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs }, accessedIndicesCollection);
210+
referenceIndices(accessedIndicesCollection, fnCall, name.info.id);
206211
return fnCall;
207212
}
208213

@@ -228,32 +233,40 @@ function resolveAccess<OtherInfo>(
228233
): ContainerIndicesCollection {
229234
let newAccessedArg: ArgTypes<OtherInfo> = accessedArg;
230235
// Unwrap access of top-level arg
231-
if(accessedArg.type === RType.Argument && accessedArg.value?.type === RType.Access) {
236+
if(accessedArg.type === RType.Argument &&
237+
(accessedArg.value?.type === RType.Access || accessedArg.value?.type === RType.Symbol)
238+
) {
232239
newAccessedArg = accessedArg.value;
233240
}
234241

235242
let indicesCollection: ContainerIndicesCollection = undefined;
236243
// Resolve access recursively
237244
if(newAccessedArg.type === RType.Access) {
238-
const accesses = newAccessedArg.access.filter(access => access !== EmptyArgument).map(access => access as RArgument<OtherInfo & ParentInformation>);
245+
const accesses = newAccessedArg.access
246+
.filter(access => access !== EmptyArgument)
247+
.map(access => access as RArgument<OtherInfo & ParentInformation>);
248+
249+
// Recursively resolve access until indices are fully resolved
239250
const resolvedIndicesCollection = resolveAccess(
240251
newAccessedArg.accessed as RAccess<OtherInfo & ParentInformation>,
241252
accesses,
242253
environment,
243254
);
244-
const subIndices = resolvedIndicesCollection?.flatMap(indices => indices.indices).filter(indices => 'subIndices' in indices).flatMap(indices => indices.subIndices);
245-
const collection: ContainerIndicesCollection = subIndices ? [
246-
{
247-
indices: subIndices,
248-
isSingleIndex: false,
249-
}
250-
] : undefined;
251-
const accessedIndicesCollection = filterIndices(collection, accessArgs);
252-
indicesCollection = accessedIndicesCollection;
253-
}
254255

255-
// When access is fully resolved, apply access
256-
if(newAccessedArg.type === RType.Symbol) {
256+
// Get sub-indices of resolved indices and filter them according to the accessArgs
257+
const subIndices = resolvedIndicesCollection
258+
?.flatMap(indices => indices.indices)
259+
.filter(indices => 'subIndices' in indices)
260+
.flatMap(indices => indices.subIndices);
261+
indicesCollection = filterIndices(subIndices, accessArgs);
262+
263+
// Get indices that are not single indices e.g. list definitions
264+
// const multiIndexCollection = resolvedIndicesCollection?.filter(indices => !indices.isSingleIndex);
265+
// if(multiIndexCollection) {
266+
// indicesCollection?.concat(multiIndexCollection);
267+
// }
268+
} else if(newAccessedArg.type === RType.Symbol) {
269+
// When access is fully resolved, apply access
257270
indicesCollection = resolveSingleIndex(newAccessedArg, accessArgs, environment);
258271
}
259272

@@ -273,15 +286,17 @@ function resolveSingleIndex<OtherInfo>(
273286
accessArg: Base<OtherInfo & ParentInformation>[],
274287
environment: REnvironmentInformation,
275288
): ContainerIndicesCollection {
276-
const resolvedAccessedArg = resolveByName(accessedArg.lexeme, environment);
277-
const indicesCollection = resolvedAccessedArg?.flatMap(param => (param as InGraphIdentifierDefinition)?.indicesCollection ?? []);
289+
const definitions = resolveByName(accessedArg.lexeme, environment);
290+
const indicesCollection = definitions?.flatMap(def => (def as InGraphIdentifierDefinition)?.indicesCollection ?? []);
278291
const accessedIndicesCollection = filterIndices(indicesCollection, accessArg);
279292
return accessedIndicesCollection;
280293
}
281294

282295
/**
283296
* Filters the single indices of the {@link indicesCollection} according to the lexeme of the {@link accessArgs}.
284297
*
298+
* Only non-single-index indices are filtered.
299+
*
285300
* @param indicesCollection - The {@link ContainerIndicesCollection} to filter
286301
* @param accessArgs - The arguments which are used to filter {@link indicesCollection}
287302
* @returns The filtered copy of {@link indicesCollection}
@@ -292,15 +307,24 @@ function filterIndices<OtherInfo>(
292307
): ContainerIndicesCollection {
293308
let accessedIndicesCollection: ContainerIndicesCollection = undefined;
294309
for(const indices of indicesCollection ?? []) {
310+
let containerIndices: ContainerIndices;
311+
// if(indices.isSingleIndex) {
295312
const filteredIndices = indices.indices.filter(index => accessArgs.some(arg => arg.lexeme === index.lexeme));
313+
296314
if(filteredIndices.length == 0) {
297315
continue;
298316
}
299-
accessedIndicesCollection ??= [];
300-
accessedIndicesCollection.push({
317+
318+
containerIndices = {
301319
indices: filteredIndices,
302320
isSingleIndex: indices.isSingleIndex
303-
});
321+
};
322+
// } else {
323+
// containerIndices = indices;
324+
// }
325+
326+
accessedIndicesCollection ??= [];
327+
accessedIndicesCollection.push(containerIndices);
304328
}
305329
return accessedIndicesCollection;
306330
}
@@ -314,13 +338,19 @@ function filterIndices<OtherInfo>(
314338
* @param parentNodeId - {@link NodeId} of the parent from which the edge starts
315339
*/
316340
function referenceIndices(
317-
accessedIndices: ContainerIndex[] | undefined,
341+
accessedIndicesCollection: ContainerIndicesCollection,
318342
fnCall: ProcessKnownFunctionCallResult,
319343
parentNodeId: NodeId,
320344
) {
345+
const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);
346+
321347
for(const accessedIndex of accessedIndices ?? []) {
322348
fnCall.information.graph.addEdge(parentNodeId, accessedIndex.nodeId, EdgeType.Reads);
323-
const accessedSubIndices = (accessedIndex as ContainerParentIndex)?.subIndices ?? [];
324-
referenceIndices(accessedSubIndices, fnCall, accessedIndex.nodeId);
349+
// const accessedSubIndices = ('subIndices' in accessedIndex) ? accessedIndex.subIndices : undefined;
350+
// referenceIndices(accessedSubIndices, fnCall, accessedIndex.nodeId);
351+
const accessedSubIndices = ('subIndices' in accessedIndex) ? accessedIndex.subIndices.flatMap(indices => indices.indices) : undefined;
352+
for(const accessedSubIndex of accessedSubIndices ?? []) {
353+
fnCall.information.graph.addEdge(accessedIndex.nodeId, accessedSubIndex.nodeId, EdgeType.Reads);
354+
}
325355
}
326356
}

src/dataflow/internal/process/functions/call/built-in/built-in-assignment.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ export function markAsAssignment(
262262
if(sourceIds.length === 1) {
263263
// support for tracking indices
264264
indicesCollection = information.graph.getVertex(sourceIds[0])?.indicesCollection;
265+
// if(indicesCollection) {
266+
// const indicesCollectionString = indicesCollection.map(indices =>
267+
// indices.indices.map(index => `{ lexeme: ${index.lexeme}, nodeId: ${index.nodeId} }`).join(', ')
268+
// ).join(', ');
269+
// console.log(`Defining indices ${indicesCollectionString} for ${nodeToDefine.name}`);
270+
// }
265271
}
266272
if(config?.indicesCollection !== undefined) {
267273
indicesCollection = (indicesCollection ?? []).concat(config.indicesCollection);

src/dataflow/internal/process/functions/call/built-in/built-in-list.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,13 @@ export function processList<OtherInfo>(
4040
// Check whether argument value is non-primitve
4141
if(arg.value?.type === RType.Symbol) {
4242
const defs = resolveByName(arg.value.lexeme, data.environment);
43-
const indices = defs
44-
?.flatMap(index => (index as InGraphIdentifierDefinition).indicesCollection ?? [])
45-
.flatMap(indices => indices.indices);
46-
// console.log('indices of', arg.value.lexeme, ':', indices);
47-
newIndex = {
48-
...newIndex,
49-
subIndices: indices,
50-
};
43+
const indices = defs?.flatMap(index => (index as InGraphIdentifierDefinition).indicesCollection ?? []);
44+
if(indices) {
45+
newIndex = {
46+
...newIndex,
47+
subIndices: indices,
48+
};
49+
}
5150
}
5251

5352
namedArguments.push(newIndex);

src/dataflow/internal/process/functions/call/common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export function processAllArguments<OtherInfo>(
118118
// When only a single index is referenced, we don't need to reference the whole object
119119
const resolvedInGraphDef = resolved as InGraphIdentifierDefinition;
120120
const isSingleIndex = resolvedInGraphDef?.indicesCollection?.every((indices) => indices.isSingleIndex);
121+
// TODO
121122
if(!isSingleIndex) {
122123
finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, EdgeType.Reads);
123124
}

src/dataflow/internal/process/functions/call/known-call-handling.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function markNonStandardEvaluationEdges(
5858
}
5959

6060
export function processKnownFunctionCall<OtherInfo>(
61-
{ name,args, rootId,data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>, indicesCollection: ContainerIndicesCollection = undefined,
61+
{ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>, indicesCollection: ContainerIndicesCollection = undefined,
6262
): ProcessKnownFunctionCallResult {
6363
const functionName = processDataflowFor(name, data);
6464

0 commit comments

Comments
 (0)