Пример #1
0
        public override Runtime.Object GenerateRuntimeObject()
        {
            // End = end flow immediately
            // Done = return from thread or instruct the flow that it's safe to exit
            if (isEnd)
            {
                return(Runtime.ControlCommand.End());
            }
            if (isDone)
            {
                return(Runtime.ControlCommand.Done());
            }

            runtimeDivert = new Runtime.Divert();

            // Normally we resolve the target content during the
            // Resolve phase, since we expect all runtime objects to
            // be available in order to find the final runtime path for
            // the destination. However, we need to resolve the target
            // (albeit without the runtime target) early so that
            // we can get information about the arguments - whether
            // they're by reference - since it affects the code we
            // generate here.
            ResolveTargetContent();


            CheckArgumentValidity();

            // Passing arguments to the knot
            bool requiresArgCodeGen = arguments != null && arguments.Count > 0;

            if (requiresArgCodeGen || isFunctionCall || isTunnel || isThread)
            {
                var container = new Runtime.Container();

                // Generate code for argument evaluation
                // This argument generation is coded defensively - it should
                // attempt to generate the code for all the parameters, even if
                // they don't match the expected arguments. This is so that the
                // parameter objects themselves are generated correctly and don't
                // get into a state of attempting to resolve references etc
                // without being generated.
                if (requiresArgCodeGen)
                {
                    // Function calls already in an evaluation context
                    if (!isFunctionCall)
                    {
                        container.AddContent(Runtime.ControlCommand.EvalStart());
                    }

                    List <FlowBase.Argument> targetArguments = null;
                    if (targetContent)
                    {
                        targetArguments = (targetContent as FlowBase).arguments;
                    }

                    for (var i = 0; i < arguments.Count; ++i)
                    {
                        Expression        argToPass   = arguments [i];
                        FlowBase.Argument argExpected = null;
                        if (targetArguments != null && i < targetArguments.Count)
                        {
                            argExpected = targetArguments [i];
                        }

                        // Pass by reference: argument needs to be a variable reference
                        if (argExpected != null && argExpected.isByReference)
                        {
                            var varRef = argToPass as VariableReference;
                            if (varRef == null)
                            {
                                Error("Expected variable name to pass by reference to 'ref " + argExpected.name + "' but saw " + argToPass.ToString());
                                break;
                            }

                            // Check that we're not attempting to pass a read count by reference
                            var           targetPath     = new Path(varRef.path);
                            Parsed.Object targetForCount = targetPath.ResolveFromContext(this);
                            if (targetForCount != null)
                            {
                                Error("can't pass a read count by reference. '" + targetPath.dotSeparatedComponents + "' is a knot/stitch/label, but '" + target.dotSeparatedComponents + "' requires the name of a VAR to be passed.");
                                break;
                            }

                            var varPointer = new Runtime.VariablePointerValue(varRef.name);
                            container.AddContent(varPointer);
                        }

                        // Normal value being passed: evaluate it as normal
                        else
                        {
                            argToPass.GenerateIntoContainer(container);
                        }
                    }

                    // Function calls were already in an evaluation context
                    if (!isFunctionCall)
                    {
                        container.AddContent(Runtime.ControlCommand.EvalEnd());
                    }
                }


                // Starting a thread? A bit like a push to the call stack below... but not.
                // It sort of puts the call stack on a thread stack (argh!) - forks the full flow.
                if (isThread)
                {
                    container.AddContent(Runtime.ControlCommand.StartThread());
                }

                // If this divert is a function call, tunnel, we push to the call stack
                // so we can return again
                else if (isFunctionCall || isTunnel)
                {
                    runtimeDivert.pushesToStack = true;
                    runtimeDivert.stackPushType = isFunctionCall ? Runtime.PushPopType.Function : Runtime.PushPopType.Tunnel;
                }

                // Jump into the "function" (knot/stitch)
                container.AddContent(runtimeDivert);

                return(container);
            }

            // Simple divert
            else
            {
                return(runtimeDivert);
            }
        }
Пример #2
0
		public override Runtime.Object GenerateRuntimeObject ()
		{
            // End = end flow immediately
            // Done = return from thread or instruct the flow that it's safe to exit
            if (isEnd) {
                return Runtime.ControlCommand.End ();
            }
            if (isDone) {
                return Runtime.ControlCommand.Done ();
            }

            runtimeDivert = new Runtime.Divert ();

            // Normally we resolve the target content during the
            // Resolve phase, since we expect all runtime objects to
            // be available in order to find the final runtime path for
            // the destination. However, we need to resolve the target
            // (albeit without the runtime target) early so that
            // we can get information about the arguments - whether
            // they're by reference - since it affects the code we 
            // generate here.
            ResolveTargetContent ();


            CheckArgumentValidity ();

            // Passing arguments to the knot
            bool requiresArgCodeGen = arguments != null && arguments.Count > 0;
            if ( requiresArgCodeGen || isFunctionCall || isTunnel || isThread ) {

                var container = new Runtime.Container ();

                // Generate code for argument evaluation
                // This argument generation is coded defensively - it should
                // attempt to generate the code for all the parameters, even if
                // they don't match the expected arguments. This is so that the
                // parameter objects themselves are generated correctly and don't
                // get into a state of attempting to resolve references etc
                // without being generated.
                if (requiresArgCodeGen) {

                    // Function calls already in an evaluation context
                    if (!isFunctionCall) {
                        container.AddContent (Runtime.ControlCommand.EvalStart());
                    }

                    List<FlowBase.Argument> targetArguments = null;
                    if( targetContent )
                        targetArguments = (targetContent as FlowBase).arguments;

                    for (var i = 0; i < arguments.Count; ++i) {
                        Expression argToPass = arguments [i];
                        FlowBase.Argument argExpected = null; 
                        if( targetArguments != null && i < targetArguments.Count ) 
                            argExpected = targetArguments [i];

                        // Pass by reference: argument needs to be a variable reference
                        if (argExpected != null && argExpected.isByReference) {

                            var varRef = argToPass as VariableReference;
                            if (varRef == null) {
                                Error ("Expected variable name to pass by reference to 'ref " + argExpected.name + "' but saw " + argToPass.ToString ());
                                break;
                            }

                            var varPointer = new Runtime.VariablePointerValue (varRef.name);
                            container.AddContent (varPointer);
                        } 

                        // Normal value being passed: evaluate it as normal
                        else {
                            argToPass.GenerateIntoContainer (container);
                        }
                    }

                    // Function calls were already in an evaluation context
                    if (!isFunctionCall) {
                        container.AddContent (Runtime.ControlCommand.EvalEnd());
                    }
                }
                    

                // Starting a thread? A bit like a push to the call stack below... but not.
                // It sort of puts the call stack on a thread stack (argh!) - forks the full flow.
                if (isThread) {
                    container.AddContent(Runtime.ControlCommand.StartThread());
                }

                // If this divert is a function call, tunnel, we push to the call stack
                // so we can return again
                else if (isFunctionCall || isTunnel) {
                    runtimeDivert.pushesToStack = true;
                    runtimeDivert.stackPushType = isFunctionCall ? Runtime.PushPopType.Function : Runtime.PushPopType.Tunnel;
                }

                // Jump into the "function" (knot/stitch)
                container.AddContent (runtimeDivert);

                return container;
            } 

            // Simple divert
            else {
                return runtimeDivert;
            }			
		}