Skip to content

Commit

Permalink
feat(list-access): add singleIndex property to container indices
Browse files Browse the repository at this point in the history
  • Loading branch information
Slartibartfass2 committed Nov 27, 2024
1 parent 12e2bd0 commit 8417576
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/dataflow/environments/identifier.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { BuiltInIdentifierConstant, BuiltInIdentifierDefinition } from './built-in';
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
import type { ControlDependency } from '../info';
import type { ContainerIndices } from '../graph/vertex';
import type { ContainerIndicesCollection } from '../graph/vertex';

export type Identifier = string & { __brand?: 'identifier' }

Expand Down Expand Up @@ -65,7 +65,7 @@ export interface InGraphIdentifierDefinition extends IdentifierReference {
/** The assignment (or whatever, like `assign` function call) node which ultimately defined this identifier */
readonly definedAt: NodeId

indices?: ContainerIndices | undefined
indicesCollection?: ContainerIndicesCollection
}

/**
Expand Down
11 changes: 8 additions & 3 deletions src/dataflow/graph/vertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ export enum VertexType {
FunctionDefinition = 'function-definition'
}

export interface ContainerIndex{
export interface ContainerIndex {
readonly lexeme: string,
readonly nodeId: NodeId,
}
export type ContainerIndices = ContainerIndex[] | undefined
export interface ContainerIndices {
readonly indices: ContainerIndex[],
// Differentiate between single and multiple indices (a list with one index is not a single index)
readonly isSingleIndex: boolean,
}
export type ContainerIndicesCollection = ContainerIndices[] | undefined

/**
* Arguments required to construct a vertex in the dataflow graph.
Expand All @@ -46,7 +51,7 @@ interface DataflowGraphVertexBase extends MergeableRecord {
*/
controlDependencies: ControlDependency[] | undefined

indices?: ContainerIndices
indicesCollection?: ContainerIndicesCollection
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,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 { ContainerIndices } from '../../../../../graph/vertex';
import type { ContainerIndicesCollection } from '../../../../../graph/vertex';

interface TableAssignmentProcessorMarker {
definitionRootNodes: NodeId[]
Expand Down Expand Up @@ -108,19 +108,29 @@ export function processAccess<OtherInfo>(
}
}
// a$foo a@foo
let accessedArguments: ContainerIndices;
let accessedIndicesCollection: ContainerIndicesCollection;
if(newArgs[0] !== EmptyArgument) {
const accessArg = newArgs[1] === EmptyArgument ? undefined : newArgs[1].lexeme;
const resolvedFirstParameter = resolveByName(newArgs[0].lexeme ?? '', data.environment);
const resolvedFirstParameterIndices = resolvedFirstParameter?.flatMap(param => (param as InGraphIdentifierDefinition)?.indices ?? []);
accessedArguments = resolvedFirstParameterIndices?.filter(index => index.lexeme === accessArg);
const indicesCollection = resolvedFirstParameter?.flatMap(param => (param as InGraphIdentifierDefinition)?.indicesCollection ?? []);
for(const indices of indicesCollection ?? []) {
const filteredIndices = indices.indices.filter(index => index.lexeme === accessArg);
if(filteredIndices.length == 0) {
continue;
}
accessedIndicesCollection ??= [];
accessedIndicesCollection.push({
indices: filteredIndices,
isSingleIndex: indices.isSingleIndex
});
}
}

const indices = accessedArguments === undefined ? undefined : accessedArguments;
fnCall = processKnownFunctionCall({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs }, indices);
accessedArguments?.forEach((arg) => {
fnCall.information.graph.addEdge(name.info.id, arg.nodeId, EdgeType.Reads);
});
fnCall = processKnownFunctionCall({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs }, accessedIndicesCollection);
const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);
for(const accessedIndex of accessedIndices ?? []) {
fnCall.information.graph.addEdge(name.info.id, accessedIndex.nodeId, EdgeType.Reads);
}
}

