Esempio n. 1
0
        private void DecomposeMethodCall(MethodCallNode methodCallNode, bool isYielding, bool mayPanic)
        {
            NIType outputType;
            // TODO: try to use something like Unit or Void
            NIType emptyOutputType = NITypes.Boolean;

            switch (methodCallNode.OutputTerminals.Count)
            {
            case 0:
                outputType = emptyOutputType;
                break;

            case 1:
                outputType = methodCallNode.OutputTerminals[0].GetTrueVariable().Type;
                break;

            default:
                outputType = methodCallNode.OutputTerminals.Select(t => t.GetTrueVariable().Type).DefineTupleType();
                break;
            }

            AutoBorrowNodeFacade methodCallNodeFacade = AutoBorrowNodeFacade.GetNodeFacade(methodCallNode);
            AwaitNode            awaitNode            = null;

            if (isYielding)
            {
                CreateMethodCallPromise createMethodCallPromise       = new CreateMethodCallPromise(methodCallNode.ParentDiagram, methodCallNode.Signature, methodCallNode.TargetName);
                AutoBorrowNodeFacade    createMethodCallPromiseFacade = AutoBorrowNodeFacade.GetNodeFacade(createMethodCallPromise);
                foreach (var terminalPair in methodCallNode.InputTerminals.Zip(createMethodCallPromise.InputTerminals))
                {
                    Terminal methodCallTerminal = terminalPair.Key, createMethodCallPromiseTerminal = terminalPair.Value;
                    methodCallTerminal.ConnectedTerminal.ConnectTo(createMethodCallPromiseTerminal);
                    createMethodCallPromiseFacade[createMethodCallPromiseTerminal] = methodCallNodeFacade[methodCallTerminal];
                }

                Terminal methodCallOutputTerminal = methodCallNode.OutputTerminals.FirstOrDefault();
                NIType   awaitOutputType          = mayPanic ? outputType.CreatePanicResult() : outputType;
                NIType   promiseType     = awaitOutputType.CreateMethodCallPromise();
                Terminal promiseTerminal = createMethodCallPromise.OutputTerminals[0];
                createMethodCallPromiseFacade[promiseTerminal] = new SimpleTerminalFacade(
                    promiseTerminal,
                    createMethodCallPromise.GetTypeVariableSet().CreateTypeVariableReferenceFromNIType(promiseType));

                awaitNode = ConnectNewNodeToOutputTerminalWithOutputFacade(createMethodCallPromise, diagram => new AwaitNode(diagram), awaitOutputType);
                VariableSet           variableSet            = awaitNode.GetVariableSet();
                TypeVariableReference outputTypeVariable     = awaitNode.OutputTerminal.GetTrueVariable().TypeVariableReference;
                TypeVariableReference pollResultTypeVariable = variableSet.TypeVariableSet.CreateReferenceToOptionType(outputTypeVariable);
                awaitNode.PollResultVariable = variableSet.CreateNewVariable(
                    diagramId: 0,
                    variableType: pollResultTypeVariable,
                    mutable: false);
            }

            Node outputNode = awaitNode;

            if (mayPanic)
            {
                Node panicOrContinueInput = awaitNode;
                if (!isYielding)
                {
                    // Create PanickingMethodCall as input to PanicOrContinue
                    throw new NotImplementedException("Calling non-yielding panicking methods not supported yet.");
                }
                outputNode = ConnectNewNodeToOutputTerminalWithOutputFacade(
                    panicOrContinueInput,
                    diagram => new PanicOrContinueNode(diagram),
                    outputType);
            }

            Terminal outputNodeTerminal = outputNode.OutputTerminals[0];

            switch (methodCallNode.OutputTerminals.Count)
            {
            case 0:
                // no method call output terminals; drop the result of the await
                InsertDropTransform.InsertDropForVariable(outputNode.ParentDiagram, LiveVariable.FromTerminal(outputNodeTerminal), _unificationResultFactory);
                break;

            case 1:
                ConnectOutputTerminal(methodCallNode.OutputTerminals[0], outputNodeTerminal);
                break;

            default:
            {
                // for >1 method call output terminals, decompose the tuple result of the await and match each
                // decomposed terminal to a method call terminal
                DecomposeTupleNode decomposeTupleNode = InsertDropTransform.InsertDecompositionForTupleVariable(
                    methodCallNode.ParentDiagram,
                    LiveVariable.FromTerminal(outputNodeTerminal),
                    _unificationResultFactory);
                foreach (var pair in methodCallNode.OutputTerminals.Zip(decomposeTupleNode.OutputTerminals))
                {
                    Terminal methodCallTerminal = pair.Key, decomposeTupleTerminal = pair.Value;
                    ConnectOutputTerminal(methodCallTerminal, decomposeTupleTerminal);
                }
                break;
            }
            }

            methodCallNode.RemoveFromGraph();
        }
Esempio n. 2
0
        private void ConnectOutputTerminal(Terminal outputTerminal, Terminal newOutputTerminal)
        {
            AutoBorrowNodeFacade nodeToReplaceFacade   = AutoBorrowNodeFacade.GetNodeFacade(outputTerminal.ParentNode);
            AutoBorrowNodeFacade newTerminalNodeFacade = AutoBorrowNodeFacade.GetNodeFacade(newOutputTerminal.ParentNode);

            if (outputTerminal.IsConnected)
            {
                outputTerminal.ConnectedTerminal.ConnectTo(newOutputTerminal);
                newTerminalNodeFacade[newOutputTerminal] = nodeToReplaceFacade[outputTerminal];
            }
            else
            {
                InsertDropTransform.InsertDropForVariable(newOutputTerminal.ParentDiagram, LiveVariable.FromTerminal(newOutputTerminal), _unificationResultFactory);
            }
        }