Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Slartibartfass2 committed Dec 13, 2024
1 parent 98af78b commit 0216e11
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 128 deletions.
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"node_modules/**"
],
"program": "${workspaceFolder}/src/cli/flowr.ts",
"preLaunchTask": "npm: build:bundle-flowr",
"console": "integratedTerminal",
},
{
"type": "node",
"request": "attach",
"name": "Attach to Process",
"port": 9229
}
]
}
26 changes: 26 additions & 0 deletions example1.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# algebra_grades <- list(test = 1.0, exam = 3.0)
# algebra_grades$test <- 4.0
# grades <- list(algebra = algebra_grades, sports = 1.7)
# grades$sports <- 1.0
# person <- list(name = "John", grades = grades)
# person$name <- "Jane"
# result <- person$grades$algebra$exam
# print(result)

# grades <- list(algebra = 1.3, sports = 1.7)
# grades$algebra <- 1.0
# person <- list(name = "John", grades = grades)
# result <- person$grades$algebra

grades <- list(algebra = 1.3, german = 2.0, english = 2.3, sports = 1.7)
grades$algebra <- 1.0
grades$sports <- 1.0
person <- list(age = 24, name = "John", height = 164, is_male = FALSE, grades = grades)
person$name <- "Jane"
person$height <- 177
result <- person$grades$algebra

# grades <- list(algebra = 1.3, german = 2.0, english = 2.3, sports = 1.7)
# grades$algebra <- 1.0
# person <- list(age = 24, name = "John", height = 164, is_male = FALSE, grades = grades)
# result <- person$grades$algebra
11 changes: 11 additions & 0 deletions example2.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
person <- list(age = 24, name = "John")
person$is_male <- TRUE

if (length(person) >= 3) {
person$name <- "Jane"
} else {
person$name <- "Lorane"
}

result <- person$name
result
16 changes: 16 additions & 0 deletions src/dataflow/environments/define.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import { cloneEnvironmentInformation } from './clone';
import type { IdentifierDefinition, InGraphIdentifierDefinition } from './identifier';
import type { ContainerIndex, ContainerIndicesCollection } from '../graph/vertex';

function printDefChanges(newEnvironments: IEnvironment, name: string) {

Check failure on line 9 in src/dataflow/environments/define.ts

View workflow job for this annotation

GitHub Actions / 👩‍🏫 Linting (local)

'printDefChanges' is defined but never used. Allowed unused vars must match /^_/u
const defs = newEnvironments.memory.get(name);
console.log(`def for ${name} after redefinition:`);
for(const element of defs ?? []) {
const def = element as InGraphIdentifierDefinition;
for(const index of def.indicesCollection ?? []) {
console.log(index.indices, index.isSingleIndex);
}
}
}

function defInEnv(newEnvironments: IEnvironment, name: string, definition: IdentifierDefinition) {
const existing = newEnvironments.memory.get(name);
Expand All @@ -14,6 +24,7 @@ function defInEnv(newEnvironments: IEnvironment, name: string, definition: Ident
const inGraphDefinition = definition as InGraphIdentifierDefinition;
if(existing !== undefined && inGraphDefinition.indicesCollection !== undefined && inGraphDefinition.controlDependencies === undefined) {
newEnvironments.memory.set(name, mergeIndices(existing, inGraphDefinition));
// printDefChanges(newEnvironments, name);
return;
}

Expand Down Expand Up @@ -42,6 +53,7 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
if(existingDef.indicesCollection === undefined) {
continue;
}
// console.log(existingDef);
const newIndicesCollection: ContainerIndicesCollection = [];
for(const indices of existingDef.indicesCollection) {
let newIndices: ContainerIndex[];
Expand All @@ -59,6 +71,7 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
});
}
}
// console.log('newIndicesCollection', newIndicesCollection);

