public void TestParseErrorGetsReported() { // Create an instance of our language grammar and set handlers for its rules. LanguageGrammar<Expression> g = new LanguageGrammar<Expression>(); g.DivideRule.Action = (e1, e2) => Expression.Divide(e1, e2); g.DoubleLiteralRule.Action = (d) => Expression.Constant(d); g.IntLiteralRule.Action = (i) => Expression.Constant(i); g.StringLiteralRule.Action = (s) => Expression.Constant(s); g.MinusRule.Action = (e1, e2) => Expression.Subtract(e1, e2); g.ModRule.Action = (e1, e2) => Expression.Modulo(e1, e2); g.MultiplyRule.Action = (e1, e2) => Expression.Multiply(e1, e2); g.NegateRule.Action = (e) => Expression.Negate(e); g.PlusRule.Action = (e1, e2) => Expression.Add(e1, e2); g.VariableRefRule.SetStatefulAction<ParserState>((s, name) => s.GetVariable(name)); // Spin up a parser for our language. // TODO: Package this up and simplify it. var expressionHelper = new ExpressionHelper(); var classifierSession = new TerminalClassifierSession<char, ParserState, int>() .AddSkipTerminal(new Terminal<char> { Name = "Whitespace", InitialState = RegexCharNFABuilder.RegexCompiler(@"\s+") }) .CurrentCharExprIs(x => x.CurrentChar()) .GetFromMarkExprIs(x => x.GetFromMarkedPos()) .HasCurrentCharExprIs(x => x.HasCurrentChar()) .MarkPosExprIs(x => x.MarkPos()) .MoveNextCharExprIs(x => x.MoveNextChar()) .GetLocationIs(x=>new ParseLocation {Line = 1, Column = x.GetPos()}) .ErrorCollectionIs(x=>x.Errors) .UnmarkPosExprIs(x => x.UnmarkPos()); var parserGen = new ParserGenerator<char>(expressionHelper); var parseTableBuilder = new LRParseTableBuilder(); var parseTable = parseTableBuilder.BuildParseTable(g); var session = parserGen.NewSession<ParserState>() .NonTerminalValueExprIs<object>(x => x.NonTerminalValue) .TerminalValueExprIs<string>(x => x.TerminalStringValue) .TerminalValueExprIs<int>(x => x.TerminalIntValue) .TerminalValueExprIs<double>(x => x.TerminalDoubleValue) .TerminalIs(x => x.Terminal) .NonTerminalIs(x => x.NonTerminal) .IncludeSymbols(true) .DebugOutputIs(x => Debug.WriteLine(x)) .Generate("LanguageParser", parseTable, classifierSession); // At this point, session is an Expression<ParserState,int> representing our parser. // We can compile it into a delegate or a MethodBuilder. For the examples, we'll use a delegate. var compiler = session.Compile(); // Create a parser state object and initialize it. ParserState ps = new ParserState("x*y +* 2.0"); ps.SetParameters( Expression.Parameter(typeof(double), "x"), Expression.Parameter(typeof(double), "y")); Assert.AreNotEqual(0, compiler(ps)); Assert.AreNotEqual(0, ps.Errors.Count); Assert.Less(ps.Errors.First().ExpectedTerminalNames.Count, g.Terminals.Count); }
public void TestCreateClassifier() { Expression<Func<TextReader, TerminalMatch>> foundOpenTag = r => TerminalMatch.OpenTag; Expression<Func<TextReader, TerminalMatch>> foundCloseTag = r => TerminalMatch.CloseTag; Expression<Func<TextReader, TerminalMatch>> foundLeafTag = r => TerminalMatch.LeafTag; Expression<Func<TextReader, TerminalMatch>> foundNoTag = r => TerminalMatch.None; //var classifier = _parserGenerator.Classifier<TextReader, TerminalMatch>() var classifier = new TerminalClassifierSession<char, TextReader, TerminalMatch>() .HasCurrentCharExprIs(r => r.Peek() != -1) .CurrentCharExprIs(r => (char)r.Peek()) .MoveNextCharExprIs(r => r.Read()) .AddTerminalHandler(_openTag, r => TerminalMatch.OpenTag) .AddTerminalHandler(_closeTag, r => TerminalMatch.CloseTag) .AddTerminalHandler(_leafTag, r => TerminalMatch.LeafTag) .RejectHandlerIs(r => TerminalMatch.None) .Generate(); var open1 = new StringReader("<Open1>"); var open2 = new StringReader("<x>"); var close1 = new StringReader("</Close1>"); var close2 = new StringReader("</x>"); var leaf1 = new StringReader("<Leaf/>"); var leaf2 = new StringReader("<x/>"); var reject1 = new StringReader("<>"); var reject2 = new StringReader("</>"); var reject3 = new StringReader("x/>"); var reject4 = new StringReader("<reject4"); var reject5 = new StringReader("<reject5/"); var reject6 = new StringReader("</reject6"); var reject7 = new StringReader(""); var f = classifier.Compile(); Assert.AreEqual(TerminalMatch.OpenTag, f(open1)); Assert.AreEqual(TerminalMatch.OpenTag, f(open2)); Assert.AreEqual(TerminalMatch.CloseTag, f(close1)); Assert.AreEqual(TerminalMatch.CloseTag, f(close2)); Assert.AreEqual(TerminalMatch.LeafTag, f(leaf1)); Assert.AreEqual(TerminalMatch.LeafTag, f(leaf2)); Assert.AreEqual(TerminalMatch.None, f(reject1)); Assert.AreEqual(TerminalMatch.None, f(reject2)); Assert.AreEqual(TerminalMatch.None, f(reject3)); Assert.AreEqual(TerminalMatch.None, f(reject4)); Assert.AreEqual(TerminalMatch.None, f(reject5)); Assert.AreEqual(TerminalMatch.None, f(reject6)); Assert.AreEqual(TerminalMatch.None, f(reject7)); }
public void TestClassifyTokensAndCaptureIdentifiersUntilEof() { Expression<Func<TestStringInput, string, TerminalMatch>> capture = ((t, m) => t.Capture(m, TerminalMatch.Identifier)); var classifier = new TerminalClassifierSession<char, TestStringInput, TerminalMatch>() .HasCurrentCharExprIs(r => r.HasCurrentChar()) .CurrentCharExprIs(r => r.CurrentChar()) .MoveNextCharExprIs(r => r.MoveNextChar()) .MarkPosExprIs(r => r.MarkPos()) .UnmarkPosExprIs(r => r.UnmarkPos()) .GetFromMarkExprIs(r => r.GetFromMarkedPos()) .AddTerminalHandler(_if, r => TerminalMatch.If) .AddTerminalHandler(_while, r => TerminalMatch.While) .AddTerminalHandler(_identifier, capture) .AddSkipTerminal(_whitespace) .EofHandlerIs(r => TerminalMatch.Eof) .RejectHandlerIs(r => TerminalMatch.None) .Generate(); var f = classifier.Compile(); var strIds = new TestStringInput("if while bob ida\nwhere iffy wh wherefore i if8 d7"); Assert.AreEqual(TerminalMatch.If, f(strIds)); Assert.AreEqual(TerminalMatch.While, f(strIds)); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("bob", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("ida", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("where", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("iffy", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("wh", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("wherefore", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("i", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("if8", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Identifier, f(strIds)); Assert.AreEqual("d7", strIds.LastCapture); Assert.AreEqual(TerminalMatch.Eof, f(strIds)); }
public void TestClassifyKeywordsAndIdentifiers() { Expression<Func<TextReader, TerminalMatch>> foundIdentifer = (r) => TerminalMatch.Identifier; Expression<Func<TextReader, TerminalMatch>> foundIf = (r) => TerminalMatch.If; Expression<Func<TextReader, TerminalMatch>> foundWhile = (r) => TerminalMatch.While; Expression<Func<TextReader, TerminalMatch>> foundNone = (r) => TerminalMatch.None; var classifier = new TerminalClassifierSession<char, TextReader, TerminalMatch>() .HasCurrentCharExprIs(r => r.Peek() != -1) .CurrentCharExprIs(r => (char)r.Peek()) .MoveNextCharExprIs(r => r.Read()) .AddTerminalHandler(_if, r => TerminalMatch.If) .AddTerminalHandler(_while, r => TerminalMatch.While) .AddTerminalHandler(_identifier, r => TerminalMatch.Identifier) .RejectHandlerIs(r => TerminalMatch.None) .Generate(); var f = classifier.Compile(); var strIf = new StringReader("if"); var strWhile = new StringReader("while"); var id1 = new StringReader("bob"); var id2 = new StringReader("ida"); var id3 = new StringReader("where"); var id4 = new StringReader("iffy"); var id5 = new StringReader("wh"); var id6 = new StringReader("wherefore"); var id7 = new StringReader("i"); var id8 = new StringReader("if8"); var id9 = new StringReader("d7 = 123"); var reject1 = new StringReader("99"); var reject2 = new StringReader("(@*#"); var reject3 = new StringReader(""); Assert.AreEqual(TerminalMatch.If, f(strIf)); Assert.AreEqual(TerminalMatch.While, f(strWhile)); Assert.AreEqual(TerminalMatch.Identifier, f(id1)); Assert.AreEqual(TerminalMatch.Identifier, f(id2)); Assert.AreEqual(TerminalMatch.Identifier, f(id3)); Assert.AreEqual(TerminalMatch.Identifier, f(id4)); Assert.AreEqual(TerminalMatch.Identifier, f(id5)); Assert.AreEqual(TerminalMatch.Identifier, f(id6)); Assert.AreEqual(TerminalMatch.Identifier, f(id7)); Assert.AreEqual(TerminalMatch.Identifier, f(id8)); Assert.AreEqual(TerminalMatch.Identifier, f(id9)); Assert.AreEqual(TerminalMatch.None, f(reject1)); Assert.AreEqual(TerminalMatch.None, f(reject2)); Assert.AreEqual(TerminalMatch.None, f(reject3)); }
public void TestQuotedStringValue() { LanguageGrammar<string> g = new LanguageGrammar<string>(); g.StringLiteralRule.Action = (s) => s; // Spin up a parser for our language. // TODO: Package this up and simplify it. var expressionHelper = new ExpressionHelper(); //var classifierGen = new TerminalClassifier<char>(); var classifierSession = new TerminalClassifierSession<char, ParserState, int>() .AddSkipTerminal(new Terminal<char> { Name = "Whitespace", InitialState = RegexCharNFABuilder.RegexCompiler(@"\s+") }) .CurrentCharExprIs(x => x.CurrentChar()) .GetFromMarkExprIs(x => x.GetFromMarkedPos()) .HasCurrentCharExprIs(x => x.HasCurrentChar()) .MarkPosExprIs(x => x.MarkPos()) .MoveNextCharExprIs(x => x.MoveNextChar()) .UnmarkPosExprIs(x => x.UnmarkPos()); var parserGen = new ParserGenerator<char>(expressionHelper); var parseTableBuilder = new LRParseTableBuilder(); var parseTable = parseTableBuilder.BuildParseTable(g); var session = parserGen.NewSession<ParserState>() .NonTerminalValueExprIs<object>(x => x.NonTerminalValue) .TerminalValueExprIs<string>(x => x.TerminalStringValue) .TerminalValueExprIs<int>(x => x.TerminalIntValue) .TerminalValueExprIs<double>(x => x.TerminalDoubleValue) .TerminalIs(x => x.Terminal) .NonTerminalIs(x => x.NonTerminal) .IncludeSymbols(true) .UseDefaultValue(true) .DebugOutputIs(x => Debug.WriteLine(x)) .Generate("LanguageParser", parseTable, classifierSession); // At this point, session is an Expression<ParserState,int> representing our parser. // We can compile it into a delegate or a MethodBuilder. For the examples, we'll use a delegate. var compiler = session.Compile(); ParserState ps = new ParserState("\"This is a quoted string\""); Assert.AreEqual(0, compiler(ps)); Assert.AreEqual("This is a quoted string", ps.NonTerminalValue); ps = new ParserState("\"Here are some \\t escape characters\\r\\netc...\""); Assert.AreEqual(0, compiler(ps)); Assert.AreEqual("Here are some \t escape characters\r\netc...", ps.NonTerminalValue); ps = new ParserState("\"And more \\\\ escape \\\" characters\""); Assert.AreEqual(0, compiler(ps)); Assert.AreEqual("And more \\ escape \" characters", ps.NonTerminalValue); }
public void TestParserSucceedsWithoutAValue() { LanguageGrammar<Expression> g = new LanguageGrammar<Expression>(); // Spin up a parser for our language. // TODO: Package this up and simplify it. var expressionHelper = new ExpressionHelper(); //var classifierGen = new TerminalClassifier<char>(); var classifierSession = new TerminalClassifierSession<char, ParserState, int>() .CurrentCharExprIs(x => x.CurrentChar()) .GetFromMarkExprIs(x => x.GetFromMarkedPos()) .HasCurrentCharExprIs(x => x.HasCurrentChar()) .MarkPosExprIs(x => x.MarkPos()) .MoveNextCharExprIs(x => x.MoveNextChar()) .UnmarkPosExprIs(x => x.UnmarkPos()); var parserGen = new ParserGenerator<char>(expressionHelper); var parseTableBuilder = new LRParseTableBuilder(); var parseTable = parseTableBuilder.BuildParseTable(g); var session = parserGen.NewSession<ParserState>() .NonTerminalValueExprIs<object>(x => x.NonTerminalValue) .TerminalValueExprIs<string>(x => x.TerminalStringValue) .TerminalValueExprIs<int>(x => x.TerminalIntValue) .TerminalValueExprIs<double>(x => x.TerminalDoubleValue) .TerminalIs(x => x.Terminal) .NonTerminalIs(x => x.NonTerminal) .IncludeSymbols(true) .UseDefaultValue(true) .DebugOutputIs(x => Debug.WriteLine(x)) .Generate("LanguageParser", parseTable, classifierSession); // At this point, session is an Expression<ParserState,int> representing our parser. // We can compile it into a delegate or a MethodBuilder. For the examples, we'll use a delegate. var compiler = session.Compile(); // Create a parser state object and initialize it. ParserState ps = new ParserState("x*y+2.0"); Assert.AreEqual(0, compiler(ps)); }