protected override ICode VisitBinary(ExprBinary e) {
     var ctx = e.Ctx;
     // Special cases for == and != needed as an empty string is false, not true
     if (e.Op == BinaryOp.Equal) {
         if (e.Left.IsLiteralNull()) {
             if (e.Right.IsVar() && e.Right.Type.IsValueType && !e.Right.Type.IsNullable()) {
                 return ctx.Literal(false); // Non-nullable Value-type can never be null
             } else {
                 return new ExprJsExplicit(ctx, "(e == null)", ctx.Boolean, e.Right.Named("e"));
             }
         }
         if (e.Right.IsLiteralNull()) {
             if (e.Left.IsVar() && e.Left.Type.IsValueType && !e.Left.Type.IsNullable()) {
                 return ctx.Literal(false); // Non-nullable Value-type can never be null
             } else {
                 return new ExprJsExplicit(ctx, "(e == null)", ctx.Boolean, e.Left.Named("e"));
             }
         }
     }
     if (e.Op == BinaryOp.NotEqual || e.Op == BinaryOp.GreaterThan_Un) {
         if (e.Left.IsLiteralNull()) {
             if (e.Right.IsVar() && e.Right.Type.IsValueType && !e.Right.Type.IsNullable()) {
                 return ctx.Literal(true); // Non-nullable Value-type can never be null
             } else {
                 return new ExprJsExplicit(ctx, "(e != null)", ctx.Boolean, e.Right.Named("e"));
             }
         }
         if (e.Right.IsLiteralNull()) {
             if (e.Left.IsVar() && e.Left.Type.IsValueType && !e.Left.Type.IsNullable()) {
                 return ctx.Literal(true); // Non-nullable Value-type can never be null
             } else {
                 return new ExprJsExplicit(ctx, "(e != null)", ctx.Boolean, e.Left.Named("e"));
             }
         }
     }
     // Special case for eq and neq with unsigned integer types.
     // If either side of the eq/neq is unsigned, then ensure that both sides are unsigned
     if (e.Op == BinaryOp.Equal || e.Op == BinaryOp.NotEqual) {
         if (e.Left.Type.IsUnsignedInteger()) {
             if (e.Right.Type.IsSignedInteger()) {
                 return new ExprBinary(ctx, e.Op, e.Type, e.Left, new ExprConv(ctx, e.Right, e.Left.Type, false));
             }
         } else if (e.Right.Type.IsUnsignedInteger()) {
             if (e.Left.Type.IsSignedInteger()) {
                 return new ExprBinary(ctx, e.Op, e.Type, new ExprConv(ctx, e.Left, e.Right.Type, false), e.Right);
             }
         }
     }
     // Special case for unsigned <, <=, >, >=
     // Force conversions to unsigned if either side is signed
     if (e.Op == BinaryOp.LessThan_Un || e.Op == BinaryOp.LessThanOrEqual_Un ||
         e.Op == BinaryOp.GreaterThan_Un || e.Op == BinaryOp.GreaterThanOrEqual_Un) {
         Expr newLeft = null, newRight = null;
         if (e.Left.Type.IsSignedInteger()) {
             newLeft = new ExprConv(ctx, e.Left, e.Left.Type.UnsignedEquivilent(ctx.TypeSystem), false);
         }
         if (e.Right.Type.IsSignedInteger()) {
             newRight = new ExprConv(ctx, e.Right, e.Right.Type.UnsignedEquivilent(ctx.TypeSystem), false);
         }
         if (newLeft != null || newRight != null) {
             return new ExprBinary(ctx, e.Op, e.Type, newLeft ?? e.Left, newRight ?? e.Right);
         }
     }
     return base.VisitBinary(e);
 }
 protected override ICode VisitBox(ExprBox e) {
     var ctx = e.Ctx;
     var expr = (Expr)this.Visit(e.Expr);
     if (e.Type.IsUnsignedInteger() && expr.Type.IsSignedInteger()) {
         expr = new ExprConv(ctx, expr, e.Type, false);
     }
     if (!e.Type.IsValueType) {
         // For ref-types 'box' does nothing
         return this.Visit(e.Expr);
     }
     var eType = new ExprJsTypeVarName(ctx, e.Type);
     if (e.Type.IsNullable()) {
         var exprIsVar = expr.IsVar();
         var innerType = e.Type.GetNullableInnerType();
         var temp = exprIsVar ? null : new ExprVarLocal(ctx, e.Type);
         var box = new ExprBox(ctx, temp ?? expr, innerType).Named("box");
         var nullableJs = exprIsVar ? "(expr !== null ? box : null)" : "((temp = expr) !== null ? box : null)";
         var nullableExpr = new ExprJsExplicit(ctx, nullableJs, innerType, temp.Named("temp"), expr.Named("expr"), box);
         return nullableExpr;
     } else {
         var deepCopyExpr = InternalFunctions.ValueTypeDeepCopyIfRequired(e.Type, () => (Expr)this.Visit(expr));
         var int2bool = e.Type.IsBoolean() && expr.Type.IsInteger() ? "!!" : "";
         var js = "{v:" + int2bool + "expr,_:type}";
         var ret = new ExprJsExplicit(ctx, js, e.Type, (deepCopyExpr ?? expr).Named("expr"), eType.Named("type"));
         return ret;
     }
 }
 protected override ICode VisitAssignment(ExprAssignment e) {
     var ctx = e.Ctx;
     var expr = (Expr)this.Visit(e.Expr);
     var target = (ExprVar)this.Visit(e.Target);
     if (target.Type.IsBoolean() && expr.Type.IsInteger()) {
         expr = new ExprJsExplicit(ctx, "!!expr", ctx.Boolean, expr.Named("expr"));
     } else if (target.Type.IsUnsignedInteger() && expr.Type.IsSignedInteger()) {
         expr = new ExprConv(ctx, expr, expr.Type.UnsignedEquivilent(ctx.TypeSystem), false);
     }
     if (expr != e.Expr || target != e.Target) {
         return new ExprAssignment(ctx, target, expr);
     } else {
         return e;
     }
 }
