Beispiel #1
0
        public override Runtime.Object GenerateRuntimeObject()
        {
            // Check whether flow has a loose end:
            //  - Most flows should end in a choice or a divert (otherwise issue a warning)
            //  - Functions need a return, otherwise an implicit one is added
            ValidateTermination();

            if (isFunction)
            {
                CheckForDisallowedFunctionFlowControl();
            }

            var container = new Runtime.Container();

            container.name = name;

            if (this.story.countAllVisits)
            {
                container.visitsShouldBeCounted    = true;
                container.turnIndexShouldBeCounted = true;
            }

            GenerateArgumentVariableAssignments(container);

            // Run through content defined for this knot/stitch:
            //  - First of all, any initial content before a sub-stitch
            //    or any weave content is added to the main content container
            //  - The first inner knot/stitch is automatically entered, while
            //    the others are only accessible by an explicit divert
            //       - The exception to this rule is if the knot/stitch takes
            //         parameters, in which case it can't be auto-entered.
            //  - Any Choices and Gathers (i.e. IWeavePoint) found are
            //    processsed by GenerateFlowContent.
            int contentIdx = 0;

            while (content != null && contentIdx < content.Count)
            {
                Parsed.Object obj = content [contentIdx];

                // Inner knots and stitches
                if (obj is FlowBase)
                {
                    var childFlow = (FlowBase)obj;

                    var childFlowRuntime = childFlow.runtimeObject;

                    // First inner knot/stitch - automatically step into it
                    if (contentIdx == 0 && !childFlow.hasParameters)
                    {
                        _startingSubFlowDivert = new Runtime.Divert();
                        container.AddContent(_startingSubFlowDivert);
                        _startingSubFlowRuntime = childFlowRuntime;
                    }

                    // Check for duplicate knots/stitches with same name
                    var namedChild = (Runtime.INamedContent)childFlowRuntime;
                    Runtime.INamedContent existingChild = null;
                    if (container.namedContent.TryGetValue(namedChild.name, out existingChild))
                    {
                        var errorMsg = string.Format("{0} already contains flow named '{1}' (at {2})",
                                                     this.GetType().Name,
                                                     namedChild.name,
                                                     (existingChild as Runtime.Object).debugMetadata);

                        Error(errorMsg, childFlow);
                    }

                    container.AddToNamedContentOnly(namedChild);
                }

                // Other content (including entire Weaves that were grouped in the constructor)
                // At the time of writing, all FlowBases have a maximum of one piece of "other content"
                // and it's always the root Weave
                else
                {
                    container.AddContent(obj.runtimeObject);
                }

                contentIdx++;
            }

            // Tie up final loose ends to the very end
            if (_rootWeave && _rootWeave.looseEnds != null && _rootWeave.looseEnds.Count > 0)
            {
                foreach (var looseEnd in _rootWeave.looseEnds)
                {
                    if (looseEnd is Divert)
                    {
                        if (_finalLooseEnds == null)
                        {
                            _finalLooseEnds      = new List <Ink.Runtime.Divert> ();
                            _finalLooseEndTarget = Runtime.ControlCommand.NoOp();
                            container.AddContent(_finalLooseEndTarget);
                        }

                        _finalLooseEnds.Add((Runtime.Divert)looseEnd.runtimeObject);
                    }
                }
            }

            return(container);
        }
Beispiel #2
0
        public override Runtime.Object GenerateRuntimeObject()
        {
            Return foundReturn = null;

            if (isFunction)
            {
                CheckForDisallowedFunctionFlowControl();
            }

            // Non-functon: Make sure knots and stitches don't attempt to use Return statement
            else if (flowLevel == FlowLevel.Knot || flowLevel == FlowLevel.Stitch)
            {
                foundReturn = Find <Return> ();
                if (foundReturn != null)
                {
                    Error("Return statements can only be used in knots that are declared as functions: == function " + this.identifier + " ==", foundReturn);
                }
            }

            var container = new Runtime.Container();

            container.name = identifier?.name;

            if (this.story.countAllVisits)
            {
                container.visitsShouldBeCounted = true;
            }

            GenerateArgumentVariableAssignments(container);

            // Run through content defined for this knot/stitch:
            //  - First of all, any initial content before a sub-stitch
            //    or any weave content is added to the main content container
            //  - The first inner knot/stitch is automatically entered, while
            //    the others are only accessible by an explicit divert
            //       - The exception to this rule is if the knot/stitch takes
            //         parameters, in which case it can't be auto-entered.
            //  - Any Choices and Gathers (i.e. IWeavePoint) found are
            //    processsed by GenerateFlowContent.
            int contentIdx = 0;

            while (content != null && contentIdx < content.Count)
            {
                Parsed.Object obj = content [contentIdx];

                // Inner knots and stitches
                if (obj is FlowBase)
                {
                    var childFlow = (FlowBase)obj;

                    var childFlowRuntime = childFlow.runtimeObject;

                    // First inner stitch - automatically step into it
                    // 20/09/2016 - let's not auto step into knots
                    if (contentIdx == 0 && !childFlow.hasParameters &&
                        this.flowLevel == FlowLevel.Knot)
                    {
                        _startingSubFlowDivert = new Runtime.Divert();
                        container.AddContent(_startingSubFlowDivert);
                        _startingSubFlowRuntime = childFlowRuntime;
                    }

                    // Check for duplicate knots/stitches with same name
                    var namedChild = (Runtime.INamedContent)childFlowRuntime;
                    Runtime.INamedContent existingChild = null;
                    if (container.namedContent.TryGetValue(namedChild.name, out existingChild))
                    {
                        var errorMsg = string.Format("{0} already contains flow named '{1}' (at {2})",
                                                     this.GetType().Name,
                                                     namedChild.name,
                                                     (existingChild as Runtime.Object).debugMetadata);

                        Error(errorMsg, childFlow);
                    }

                    container.AddToNamedContentOnly(namedChild);
                }

                // Other content (including entire Weaves that were grouped in the constructor)
                // At the time of writing, all FlowBases have a maximum of one piece of "other content"
                // and it's always the root Weave
                else
                {
                    container.AddContent(obj.runtimeObject);
                }

                contentIdx++;
            }

            // CHECK FOR FINAL LOOSE ENDS!
            // Notes:
            //  - Functions don't need to terminate - they just implicitly return
            //  - If return statement was found, don't continue finding warnings for missing control flow,
            // since it's likely that a return statement has been used instead of a ->-> or something,
            // or the writer failed to mark the knot as a function.
            //  - _rootWeave may be null if it's a knot that only has stitches
            if (flowLevel != FlowLevel.Story && !this.isFunction && _rootWeave != null && foundReturn == null)
            {
                _rootWeave.ValidateTermination(WarningInTermination);
            }

            return(container);
        }