static ISymbolValue HandleSingleMathOp(OperatorBasedExpression x, ISemantic l, ISemantic r, MathOp2 m, bool UnorderedCheck = true)
        {
            if (l == null || r == null)
            {
                return(null);
            }

            var pl = l as PrimitiveValue;
            var pr = r as PrimitiveValue;

            //TODO: imaginary/complex parts

            if (pl != null && pr != null)
            {
                if (UnorderedCheck && (pl.IsNaN || pr.IsNaN))
                {
                    return(PrimitiveValue.CreateNaNValue(x, pl.IsNaN ? pl.BaseTypeToken : pr.BaseTypeToken));
                }

                return(m(pl, pr, x));
            }

            return(null);
            //throw new NotImplementedException("Operator overloading not implemented yet.");
        }
        ISemantic E(OperatorBasedExpression x, ISemantic lValue=null)
        {
            if (x is AssignExpression)
                return E((AssignExpression)x,lValue);

            // TODO: Implement operator precedence (see http://forum.dlang.org/thread/[email protected] )

            if (x is XorExpression || // a ^ b
                x is OrExpression || // a | b
                x is AndExpression || // a & b
                x is ShiftExpression || // a << 8
                x is AddExpression || // a += b; a -= b;
                x is MulExpression || // a *= b; a /= b; a %= b;
                x is CatExpression || // a ~= b;
                x is PowExpression) // a ^^ b;
                return E_MathOp(x, lValue);

            else if (x is EqualExpression) // a==b
                return E((EqualExpression)x, lValue);

            else if (x is OrOrExpression || // a || b
                x is AndAndExpression || // a && b
                x is IdendityExpression || // a is T
                x is RelExpression) // a <= b
                return E_BoolOp(x, lValue as ISymbolValue);

            else if (x is InExpression) // a in b
                return E((InExpression)x, lValue);

            throw new WrongEvaluationArgException();
        }
Пример #3
0
        AbstractType OpExpressionType(OperatorBasedExpression x)
        {
            var t = x.LeftOperand != null?x.LeftOperand.Accept(this) : null;

            if (t != null)
            {
                return(t);
            }

            return(x.RightOperand != null?x.RightOperand.Accept(this) : null);
        }
        static PrimitiveValue mult(PrimitiveValue a, PrimitiveValue b, OperatorBasedExpression x)
        {
            decimal v  = 0;
            decimal im = 0;

            switch (x.OperatorToken)
            {
            case DTokens.Pow:
                v = (decimal)Math.Pow((double)a.Value, (double)b.Value);
                v = (decimal)Math.Pow((double)a.ImaginaryPart, (double)b.ImaginaryPart);
                break;

            case DTokens.Times:
                v  = a.Value * b.Value;
                im = a.ImaginaryPart * b.ImaginaryPart;
                break;

            case DTokens.Div:
                if ((a.Value != 0 && b.Value == 0) || (a.ImaginaryPart != 0 && b.ImaginaryPart == 0))
                {
                    throw new DivideByZeroException();
                }
                if (b.Value != 0)
                {
                    v = a.Value / b.Value;
                }
                if (b.ImaginaryPart != 0)
                {
                    im = a.ImaginaryPart / b.ImaginaryPart;
                }
                break;

            case DTokens.Mod:
                if ((a.Value != 0 && b.Value == 0) || (a.ImaginaryPart != 0 && b.ImaginaryPart == 0))
                {
                    throw new DivideByZeroException();
                }
                if (b.Value != 0)
                {
                    v = a.Value % b.Value;
                }
                if (b.ImaginaryPart != 0)
                {
                    im = a.ImaginaryPart % b.ImaginaryPart;
                }
                break;

            default:
                return(null);
                //EvalError(x, "Invalid token for multiplication expression (*,/,% only)");
            }

            return(new PrimitiveValue(a.BaseTypeToken, v, x, im));
        }
