📄 expression.cs
字号:
// A plus in front of something is just a no-op, so return the child. // return Expr; case Operator.UnaryNegation: // // Deals with -literals // int operator- (int x) // long operator- (long x) // float operator- (float f) // double operator- (double d) // decimal operator- (decimal d) // Expression expr = null; // // transform - - expr into expr // if (Expr is Unary){ Unary unary = (Unary) Expr; if (unary.Oper == Operator.UnaryNegation) return unary.Expr; } // // perform numeric promotions to int, // long, double. // // // The following is inneficient, because we call // ImplicitConversion too many times. // // It is also not clear if we should convert to Float // or Double initially. // if (expr_type == TypeManager.uint32_type){ // // FIXME: handle exception to this rule that // permits the int value -2147483648 (-2^31) to // bt wrote as a decimal interger literal // type = TypeManager.int64_type; Expr = Convert.ImplicitConversion (ec, Expr, type, loc); return this; } if (expr_type == TypeManager.uint64_type){ // // FIXME: Handle exception of `long value' // -92233720368547758087 (-2^63) to be wrote as // decimal integer literal. // Error23 (expr_type); return null; } if (expr_type == TypeManager.float_type){ type = expr_type; return this; } expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc); if (expr != null){ Expr = expr; type = expr.Type; return this; } expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc); if (expr != null){ Expr = expr; type = expr.Type; return this; } expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc); if (expr != null){ Expr = expr; type = expr.Type; return this; } Error23 (expr_type); return null; } Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" + TypeManager.CSharpName (expr_type) + "'"); return null; } public override Expression DoResolve (EmitContext ec) { if (Oper == Operator.AddressOf) { Expr = Expr.DoResolveLValue (ec, new EmptyExpression ()); if (Expr == null || Expr.eclass != ExprClass.Variable){ Error (211, "Cannot take the address of the given expression"); return null; } } else Expr = Expr.Resolve (ec); if (Expr == null) return null; eclass = ExprClass.Value; return ResolveOperator (ec); } public override Expression DoResolveLValue (EmitContext ec, Expression right) { if (Oper == Operator.Indirection) return DoResolve (ec); return null; } public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; switch (Oper) { case Operator.UnaryPlus: throw new Exception ("This should be caught by Resolve"); case Operator.UnaryNegation: if (ec.CheckState) { ig.Emit (OpCodes.Ldc_I4_0); if (type == TypeManager.int64_type) ig.Emit (OpCodes.Conv_U8); Expr.Emit (ec); ig.Emit (OpCodes.Sub_Ovf); } else { Expr.Emit (ec); ig.Emit (OpCodes.Neg); } break; case Operator.LogicalNot: Expr.Emit (ec); ig.Emit (OpCodes.Ldc_I4_0); ig.Emit (OpCodes.Ceq); break; case Operator.OnesComplement: Expr.Emit (ec); ig.Emit (OpCodes.Not); break; case Operator.AddressOf: ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore); break; default: throw new Exception ("This should not happen: Operator = " + Oper.ToString ()); } } public override void EmitBranchable (EmitContext ec, Label target, bool onTrue) { if (Oper == Operator.LogicalNot) Expr.EmitBranchable (ec, target, !onTrue); else base.EmitBranchable (ec, target, onTrue); } public override string ToString () { return "Unary (" + Oper + ", " + Expr + ")"; } } // // Unary operators are turned into Indirection expressions // after semantic analysis (this is so we can take the address // of an indirection). // public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable { Expression expr; LocalTemporary temporary; bool prepared; public Indirection (Expression expr, Location l) { this.expr = expr; type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type; eclass = ExprClass.Variable; loc = l; } public override void Emit (EmitContext ec) { if (!prepared) expr.Emit (ec); LoadFromPtr (ec.ig, Type); } public void Emit (EmitContext ec, bool leave_copy) { Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temporary = new LocalTemporary (ec, expr.Type); temporary.Store (ec); } } public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { prepared = prepare_for_load; expr.Emit (ec); if (prepare_for_load) ec.ig.Emit (OpCodes.Dup); source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); temporary = new LocalTemporary (ec, expr.Type); temporary.Store (ec); } StoreFromPtr (ec.ig, type); if (temporary != null) temporary.Emit (ec); } public void AddressOf (EmitContext ec, AddressOp Mode) { expr.Emit (ec); } public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { return DoResolve (ec); } public override Expression DoResolve (EmitContext ec) { // // Born fully resolved // return this; } public override string ToString () { return "*(" + expr + ")"; } #region IVariable Members public VariableInfo VariableInfo { get { return null; } } public bool VerifyFixed () { // A pointer-indirection is always fixed. return true; } #endregion } /// <summary> /// Unary Mutator expressions (pre and post ++ and --) /// </summary> /// /// <remarks> /// UnaryMutator implements ++ and -- expressions. It derives from /// ExpressionStatement becuase the pre/post increment/decrement /// operators can be used in a statement context. /// /// FIXME: Idea, we could split this up in two classes, one simpler /// for the common case, and one with the extra fields for more complex /// classes (indexers require temporary access; overloaded require method) /// /// </remarks> public class UnaryMutator : ExpressionStatement { [Flags] public enum Mode : byte { IsIncrement = 0, IsDecrement = 1, IsPre = 0, IsPost = 2, PreIncrement = 0, PreDecrement = IsDecrement, PostIncrement = IsPost, PostDecrement = IsPost | IsDecrement } Mode mode; bool is_expr = false; bool recurse = false; Expression expr; // // This is expensive for the simplest case. // StaticCallExpr method; public UnaryMutator (Mode m, Expression e, Location l) { mode = m; loc = l; expr = e; } static string OperName (Mode mode) { return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ? "++" : "--"; } /// <summary> /// Returns whether an object of type `t' can be incremented /// or decremented with add/sub (ie, basically whether we can /// use pre-post incr-decr operations on it, but it is not a /// System.Decimal, which we require operator overloading to catch) /// </summary> static bool IsIncrementableNumber (Type t) { return (t == TypeManager.sbyte_type) || (t == TypeManager.byte_type) || (t == TypeManager.short_type) || (t == TypeManager.ushort_type) || (t == TypeManager.int32_type) || (t == TypeManager.uint32_type) || (t == TypeManager.int64_type) || (t == TypeManager.uint64_type) || (t == TypeManager.char_type) || (t.IsSubclassOf (TypeManager.enum_type)) || (t == TypeManager.float_type) || (t == TypeManager.double_type) || (t.IsPointer && t != TypeManager.void_ptr_type); } Expression ResolveOperator (EmitContext ec) { Type expr_type = expr.Type; // // Step 1: Perform Operator Overload location // Expression mg; string op_name; if (mode == Mode.PreIncrement || mode == Mode.PostIncrement) op_name = "op_Increment"; else op_name = "op_Decrement"; mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc); if (mg != null) { method = StaticCallExpr.MakeSimpleCall ( ec, (MethodGroupExpr) mg, expr, loc); type = method.Type; } else if (!IsIncrementableNumber (expr_type)) { Error (187, "No such operator '" + OperName (mode) + "' defined for type '" + TypeManager.CSharpName (expr_type) + "'"); return null; } // // The operand of the prefix/postfix increment decrement operators // should be an expression that is classified as a variable, // a property access or an indexer access // type = expr_type; if (expr.eclass == ExprClass.Variable){ LocalVariableReference var = expr as LocalVariableReference; if ((var != null) && var.IsReadOnly) { Error (1604, "cannot assign to `" + var.Name + "' because it is readonly"); return null; } } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){ expr = expr.ResolveLValue (ec, this, Location); if (expr == null) return null; } else { expr.Error_UnexpectedKind (ec, "variable, indexer or property access", loc); return null; } return this; } public override Expression DoResolve (EmitContext ec) { expr = expr.Resolve (ec); if (expr == null) return null; eclass = ExprClass.Value; return ResolveOperator (ec); } static int PtrTypeSize (Type t) { return GetTypeSize (TypeManager.GetElementType (t)); } // // Loads the proper "1" into the stack based on the type, then it emits the // opcode for the operation requested // void LoadOneAndEmitOp (EmitContext ec, Type t) { // // Measure if getting the typecode and using that is more/less efficient // that comparing types. t.GetTypeCode() is an internal call. // ILGenerator ig = ec.ig; if (t == TypeManager.uint64_type || t == TypeManager.int64_type) LongConstant.EmitLong (ig, 1); else if (t == TypeManager.double_type) ig.Emit (OpCodes.Ldc_R8, 1.0); else if (t == TypeManager.float_type) ig.Emit (OpCodes.Ldc_R4, 1.0F); else if (t.IsPointer){ int n = PtrTypeSize (t); if (n == 0) ig.Emit (OpCodes.Sizeof, t); else IntConstant.EmitInt (ig, n); } else ig.Emit (OpCodes.Ldc_I4_1); // // Now emit the operation // if (ec.CheckState){ if (t == TypeManager.int32_type || t == TypeManager.int64_type){ if ((mode & Mode.IsDecrement) != 0) ig.Emit (OpCodes.Sub_Ovf); else ig.Emit (OpCodes.Add_Ovf); } else if (t == TypeManager.uint32_type || t == TypeManager.uint64_type){ if ((mode & Mode.IsDecrement) != 0) ig.Emit (OpCodes.Sub_Ovf_Un); else ig.Emit (OpCodes.Add_Ovf_Un); } else { if ((mode & Mode.IsDecrement) != 0) ig.Emit (OpCodes.Sub_Ovf); else ig.Emit (OpCodes.Add_Ovf); } } else { if ((mode & Mode.IsDecrement) != 0) ig.Emit (OpCodes.Sub); else ig.Emit (OpCodes.Add); } if (t == TypeManager.sbyte_type){ if (ec.CheckState) ig.Emit (OpCodes.Conv_Ovf_I1); else ig.Emit (OpCodes.Conv_I1); } else if (t == TypeManager.byte_type){ if (ec.CheckState) ig.Emit (OpCodes.Conv_Ovf_U1); else ig.Emit (OpCodes.Conv_U1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -