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; } }
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; } }