Inheritance: Parsed.Object
Ejemplo n.º 1
0
        public Choice(ContentList startContent, ContentList choiceOnlyContent, ContentList innerContent, Divert divert)
        {
            this.startContent      = startContent;
            this.choiceOnlyContent = choiceOnlyContent;
            this.innerContent      = innerContent;
            this.indentationDepth  = 1;

            if (startContent)
            {
                AddContent(this.startContent);
            }

            if (choiceOnlyContent)
            {
                AddContent(this.choiceOnlyContent);
            }

            if (innerContent)
            {
                AddContent(this.innerContent);
            }

            this.onceOnly = true; // default

            if (divert)
            {
                terminatingDivert = divert;
                AddContent(terminatingDivert);
            }
        }
Ejemplo n.º 2
0
        void ValidateTerminatingDivert(Divert terminatingDivert)
        {
            if (terminatingDivert.isFunctionCall)
            {
                WarningInTermination(terminatingDivert);
                return;
            }

            if (terminatingDivert.isTunnel)
            {
                WarningInTermination(terminatingDivert, "When final tunnel to '" + terminatingDivert.target + " ->' returns it won't have anywhere to go.");
            }
        }
Ejemplo n.º 3
0
        public Choice(ContentList startContent, ContentList choiceOnlyContent, ContentList innerContent, Divert divert)
        {
            this.startContent = startContent;
            this.choiceOnlyContent = choiceOnlyContent;
            this.innerContent = innerContent;
            this.indentationDepth = 1;

            if (startContent)
                AddContent (this.startContent);

            if (choiceOnlyContent)
                AddContent (this.choiceOnlyContent);

            if( innerContent )
                AddContent (this.innerContent);

            this.onceOnly = true; // default

            if (divert) {
                terminatingDivert = divert;
                AddContent (terminatingDivert);
            }
        }
Ejemplo n.º 4
0
        protected List<Parsed.Object> MultiDivert()
        {
            Whitespace ();

            List<Parsed.Object> diverts = null;

            // Try single thread first
            var threadDivert = Parse(StartThread);
            if (threadDivert) {
                diverts = new List<Object> ();
                diverts.Add (threadDivert);
                return diverts;
            }

            // Normal diverts and tunnels
            var arrowsAndDiverts = Interleave<object> (
                ParseDivertArrowOrTunnelOnwards,
                DivertIdentifierWithArguments);
            
            if (arrowsAndDiverts == null)
                return null;

            diverts = new List<Parsed.Object> ();

            // Possible patterns:
            //  ->                   -- explicit gather
            //  ->->                 -- tunnel onwards
            //  -> div               -- normal divert
            //  ->-> div             -- tunnel onwards, followed by override divert
            //  -> div ->            -- normal tunnel
            //  -> div ->->          -- tunnel then tunnel continue
            //  -> div -> div        -- tunnel then divert
            //  -> div -> div ->     -- tunnel then tunnel
            //  -> div -> div ->->   (etc)

            bool hasInitialTunnelOnwards = false;
            bool hasFinalTunnelOnwards = false;

            // Look at the arrows and diverts
            for (int i = 0; i < arrowsAndDiverts.Count; ++i) {
                bool isArrow = (i % 2) == 0;

                // Arrow string
                if (isArrow) {
                    string arrow = arrowsAndDiverts [i] as string;
                    if (arrow == "->->") {
                        if (i == 0) {
                            hasInitialTunnelOnwards = true;
                        } else if (i == arrowsAndDiverts.Count - 1) {
                            hasFinalTunnelOnwards = true;
                        } else {
                            Error ("Tunnel onwards '->->' must only come at the begining or the start of a divert");
                        }
                    }
                }

                // Divert
                else {

                    var divert = arrowsAndDiverts [i] as Divert;

                    // More to come? (further arrows) Must be tunnelling.
                    if (i < arrowsAndDiverts.Count - 1) {
                        divert.isTunnel = true;
                    }

                    diverts.Add (divert);
                }
            }

            // ->-> (with optional override divert)
            if (hasInitialTunnelOnwards) {
                if (arrowsAndDiverts.Count > 2) {
                    Error ("Tunnel onwards '->->' must either be on its own or followed by a single target");
                }

                var tunnelOnwards = new TunnelOnwards ();

                // Optional override target to divert to after tunnel onwards?
                // Replace divert with the tunnel onwards to that target.
                if (arrowsAndDiverts.Count > 1) {
                    var overrideDivert = diverts [0] as Parsed.Divert;
                    tunnelOnwards.overrideReturnPath = overrideDivert.target;
                    diverts.RemoveAt (0);
                }

                diverts.Add (tunnelOnwards);
            }

            // Single ->
            else if (diverts.Count == 0 && arrowsAndDiverts.Count == 1) {
                var gatherDivert = new Divert ((Parsed.Object)null);
                gatherDivert.isToGather = true;
                diverts.Add (gatherDivert);
            }

            // Divert that terminates in ->->
            else if (hasFinalTunnelOnwards) {
                diverts.Add (new TunnelOnwards ());
            }

            return diverts;
        }