// if indices are now empty list, don't keep empty definition
if(newIndicesCollection.length > 0) {
Expand All @@ -69,6 +82,7 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
}
}
}
// console.log('newExistingDefs', newExistingDefs);
// store changed existing definitons and add new one
return [...newExistingDefs, definition];
}
Expand All @@ -79,6 +93,8 @@ function mergeIndices(existing: IdentifierDefinition[], definition: InGraphIdent
*/
export function define(definition: IdentifierDefinition, superAssign: boolean | undefined, environment: REnvironmentInformation): REnvironmentInformation {
const name = definition.name;
// console.log('defining:', name);
// console.log('definition:', definition);
guard(name !== undefined, () => `Name must be defined, but isn't for ${JSON.stringify(definition)}`);
let newEnvironment;
if(superAssign) {
Expand Down
2 changes: 1 addition & 1 deletion src/dataflow/graph/vertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export interface ContainerParentIndex extends ContainerLeafIndex {
/**
* Sub-indices of index.
*/
readonly subIndices: ContainerIndex[],
readonly subIndices: ContainerIndices[],
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { markAsAssignment } from './built-in-assignment';
import { ReferenceType } from '../../../../../environments/identifier';
import type { InGraphIdentifierDefinition } from '../../../../../environments/identifier';
import { resolveByName } from '../../../../../environments/resolve-by-name';
import type { ContainerIndex, ContainerIndicesCollection, ContainerParentIndex } from '../../../../../graph/vertex';
import type { ContainerIndices, ContainerIndicesCollection } from '../../../../../graph/vertex';
import type { RArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument';
import { RoleInParent } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/role';
import type { RAccess } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-access';
Expand Down Expand Up @@ -126,7 +126,7 @@ function processNumberBasedAccess<OtherInfo>(
name: RSymbol<OtherInfo & ParentInformation, string>,
args: readonly RFunctionArgument<OtherInfo & ParentInformation>[],
rootId: NodeId,
config: { treatIndicesAsString: boolean; } & ForceArguments,
config: ForceArguments,
head: RArgument<OtherInfo & ParentInformation>,
) {
const existing = data.environment.current.memory.get(':=');
Expand Down Expand Up @@ -169,7 +169,7 @@ function processStringBasedAccess<OtherInfo>(
data: DataflowProcessorInformation<OtherInfo & ParentInformation>,
name: RSymbol<OtherInfo & ParentInformation, string>,
rootId: NodeId,
config: { treatIndicesAsString: boolean; } & ForceArguments,
config: ForceArguments,
) {
const newArgs = [...args];
// if the argument is a symbol, we convert it to a string for this perspective
Expand All @@ -191,18 +191,23 @@ function processStringBasedAccess<OtherInfo>(
};
}
}

const nonEmptyArgs = newArgs.filter(arg => arg !== EmptyArgument);
const accessedArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.Accessed);
const accessArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.IndexAccess);

const isNestedAccess = accessedArg?.value?.type === RType.Access;
const isTopMostNestedAccess = isNestedAccess && accessedArg?.lexeme === '$';
const shouldResolveIndices = !isNestedAccess || (isTopMostNestedAccess);
let accessedIndicesCollection: ContainerIndicesCollection;
if(accessArg !== undefined && accessedArg != undefined) {
// wenn accessed arg lexem == $ -> top most
if(shouldResolveIndices && accessArg !== undefined && accessedArg != undefined) {
accessedIndicesCollection = resolveAccess(accessedArg, [accessArg], data.environment);
console.log('fully resolved' , `${accessedArg.info.fullLexeme}$${accessArg.lexeme}`, 'to', accessedIndicesCollection?.flatMap(indices => indices.indices));
}

const fnCall = processKnownFunctionCall({ name, args: [], rootId, data, forceArgs: config.forceArgs }, accessedIndicesCollection);
const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);
referenceIndices(accessedIndices, fnCall, name.info.id);
const fnCall = processKnownFunctionCall({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs }, accessedIndicesCollection);
referenceIndices(accessedIndicesCollection, fnCall, name.info.id);
return fnCall;
}

Expand All @@ -228,32 +233,40 @@ function resolveAccess<OtherInfo>(
): ContainerIndicesCollection {
let newAccessedArg: ArgTypes<OtherInfo> = accessedArg;
// Unwrap access of top-level arg
if(accessedArg.type === RType.Argument && accessedArg.value?.type === RType.Access) {
if(accessedArg.type === RType.Argument &&
(accessedArg.value?.type === RType.Access || accessedArg.value?.type === RType.Symbol)
) {
newAccessedArg = accessedArg.value;
}

let indicesCollection: ContainerIndicesCollection = undefined;
// Resolve access recursively
if(newAccessedArg.type === RType.Access) {
const accesses = newAccessedArg.access.filter(access => access !== EmptyArgument).map(access => access as RArgument<OtherInfo & ParentInformation>);
const accesses = newAccessedArg.access
.filter(access => access !== EmptyArgument)
.map(access => access as RArgument<OtherInfo & ParentInformation>);

// Recursively resolve access until indices are fully resolved
const resolvedIndicesCollection = resolveAccess(
newAccessedArg.accessed as RAccess<OtherInfo & ParentInformation>,
accesses,
environment,
);
const subIndices = resolvedIndicesCollection?.flatMap(indices => indices.indices).filter(indices => 'subIndices' in indices).flatMap(indices => indices.subIndices);
const collection: ContainerIndicesCollection = subIndices ? [
{
indices: subIndices,
isSingleIndex: false,
}
] : undefined;
const accessedIndicesCollection = filterIndices(collection, accessArgs);
indicesCollection = accessedIndicesCollection;
}

// When access is fully resolved, apply access
if(newAccessedArg.type === RType.Symbol) {
// Get sub-indices of resolved indices and filter them according to the accessArgs
const subIndices = resolvedIndicesCollection
?.flatMap(indices => indices.indices)
.filter(indices => 'subIndices' in indices)
.flatMap(indices => indices.subIndices);
indicesCollection = filterIndices(subIndices, accessArgs);

// Get indices that are not single indices e.g. list definitions
// const multiIndexCollection = resolvedIndicesCollection?.filter(indices => !indices.isSingleIndex);
// if(multiIndexCollection) {
// indicesCollection?.concat(multiIndexCollection);
// }
} else if(newAccessedArg.type === RType.Symbol) {
// When access is fully resolved, apply access
indicesCollection = resolveSingleIndex(newAccessedArg, accessArgs, environment);
}

Expand All @@ -273,15 +286,17 @@ function resolveSingleIndex<OtherInfo>(
accessArg: Base<OtherInfo & ParentInformation>[],
environment: REnvironmentInformation,
): ContainerIndicesCollection {
const resolvedAccessedArg = resolveByName(accessedArg.lexeme, environment);
const indicesCollection = resolvedAccessedArg?.flatMap(param => (param as InGraphIdentifierDefinition)?.indicesCollection ?? []);
const definitions = resolveByName(accessedArg.lexeme, environment);
const indicesCollection = definitions?.flatMap(def => (def as InGraphIdentifierDefinition)?.indicesCollection ?? []);
const accessedIndicesCollection = filterIndices(indicesCollection, accessArg);
return accessedIndicesCollection;
}

/**
* Filters the single indices of the {@link indicesCollection} according to the lexeme of the {@link accessArgs}.
*
* Only non-single-index indices are filtered.
*
* @param indicesCollection - The {@link ContainerIndicesCollection} to filter
* @param accessArgs - The arguments which are used to filter {@link indicesCollection}
* @returns The filtered copy of {@link indicesCollection}
Expand All @@ -292,15 +307,24 @@ function filterIndices<OtherInfo>(
): ContainerIndicesCollection {
let accessedIndicesCollection: ContainerIndicesCollection = undefined;
for(const indices of indicesCollection ?? []) {
let containerIndices: ContainerIndices;
// if(indices.isSingleIndex) {
const filteredIndices = indices.indices.filter(index => accessArgs.some(arg => arg.lexeme === index.lexeme));

if(filteredIndices.length == 0) {
continue;
}
accessedIndicesCollection ??= [];
accessedIndicesCollection.push({

containerIndices = {

Check failure on line 318 in src/dataflow/internal/process/functions/call/built-in/built-in-access.ts

View workflow job for this annotation

GitHub Actions / 👩‍🏫 Linting (local)

'containerIndices' is never reassigned. Use 'const' instead
indices: filteredIndices,
isSingleIndex: indices.isSingleIndex
});
};
// } else {
// containerIndices = indices;
// }

accessedIndicesCollection ??= [];
accessedIndicesCollection.push(containerIndices);
}
return accessedIndicesCollection;
}
Expand All @@ -314,13 +338,19 @@ function filterIndices<OtherInfo>(
* @param parentNodeId - {@link NodeId} of the parent from which the edge starts
*/
function referenceIndices(
accessedIndices: ContainerIndex[] | undefined,
accessedIndicesCollection: ContainerIndicesCollection,
fnCall: ProcessKnownFunctionCallResult,
parentNodeId: NodeId,
) {
const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);

for(const accessedIndex of accessedIndices ?? []) {
fnCall.information.graph.addEdge(parentNodeId, accessedIndex.nodeId, EdgeType.Reads);
const accessedSubIndices = (accessedIndex as ContainerParentIndex)?.subIndices ?? [];
referenceIndices(accessedSubIndices, fnCall, accessedIndex.nodeId);
// const accessedSubIndices = ('subIndices' in accessedIndex) ? accessedIndex.subIndices : undefined;
// referenceIndices(accessedSubIndices, fnCall, accessedIndex.nodeId);
const accessedSubIndices = ('subIndices' in accessedIndex) ? accessedIndex.subIndices.flatMap(indices => indices.indices) : undefined;
for(const accessedSubIndex of accessedSubIndices ?? []) {
fnCall.information.graph.addEdge(accessedIndex.nodeId, accessedSubIndex.nodeId, EdgeType.Reads);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ export function markAsAssignment(
if(sourceIds.length === 1) {
// support for tracking indices
indicesCollection = information.graph.getVertex(sourceIds[0])?.indicesCollection;
// if(indicesCollection) {
// const indicesCollectionString = indicesCollection.map(indices =>
// indices.indices.map(index => `{ lexeme: ${index.lexeme}, nodeId: ${index.nodeId} }`).join(', ')
// ).join(', ');
// console.log(`Defining indices ${indicesCollectionString} for ${nodeToDefine.name}`);
// }
}
if(config?.indicesCollection !== undefined) {
indicesCollection = (indicesCollection ?? []).concat(config.indicesCollection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,13 @@ export function processList<OtherInfo>(
// Check whether argument value is non-primitve
if(arg.value?.type === RType.Symbol) {
const defs = resolveByName(arg.value.lexeme, data.environment);
const indices = defs
?.flatMap(index => (index as InGraphIdentifierDefinition).indicesCollection ?? [])
.flatMap(indices => indices.indices);
// console.log('indices of', arg.value.lexeme, ':', indices);
newIndex = {
...newIndex,
subIndices: indices,
};
const indices = defs?.flatMap(index => (index as InGraphIdentifierDefinition).indicesCollection ?? []);
if(indices) {
newIndex = {
...newIndex,
subIndices: indices,
};
}
}

namedArguments.push(newIndex);
Expand Down
1 change: 1 addition & 0 deletions src/dataflow/internal/process/functions/call/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export function processAllArguments<OtherInfo>(
// When only a single index is referenced, we don't need to reference the whole object
const resolvedInGraphDef = resolved as InGraphIdentifierDefinition;
const isSingleIndex = resolvedInGraphDef?.indicesCollection?.every((indices) => indices.isSingleIndex);
// TODO
if(!isSingleIndex) {
finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, EdgeType.Reads);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function markNonStandardEvaluationEdges(
}

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

Expand Down
Loading

0 comments on commit 0216e11

Please sign in to comment.