예제 #1
0
        public void ChoiceTest()
        {
            Combinator.Choice <Char, Char>(Enumerable.Empty <Parser <Char, Char> >())
            .Run("inputString".AsStream())
            .Case(
                failure: (restStream, _) => { /* OK */ },
                success: (restStream, _) => Assert.Fail());

            Combinator.Choice <Char, Char>(new[] {
                Parser.Fail <Char, Char>("Failure"),
                Parser.Fail <Char, Char>("Failure")
            })
            .Run("inputString".AsStream())
            .Case(
                failure: (restStream, _) => { /* OK */ },
                success: (restStream, _) => Assert.Fail());

            Combinator.Choice <Char, Char>(new[] {
                Chars.Satisfy('i'),
                Parser.Fail <Char, Char>("Failure")
            })
            .Run("inputString".AsStream())
            .Case(
                failure: (restStream, _) => Assert.Fail(),
                success: (restStream, value) =>
            {
                Assert.AreEqual('i', value);
                Assert.True(restStream.Current.HasValue);
                Assert.AreEqual('n', restStream.Current.Value.Item0);
                Assert.AreEqual(1, restStream.Current.Value.Item1.Line);
                Assert.AreEqual(2, restStream.Current.Value.Item1.Column);
            });

            Combinator.Choice <Char, Char>(new[] {
                Parser.Fail <Char, Char>("Failure"),
                Chars.Satisfy('i')
            })
            .Run("inputString".AsStream())
            .Case(
                failure: (restStream, _) => Assert.Fail(),
                success: (restStream, value) =>
            {
                Assert.AreEqual('i', value);
                Assert.True(restStream.Current.HasValue);
                Assert.AreEqual('n', restStream.Current.Value.Item0);
                Assert.AreEqual(1, restStream.Current.Value.Item1.Line);
                Assert.AreEqual(2, restStream.Current.Value.Item1.Column);
            });

            Combinator.Choice <Char, Char>(new[] {
                Parser.Return <Char, Char>('a'),
                Parser.Return <Char, Char>('b'),
            })
            .Run("inputString".AsStream())
            .Case(
                failure: (restStream, _) => Assert.Fail(),
                success: (restStream, value) =>
            {
                Assert.AreEqual('a', value);
            });
        }