Ejemplo n.º 5
0
        void ValidateTerminatingDivert(Divert terminatingDivert)
        {
            if (terminatingDivert.isFunctionCall) {
                WarningInTermination (terminatingDivert);
                return;
            }

            if (terminatingDivert.isTunnel) {
                WarningInTermination (terminatingDivert, "When final tunnel to '"+terminatingDivert.target+" ->' returns it won't have anywhere to go.");
            }
        }
Ejemplo n.º 6
0
        protected List<Parsed.Object> MultiDivert()
        {
            Whitespace ();

            List<Parsed.Object> diverts = null;

            // Try single thread first
            var threadDivert = Parse(StartThread);
            if (threadDivert) {
                diverts = new List<Object> ();
                diverts.Add (threadDivert);
                return diverts;
            }

            // Normal diverts and tunnels
            var arrowsAndDiverts = Interleave<object> (
                ParseDivertArrowOrTunnelOnwards,
                DivertIdentifierWithArguments);

            if (arrowsAndDiverts == null)
                return null;

            diverts = new List<Parsed.Object> ();

            // Divert arrow only:
            // ->
            // ->->
            // (with no target)
            if (arrowsAndDiverts.Count == 1) {

                // Single:
                // ->
                // Assume if there are no target components, it must be a divert to a gather point
                if ( (string) arrowsAndDiverts [0] == "->") {
                    var gatherDivert = new Divert ((Parsed.Object)null);
                    gatherDivert.isToGather = true;
                    diverts.Add (gatherDivert);
                }

                // Double: (tunnel onwards)
                // ->->
                else {
                    diverts.Add (new TunnelOnwards());
                }

            }

            // Possible patterns:
            //  -> div               -- normal divert
            //  -> div ->            -- normal tunnel
            //  -> div ->->          -- tunnel then tunnel continue
            //  -> div -> div        -- tunnel then divert
            //  -> div -> div ->     -- tunnel then tunnel
            //  -> div -> div ->->   (etc)
            else {

                bool hasFinalTunnelOnwards = false;

                // Look at the arrows and diverts
                for (int i = 0; i < arrowsAndDiverts.Count; ++i) {
                    bool isArrow = (i % 2) == 0;

                    // Arrow string
                    if (isArrow) {
                        string arrow = arrowsAndDiverts [i] as string;
                        if (arrow == "->->") {
                            if (i == arrowsAndDiverts.Count - 1) {
                                hasFinalTunnelOnwards = true;
                            } else {
                                Error ("Unexpected content after a '->->' tunnel onwards");
                            }
                        }
                    }

                    // Divert
                    else {

                        var divert = arrowsAndDiverts [i] as Divert;

                        // More to come? (further arrows) Must be tunnelling.
                        if (i < arrowsAndDiverts.Count - 1) {
                            divert.isTunnel = true;
                        }

                        diverts.Add (divert);
                    }
                }

                if (hasFinalTunnelOnwards)
                    diverts.Add(new TunnelOnwards());
            }

            return diverts;
        }
Ejemplo n.º 7
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;

            // Count visits on all knots and stitches
            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 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++;
            }

            // Tie up final loose ends to the very end
            if (_rootWeave && _rootWeave.looseEnds != null && _rootWeave.looseEnds.Count > 0)
            {
                foreach (var looseEnd in _rootWeave.looseEnds)
                {
                    Divert looseEndDivert = looseEnd as Divert;

                    if (looseEndDivert == null)
                    {
                        continue;
                    }

                    if (_finalLooseEnds == null)
                    {
                        _finalLooseEnds      = new List <Ink.Runtime.Divert> ();
                        _finalLooseEndTarget = Runtime.ControlCommand.NoOp();
                        container.AddContent(_finalLooseEndTarget);
                    }

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

            return(container);
        }