public void Should_cast_function_params()
        {
            BracketOpenDefinition openBracket, logFn;
            GrammerDefinition     listDelimeter;
            var language = new Language(

                logFn = new FunctionCallDefinition(
                    name: "LOG",
                    regex: @"[Ll]og\(",
                    argumentTypes: new[] { typeof(double), typeof(double) },
                    expressionBuilder: args => Expression.Call(Type <int> .Method(x => Math.Log(0, 0)), args)),
                openBracket = new BracketOpenDefinition(
                    name: "OPENBRACKET",
                    regex: @"\("),
                listDelimeter = new ListDelimiterDefinition(
                    name: "COMMA",
                    regex: @"\,"),
                new BracketCloseDefinition(
                    name: "CLOSEBRACKET",
                    regex: @"\)",
                    bracketOpenDefinitions: new[] { openBracket, logFn },
                    listDelimeterDefinition: listDelimeter),
                new OperandDefinition(
                    name: "NUMBER",
                    regex: @"\d+",
                    expressionBuilder: x => Expression.Constant(int.Parse(x))),
                new GrammerDefinition(name: "WHITESPACE", regex: @"\s+", ignore: true)
                );

            var expression = language.Parse <double>("Log(1024,2)");

            Assert.Equal(10, expression.Compile()());
        }
        public void Should_run_single_param_functions()
        {
            BracketOpenDefinition openBracket, sinFn;
            var language = new Language(
                new OperatorDefinition(
                    name: "PLUS",
                    regex: @"\+",
                    orderOfPrecedence: 10,
                    paramaterPositions: new[] { RelativePosition.Left, RelativePosition.Right },
                    expressionBuilder: args => Expression.Add(args[0], args[1])),
                sinFn = new FunctionCallDefinition(
                    name: "SIN",
                    regex: @"sin\(",
                    expressionBuilder: args => Expression.Call(typeof(Math).GetMethod("Sin"), args[0])),
                openBracket = new BracketOpenDefinition(
                    name: "OPENBRACKET",
                    regex: @"\("),
                new BracketCloseDefinition(
                    name: "CLOSEBRACKET",
                    regex: @"\)",
                    bracketOpenDefinitions: new[] { openBracket, sinFn }),
                new OperandDefinition(
                    name: "NUMBER",
                    regex: @"\d*\.?\d+?",
                    expressionBuilder: x => Expression.Constant(double.Parse(x))),
                new GrammerDefinition(name: "WHITESPACE", regex: @"\s+", ignore: true)
                );

            var expression = language.Parse <double>("sin(1+2)+3");

            Assert.Equal(3.14, expression.Compile()(), 2);
        }
        public void Should_apply_brackets()
        {
            BracketOpenDefinition openBracket;
            var language = new Language(
                new OperatorDefinition(
                    name: "PLUS",
                    regex: @"\+",
                    orderOfPrecedence: 1,
                    paramaterPositions: new[] { RelativePosition.Left, RelativePosition.Right },
                    expressionBuilder: args => Expression.Add(args[0], args[1])),
                new OperatorDefinition(
                    name: "MULTIPLY",
                    regex: @"\*",
                    orderOfPrecedence: 2,
                    paramaterPositions: new[] { RelativePosition.Left, RelativePosition.Right },
                    expressionBuilder: args => Expression.Multiply(args[0], args[1])),
                openBracket = new BracketOpenDefinition(
                    name: "OPENBRACKET",
                    regex: @"\("),
                new BracketCloseDefinition(
                    name: "CLOSEBRACKET",
                    regex: @"\)",
                    bracketOpenDefinition: openBracket),
                new OperandDefinition(
                    name: "NUMBER",
                    regex: @"\d*\.?\d+?",
                    expressionBuilder: x => Expression.Constant(decimal.Parse(x))),
                new GrammerDefinition(name: "WHITESPACE", regex: @"\s+", ignore: true)
                );

            var expression = language.Parse <decimal>("(1 + 2) * (3 + 5)");

            Assert.Equal(24, expression.Compile()());
        }
        public ParserErrorTests()
        {
            BracketOpenDefinition openBracket, logFn, errorFn;
            GrammerDefinition     listDelimeter;

            Language = new Language(
                new OperatorDefinition(
                    name: "PLUS",
                    regex: @"\+",
                    orderOfPrecedence: 1,
                    paramaterPositions: new[] { RelativePosition.Left, RelativePosition.Right },
                    expressionBuilder: args => Expression.Add(args[0], args[1])),
                new OperatorDefinition(
                    name: "MULTIPLY",
                    regex: @"\*",
                    orderOfPrecedence: 1,
                    paramaterPositions: new[] { RelativePosition.Left, RelativePosition.Right },
                    expressionBuilder: args => Expression.Multiply(args[0], args[1])),
                logFn = new FunctionCallDefinition(
                    name: "LOG",
                    regex: @"[Ll]og\(",
                    argumentTypes: new[] { typeof(double), typeof(double) },
                    expressionBuilder: args => Expression.Call(Type <int> .Method(x => Math.Log(0, 0)), args)),
                errorFn = new FunctionCallDefinition(
                    name: "ERROR",
                    regex: @"error\(",
                    argumentTypes: new[] { typeof(double), typeof(double) },
                    expressionBuilder: args => { throw new NotImplementedException("I am a function error"); }),
                openBracket = new BracketOpenDefinition(
                    name: "OPENBRACKET",
                    regex: @"\("),
                listDelimeter = new ListDelimiterDefinition(
                    name: "COMMA",
                    regex: @"\,"),
                new BracketCloseDefinition(
                    name: "CLOSEBRACKET",
                    regex: @"\)",
                    bracketOpenDefinitions: new[] { openBracket, logFn, errorFn },
                    listDelimeterDefinition: listDelimeter),
                new OperandDefinition(
                    name: "NUMBER",
                    regex: @"\d*\.?\d+?",
                    expressionBuilder: x => Expression.Constant(decimal.Parse(x))),
                new OperandDefinition(
                    name: "POOP",
                    regex: @"💩",
                    expressionBuilder: x => { throw new NotImplementedException("I am an operand error"); }),
                new OperandDefinition(
                    name: "STRING",
                    regex: @"'.*?'",
                    expressionBuilder: x => Expression.Constant(x)),
                new GrammerDefinition(name: "WHITESPACE", regex: @"\s+", ignore: true)
                );
        }
        /// <summary>
        /// Returns the definitions for brackets used within the language.
        /// </summary>
        /// <param name="functionCalls">The function calls in the language. (used as opening brackets)</param>
        /// <returns></returns>
        protected virtual IEnumerable <GrammerDefinition> BracketDefinitions(IEnumerable <FunctionCallDefinition> functionCalls)
        {
            BracketOpenDefinition   openBracket;
            ListDelimiterDefinition delimeter;

            return(new GrammerDefinition[] {
                openBracket = new BracketOpenDefinition(
                    name: "OPEN_BRACKET",
                    regex: @"\("),
                delimeter = new ListDelimiterDefinition(
                    name: "COMMA",
                    regex: ","),
                new BracketCloseDefinition(
                    name: "CLOSE_BRACKET",
                    regex: @"\)",
                    bracketOpenDefinitions: new[] { openBracket }.Concat(functionCalls),
                    listDelimeterDefinition: delimeter)
            });
        }
        public void Should_run_two_param_functions()
        {
            BracketOpenDefinition openBracket, logFn;
            GrammerDefinition     listDelimeter;
            var language = new Language(
                new OperatorDefinition(
                    name: "PLUS",
                    regex: @"\+",
                    orderOfPrecedence: 1,
                    paramaterPositions: new[] { RelativePosition.Left, RelativePosition.Right },
                    expressionBuilder: args => Expression.Add(args[0], args[1])),
                logFn = new FunctionCallDefinition(
                    name: "LOG",
                    regex: @"[Ll]og\(",
                    expressionBuilder: args => Expression.Call(Type <int> .Method(x => Math.Log(0, 0)), args)),
                openBracket = new BracketOpenDefinition(
                    name: "OPENBRACKET",
                    regex: @"\("),
                listDelimeter = new ListDelimiterDefinition(
                    name: "COMMA",
                    regex: @"\,"),
                new BracketCloseDefinition(
                    name: "CLOSEBRACKET",
                    regex: @"\)",
                    bracketOpenDefinitions: new[] { openBracket, logFn },
                    listDelimeterDefinition: listDelimeter),
                new OperandDefinition(
                    name: "NUMBER",
                    regex: @"\d*\.?\d+?",
                    expressionBuilder: x => Expression.Constant(double.Parse(x))),
                new GrammerDefinition(name: "WHITESPACE", regex: @"\s+", ignore: true)
                );

            var expression = language.Parse <double>("Log(1024,2) + 5");

            Assert.Equal(15, expression.Compile()());
        }