コード例 #1
0
        public static ParserAction Parse(ExpressionWalker ew, string code, LineBuilder output)
        {
            //  multiline:
            //      %foreach expr%
            //        code #1
            //      %
            //  singleline:
            //      %foreach expr
            //          code #1
            ew.IsCurrentOrThrow(ExpressionToken.Foreach);
            ew.NextOrThrow();
            //parse the arguments for the foreach
            var args = ArgumentsExpression.Parse(ew, token => token.Token == ExpressionToken.NewLine || token.Token == ExpressionToken.Mod, false, typeof(ForeachExpression));

            //ew.Back(); //agrumentsExpression skips the closer token and we need it to identify if this is a singleline or multiline
            if (output == null)
            {
                output = new LineBuilder(code);
            }

            string content;
            var    relatedLines = new List <Line>();

            relatedLines.AddRange(output.GetLinesRelated(args.Matches()));
            if (ew.PeakBack.Token == ExpressionToken.Mod)
            {
                //the content is % to % block
                var leftBorder = ew.Current.Match;
                var nextMod    = ForeachExpression.FindCloser(leftBorder.Index, code);
                //handle implicit end block (when % is not existing)
                if (nextMod == -1)
                {
                    nextMod = code.Length - 1;
                }
                ew.SkipForwardWhile(token => token.Match.Index < nextMod);
                ew.Next(); //skip % itself
                var l1 = output.GetLineAt(leftBorder.Index) ?? output.Lines.First();

                relatedLines.AddRange(new Range(l1.LineNumber, output.GetLineAt(nextMod).LineNumber).EnumerateIndexes().Select(output.GetLineByLineNumber));
                content = null;
            }
            else
            {
                //the content is only next line
                var leftMod = ew.Current.Match;
                var nextMod = code.IndexOf('\n', leftMod.Index);
                relatedLines.Add(output.GetLineByLineNumber(relatedLines.Last().LineNumber + 1)); //next line.
                content = code.Substring(leftMod.Index, nextMod == -1 ? (code.Length - leftMod.Index) : nextMod - leftMod.Index);
            }

            relatedLines = relatedLines.Distinct().OrderBy(l => l.StartIndex).ToList();

            if (relatedLines.Count(l => l.Content.Contains("%foreach")) <= relatedLines.Count(l => l.CleanContent() == "%") && relatedLines.Last().CleanContent() == "%")
            {
                relatedLines[relatedLines.Count - 1].MarkedForDeletion = true;
                relatedLines.RemoveAt(relatedLines.Count - 1);
            }

            //make sure to clean out % at the end
            if (content == null)
            {
                content = relatedLines.Select(l => l.Content).StringJoin();
            }


            //all lines of the foreach are destined to deletion
            foreach (var line in relatedLines)
            {
                line.MarkedForDeletion = true;
            }

            return(new ParserAction(ParserToken.ForeachLoop, relatedLines, new ForeachExpression()
            {
                Content = content, Arguments = args
            }));
        }