p5
Version:
[](https://www.npmjs.com/package/p5)
161 lines (143 loc) • 4.63 kB
JavaScript
import { BasePriority, NodeTypeRequiredFields, NodeTypeToName, BaseType } from './ir_types.js';
import { internalError } from './strands_FES.js';
/////////////////////////////////
// Public functions for strands runtime
/////////////////////////////////
function createDirectedAcyclicGraph() {
const graph = {
nextID: 0,
cache: new Map(),
nodeTypes: [],
baseTypes: [],
dimensions: [],
opCodes: [],
values: [],
identifiers: [],
phiBlocks: [],
dependsOn: [],
usedBy: [],
statementTypes: [],
swizzles: [],
};
return graph;
}
function getOrCreateNode(graph, node) {
// const key = getNodeKey(node);
// const existing = graph.cache.get(key);
// if (existing !== undefined) {
// return existing;
// } else {
const id = createNode(graph, node);
// graph.cache.set(key, id);
return id;
// }
}
function createNodeData(data = {}) {
const node = {
nodeType: data.nodeType ?? null,
baseType: data.baseType ?? null,
dimension: data.dimension ?? null,
opCode: data.opCode ?? null,
value: data.value ?? null,
identifier: data.identifier ?? null,
statementType: data.statementType ?? null,
swizzle: data.swizzle ?? null,
dependsOn: Array.isArray(data.dependsOn) ? data.dependsOn : [],
usedBy: Array.isArray(data.usedBy) ? data.usedBy : [],
phiBlocks: Array.isArray(data.phiBlocks) ? data.phiBlocks : [],
};
validateNode(node);
return node;
}
function getNodeDataFromID(graph, id) {
return {
id,
nodeType: graph.nodeTypes[id],
opCode: graph.opCodes[id],
value: graph.values[id],
identifier: graph.identifiers[id],
dependsOn: graph.dependsOn[id],
usedBy: graph.usedBy[id],
phiBlocks: graph.phiBlocks[id],
dimension: graph.dimensions[id],
baseType: graph.baseTypes[id],
statementType: graph.statementTypes[id],
swizzle: graph.swizzles[id],
}
}
function extractNodeTypeInfo(dag, nodeID) {
return {
baseType: dag.baseTypes[nodeID],
dimension: dag.dimensions[nodeID],
priority: BasePriority[dag.baseTypes[nodeID]],
};
}
// Propagate a known type to an ASSIGN_ON_USE node and all its ASSIGN_ON_USE dependencies
function propagateTypeToAssignOnUse(dag, nodeId, baseType, dimension, visited = new Set()) {
// Avoid infinite loops
if (visited.has(nodeId)) {
return;
}
visited.add(nodeId);
const node = getNodeDataFromID(dag, nodeId);
// Only update if this node is ASSIGN_ON_USE
if (node.baseType !== BaseType.ASSIGN_ON_USE) {
return;
}
// Update this node's type
dag.baseTypes[nodeId] = baseType;
dag.dimensions[nodeId] = dimension;
// Recursively propagate to any ASSIGN_ON_USE dependencies
if (node.dependsOn && node.dependsOn.length > 0) {
for (const depId of node.dependsOn) {
const dep = getNodeDataFromID(dag, depId);
if (dep.baseType === BaseType.ASSIGN_ON_USE) {
propagateTypeToAssignOnUse(dag, depId, baseType, dimension, visited);
}
}
}
}
/////////////////////////////////
// Private functions
/////////////////////////////////
function createNode(graph, node) {
const id = graph.nextID++;
graph.nodeTypes[id] = node.nodeType;
graph.opCodes[id] = node.opCode;
graph.values[id] = node.value;
graph.identifiers[id] = node.identifier;
graph.dependsOn[id] = node.dependsOn.slice();
graph.usedBy[id] = node.usedBy;
graph.phiBlocks[id] = node.phiBlocks.slice();
graph.baseTypes[id] = node.baseType;
graph.dimensions[id] = node.dimension;
graph.statementTypes[id] = node.statementType;
graph.swizzles[id] = node.swizzle;
for (const dep of node.dependsOn) {
if (!Array.isArray(graph.usedBy[dep])) {
graph.usedBy[dep] = [];
}
graph.usedBy[dep].push(id);
}
return id;
}
function validateNode(node){
const nodeType = node.nodeType;
const requiredFields = NodeTypeRequiredFields[nodeType];
if (requiredFields.length === 2) {
internalError(`Required fields for node type '${NodeTypeToName[nodeType]}' not defined. Please add them to the utils.js file in p5.strands!`);
}
const missingFields = [];
for (const field of requiredFields) {
if (node[field] === null) {
missingFields.push(field);
}
}
if (node.dependsOn?.some(v => v === undefined)) {
throw new Error('Undefined dependency!');
}
if (missingFields.length > 0) {
internalError(`Missing fields ${missingFields.join(', ')} for a node type '${NodeTypeToName[nodeType]}'.`);
}
}
export { createDirectedAcyclicGraph, createNodeData, extractNodeTypeInfo, getNodeDataFromID, getOrCreateNode, propagateTypeToAssignOnUse };