Exemplo n.º 1
0
        protected List <ConditionalSingleBranch> InlineConditionalBranches()
        {
            var listOfLists = Interleave <List <Parsed.Object> > (MixedTextAndLogic, Exclude(String("|")), flatten: false);

            if (listOfLists == null || listOfLists.Count == 0)
            {
                return(null);
            }

            var result = new List <ConditionalSingleBranch> ();

            if (listOfLists.Count > 2)
            {
                Error("Expected one or two alternatives separated by '|' in inline conditional");
            }
            else
            {
                var trueBranch = new ConditionalSingleBranch(listOfLists[0]);
                trueBranch.isTrueBranch = true;
                result.Add(trueBranch);

                if (listOfLists.Count > 1)
                {
                    var elseBranch = new ConditionalSingleBranch(listOfLists[1]);
                    elseBranch.isElse = true;
                    result.Add(elseBranch);
                }
            }

            return(result);
        }
Exemplo n.º 2
0
        protected ConditionalSingleBranch SingleMultilineCondition()
        {
            Whitespace();

            // Make sure we're not accidentally parsing a divert
            if (ParseString("->") != null)
            {
                return(null);
            }

            if (ParseString("-") == null)
            {
                return(null);
            }

            Whitespace();

            Expression expr   = null;
            bool       isElse = Parse(ElseExpression) != null;

            if (!isElse)
            {
                expr = Parse(ConditionExpression);
            }

            List <Parsed.Object> content = StatementsAtLevel(StatementLevel.InnerBlock);

            if (expr == null && content == null)
            {
                Error("expected content for the conditional branch following '-'");

                // Recover
                content = new List <Ink.Parsed.Object> ();
                content.Add(new Text(""));
            }

            // Allow additional multiline whitespace, if the statements were empty (valid)
            // then their surrounding multiline whitespacce needs to be handled manually.
            // e.g.
            // { x:
            //   - 1:    // intentionally left blank, but newline needs to be parsed
            //   - 2: etc
            // }
            MultilineWhitespace();

            var branch = new ConditionalSingleBranch(content);

            branch.ownExpression = expr;
            branch.isElse        = isElse;
            return(branch);
        }
Exemplo n.º 3
0
        protected Conditional InnerConditionalContent(Expression initialQueryExpression)
        {
            List <ConditionalSingleBranch> alternatives;

            bool canBeInline = initialQueryExpression != null;
            bool isInline    = Parse(Newline) == null;

            if (isInline && !canBeInline)
            {
                return(null);
            }

            // Inline innards
            if (isInline)
            {
                alternatives = InlineConditionalBranches();
            }

            // Multiline innards
            else
            {
                alternatives = MultilineConditionalBranches();
                if (alternatives == null)
                {
                    // Allow single piece of content within multi-line expression, e.g.:
                    // { true:
                    //    Some content that isn't preceded by '-'
                    // }
                    if (initialQueryExpression)
                    {
                        List <Parsed.Object> soleContent = StatementsAtLevel(StatementLevel.InnerBlock);
                        if (soleContent != null)
                        {
                            var soleBranch = new ConditionalSingleBranch(soleContent);
                            alternatives = new List <ConditionalSingleBranch> ();
                            alternatives.Add(soleBranch);

                            // Also allow a final "- else:" clause
                            var elseBranch = Parse(SingleMultilineCondition);
                            if (elseBranch)
                            {
                                if (!elseBranch.isElse)
                                {
                                    ErrorWithParsedObject("Expected an '- else:' clause here rather than an extra condition", elseBranch);
                                    elseBranch.isElse = true;
                                }
                                alternatives.Add(elseBranch);
                            }
                        }
                    }

                    // Still null?
                    if (alternatives == null)
                    {
                        return(null);
                    }
                }

                // Empty true branch - didn't get parsed, but should insert one for semantic correctness,
                // and to make sure that any evaluation stack values get tidied up correctly.
                else if (alternatives.Count == 1 && alternatives [0].isElse && initialQueryExpression)
                {
                    var emptyTrueBranch = new ConditionalSingleBranch(null);
                    emptyTrueBranch.isTrueBranch = true;
                    alternatives.Insert(0, emptyTrueBranch);
                }

                // Like a switch statement
                // { initialQueryExpression:
                //    ... match the expression
                // }
                if (initialQueryExpression)
                {
                    bool earlierBranchesHaveOwnExpression = false;
                    for (int i = 0; i < alternatives.Count; ++i)
                    {
                        var  branch = alternatives [i];
                        bool isLast = (i == alternatives.Count - 1);

                        // Matching equality with initial query expression
                        // We set this flag even for the "else" clause so that
                        // it knows to tidy up the evaluation stack at the end

                        // Match query
                        if (branch.ownExpression)
                        {
                            branch.matchingEquality          = true;
                            earlierBranchesHaveOwnExpression = true;
                        }

                        // Else (final branch)
                        else if (earlierBranchesHaveOwnExpression && isLast)
                        {
                            branch.matchingEquality = true;
                            branch.isElse           = true;
                        }

                        // Binary condition:
                        // { trueOrFalse:
                        //    - when true
                        //    - when false
                        // }
                        else
                        {
                            if (!isLast && alternatives.Count > 2)
                            {
                                ErrorWithParsedObject("Only final branch can be an 'else'. Did you miss a ':'?", branch);
                            }
                            else
                            {
                                if (i == 0)
                                {
                                    branch.isTrueBranch = true;
                                }
                                else
                                {
                                    branch.isElse = true;
                                }
                            }
                        }
                    }
                }

                // No initial query, so just a multi-line conditional. e.g.:
                // {
                //   - x > 3:  greater than three
                //   - x == 3: equal to three
                //   - x < 3:  less than three
                // }
                else
                {
                    for (int i = 0; i < alternatives.Count; ++i)
                    {
                        var  alt    = alternatives [i];
                        bool isLast = (i == alternatives.Count - 1);
                        if (alt.ownExpression == null)
                        {
                            if (isLast)
                            {
                                alt.isElse = true;
                            }
                            else
                            {
                                if (alt.isElse)
                                {
                                    // Do we ALSO have a valid "else" at the end? Let's report the error there.
                                    var finalClause = alternatives [alternatives.Count - 1];
                                    if (finalClause.isElse)
                                    {
                                        ErrorWithParsedObject("Multiple 'else' cases. Can have a maximum of one, at the end.", finalClause);
                                    }
                                    else
                                    {
                                        ErrorWithParsedObject("'else' case in conditional should always be the final one", alt);
                                    }
                                }
                                else
                                {
                                    ErrorWithParsedObject("Branch doesn't have condition. Are you missing a ':'? ", alt);
                                }
                            }
                        }
                    }

                    if (alternatives.Count == 1 && alternatives [0].ownExpression == null)
                    {
                        ErrorWithParsedObject("Condition block with no conditions", alternatives [0]);
                    }
                }
            }

            // TODO: Come up with water-tight error conditions... it's quite a flexible system!
            // e.g.
            //   - inline conditionals must have exactly 1 or 2 alternatives
            //   - multiline expression shouldn't have mixed existence of branch-conditions?
            if (alternatives == null)
            {
                return(null);
            }

            var cond = new Conditional(initialQueryExpression, alternatives);

            return(cond);
        }