const info = fnCall.information;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import type { RString } from '../../../../../../r-bridge/lang-4.x/ast/model/node
import { removeRQuotes } from '../../../../../../r-bridge/retriever';
import type { RUnnamedArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument';
import { VertexType } from '../../../../../graph/vertex';
import type { ContainerIndices } from '../../../../../graph/vertex';
import type { ContainerIndicesCollection } from '../../../../../graph/vertex';
import { define } from '../../../../../environments/define';
import { EdgeType } from '../../../../../graph/edge';
import type { ForceArguments } from '../common';
Expand Down Expand Up @@ -59,7 +59,7 @@ export interface AssignmentConfiguration extends ForceArguments {
readonly makeMaybe?: boolean
readonly quoteSource?: boolean
readonly canBeReplacement?: boolean
readonly indices?: ContainerIndices
readonly indices?: ContainerIndicesCollection
}

function findRootAccess<OtherInfo>(node: RNode<OtherInfo & ParentInformation>): RSymbol<OtherInfo & ParentInformation> | undefined {
Expand Down Expand Up @@ -253,15 +253,15 @@ export function markAsAssignment(
rootIdOfAssignment: NodeId,
config?: AssignmentConfiguration | undefined,
) {
let indices: ContainerIndices;
let indices: ContainerIndicesCollection = undefined;
if(sourceIds.length === 1) {
// support for tracking indices
indices = information.graph.getVertex(sourceIds[0])?.indices;
indices = information.graph.getVertex(sourceIds[0])?.indicesCollection;
}
if(config?.indices !== undefined) {
indices = (indices ?? []).concat(config.indices);
}
nodeToDefine.indices ??= indices;
nodeToDefine.indicesCollection ??= indices;

information.environment = define(nodeToDefine, config?.superAssignment, information.environment);
information.graph.setDefinitionOfVertex(nodeToDefine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EmptyArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nod
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
import type { ContainerIndex } from '../../../../../graph/vertex';
import type { ContainerIndex, ContainerIndices } from '../../../../../graph/vertex';
import type { DataflowInformation } from '../../../../../info';
import type { DataflowProcessorInformation } from '../../../../../processor';
import { processKnownFunctionCall } from '../known-call-handling';
Expand All @@ -29,8 +29,16 @@ export function processList<OtherInfo>(
continue;
}

namedArguments.push({ lexeme: arg.name.content, nodeId: arg.info.id });
const newIndex: ContainerIndex = {
lexeme: arg.name.content,
nodeId: arg.info.id,
};
namedArguments.push(newIndex);
}

return processKnownFunctionCall({ name, args, rootId, data }, namedArguments).information;
const indices: ContainerIndices = {
indices: namedArguments,
isSingleIndex: false,
};
return processKnownFunctionCall({ name, args, rootId, data }, [indices]).information;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/node
import { EmptyArgument, type RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
import { dataflowLogger } from '../../../../../logger';
import type { ContainerIndices } from '../../../../../graph/vertex';
import type { ContainerIndicesCollection } from '../../../../../graph/vertex';
import { VertexType } from '../../../../../graph/vertex';
import { getReferenceOfArgument } from '../../../../../graph/graph';
import { EdgeType } from '../../../../../graph/edge';
Expand All @@ -35,15 +35,20 @@ export function processReplacementFunction<OtherInfo>(
/* we only get here if <-, <<-, ... or whatever is part of the replacement is not overwritten */
expensiveTrace(dataflowLogger, () => `Replacement ${name.content} with ${JSON.stringify(args)}, processing`);

let indices: ContainerIndices | undefined = undefined;
let indices: ContainerIndicesCollection = undefined;
if(name.content === '$<-') {
const nonEmptyArgs = args.filter(arg => arg !== EmptyArgument);
const accessedArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.Accessed);
const indexArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.IndexAccess);
const valueArg = nonEmptyArgs.find(arg => arg.info.role === RoleInParent.BinaryOperationRhs);
if(indexArg !== undefined && valueArg?.value !== undefined && accessedArg != undefined) {
// use access node as reference to get complete line in slice
indices = [ { lexeme: indexArg.lexeme, nodeId: accessedArg.info.parent ?? '' } ]; // valueArg.value.info.id
indices = [
{
indices: [ { lexeme: indexArg.lexeme, nodeId: accessedArg.info.parent ?? '' } ],
isSingleIndex: true
}
];
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/dataflow/internal/process/functions/call/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ function forceVertexArgumentValueReferences(rootId: NodeId, value: DataflowInfor

export function processAllArguments<OtherInfo>(
{ functionName, args, data, finalGraph, functionRootId, forceArgs = [], patchData = d => d }: ProcessAllArgumentInput<OtherInfo>,
isSingle: boolean = false,
isSingleIndex: boolean = false,
): ProcessAllArgumentResult {
let finalEnv = functionName.environment;
// arg env contains the environments with other args defined
Expand Down Expand Up @@ -116,7 +116,8 @@ export function processAllArguments<OtherInfo>(
if(happensInEveryBranch(resolved.controlDependencies)) {
assumeItMayHaveAHigherTarget = false;
}
if(!isSingle) {
// When only a single index is referenced, we don't need to reference the whole object
if(!isSingleIndex) {
finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, EdgeType.Reads);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { DataflowGraph } from '../../../../graph/graph';
import { EdgeType } from '../../../../graph/edge';
import { dataflowLogger } from '../../../../logger';
import { VertexType } from '../../../../graph/vertex';
import type { ContainerIndices } from '../../../../graph/vertex';
import type { ContainerIndicesCollection } from '../../../../graph/vertex';
import { expensiveTrace } from '../../../../../util/log';

export interface ProcessKnownFunctionCallInput<OtherInfo> extends ForceArguments {
Expand Down 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>, indices: ContainerIndices = 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 All @@ -68,12 +68,13 @@ export function processKnownFunctionCall<OtherInfo>(

const processArgs = reverseOrder ? [...args].reverse() : args;

const isSingleIndex = indicesCollection?.every(indices => indices.isSingleIndex);
const {
finalEnv,
callArgs,
remainingReadInArgs,
processedArguments
} = processAllArguments<OtherInfo>({ functionName, args: processArgs, data, finalGraph, functionRootId: rootId, patchData, forceArgs }, indices?.length === 1);
} = processAllArguments<OtherInfo>({ functionName, args: processArgs, data, finalGraph, functionRootId: rootId, patchData, forceArgs }, isSingleIndex);
if(markAsNSE) {
markNonStandardEvaluationEdges(markAsNSE, processedArguments, finalGraph, rootId);
}
Expand All @@ -87,7 +88,7 @@ export function processKnownFunctionCall<OtherInfo>(
onlyBuiltin: false,
controlDependencies: data.controlDependencies,
args: reverseOrder ? [...callArgs].reverse() : callArgs,
indices: indices,
indicesCollection: indicesCollection,
});

if(hasUnknownSideEffect) {
Expand Down

0 comments on commit 8417576

Please sign in to comment.