예제 #2
0
        private static void InitializeV04Parser()
        {
            var space            = Chars.OneOf('\t', ' ').Ignore();
            var spaces           = space.Many0().Ignore();
            var spacesOrNewlines = Chars.OneOf('\t', ' ', '\r', '\n').Many0().Ignore();
            var newline          = Combinator.Choice(
                Chars.Sequence("\r\n"),
                Chars.Sequence("\r"),
                Chars.Sequence("\n")
                ).Ignore();
            var newlineOrEof   = newline.Or(Chars.EndOfInput()).Ignore();
            var notNewlineChar = Chars.NoneOf('\r', '\n');

            var comment = notNewlineChar.Many0()
                          .Between(Chars.Satisfy('#').Ignore(), newlineOrEof)
                          .Select(c => new Comment(c));
            var newlineOrComment = newlineOrEof.Select(_ => (Comment)null).Or(comment);

            var escaped = Chars.Satisfy('\\').Bindr(Combinator.Choice(
                                                        Chars.Satisfy('b').Select(_ => "\b"),
                                                        Chars.Satisfy('t').Select(_ => "\t"),
                                                        Chars.Satisfy('n').Select(_ => "\n"),
                                                        Chars.Satisfy('f').Select(_ => "\f"),
                                                        Chars.Satisfy('r').Select(_ => "\r"),
                                                        Chars.Sequence("\""),
                                                        //Chars.Sequence("/"),
                                                        Chars.Sequence("\\"),
                                                        Chars.Satisfy('u').Bindr(Chars.Hex().Repeat(4))
                                                        .Or(Chars.Satisfy('U').Bindr(Chars.Hex().Repeat(8)))
                                                        .Select(c => char.ConvertFromUtf32(Convert.ToInt32(string.Concat(c), 16)))
                                                        ));

            var newlineEscape = Combinator.Choice(Chars.Sequence("\\\r\n"), Chars.Sequence("\\\r"), Chars.Sequence("\\\n"))
                                .Bindr(spacesOrNewlines).Select(_ => "");

            var basicString = Chars.NoneOf('\r', '\n', '"', '\\').Select(c => c.ToString())
                              .Or(escaped).Many0().Between(Chars.Satisfy('"').Ignore(), Chars.Satisfy('"').Ignore())
                              .Select(c => new TomlValue(TomlItemType.BasicString, c.Unfold()));

            var threeQuotes = Chars.Sequence("\"\"\"").Ignore();
            var multilineBasicStringChar = Combinator.Choice(
                Chars.NoneOf('\\', '"').Select(c => c.ToString()),
                escaped, newlineEscape
                );
            var multilineBasicString = Combinator.Choice(
                multilineBasicStringChar,
                Combinator.Sequence(Chars.Sequence('"'), multilineBasicStringChar).Select(Unfold),
                Combinator.Sequence(Chars.Sequence("\"\""), multilineBasicStringChar).Select(Unfold)
                ).Many0().Between(threeQuotes, threeQuotes)
                                       .Select(c => new TomlValue(TomlItemType.MultilineBasicString, c.Unfold().RemoveFirstNewLine()));

            var literalString = Chars.NoneOf('\r', '\n', '\'').Many0()
                                .Between(Chars.Satisfy('\'').Ignore(), Chars.Satisfy('\'').Ignore())
                                .Select(c => new TomlValue(TomlItemType.LiteralString, string.Concat(c)));

            var threeLiteralQuotes         = Chars.Sequence("'''").Ignore();
            var multilineLiteralStringChar = Chars.NoneOf('\'');
            var multilineLiteralString     = Combinator.Choice(
                multilineLiteralStringChar.Select(c => c.ToString()),
                Combinator.Sequence(Chars.Satisfy('\''), multilineLiteralStringChar),
                Chars.Sequence("''").Bindr(multilineLiteralStringChar).Select(c => string.Concat("''", c))
                ).Many0().Between(threeLiteralQuotes, threeLiteralQuotes)
                                             .Select(c => new TomlValue(TomlItemType.MultilineLiteralString, c.Unfold().RemoveFirstNewLine()));

            var sign   = Chars.OneOf('+', '-').Optional().Select(o => o.Case(() => "", c => c.ToString()));
            var digit  = Chars.Satisfy(c => c >= '0' && c <= '9');
            var digits = digit.Many1();
            var digitsWithUnderscores       = digits.SepBy1(Chars.Satisfy('_').Ignore()).Select(Unfold);
            var signedDigitsWithUnderscores = sign.Append(digitsWithUnderscores);

            var integer = signedDigitsWithUnderscores.Select(x => new TomlValue(TomlItemType.Integer, string.Concat(x)));

            var floatv = Combinator.Choice(
                signedDigitsWithUnderscores.Append(Chars.Satisfy('.')).Append(digitsWithUnderscores),
                signedDigitsWithUnderscores.Append(Chars.Sequence(".").Append(digitsWithUnderscores).Optional())
                .Append(Chars.OneOf('e', 'E')).Append(signedDigitsWithUnderscores)
                ).Select(x => new TomlValue(TomlItemType.Float, string.Concat(x)));

            var boolv = Chars.Sequence("true").Select(_ => true)
                        .Or(Chars.Sequence("false").Select(_ => false))
                        .Select(b => new TomlValue(TomlItemType.Boolean, b));

            var hyphen    = Chars.Satisfy('-');
            var colon     = Chars.Satisfy(':');
            var twoDigits = digit.Repeat(2);
            var datetime  = digit.Repeat(4)                   // year
                            .Append(hyphen).Append(twoDigits) // month
                            .Append(hyphen).Append(twoDigits) // day
                            .Append(
                Chars.Sequence("T").Append(twoDigits)         // hour
                .Append(colon).Append(twoDigits)              // minute
                .Append(colon).Append(twoDigits)              // second
                .Append(
                    Chars.Sequence(".").Append(digits).Optional()
                    )
                .Append(
                    Chars.Sequence("Z")
                    .Or(
                        Chars.Sequence("+").Or(Chars.Sequence("-"))
                        .Append(twoDigits)
                        .Append(Chars.Satisfy(':'))
                        .Append(twoDigits)
                        )
                    .Optional()
                    )
                .Optional()
                )
                            .Select(x => new TomlValue(TomlItemType.Datetime, XmlConvert.ToDateTimeOffset(string.Concat(x))));

            Parser <char, TomlValue> arrayRef = null;
            var array = Delayed.Return(() => arrayRef);
            Parser <char, TomlValue> inlineTableRef = null;
            var inlineTable = Delayed.Return(() => inlineTableRef);

            var key = Chars.Satisfy(c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-')
                      .Many1().Or(basicString.Select(x => (string)x.Value));
            var value = Combinator.Choice(
                multilineBasicString, basicString, multilineLiteralString, literalString, // 順番大事
                datetime, floatv, integer, boolv, Combinator.Lazy(array), Combinator.Lazy(inlineTable)
                );

            inlineTableRef = key.Between(spaces, spaces)
                             .Pipe(
                Chars.Satisfy('=').Bindr(value.Between(spaces, spaces)),
                (k, v) => new KeyValue(k, v, null)
                )
                             .SepEndBy0(Chars.Satisfy(',').Ignore())
                             .Between(Chars.Satisfy('{').Ignore(), spaces.SeqIgnore(Chars.Satisfy('}')))
                             .Select(x => new TomlValue(TomlItemType.InlineTable, x));

            var comments = comment.Between(spacesOrNewlines, spacesOrNewlines).Many0();
            var comma    = Chars.Satisfy(',').Between(spacesOrNewlines, spacesOrNewlines).Ignore();
            Func <Parser <char, TomlValue>, Parser <char, TomlValue> > createArrayParser = p =>
                                                                                           Chars.Satisfy('[').Bindr(
                from i in
                (from b in comments
                 from v in p.Between(spacesOrNewlines, spacesOrNewlines)
                 from a in comments
                 select new ArrayItem(v, b, a)
                ).SepEndBy0(comma)
                from c in comments.Bindl(Chars.Satisfy(']'))
                select new TomlValue(TomlItemType.Array, i.Concat(new[] { new ArrayItem(null, null, c) }))
                );

            arrayRef = Combinator.Choice(
                createArrayParser(Combinator.Choice(
                                      multilineBasicString, basicString, multilineLiteralString, literalString)), // 順番大事
                createArrayParser(datetime),
                createArrayParser(floatv),
                createArrayParser(integer),
                createArrayParser(boolv),
                createArrayParser(Combinator.Lazy(array)),
                createArrayParser(Combinator.Lazy(inlineTable))
                );

            var tableName = key.Between(spaces, spaces).SepBy1(Chars.Satisfy('.').Ignore());

            var startTable = tableName.Between(
                spacesOrNewlines.SeqIgnore(Chars.Satisfy('[')),
                Chars.Satisfy(']').SeqIgnore(spaces)
                );
            var startTableLine = from t in startTable
                                 from c in newlineOrComment
                                 select new TableInfo(t, c, false);

            var startArrayOfTable = tableName.Between(
                spacesOrNewlines.SeqIgnore(Chars.Sequence("[[")),
                Chars.Sequence("]]").SeqIgnore(spaces)
                );
            var startArrayOfTableLine = from t in startArrayOfTable
                                        from c in newlineOrComment
                                        select new TableInfo(t, c, true);

            var keyValue = from k in key.Between(spacesOrNewlines, spaces)
                           from v in Chars.Satisfy('=').Bindr(value.Between(spaces, spaces))
                           from c in newlineOrComment
                           select(TableNode) new KeyValue(k, v, c);

            var nodes = Combinator.Choice(keyValue, spacesOrNewlines.Bindr(comment)).Many0();
            var table = from t in Combinator.Choice(startTableLine, startArrayOfTableLine)
                        from c in nodes
                        select new Table(t, c);

            v04Parser = from r in nodes
                        from t in table.Many0().Bindl(spacesOrNewlines)
                        select new ParseResult(r, t);
        }
예제 #3
0
파일: Prims.cs 프로젝트: Zaid-Ajaj/parseq
 public static Parser <TToken, TToken> OneOf <TToken>(IEnumerable <TToken> candidates)
     where TToken : IEquatable <TToken>
 {
     return(Combinator.Choice(candidates.Select(Prims.Satisfy <TToken>)));
 }
예제 #4
0
파일: Chars.cs 프로젝트: Zaid-Ajaj/parseq
 public static Parser <Char, Char> OneOf(IEnumerable <Char> candidates)
 {
     return(Combinator.Choice(candidates.Select(Chars.Char)));
 }
예제 #5
0
 private static Parser <TToken, Unit> DiscardBefore <TToken, T>(Parser <TToken, T> p) =>
 Combinator.Choice(p.Lookahead().Ignore(),
                   from junk in Prims.Any <TToken>().Ignore()
                   from pAhead in DiscardBefore(p)
                   select junk);
예제 #6
0
        internal StandardGrammar()
        {
            this._isReadOnly = false;
            var newline = Combinator.Choice(
                Chars.Sequence("\r\n"),
                Chars.OneOf('\r', '\n', '\x85', '\u2028', '\u2029')
                .Select(EnumerableEx.Return)
                ).Select(_ => Environment.NewLine);

            var punctuation = Chars.OneOf('"', '\'', '(', ')', ',', '.', ':', ';', '[', ']', '`', '{', '}');

            Parser <Char, YacqExpression> expressionRef = null;
            var expression = new Lazy <Parser <Char, YacqExpression> >(
                () => stream => expressionRef(stream)
                );

            this.Add("yacq", "expression", g => expression.Value);

            // Comments
            {
                this.Add("comment", "eol", g => Prims.Pipe(
                             ';'.Satisfy(),
                             newline.Not().Right(Chars.Any()).Many(),
                             newline.Ignore().Or(Chars.Eof()),
                             (p, r, s) => (YacqExpression)YacqExpression.Ignore()
                             ));

                Parser <Char, YacqExpression> blockCommentRef     = null;
                Parser <Char, YacqExpression> blockCommentRestRef = null;
                var blockComment = new Lazy <Parser <Char, YacqExpression> >(
                    () => stream => blockCommentRef(stream)
                    );
                var blockCommentRest = new Lazy <Parser <Char, YacqExpression> >(
                    () => stream => blockCommentRestRef(stream)
                    );
                var blockCommentPrefix = Chars.Sequence("#|");
                var blockCommentSuffix = Chars.Sequence("|#");
                blockCommentRef = blockCommentPrefix
                                  .Right(blockCommentRest.Value.Many())
                                  .Left(blockCommentSuffix)
                                  .Select(_ => (YacqExpression)YacqExpression.Ignore());
                blockCommentRestRef = blockCommentPrefix.Not()
                                      .Right(blockCommentSuffix.Not())
                                      .Right(Chars.Any())
                                      .Select(_ => (YacqExpression)YacqExpression.Ignore())
                                      .Or(blockComment.Value);
                this.Add("comment", "block", g => blockComment.Value);

                this.Add("comment", "expression", g => Prims.Pipe(
                             Chars.Sequence("#;"),
                             g["yacq", "expression"],
                             (p, r) => (YacqExpression)YacqExpression.Ignore()
                             ));

                this.Add("yacq", "comment", g => Combinator.Choice(g["comment"]));
            }

            this.Add("yacq", "ignore", g => Combinator.Choice(
                         this.Get["yacq", "comment"].Ignore(),
                         Chars.Space().Ignore(),
                         newline.Ignore()
                         ).Many().Select(_ => (YacqExpression)YacqExpression.Ignore()));

            // Texts
            this.Add("term", "text", g => SetPosition(
                         Chars.OneOf('\'', '\"', '`')
                         .SelectMany(q => q.Satisfy()
                                     .Not()
                                     .Right('\\'.Satisfy()
                                            .Right(q.Satisfy())
                                            .Or(Chars.Any())
                                            )
                                     .Many()
                                     .Left(q.Satisfy())
                                     .Select(cs => cs.StartWith(q).EndWith(q))
                                     )
                         .Select(cs => (YacqExpression)YacqExpression.Text(new String(cs.ToArray())))
                         ));

            // Numbers
            {
                var numberPrefix = Chars.OneOf('+', '-');
                var numberSuffix = Combinator.Choice(
                    Chars.Sequence("ul"),
                    Chars.Sequence("UL"),
                    Chars.OneOf('D', 'F', 'L', 'M', 'U', 'd', 'f', 'l', 'm', 'u')
                    .Select(EnumerableEx.Return)
                    );
                var digit     = '_'.Satisfy().Many().Right(Chars.Digit());
                var hexPrefix = Chars.Sequence("0x");
                var hex       = '_'.Satisfy().Many().Right(Chars.Hex());
                var octPrefix = Chars.Sequence("0o");
                var oct       = '_'.Satisfy().Many().Right(Chars.Oct());
                var binPrefix = Chars.Sequence("0b");
                var bin       = '_'.Satisfy().Many().Right(Chars.OneOf('0', '1'));
                var fraction  = Prims.Pipe(
                    '.'.Satisfy(),
                    digit.Many(1),
                    (d, ds) => ds.StartWith(d)
                    );
                var exponent = Prims.Pipe(
                    Chars.OneOf('E', 'e'),
                    Chars.OneOf('+', '-').Maybe(),
                    digit.Many(1),
                    (e, s, ds) => ds
                    .If(_ => s.Exists(), _ => _.StartWith(s.Perform()))
                    .StartWith(e)
                    );

                this.Add("term", "number", g => Combinator.Choice(
                             SetPosition(Prims.Pipe(
                                             binPrefix,
                                             bin.Many(1),
                                             numberSuffix.Maybe(),
                                             (p, n, s) => (YacqExpression)YacqExpression.Number(
                                                 new String(p.Concat(n).If(
                                                                _ => s.Exists(),
                                                                cs => cs.Concat(s.Perform())
                                                                ).ToArray())
                                                 )
                                             )),
                             SetPosition(Prims.Pipe(
                                             octPrefix,
                                             oct.Many(1),
                                             numberSuffix.Maybe(),
                                             (p, n, s) => (YacqExpression)YacqExpression.Number(
                                                 new String(p.Concat(n).If(
                                                                _ => s.Exists(),
                                                                cs => cs.Concat(s.Perform())
                                                                ).ToArray())
                                                 )
                                             )),
                             SetPosition(Prims.Pipe(
                                             hexPrefix,
                                             hex.Many(1),
                                             numberSuffix.Maybe(),
                                             (p, n, s) => (YacqExpression)YacqExpression.Number(
                                                 new String(p.Concat(n).If(
                                                                _ => s.Exists(),
                                                                cs => cs.Concat(s.Perform())
                                                                ).ToArray())
                                                 )
                                             )),
                             SetPosition(
                                 numberPrefix.Maybe().SelectMany(p =>
                                                                 digit.Many(1).SelectMany(i =>
                                                                                          fraction.Maybe().SelectMany(f =>
                                                                                                                      exponent.Maybe().SelectMany(e =>
                                                                                                                                                  numberSuffix.Maybe().Select(s =>
                                                                                                                                                                              (YacqExpression)YacqExpression.Number(new String(EnumerableEx.Concat(
                                                                                                                                                                                                                                   i.If(_ => p.Exists(), _ => _.StartWith(p.Perform())),
                                                                                                                                                                                                                                   f.Otherwise(Enumerable.Empty <Char>),
                                                                                                                                                                                                                                   e.Otherwise(Enumerable.Empty <Char>),
                                                                                                                                                                                                                                   s.Otherwise(Enumerable.Empty <Char>)
                                                                                                                                                                                                                                   ).ToArray()))
                                                                                                                                                                              )
                                                                                                                                                  )
                                                                                                                      )
                                                                                          )
                                                                 )
                                 )
                             ));
            }

            // Lists
            this.Add("term", "list", g => SetPosition(
                         g["yacq", "expression"]
                         .Between(g["yacq", "ignore"], g["yacq", "ignore"])
                         .Many()
                         .Between('('.Satisfy(), ')'.Satisfy())
                         .Select(es => (YacqExpression)YacqExpression.List(es))
                         ));

            // Vectors
            this.Add("term", "vector", g => SetPosition(
                         g["yacq", "expression"]
                         .Between(g["yacq", "ignore"], g["yacq", "ignore"])
                         .Many()
                         .Between('['.Satisfy(), ']'.Satisfy())
                         .Select(es => (YacqExpression)YacqExpression.Vector(es))
                         ));

            // Lambda Lists
            this.Add("term", "lambdaList", g => SetPosition(
                         g["yacq", "expression"]
                         .Between(g["yacq", "ignore"], g["yacq", "ignore"])
                         .Many()
                         .Between('{'.Satisfy(), '}'.Satisfy())
                         .Select(es => (YacqExpression)YacqExpression.LambdaList(es))
                         ));

            // Quotes
            this.Add("term", "quote", g => SetPosition(
                         Prims.Pipe(
                             Chars.Sequence("#'"),
                             g["yacq", "expression"],
                             (p, e) => (YacqExpression)YacqExpression.List(YacqExpression.Identifier("quote"), e)
                             )
                         ));

            // Quasiquotes
            this.Add("term", "quasiquote", g => SetPosition(
                         Prims.Pipe(
                             Chars.Sequence("#`"),
                             g["yacq", "expression"],
                             (p, e) => (YacqExpression)YacqExpression.List(YacqExpression.Identifier("quasiquote"), e)
                             )
                         ));

            // Unquote-Splicings
            this.Add("term", "unquoteSplicing", g => SetPosition(
                         Prims.Pipe(
                             Chars.Sequence("#,@"),
                             g["yacq", "expression"],
                             (p, e) => (YacqExpression)YacqExpression.List(YacqExpression.Identifier("unquote-splicing"), e)
                             )
                         ));

            // Unquotes
            this.Add("term", "unquote", g => SetPosition(
                         Prims.Pipe(
                             Chars.Sequence("#,"),
                             g["yacq", "expression"],
                             (p, e) => (YacqExpression)YacqExpression.List(YacqExpression.Identifier("unquote"), e)
                             )
                         ));

            // Identifiers
            this.Add("term", "identifier", g => Combinator.Choice(
                         SetPosition('.'.Satisfy()
                                     .Many(1)
                                     .Select(cs => (YacqExpression)YacqExpression.Identifier(new String(cs.ToArray())))
                                     ),
                         SetPosition(':'.Satisfy()
                                     .Many(1)
                                     .Select(cs => (YacqExpression)YacqExpression.Identifier(new String(cs.ToArray())))
                                     ),
                         SetPosition(Chars.Digit()
                                     .Not()
                                     .Right(Chars.Space()
                                            .Or(punctuation)
                                            .Not()
                                            .Right(Chars.Any())
                                            .Many(1)
                                            )
                                     .Select(cs => (YacqExpression)YacqExpression.Identifier(new String(cs.ToArray())))
                                     )
                         ));

            // Terms
            this.Add("yacq", "term", g => Combinator.Choice(g["term"])
                     .Between(g["yacq", "ignore"], g["yacq", "ignore"])
                     );

            // Infix Dots
            this.Add("infix", "dot", g => Prims.Pipe(
                         g["yacq", "term"],
                         '.'.Satisfy()
                         .Right(g["yacq", "term"])
                         .Many(),
                         (h, t) => t.Aggregate(h, (l, r) =>
                                               (YacqExpression)YacqExpression.List(YacqExpression.Identifier("."), l, r)
                                               )
                         ));

            // Infix Colons
            this.Add("infix", "colon", g => Prims.Pipe(
                         g["infix", "dot"],
                         ':'.Satisfy()
                         .Right(g["infix", "dot"])
                         .Many(),
                         (h, t) => t.Aggregate(h, (l, r) =>
                                               (YacqExpression)YacqExpression.List(YacqExpression.Identifier(":"), l, r)
                                               )
                         ));

            expressionRef = this.Get["infix"].Last();

            this.Set.Default = g => g["yacq", "expression"];

            this._isReadOnly = true;
        }