Sprache is a C# parser combinator library. Its a really well-written library but it suffers from a lack of documentation, meaning the only way to figure out how to use it is to hunt for blog posts and examples, or to start digging through the source code. I’ve chosen the latter option.

This post will be part of a series picking apart and documenting each method in Sprache with examples in XUnit test syntax. This isn’t an introductory series, the best place to start is this introductory article if you are completely new to Sprache.

To start with, this post covers all the methods for parsing single characters.

Char

Parse a single character c. This method has two overloads:

  • Parser<char> Char(char c)
  • Parser<char> Char(Predicate<char> predicate, string description)

The first parses only the supplied character, the second parses any character which matches the predicate and also accepts a string which names the parser (see the Parser.Named method). The overload accepting a predicate is the building block for most of the remainder of the character parsing methods.

1
2
3
4
5
Parser<char> multiply = Parse.Char('*');
Assert.Equal('*', multiply.Parse("*"));

Parser<char> punctuation = Parse.Char(char.IsPunctuation, "punctuation");
Assert.Equal(',', punctuation.Parse(","));

Chars

Parse a single character from the supplied list. This method has two overloads depending on whether the list of characters shoudl be supplied as a character array or a string:

  • Parser<char> Chars(params char[] c)
  • Parser<char> Chars(string c)
1
2
3
4
5
Parser<char> op = Parse.Chars('+', '-', '*', '/');
Assert.Equal('-', op.Parse("-"));

Parser<char> parens = Parse.Chars("()");
Assert.Equal(')', parens.Parse(")"));

CharExcept

Parses any single character except for the one(s) supplied. This method has 4 overloads:

  • Parser<char> CharExcept(char c)
  • Parser<char> CharExcept(IEnumerable<char> c)
  • Parser<char> CharExcept(string c)
  • Parser<char> CharExcept(Predicate<char> predicate, string description)

When using the overload that accepts a predicate, the description is of the character that should not be matched:

1
2
3
4
Parser<char> parser = Parse.CharExcept(char.IsPunctuation, "punctuation");

// unexpected '.'; expected any character except punctuation
Assert.Throws<ParseException>(() => parser.Parse("."));

IgnoreCase

Parses a single character ignoring case.

  • Parser<char> IgnoreCase(char c)
1
2
3
Parser<char> parser = Parse.IgnoreCase('a');

Assert.Equal('A', parser.Parse("A"));

WhiteSpace

Parse a single whitespace character, according to char.IsWhiteSpace.

1
2
Assert.Equal(' ', Parse.WhiteSpace.Parse(" "));
Assert.Equal('\t', Parse.WhiteSpace.Parse("\t"));

Digit

Parse a single, according to char.IsDigit.

1
Assert.Equal('7', Parse.Digit.Parse("7"));

Numeric

Parses a single numeric character, according to char.IsNumber.

1
2
Assert.Equal('1', Parse.Numeric.Parse("1"));
Assert.Equal('¼', Parse.Numeric.Parse("¼"));

Letter

Parse a single letter, according to char.IsLetter.

1
Assert.Equal('a', Parse.Letter.Parse("a"));

LetterOrDigit

Parse a single letter or digit, according to char.IsLetterOrDigit.

1
2
Assert.Equal('a', Parse.LetterOrDigit.Parse("a"));
Assert.Equal('4', Parse.LetterOrDigit.Parse("4"));

Lower

Parse a single lowercase letter, according to char.IsLower.

1
2
3
Assert.Equal('a', Parse.Lower.Parse("a"));
// unexpected '4'; expected lowercase letter
Assert.Throws<ParseException>(() => Parse.Lower.Parse("4"));

Upper

Parse a single uppercase letter, according to char.IsUpper.

1
Assert.Equal('A', Parse.Upper.Parse("A"));

AnyChar

Parse any character.

1
Assert.Equal('a', Parse.AnyChar.Parse("abcd"));