public SubroutineCatalogItem Initiate()
        {
            // Setup the subroutine element.
            Subroutine subroutine = _deltinScript.SubroutineCollection.NewSubroutine(_context.ElementName);

            // Create the rule.
            _subroutineRule = new TranslateRule(_deltinScript, subroutine, _context.RuleName, _context.VariableGlobalDefault);

            // Setup the return handler.
            _actionSet = _subroutineRule.ActionSet
                         .ContainVariableAssigner()
                         .SetThisTypeLinker(_context.TypeLinker)
                         .New(_context.Controller.Attributes.IsRecursive);

            // Create the function builder.
            var controller = _context.Controller;

            // Create the parameter handlers.
            _parameterHandler = controller.CreateParameterHandler(_actionSet, null);

            // If the subroutine is an object function inside a class, create a variable to store the class object.
            if (controller.Attributes.IsInstance)
            {
                _objectStore = _actionSet.VarCollection.Assign(_context.ObjectStackName, true, !controller.Attributes.IsRecursive);

                // Set the objectStore as an empty array if the subroutine is recursive.
                if (controller.Attributes.IsRecursive)
                {
                    // Initialize as empty array.
                    _actionSet.InitialSet().AddAction(_objectStore.SetVariable(Element.EmptyArray()));

                    // Add to assigner with the last of the objectStore stack being the object instance.
                    _context.ContainingType?.AddObjectVariablesToAssigner(_actionSet.ToWorkshop, Element.LastOf(_objectStore.GetVariable()), _actionSet.IndexAssigner);

                    // Set the actionSet.
                    _actionSet = _actionSet.New(Element.LastOf(_objectStore.Get())).PackThis().New(_objectStore.CreateChild(Element.CountOf(_objectStore.Get()) - 1));
                }
                else
                {
                    // Add to assigner with the objectStore being the object instance.
                    _context.ContainingType?.AddObjectVariablesToAssigner(_actionSet.ToWorkshop, _objectStore.GetVariable(), _actionSet.IndexAssigner);

                    // Set the actionSet.
                    _actionSet = _actionSet.New(_objectStore.Get()).PackThis().New(_objectStore);
                }
            }

            _functionBuilder = new WorkshopFunctionBuilder(_actionSet, controller);
            _functionBuilder.ModifySet(a => a.PackThis()); // TODO: is this required?
            _functionBuilder.SetupReturnHandler();
            _parameterHandler.AddParametersToAssigner(_actionSet.IndexAssigner);

            // Done.
            return(Result = new SubroutineCatalogItem(
                       subroutine: subroutine,
                       parameterHandler: _parameterHandler,
                       objectStack: _objectStore,
                       returnHandler: _functionBuilder.ReturnHandler));
        }
        public IWorkshopTree Call(ICallInfo call)
        {
            // Get the subroutine.
            _subroutine = Controller.GetSubroutine();
            if (_subroutine)
            {
                ParameterHandler = _subroutine.ParameterHandler;
                SetParameters(call);

                // Store the object the subroutine is executing with.
                if (Controller.Attributes.IsInstance)
                {
                    // Normal
                    if (!Controller.Attributes.IsRecursive)
                    {
                        ActionSet.AddAction(_subroutine.ObjectStack.SetVariable((Element)ActionSet.CurrentObject));
                    }
                    // Recursive: Stack
                    else
                    {
                        ActionSet.AddAction(_subroutine.ObjectStack.ModifyVariable(Operation.AppendToArray, Element.CreateArray(ActionSet.CurrentObject)));
                    }
                }

                call.ExecuteSubroutine(ActionSet, _subroutine.Subroutine);

                // If a return handler was provided, bridge the return value.
                if (call.ProvidedReturnHandler != null && _subroutine.ReturnHandler != null)
                {
                    call.ProvidedReturnHandler.ReturnValue(_subroutine.ReturnHandler.GetReturnedValue());
                }

                return(_subroutine.ReturnHandler?.GetReturnedValue());
            }
            else
            {
                // Inline
                // Recursive stack.
                if (Controller.Attributes.IsRecursive)
                {
                    var lastCall = GetExistingStack();

                    // Function is not yet on the stack.
                    if (lastCall == null)
                    {
                        return(BuildInline(call));
                    }
                    else // Recursive call.
                    {
                        lastCall.RecursiveCall(call, ActionSet);
                        return(ActionSet.ReturnHandler.GetReturnedValue());
                    }
                }
                else
                {
                    return(BuildInline(call));
                }
            }
        }
 public SetupSubroutine(SubroutineCatalogItem item, Action completeSetup)
 {
     Item          = item;
     CompleteSetup = completeSetup;
 }
 public SetupSubroutine(SubroutineBuilder builder)
 {
     Item          = builder.Initiate();
     CompleteSetup = builder.Complete;
 }