Skip to content

Commit

Permalink
Merge pull request #1958 from xodio/dont-utilize-jumpers-during-bus-c…
Browse files Browse the repository at this point in the history
…onnecting-and-type-resolution

Stop relying on jumpers when connecting buses or deducing types
  • Loading branch information
evgenykochetkov authored Feb 13, 2020
2 parents 3c9715c + 318c0d9 commit fbff3d7
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 289 deletions.
2 changes: 1 addition & 1 deletion packages/xod-arduino/src/transpiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ const transformProjectWithImpls = def(
R.map(XP.extractBoundInputsToConstNodes(path)),
R.chain(XP.flatten(R.__, path)),
R.map(XP.expandVariadicNodes(path)),
R.map(XP.jumperizePatchRecursively(path)),
R.map(XP.linkifyPatchRecursively(path)),
R.chain(XP.autoresolveTypes(path)),
R.unless(
() => liveness !== LIVENESS.NONE,
Expand Down
88 changes: 49 additions & 39 deletions packages/xod-project/src/Buses.re
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ type matchingBusNodes = list((Node.t, list(Node.t)));

[@bs.module ".."] external toBusPatchPath : Patch.path = "TO_BUS_PATH";

[@bs.module ".."] external jumperPatchPath : Patch.path = "JUMPER_PATCH_PATH";

let getMatchingBusNodes = patch => {
let nodes = Patch.listNodes(patch);
let toBusNodesByLabel =
Expand Down Expand Up @@ -39,53 +37,65 @@ let getMatchingBusNodes = patch => {
};
};

let jumperizePatch: (Patch.t, matchingBusNodes) => Patch.t =
(patch, matchingBusNodes) => {
let linksByOutputNodeId =
patch
|. Patch.listLinks
|. BeltHoles.List.groupByString(Link.getOutputNodeId);
let linkifyPatch: (Patch.t, matchingBusNodes) => Patch.t =
(originalPatch, matchingBusNodes) => {
List.reduce(
matchingBusNodes,
patch,
(jPatch, (toBusNode, fromBusNodes)) => {
let jumperNodeId = Node.getId(toBusNode);
let linksFromJumperToBusDestinations =
fromBusNodes
|. List.map(fromBusNode =>
Map.String.getWithDefault(
linksByOutputNodeId,
Node.getId(fromBusNode),
[],
)
)
|. List.flatten
|. List.map(link =>
Link.create(
~toPin=Link.getInputPinKey(link),
~toNode=Link.getInputNodeId(link),
~fromPin="__out__",
~fromNode=jumperNodeId,
)
);
let dissocFromBusNodes = patchWithFromBusNodes =>
List.reduce(fromBusNodes, patchWithFromBusNodes, (accP, n) =>
Patch.dissocNode(accP, Node.getId(n))
);
jPatch
|. Patch.assocNode(Node.setType(jumperPatchPath, toBusNode))
|. dissocFromBusNodes
|. Patch.upsertLinks(linksFromJumperToBusDestinations);
originalPatch,
(patch, (toBusNode, fromBusNodes)) => {
let toBusNodeId = Node.getId(toBusNode);

let linksByOutputNodeId =
patch
|. Patch.listLinks
|. BeltHoles.List.groupByString(Link.getOutputNodeId);

patch
|. Patch.listLinks
|. List.keep(l => Link.getInputNodeId(l) == toBusNodeId)
|. List.head
|. Option.mapWithDefault(patch, linkFromSource => {
let sourceNodeId = Link.getOutputNodeId(linkFromSource);
let sourcePinKey = Link.getOutputPinKey(linkFromSource);

let linksFromSourceToBusDestinations =
fromBusNodes
|. List.map(fromBusNode =>
Map.String.getWithDefault(
linksByOutputNodeId,
Node.getId(fromBusNode),
[],
)
)
|. List.flatten
|. List.map(link =>
Link.create(
~toPin=Link.getInputPinKey(link),
~toNode=Link.getInputNodeId(link),
~fromPin=sourcePinKey,
~fromNode=sourceNodeId,
)
);

let dissocFromBusNodes = patchWithFromBusNodes =>
List.reduce(fromBusNodes, patchWithFromBusNodes, (accP, n) =>
Patch.dissocNode(accP, Node.getId(n))
);
patch
|. Patch.dissocNode(toBusNodeId)
|. dissocFromBusNodes
|. Patch.upsertLinks(linksFromSourceToBusDestinations);
});
},
);
};

let jumperizePatchRecursively = (project, entryPatchPath) =>
let linkifyPatchRecursively = (project, entryPatchPath) =>
project
|. Project.getPatchDependencies(entryPatchPath)
|. List.add(entryPatchPath)
|. List.keepMap(Project.getPatchByPath(project))
|. List.map(p => jumperizePatch(p, getMatchingBusNodes(p)))
|. List.map(p => linkifyPatch(p, getMatchingBusNodes(p)))
|> Project.upsertPatches(project);

/* move to Link module? */
Expand Down
11 changes: 4 additions & 7 deletions packages/xod-project/src/Buses.rei
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ type matchingBusNodes = list((Node.t, list(Node.t)));
/** Returns a list of valid matching bus nodes for a given patch */
let getMatchingBusNodes: Patch.t => matchingBusNodes;

/** Replaces `to-bus` nodes with `jumper`s,
creates links from it to `from-bus` nodes.
see https://raw.githubusercontent.com/wiki/xodio/xod/images/illustrations-for-xod-source-code/xod-project/jumperize-before-after.png
*/
let jumperizePatch: (Patch.t, matchingBusNodes) => Patch.t;
/** Converts matching bus nodes into links */
let linkifyPatch: (Patch.t, matchingBusNodes) => Patch.t;

/** "Jumperizes" a patch with a given path and all patches it depends on */
let jumperizePatchRecursively: (Project.t, Patch.path) => Project.t;
/** "Linkifies" a patch with a given path and all patches it depends on */
let linkifyPatchRecursively: (Project.t, Patch.path) => Project.t;

/** Splits links with given ids into buses.
Buses are named after output pin labels, so name conflicts are possible. */
Expand Down
4 changes: 2 additions & 2 deletions packages/xod-project/src/Buses_Js.re
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
let jumperizePatchRecursivelyU: (Patch.path, Project.t) => Project.t =
let linkifyPatchRecursivelyU: (Patch.path, Project.t) => Project.t =
(patchPath, project) =>
Buses.jumperizePatchRecursively(project, patchPath);
Buses.linkifyPatchRecursively(project, patchPath);

let splitLinksToBusesU:
((Node.t, Pin.t) => Position.t, Patch.path, array(Link.id), Project.t) =>
Expand Down
2 changes: 2 additions & 0 deletions packages/xod-project/src/Pin.re
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,5 @@ let getPrimitiveTypeExn = (pin: t) : primitiveDataType => {
};

let getLabel = pin => pin##label;

let getType = pin => pin##_type;
2 changes: 2 additions & 0 deletions packages/xod-project/src/Pin.rei
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ let getPrimitiveTypeExn: t => primitiveDataType;
let getKey: t => key;

let getLabel: t => string;

let getType: t => dataType;
94 changes: 62 additions & 32 deletions packages/xod-project/src/TypeDeduction.re
Original file line number Diff line number Diff line change
Expand Up @@ -58,40 +58,70 @@ module ResultsMap = {
external deducePinTypesWithoutBuses_ : (Patch.t, Project.t) => ResultsMap.t_Js =
"deducePinTypesWithoutBuses";

let jumperOutPinKey = "__out__";
let toBusInputPinKey = "__in__";
let fromBusOutputPinKey = "__out__";

let deducePinTypes: (Patch.t, Project.t) => ResultsMap.t =
(patch, project) => {
let matchingBusNodes = Buses.getMatchingBusNodes(patch);
let jumperizedPatch = Buses.jumperizePatch(patch, matchingBusNodes);
let deductionResultsForJumperizedPatch =
jumperizedPatch
(originalPatch, project) => {
let matchingBusNodes = Buses.getMatchingBusNodes(originalPatch);
let linkifiedPatch = Buses.linkifyPatch(originalPatch, matchingBusNodes);
let deductionResultsForLinkifiedPatch =
linkifiedPatch
|. deducePinTypesWithoutBuses_(project)
|. ResultsMap.fromJsDict;
List.reduce(
matchingBusNodes,
deductionResultsForJumperizedPatch,
(deductionResults, (toBusNode, fromBusNodes)) => {
let jumperNodeId = Node.getId(toBusNode);
switch (
ResultsMap.get(deductionResults, jumperNodeId, jumperOutPinKey)
) {
| None => deductionResults
| Some(deductionResultForJumperOut) =>
let fromBusNodeIds = List.map(fromBusNodes, Node.getId);
let copyResultToFromBusNodes = drs =>
List.reduce(fromBusNodeIds, drs, (accDrs, nodeId) =>
ResultsMap.assoc(
accDrs,
nodeId,
jumperOutPinKey,
deductionResultForJumperOut,
)
);
deductionResults
|. ResultsMap.dissoc(jumperNodeId, jumperOutPinKey)
|. copyResultToFromBusNodes;
};
},
);

switch (List.length(matchingBusNodes)) {
| 0 => deductionResultsForLinkifiedPatch
| _ =>
let linksByInputNodeId =
originalPatch
|. Patch.listLinks
|. BeltHoles.List.groupByString(Link.getInputNodeId);
List.reduce(
matchingBusNodes,
deductionResultsForLinkifiedPatch,
(deductionResults, (toBusNode, fromBusNodes)) => {
let toBusNodeId = Node.getId(toBusNode);

linksByInputNodeId
|. Map.String.get(toBusNodeId)
|. Option.flatMap(List.head)
|. Option.mapWithDefault(deductionResults, linkFromSource => {
let sourceNodeId = Link.getOutputNodeId(linkFromSource);
let sourcePinKey = Link.getOutputPinKey(linkFromSource);

let deductionResultForSourceOutput = switch (
ResultsMap.get(deductionResults, sourceNodeId, sourcePinKey)
) {
| Some(deductionResult) => deductionResult
| None =>
// it's not in the deducted types,
// so it must be a non-generic pin
// (or even from a dead node)
originalPatch
|. Patch.getNodeById(sourceNodeId)
|. Option.flatMap(Project.getPatchByNode(project))
|. Option.flatMap(Patch.getPinByKey(_, sourcePinKey))
|. Option.map(Pin.getType)
|. Option.mapWithDefault(Result.Error([||]), pinType => Result.Ok(pinType));
};

let fromBusNodeIds = List.map(fromBusNodes, Node.getId);
let copyResultToFromBusNodes = drs =>
List.reduce(fromBusNodeIds, drs, (accDrs, nodeId) =>
ResultsMap.assoc(
accDrs,
nodeId,
fromBusOutputPinKey,
deductionResultForSourceOutput,
)
);

deductionResults
|. ResultsMap.assoc(toBusNodeId, toBusInputPinKey, deductionResultForSourceOutput)
|. copyResultToFromBusNodes;
})
},
);
}
};
4 changes: 2 additions & 2 deletions packages/xod-project/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { curry } from 'ramda';

// because functions exported from Reason are uncurried
import { jumperizePatchRecursivelyU, splitLinksToBusesU } from './Buses_Js.bs';
import { linkifyPatchRecursivelyU, splitLinksToBusesU } from './Buses_Js.bs';
import { listUpstreamPinsToNiixU } from './Traversing_Js.bs';

export * from './project';
Expand Down Expand Up @@ -143,6 +143,6 @@ export { sortGraph } from './gmath';
export { BUILT_IN_TERMINAL_PATCH_PATHS } from './builtinTerminalPatches';
export { BINDABLE_CUSTOM_TYPES } from './custom-types';

export const jumperizePatchRecursively = curry(jumperizePatchRecursivelyU);
export const linkifyPatchRecursively = curry(linkifyPatchRecursivelyU);
export const splitLinksToBuses = curry(splitLinksToBusesU);
export const listUpstreamPinsToNiix = curry(listUpstreamPinsToNiixU);
8 changes: 4 additions & 4 deletions packages/xod-project/test/buses.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ const calculateNodeIdForStructuralComparison = node => {
};

describe('buses', () => {
describe('jumperizePatchRecursively', () => {
describe('linkifyPatchRecursively', () => {
it('replaces bus nodes with links', () => {
const project = H.loadXodball('./fixtures/jumperize.xodball');
const project = H.loadXodball('./fixtures/linkify.xodball');

const actualProject = XP.jumperizePatchRecursively('@/main', project);
const actualProject = XP.linkifyPatchRecursively('@/main', project);

const expectedProject = H.loadXodball(
'./fixtures/jumperize.expected.xodball'
'./fixtures/linkify.expected.xodball'
);

H.assertPatchesAreStructurallyEqual(
Expand Down
Loading

0 comments on commit fbff3d7

Please sign in to comment.