private FuturePortValue unwrapPort(Value inputPortValue) { if (inputPortValue instanceof TupleValue) { TupleValue inputPortTuple = (TupleValue) inputPortValue; if (inputPortTuple.getSize() == 1) { // get "first" entry Iterator<Value> it = inputPortTuple.getEntries().values().iterator(); // possibly wrapped again? return unwrapPort(it.next()); } else { throw new UndefinedBehaviourError("cannot unwrap"); } } else if (inputPortValue instanceof FuturePortValue) { return (FuturePortValue) inputPortValue; } else { throw new UndefinedBehaviourError("value not a port or 1-tuple of ports"); } }
@Override public void elaborate() throws Exception { // prevent infinite recursive elaboration if (futureOutputPorts != null) { return; } log.debug("type signature is " + signature.toString()); // decompose signature into (input) -> (output) TupleTypeValue inputType = (TupleTypeValue) signature.getInputType(); TupleTypeValue outputType = (TupleTypeValue) signature.getOutputType(); // construct values for all future output ports // simultaneously build a collection of all input port names Set<String> inputPortNames = new HashSet<>(); Set<String> outputPortNames = new HashSet<>(); inputPortNames.addAll(nodeType.getPorts().keySet()); MappedArray<String, Value> futurePortMap = new MappedArray<>(); for (MappedArray<String, TypeValue>.Entry typeEntry : outputType.getSubtypes()) { String outputPortName = typeEntry.getKey(); PortTypeValue outputPortType = nodeType.getPorts().get(outputPortName); FuturePortValue futurePort = new FuturePortValue(this, outputPortName, outputPortType); futurePortMap.put(outputPortName, futurePort); inputPortNames.remove(outputPortName); outputPortNames.add(outputPortName); } futureOutputPorts = new TupleValue(outputType, futurePortMap); inputEdge.getSource().elaborate(); Value inputValue = inputEdge.getSource().getValue(); TupleValue input = (TupleValue) inputValue; // now we have enough information to disassemble `input` // into attributes and (future) input ports Map<String, Value> nodeAttrs = new HashMap<>(); Map<String, Map<String, Value>> portAttrs = new HashMap<>(); for (String inputPortName : inputPortNames) { PortTypeValue inputPortType = nodeType.getPorts().get(inputPortName); Value inputPortValue = input.getEntry(inputPortName); // if the port has attributes, this is a tuple // (0: FuturePortValue, 1: (attributes)) // otherwise, this is just a FuturePortValue FuturePortValue futurePort; Map<String, Value> inputPortAttrs; if (inputPortType.getAttributes().isEmpty()) { // in the case where a single output port is directly used as input, // this is a tuple of size 1 that needs to be "unwrapped" first futurePort = unwrapPort(inputPortValue); futureInputPorts.put(inputPortName, futurePort); inputPortAttrs = new HashMap<>(); // no attributes } else { TupleValue inputPortTuple = (TupleValue) inputPortValue; // same story here about unwrapping the port futurePort = unwrapPort(inputPortTuple.getEntry(0)); TupleValue attributesValue = (TupleValue) inputPortTuple.getEntry(1); // TODO this can probably be done better, it assumes that all tuple values are named inputPortAttrs = MappedArray.toMap(attributesValue.getEntries()); } futureInputPorts.put(inputPortName, futurePort); portAttrs.put(inputPortName, inputPortAttrs); } // we must also get output port attributes, which appear as function inputs for (String outputPortName : outputPortNames) { PortTypeValue outputPortType = nodeType.getPorts().get(outputPortName); Map<String, Value> outputPortAttrs; if (outputPortType.getAttributes().isEmpty()) { outputPortAttrs = new HashMap<>(); // no attributes } else { TupleValue attributesValue = (TupleValue) input.getEntry(outputPortName); outputPortAttrs = MappedArray.toMap(attributesValue.getEntries()); } portAttrs.put(outputPortName, outputPortAttrs); } for (String attrName : nodeType.getAttributes().keySet()) { Value attrValue = input.getEntry(attrName); nodeAttrs.put(attrName, attrValue); } node = new NodeValue(nodeType, nodeAttrs, portAttrs); }