mirror of
https://github.com/xodio/xod.git
synced 2026-02-20 02:01:20 +01:00
feat(xod-project, xod-arduino): introduce variadic-pass nodes
This commit is contained in:
@@ -794,6 +794,7 @@ const transformProjectWithImpls = def(
|
||||
R.map(XP.extractBoundInputsToConstNodes(path)),
|
||||
R.chain(XP.flatten(R.__, path)),
|
||||
R.map(XP.expandVariadicNodes(path)),
|
||||
R.map(XP.expandVariadicPassNodes(path)),
|
||||
R.map(XP.linkifyPatchRecursively(path)),
|
||||
R.chain(XP.autoresolveTypes(path)),
|
||||
R.unless(
|
||||
|
||||
@@ -23,7 +23,7 @@ const getMarkerNodesErrorMap = (predicate, validator, errorType) => patch => {
|
||||
mergeAllWithConcat,
|
||||
R.map(R.objOf(R.__, { [errorType]: [err] }))
|
||||
)(markerNodeIds),
|
||||
R.always({ [errorType]: [] }),
|
||||
R.always({}),
|
||||
validator(patch)
|
||||
);
|
||||
};
|
||||
@@ -35,12 +35,30 @@ const getMarkerNodesErrorMap = (predicate, validator, errorType) => patch => {
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
// :: Patch -> Map NodeId (Map ErrorType [Error])
|
||||
export const getVariadicMarkersErrorMap = getMarkerNodesErrorMap(
|
||||
R.pipe(XP.getNodeType, XP.isVariadicPath),
|
||||
XP.validatePatchForVariadics,
|
||||
'validatePatchForVariadics'
|
||||
);
|
||||
// :: Patch -> Project -> Map NodeId (Map ErrorType [Error])
|
||||
export const getVariadicMarkersErrorMap = (patch, project) =>
|
||||
R.compose(
|
||||
foldEither(
|
||||
err =>
|
||||
R.compose(
|
||||
R.fromPairs,
|
||||
R.map(markerNodeId => [
|
||||
markerNodeId,
|
||||
{ validatePatchForVariadics: [err] },
|
||||
]),
|
||||
R.map(XP.getNodeId),
|
||||
R.filter(
|
||||
R.pipe(
|
||||
XP.getNodeType,
|
||||
R.either(XP.isVariadicPath, XP.isVariadicPassPath)
|
||||
)
|
||||
),
|
||||
XP.listNodes
|
||||
)(patch),
|
||||
R.always({})
|
||||
),
|
||||
XP.validatePatchForVariadics
|
||||
)(project, patch);
|
||||
|
||||
// :: Patch -> Map NodeId (Map ErrorType [Error])
|
||||
export const getAbstractMarkersErrorMap = getMarkerNodesErrorMap(
|
||||
|
||||
@@ -198,6 +198,18 @@
|
||||
"@/variadic-3": {
|
||||
"description": "Makes three rightmost inputs of the patch node containing this node variadic",
|
||||
"path": "@/variadic-3"
|
||||
},
|
||||
"@/variadic-pass-1": {
|
||||
"description": "Makes the rightmost input of the patch node containing this node variadic, passing the arity level down to the variadic nodes to which they link",
|
||||
"path": "@/variadic-pass-1"
|
||||
},
|
||||
"@/variadic-pass-2": {
|
||||
"description": "Makes two rightmost inputs of the patch node containing this node variadic, passing the arity level down to the variadic nodes to which they link",
|
||||
"path": "@/variadic-pass-2"
|
||||
},
|
||||
"@/variadic-pass-3": {
|
||||
"description": "Makes three rightmost inputs of the patch node containing this node variadic, passing the arity level down to the variadic nodes to which they link",
|
||||
"path": "@/variadic-pass-3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const nodeIdLens = R.lens(Node.getNodeId, R.assoc('id'));
|
||||
|
||||
// helpers for creating nodes inside expanded patch
|
||||
|
||||
const createAdditionalValueTerminalGroups = (
|
||||
export const createAdditionalValueTerminalGroups = (
|
||||
patch,
|
||||
desiredArityLevel,
|
||||
originalTerminalNodes,
|
||||
|
||||
231
packages/xod-project/src/expandVariadicPassNodes.js
Normal file
231
packages/xod-project/src/expandVariadicPassNodes.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import * as R from 'ramda';
|
||||
import { Maybe } from 'ramda-fantasy';
|
||||
import { explodeEither, isAmong } from 'xod-func-tools';
|
||||
|
||||
import { def } from './types';
|
||||
|
||||
import * as Pin from './pin';
|
||||
import * as Node from './node';
|
||||
import * as Link from './link';
|
||||
import * as Patch from './patch';
|
||||
import * as Project from './project';
|
||||
import {
|
||||
getExpandedVariadicPatchPath,
|
||||
isVariadicPassPath,
|
||||
} from './patchPathUtils';
|
||||
import { createAdditionalValueTerminalGroups } from './expandVariadicNodes';
|
||||
|
||||
const expandPassPatch = R.curry((desiredArityLevel, patch) => {
|
||||
const expandedPatchPath = R.compose(
|
||||
getExpandedVariadicPatchPath(desiredArityLevel),
|
||||
Patch.getPatchPath
|
||||
)(patch);
|
||||
|
||||
// :: {
|
||||
// acc :: [Pin],
|
||||
// value :: [Pin],
|
||||
// shared :: [Pin],
|
||||
// outputs :: [Pin],
|
||||
// }
|
||||
const variadicPins = R.compose(
|
||||
R.map(R.sortBy(Pin.getPinOrder)),
|
||||
explodeEither,
|
||||
Patch.computeVariadicPins
|
||||
)(patch);
|
||||
|
||||
// :: [Node]
|
||||
const originalTerminalNodes = R.compose(
|
||||
R.filter(Node.isPinNode),
|
||||
Patch.listNodes
|
||||
)(patch);
|
||||
|
||||
// :: [ [Node] ]
|
||||
const additionalValueTerminalGroups = createAdditionalValueTerminalGroups(
|
||||
patch,
|
||||
desiredArityLevel,
|
||||
originalTerminalNodes,
|
||||
variadicPins
|
||||
);
|
||||
|
||||
const variadicPinKeys = R.compose(R.map(Pin.getPinKey), R.prop('value'))(
|
||||
variadicPins
|
||||
);
|
||||
|
||||
const linksFromVariadicOutputs = R.compose(
|
||||
R.filter(R.pipe(Link.getLinkOutputNodeId, isAmong(variadicPinKeys))),
|
||||
Patch.listLinks
|
||||
)(patch);
|
||||
const nodesConnectedToVariadicInputs = R.compose(
|
||||
R.map(nodeId => Patch.getNodeByIdUnsafe(nodeId, patch)),
|
||||
R.uniq,
|
||||
R.map(Link.getLinkInputNodeId)
|
||||
)(linksFromVariadicOutputs);
|
||||
|
||||
const arityLens = R.lens(Node.getNodeArityLevel, Node.setNodeArityLevel);
|
||||
const variadicNodesWithAddedArity = R.map(
|
||||
R.over(arityLens, R.add(desiredArityLevel - 1)),
|
||||
nodesConnectedToVariadicInputs
|
||||
);
|
||||
|
||||
const linksFromAdditionalTerminalsToNodesWithAddedArity = R.compose(
|
||||
R.chain(terminalGroupIndex =>
|
||||
R.map(link => {
|
||||
const inputNodeId = Link.getLinkInputNodeId(link);
|
||||
const inputPinKey = R.compose(
|
||||
R.over(Pin.variadicPinKeySuffixLens, R.add(terminalGroupIndex)),
|
||||
Link.getLinkInputPinKey
|
||||
)(link);
|
||||
const outputNodeId = R.compose(
|
||||
Pin.addVariadicPinKeySuffix(terminalGroupIndex),
|
||||
Link.getLinkOutputNodeId
|
||||
)(link);
|
||||
const outputPinKey = Link.getLinkOutputPinKey(link);
|
||||
|
||||
return Link.createLink(
|
||||
inputPinKey,
|
||||
inputNodeId,
|
||||
outputPinKey,
|
||||
outputNodeId
|
||||
);
|
||||
})(linksFromVariadicOutputs)
|
||||
),
|
||||
R.range(1) // [1; desiredArityLevel)
|
||||
)(desiredArityLevel);
|
||||
|
||||
const markerNode = R.compose(
|
||||
R.find(R.pipe(Node.getNodeType, isVariadicPassPath)),
|
||||
Patch.listNodes
|
||||
)(patch);
|
||||
|
||||
return R.compose(
|
||||
Patch.dissocNode(markerNode),
|
||||
Patch.upsertLinks(linksFromAdditionalTerminalsToNodesWithAddedArity),
|
||||
Patch.upsertNodes([
|
||||
...R.unnest(additionalValueTerminalGroups),
|
||||
...variadicNodesWithAddedArity,
|
||||
]),
|
||||
Patch.setPatchPath(expandedPatchPath)
|
||||
)(patch);
|
||||
});
|
||||
|
||||
//
|
||||
// expand all patches(starting from a specified entry patch)
|
||||
//
|
||||
|
||||
const traverseExpandableQueue = (
|
||||
queue,
|
||||
processed,
|
||||
acc,
|
||||
processQueueElement
|
||||
) => {
|
||||
if (R.isEmpty(queue)) return acc;
|
||||
|
||||
const [currentQueueElement, ...restQueueElements] = queue;
|
||||
|
||||
if (R.contains(currentQueueElement, processed))
|
||||
return traverseExpandableQueue(
|
||||
restQueueElements,
|
||||
processed,
|
||||
acc,
|
||||
processQueueElement
|
||||
);
|
||||
|
||||
const { result, additionalQueueElements } = processQueueElement(
|
||||
currentQueueElement,
|
||||
acc
|
||||
);
|
||||
|
||||
const updatedQueue = R.compose(
|
||||
R.uniq,
|
||||
R.concat(restQueueElements),
|
||||
R.difference(R.__, processed)
|
||||
)(additionalQueueElements);
|
||||
|
||||
return traverseExpandableQueue(
|
||||
updatedQueue,
|
||||
R.append(currentQueueElement, processed),
|
||||
result,
|
||||
processQueueElement
|
||||
);
|
||||
};
|
||||
|
||||
export default def(
|
||||
'expandVariadicPassNodes :: PatchPath -> Project -> Project',
|
||||
(entryPatchPath, initialProject) =>
|
||||
traverseExpandableQueue(
|
||||
[entryPatchPath],
|
||||
[],
|
||||
initialProject,
|
||||
(currentPatchPath, project) => {
|
||||
const initialPatch = Project.getPatchByPathUnsafe(
|
||||
currentPatchPath,
|
||||
project
|
||||
);
|
||||
|
||||
const nodesToExpand = R.compose(
|
||||
R.filter(
|
||||
R.compose(
|
||||
Patch.isVariadicPassPatch,
|
||||
Project.getPatchByPathUnsafe(R.__, project),
|
||||
Node.getNodeType
|
||||
)
|
||||
),
|
||||
R.filter(R.pipe(Node.getNodeArityLevel, al => al > 1)),
|
||||
Patch.listNodes
|
||||
)(initialPatch);
|
||||
// TODO: short-cirquit if nodesToExpand is empty?
|
||||
|
||||
const expandedPatches = R.compose(
|
||||
R.map(({ patchPath, desiredArityLevel }) =>
|
||||
R.compose(
|
||||
expandPassPatch(desiredArityLevel),
|
||||
Project.getPatchByPathUnsafe(patchPath)
|
||||
)(project)
|
||||
),
|
||||
R.reject(({ patchPath, desiredArityLevel }) =>
|
||||
R.compose(
|
||||
Maybe.isJust,
|
||||
Project.getPatchByPath(
|
||||
getExpandedVariadicPatchPath(desiredArityLevel, patchPath)
|
||||
)
|
||||
)(project)
|
||||
),
|
||||
R.uniq,
|
||||
R.map(
|
||||
R.applySpec({
|
||||
patchPath: Node.getNodeType,
|
||||
desiredArityLevel: Node.getNodeArityLevel,
|
||||
})
|
||||
)
|
||||
)(nodesToExpand);
|
||||
|
||||
const updatedPatch = R.compose(
|
||||
Patch.upsertNodes(R.__, initialPatch),
|
||||
R.map(node =>
|
||||
R.compose(
|
||||
Node.setNodeArityLevel(1),
|
||||
Node.setNodeType(
|
||||
getExpandedVariadicPatchPath(
|
||||
Node.getNodeArityLevel(node),
|
||||
Node.getNodeType(node)
|
||||
)
|
||||
)
|
||||
)(node)
|
||||
)
|
||||
)(nodesToExpand);
|
||||
|
||||
const additionalQueueElements = R.compose(
|
||||
R.map(Node.getNodeType),
|
||||
Patch.listNodes
|
||||
)(updatedPatch);
|
||||
|
||||
return {
|
||||
result: Project.upsertPatches(
|
||||
[updatedPatch, ...expandedPatches],
|
||||
project
|
||||
),
|
||||
additionalQueueElements,
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -63,7 +63,6 @@ export {
|
||||
listVariadicValuePins,
|
||||
listVariadicAccPins,
|
||||
listVariadicSharedPins,
|
||||
validatePatchForVariadics,
|
||||
getArityStepFromPatch,
|
||||
isVariadicPatch,
|
||||
isAbstractPatch,
|
||||
@@ -127,6 +126,7 @@ export {
|
||||
default as extractBoundInputsToConstNodes,
|
||||
} from './extractBoundInputsToConstNodes';
|
||||
export { default as expandVariadicNodes } from './expandVariadicNodes';
|
||||
export { default as expandVariadicPassNodes } from './expandVariadicPassNodes';
|
||||
export * from './patchPathUtils';
|
||||
export * from './versionUtils';
|
||||
export * from './xodball';
|
||||
|
||||
@@ -202,6 +202,12 @@ export default {
|
||||
note: `A variadic-${arityStep} patch with ${outputCount} outputs should have at least ${minInputs} inputs`,
|
||||
trace,
|
||||
}),
|
||||
NOT_ENOUGH_VARIADIC_PASS_INPUTS: ({ trace, arityStep }) => ({
|
||||
title: 'Too few variadic inputs',
|
||||
note: `A variadic-pass-${arityStep} patch should have at least ${arityStep} inputs`,
|
||||
solution: 'Add inputs or delete the marker to continue.',
|
||||
trace,
|
||||
}),
|
||||
WRONG_VARIADIC_PIN_TYPES: ({ accPinLabels, outPinLabels, trace }) => ({
|
||||
title: 'Invalid variadic patch',
|
||||
note: `Types of inputs ${accPinLabels.join(
|
||||
@@ -214,6 +220,24 @@ export default {
|
||||
note: `A variadic patch should have at least one output`,
|
||||
trace,
|
||||
}),
|
||||
VARIADIC_PASS_CONNECTED_TO_NON_VARIADIC_NODE: ({
|
||||
trace,
|
||||
variadicPassPinLabel,
|
||||
connectedNodeType,
|
||||
}) => ({
|
||||
title: 'Variadic input links to scalar node',
|
||||
note: `A variadic-pass input ${variadicPassPinLabel} is linked to a non-variadic node ${connectedNodeType}`,
|
||||
trace,
|
||||
}),
|
||||
VARIADIC_PASS_CONNECTED_TO_NON_VARIADIC_PIN: ({
|
||||
trace,
|
||||
variadicPassPinLabel,
|
||||
connectedNodeType,
|
||||
}) => ({
|
||||
title: 'Variadic input links to scalar pin of a variadic node',
|
||||
note: `A variadic-pass input ${variadicPassPinLabel} is linked to a non-variadic pin of node ${connectedNodeType}`,
|
||||
trace,
|
||||
}),
|
||||
|
||||
// Transpile
|
||||
IMPLEMENTATION_NOT_FOUND: ({ patchPath, trace }) => ({
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
isBuiltInLibName,
|
||||
isLocalMarker,
|
||||
isVariadicPath,
|
||||
isVariadicPassPath,
|
||||
isExpandedVariadicPatchBasename,
|
||||
getArityStepFromPatchPath,
|
||||
getSpecializationPatchPath,
|
||||
@@ -1226,7 +1227,12 @@ export const patchListEqualsBy = def(
|
||||
*/
|
||||
const findVariadicPatchPath = def(
|
||||
'findVariadicPatchPath :: Patch -> Maybe PatchPath',
|
||||
R.compose(Maybe, R.find(isVariadicPath), R.map(Node.getNodeType), listNodes)
|
||||
R.compose(
|
||||
Maybe,
|
||||
R.find(R.either(isVariadicPath, isVariadicPassPath)),
|
||||
R.map(Node.getNodeType),
|
||||
listNodes
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -1237,6 +1243,11 @@ export const isVariadicPatch = def(
|
||||
R.compose(Maybe.isJust, findVariadicPatchPath)
|
||||
);
|
||||
|
||||
export const isVariadicPassPatch = def(
|
||||
'isVariadicPassPatch :: Patch -> Boolean',
|
||||
R.compose(foldMaybe(false, isVariadicPassPath), findVariadicPatchPath)
|
||||
);
|
||||
|
||||
/**
|
||||
* Get arity step (1/2/3) from Patch by checking for
|
||||
* existing of variadic node and extract its arity step from
|
||||
@@ -1256,7 +1267,7 @@ const checkArityMarkersAmount = def(
|
||||
R.compose(
|
||||
R.equals(1),
|
||||
R.length,
|
||||
R.filter(isVariadicPath),
|
||||
R.filter(R.either(isVariadicPath, isVariadicPassPath)),
|
||||
R.map(Node.getNodeType),
|
||||
listNodes
|
||||
)
|
||||
@@ -1277,10 +1288,12 @@ export const computeVariadicPins = def(
|
||||
return fail('TOO_MANY_VARIADIC_MARKERS', { trace: [patchPath] });
|
||||
}
|
||||
|
||||
const isVariadicPass = isVariadicPassPatch(patch);
|
||||
|
||||
const outputs = listOutputPins(patch);
|
||||
const outputCount = outputs.length;
|
||||
|
||||
if (outputCount === 0) {
|
||||
if (!isVariadicPass && outputCount === 0) {
|
||||
return fail('VARIADIC_HAS_NO_OUTPUTS', { trace: [patchPath] });
|
||||
}
|
||||
|
||||
@@ -1293,13 +1306,18 @@ export const computeVariadicPins = def(
|
||||
getArityStepFromPatch
|
||||
)(patch);
|
||||
|
||||
if (inputCount - arityStep < outputCount) {
|
||||
const minInputs = R.add(outputCount, arityStep);
|
||||
const notEnoughVariadicInputs = inputCount - arityStep < outputCount;
|
||||
if (!isVariadicPass && notEnoughVariadicInputs) {
|
||||
return fail('NOT_ENOUGH_VARIADIC_INPUTS', {
|
||||
trace: [patchPath],
|
||||
arityStep,
|
||||
outputCount,
|
||||
minInputs,
|
||||
minInputs: outputCount + arityStep,
|
||||
});
|
||||
} else if (isVariadicPass && inputCount < arityStep) {
|
||||
return fail('NOT_ENOUGH_VARIADIC_PASS_INPUTS', {
|
||||
trace: [patchPath],
|
||||
arityStep,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1309,30 +1327,30 @@ export const computeVariadicPins = def(
|
||||
R.slice(0, R.negate(arityStep))
|
||||
)(inputs);
|
||||
|
||||
const pinLabelsOfNonEqualPinTypes = R.compose(
|
||||
R.reject(R.isNil),
|
||||
mapIndexed((accPin, idx) => {
|
||||
const curPinType = Pin.getPinType(accPin);
|
||||
const outPinType = Pin.getPinType(outputs[idx]);
|
||||
return curPinType === outPinType
|
||||
? null
|
||||
: [Pin.getPinLabel(accPin), Pin.getPinLabel(outputs[idx])];
|
||||
})
|
||||
)(accPins);
|
||||
if (!isVariadicPass) {
|
||||
const pinLabelsOfNonEqualPinTypes = R.compose(
|
||||
R.reject(R.isNil),
|
||||
mapIndexed((accPin, idx) => {
|
||||
const curPinType = Pin.getPinType(accPin);
|
||||
const outPinType = Pin.getPinType(outputs[idx]);
|
||||
return curPinType === outPinType
|
||||
? null
|
||||
: [Pin.getPinLabel(accPin), Pin.getPinLabel(outputs[idx])];
|
||||
})
|
||||
)(accPins);
|
||||
|
||||
if (notEmpty(pinLabelsOfNonEqualPinTypes)) {
|
||||
const accPinLabels = R.pluck(0, pinLabelsOfNonEqualPinTypes);
|
||||
const outPinLabels = R.pluck(1, pinLabelsOfNonEqualPinTypes);
|
||||
return fail('WRONG_VARIADIC_PIN_TYPES', {
|
||||
trace: [patchPath],
|
||||
accPinLabels,
|
||||
outPinLabels,
|
||||
});
|
||||
if (notEmpty(pinLabelsOfNonEqualPinTypes)) {
|
||||
const accPinLabels = R.pluck(0, pinLabelsOfNonEqualPinTypes);
|
||||
const outPinLabels = R.pluck(1, pinLabelsOfNonEqualPinTypes);
|
||||
return fail('WRONG_VARIADIC_PIN_TYPES', {
|
||||
trace: [patchPath],
|
||||
accPinLabels,
|
||||
outPinLabels,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const sharedPins = R.slice(0, R.negate(R.add(accPins.length, arityStep)))(
|
||||
inputs
|
||||
);
|
||||
const sharedPins = R.slice(0, -(accPins.length + arityStep), inputs);
|
||||
|
||||
return Either.of({
|
||||
acc: accPins,
|
||||
@@ -1372,22 +1390,6 @@ export const listVariadicSharedPins = def(
|
||||
R.compose(R.pluck('shared'), computeVariadicPins)
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks a patch for variadic marker existence.
|
||||
* If it has variadic marker — compute and validate variadic Pins,
|
||||
* and then return Either Error Patch.
|
||||
* If not - just return Either.Right Patch.
|
||||
*/
|
||||
export const validatePatchForVariadics = def(
|
||||
'validatePatchForVariadics :: Patch -> Either Error Patch',
|
||||
patch =>
|
||||
R.ifElse(
|
||||
isVariadicPatch,
|
||||
R.compose(R.map(R.always(patch)), computeVariadicPins),
|
||||
Either.of
|
||||
)(patch)
|
||||
);
|
||||
|
||||
/**
|
||||
* Computes and returns map of pins for Node with additional Pins,
|
||||
* if Node has `arityLevel > 1` and Patch has a variadic markers.
|
||||
|
||||
@@ -208,11 +208,22 @@ const variadicRegExp = new RegExp(`^${PATCH_NODES_LIB_NAME}/variadic-([1-3])`);
|
||||
// :: PatchPath -> Boolean
|
||||
export const isVariadicPath = R.test(variadicRegExp);
|
||||
|
||||
const variadicPassRegExp = new RegExp(
|
||||
`^${PATCH_NODES_LIB_NAME}/variadic-pass-([1-3])`
|
||||
);
|
||||
|
||||
// :: PatchPath -> Boolean
|
||||
export const isVariadicPassPath = R.test(variadicPassRegExp);
|
||||
|
||||
const variadicOrPassRegExp = new RegExp(
|
||||
`^${PATCH_NODES_LIB_NAME}/variadic-(?:pass-)?([1-3])`
|
||||
);
|
||||
|
||||
// :: PatchPath -> ArityStep
|
||||
export const getArityStepFromPatchPath = R.compose(
|
||||
x => parseInt(x, 10),
|
||||
R.nth(1),
|
||||
R.match(variadicRegExp)
|
||||
R.match(variadicOrPassRegExp)
|
||||
);
|
||||
|
||||
// :: NonZeroNaturalNumber -> PatchPath
|
||||
|
||||
@@ -324,6 +324,28 @@ export const addVariadicPinKeySuffix = def(
|
||||
(index, key) => `${key}-$${index}`
|
||||
);
|
||||
|
||||
const parseVariadicPinKey = pinKey => {
|
||||
const [, base, , indexStr = '0'] = R.match(
|
||||
/([A-Za-z0-9_-]*)(-\$(\d+))?$/,
|
||||
pinKey
|
||||
);
|
||||
return {
|
||||
base,
|
||||
index: parseInt(indexStr, 10),
|
||||
};
|
||||
};
|
||||
|
||||
export const variadicPinKeySuffixLens = R.lens(
|
||||
R.pipe(parseVariadicPinKey, R.prop('index')),
|
||||
(newIndex, pinKey) => {
|
||||
const { base } = parseVariadicPinKey(pinKey);
|
||||
|
||||
if (newIndex === 0) return base;
|
||||
|
||||
return addVariadicPinKeySuffix(newIndex, base);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* (!) This function should be called only for variadic pins,
|
||||
* that should have an updated label.
|
||||
|
||||
@@ -736,6 +736,118 @@ const checkPatchForDeadLinksAndPins = def(
|
||||
}
|
||||
);
|
||||
|
||||
export const validatePatchForVariadics = def(
|
||||
'validatePatchForVariadics :: Project -> Patch -> Either Error Patch',
|
||||
(project, validatedPatch) => {
|
||||
if (!Patch.isVariadicPatch(validatedPatch)) {
|
||||
return Either.of(validatedPatch);
|
||||
}
|
||||
|
||||
return Patch.computeVariadicPins(validatedPatch).chain(
|
||||
({ value: variadicPins }) => {
|
||||
// `computeVariadicPins` checks for all possible errors in "regular" variadic patches.
|
||||
// We only need to do additional checks for variadic-pass patches.
|
||||
if (!Patch.isVariadicPassPatch(validatedPatch)) {
|
||||
return Either.of(validatedPatch);
|
||||
}
|
||||
|
||||
const normalizedPinLabelsByPinKey = R.compose(
|
||||
R.map(Pin.getPinLabel),
|
||||
R.indexBy(Pin.getPinKey),
|
||||
Pin.normalizeEmptyPinLabels,
|
||||
Patch.listPins
|
||||
)(validatedPatch);
|
||||
|
||||
const variadicPassPinsByKey = R.indexBy(Pin.getPinKey, variadicPins);
|
||||
|
||||
return R.compose(
|
||||
R.map(R.head),
|
||||
R.sequence(Either.of),
|
||||
R.map(link => {
|
||||
const variadicPassPinLabel = R.compose(
|
||||
R.prop(R.__, normalizedPinLabelsByPinKey),
|
||||
Link.getLinkOutputNodeId
|
||||
)(link);
|
||||
|
||||
return R.compose(
|
||||
foldMaybe(
|
||||
// If we got here, some variadic pins
|
||||
// are connected to a dead node.
|
||||
// That's a job for other validators.
|
||||
Either.of(validatedPatch),
|
||||
([connectedNodeType, connectedPatch]) => {
|
||||
if (!Patch.isVariadicPatch(connectedPatch)) {
|
||||
return fail(
|
||||
'VARIADIC_PASS_CONNECTED_TO_NON_VARIADIC_NODE',
|
||||
{
|
||||
variadicPassPinLabel,
|
||||
connectedNodeType,
|
||||
trace: [Patch.getPatchPath(validatedPatch)],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const connectedPatchVariadicPins = Patch.computeVariadicPins(
|
||||
connectedPatch
|
||||
);
|
||||
|
||||
if (Either.isLeft(connectedPatchVariadicPins)) {
|
||||
// That's a job for a validator of that particular patch
|
||||
return Either.of(validatedPatch);
|
||||
}
|
||||
|
||||
return connectedPatchVariadicPins.chain(
|
||||
({ value: variadicPinsOfConnectedNode }) => {
|
||||
const inputPinKey = R.compose(
|
||||
R.set(Pin.variadicPinKeySuffixLens, 0),
|
||||
Link.getLinkInputPinKey
|
||||
)(link);
|
||||
|
||||
const isInputPinVariadic = R.compose(
|
||||
R.contains(inputPinKey),
|
||||
R.map(Pin.getPinKey)
|
||||
)(variadicPinsOfConnectedNode);
|
||||
|
||||
if (isInputPinVariadic) return Either.of(validatedPatch);
|
||||
|
||||
return fail(
|
||||
'VARIADIC_PASS_CONNECTED_TO_NON_VARIADIC_PIN',
|
||||
{
|
||||
variadicPassPinLabel,
|
||||
connectedNodeType,
|
||||
trace: [Patch.getPatchPath(validatedPatch)],
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
),
|
||||
R.chain(connectedNode => {
|
||||
const connectedNodeType = Node.getNodeType(connectedNode);
|
||||
const maybeConnectedPatch = getPatchByPath(
|
||||
connectedNodeType,
|
||||
project
|
||||
);
|
||||
|
||||
return R.sequence(Maybe.of, [
|
||||
Maybe.of(connectedNodeType),
|
||||
maybeConnectedPatch,
|
||||
]);
|
||||
}),
|
||||
Patch.getNodeById(R.__, validatedPatch),
|
||||
Link.getLinkInputNodeId
|
||||
)(link);
|
||||
}),
|
||||
R.filter(
|
||||
R.pipe(Link.getLinkOutputNodeId, R.has(R.__, variadicPassPinsByKey))
|
||||
),
|
||||
Patch.listLinks
|
||||
)(validatedPatch);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks `patch` content to be valid:
|
||||
*
|
||||
@@ -756,7 +868,7 @@ export const validatePatchContents = def(
|
||||
.chain(Patch.validateAbstractPatch)
|
||||
.chain(Patch.validateConstructorPatch)
|
||||
.chain(Patch.validateRecordPatch)
|
||||
.chain(Patch.validatePatchForVariadics)
|
||||
.chain(validatePatchForVariadics(project))
|
||||
.chain(Patch.validateBuses)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,110 +1,54 @@
|
||||
import R from 'ramda';
|
||||
import { assert } from 'chai';
|
||||
import { loadXodball } from './helpers';
|
||||
import * as H from './helpers';
|
||||
import * as XP from '../src';
|
||||
|
||||
import * as Node from '../src/node';
|
||||
import * as Link from '../src/link';
|
||||
import * as Patch from '../src/patch';
|
||||
import * as Project from '../src/project';
|
||||
// assume that nodes have an unique combination of
|
||||
// type, label and position
|
||||
const calculateNodeIdForStructuralComparison = node => {
|
||||
const type = XP.getNodeType(node);
|
||||
const label = XP.getNodeLabel(node);
|
||||
const position = XP.getNodePosition(node);
|
||||
|
||||
import expandVariadicNodes from '../src/expandVariadicNodes';
|
||||
return `${type}~~~${label}~~~${position.x}_${position.y}`;
|
||||
};
|
||||
|
||||
describe('expandVariadicNodes', () => {
|
||||
it('expands a simple variadic patch', () => {
|
||||
const project = loadXodball('./fixtures/expanding.xodball');
|
||||
const expandedProject = expandVariadicNodes('@/main', project);
|
||||
const project = H.loadXodball('./fixtures/expanding.xodball');
|
||||
const expandedProject = XP.expandVariadicNodes('@/main', project);
|
||||
|
||||
assert.deepEqual(
|
||||
Project.getPatchByPathUnsafe('@/my-variadic', expandedProject),
|
||||
Project.getPatchByPathUnsafe('@/my-variadic', project),
|
||||
XP.getPatchByPathUnsafe('@/my-variadic', expandedProject),
|
||||
XP.getPatchByPathUnsafe('@/my-variadic', project),
|
||||
'expanded patch should not change'
|
||||
);
|
||||
|
||||
const expected = loadXodball('./fixtures/expanding.expected.xodball');
|
||||
const expected = H.loadXodball('./fixtures/expanding.expected.xodball');
|
||||
|
||||
assert.sameMembers(
|
||||
Project.listPatchPaths(expandedProject),
|
||||
Project.listPatchPaths(expected)
|
||||
XP.listPatchPaths(expandedProject),
|
||||
XP.listPatchPaths(expected)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
Project.getPatchByPathUnsafe('@/main', expandedProject),
|
||||
Project.getPatchByPathUnsafe('@/main', expected),
|
||||
XP.getPatchByPathUnsafe('@/main', expandedProject),
|
||||
XP.getPatchByPathUnsafe('@/main', expected),
|
||||
'expanded node type should be updated'
|
||||
);
|
||||
|
||||
const expandedPatch = Project.getPatchByPathUnsafe(
|
||||
const expandedPatch = XP.getPatchByPathUnsafe(
|
||||
'@/my-variadic-$5',
|
||||
expandedProject
|
||||
);
|
||||
const expectedExpandedPatch = Project.getPatchByPathUnsafe(
|
||||
const expectedExpandedPatch = XP.getPatchByPathUnsafe(
|
||||
'@/my-variadic-$5',
|
||||
expected
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
Patch.listPins(expandedPatch),
|
||||
Patch.listPins(expectedExpandedPatch),
|
||||
'pins are equal'
|
||||
);
|
||||
|
||||
const [
|
||||
expandedPatchNonTerminalNodes,
|
||||
expectedExpandedPatchNonTerminalNodes,
|
||||
] = R.map(
|
||||
R.compose(
|
||||
R.sortBy(R.pipe(Node.getNodePosition, R.prop('x'))),
|
||||
R.reject(Node.isPinNode),
|
||||
Patch.listNodes
|
||||
),
|
||||
[expandedPatch, expectedExpandedPatch]
|
||||
);
|
||||
|
||||
const omitIds = R.map(R.dissoc('id'));
|
||||
|
||||
assert.deepEqual(
|
||||
omitIds(expandedPatchNonTerminalNodes),
|
||||
omitIds(expectedExpandedPatchNonTerminalNodes),
|
||||
'non-terminal nodes are structurally equal'
|
||||
);
|
||||
|
||||
// because nodes are structurally equal,
|
||||
// we can compare links by replacing node ids
|
||||
const correspondingExpectedNodeIds = R.compose(
|
||||
R.fromPairs,
|
||||
R.map(R.map(Node.getNodeId)),
|
||||
R.zip
|
||||
)(expandedPatchNonTerminalNodes, expectedExpandedPatchNonTerminalNodes);
|
||||
const replaceId = id => correspondingExpectedNodeIds[id] || id;
|
||||
|
||||
const expectedExpandedPatchLinks = R.compose(omitIds, Patch.listLinks)(
|
||||
H.assertPatchesAreStructurallyEqual(
|
||||
calculateNodeIdForStructuralComparison,
|
||||
expandedPatch,
|
||||
expectedExpandedPatch
|
||||
);
|
||||
|
||||
const expandedPatchLinks = R.compose(
|
||||
omitIds,
|
||||
R.map(link => {
|
||||
const inputPinKey = Link.getLinkInputPinKey(link);
|
||||
const inputNodeId = R.compose(replaceId, Link.getLinkInputNodeId)(link);
|
||||
const outputPinKey = Link.getLinkOutputPinKey(link);
|
||||
const outputNodeId = R.compose(replaceId, Link.getLinkOutputNodeId)(
|
||||
link
|
||||
);
|
||||
|
||||
return Link.createLink(
|
||||
inputPinKey,
|
||||
inputNodeId,
|
||||
outputPinKey,
|
||||
outputNodeId
|
||||
);
|
||||
}),
|
||||
Patch.listLinks
|
||||
)(expandedPatch);
|
||||
|
||||
assert.deepEqual(
|
||||
expandedPatchLinks,
|
||||
expectedExpandedPatchLinks,
|
||||
'links are structurally equal'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
52
packages/xod-project/test/expandVariadicPassNodes.spec.js
Normal file
52
packages/xod-project/test/expandVariadicPassNodes.spec.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { assert } from 'chai';
|
||||
import * as H from './helpers';
|
||||
import * as XP from '../src';
|
||||
|
||||
// assume that nodes have an unique combination of
|
||||
// type, label and position
|
||||
const calculateNodeIdForStructuralComparison = node => {
|
||||
const type = XP.getNodeType(node);
|
||||
const label = XP.getNodeLabel(node);
|
||||
const position = XP.getNodePosition(node);
|
||||
|
||||
return `${type}~~~${label}~~~${position.x}_${position.y}`;
|
||||
};
|
||||
|
||||
describe('expandVariadicPassNodes', () => {
|
||||
it('expands a variadic-pass patch', () => {
|
||||
const project = H.loadXodball('./fixtures/expanding-variadic-pass.xodball');
|
||||
const expandedProject = XP.expandVariadicPassNodes('@/main', project);
|
||||
|
||||
assert.deepEqual(
|
||||
XP.getPatchByPathUnsafe('@/my-variadic-pass', expandedProject),
|
||||
XP.getPatchByPathUnsafe('@/my-variadic-pass', project),
|
||||
'expanded patch should not change'
|
||||
);
|
||||
|
||||
const expected = H.loadXodball(
|
||||
'./fixtures/expanding-variadic-pass.expected.xodball'
|
||||
);
|
||||
|
||||
assert.sameMembers(
|
||||
XP.listPatchPaths(expandedProject),
|
||||
XP.listPatchPaths(expected)
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
XP.getPatchByPathUnsafe('@/main', expandedProject),
|
||||
XP.getPatchByPathUnsafe('@/main', expected),
|
||||
'expanded node type should be updated'
|
||||
);
|
||||
|
||||
H.assertPatchesAreStructurallyEqual(
|
||||
calculateNodeIdForStructuralComparison,
|
||||
XP.getPatchByPathUnsafe('@/my-variadic-pass-$4', expected),
|
||||
XP.getPatchByPathUnsafe('@/my-variadic-pass-$4', expected)
|
||||
);
|
||||
H.assertPatchesAreStructurallyEqual(
|
||||
calculateNodeIdForStructuralComparison,
|
||||
XP.getPatchByPathUnsafe('@/my-nested-variadic-pass-$4', expected),
|
||||
XP.getPatchByPathUnsafe('@/my-nested-variadic-pass-$4', expected)
|
||||
);
|
||||
});
|
||||
});
|
||||
679
packages/xod-project/test/fixtures/expanding-variadic-pass.expected.xodball
vendored
Normal file
679
packages/xod-project/test/fixtures/expanding-variadic-pass.expected.xodball
vendored
Normal file
@@ -0,0 +1,679 @@
|
||||
{
|
||||
"patches": {
|
||||
"@/main": {
|
||||
"nodes": {
|
||||
"HJBtpIRzu": {
|
||||
"id": "HJBtpIRzu",
|
||||
"type": "@/my-variadic-pass-$4",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"boundLiterals": {
|
||||
"Hyo8pL0zu": "11",
|
||||
"SkTITICfO": "12",
|
||||
"Hyo8pL0zu-$1": "21",
|
||||
"SkTITICfO-$1": "22",
|
||||
"Hyo8pL0zu-$2": "31",
|
||||
"SkTITICfO-$2": "32",
|
||||
"Hyo8pL0zu-$3": "41",
|
||||
"SkTITICfO-$3": "42"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/main"
|
||||
},
|
||||
"@/my-variadic-pass": {
|
||||
"nodes": {
|
||||
"Skq3nUAGd": {
|
||||
"id": "Skq3nUAGd",
|
||||
"type": "@/my-nested-variadic-pass",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rJMIpICz_": {
|
||||
"id": "rJMIpICz_",
|
||||
"type": "xod/patch-nodes/variadic-pass-2",
|
||||
"position": {
|
||||
"x": 6,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hyo8pL0zu": {
|
||||
"id": "Hyo8pL0zu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"SkTITICfO": {
|
||||
"id": "SkTITICfO",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rJ3d68AzO": {
|
||||
"id": "rJ3d68AzO",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 5,
|
||||
"units": "slots"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"S1VDTURGO": {
|
||||
"id": "S1VDTURGO",
|
||||
"output": {
|
||||
"nodeId": "Hyo8pL0zu",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "Hk5io80G_"
|
||||
}
|
||||
},
|
||||
"SyHPTIRf_": {
|
||||
"id": "SyHPTIRf_",
|
||||
"output": {
|
||||
"nodeId": "SkTITICfO",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "HkH6nIAf_"
|
||||
}
|
||||
},
|
||||
"ByRuT8CfO": {
|
||||
"id": "ByRuT8CfO",
|
||||
"output": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "ry-bhIRfu"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "rJ3d68AzO",
|
||||
"pinKey": "__in__"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/my-variadic-pass"
|
||||
},
|
||||
"@/my-nested-variadic-pass": {
|
||||
"nodes": {
|
||||
"BJYOjU0fd": {
|
||||
"id": "BJYOjU0fd",
|
||||
"type": "@/foo",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"units": "slots"
|
||||
},
|
||||
"boundLiterals": {
|
||||
"H10LiLCGu": "42",
|
||||
"HJzkaICfu": "1337"
|
||||
},
|
||||
"arityLevel": 2
|
||||
},
|
||||
"Hk5io80G_": {
|
||||
"id": "Hk5io80G_",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"ry-bhIRfu": {
|
||||
"id": "ry-bhIRfu",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 4,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HkH6nIAf_": {
|
||||
"id": "HkH6nIAf_",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rkOfaICMO": {
|
||||
"id": "rkOfaICMO",
|
||||
"type": "xod/patch-nodes/variadic-pass-2",
|
||||
"position": {
|
||||
"x": 7,
|
||||
"y": 2,
|
||||
"units": "slots"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"Sy_W2UAMO": {
|
||||
"id": "Sy_W2UAMO",
|
||||
"output": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "rk7UiIRf_"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "ry-bhIRfu",
|
||||
"pinKey": "__in__"
|
||||
}
|
||||
},
|
||||
"Skf7aUAG_": {
|
||||
"id": "Skf7aUAG_",
|
||||
"output": {
|
||||
"nodeId": "Hk5io80G_",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "HJzkaICfu-$1"
|
||||
}
|
||||
},
|
||||
"BkmQTU0f_": {
|
||||
"id": "BkmQTU0f_",
|
||||
"output": {
|
||||
"nodeId": "HkH6nIAf_",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "H10LiLCGu-$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/my-nested-variadic-pass"
|
||||
},
|
||||
"@/foo": {
|
||||
"nodes": {
|
||||
"SyjVsIRfO": {
|
||||
"id": "SyjVsIRfO",
|
||||
"type": "xod/patch-nodes/utility",
|
||||
"position": {
|
||||
"x": 8,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"B1vrs8AzO": {
|
||||
"id": "B1vrs8AzO",
|
||||
"type": "xod/patch-nodes/not-implemented-in-xod",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"BJTSsU0Mu": {
|
||||
"id": "BJTSsU0Mu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"label": "ACC"
|
||||
},
|
||||
"rk7UiIRf_": {
|
||||
"id": "rk7UiIRf_",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 5,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"H10LiLCGu": {
|
||||
"id": "H10LiLCGu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"label": "V1"
|
||||
},
|
||||
"rJJypU0GO": {
|
||||
"id": "rJJypU0GO",
|
||||
"type": "xod/patch-nodes/variadic-2",
|
||||
"position": {
|
||||
"x": 5,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HJzkaICfu": {
|
||||
"id": "HJzkaICfu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 7,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"label": "V2"
|
||||
}
|
||||
},
|
||||
"path": "@/foo",
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "patch.cpp",
|
||||
"encoding": "utf-8",
|
||||
"content": "\nnode {\n void evaluate(Context ctx) {}\n}\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@/my-variadic-pass-$4": {
|
||||
"nodes": {
|
||||
"Skq3nUAGd": {
|
||||
"id": "Skq3nUAGd",
|
||||
"type": "@/my-nested-variadic-pass-$4",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hyo8pL0zu": {
|
||||
"id": "Hyo8pL0zu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"SkTITICfO": {
|
||||
"id": "SkTITICfO",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rJ3d68AzO": {
|
||||
"id": "rJ3d68AzO",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 5,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hyo8pL0zu-$1": {
|
||||
"id": "Hyo8pL0zu-$1",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 5,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"SkTITICfO-$1": {
|
||||
"id": "SkTITICfO-$1",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hyo8pL0zu-$2": {
|
||||
"id": "Hyo8pL0zu-$2",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 7,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"SkTITICfO-$2": {
|
||||
"id": "SkTITICfO-$2",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 8,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hyo8pL0zu-$3": {
|
||||
"id": "Hyo8pL0zu-$3",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 9,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"SkTITICfO-$3": {
|
||||
"id": "SkTITICfO-$3",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"S1VDTURGO": {
|
||||
"id": "S1VDTURGO",
|
||||
"output": {
|
||||
"nodeId": "Hyo8pL0zu",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "Hk5io80G_"
|
||||
}
|
||||
},
|
||||
"SyHPTIRf_": {
|
||||
"id": "SyHPTIRf_",
|
||||
"output": {
|
||||
"nodeId": "SkTITICfO",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "HkH6nIAf_"
|
||||
}
|
||||
},
|
||||
"ByRuT8CfO": {
|
||||
"id": "ByRuT8CfO",
|
||||
"output": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "ry-bhIRfu"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "rJ3d68AzO",
|
||||
"pinKey": "__in__"
|
||||
}
|
||||
},
|
||||
"BywLCLCfO": {
|
||||
"id": "BywLCLCfO",
|
||||
"output": {
|
||||
"nodeId": "Hyo8pL0zu-$1",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "Hk5io80G_-$1"
|
||||
}
|
||||
},
|
||||
"BklD8CL0zd": {
|
||||
"id": "BklD8CL0zd",
|
||||
"output": {
|
||||
"nodeId": "SkTITICfO-$1",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "HkH6nIAf_-$1"
|
||||
}
|
||||
},
|
||||
"ryWPI0LCzu": {
|
||||
"id": "ryWPI0LCzu",
|
||||
"output": {
|
||||
"nodeId": "Hyo8pL0zu-$2",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "Hk5io80G_-$2"
|
||||
}
|
||||
},
|
||||
"SJzDL0UAfu": {
|
||||
"id": "SJzDL0UAfu",
|
||||
"output": {
|
||||
"nodeId": "SkTITICfO-$2",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "HkH6nIAf_-$2"
|
||||
}
|
||||
},
|
||||
"HyQvLA8Rfd": {
|
||||
"id": "HyQvLA8Rfd",
|
||||
"output": {
|
||||
"nodeId": "Hyo8pL0zu-$3",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "Hk5io80G_-$3"
|
||||
}
|
||||
},
|
||||
"H1Ew808AGO": {
|
||||
"id": "H1Ew808AGO",
|
||||
"output": {
|
||||
"nodeId": "SkTITICfO-$3",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "HkH6nIAf_-$3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/my-variadic-pass-$4"
|
||||
},
|
||||
"@/my-nested-variadic-pass-$4": {
|
||||
"nodes": {
|
||||
"BJYOjU0fd": {
|
||||
"id": "BJYOjU0fd",
|
||||
"type": "@/foo",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"units": "slots"
|
||||
},
|
||||
"boundLiterals": {
|
||||
"H10LiLCGu": "42",
|
||||
"HJzkaICfu": "1337"
|
||||
},
|
||||
"arityLevel": 5
|
||||
},
|
||||
"Hk5io80G_": {
|
||||
"id": "Hk5io80G_",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"ry-bhIRfu": {
|
||||
"id": "ry-bhIRfu",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 4,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HkH6nIAf_": {
|
||||
"id": "HkH6nIAf_",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hk5io80G_-$1": {
|
||||
"id": "Hk5io80G_-$1",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 5,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HkH6nIAf_-$1": {
|
||||
"id": "HkH6nIAf_-$1",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 6,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hk5io80G_-$2": {
|
||||
"id": "Hk5io80G_-$2",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 7,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HkH6nIAf_-$2": {
|
||||
"id": "HkH6nIAf_-$2",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 8,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hk5io80G_-$3": {
|
||||
"id": "Hk5io80G_-$3",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 9,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HkH6nIAf_-$3": {
|
||||
"id": "HkH6nIAf_-$3",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"Sy_W2UAMO": {
|
||||
"id": "Sy_W2UAMO",
|
||||
"output": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "rk7UiIRf_"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "ry-bhIRfu",
|
||||
"pinKey": "__in__"
|
||||
}
|
||||
},
|
||||
"Skf7aUAG_": {
|
||||
"id": "Skf7aUAG_",
|
||||
"output": {
|
||||
"nodeId": "Hk5io80G_",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "HJzkaICfu-$1"
|
||||
}
|
||||
},
|
||||
"BkmQTU0f_": {
|
||||
"id": "BkmQTU0f_",
|
||||
"output": {
|
||||
"nodeId": "HkH6nIAf_",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "H10LiLCGu-$1"
|
||||
}
|
||||
},
|
||||
"SJHPU0LAzO": {
|
||||
"id": "SJHPU0LAzO",
|
||||
"output": {
|
||||
"nodeId": "Hk5io80G_-$1",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "HJzkaICfu-$2"
|
||||
}
|
||||
},
|
||||
"Sy8w8RUAGu": {
|
||||
"id": "Sy8w8RUAGu",
|
||||
"output": {
|
||||
"nodeId": "HkH6nIAf_-$1",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "H10LiLCGu-$2"
|
||||
}
|
||||
},
|
||||
"HyDvIAI0Gu": {
|
||||
"id": "HyDvIAI0Gu",
|
||||
"output": {
|
||||
"nodeId": "Hk5io80G_-$2",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "HJzkaICfu-$3"
|
||||
}
|
||||
},
|
||||
"H1uP8AURfu": {
|
||||
"id": "H1uP8AURfu",
|
||||
"output": {
|
||||
"nodeId": "HkH6nIAf_-$2",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "H10LiLCGu-$3"
|
||||
}
|
||||
},
|
||||
"S1KvURIRGO": {
|
||||
"id": "S1KvURIRGO",
|
||||
"output": {
|
||||
"nodeId": "Hk5io80G_-$3",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "HJzkaICfu-$4"
|
||||
}
|
||||
},
|
||||
"S1cw80LRG_": {
|
||||
"id": "S1cw80LRG_",
|
||||
"output": {
|
||||
"nodeId": "HkH6nIAf_-$3",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "H10LiLCGu-$4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/my-nested-variadic-pass-$4"
|
||||
}
|
||||
},
|
||||
"name": ""
|
||||
}
|
||||
283
packages/xod-project/test/fixtures/expanding-variadic-pass.xodball
vendored
Normal file
283
packages/xod-project/test/fixtures/expanding-variadic-pass.xodball
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
{
|
||||
"patches": {
|
||||
"@/main": {
|
||||
"nodes": {
|
||||
"HJBtpIRzu": {
|
||||
"id": "HJBtpIRzu",
|
||||
"type": "@/my-variadic-pass",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"boundLiterals": {
|
||||
"Hyo8pL0zu": "11",
|
||||
"SkTITICfO": "12",
|
||||
"Hyo8pL0zu-$1": "21",
|
||||
"SkTITICfO-$1": "22",
|
||||
"Hyo8pL0zu-$2": "31",
|
||||
"SkTITICfO-$2": "32",
|
||||
"Hyo8pL0zu-$3": "41",
|
||||
"SkTITICfO-$3": "42"
|
||||
},
|
||||
"arityLevel": 4
|
||||
}
|
||||
},
|
||||
"path": "@/main"
|
||||
},
|
||||
"@/my-variadic-pass": {
|
||||
"nodes": {
|
||||
"Skq3nUAGd": {
|
||||
"id": "Skq3nUAGd",
|
||||
"type": "@/my-nested-variadic-pass",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rJMIpICz_": {
|
||||
"id": "rJMIpICz_",
|
||||
"type": "xod/patch-nodes/variadic-pass-2",
|
||||
"position": {
|
||||
"x": 6,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"Hyo8pL0zu": {
|
||||
"id": "Hyo8pL0zu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"SkTITICfO": {
|
||||
"id": "SkTITICfO",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rJ3d68AzO": {
|
||||
"id": "rJ3d68AzO",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 5,
|
||||
"units": "slots"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"S1VDTURGO": {
|
||||
"id": "S1VDTURGO",
|
||||
"output": {
|
||||
"nodeId": "Hyo8pL0zu",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "Hk5io80G_"
|
||||
}
|
||||
},
|
||||
"SyHPTIRf_": {
|
||||
"id": "SyHPTIRf_",
|
||||
"output": {
|
||||
"nodeId": "SkTITICfO",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "HkH6nIAf_"
|
||||
}
|
||||
},
|
||||
"ByRuT8CfO": {
|
||||
"id": "ByRuT8CfO",
|
||||
"output": {
|
||||
"nodeId": "Skq3nUAGd",
|
||||
"pinKey": "ry-bhIRfu"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "rJ3d68AzO",
|
||||
"pinKey": "__in__"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/my-variadic-pass"
|
||||
},
|
||||
"@/my-nested-variadic-pass": {
|
||||
"nodes": {
|
||||
"BJYOjU0fd": {
|
||||
"id": "BJYOjU0fd",
|
||||
"type": "@/foo",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 2,
|
||||
"units": "slots"
|
||||
},
|
||||
"boundLiterals": {
|
||||
"H10LiLCGu": "42",
|
||||
"HJzkaICfu": "1337"
|
||||
},
|
||||
"arityLevel": 2
|
||||
},
|
||||
"Hk5io80G_": {
|
||||
"id": "Hk5io80G_",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"ry-bhIRfu": {
|
||||
"id": "ry-bhIRfu",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 4,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HkH6nIAf_": {
|
||||
"id": "HkH6nIAf_",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 0,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"rkOfaICMO": {
|
||||
"id": "rkOfaICMO",
|
||||
"type": "xod/patch-nodes/variadic-pass-2",
|
||||
"position": {
|
||||
"x": 7,
|
||||
"y": 2,
|
||||
"units": "slots"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"Sy_W2UAMO": {
|
||||
"id": "Sy_W2UAMO",
|
||||
"output": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "rk7UiIRf_"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "ry-bhIRfu",
|
||||
"pinKey": "__in__"
|
||||
}
|
||||
},
|
||||
"Skf7aUAG_": {
|
||||
"id": "Skf7aUAG_",
|
||||
"output": {
|
||||
"nodeId": "Hk5io80G_",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "HJzkaICfu-$1"
|
||||
}
|
||||
},
|
||||
"BkmQTU0f_": {
|
||||
"id": "BkmQTU0f_",
|
||||
"output": {
|
||||
"nodeId": "HkH6nIAf_",
|
||||
"pinKey": "__out__"
|
||||
},
|
||||
"input": {
|
||||
"nodeId": "BJYOjU0fd",
|
||||
"pinKey": "H10LiLCGu-$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"path": "@/my-nested-variadic-pass"
|
||||
},
|
||||
"@/foo": {
|
||||
"nodes": {
|
||||
"SyjVsIRfO": {
|
||||
"id": "SyjVsIRfO",
|
||||
"type": "xod/patch-nodes/utility",
|
||||
"position": {
|
||||
"x": 8,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"B1vrs8AzO": {
|
||||
"id": "B1vrs8AzO",
|
||||
"type": "xod/patch-nodes/not-implemented-in-xod",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"BJTSsU0Mu": {
|
||||
"id": "BJTSsU0Mu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"label": "ACC"
|
||||
},
|
||||
"rk7UiIRf_": {
|
||||
"id": "rk7UiIRf_",
|
||||
"type": "xod/patch-nodes/output-number",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 5,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"H10LiLCGu": {
|
||||
"id": "H10LiLCGu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 4,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"label": "V1"
|
||||
},
|
||||
"rJJypU0GO": {
|
||||
"id": "rJJypU0GO",
|
||||
"type": "xod/patch-nodes/variadic-2",
|
||||
"position": {
|
||||
"x": 5,
|
||||
"y": 3,
|
||||
"units": "slots"
|
||||
}
|
||||
},
|
||||
"HJzkaICfu": {
|
||||
"id": "HJzkaICfu",
|
||||
"type": "xod/patch-nodes/input-number",
|
||||
"position": {
|
||||
"x": 7,
|
||||
"y": 1,
|
||||
"units": "slots"
|
||||
},
|
||||
"label": "V2"
|
||||
}
|
||||
},
|
||||
"path": "@/foo",
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "patch.cpp",
|
||||
"encoding": "utf-8",
|
||||
"content": "\nnode {\n void evaluate(Context ctx) {}\n}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"name": ""
|
||||
}
|
||||
Reference in New Issue
Block a user