Пример #5
0
        ulong VisitOpBasedExpression(OperatorBasedExpression op)
        {
            ulong hashCode = 0uL;

            unchecked
            {
                if (op.LeftOperand != null)
                {
                    hashCode += 1000000007 * op.LeftOperand.Accept(this);
                }
                if (op.RightOperand != null)
                {
                    hashCode += 1000000009 * op.RightOperand.Accept(this);
                }
                hashCode += 1000000021 * (ulong)op.OperatorToken;
            }
            return(hashCode);
        }
        ISemantic E(OperatorBasedExpression x, ISemantic lValue = null)
        {
            if (x is AssignExpression)
            {
                return(E((AssignExpression)x, lValue));
            }

            // TODO: Implement operator precedence (see http://forum.dlang.org/thread/[email protected] )

            if (x is XorExpression ||             // a ^ b
                x is OrExpression ||              // a | b
                x is AndExpression ||             // a & b
                x is ShiftExpression ||           // a << 8
                x is AddExpression ||             // a += b; a -= b;
                x is MulExpression ||             // a *= b; a /= b; a %= b;
                x is CatExpression ||             // a ~= b;
                x is PowExpression)               // a ^^ b;
            {
                return(E_MathOp(x, lValue));
            }

            else if (x is EqualExpression)             // a==b
            {
                return(E((EqualExpression)x, lValue));
            }

            else if (x is OrOrExpression ||         // a || b
                     x is AndAndExpression ||       // a && b
                     x is IdendityExpression ||     // a is T
                     x is RelExpression)            // a <= b
            {
                return(E_BoolOp(x, lValue as ISymbolValue));
            }

            else if (x is InExpression)             // a in b
            {
                return(E((InExpression)x, lValue));
            }

            throw new WrongEvaluationArgException();
        }
        static PrimitiveValue mult(PrimitiveValue a, PrimitiveValue b, OperatorBasedExpression x)
        {
            decimal v = 0;
            decimal im=0;
            switch (x.OperatorToken)
            {
                case DTokens.Pow:
                    v = (decimal)Math.Pow((double)a.Value, (double)b.Value);
                    v = (decimal)Math.Pow((double)a.ImaginaryPart, (double)b.ImaginaryPart);
                    break;
                case DTokens.Times:
                    v= a.Value * b.Value;
                    im=a.ImaginaryPart * b.ImaginaryPart;
                    break;
                case DTokens.Div:
                    if ((a.Value!=0 && b.Value == 0) || (a.ImaginaryPart!=0 && b.ImaginaryPart==0))
                        throw new DivideByZeroException();
                    if(b.Value!=0)
                        v= a.Value / b.Value;
                    if(b.ImaginaryPart!=0)
                        im=a.ImaginaryPart / b.ImaginaryPart;
                    break;
                case DTokens.Mod:
                    if ((a.Value!=0 && b.Value == 0) || (a.ImaginaryPart!=0 && b.ImaginaryPart==0))
                        throw new DivideByZeroException();
                    if(b.Value!=0)
                        v= a.Value % b.Value;
                    if(b.ImaginaryPart!=0)
                        im=a.ImaginaryPart % b.ImaginaryPart;
                    break;
                default:
                    return null;
                    //EvalError(x, "Invalid token for multiplication expression (*,/,% only)");
            }

            return new PrimitiveValue(a.BaseTypeToken, v, x, im);
        }
		public virtual void VisitOpBasedExpression(OperatorBasedExpression ox)
		{
			VisitChildren(ox);
		}
		ISymbolValue E_BoolOp(OperatorBasedExpression x)
		{
			var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null);
			var rValue = this.rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null);

			this.lValue = null;
			this.rValue = null;

			var l = TryGetValue(lValue);
			var r = TryGetValue(rValue);

			if (x is OrOrExpression)
			{
				// The OrOrExpression evaluates its left operand. 
				// If the left operand, converted to type bool, evaluates to true, 
				// then the right operand is not evaluated. If the result type of the OrOrExpression 
				// is bool then the result of the expression is true. 
				// If the left operand is false, then the right operand is evaluated. 
				// If the result type of the OrOrExpression is bool then the result 
				// of the expression is the right operand converted to type bool.
				return new PrimitiveValue(!(IsFalseZeroOrNull(l) && IsFalseZeroOrNull(r)));
			}
			else if (x is AndAndExpression)
				return new PrimitiveValue(!IsFalseZeroOrNull(l) && !IsFalseZeroOrNull(r));
			else if (x is IdentityExpression)
			{
				// http://dlang.org/expression.html#IdentityExpression
			}
			else if (x is RelExpression)
			{
				return HandleSingleMathOp(x, l, r, (a,b, op) => {

					// Unordered-ness is when at least one operator is Not any Number (NaN)
					bool unordered = a.IsNaN || b.IsNaN;

					bool relationIsTrue=false;
					bool cmpIm = a.ImaginaryPart != 0 || b.ImaginaryPart != 0;

					switch(x.OperatorToken)
					{
						case DTokens.GreaterThan: // greater, >
							relationIsTrue = a.Value > b.Value && (!cmpIm || a.ImaginaryPart > b.ImaginaryPart);
							break;
						case DTokens.GreaterEqual: // greater or equal, >=
							relationIsTrue = a.Value >= b.Value && a.ImaginaryPart >= b.ImaginaryPart;
							break;
						case DTokens.LessThan: // less, <
							relationIsTrue = a.Value < b.Value && (!cmpIm || a.ImaginaryPart < b.ImaginaryPart);
							break;
						case DTokens.LessEqual: // less or equal, <=
							relationIsTrue = a.Value <= b.Value && a.ImaginaryPart <= b.ImaginaryPart;
							break;
						case DTokens.Unordered: // unordered, !<>=
							relationIsTrue = unordered;
							break;
						case DTokens.LessOrGreater: // less or greater, <>
							relationIsTrue = (a.Value < b.Value || a.Value > b.Value) && (!cmpIm || (a.ImaginaryPart < b.ImaginaryPart || a.ImaginaryPart > b.ImaginaryPart));
							break;
						case DTokens.LessEqualOrGreater: // less, equal, or greater, <>=
							relationIsTrue = (a.Value < b.Value || a.Value >= b.Value) && (!cmpIm || (a.ImaginaryPart < b.ImaginaryPart || a.ImaginaryPart >= b.ImaginaryPart));
							break;
						case DTokens.UnorderedOrGreater: // unordered or greater, !<=
							relationIsTrue = unordered || (a.Value > b.Value && (!cmpIm || a.ImaginaryPart > b.ImaginaryPart));
							break;
						case DTokens.UnorderedGreaterOrEqual: // unordered, greater, or equal, !<
							relationIsTrue = unordered || (a.Value >= b.Value && a.ImaginaryPart >= b.ImaginaryPart);
							break;
						case DTokens.UnorderedOrLess: // unordered or less, !>=
							relationIsTrue = unordered || (a.Value < b.Value && (!cmpIm || a.ImaginaryPart < b.ImaginaryPart));
							break;
						case DTokens.UnorderedLessOrEqual: // unordered, less, or equal, !>
							relationIsTrue = unordered || (a.Value <= b.Value && a.ImaginaryPart <= b.ImaginaryPart);
							break;
						case DTokens.UnorderedOrEqual: // unordered or equal, !<>
							relationIsTrue = unordered || (a.Value == b.Value && a.ImaginaryPart == b.ImaginaryPart);
							break;
					}

					return new PrimitiveValue(relationIsTrue);
				}, false);
			}

			EvalError(x, "Wrong expression");
			return null;
		}
		static ISymbolValue HandleSingleMathOp(OperatorBasedExpression x, ISemantic l, ISemantic r, MathOp2 m, bool UnorderedCheck = true)
		{
			if(l == null || r == null)
				return null;
			
			var pl = l as PrimitiveValue;
			var pr = r as PrimitiveValue;

			//TODO: imaginary/complex parts

			if (pl != null && pr != null)
			{
				if (UnorderedCheck && (pl.IsNaN || pr.IsNaN))
					return PrimitiveValue.CreateNaNValue(pl.IsNaN ? pl.BaseTypeToken : pr.BaseTypeToken, pl.IsNaN ? pl.Modifier : pr.Modifier);

				return m(pl, pr, x);
			}

			return null;
			//throw new NotImplementedException("Operator overloading not implemented yet.");
		}
		/// <summary>
		/// a + b; a - b; etc.
		/// </summary>
		ISymbolValue E_MathOp(OperatorBasedExpression x)
		{
			var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null);
			var rValue = this.rValue;

			this.lValue = null;
			this.rValue = null;

			var l = TryGetValue(lValue);

			if (l == null)
			{
				/*
				 * In terms of adding opOverloading later on, 
				 * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to
				 * search the type of l for methods called opAdd etc. and call that method via ctfe.
				 * Finally, return the value the opAdd method passed back - and everything is fine.
				 */

				/*
				 * Also, pointers should be implemented later on.
				 * http://dlang.org/expression.html#AddExpression
				 */

				EvalError(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", new[]{lValue});
				return null;
			}

			//TODO: Operator overloading

			// Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c !
			if (x is MulExpression || x is PowExpression)
			{
				try{
				if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression)) //TODO: This must be true only if it's a math expression, so not an assign expression etc.
				{
					var sx = (OperatorBasedExpression)x.RightOperand;

					// Now multiply/divide/mod expression 'l' with sx.LeftOperand
					try{
					this.lValue = HandleSingleMathOp(x, l, sx.LeftOperand != null ? sx.LeftOperand.Accept(this) : null, mult);

					// afterwards, evaluate the operation between the result just returned and the sx.RightOperand.
					return sx.Accept(this);
					}catch(DivideByZeroException)
					{
						EvalError(sx, "Divide by 0");
						return null;
					}
				}

				return HandleSingleMathOp(x, l, TryGetValue(rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null)), mult);
				}catch(DivideByZeroException)
				{
					EvalError(x, "Divide by 0");
					return null;
				}
			}
			else if (x is CatExpression)
			{
				return EvalConcatenation(x as CatExpression, l);
			}

			var r = TryGetValue(rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null));

			if(r == null){
				EvalError(x, "Right operand must evaluate to a value", new[]{rValue});
				return null;
			}

			/*
			 * TODO: Handle invalid values/value ranges.
			 */
			Evaluation ev = this;

			if (x is XorExpression)
			{
				return HandleSingleMathOp(x, l,r, (a,b)=> {
					if(ev.EnsureIntegralType(x.LeftOperand,a) && ev.EnsureIntegralType(x.RightOperand,b))
						return (long)a.Value ^ (long)b.Value;
					return 0L;
				});
			}
			else if (x is OrExpression)
			{
				return HandleSingleMathOp(x, l, r, (a, b) => {
					if(ev.EnsureIntegralType(x.LeftOperand,a) && ev.EnsureIntegralType(x.RightOperand,b))
						return (long)a.Value | (long)b.Value;
                  	return 0L;
				});
			}
			else if (x is AndExpression)
			{
				return HandleSingleMathOp(x, l, r, (a, b) => {
					if(ev.EnsureIntegralType(x.LeftOperand,a) && ev.EnsureIntegralType(x.RightOperand,b))
												return (long)a.Value & (long)b.Value;
				                          	return 0L;
				});
			}
			else if (x is ShiftExpression) 
				return HandleSingleMathOp(x, l, r, (a, b) => {
					if(!ev.EnsureIntegralType(x.LeftOperand, a) || !ev.EnsureIntegralType(x.RightOperand, b))
				                          		return 0L;
					if (b.Value < 0 || b.Value > 31){
						ev.EvalError(x, "Shift operand must be between 0 and 31", new[]{b});
						return 0m;
					}

					switch(x.OperatorToken)
					{
						case DTokens.ShiftLeft:
							return (long)a.Value << (int)b.Value; // TODO: Handle the imaginary part
						case DTokens.ShiftRight:
							return (long)a.Value >> (int)b.Value;
						case DTokens.ShiftRightUnsigned: //TODO: Find out where's the difference between >> and >>>
							return (ulong)a.Value >> (int)(uint)b.Value;
					}

					ev.EvalError(x, "Invalid token for shift expression", new[]{l,r});
					return 0m;
				});
			else if (x is AddExpression)
				return HandleSingleMathOp(x, l, r, (a, b, op) =>
				{
					switch (op.OperatorToken)
					{
						case DTokens.Plus:
							return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, a.ImaginaryPart + b.ImaginaryPart, a.Modifier);
						case DTokens.Minus:
							return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, a.ImaginaryPart - b.ImaginaryPart, a.Modifier);
					}

					ev.EvalError(op, "Invalid token for add/sub expression", new[]{l,r});
					return null;
				});
			
			throw new WrongEvaluationArgException();
		}
