diff --git a/src/pages/edit/Editor/renderer/Background.tsx b/src/pages/edit/Editor/renderer/Background.tsx index 2cf0032..7dd3b1c 100644 --- a/src/pages/edit/Editor/renderer/Background.tsx +++ b/src/pages/edit/Editor/renderer/Background.tsx @@ -16,9 +16,7 @@ export default function CCComponentEditorRendererBackground() { const startPerspective = componentEditorState.perspective; const startPoint = vector2.fromDomEvent(pointerDownEvent.nativeEvent); - pointerDownEvent.currentTarget.setPointerCapture( - pointerDownEvent.pointerId, - ); + currentTarget.setPointerCapture(pointerDownEvent.pointerId); const onPointerMove = (pointerMoveEvent: PointerEvent) => { const endPoint = vector2.fromDomEvent(pointerMoveEvent); componentEditorState.setPerspective({ @@ -35,9 +33,7 @@ export default function CCComponentEditorRendererBackground() { const onPointerUp = () => { currentTarget.removeEventListener("pointermove", onPointerMove); currentTarget.removeEventListener("pointerup", onPointerUp); - pointerDownEvent.currentTarget.releasePointerCapture( - pointerDownEvent.pointerId, - ); + currentTarget.releasePointerCapture(pointerDownEvent.pointerId); }; currentTarget.addEventListener("pointermove", onPointerMove); currentTarget.addEventListener("pointerup", onPointerUp); diff --git a/src/pages/edit/Editor/renderer/NodePin.tsx b/src/pages/edit/Editor/renderer/NodePin.tsx index ffb4f4a..f825f9e 100644 --- a/src/pages/edit/Editor/renderer/NodePin.tsx +++ b/src/pages/edit/Editor/renderer/NodePin.tsx @@ -29,6 +29,7 @@ export default function CCComponentEditorRendererNodePin({ const componentEditorState = useComponentEditorStore()(); const nodePin = nullthrows(store.nodePins.get(nodePinId)); const node = nullthrows(store.nodes.get(nodePin.nodeId)); + const nodePins = store.nodePins.getManyByNodeId(node.id); const componentPin = nullthrows( store.componentPins.get(nodePin.componentPinId), ); @@ -152,7 +153,10 @@ export default function CCComponentEditorRendererNodePin({ implementationComponentPin.type === "input" ) { nodePinValue = nullthrows( - componentEditorState.getInputValue(implementationComponentPin.id), + componentEditorState.getInputValue( + implementationComponentPin.id, + nodePins, + ), ); } else { nodePinValue = nullthrows( diff --git a/src/pages/edit/Editor/store/slices/core/index.ts b/src/pages/edit/Editor/store/slices/core/index.ts index 88295d0..64828cf 100644 --- a/src/pages/edit/Editor/store/slices/core/index.ts +++ b/src/pages/edit/Editor/store/slices/core/index.ts @@ -5,7 +5,7 @@ import simulateComponent from "../../../../../../store/componentEvaluator"; import type { CCComponentPinId } from "../../../../../../store/componentPin"; import type { CCConnectionId } from "../../../../../../store/connection"; import type { CCNodeId } from "../../../../../../store/node"; -import type { CCNodePinId } from "../../../../../../store/nodePin"; +import type { CCNodePin, CCNodePinId } from "../../../../../../store/nodePin"; import type { ComponentEditorSliceCreator } from "../../types"; import type { EditorStoreCoreSlice } from "./types"; @@ -46,12 +46,13 @@ export const createComponentEditorStoreCoreSlice: ComponentEditorSliceCreator< }, /** @private */ inputValues: new Map(), - getInputValue(componentPinId: CCComponentPinId) { + getInputValue(componentPinId: CCComponentPinId, nodePins: CCNodePin[]) { const value = get().inputValues.get(componentPinId); if (!value) { const multiplexability = store.componentPins.getComponentPinMultiplexability( componentPinId, + nodePins, ); if (multiplexability === "undecidable") { throw new Error("Cannot determine multiplexability"); @@ -174,8 +175,17 @@ export const createComponentEditorStoreCoreSlice: ComponentEditorSliceCreator< const inputValues = new Map(); const pins = store.componentPins.getManyByComponentId(componentId); for (const pin of pins) { + invariant(pin.implementation); if (pin.type === "input") { - inputValues.set(pin.id, editorState.getInputValue(pin.id)); + const nodePin = store.nodePins.get(pin.implementation); + invariant(nodePin); + const node = store.nodes.get(nodePin.nodeId); + invariant(node); + const nodePins = store.nodePins.getManyByNodeId(node.id); + inputValues.set( + pin.id, + editorState.getInputValue(pin.id, nodePins), + ); } } simulationCachedFrames.push( diff --git a/src/pages/edit/Editor/store/slices/core/types.ts b/src/pages/edit/Editor/store/slices/core/types.ts index 052a3d1..e1e62d3 100644 --- a/src/pages/edit/Editor/store/slices/core/types.ts +++ b/src/pages/edit/Editor/store/slices/core/types.ts @@ -3,7 +3,7 @@ import type { Vector2 } from "../../../../../../common/vector2"; import type { CCComponentPinId } from "../../../../../../store/componentPin"; import type { CCConnectionId } from "../../../../../../store/connection"; import type { CCNodeId } from "../../../../../../store/node"; -import type { CCNodePinId } from "../../../../../../store/nodePin"; +import type { CCNodePin, CCNodePinId } from "../../../../../../store/nodePin"; export type EditorMode = EditorModeEdit | EditorModePlay; export type EditorModeEdit = "edit"; @@ -30,7 +30,10 @@ export type EditorStoreCoreSlice = { target: NodePinPropertyEditorTarget | null, ): void; inputValues: Map; - getInputValue(componentPinId: CCComponentPinId): SimulationValue; + getInputValue( + componentPinId: CCComponentPinId, + nodePins: CCNodePin[], + ): SimulationValue; setInputValue(componentPinId: CCComponentPinId, value: SimulationValue): void; setEditorMode(mode: EditorMode): void; resetTimeStep(): void; diff --git a/src/store/componentPin.ts b/src/store/componentPin.ts index b8682c1..bd73670 100644 --- a/src/store/componentPin.ts +++ b/src/store/componentPin.ts @@ -15,7 +15,7 @@ import { or, xor, } from "./intrinsics/definitions"; -import type { CCNodePinId } from "./nodePin"; +import type { CCNodePin, CCNodePinId } from "./nodePin"; export type CCComponentPin = { readonly id: CCComponentPinId; @@ -47,7 +47,11 @@ export type CCPinImplementation = CCNodePinId | null; export type CCPinMultiplexability = | { isMultiplexable: true } - | { isMultiplexable: false; multiplicity: number }; + | { + isMultiplexable: false; + multiplicity: number; + }; +// | { isMultiplexable: false; multiplicity: number }; export type CCComponentPinMultiplexability = | CCPinMultiplexability @@ -239,6 +243,7 @@ export class CCComponentPinStore extends EventEmitter */ getComponentPinMultiplexability( pinId: CCComponentPinId, + nodePins: CCNodePin[], ): CCComponentPinMultiplexability { const pin = this.#pins.get(pinId); invariant(pin); @@ -264,13 +269,43 @@ export class CCComponentPinStore extends EventEmitter return "undecidable"; } case nullthrows(aggregate.outputPin.id): { - return "undecidable"; + const multiplicity = nodePins + .filter((pin) => { + const componentPin = this.#store.componentPins.get( + pin.componentPinId, + ); + invariant(componentPin); + return componentPin.type === "input"; + }) + .reduce((acc, pin) => { + invariant(pin.userSpecifiedBitWidth); + return acc + pin.userSpecifiedBitWidth; + }, 0); + return { + isMultiplexable: false, + multiplicity, + }; } case nullthrows(decompose.outputPin.id): { return "undecidable"; } case nullthrows(decompose.inputPin.In.id): { - return "undecidable"; + const multiplicity = nodePins + .filter((pin) => { + const componentPin = this.#store.componentPins.get( + pin.componentPinId, + ); + invariant(componentPin); + return componentPin.type === "output"; + }) + .reduce((acc, pin) => { + invariant(pin.userSpecifiedBitWidth); + return acc + pin.userSpecifiedBitWidth; + }, 0); + return { + isMultiplexable: false, + multiplicity, + }; } case nullthrows(broadcast.inputPin.In.id): { return { isMultiplexable: false, multiplicity: 1 }; diff --git a/src/store/intrinsics/definitions.ts b/src/store/intrinsics/definitions.ts index 9fdac6e..67edb95 100644 --- a/src/store/intrinsics/definitions.ts +++ b/src/store/intrinsics/definitions.ts @@ -23,7 +23,7 @@ function createUnaryOperator( evaluate: (input) => { invariant(input.A[0] && !input.A[1]); const A = input.A[0]; - return A.map((a) => [evaluate(nullthrows(a))]); + return [A.map((a) => evaluate(nullthrows(a)))]; }, }); } @@ -47,9 +47,11 @@ function createBinaryOperator( const A = input.A[0]; const B = input.B[0]; invariant(A.length === B.length); - return Array.from({ length: input.A.length }, (_, i) => [ - evaluate(nullthrows(A[i]), nullthrows(B[i])), - ]); + return [ + Array.from({ length: A.length }, (_, i) => + evaluate(nullthrows(A[i]), nullthrows(B[i])), + ), + ]; }, }); } @@ -123,10 +125,11 @@ export const broadcast = new IntrinsicComponentDefinition({ out: { name: "Out", isBitWidthConfigurable: true }, evaluate: (input, outputShape) => { invariant(input.In[0] && !input.In[1]); - const inputValue = input.In[0]; + invariant(input.In[0][0] !== undefined && !input.In[0][1]); + const inputValue = input.In[0][0]; invariant(outputShape[0] && !outputShape[1]); const outputMultiplicity = outputShape[0].multiplicity; - return Array.from({ length: outputMultiplicity }, () => inputValue); + return [Array.from({ length: outputMultiplicity }, () => inputValue)]; }, }); diff --git a/src/store/nodePin.ts b/src/store/nodePin.ts index 87560b4..b3630f3 100644 --- a/src/store/nodePin.ts +++ b/src/store/nodePin.ts @@ -188,13 +188,19 @@ export class CCNodePinStore extends EventEmitter { const node = nullthrows(this.#store.nodes.get(nodeId)); const nodePins = this.getManyByNodeId(node.id); const givenPinMultiplexability = - this.#store.componentPins.getComponentPinMultiplexability(pinId); + this.#store.componentPins.getComponentPinMultiplexability( + pinId, + nodePins, + ); if (givenPinMultiplexability === "undecidable") { invariant( userSpecifiedBitWidth, "Multiplexability of undecidable pin must be contained in multiplexabilityEnv", ); - return { isMultiplexable: false, multiplicity: userSpecifiedBitWidth }; + return { + isMultiplexable: false, + multiplicity: userSpecifiedBitWidth, + }; } if (!givenPinMultiplexability.isMultiplexable) { return givenPinMultiplexability; @@ -203,6 +209,7 @@ export class CCNodePinStore extends EventEmitter { const pinMultiplexability = this.#store.componentPins.getComponentPinMultiplexability( nodePin.componentPinId, + nodePins, ); if (pinMultiplexability === "undecidable") { throw new Error("unreachable");