PageRenderTime 56ms CodeModel.GetById 18ms app.highlight 30ms RepoModel.GetById 0ms app.codeStats 1ms

/JsonVisualizer/Internal/IncludeMicroParser.Json.cs

#
C# | 3485 lines | 2662 code | 521 blank | 302 comment | 174 complexity | 8d37ca31b129a7bc9d59f00c4aac4129 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1
   2#define MICRO_PARSER_NET35
   3#define MICRO_PARSER_JSON_NET35
   4
   5
   6
   7// ----------------------------------------------------------------------------
   8// Included defines (C# requires #define to in the first part of a code file)
   9// ----------------------------------------------------------------------------
  10#define MICRO_PARSER_SUPPRESS_ANONYMOUS_TYPE
  11#define MICRO_PARSER_SUPPRESS_CHAR_PARSER_MANY_CHAR_SATISFY_2
  12#define MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_NEW_LINE
  13#define MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_NONE_OF
  14#define MICRO_PARSER_SUPPRESS_CHAR_SATISFY_COMPOSITES
  15#define MICRO_PARSER_SUPPRESS_EXTENSIONS_EXCEPT
  16#define MICRO_PARSER_SUPPRESS_EXTENSIONS_OR
  17#define MICRO_PARSER_SUPPRESS_PARSER_CHAIN
  18#define MICRO_PARSER_SUPPRESS_PARSER_COMBINE
  19#define MICRO_PARSER_SUPPRESS_PARSER_EXCEPT
  20#define MICRO_PARSER_SUPPRESS_PARSER_FAIL
  21#define MICRO_PARSER_SUPPRESS_PARSER_FAIL_WITH_EXPECTED
  22// ----------------------------------------------------------------------------
  23
  24// ----------------------------------------------------------------------------
  25// Included code
  26// ----------------------------------------------------------------------------
  27
  28
  29// #define MICRO_PARSER_SUPPRESS_ANONYMOUS_TYPE
  30
  31// #define MICRO_PARSER_SUPPRESS_PARSER_CHAIN
  32// #define MICRO_PARSER_SUPPRESS_PARSER_COMBINE
  33// #define MICRO_PARSER_SUPPRESS_PARSER_EXCEPT
  34// #define MICRO_PARSER_SUPPRESS_PARSER_FAIL
  35// #define MICRO_PARSER_SUPPRESS_PARSER_FAIL_WITH_EXPECTED
  36
  37// #define MICRO_PARSER_SUPPRESS_CHAR_PARSER_MANY_CHAR_SATISFY_2
  38// #define MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_NEW_LINE
  39// #define MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_NONE_OF
  40
  41// #define MICRO_PARSER_SUPPRESS_CHAR_SATISFY_COMPOSITES
  42
  43// #define MICRO_PARSER_SUPPRESS_EXTENSIONS_EXCEPT
  44// #define MICRO_PARSER_SUPPRESS_EXTENSIONS_OR
  45
  46
  47
  48
  49// ----------------------------------------------------------------------------
  50// Included code
  51// ----------------------------------------------------------------------------
  52
  53namespace Include
  54{
  55// ----------------------------------------------------------------------------------------------
  56// Copyright (c) Mårten Rånge.
  57// ----------------------------------------------------------------------------------------------
  58// This source code is subject to terms and conditions of the Microsoft Public License. A 
  59// copy of the license can be found in the License.html file at the root of this distribution. 
  60// If you cannot locate the  Microsoft Public License, please send an email to 
  61// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  62//  by the terms of the Microsoft Public License.
  63// ----------------------------------------------------------------------------------------------
  64// You must not remove this notice, or any other, from this software.
  65// ----------------------------------------------------------------------------------------------
  66namespace MicroParser
  67{
  68   using System;
  69   using System.Linq;
  70   using Internal;
  71
  72   static partial class CharParser
  73   {
  74#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_CHAR
  75      public static Parser<Empty> SkipChar (char toSkip)
  76      {
  77         return SkipString (new string (toSkip, 1));
  78      }
  79#endif
  80
  81#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_STRING
  82      public static Parser<Empty> SkipString (string toSkip)
  83      {
  84         if (toSkip.IsNullOrEmpty ())
  85         {
  86            throw new ArgumentNullException ("toSkip");
  87         }
  88
  89         CharSatisfy.Function satisfy = (c, i) => c == toSkip[i];
  90         var parserErrorMessage = new ParserErrorMessage_Expected (Strings.CharSatisfy.FormatChar_1.FormatWith (toSkip));
  91
  92         return SkipSatisfy (
  93            new CharSatisfy (parserErrorMessage, satisfy),
  94            toSkip.Length,
  95            toSkip.Length);
  96      }
  97#endif
  98
  99#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_ANY_OF
 100      public static Parser<Empty> SkipAnyOf (string skipAnyOfThese)
 101      {
 102         var sat = CharSatisfy.CreateSatisfyForAnyOf (skipAnyOfThese);
 103         return SkipSatisfy (
 104            sat,
 105            maxCount:1
 106            );
 107      }
 108#endif
 109
 110#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_NONE_OF
 111      public static Parser<Empty> SkipNoneOf (string skipNoneOfThese)
 112      {
 113         var sat = CharSatisfy.CreateSatisfyForNoneOf (skipNoneOfThese);
 114         return SkipSatisfy (
 115            sat,
 116            maxCount: 1
 117            );
 118      }
 119#endif
 120
 121#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_SATISFY
 122      public static Parser<Empty> SkipSatisfy (
 123         CharSatisfy charSatisfy,
 124         int minCount = 0,
 125         int maxCount = int.MaxValue
 126         )
 127      {
 128         Parser.VerifyMinAndMaxCount (minCount, maxCount);
 129
 130         Parser<Empty>.Function function = state =>
 131         {
 132            var advanceResult = state.SkipAdvance (charSatisfy.Satisfy, minCount, maxCount);
 133            return ParserReply.Create (advanceResult, state, charSatisfy.ErrorMessage, Empty.Value);
 134         };
 135         return function;
 136      }
 137#endif
 138
 139#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_WHITE_SPACE
 140      public static Parser<Empty> SkipWhiteSpace (
 141         int minCount = 0,
 142         int maxCount = int.MaxValue
 143         )
 144      {
 145         return SkipSatisfy (CharSatisfy.WhiteSpace, minCount, maxCount);
 146      }
 147#endif
 148
 149#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_SKIP_NEW_LINE
 150      public static Parser<Empty> SkipNewLine (
 151         )
 152      {
 153         return SkipChar ('\r').Opt ()
 154            .KeepRight (SkipChar ('\n'));
 155      }
 156#endif
 157
 158#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_ANY_OF
 159      public static Parser<SubString> AnyOf (
 160         string match,
 161         int minCount = 0,
 162         int maxCount = int.MaxValue
 163         )
 164      {
 165         var satisfy = CharSatisfy.CreateSatisfyForAnyOf (match);
 166
 167         return ManyCharSatisfy (satisfy, minCount, maxCount);
 168      }
 169#endif
 170
 171#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_NONE_OF
 172      public static Parser<SubString> NoneOf (
 173         string match,
 174         int minCount = 0,
 175         int maxCount = int.MaxValue
 176         )
 177      {
 178         var satisfy = CharSatisfy.CreateSatisfyForNoneOf (match);
 179
 180         return ManyCharSatisfy (satisfy, minCount, maxCount);
 181      }
 182#endif
 183
 184#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_MANY_CHAR_SATISFY
 185      public static Parser<SubString> ManyCharSatisfy (
 186         CharSatisfy satisfy,
 187         int minCount = 0,
 188         int maxCount = int.MaxValue
 189         )
 190      {
 191         Parser.VerifyMinAndMaxCount (minCount, maxCount);
 192
 193         Parser<SubString>.Function function = state =>
 194         {
 195            var subString = new SubString ();
 196            var advanceResult = state.Advance (ref subString, satisfy.Satisfy, minCount, maxCount);
 197
 198            return ParserReply.Create (
 199               advanceResult,
 200               state,
 201               satisfy.ErrorMessage,
 202               subString
 203               );
 204         };
 205         return function;
 206      }
 207#endif
 208
 209#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_MANY_CHAR_SATISFY_2
 210      public static Parser<SubString> ManyCharSatisfy2 (
 211         CharSatisfy satisfyFirst,
 212         CharSatisfy satisfyRest,
 213         int minCount = 0,
 214         int maxCount = int.MaxValue
 215         )
 216      {
 217         Parser.VerifyMinAndMaxCount (minCount, maxCount);
 218
 219         var first = satisfyFirst.Satisfy;
 220         var rest = satisfyRest.Satisfy;
 221
 222         CharSatisfy.Function satisfy = (c, i) => i == 0 ? first (c, i) : rest (c, i);
 223
 224         Parser<SubString>.Function function = state =>
 225         {
 226            var subString = new SubString ();
 227
 228            var advanceResult = state.Advance (ref subString, satisfy, minCount, maxCount);
 229
 230            var expected =
 231               (advanceResult == ParserState.AdvanceResult.Error_EndOfStream_PostionChanged || advanceResult == ParserState.AdvanceResult.Error_SatisfyFailed_PositionChanged)
 232               ? satisfyRest.ErrorMessage
 233               : satisfyFirst.ErrorMessage;
 234
 235            return ParserReply.Create (
 236               advanceResult,
 237               state,
 238               expected,
 239               subString
 240               );
 241         };
 242         return function;
 243      }
 244#endif
 245
 246      partial struct UIntResult
 247      {
 248         public uint Value;
 249         public int ConsumedCharacters;
 250      }
 251
 252      static Parser<UIntResult> UIntImpl (
 253         int minCount = 1,
 254         int maxCount = 10
 255         )
 256      {
 257         Parser.VerifyMinAndMaxCount (minCount, maxCount);
 258
 259         CharSatisfy.Function satisfy = (c, i) => char.IsDigit (c);
 260
 261         Parser<UIntResult>.Function function = state =>
 262         {
 263            var subString = new SubString ();
 264
 265            var oldPos = state.Position;
 266
 267            var advanceResult = state.Advance (ref subString, satisfy, minCount, maxCount);
 268
 269            var newPos = state.Position;
 270
 271            return ParserReply.Create (
 272               advanceResult,
 273               state,
 274               ParserErrorMessages.Expected_Digit,
 275               () =>
 276                  {
 277                     var accumulated = 0u;
 278                     var length = subString.Length;
 279                     const uint c0 = (uint) '0';
 280                     for (var iter = 0; iter < length; ++iter)
 281                     {
 282                        var c = subString[iter];
 283                        accumulated = accumulated*10 + (c - c0);
 284                     }
 285
 286                     return new UIntResult
 287                               {
 288                                  Value = accumulated,
 289                                  ConsumedCharacters = newPos.Position - oldPos.Position,
 290                               };
 291                  }
 292               );
 293         };
 294         return function;
 295      }
 296
 297#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_HEX
 298      static uint? CharToHex (char ch)
 299      {
 300         if ('0' <= ch && ch <= '9')
 301         {
 302            return (uint?) (ch - '0');
 303         }
 304         else if ('A' <= ch && ch <= 'F')
 305         {
 306            return (uint?) (ch - 'A' + 0xA);
 307         }
 308         else if ('a' <= ch && ch <= 'f')
 309         {
 310            return (uint?)(ch - 'a' + 0xA);            
 311         }
 312         else
 313         {
 314            return null;
 315         }
 316      }
 317
 318      [CLSCompliant (false)]
 319      public static Parser<uint> Hex (
 320         int minCount = 1,
 321         int maxCount = 10
 322         )
 323      {
 324         Parser.VerifyMinAndMaxCount (minCount, maxCount);
 325
 326         CharSatisfy.Function satisfy = (c, i) => CharToHex (c) != null;
 327
 328         Parser<uint>.Function function = state =>
 329         {
 330            var subString = new SubString ();
 331
 332            var advanceResult = state.Advance (ref subString, satisfy, minCount, maxCount);
 333
 334            return ParserReply.Create (
 335               advanceResult,
 336               state,
 337               ParserErrorMessages.Expected_HexDigit,
 338               () =>
 339               {
 340                  var accumulated = 0u;
 341                  var length = subString.Length;
 342                  for (var iter = 0; iter < length; ++iter)
 343                  {
 344                     var c = subString[iter];
 345                     accumulated = accumulated * 0x10U + CharToHex (c).Value;
 346                  }
 347
 348                  return accumulated;
 349               }
 350               );
 351         };
 352         return function;
 353      }
 354#endif
 355
 356#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_UINT
 357      [CLSCompliant (false)]
 358      public static Parser<uint> UInt (
 359         int minCount = 1,
 360         int maxCount = 10
 361         )
 362      {
 363         var uintParser = UIntImpl (minCount, maxCount);
 364
 365         Parser<uint>.Function function = state =>
 366         {
 367            var uintResult = uintParser.Execute (state);
 368
 369            if (uintResult.State.HasError ())
 370            {
 371               return uintResult.Failure<uint> ();
 372            }
 373
 374            return uintResult.Success (uintResult.Value.Value);
 375         };
 376         return function;
 377      }
 378#endif
 379
 380#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_INT
 381      public static Parser<int> Int (
 382         )
 383      {
 384         var intParser = Parser.Group (
 385            SkipChar ('-').Opt (),
 386            UInt ()
 387            );
 388
 389         Parser<int>.Function function = state =>
 390         {
 391            var intResult = intParser.Execute (state);
 392
 393            if (intResult.State.HasError ())
 394            {
 395               return intResult.Failure<int> ();
 396            }
 397
 398            var intValue = (int)intResult.Value.Item2;
 399
 400            return intResult.Success (intResult.Value.Item1.HasValue ? -intValue : intValue);
 401         };
 402         return function;
 403      }
 404#endif
 405
 406#if !MICRO_PARSER_SUPPRESS_CHAR_PARSER_DOUBLE
 407      public static Parser<double> Double ()
 408      {
 409         var intParser = Int ();
 410         var fracParser = SkipChar ('.').KeepRight (UIntImpl ());
 411         var expParser = SkipAnyOf ("eE").KeepRight (Parser.Group (AnyOf ("+-", maxCount:1), UInt ()));
 412
 413         var doubleParser = Parser.Group (
 414            intParser,
 415            fracParser.Opt (),
 416            expParser.Opt ()
 417            );
 418
 419         Parser<double>.Function function = state =>
 420         {
 421            var doubleResult = doubleParser.Execute (state);
 422
 423            if (doubleResult.State.HasError ())
 424            {
 425               return doubleResult.Failure<double> ();
 426            }
 427
 428            var value = doubleResult.Value;
 429
 430            var intValue = value.Item1;
 431
 432            double doubleValue;
 433
 434            if (value.Item2.HasValue)
 435            {
 436               var uIntResult = value.Item2.Value;
 437
 438               var multiplier = intValue >= 0 ? 1 : -1;
 439
 440               doubleValue = intValue + multiplier * uIntResult.Value * (Math.Pow (0.1, uIntResult.ConsumedCharacters));
 441            }
 442            else
 443            {
 444               doubleValue = intValue;
 445            }
 446
 447            if (value.Item3.HasValue)
 448            {
 449               var modifier = value.Item3.Value.Item1;
 450
 451               var multiplier = 
 452                  modifier[0] == '-'
 453                  ?  -1.0
 454                  :  1.0
 455                  ;
 456
 457               doubleValue *= Math.Pow (10.0, multiplier*value.Item3.Value.Item2);
 458            }
 459
 460            return doubleResult.Success (doubleValue);
 461         };
 462         return function;
 463      }
 464#endif
 465   }
 466}
 467}
 468namespace Include
 469{
 470// ----------------------------------------------------------------------------------------------
 471// Copyright (c) Mårten Rånge.
 472// ----------------------------------------------------------------------------------------------
 473// This source code is subject to terms and conditions of the Microsoft Public License. A 
 474// copy of the license can be found in the License.html file at the root of this distribution. 
 475// If you cannot locate the  Microsoft Public License, please send an email to 
 476// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 477//  by the terms of the Microsoft Public License.
 478// ----------------------------------------------------------------------------------------------
 479// You must not remove this notice, or any other, from this software.
 480// ----------------------------------------------------------------------------------------------
 481namespace MicroParser
 482{
 483   using System;
 484   using System.Collections.Generic;
 485   using System.Linq;
 486   using System.Linq.Expressions;
 487   using Internal;
 488
 489   sealed partial class CharSatisfy
 490   {
 491      public delegate bool Function (char ch, int index);
 492
 493      public readonly IParserErrorMessage ErrorMessage;
 494      public readonly Function Satisfy;
 495
 496      public static implicit operator CharSatisfy (char ch)
 497      {
 498         return new CharSatisfy (
 499            new ParserErrorMessage_Expected (Strings.CharSatisfy.FormatChar_1.FormatWith (ch)), 
 500            (c, i) => ch == c
 501            );
 502      }
 503
 504      public CharSatisfy (IParserErrorMessage errorMessage, Function satisfy)
 505      {
 506         ErrorMessage = errorMessage;
 507         Satisfy = satisfy;
 508      }
 509
 510#if !MICRO_PARSER_SUPPRESS_ANONYMOUS_TYPE
 511      public override string ToString ()
 512      {
 513         return new
 514                   {
 515                      ErrorMessage,
 516                   }.ToString ();
 517      }
 518#endif
 519
 520      class SatisfyFunctions
 521      {
 522         // ReSharper disable MemberHidesStaticFromOuterClass
 523         // ReSharper disable MemberCanBeMadeStatic.Local
 524
 525         // These methods should be kept non static as that reduces delegate overhead
 526
 527         public bool AnyChar (char ch, int index)
 528         {
 529            return true;
 530         }
 531
 532         public bool WhiteSpace (char ch, int index)
 533         {
 534            return char.IsWhiteSpace (ch);
 535         }
 536
 537         public bool Digit (char ch, int index)
 538         {
 539            return char.IsDigit (ch);
 540         }
 541
 542         public bool Letter (char ch, int index)
 543         {
 544            return char.IsLetter (ch);
 545         }
 546         // ReSharper restore MemberCanBeMadeStatic.Local
 547         // ReSharper restore MemberHidesStaticFromOuterClass
 548      }
 549
 550      static readonly SatisfyFunctions s_satisfyFunctions   = new SatisfyFunctions ();
 551
 552      public static readonly CharSatisfy AnyChar      = new CharSatisfy (ParserErrorMessages.Expected_Any         , s_satisfyFunctions.AnyChar     );
 553      public static readonly CharSatisfy WhiteSpace   = new CharSatisfy (ParserErrorMessages.Expected_WhiteSpace  , s_satisfyFunctions.WhiteSpace  );
 554      public static readonly CharSatisfy Digit        = new CharSatisfy (ParserErrorMessages.Expected_Digit       , s_satisfyFunctions.Digit       );
 555      public static readonly CharSatisfy Letter       = new CharSatisfy (ParserErrorMessages.Expected_Letter      , s_satisfyFunctions.Letter      );
 556
 557      public static readonly CharSatisfy LineBreak    = new CharSatisfy (ParserErrorMessages.Expected_LineBreak   , CreateSatisfyFunctionForAnyOfOrNoneOf ("\r\n", true));
 558
 559#if !MICRO_PARSER_SUPPRESS_CHAR_SATISFY_COMPOSITES
 560      public static readonly CharSatisfy LineBreakOrWhiteSpace  = LineBreak.Or (WhiteSpace);
 561      public static readonly CharSatisfy LetterOrDigit          = Letter.Or (Digit);
 562#endif
 563
 564#if MICRO_PARSER_NET35
 565      static Function CreateSatisfyFunctionForAnyOfOrNoneOf (
 566         string match,
 567         bool matchResult
 568         )
 569      {
 570         if (!match.Any (ch => ch > 255))
 571         {
 572            var boolMap = Enumerable.Repeat (!matchResult, 256).ToArray ();
 573            foreach (var c in match)
 574            {
 575               boolMap[c] = matchResult;
 576            }
 577
 578            return (c, i) => ((c & 0xFF00) == 0) && boolMap[c & 0xFF];
 579         }
 580
 581#if WINDOWS_PHONE
 582         // Windows Phone is basically .NET35 but lacks the HashSet class.
 583         // Approximate with Dictionary<>
 584         var dictionary = match.ToDictionary (v => v, v => true);
 585         return (c, i) => dictionary.ContainsKey (c) ? matchResult : !matchResult;
 586#else
 587         var hashSet = new HashSet<char> (match);
 588         return (c, i) => hashSet.Contains (c) ? matchResult : !matchResult;
 589#endif
 590      }
 591#else
 592      static Function CreateSatisfyFunctionForAnyOfOrNoneOf (
 593         string match,
 594         bool matchResult
 595         )
 596      {
 597         // For input string "Test" this generates the equivalent code to
 598         // Func<char, int> d = (ch, index) => 
 599         // {
 600         //    bool result;
 601         //    switch (ch)
 602         //    {
 603         //       case 'T':
 604         //       case 'e':
 605         //       case 's':
 606         //       case 't':
 607         //          result = matchResult;
 608         //          break;
 609         //       default:
 610         //          result = !matchResult;
 611         //          break;
 612         //    }
 613         //    return result;
 614         // }
 615
 616         var parameter0 = Expression.Parameter (typeof (char), "ch");
 617         var parameter1 = Expression.Parameter (typeof (int), "index");
 618
 619         var resultVariable = Expression.Variable (typeof (bool), "result");
 620
 621         var switchStatement = Expression.Switch (
 622            parameter0,
 623            Expression.Assign (resultVariable, Expression.Constant (!matchResult)),
 624            Expression.SwitchCase (
 625               Expression.Assign (resultVariable, Expression.Constant (matchResult)),
 626               match.Select (ch => Expression.Constant (ch)).ToArray ()
 627               ));
 628
 629         var body = Expression.Block (
 630            new[] { resultVariable },
 631            switchStatement,
 632            resultVariable
 633            );
 634
 635         var lambda = Expression.Lambda<Function>(
 636            body,
 637            parameter0,
 638            parameter1
 639            );
 640
 641         return lambda.Compile ();
 642      }
 643#endif
 644
 645      static CharSatisfy CreateSatisfyForAnyOfOrNoneOf (
 646         string match,
 647         Func<char, IParserErrorMessage> action,
 648         bool matchResult
 649         )
 650      {
 651         if (match.IsNullOrEmpty ())
 652         {
 653            throw new ArgumentNullException ("match");
 654         }
 655
 656         var errorMessages = match
 657            .Select (action)
 658            .ToArray ()
 659            ;
 660
 661         return new CharSatisfy (
 662            new ParserErrorMessage_Group (errorMessages),
 663            CreateSatisfyFunctionForAnyOfOrNoneOf (match, matchResult)
 664            );
 665      }
 666
 667      public static CharSatisfy CreateSatisfyForAnyOf (string match)
 668      {
 669         return CreateSatisfyForAnyOfOrNoneOf (
 670            match,
 671            x => new ParserErrorMessage_Expected (Strings.CharSatisfy.FormatChar_1.FormatWith (x)),
 672            true
 673            );
 674      }
 675
 676      public static CharSatisfy CreateSatisfyForNoneOf (string match)
 677      {
 678         return CreateSatisfyForAnyOfOrNoneOf (
 679            match,
 680            x => new ParserErrorMessage_Unexpected (Strings.CharSatisfy.FormatChar_1.FormatWith (x)),
 681            false
 682            );
 683      }
 684   }
 685}
 686}
 687namespace Include
 688{
 689// ----------------------------------------------------------------------------------------------
 690// Copyright (c) Mårten Rånge.
 691// ----------------------------------------------------------------------------------------------
 692// This source code is subject to terms and conditions of the Microsoft Public License. A 
 693// copy of the license can be found in the License.html file at the root of this distribution. 
 694// If you cannot locate the  Microsoft Public License, please send an email to 
 695// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 696//  by the terms of the Microsoft Public License.
 697// ----------------------------------------------------------------------------------------------
 698// You must not remove this notice, or any other, from this software.
 699// ----------------------------------------------------------------------------------------------
 700namespace MicroParser
 701{
 702   partial struct Empty
 703   {
 704      public static Empty Value;
 705
 706      public override string  ToString ()
 707      {
 708         return Strings.Empty;
 709      }
 710   }
 711
 712}
 713}
 714namespace Include
 715{
 716// ----------------------------------------------------------------------------------------------
 717// Copyright (c) Mårten Rånge.
 718// ----------------------------------------------------------------------------------------------
 719// This source code is subject to terms and conditions of the Microsoft Public License. A 
 720// copy of the license can be found in the License.html file at the root of this distribution. 
 721// If you cannot locate the  Microsoft Public License, please send an email to 
 722// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 723//  by the terms of the Microsoft Public License.
 724// ----------------------------------------------------------------------------------------------
 725// You must not remove this notice, or any other, from this software.
 726// ----------------------------------------------------------------------------------------------
 727namespace MicroParser
 728{
 729   using System.Collections.Generic;
 730   using System.Linq;
 731
 732   static partial class Extensions
 733   {
 734      // ParserReply.State
 735
 736      public static bool IsSuccessful (this ParserReply.State state)
 737      {
 738         return state == ParserReply.State.Successful;
 739      }
 740
 741      public static bool HasConsistentState (this ParserReply.State state)
 742      {
 743         return
 744            (state & ParserReply.State.FatalError_StateIsNotRestored)
 745               == 0;
 746      }
 747
 748      public static bool HasFatalError (this ParserReply.State state)
 749      {
 750         return state >= ParserReply.State.FatalError;
 751      }
 752
 753      public static bool HasError (this ParserReply.State state)
 754      {
 755         return state >= ParserReply.State.Error;
 756      }
 757
 758      public static bool HasNonFatalError (this ParserReply.State state)
 759      {
 760         return state >= ParserReply.State.Error && state < ParserReply.State.FatalError;
 761      }
 762
 763      // IParserErrorMessage
 764
 765      public static IEnumerable<IParserErrorMessage> DeepTraverse (this IParserErrorMessage value)
 766      {
 767         if (value == null)
 768         {
 769            yield break;
 770         }
 771
 772         var stack = new Stack<IParserErrorMessage> ();
 773         stack.Push (value);
 774
 775
 776         while (stack.Count > 0)
 777         {
 778            var pop = stack.Pop ();
 779
 780            var parserErrorMessageGroup = pop as ParserErrorMessage_Group;
 781
 782            if (parserErrorMessageGroup != null && parserErrorMessageGroup.Group != null)
 783            {
 784               foreach (var parserErrorMessage in parserErrorMessageGroup.Group)
 785               {
 786                  stack.Push (parserErrorMessage);
 787               }
 788            }
 789            else if (pop != null)
 790            {
 791               yield return pop;
 792            }
 793         }
 794
 795      }
 796
 797      public static IParserErrorMessage Append (this IParserErrorMessage left, IParserErrorMessage right)
 798      {
 799         return new ParserErrorMessage_Group (
 800            left.DeepTraverse ().Concat (right.DeepTraverse ()).ToArray ()
 801            );
 802      }
 803
 804      // CharSatisfy
 805
 806#if !MICRO_PARSER_SUPPRESS_EXTENSIONS_OR
 807      public static CharSatisfy Or (this CharSatisfy first, CharSatisfy second)
 808      {
 809         return new CharSatisfy (
 810            first.ErrorMessage.Append (second.ErrorMessage),
 811            (c, i) => first.Satisfy (c, i) || second.Satisfy (c, i)
 812            );
 813      }
 814#endif
 815
 816#if !MICRO_PARSER_SUPPRESS_EXTENSIONS_EXCEPT
 817      static IParserErrorMessage ExpectedToUnexpected (
 818         IParserErrorMessage parserErrorMessage
 819         )
 820      {
 821         var parserErrorMessageExpected = parserErrorMessage as ParserErrorMessage_Expected;
 822         return parserErrorMessageExpected != null
 823            ? new ParserErrorMessage_Unexpected (parserErrorMessageExpected.Expected)
 824            : parserErrorMessage
 825            ;
 826      }
 827
 828      public static CharSatisfy Except (this CharSatisfy first, CharSatisfy second)
 829      {
 830         return new CharSatisfy (
 831            first.ErrorMessage.Append (ExpectedToUnexpected (second.ErrorMessage)),
 832            (c, i) => first.Satisfy (c, i) && !second.Satisfy (c, i)
 833            );
 834      }
 835#endif
 836   }
 837}
 838}
 839namespace Include
 840{
 841// ----------------------------------------------------------------------------------------------
 842// Copyright (c) Mårten Rånge.
 843// ----------------------------------------------------------------------------------------------
 844// This source code is subject to terms and conditions of the Microsoft Public License. A 
 845// copy of the license can be found in the License.html file at the root of this distribution. 
 846// If you cannot locate the  Microsoft Public License, please send an email to 
 847// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 848//  by the terms of the Microsoft Public License.
 849// ----------------------------------------------------------------------------------------------
 850// You must not remove this notice, or any other, from this software.
 851// ----------------------------------------------------------------------------------------------
 852namespace MicroParser.Internal
 853{
 854   using System;
 855   using System.Collections.Generic;
 856   using System.Globalization;
 857   using System.Text;
 858
 859   static partial class Extensions
 860   {
 861
 862      // System.String
 863
 864      public static string FormatWith (this string format, params object[] args)
 865      {
 866         return string.Format (CultureInfo.InvariantCulture, format, args);
 867      }
 868
 869      public static bool IsNullOrEmpty (this string str)
 870      {
 871         return string.IsNullOrEmpty (str);
 872      }
 873
 874      // IEnumerable<string>
 875
 876      public static string Concatenate (
 877         this IEnumerable<string> strings,
 878         string delimiter = null,
 879         string prepend = null,
 880         string append = null
 881         )
 882      {
 883         var first = true;
 884
 885         var sb = new StringBuilder (prepend ?? String.Empty);
 886
 887         var del = delimiter ?? String.Empty;
 888
 889         foreach (var value in strings)
 890         {
 891            if (first)
 892            {
 893               first = false;
 894            }
 895            else
 896            {
 897               sb.Append (del);
 898            }
 899            sb.Append (value);
 900         }
 901
 902         sb.Append (append ?? String.Empty);
 903         return sb.ToString ();
 904      }
 905   }
 906}
 907}
 908namespace Include
 909{
 910// ----------------------------------------------------------------------------------------------
 911// Copyright (c) Mårten Rånge.
 912// ----------------------------------------------------------------------------------------------
 913// This source code is subject to terms and conditions of the Microsoft Public License. A 
 914// copy of the license can be found in the License.html file at the root of this distribution. 
 915// If you cannot locate the  Microsoft Public License, please send an email to 
 916// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 917//  by the terms of the Microsoft Public License.
 918// ----------------------------------------------------------------------------------------------
 919// You must not remove this notice, or any other, from this software.
 920// ----------------------------------------------------------------------------------------------
 921
 922namespace MicroParser
 923{
 924#if MICRO_PARSER_MAKE_PUBLIC
 925   public partial class CharParser
 926   {
 927
 928   }
 929
 930   public partial class CharSatisfy
 931   {
 932
 933   }
 934
 935   public partial interface IParserErrorMessage
 936   {
 937
 938   }
 939
 940   public partial struct Empty
 941   {
 942      
 943   }
 944
 945   public partial class Extensions
 946   {
 947      
 948   }
 949
 950   public partial class Optional
 951   {
 952
 953   }
 954
 955   public partial struct Optional<TValue>
 956   {
 957      
 958   }
 959
 960   public partial class Parser<TValue>
 961   {
 962
 963   }
 964
 965   public partial class Parser
 966   {
 967      
 968   }
 969
 970   public partial class ParserFunctionRedirect<TValue>
 971   {
 972
 973   }
 974
 975   public partial class ParserReply
 976   {
 977
 978   }
 979
 980   public partial struct ParserReply<TValue>
 981   {
 982
 983   }
 984
 985   public partial class BaseParserResult
 986   {
 987
 988   }
 989
 990   public partial class ParserResult<TValue>
 991   {
 992
 993   }
 994
 995   public partial class ParserState
 996   {
 997
 998   }
 999
1000   public partial struct ParserStatePosition
1001   {
1002
1003   }
1004
1005   public partial struct SubString
1006   {
1007
1008   }
1009
1010#if MICRO_PARSER_NET35
1011   public partial class Tuple
1012   {
1013
1014   }
1015
1016   public partial struct Tuple<TValue1, TValue2>
1017   {
1018
1019   }
1020
1021   public partial struct Tuple<TValue1, TValue2, TValue3>
1022   {
1023
1024   }
1025#endif
1026
1027#endif
1028}
1029}
1030namespace Include
1031{
1032// ----------------------------------------------------------------------------------------------
1033// Copyright (c) Mårten Rånge.
1034// ----------------------------------------------------------------------------------------------
1035// This source code is subject to terms and conditions of the Microsoft Public License. A 
1036// copy of the license can be found in the License.html file at the root of this distribution. 
1037// If you cannot locate the  Microsoft Public License, please send an email to 
1038// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
1039//  by the terms of the Microsoft Public License.
1040// ----------------------------------------------------------------------------------------------
1041// You must not remove this notice, or any other, from this software.
1042// ----------------------------------------------------------------------------------------------
1043namespace MicroParser
1044{
1045   static partial class Optional
1046   {
1047      public static Optional<TValue> Create<TValue> (TValue value)
1048      {
1049         return new Optional<TValue> (value);
1050      }
1051
1052      public static Optional<TValue> Create<TValue> ()
1053      {
1054         return new Optional<TValue> ();
1055      }
1056   }
1057
1058   partial struct Optional<TValue>
1059   {
1060      public readonly bool HasValue;
1061      public readonly TValue Value;
1062
1063      public Optional (TValue value)
1064      {
1065         HasValue = true;
1066         Value = value;
1067      }
1068
1069#if !MICRO_PARSER_SUPPRESS_ANONYMOUS_TYPE
1070      public override string ToString ()
1071      {
1072         return new
1073                   {
1074                      HasValue,
1075                      Value = HasValue ? Value : default (TValue),
1076                   }.ToString ();
1077      }
1078#endif
1079   }
1080}
1081}
1082namespace Include
1083{
1084// ----------------------------------------------------------------------------------------------
1085// Copyright (c) Mårten Rånge.
1086// ----------------------------------------------------------------------------------------------
1087// This source code is subject to terms and conditions of the Microsoft Public License. A 
1088// copy of the license can be found in the License.html file at the root of this distribution. 
1089// If you cannot locate the  Microsoft Public License, please send an email to 
1090// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
1091//  by the terms of the Microsoft Public License.
1092// ----------------------------------------------------------------------------------------------
1093// You must not remove this notice, or any other, from this software.
1094// ----------------------------------------------------------------------------------------------
1095
1096namespace MicroParser
1097{
1098   using System;
1099   using System.Collections.Generic;
1100   using System.Diagnostics;
1101   using System.Linq;
1102   using Internal;
1103
1104   sealed partial class Parser<TValue>
1105   {
1106      // ParserState is basically a string with a position
1107      // ParserReply contains the updated state and the result of the parser
1108      // operation depending on if the operation was successful
1109      public delegate ParserReply<TValue> Function (ParserState state);
1110
1111      public readonly Function Execute;
1112
1113      public Parser (Function function)
1114      {
1115         if (function == null)
1116         {
1117            throw new ArgumentNullException ("function");
1118         }
1119
1120         Execute = function;
1121      }
1122
1123      public static implicit operator Parser<TValue> (Function function)
1124      {
1125         return new Parser<TValue> (function);
1126      }
1127   }
1128
1129   static partial class Parser
1130   {
1131      public static ParserResult<TValue> Parse<TValue> (Parser<TValue> parserFunction, string text)
1132      {
1133         var parseResult = parserFunction.Execute (
1134            ParserState.Create (
1135               text ?? Strings.Empty,
1136               suppressParserErrorMessageOperations:true
1137               ));
1138
1139         if (!parseResult.State.IsSuccessful ())
1140         {
1141            var parseResultWithErrorInfo = parserFunction.Execute (
1142               ParserState.Create (
1143                  text ?? Strings.Empty
1144                  ));
1145
1146            var errorResult = parseResultWithErrorInfo
1147               .ParserErrorMessage
1148               .DeepTraverse ()
1149               .GroupBy (msg => msg.Description)
1150               .OrderBy (group => group.Key)
1151               .Select (group =>
1152                        Strings.Parser.ErrorMessage_2.FormatWith (
1153                           group.Key,
1154                           group.Select (message => message.Value.ToString ()).Distinct ().OrderBy (v => v).Concatenate (", ")
1155                           ))
1156               .Concatenate (", ");
1157
1158            var subString = new SubString ( 
1159                     text,
1160                     parseResultWithErrorInfo.ParserState.InternalPosition
1161                  );
1162
1163            var completeErrorResult =
1164               "Pos: {0} ('{1}') - {2}".FormatWith (
1165                  subString.Position,
1166                  subString[0],
1167                  errorResult
1168                  );
1169
1170            return new ParserResult<TValue> (
1171               false,
1172               subString,
1173               completeErrorResult,
1174               default (TValue)
1175               );
1176         }
1177
1178         return new ParserResult<TValue> (
1179            true,
1180            new SubString ( 
1181                  text,
1182                  parseResult.ParserState.InternalPosition
1183               ),
1184            Strings.Empty,
1185            parseResult.Value
1186            );
1187      }
1188
1189#if !MICRO_PARSER_SUPPRESS_PARSER_REDIRECT
1190      public static ParserFunctionRedirect<TValue> Redirect<TValue> ()
1191      {
1192         return new ParserFunctionRedirect<TValue> ();
1193      }
1194#endif
1195
1196#if !MICRO_PARSER_SUPPRESS_PARSER_RETURN
1197      public static Parser<TValue> Return<TValue> (TValue value)
1198      {
1199         Parser<TValue>.Function function = state => ParserReply<TValue>.Success (state, value);
1200         return function;
1201      }
1202#endif
1203
1204#if !MICRO_PARSER_SUPPRESS_PARSER_FAIL
1205      public static Parser<TValue> Fail<TValue>(string message)
1206      {
1207         var parserErrorMessageMessage = new ParserErrorMessage_Message (message);
1208         Parser<TValue>.Function function = state => ParserReply<TValue>.Failure (ParserReply.State.Error, state, parserErrorMessageMessage);
1209         return function;
1210      }
1211#endif
1212
1213#if !MICRO_PARSER_SUPPRESS_PARSER_FAIL_WITH_EXPECTED
1214      public static Parser<TValue> FailWithExpected<TValue>(this Parser<TValue> parser, string message)
1215      {
1216         var parserErrorMessageMessage = new ParserErrorMessage_Expected (message);
1217         Parser<TValue>.Function function = 
1218            state => 
1219               {
1220                  var reply = parser.Execute (state);
1221                  if (reply.State.HasError ())
1222                  {
1223                     return ParserReply<TValue>.Failure(
1224                        ParserReply.State.Error_Expected | reply.State & ParserReply.State.FatalError_Mask, 
1225                        state, 
1226                        parserErrorMessageMessage
1227                        );
1228                  }
1229                  return reply;
1230                  
1231               };
1232         return function;
1233      }
1234#endif
1235
1236#if !MICRO_PARSER_SUPPRESS_PARSER_DEBUG_BREAK
1237      public static Parser<TValue> DebugBreak<TValue> (this Parser<TValue> parser)
1238      {
1239         Parser<TValue>.Function function =
1240            state =>
1241               {
1242                  Debug.Assert (false);
1243                  return parser.Execute (state);
1244               };
1245         return function;
1246      }
1247#endif
1248
1249#if !MICRO_PARSER_SUPPRESS_PARSER_END_OF_STREAM
1250      public static Parser<Empty> EndOfStream ()
1251      {
1252         Parser<Empty>.Function function = state =>
1253                state.EndOfStream
1254                   ? ParserReply<Empty>.Success (state, Empty.Value)
1255                   : ParserReply<Empty>.Failure (
1256                      ParserReply.State.Error_Expected,
1257                      state,
1258                      ParserErrorMessages.Expected_EndOfStream
1259                      );
1260         return function;
1261      }
1262#endif
1263
1264#if !MICRO_PARSER_SUPPRESS_PARSER_COMBINE
1265      public static Parser<TValue2> Combine<TValue, TValue2>(this Parser<TValue> firstParser, Func<TValue, Parser<TValue2>> second)
1266      {
1267         Parser<TValue2>.Function function = state =>
1268                   {
1269                      var firstResult = firstParser.Execute (state);
1270                      if (firstResult.State.HasError ())
1271                      {
1272                         return firstResult.Failure<TValue2> ();
1273                      }
1274
1275                      var secondParser = second (firstResult.Value);
1276                      var secondResult = secondParser.Execute (state);
1277                      return secondResult;
1278                   };
1279         return function;
1280      }
1281#endif
1282
1283#if !MICRO_PARSER_SUPPRESS_PARSER_MAP
1284      public static Parser<TValue2> Map<TValue1, TValue2> (this Parser<TValue1> firstParser, Func<TValue1, TValue2> mapper)
1285      {
1286         Parser<TValue2>.Function function = state =>
1287         {
1288            var firstResult = firstParser.Execute (state);
1289
1290            if (firstResult.State.HasError ())
1291            {
1292               return firstResult.Failure<TValue2> ();
1293            }
1294
1295            return firstResult.Success (mapper (firstResult.Value));
1296         };
1297         return function;
1298      }
1299
1300      public static Parser<TValue2> Map<TValue1, TValue2> (this Parser<TValue1> firstParser, TValue2 value2)
1301      {
1302         return firstParser.Map (ignore => value2);
1303      }
1304#endif
1305
1306#if !MICRO_PARSER_SUPPRESS_PARSER_CHAIN
1307      public static Parser<TValue1> Chain<TValue1, TValue2>(
1308         this Parser<TValue1> parser,
1309         Parser<TValue2> separator,
1310         Func<TValue1, TValue2, TValue1, TValue1> combiner
1311         )
1312      {
1313         Parser<TValue1>.Function function = state =>
1314            {
1315               var result = parser.Execute (state);
1316               if (result.State.HasError ())
1317               {
1318                  return result;
1319               }
1320
1321               var accu = result.Value;
1322
1323               ParserReply<TValue2> separatorResult;
1324
1325               while ((separatorResult = separator.Execute (state)).State.IsSuccessful ())
1326               {
1327                  var trailingResult = parser.Execute (state);
1328
1329                  if (trailingResult.State.HasError ())
1330                  {
1331                     return trailingResult;
1332                  }
1333
1334                  accu = combiner (accu, separatorResult.Value, trailingResult.Value);
1335               }
1336
1337               if (separatorResult.State.HasFatalError ())
1338               {
1339                  return separatorResult.Failure<TValue1> ();
1340               }
1341
1342               return ParserReply<TValue1>.Success (state, accu);
1343            };
1344         return function;
1345      }
1346#endif
1347
1348#if !MICRO_PARSER_SUPPRESS_PARSER_ARRAY
1349      public static Parser<TValue[]> Array<TValue> (
1350         this Parser<TValue> parser,
1351         Parser<Empty> separator,
1352         bool allowTrailingSeparator = false,
1353         int minCount = 0,
1354         int maxCount = int.MaxValue
1355         )
1356      {
1357         VerifyMinAndMaxCount (minCount, maxCount);
1358
1359         Parser<TValue[]>.Function function = state =>
1360         {
1361            var initialPosition = state.Position;
1362
1363            var result = new List<TValue> (Math.Max (minCount, 16));
1364
1365            // Collect required
1366
1367            for (var iter = 0; iter < minCount; ++iter)
1368            {
1369               if (result.Count > 0)
1370               {
1371                  var separatorResult = separator.Execute (state);
1372
1373                  if (separatorResult.State.HasError ())
1374                  {
1375                     return separatorResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1376                  }
1377               }
1378
1379               var parserResult = parser.Execute (state);
1380
1381               if (parserResult.State.HasError ())
1382               {
1383                  return parserResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1384               }
1385
1386               result.Add (parserResult.Value);
1387            }
1388
1389            // Collect optional
1390
1391            for (var iter = minCount; iter < maxCount; ++iter)
1392            {
1393               if (result.Count > 0)
1394               {
1395                  var separatorResult = separator.Execute (state);
1396
1397                  if (separatorResult.State.HasFatalError ())
1398                  {
1399                     return separatorResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1400                  }
1401                  else if (separatorResult.State.HasError ())
1402                  {
1403                     break;
1404                  }
1405
1406               }               
1407
1408               var parserResult = parser.Execute (state);
1409
1410               if (!allowTrailingSeparator && result.Count > 0)
1411               {
1412                  // If a separator has been consumed we need to fail on failures
1413                  if (parserResult.State.HasError())
1414                  {
1415                     return parserResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1416                  }
1417               }
1418               else
1419               {
1420                  // If a separator has not been consumed we only need to fail on fatal errors
1421                  if (parserResult.State.HasFatalError ())
1422                  {
1423                     return parserResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1424                  }
1425                  else if (parserResult.State.HasError ())
1426                  {
1427                     break;
1428                  }
1429               }
1430
1431                result.Add (parserResult.Value);
1432            }
1433
1434            return ParserReply<TValue[]>.Success (state, result.ToArray ());
1435         };
1436         return function;
1437      }
1438#endif
1439
1440#if !MICRO_PARSER_SUPPRESS_PARSER_MANY
1441      public static Parser<TValue[]> Many<TValue> (
1442         this Parser<TValue> parser, 
1443         int minCount = 0, 
1444         int maxCount = int.MaxValue
1445         )
1446      {
1447         VerifyMinAndMaxCount (minCount, maxCount);
1448
1449         Parser<TValue[]>.Function function = state =>
1450         {
1451            var initialPosition = state.Position;
1452
1453            var result = new List<TValue> (Math.Max (minCount, 16));
1454
1455            // Collect required
1456
1457            for (var iter = 0; iter < minCount; ++iter)
1458            {
1459               var parserResult = parser.Execute (state);
1460
1461               if (parserResult.State.HasError ())
1462               {
1463                  return parserResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1464               }
1465
1466               result.Add (parserResult.Value);
1467            }
1468
1469            // Collect optional
1470
1471            for (var iter = minCount; iter < maxCount; ++iter)
1472            {
1473               var parserResult = parser.Execute (state);
1474
1475               if (parserResult.State.HasFatalError ())
1476               {
1477                  return parserResult.Failure<TValue[]> ().VerifyConsistency (initialPosition);
1478               }
1479               else if (parserResult.State.HasError ())
1480               {
1481                  break;
1482               }
1483
1484               result.Add (parserResult.Value);
1485            }
1486
1487            return ParserReply<TValue[]>.Success (state, result.ToArray ());
1488         };
1489         return function;
1490      }
1491#endif
1492
1493#if !MICRO_PARSER_SUPPRESS_PARSER_SWITCH
1494      public enum SwitchCharacterBehavior
1495      {
1496         Consume  ,
1497         Leave    ,
1498      }
1499
1500      public struct SwitchCase<TValue>
1501      {
1502         public readonly string           Case;  
1503         public readonly Parser<TValue>   Parser;
1504         public readonly string           Expected;
1505
1506         public SwitchCase (string @case, Parser<TValue> parser, string expected) : this()
1507         {
1508            Case     = @case     ?? "";
1509            Parser   = parser    ;
1510            Expected = expected  ?? "";
1511         }
1512      }
1513      
1514      public static SwitchCase<TValue> Case<TValue> (
1515         string @case,
1516         Parser<TValue> parser,
1517         string expected = null
1518         )
1519      {
1520         return new SwitchCase<TValue>(@case, parser, expected);
1521      }
1522
1523      public static Parser<TValue> Switch<TValue> (
1524         SwitchCharacterBehavior switchCharacterBehavior,
1525         params SwitchCase<TValue>[] cases
1526         )
1527      {
1528         if (cases == null)
1529         {
1530            throw new ArgumentNullException ("cases");
1531         }
1532
1533         if (cases.Length == 0)
1534         {
1535            throw new ArgumentOutOfRangeException ("cases", Strings.Parser.Verify_AtLeastOneParserFunctions);
1536         }
1537
1538         var caseDictionary = cases
1539            .SelectMany ((@case, i) => @case.Case.Select (c => Tuple.Create (c, i)))
1540            .ToDictionary (kv => kv.Item1, kv => kv.Item2);
1541
1542         var errorMessages = cases
1543            .SelectMany(
1544               (@case, i) => @case.Expected.IsNullOrEmpty()
1545                                ? @case
1546                                     .Case
1547                                     .Select(ch => Strings.CharSatisfy.FormatChar_1.FormatWith(ch))
1548                                : new[] { @case.Expected })
1549            .Distinct ()
1550            .Select (message => new ParserErrorMessage_Expected (message))            
1551            .ToArray();
1552
1553         var errorMessage = new ParserErrorMessage_Group (
1554            errorMe

Large files files are truncated, but you can click here to view the full file