Пример #12
0
 public virtual void VisitOpBasedExpression(OperatorBasedExpression ox)
 {
     VisitChildren(ox);
 }
        ISemantic E_BoolOp(OperatorBasedExpression x, ISemantic lValue = null, ISemantic rValue = null)
        {
            if (!eval)
            {
                return(new PrimitiveType(DTokens.Bool));
            }

            var l = TryGetValue(lValue ?? E(x.LeftOperand));
            var r = TryGetValue(rValue ?? E(x.RightOperand));

            if (x is OrOrExpression)
            {
                // The OrOrExpression evaluates its left operand.
                // If the left operand, converted to type bool, evaluates to true,
                // then the right operand is not evaluated. If the result type of the OrOrExpression
                // is bool then the result of the expression is true.
                // If the left operand is false, then the right operand is evaluated.
                // If the result type of the OrOrExpression is bool then the result
                // of the expression is the right operand converted to type bool.
                return(new PrimitiveValue(!(IsFalseZeroOrNull(l) && IsFalseZeroOrNull(r)), x));
            }
            else if (x is AndAndExpression)
            {
                return(new PrimitiveValue(!IsFalseZeroOrNull(l) && !IsFalseZeroOrNull(r), x));
            }
            else if (x is IdendityExpression)
            {
                // http://dlang.org/expression.html#IdentityExpression
            }
            else if (x is RelExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b, op) => {
                    // Unordered-ness is when at least one operator is Not any Number (NaN)
                    bool unordered = a.IsNaN || b.IsNaN;

                    bool relationIsTrue = false;
                    bool cmpIm = a.ImaginaryPart != 0 || b.ImaginaryPart != 0;

                    switch (x.OperatorToken)
                    {
                    case DTokens.GreaterThan:                             // greater, >
                        relationIsTrue = a.Value > b.Value && (cmpIm ? a.ImaginaryPart > b.ImaginaryPart : true);
                        break;

                    case DTokens.GreaterEqual:                             // greater or equal, >=
                        relationIsTrue = a.Value >= b.Value && a.ImaginaryPart >= b.ImaginaryPart;
                        break;

                    case DTokens.LessThan:                             // less, <
                        relationIsTrue = a.Value < b.Value && (cmpIm ? a.ImaginaryPart < b.ImaginaryPart : true);
                        break;

                    case DTokens.LessEqual:                             // less or equal, <=
                        relationIsTrue = a.Value <= b.Value && a.ImaginaryPart <= b.ImaginaryPart;
                        break;

                    case DTokens.Unordered:                             // unordered, !<>=
                        relationIsTrue = unordered;
                        break;

                    case DTokens.LessOrGreater:                             // less or greater, <>
                        relationIsTrue = (a.Value <b.Value || a.Value> b.Value) && (cmpIm ?
                                                                                    (a.ImaginaryPart <b.ImaginaryPart || a.ImaginaryPart> b.ImaginaryPart) : true);
                        break;

                    case DTokens.LessEqualOrGreater:                             // less, equal, or greater, <>=
                        relationIsTrue = (a.Value < b.Value || a.Value >= b.Value) && (cmpIm ?
                                                                                       (a.ImaginaryPart < b.ImaginaryPart || a.ImaginaryPart >= b.ImaginaryPart) : true);
                        break;

                    case DTokens.UnorderedOrGreater:                             // unordered or greater, !<=
                        relationIsTrue = unordered || (a.Value > b.Value && (cmpIm ? a.ImaginaryPart > b.ImaginaryPart : true));
                        break;

                    case DTokens.UnorderedGreaterOrEqual:                             // unordered, greater, or equal, !<
                        relationIsTrue = unordered || (a.Value >= b.Value && a.ImaginaryPart >= b.ImaginaryPart);
                        break;

                    case DTokens.UnorderedOrLess:                             // unordered or less, !>=
                        relationIsTrue = unordered || (a.Value < b.Value && (cmpIm ? a.ImaginaryPart < b.ImaginaryPart : true));
                        break;

                    case DTokens.UnorderedLessOrEqual:                             // unordered, less, or equal, !>
                        relationIsTrue = unordered || (a.Value <= b.Value && a.ImaginaryPart <= b.ImaginaryPart);
                        break;

                    case DTokens.UnorderedOrEqual:                             // unordered or equal, !<>
                        relationIsTrue = unordered || (a.Value == b.Value && a.ImaginaryPart == b.ImaginaryPart);
                        break;
                    }

                    return new PrimitiveValue(relationIsTrue, op);
                }, false));
            }

            throw new WrongEvaluationArgException();
        }
        /// <summary>
        /// a + b; a - b; etc.
        /// </summary>
        ISemantic E_MathOp(OperatorBasedExpression x, ISemantic lValue = null, ISemantic rValue = null)
        {
            if (!eval)
            {
                return(lValue ?? E(x.LeftOperand));
            }

            var l = TryGetValue(lValue ?? E(x.LeftOperand));

            if (l == null)
            {
                /*
                 * In terms of adding opOverloading later on,
                 * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to
                 * search the type of l for methods called opAdd etc. and call that method via ctfe.
                 * Finally, return the value the opAdd method passed back - and everything is fine.
                 */

                /*
                 * Also, pointers should be implemented later on.
                 * http://dlang.org/expression.html#AddExpression
                 */

                EvalError(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", new[] { lValue });
                return(null);
            }

            //TODO: Operator overloading

            // Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c !
            if (x is MulExpression || x is PowExpression)
            {
                try{
                    if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression))             //TODO: This must be true only if it's a math expression, so not an assign expression etc.
                    {
                        var sx = (OperatorBasedExpression)x.RightOperand;

                        // Now multiply/divide/mod expression 'l' with sx.LeftOperand
                        try{
                            var intermediateResult = HandleSingleMathOp(x, l, E(sx.LeftOperand), mult);

                            // afterwards, evaluate the operation between the result just returned and the sx.RightOperand.
                            return(E(sx, intermediateResult));
                        }catch (DivideByZeroException)
                        {
                            EvalError(sx, "Divide by 0");
                            return(null);
                        }
                    }

                    return(HandleSingleMathOp(x, l, TryGetValue(rValue ?? E(x.RightOperand)), mult));
                }catch (DivideByZeroException)
                {
                    EvalError(x, "Divide by 0");
                    return(null);
                }
            }
            else if (x is CatExpression)
            {
                return(EvalConcatenation(x as CatExpression, l));
            }

            var r = TryGetValue(rValue ?? E(x.RightOperand));

            if (r == null)
            {
                EvalError(x, "Right operand must evaluate to a value", new[] { lValue });
                return(null);
            }

            /*
             * TODO: Handle invalid values/value ranges.
             */

            if (x is XorExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) => {
                    if (EnsureIntegralType(x.LeftOperand, a) && EnsureIntegralType(x.RightOperand, b))
                    {
                        return (long)a.Value ^ (long)b.Value;
                    }
                    return 0L;
                }));
            }
            else if (x is OrExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    if (EnsureIntegralType(x.LeftOperand, a) && EnsureIntegralType(x.RightOperand, b))
                    {
                        return (long)a.Value | (long)b.Value;
                    }
                    return 0L;
                }));
            }
            else if (x is AndExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    if (EnsureIntegralType(x.LeftOperand, a) && EnsureIntegralType(x.RightOperand, b))
                    {
                        return (long)a.Value & (long)b.Value;
                    }
                    return 0L;
                }));
            }
            else if (x is ShiftExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    if (!EnsureIntegralType(x.LeftOperand, a) || !EnsureIntegralType(x.RightOperand, b))
                    {
                        return 0L;
                    }
                    if (b.Value < 0 || b.Value > 31)
                    {
                        EvalError(x, "Shift operand must be between 0 and 31", new[] { b });
                        return 0m;
                    }

                    switch (x.OperatorToken)
                    {
                    case DTokens.ShiftLeft:
                        return (long)a.Value << (int)b.Value;                                 // TODO: Handle the imaginary part

                    case DTokens.ShiftRight:
                        return (long)a.Value >> (int)b.Value;

                    case DTokens.ShiftRightUnsigned:                             //TODO: Find out where's the difference between >> and >>>
                        return (ulong)a.Value >> (int)(uint)b.Value;
                    }

                    EvalError(x, "Invalid token for shift expression", new[] { l, r });
                    return 0m;
                }));
            }
            else if (x is AddExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b, op) =>
                {
                    switch (op.OperatorToken)
                    {
                    case DTokens.Plus:
                        return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, x, a.ImaginaryPart + b.ImaginaryPart);

                    case DTokens.Minus:
                        return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, x, a.ImaginaryPart - b.ImaginaryPart);
                    }

                    EvalError(x, "Invalid token for add/sub expression", new[] { l, r });
                    return null;
                }));
            }

            throw new WrongEvaluationArgException();
        }
        /// <summary>
        /// a + b; a - b; etc.
        /// </summary>
        ISemantic E_MathOp(OperatorBasedExpression x, ISemantic lValue = null, ISemantic rValue = null)
        {
            if (!eval)
            {
                return(lValue ?? E(x.LeftOperand));
            }

            var l = TryGetValue(lValue ?? E(x.LeftOperand));

            if (l == null)
            {
                /*
                 * In terms of adding opOverloading later on,
                 * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to
                 * search the type of l for methods called opAdd etc. and call that method via ctfe.
                 * Finally, return the value the opAdd method passed back - and everything is fine.
                 */

                /*
                 * Also, pointers should be implemented later on.
                 * http://dlang.org/expression.html#AddExpression
                 */

                throw new EvaluationException(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", lValue);
            }

            //TODO: Operator overloading

            // Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c !
            if (x is MulExpression || x is PowExpression)
            {
                if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression))                 //TODO: This must be true only if it's a math expression, so not an assign expression etc.
                {
                    var sx = (OperatorBasedExpression)x.RightOperand;

                    // Now multiply/divide/mod expression 'l' with sx.LeftOperand
                    var intermediateResult = HandleSingleMathOp(x, l, E(sx.LeftOperand), mult);

                    // afterwards, evaluate the operation between the result just returned and the sx.RightOperand.
                    return(E(sx, intermediateResult));
                }

                return(HandleSingleMathOp(x, l, rValue ?? E(x.RightOperand), mult));
            }

            var r = TryGetValue(rValue ?? E(x.RightOperand));

            if (r == null)
            {
                throw new EvaluationException(x, "Right operand must evaluate to a value", lValue);
            }

            /*
             * TODO: Handle invalid values/value ranges.
             */

            if (x is XorExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) => {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value ^ (long)b.Value;
                }));
            }
            else if (x is OrExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value | (long)b.Value;
                }));
            }
            else if (x is AndExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value & (long)b.Value;
                }));
            }
            else if (x is ShiftExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    if (b.Value < 0 || b.Value > 31)
                    {
                        throw new EvaluationException(b.BaseExpression, "Shift operand must be between 0 and 31", b);
                    }

                    switch (x.OperatorToken)
                    {
                    case DTokens.ShiftLeft:
                        return (long)a.Value << (int)b.Value;                                 // TODO: Handle the imaginary part

                    case DTokens.ShiftRight:
                        return (long)a.Value >> (int)b.Value;

                    case DTokens.ShiftRightUnsigned:                             //TODO: Find out where's the difference between >> and >>>
                        return (ulong)a.Value >> (int)(uint)b.Value;
                    }

                    throw new EvaluationException(x, "Invalid token for shift expression", l, r);
                }));
            }
            else if (x is AddExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b, op) =>
                {
                    switch (op.OperatorToken)
                    {
                    case DTokens.Plus:
                        return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, x, a.ImaginaryPart + b.ImaginaryPart);

                    case DTokens.Minus:
                        return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, x, a.ImaginaryPart - b.ImaginaryPart);
                    }

                    throw new EvaluationException(x, "Invalid token for add/sub expression", l, r);
                }));
            }
            else if (x is CatExpression)
            {
                // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array

                var av_l = l as ArrayValue;
                var av_r = r as ArrayValue;

                if (av_l != null && av_r != null)
                {
                    // Ensure that both arrays are of the same type
                    if (!ResultComparer.IsEqual(av_l.RepresentedType, av_r.RepresentedType))
                    {
                        throw new EvaluationException(x, "Both arrays must be of same type", l, r);
                    }

                    // Might be a string
                    if (av_l.IsString && av_r.IsString)
                    {
                        return(new ArrayValue(av_l.RepresentedType as ArrayType, x, av_l.StringValue + av_r.StringValue));
                    }
                    else
                    {
                        var elements = new ISymbolValue[av_l.Elements.Length + av_r.Elements.Length];
                        Array.Copy(av_l.Elements, 0, elements, 0, av_l.Elements.Length);
                        Array.Copy(av_r.Elements, 0, elements, av_l.Elements.Length, av_r.Elements.Length);

                        return(new ArrayValue(av_l.RepresentedType as ArrayType, elements));
                    }
                }

                ArrayType at = null;

                // Append the right value to the array
                if (av_l != null && (at = av_l.RepresentedType as ArrayType) != null &&
                    ResultComparer.IsImplicitlyConvertible(r.RepresentedType, at.ValueType, ctxt))
                {
                    var elements = new ISymbolValue[av_l.Elements.Length + 1];
                    Array.Copy(av_l.Elements, elements, av_l.Elements.Length);
                    elements[elements.Length - 1] = r;

                    return(new ArrayValue(at, elements));
                }
                // Put the left value into the first position
                else if (av_r != null && (at = av_r.RepresentedType as ArrayType) != null &&
                         ResultComparer.IsImplicitlyConvertible(l.RepresentedType, at.ValueType, ctxt))
                {
                    var elements = new ISymbolValue[1 + av_r.Elements.Length];
                    elements[0] = l;
                    Array.Copy(av_r.Elements, 0, elements, 1, av_r.Elements.Length);

                    return(new ArrayValue(at, elements));
                }

                throw new EvaluationException(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", l, r);
            }

            throw new WrongEvaluationArgException();
        }
        /// <summary>
        /// a + b; a - b; etc.
        /// </summary>
        ISemantic E_MathOp(OperatorBasedExpression x, ISemantic lValue=null, ISemantic rValue=null)
        {
            if (!eval)
                return lValue ?? E(x.LeftOperand);

            var l = TryGetValue(lValue ?? E(x.LeftOperand));

            if (l == null)
            {
                /*
                 * In terms of adding opOverloading later on,
                 * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to
                 * search the type of l for methods called opAdd etc. and call that method via ctfe.
                 * Finally, return the value the opAdd method passed back - and everything is fine.
                 */

                /*
                 * Also, pointers should be implemented later on.
                 * http://dlang.org/expression.html#AddExpression
                 */

                throw new EvaluationException(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", lValue);
            }

            //TODO: Operator overloading

            // Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c !
            if (x is MulExpression || x is PowExpression)
            {
                if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression)) //TODO: This must be true only if it's a math expression, so not an assign expression etc.
                {
                    var sx = (OperatorBasedExpression)x.RightOperand;

                    // Now multiply/divide/mod expression 'l' with sx.LeftOperand
                    var intermediateResult = HandleSingleMathOp(x, l, E(sx.LeftOperand), mult);

                    // afterwards, evaluate the operation between the result just returned and the sx.RightOperand.
                    return E(sx, intermediateResult);
                }

                return HandleSingleMathOp(x, l, rValue ?? E(x.RightOperand), mult);
            }

            var r = TryGetValue(rValue ?? E(x.RightOperand));

            if(r == null)
                throw new EvaluationException(x, "Right operand must evaluate to a value", lValue);

            /*
             * TODO: Handle invalid values/value ranges.
             */

            if (x is XorExpression)
            {
                return HandleSingleMathOp(x, l,r, (a,b)=>{
                    EnsureIntegralType(a);EnsureIntegralType(b);
                    return (long)a.Value ^ (long)b.Value;
                });
            }
            else if (x is OrExpression)
            {
                return HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value | (long)b.Value;
                });
            }
            else if (x is AndExpression)
            {
                return HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value & (long)b.Value;
                });
            }
            else if (x is ShiftExpression)
                return HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    if (b.Value < 0 || b.Value > 31)
                        throw new EvaluationException(b.BaseExpression, "Shift operand must be between 0 and 31", b);

                    switch(x.OperatorToken)
                    {
                        case DTokens.ShiftLeft:
                            return (long)a.Value << (int)b.Value; // TODO: Handle the imaginary part
                        case DTokens.ShiftRight:
                            return (long)a.Value >> (int)b.Value;
                        case DTokens.ShiftRightUnsigned: //TODO: Find out where's the difference between >> and >>>
                            return (ulong)a.Value >> (int)(uint)b.Value;
                    }

                    throw new EvaluationException(x, "Invalid token for shift expression", l,r);
                });
            else if (x is AddExpression)
                return HandleSingleMathOp(x, l, r, (a, b, op) =>
                {
                    switch (op.OperatorToken)
                    {
                        case DTokens.Plus:
                            return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, x, a.ImaginaryPart + b.ImaginaryPart);
                        case DTokens.Minus:
                            return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, x, a.ImaginaryPart - b.ImaginaryPart);
                    }

                    throw new EvaluationException(x, "Invalid token for add/sub expression", l, r);
                });
            else if (x is CatExpression)
            {
                // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array

                var av_l = l as ArrayValue;
                var av_r = r as ArrayValue;

                if (av_l!=null && av_r!=null)
                {
                    // Ensure that both arrays are of the same type
                    if(!ResultComparer.IsEqual(av_l.RepresentedType, av_r.RepresentedType))
                        throw new EvaluationException(x, "Both arrays must be of same type", l,r);

                    // Might be a string
                    if (av_l.IsString && av_r.IsString)
                        return new ArrayValue(av_l.RepresentedType as ArrayType, x, av_l.StringValue + av_r.StringValue);
                    else
                    {
                        var elements = new ISymbolValue[av_l.Elements.Length + av_r.Elements.Length];
                        Array.Copy(av_l.Elements, 0, elements, 0, av_l.Elements.Length);
                        Array.Copy(av_r.Elements, 0, elements, av_l.Elements.Length, av_r.Elements.Length);

                        return new ArrayValue(av_l.RepresentedType as ArrayType, elements);
                    }
                }

                ArrayType at = null;

                // Append the right value to the array
                if (av_l!=null &&  (at=av_l.RepresentedType as ArrayType) != null &&
                    ResultComparer.IsImplicitlyConvertible(r.RepresentedType, at.ValueType, ctxt))
                {
                    var elements = new ISymbolValue[av_l.Elements.Length + 1];
                    Array.Copy(av_l.Elements, elements, av_l.Elements.Length);
                    elements[elements.Length - 1] = r;

                    return new ArrayValue(at, elements);
                }
                // Put the left value into the first position
                else if (av_r != null && (at = av_r.RepresentedType as ArrayType) != null &&
                    ResultComparer.IsImplicitlyConvertible(l.RepresentedType, at.ValueType, ctxt))
                {
                    var elements = new ISymbolValue[1 + av_r.Elements.Length];
                    elements[0] = l;
                    Array.Copy(av_r.Elements,0,elements,1,av_r.Elements.Length);

                    return new ArrayValue(at, elements);
                }

                throw new EvaluationException(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", l, r);
            }

            throw new WrongEvaluationArgException();
        }