Example #4
0
 protected override ICode VisitConv(ExprConv e) {
     throw new InvalidOperationException("This should never occur");
 }
 protected override ICode VisitConv(ExprConv e) {
     this.code.AppendFormat("(conv:{0})", e.Type);
     this.Visit(e.Expr);
     return e;
 }
 private Expr InsertConvIfRequired(Expr expr, TypeReference requiredType) {
     if (requiredType.IsSame(expr.Type)) {
         return expr;
     }
     if (!requiredType.IsNumeric() || !expr.Type.IsNumeric()) {
         return expr;
     }
     var conv = new ExprConv(this.ctx, expr, requiredType, false);
     return conv;
 }
 private Stmt Conv(TypeReference convTo, bool forceFromUnsigned = false) {
     var expr = this.stack.Pop();
     var conv = new ExprConv(this.ctx, expr, convTo, forceFromUnsigned);
     return this.SsaLocalAssignment(conv);
 }
        protected override ICode VisitConv(ExprConv e) {
            var fromType = e.Expr.Type;
            var toType = e.Type;

            var fromTypeMetadataType = fromType.MetadataType;
            var toTypeMetadataType = toType.MetadataType;
            if (e.ForceFromUnsigned) {
                switch (fromTypeMetadataType) {
                case MetadataType.SByte: fromTypeMetadataType = MetadataType.Byte; break;
                case MetadataType.Int16: fromTypeMetadataType = MetadataType.UInt16; break;
                case MetadataType.Int32: fromTypeMetadataType = MetadataType.UInt32; break;
                case MetadataType.Int64: fromTypeMetadataType = MetadataType.UInt64; break;
                case MetadataType.IntPtr: fromTypeMetadataType = MetadataType.UIntPtr; break;
                }
            }
            if (fromTypeMetadataType == MetadataType.Char) {
                fromTypeMetadataType = MetadataType.UInt16;
            }
            if (toTypeMetadataType == MetadataType.Char) {
                toTypeMetadataType = MetadataType.UInt16;
            }

            var fromIdx = indexMap.ValueOrDefault(fromTypeMetadataType, -1);
            var toIdx = indexMap.ValueOrDefault(toTypeMetadataType, -1);

            if (fromIdx == -1 || toIdx == -1) {
                return e.Expr;
            }

            var ctx = e.Ctx;
            var js = jss[fromIdx, toIdx];
            if (js != null) {
                // In-place conversion
                var expr = new ExprJsExplicit(ctx, js, e.Type, e.Expr.Named("e"));
                return expr;
            } else {
                // Call conversion function
                var convMi = ((Func<int, int>)InternalFunctions.Conv<int, int>).Method.GetGenericMethodDefinition();
                var mConv = ctx.Module.Import(convMi).MakeGeneric(e.Expr.Type, e.Type);
                var convCall = new ExprCall(ctx, mConv, null, e.Expr);
                return convCall;
            }
        }