Accept and evaluate simple expressions using a specific .NET language syntax/semantics.
C# is implemented using the following LL(1) BNF. ------------------------------------------------ expression ::= condOr cond2 cond2 ::= '?' expression ':' expression | '??' expression | {empty} condOr ::= condAnd condOr2 condOr2 ::= '||' condAnd condOr2 | {empty} condAnd ::= logicalOr condAnd2 condAnd2 ::= '&&' logicalOr condAnd2 | {empty} logicalOr ::= logicalXor logicalOr2 logicalOr2 ::= '|' logicalXor logicalOr2 | {empty} logicalXor ::= logicalAnd logicalXor2 logicalXor2 ::= '^' logicalAnd logicalXor2 | {empty} logicalAnd ::= equality logicalAnd2 logicalAnd2 ::= '&' equality logicalAnd2 | {empty} equality ::= relational equality2 equality2 ::= '==' relational equality2 | '!=' relational equality2 | {empty} relational ::= shift relational2 relational2 ::= '<' shift relational2 | '>' shift relational2 | '<=' shift relational2 | '>=' shift relational2 | {empty} shift ::= addsub shift2 shift2 ::= '<<' addsub shift2 | '>>' addsub shift2 | {empty} addsub ::= term expression2 expression2 ::= '+' term expression2 | '-' term expression2 | {empty} term ::= factor term2 term2 ::= '*' factor term2 | '/' factor term2 | '%' factor term2 | {empty} factor ::= '+' factor | '-' factor | '!' factor | '~' factor | access access ::= primary access2 access2 ::= '.' identifier methodcall access2 | '[' arglist1 ']' access2 | {empty} methodcall ::= '(' arglist ')' | {empty} primary ::= integer-literal | real-literal | boolean-literal | char-literal | string-literal | identifier | '(' expression ')' arglist ::= expression arglist2 | {empty} arglist1 ::= expression arglist2 | arglist2 ::= ',' expression arglist2 | {empty} VB.NET is implemented using the following LL(1) BNF. ---------------------------------------------------- expression ::= logicalOrVB logicalXor2VB logicalXor2VB ::= 'Xor' logicalOrVB logicalXor2VB | {empty} logicalOrVB ::= logicalAndVB logicalOr2VB logicalOr2VB ::= 'Or' logicalAndVB logicalOr2VB | 'OrElse' logicalAndVB logicalOr2VB | {empty} logicalAndVB ::= logicalNotVB logicalAnd2VB logicalAnd2VB ::= 'And' logicalNotVB logicalAnd2VB | 'AndAlso' logicalNotVB logicalAnd2VB | {empty} logicalNotVB ::= "Not' logicalNotVB | relationalVB relationalVB ::= shiftVB relational2VB relational2VB ::= '<' shiftVB relational2VB | '>' shiftVB relational2VB | '<=' shiftVB relational2VB | '>=' shiftVB relational2VB | '=' shiftVB relational2VB | '<>' shiftVB relational2VB | {empty} shiftVB ::= concatVB shift2VB shift2VB ::= '<<' concatVB shift2VB | '>>' concatVB shift2VB | {empty} concatVB ::= addsubVB concat2VB concat2VB ::= '&' addsubVB concat2VB | {empty} addsubVB ::= modVB addsub2VB addsub2VB ::= '+' modVB addsub2VB | '-' modVB addsub2VB | {empty} modVB ::= intdivVB mod2VB mod2VB ::= 'Mod' intdivVB mod2VB | {empty} intdivVB ::= termVB intdiv2VB intdiv2VB ::= '\' termVB intdiv2VB | {empty} termVB ::= factorVB term2VB term2VB ::= '*' factorVB term2VB | '/' factorVB term2VB | {empty} factorVB ::= '+' factorVB | '-' factorVB | expoVB expoVB ::= accessVB expo2VB expo2VB ::= '^' accessVB expo2VB | {empty} accessVB ::= primary access2VB access2VB ::= '.' identifier methodcall access2VB | '(' arglist1 ')' access2VB | {empty} methodcall ::= '(' arglist ')' | {empty} primary ::= integer-literal | real-literal | boolean-literal | char-literal | string-literal | identifier | '(' expression ')' arglist ::= expression arglist2 | {empty} arglist1 ::= expression arglist2 | arglist2 ::= ',' expression arglist2 | {empty}
Inheritance: Arithmetic
        /// <summary>
        /// Converts source values to a value for the binding target.
        /// </summary>
        /// <param name="values">The array of values that the source bindings produces.</param>
        /// <param name="targetType">The type of the binding target property.</param>
        /// <param name="parameter">The converter parameter to use.</param>
        /// <param name="culture">The culture to use in the converter.</param>
        /// <returns>A converted value.</returns>
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                // First time around we parse the evaluation input
                if (_eval == null)
                {
                    _eval = new Eval(_language);
                    _eval.ResolveIdentifier += new EventHandler<ResolveIdentifierEventArgs>(OnResolveIdentifier);
                    _eval.Parse(_expression);
                }

                // Every time we evaluate we could throw an exception. This is because each time around the
                // bindings can provide values of different types. So first time round the binding has an
                // integer and so works correctly but next time it could provide a string and cause a type
                // error in the evaluation.
                EvalResult ret = _eval.Evaluate(values);

                // Null means we have no result to provide
                if (ret == null)
                    return DependencyProperty.UnsetValue;
                else
                {
                    // If the return type is different to the target type
                    if (ret.Value.GetType() != targetType)
                    {
                        // If possible we perform an implicit conversion to the target
                        TypeCode targetTypeCode = Type.GetTypeCode(targetType);
                        if (ImplicitConverter.CanConvertTo(targetTypeCode, ret.Value, _language))
                            ret.Value = ImplicitConverter.ConvertTo(targetTypeCode, ret.Value, _language);
                        else
                        {
                            // Use type converters to attempt an explicit conversion
                            ret.Value = ConvertUsingConverter(ret, targetType);
                        }
                    }

                    return ret.Value;
                }
            }
            catch (ParseException pe)
            {
                Console.WriteLine("EvalBinding Parsing Exception : {0} : Index '{1}'", pe.Message, pe.Index);
                return DependencyProperty.UnsetValue;
            }
            catch (Exception e)
            {
                Console.WriteLine("EvalBinding Evaluation Exception : {0} : Eval '{1}'", e.Message, _eval.ToString());
                return DependencyProperty.UnsetValue;
            }
        }
 /// <summary>
 /// Initialize a new instance of the EvalNodeIdentifier class.
 /// </summary>
 /// <param name="eval">Owning eval instance..</param>
 /// <param name="identifier">Specifies identifier of the member to call.</param>
 /// <param name="language">Language used for evaluation.</param>
 public EvalNodeIdentifier(Eval eval, string identifier, Language language)
 {
     _eval = eval;
     _identifier = identifier;
     _language = language;
 }
        public static void TestEvalFailedError(string input, object thisArray, Language language)
        {
            try
            {
                Eval eval = new Eval(input, language);
                eval.Evaluate(thisArray);
            }
            catch (ParseException pe)
            {
                throw new ApplicationException("Eval parse error not expected. Input string '" + input + "' and parse error at index '" + pe.Index.ToString() + "'.");
            }
            catch (Exception)
            {
                return;
            }

            throw new ApplicationException("Eval error expected but not found. Input string '" + input + "'.");
        }
 public static void TestEvalFailedParseError(string input, int errorIndex, Language language)
 {
     try
     {
         Eval eval = new Eval(input, language);
         throw new ApplicationException("Eval parse error expected but not found. Input string '" + input + "' and expected error at index '" + errorIndex.ToString() + "'.");
     }
     catch (ParseException pe)
     {
         if (pe.Index == errorIndex)
             return;
         else
             throw new ApplicationException("Eval parse error at wrong index location. Input string '" + input + "' and expected error at index '" + errorIndex.ToString() + "' but found at '" + pe.Index.ToString() + "'.");
     }
 }
        public static void TestEvalSuccess(string input, TypeCode resultCode, object resultValue, object thisArray, Language language)
        {
            Eval eval = new Eval(input, language);
            EvalResult result = eval.Evaluate(thisArray);

            if ((resultCode != result.Type) ||                             
                ((resultValue == null) && (result.Value != null)) ||       
                ((result.Value != null) && (Type.GetTypeCode(resultValue.GetType()) != resultCode)))   
                throw new ApplicationException("Eval result type incorrect. Expected '" + resultCode.ToString() + "' but received '" + result.Type.ToString() + "' for input string '" + input + "'.");
            else
            {
                // Check result specific value
                switch (resultCode)
                {
                    case TypeCode.Boolean:
                        if ((Boolean)resultValue == (Boolean)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Byte:
                        if ((Byte)resultValue == (Byte)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Char:
                        if ((Char)resultValue == (Char)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.DateTime:
                        if ((DateTime)resultValue == (DateTime)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.DBNull:
                        if ((DBNull)resultValue == (DBNull)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Decimal:
                        if ((Decimal)resultValue == (Decimal)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Double:
                        if ((Double)resultValue == (Double)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Empty:
                        if (resultValue == null)
                            return;
                        else
                            break;
                    case TypeCode.Int16:
                        if ((Int16)resultValue == (Int16)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Int32:
                        if ((Int32)resultValue == (Int32)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Int64:
                        if ((Int64)resultValue == (Int64)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Object:
                        if (resultValue == result.Value)
                            return;
                        else
                            break;
                    case TypeCode.SByte:
                        if ((SByte)resultValue == (SByte)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.Single:
                        if ((Single)resultValue == (Single)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.String:
                        if ((String)resultValue == (String)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.UInt16:
                        if ((UInt16)resultValue == (UInt16)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.UInt32:
                        if ((UInt32)resultValue == (UInt32)result.Value)
                            return;
                        else
                            break;
                    case TypeCode.UInt64:
                        if ((UInt64)resultValue == (UInt64)result.Value)
                            return;
                        else
                            break;
                }

                throw new ApplicationException("Eval result value incorrect. Expected '" + resultValue.ToString() + "' but received '" + result.Value.ToString() + "' for input string '" + input + "'.");
            }
        }