public static Parser <char, IExpr> CreateExpressionParser() { Parser <char, IExpr> expr = null; var call = Parenthesised(Rec(() => expr).Separated(Tok(","))) .Select <Func <IExpr, IExpr> >( args => method => new Call(method, args.ToImmutableArray()) ).Labelled("function call"); var term = OneOf( Identifier, Floating, Parenthesised(Rec(() => expr)).Labelled("parenthesised expression") ); expr = ExpressionParser.Build( term, new[] { Operator.PostfixChainable(call), Operator.InfixL(Powered), Operator.Prefix(Neg), Operator.InfixL(Div), Operator.InfixL(Mul), Operator.InfixL(Sub), Operator.InfixL(Add) } ).Labelled("expression"); return(expr); }
public void TestPrefix() { Parser <char, bool> parser = null; var termParser = String("false").Select(_ => false) .Or(String("true").Select(_ => true)) .Or(Rec(() => parser).Between(Char('('), Char(')'))); parser = ExpressionParser.Build( termParser, new[] { new[] { Operator.Prefix( Char('!').Select <Func <bool, bool> >(_ => b => !b) ) } } ); AssertSuccess(parser.Parse("true"), true, true); AssertSuccess(parser.Parse("!true"), false, true); AssertSuccess(parser.Parse("!(!true)"), true, true); }
private static Parser <char, Expression> BuildExpressionParser() { Parser <char, Expression> expr = null; var term = OneOf( Identifier, IntegerLiteral, Parenthesised(Rec(() => expr)).Labelled("parenthesised expression") ); var call = Parenthesised(Rec(() => expr).Separated(Token(","))) .Select <Func <Expression, Expression> >(args => method => new Call(method, args.ToImmutableArray())) .Labelled("function call"); expr = ExpressionParser.Build( term, new[] { Operator.PostfixChainable(call), Operator.Prefix(Negate).And(Operator.Prefix(Complement)), Operator.InfixL(Multiply), Operator.InfixL(Add) } ).Labelled("expression"); return(expr); }
public void Setup() { _bigExpression = string.Join("+", Enumerable.Range(1, 1000)); var infixL = Operator.InfixL(Parser.Char('+').Then(Return <Func <int, int, int> >((x, y) => x + y))); _leftAssoc = ExpressionParser.Build( Parser.Num, new[] { new[] { infixL } } ); var infixR = Operator.InfixR(Parser.Char('+').Then(Return <Func <int, int, int> >((x, y) => x + y))); _rightAssoc = ExpressionParser.Build( Parser.Num, new[] { new[] { infixR } } ); }
public void TestInfixR() { Parser <char, Expr> parser = null; var termParser = Digit.Select <Expr>(x => new Lit((int)char.GetNumericValue(x))); parser = ExpressionParser.Build( termParser, new[] { new[] { Operator.InfixR( Char('*').Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Times(x, y))) ) }, new[] { Operator.InfixR( Char('+').Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Plus(x, y))) ), Operator.InfixR( Char('-').Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Minus(x, y))) ) } } ); AssertSuccess( parser.Parse("1+2+3+4"), new Plus(new Lit(1), new Plus(new Lit(2), new Plus(new Lit(3), new Lit(4)))), true ); // yeah it's not mathematically accurate but who cares, it's a test AssertSuccess( parser.Parse("1+2-3+4"), new Plus(new Lit(1), new Minus(new Lit(2), new Plus(new Lit(3), new Lit(4)))), true ); AssertSuccess( parser.Parse("1*2*3+4*5"), new Plus(new Times(new Lit(1), new Times(new Lit(2), new Lit(3))), new Times(new Lit(4), new Lit(5))), true ); }
public void TestPostfix() { Func <dynamic> f = () => true; Parser <char, dynamic> parser = null; var termParser = String("f").Select <dynamic>(_ => f); parser = ExpressionParser.Build( termParser, new[] { new[] { Operator.Postfix(String("()").Select <Func <dynamic, dynamic> >(_ => g => g())) } } ); AssertSuccess(parser.Parse("f"), f, true); AssertSuccess(parser.Parse("f()"), f(), true); }
static SyntaxQueryParser() { var axis = OneOf( Try(String("self::").Select(s => SyntaxQueryAxis.Self)), Try(OneOf(String("//"), String("descendant::")).Select(s => SyntaxQueryAxis.Descendant)), String("/").Select(s => SyntaxQueryAxis.Child), Try(String("parent::").Select(s => SyntaxQueryAxis.Parent)) ); var target = Letter.Labelled("keyword").AtLeastOnceString().Select(ParseKeyword); Parser <char, SyntaxQuery> query = null; var literal = AnyCharExcept('\'').ManyString().Between(Char('\'')) .Select(value => new SyntaxFilterLiteralExpression(value)); var expressionLeaf = OneOf( Rec(() => query).Cast <ISyntaxFilterExpression>(), literal.Cast <ISyntaxFilterExpression>() ); var expression = ExpressionParser.Build( expressionLeaf, new[] { new[] { BinaryOperator("==", SyntaxFilterBinaryOperator.Equals) }, new[] { BinaryOperator("&&", SyntaxFilterBinaryOperator.And) }, } ); var filter = Char('[').Then(expression).Before(Char(']')); query = Map( (a, t, f) => new SyntaxQuery(a.GetValueOrDefault(SyntaxQueryAxis.Child), t, f.GetValueOrDefault()), axis.Optional(), target, filter.Optional() ); Root = query.Before(End()); }
public void TestInfixL() { Parser <char, Expr> parser = null; var termParser = Digit.Select <Expr>(x => new Lit((int)char.GetNumericValue(x))); parser = ExpressionParser.Build( termParser, new[] { Operator.InfixL( Char('*').Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Times(x, y))) ), Operator.InfixL( Char('+').Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Plus(x, y))) ).And(Operator.InfixL( Char('-').Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Minus(x, y))) )) } ); AssertSuccess( parser.Parse("1+2+3+4"), new Plus(new Plus(new Plus(new Lit(1), new Lit(2)), new Lit(3)), new Lit(4)), true ); AssertSuccess( parser.Parse("1+2-3+4"), new Plus(new Minus(new Plus(new Lit(1), new Lit(2)), new Lit(3)), new Lit(4)), true ); AssertSuccess( parser.Parse("1*2*3+4*5"), new Plus(new Times(new Times(new Lit(1), new Lit(2)), new Lit(3)), new Times(new Lit(4), new Lit(5))), true ); }
private static Tuple <Parser <char, Expr>, Stack <bool>, Stack <bool> > BuildExprParser() { Parser <char, Expr> exprParser = null; var listParser = Rec(() => exprParser).Separated(Comma.Before(SkipWhitespaces)); var funcHead = Id.Or(If).Between(SkipWhitespaces).Before(LParen.Between(SkipWhitespaces)); var funcParser = Try(Lookahead(funcHead)).Then(Map((id, prms) => (Expr) new Function(id, prms), funcHead, listParser.Before(RParen))).Labelled("func"); var termParser = funcParser .Or(Try(Bool.Select <Expr>(x => new BoolLit(x))) .Or(Num.Select <Expr>(x => new NumLit(x))) .Or(Str.Select <Expr>(x => new StringLit(x))) .Or(Chr.Select <Expr>(x => new CharLit(x))) .Or(Id.Select <Expr>(x => new Identifier(x))) .Or(Rec(() => listParser) .Between(LBrace.Then(SkipWhitespaces), SkipWhitespaces.Then(RBrace)) .Select <Expr>(x => new Membership(x))) .Or(Rec(() => exprParser) .Between(LParen.Then(SkipWhitespaces), SkipWhitespaces.Then(RParen)) .Select <Expr>(x => new Nested(x))) ).Labelled("term") .Between(SkipWhitespaces.Or(End())); var cTerStack = new Stack <bool>(); var pyTerStack = new Stack <bool>(); exprParser = ExpressionParser.Build(termParser, new[] { // arithmatic new[] { Operator.Prefix(Char('+').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr> >(x => new Positive(x)))), Operator.Prefix(Char('-').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr> >(x => new Negative(x)))), }, new[] { Operator.InfixR(Char('^').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Power(x, y)))), }, new[] { Operator.InfixL(Char('*').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Mult(x, y)))), Operator.InfixL(Char('/').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Div(x, y)))), }, new[] { Operator.InfixL(Char('%').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Mod(x, y)))), }, new[] { Operator.InfixL(Char('+').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Plus(x, y)))), Operator.InfixL(Char('-').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Minus(x, y)))), }, new[] { // VB string cat Operator.InfixL(Try(Lookahead(Not(Char('&').Before(Char('&'))))).Then(Char('&').Between(SkipWhitespaces)).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Cat(x, y)))), }, new[] { Operator.InfixL(Try(Lookahead(String("??"))).Then(String("??").Between(SkipWhitespaces)).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new NullCoalesce(x, y)))), }, // comparision. TODO: check how to separate arithmatic, comparison and logical ops new[] { Operator.InfixL(Try(String(">=").Between(SkipWhitespaces)).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Ge(x, y)))), Operator.InfixL(Try(String("<=").Between(SkipWhitespaces)).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Le(x, y)))), Operator.InfixL(Try(String("<>").Between(SkipWhitespaces)).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Ne("<>", x, y)))), Operator.InfixL(String("!=").Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Ne(x, y)))), Operator.InfixL(String(">").Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Gt(x, y)))), Operator.InfixL(String("<").Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Lt(x, y)))), Operator.InfixL(Try(String("==")).Or(String("=")).Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Eq(x, y)))), Operator.InfixL(Try(String("in").Between(SkipWhitespaces).Before(Lookahead(LBrace))).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new In(x, y)))), }, // logical. TODO: check how to separate arithmatic, comparison and logical ops new[] { Operator.Prefix(Char('!').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr> >(x => new Not(x)))), }, new[] { Operator.InfixL(String("&&").Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new And(x, y)))), }, new[] { Operator.InfixL(String("||").Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => new Or(x, y)))), }, new[] { Operator.InfixR(If.Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => { if (pyTerStack.Count == 0) { throw new InvalidOperationException("Unbalanced Python-style Ternary Operators, fewer 'else' parts than 'then' parts"); } pyTerStack.Pop(); return(TerUtils.FormPyTerExpr(x, y)); }))), Operator.InfixR(Else.Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => { pyTerStack.Push(true); return(new PyTerExprElse(x, y)); }))), Operator.InfixR(Try(Lookahead(Not(Char('?').Before(Char('?'))))).Then(Char('?').Between(SkipWhitespaces)).Then(Return <Func <Expr, Expr, Expr> >((x, y) => { if (cTerStack.Count == 0) { throw new InvalidOperationException("Unbalanced C-style Ternary Operators, fewer 'else' parts than 'then' parts"); } cTerStack.Pop(); return(TerUtils.FormCTerExpr(x, y)); }))), Operator.InfixR(Char(':').Between(SkipWhitespaces).Then(Return <Func <Expr, Expr, Expr> >((x, y) => { cTerStack.Push(true); return(new CTerElseExpr(x, y)); }))), }, }); return(Tuple.Create(exprParser, cTerStack, pyTerStack)); }