Merged everything from SVN HEAD back.
svn path=/branches/martin/anonymous-methods2/mcs/; revision=68669
+2006-11-29 Martin Baulig <martin@ximian.com>
+
+ Merged everything from SVN HEAD back.
+
2006-11-28 Martin Baulig <martin@ximian.com>
Milestone II: We are ready to merge things back.
**** The anonymous methods branch starts here ****
+2006-11-22 Marek Safar <marek.safar@gmail.com>
+
+ A fix for bug #79987
+ * class.cs (VerifyClsCompliance): Move redundant CLS compliance attribute
+ check to a base class.
+ * decl.cs (VerifyClsCompliance): Warn that CLS compliance cannot be tested
+ only when assembly has missing attribute.
+ * report.cs: Update.
+
+2006-11-21 Marek Safar <marek.safar@gmail.com>
+
+ * cs-tokenizer.cs: Merged with gmcs version.
+
+2006-11-20 Marek Safar <marek.safar@gmail.com>
+
+ * cs-tokenizer.cs,
+ * cs-parser.jay: Better error message when partial keyword is misplaced.
+
+2006-11-19 Gert Driesen <drieseng@users.sourceforge.net>
+
+ A fix for bug #79810
+ report.cs: CS1058 only applies to 2.0 profile (gmcs).
+ codegen.cs: on 2.0 profile, non-exception throwables are wrapped in
+ a RuntimeWrappedException by default.
+
+2006-11-18 Marek Safar <marek.safar@gmail.com>
+
+ A fix for bug #79843
+ * delegate.cs (Delegate.VerifyMethod): Fixed covariance and contravariance
+ implementation.
+ (DelegateCreation.Error_NoMatchingMethodForDelegate): Ditto.
+
+2006-11-18 Marek Safar <marek.safar@gmail.com>
+
+ * driver.cs, namespace.cs: Uses faster IndexOf version.
+
+2006-11-17 Marek Safar <marek.safar@gmail.com>
+
+ A fix for bug #79941
+ * class.cs (MemberCore.IsDuplicateImplementation): Add more tricks for
+ operators.
+ (Operator.Define): Implicit/Explicit operator of same type is duplicate
+ even if internal name is different.
+ * convert.cs (GetConversionOperator): Replaced EmitContext with parentType.
+ (UserDefinedConversion): Simplified as the operators cannot be internal.
+ * ecore.cs (Error_ValueCannotBeConverted): Take account of user
+ conversions.
+ (MethodLookup): Replaced EmitContext with parentType.
+ * expression.cs: Updated.
+
2006-11-09 Raja R Harinath <rharinath@novell.com>
* driver.cs (BadAssembly): Handle all the ugliness of
if (base_type != null && !AttributeTester.IsClsCompliant (base_type)) {
Report.Error (3009, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (base_type));
}
-
- if (!Parent.IsClsComplianceRequired ()) {
- Report.Error (3018, Location, "`{0}' cannot be marked as CLS-compliant because it is a member of non CLS-compliant type `{1}'",
- GetSignatureForError (), Parent.GetSignatureForError ());
- }
return true;
}
return true;
}
+ // TODO: create a special method for operators only to make code better
protected bool IsDuplicateImplementation (MethodCore method)
{
- if (method == this || !(method.MemberName.Equals (MemberName)))
+ if (method == this)
return false;
+ Operator op2 = null;
+ Operator op1 = null;
+
+ if (!(method.MemberName.Equals (MemberName)))
+ {
+ op1 = this as Operator;
+ if (op1 == null || !(op1.OperatorType == Operator.OpType.Explicit || op1.OperatorType == Operator.OpType.Implicit))
+ return false;
+
+ op2 = method as Operator;
+ if (op2 == null || !(op2.OperatorType == Operator.OpType.Explicit || op2.OperatorType == Operator.OpType.Implicit))
+ return false;
+ } else {
+ op1 = this as Operator;
+ op2 = method as Operator;
+ }
+
Type[] param_types = method.ParameterTypes;
// This never happen. Rewrite this as Equal
if (param_types == null && ParameterTypes == null)
equal = false;
// TODO: make operator compatible with MethodCore to avoid this
- if (this is Operator && method is Operator) {
+ if (op1 != null && op2 != null) {
if (MemberType != method.MemberType)
equal = false;
}
int mod_flags, Parameters parameters,
ToplevelBlock block, Attributes attrs, Location loc)
: base (parent, null, ret_type, mod_flags, AllowedModifiers, false,
- new MemberName ("op_" + type, loc), attrs, parameters)
+ new MemberName ("op_" + type.ToString(), loc), attrs, parameters)
{
OperatorType = type;
Block = block;
return false;
}
+ // imlicit and explicit operator of same types are not allowed
+ if (OperatorType == OpType.Explicit || OperatorType == OpType.Implicit)
+ MarkForDuplicationCheck ();
+
if (!base.Define ())
return false;
public AssemblyClass (): base ()
{
+#if GMCS_SOURCE
wrap_non_exception_throws = true;
+#endif
}
public bool IsClsCompliant {
--- /dev/null
+//
+// conversion.cs: various routines for implementing conversions.
+//
+// Authors:
+// Miguel de Icaza (miguel@ximian.com)
+// Ravi Pratap (ravi@ximian.com)
+//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+//
+
+namespace Mono.CSharp {
+ using System;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Reflection.Emit;
+
+ //
+ // A container class for all the conversion operations
+ //
+ public class Convert {
+#if GMCS_SOURCE
+ static bool TypeParameter_to_Null (Type target_type)
+ {
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
+ if (gc == null)
+ return false;
+
+ if (gc.HasReferenceTypeConstraint)
+ return true;
+ if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint))
+ return true;
+
+ return false;
+ }
+
+ static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
+ {
+ ArrayList list = new ArrayList ();
+ list.Add (gc.EffectiveBaseClass);
+ foreach (Type t in gc.InterfaceConstraints) {
+ if (!TypeManager.IsGenericParameter (t))
+ continue;
+
+ GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
+ if (new_gc != null)
+ list.Add (TypeParam_EffectiveBaseType (new_gc));
+ }
+ return FindMostEncompassedType (list);
+ }
+#endif
+
+ //
+ // From a one-dimensional array-type S[] to System.Collections.IList<S> and base
+ // interfaces of this interface.
+ //
+ // From a one-dimensional array-type S[] to System.Collections.IList<T> and base
+ // interfaces of this interface, provided there is an implicit reference conversion
+ // from S to T.
+ //
+ static bool Array_To_IList (Type array, Type list)
+ {
+#if GMCS_SOURCE
+ if (!array.IsArray || (array.GetArrayRank () != 1) || !list.IsGenericType)
+ return false;
+
+ Type gt = list.GetGenericTypeDefinition ();
+ if ((gt != TypeManager.generic_ilist_type) &&
+ (gt != TypeManager.generic_icollection_type) &&
+ (gt != TypeManager.generic_ienumerable_type))
+ return false;
+
+ Type element_type = TypeManager.GetElementType (array);
+ Type arg_type = TypeManager.GetTypeArguments (list) [0];
+
+ if (element_type == arg_type)
+ return true;
+
+ if (MyEmptyExpr == null)
+ MyEmptyExpr = new EmptyExpression ();
+ MyEmptyExpr.SetType (TypeManager.GetElementType (array));
+
+ return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type);
+#else
+ return false;
+#endif
+ }
+
+ static Expression ImplicitTypeParameterConversion (Expression expr,
+ Type target_type)
+ {
+#if GMCS_SOURCE
+ Type expr_type = expr.Type;
+
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
+
+ if (gc == null) {
+ if (target_type == TypeManager.object_type)
+ return new BoxedCast (expr, target_type);
+
+ return null;
+ }
+
+ // We're converting from a type parameter which is known to be a reference type.
+ Type base_type = TypeParam_EffectiveBaseType (gc);
+
+ if (TypeManager.IsSubclassOf (base_type, target_type))
+ return new ClassCast (expr, target_type);
+
+ if (target_type.IsInterface) {
+ if (TypeManager.ImplementsInterface (base_type, target_type))
+ return new ClassCast (expr, target_type);
+
+ foreach (Type t in gc.InterfaceConstraints) {
+ if (TypeManager.IsSubclassOf (t, target_type))
+ return new ClassCast (expr, target_type);
+ if (TypeManager.ImplementsInterface (t, target_type))
+ return new ClassCast (expr, target_type);
+ }
+ }
+
+ foreach (Type t in gc.InterfaceConstraints) {
+ if (!TypeManager.IsGenericParameter (t))
+ continue;
+ if (TypeManager.IsSubclassOf (t, target_type))
+ return new ClassCast (expr, target_type);
+ if (TypeManager.ImplementsInterface (t, target_type))
+ return new ClassCast (expr, target_type);
+ }
+#endif
+ return null;
+ }
+
+ static bool ExplicitTypeParameterConversionExists (Type source_type, Type target_type)
+ {
+#if GMCS_SOURCE
+ if (target_type.IsInterface)
+ return true;
+
+ if (TypeManager.IsGenericParameter (target_type)) {
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
+ if (gc == null)
+ return false;
+
+ foreach (Type iface in gc.InterfaceConstraints) {
+ if (!TypeManager.IsGenericParameter (iface))
+ continue;
+
+ if (TypeManager.IsSubclassOf (source_type, iface))
+ return true;
+ }
+ }
+#endif
+ return false;
+ }
+
+ static Expression ExplicitTypeParameterConversion (Expression source, Type target_type)
+ {
+#if GMCS_SOURCE
+ Type source_type = source.Type;
+
+ if (target_type.IsInterface)
+ return new ClassCast (source, target_type);
+
+ if (TypeManager.IsGenericParameter (target_type)) {
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
+ if (gc == null)
+ return null;
+
+ foreach (Type iface in gc.InterfaceConstraints) {
+ if (!TypeManager.IsGenericParameter (iface))
+ continue;
+
+ if (TypeManager.IsSubclassOf (source_type, iface))
+ return new ClassCast (source, target_type);
+ }
+ }
+#endif
+ return null;
+ }
+
+ static EmptyExpression MyEmptyExpr;
+ static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
+ // if we are a method group, emit a warning
+
+ expr.Emit (null);
+ }
+
+ if (expr_type == TypeManager.void_type)
+ return null;
+
+ if (TypeManager.IsGenericParameter (expr_type))
+ return ImplicitTypeParameterConversion (expr, target_type);
+
+ //
+ // notice that it is possible to write "ValueType v = 1", the ValueType here
+ // is an abstract class, and not really a value type, so we apply the same rules.
+ //
+ if (target_type == TypeManager.object_type) {
+ //
+ // A pointer type cannot be converted to object
+ //
+ if (expr_type.IsPointer)
+ return null;
+
+ if (TypeManager.IsValueType (expr_type))
+ return new BoxedCast (expr, target_type);
+ if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
+ if (expr_type == TypeManager.anonymous_method_type)
+ return null;
+ return new EmptyCast (expr, target_type);
+ }
+
+ return null;
+ } else if (target_type == TypeManager.value_type) {
+ if (TypeManager.IsValueType (expr_type))
+ return new BoxedCast (expr, target_type);
+ if (expr_type == TypeManager.null_type)
+ return new EmptyConstantCast ((Constant)expr, target_type);
+
+ return null;
+ } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
+ //
+ // Special case: enumeration to System.Enum.
+ // System.Enum is not a value type, it is a class, so we need
+ // a boxing conversion
+ //
+ if (expr_type.IsEnum || TypeManager.IsGenericParameter (expr_type))
+ return new BoxedCast (expr, target_type);
+
+ return new EmptyCast (expr, target_type);
+ }
+
+ // This code is kind of mirrored inside ImplicitStandardConversionExists
+ // with the small distinction that we only probe there
+ //
+ // Always ensure that the code here and there is in sync
+
+ // from the null type to any reference-type.
+ if (expr_type == TypeManager.null_type) {
+ NullConstant nc = (NullConstant)expr;
+ return nc.ToType(target_type);
+ }
+
+ // from any class-type S to any interface-type T.
+ if (target_type.IsInterface) {
+ if (target_type != TypeManager.iconvertible_type &&
+ expr_type.IsValueType && (expr is Constant) &&
+ !(expr is IntLiteral || expr is BoolLiteral ||
+ expr is FloatLiteral || expr is DoubleLiteral ||
+ expr is LongLiteral || expr is CharLiteral ||
+ expr is StringLiteral || expr is DecimalLiteral ||
+ expr is UIntLiteral || expr is ULongLiteral)) {
+ return null;
+ }
+
+ if (TypeManager.ImplementsInterface (expr_type, target_type)){
+ if (TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))
+ return new BoxedCast (expr, target_type);
+ else
+ return new EmptyCast (expr, target_type);
+ }
+ }
+
+ // from any interface type S to interface-type T.
+ if (expr_type.IsInterface && target_type.IsInterface) {
+ if (TypeManager.ImplementsInterface (expr_type, target_type))
+ return new EmptyCast (expr, target_type);
+ else
+ return null;
+ }
+
+ // from an array-type S to an array-type of type T
+ if (expr_type.IsArray && target_type.IsArray) {
+ if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
+
+ Type expr_element_type = TypeManager.GetElementType (expr_type);
+
+ if (MyEmptyExpr == null)
+ MyEmptyExpr = new EmptyExpression ();
+
+ MyEmptyExpr.SetType (expr_element_type);
+ Type target_element_type = TypeManager.GetElementType (target_type);
+
+ if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
+ if (ImplicitStandardConversionExists (MyEmptyExpr,
+ target_element_type))
+ return new EmptyCast (expr, target_type);
+ }
+ }
+
+ // from an array-type to System.Array
+ if (expr_type.IsArray && target_type == TypeManager.array_type)
+ return new EmptyCast (expr, target_type);
+
+ // from an array-type of type T to IList<T>
+ if (expr_type.IsArray && Array_To_IList (expr_type, target_type))
+ return new EmptyCast (expr, target_type);
+
+ // from any delegate type to System.Delegate
+ if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
+ target_type == TypeManager.delegate_type)
+ return new EmptyCast (expr, target_type);
+
+ // from any array-type or delegate type into System.ICloneable.
+ if (expr_type.IsArray ||
+ expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
+ if (target_type == TypeManager.icloneable_type)
+ return new EmptyCast (expr, target_type);
+
+ // from a generic type definition to a generic instance.
+ if (TypeManager.IsEqual (expr_type, target_type))
+ return new EmptyCast (expr, target_type);
+
+ return null;
+ }
+
+ //
+ // Tests whether an implicit reference conversion exists between expr_type
+ // and target_type
+ //
+ public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
+ {
+ if (target_type.IsValueType)
+ return false;
+
+ Type expr_type = expr.Type;
+
+ if (TypeManager.IsGenericParameter (expr_type))
+ return ImplicitTypeParameterConversion (expr, target_type) != null;
+
+ //
+ // This is the boxed case.
+ //
+ if (target_type == TypeManager.object_type) {
+ if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
+ expr_type.IsInterface || expr_type == TypeManager.enum_type)
+ if (target_type != TypeManager.anonymous_method_type)
+ return true;
+
+ return false;
+ } else if (TypeManager.IsSubclassOf (expr_type, target_type))
+ return true;
+
+ // Please remember that all code below actually comes
+ // from ImplicitReferenceConversion so make sure code remains in sync
+
+ // from any class-type S to any interface-type T.
+ if (target_type.IsInterface) {
+ if (target_type != TypeManager.iconvertible_type &&
+ expr_type.IsValueType && (expr is Constant) &&
+ !(expr is IntLiteral || expr is BoolLiteral ||
+ expr is FloatLiteral || expr is DoubleLiteral ||
+ expr is LongLiteral || expr is CharLiteral ||
+ expr is StringLiteral || expr is DecimalLiteral ||
+ expr is UIntLiteral || expr is ULongLiteral)) {
+ return false;
+ }
+
+ if (TypeManager.ImplementsInterface (expr_type, target_type))
+ return true;
+ }
+
+ // from any interface type S to interface-type T.
+ if (expr_type.IsInterface && target_type.IsInterface)
+ if (TypeManager.ImplementsInterface (expr_type, target_type))
+ return true;
+
+ // from an array-type S to an array-type of type T
+ if (expr_type.IsArray && target_type.IsArray) {
+ if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
+
+ Type expr_element_type = expr_type.GetElementType ();
+
+ if (MyEmptyExpr == null)
+ MyEmptyExpr = new EmptyExpression ();
+
+ MyEmptyExpr.SetType (expr_element_type);
+ Type target_element_type = TypeManager.GetElementType (target_type);
+
+ if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
+ if (ImplicitStandardConversionExists (MyEmptyExpr,
+ target_element_type))
+ return true;
+ }
+ }
+
+ // from an array-type to System.Array
+ if (expr_type.IsArray && (target_type == TypeManager.array_type))
+ return true;
+
+ // from an array-type of type T to IList<T>
+ if (expr_type.IsArray && Array_To_IList (expr_type, target_type))
+ return true;
+
+ // from any delegate type to System.Delegate
+ if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
+ target_type == TypeManager.delegate_type)
+ if (target_type.IsAssignableFrom (expr_type))
+ return true;
+
+ // from any array-type or delegate type into System.ICloneable.
+ if (expr_type.IsArray ||
+ expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
+ if (target_type == TypeManager.icloneable_type)
+ return true;
+
+ // from the null type to any reference-type.
+ if (expr_type == TypeManager.null_type){
+ if (target_type.IsPointer)
+ return true;
+
+ if (!target_type.IsValueType)
+ return true;
+ }
+
+ // from a generic type definition to a generic instance.
+ if (TypeManager.IsEqual (expr_type, target_type))
+ return true;
+
+ return false;
+ }
+
+ /// <summary>
+ /// Implicit Numeric Conversions.
+ ///
+ /// expr is the expression to convert, returns a new expression of type
+ /// target_type or null if an implicit conversion is not possible.
+ /// </summary>
+ static public Expression ImplicitNumericConversion (Expression expr,
+ Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ //
+ // Attempt to do the implicit constant expression conversions
+
+ if (expr is Constant){
+ if (expr is IntConstant){
+ Expression e;
+
+ e = TryImplicitIntConversion (target_type, (IntConstant) expr);
+
+ if (e != null)
+ return e;
+ } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
+ //
+ // Try the implicit constant expression conversion
+ // from long to ulong, instead of a nice routine,
+ // we just inline it
+ //
+ long v = ((LongConstant) expr).Value;
+ if (v >= 0)
+ return new ULongConstant ((ulong) v, expr.Location);
+ }
+ }
+
+ Type real_target_type = target_type;
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to short, int, long, float, double, decimal
+ //
+ if (real_target_type == TypeManager.int32_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.short_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.byte_type){
+ //
+ // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
+ //
+ if ((real_target_type == TypeManager.short_type) ||
+ (real_target_type == TypeManager.ushort_type) ||
+ (real_target_type == TypeManager.int32_type) ||
+ (real_target_type == TypeManager.uint32_type))
+ return new EmptyCast (expr, target_type);
+
+ if (real_target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+
+ } else if (expr_type == TypeManager.short_type){
+ //
+ // From short to int, long, float, double, decimal
+ //
+ if (real_target_type == TypeManager.int32_type)
+ return new EmptyCast (expr, target_type);
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+
+ } else if (expr_type == TypeManager.ushort_type){
+ //
+ // From ushort to int, uint, long, ulong, float, double, decimal
+ //
+ if (real_target_type == TypeManager.uint32_type)
+ return new EmptyCast (expr, target_type);
+
+ if (real_target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (real_target_type == TypeManager.int32_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.int32_type){
+ //
+ // From int to long, float, double, decimal
+ //
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.uint32_type){
+ //
+ // From uint to long, ulong, float, double, decimal
+ //
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (real_target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.int64_type){
+ //
+ // From long/ulong to float, double
+ //
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.uint64_type){
+ //
+ // From ulong to float, double
+ //
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.char_type){
+ //
+ // From char to ushort, int, uint, long, ulong, float, double, decimal
+ //
+ if ((real_target_type == TypeManager.ushort_type) ||
+ (real_target_type == TypeManager.int32_type) ||
+ (real_target_type == TypeManager.uint32_type))
+ return new EmptyCast (expr, target_type);
+ if (real_target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (real_target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (real_target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr);
+ } else if (expr_type == TypeManager.float_type){
+ //
+ // float to double
+ //
+ if (real_target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Same as ImplicitStandardConversionExists except that it also looks at
+ /// implicit user defined conversions - needed for overload resolution
+ /// </summary>
+ public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
+ {
+#if GMCS_SOURCE
+ if (expr is NullLiteral) {
+ if (TypeManager.IsGenericParameter (target_type))
+ return TypeParameter_to_Null (target_type);
+
+ if (TypeManager.IsNullableType (target_type))
+ return true;
+ }
+#endif
+ if (ImplicitStandardConversionExists (expr, target_type))
+ return true;
+
+ return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
+ }
+
+ public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
+ {
+ return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
+ }
+
+ /// <summary>
+ /// Determines if a standard implicit conversion exists from
+ /// expr_type to target_type
+ ///
+ /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
+ /// </summary>
+ public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+#if GMCS_SOURCE
+ if (TypeManager.IsNullableType (target_type)) {
+ // if implicit standard conversion S -> T exists, S -> T? and S? -> T? also exists
+ target_type = TypeManager.GetTypeArguments (target_type) [0];
+
+ // S? -> T?
+ if (TypeManager.IsNullableType (expr_type)) {
+ EmptyExpression new_expr = EmptyExpression.Grab ();
+ new_expr.SetType (TypeManager.GetTypeArguments (expr_type) [0]);
+ bool retval = ImplicitStandardConversionExists (new_expr, target_type);
+ EmptyExpression.Release (new_expr);
+ return retval;
+ }
+ }
+#endif
+ if (expr_type == TypeManager.void_type)
+ return false;
+
+ //Console.WriteLine ("Expr is {0}", expr);
+ //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
+ if (expr_type.Equals (target_type))
+ return true;
+
+
+ // First numeric conversions
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to short, int, long, float, double, decimal
+ //
+ if ((target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.short_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.byte_type){
+ //
+ // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
+ //
+ if ((target_type == TypeManager.short_type) ||
+ (target_type == TypeManager.ushort_type) ||
+ (target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.uint32_type) ||
+ (target_type == TypeManager.uint64_type) ||
+ (target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.short_type){
+ //
+ // From short to int, long, double, float, decimal
+ //
+ if ((target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.ushort_type){
+ //
+ // From ushort to int, uint, long, ulong, double, float, decimal
+ //
+ if ((target_type == TypeManager.uint32_type) ||
+ (target_type == TypeManager.uint64_type) ||
+ (target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.int32_type){
+ //
+ // From int to long, double, float, decimal
+ //
+ if ((target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.uint32_type){
+ //
+ // From uint to long, ulong, double, float, decimal
+ //
+ if ((target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.uint64_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if ((expr_type == TypeManager.uint64_type) ||
+ (expr_type == TypeManager.int64_type)) {
+ //
+ // From long/ulong to double, float, decimal
+ //
+ if ((target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.char_type){
+ //
+ // From char to ushort, int, uint, ulong, long, float, double, decimal
+ //
+ if ((target_type == TypeManager.ushort_type) ||
+ (target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.uint32_type) ||
+ (target_type == TypeManager.uint64_type) ||
+ (target_type == TypeManager.int64_type) ||
+ (target_type == TypeManager.float_type) ||
+ (target_type == TypeManager.double_type) ||
+ (target_type == TypeManager.decimal_type))
+ return true;
+
+ } else if (expr_type == TypeManager.float_type){
+ //
+ // float to double
+ //
+ if (target_type == TypeManager.double_type)
+ return true;
+ }
+
+ if (expr.eclass == ExprClass.MethodGroup){
+ if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){
+ MethodGroupExpr mg = expr as MethodGroupExpr;
+ if (mg != null){
+ return DelegateCreation.ImplicitStandardConversionExists (mg, target_type) != null;
+ }
+ }
+ }
+
+ if (ImplicitReferenceConversionExists (expr, target_type))
+ return true;
+
+ //
+ // Implicit Constant Expression Conversions
+ //
+ if (expr is IntConstant){
+ int value = ((IntConstant) expr).Value;
+
+ if (target_type == TypeManager.sbyte_type){
+ if (value >= SByte.MinValue && value <= SByte.MaxValue)
+ return true;
+ } else if (target_type == TypeManager.byte_type){
+ if (value >= 0 && value <= Byte.MaxValue)
+ return true;
+ } else if (target_type == TypeManager.short_type){
+ if (value >= Int16.MinValue && value <= Int16.MaxValue)
+ return true;
+ } else if (target_type == TypeManager.ushort_type){
+ if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
+ return true;
+ } else if (target_type == TypeManager.uint32_type){
+ if (value >= 0)
+ return true;
+ } else if (target_type == TypeManager.uint64_type){
+ //
+ // we can optimize this case: a positive int32
+ // always fits on a uint64. But we need an opcode
+ // to do it.
+ //
+ if (value >= 0)
+ return true;
+ }
+
+ if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
+ return true;
+ }
+
+ if (expr is LongConstant && target_type == TypeManager.uint64_type){
+ //
+ // Try the implicit constant expression conversion
+ // from long to ulong, instead of a nice routine,
+ // we just inline it
+ //
+ long v = ((LongConstant) expr).Value;
+ if (v >= 0)
+ return true;
+ }
+
+ if ((target_type == TypeManager.enum_type ||
+ target_type.IsSubclassOf (TypeManager.enum_type)) &&
+ expr is IntLiteral){
+ IntLiteral i = (IntLiteral) expr;
+
+ if (i.Value == 0)
+ return true;
+ }
+
+ //
+ // If `expr_type' implements `target_type' (which is an iface)
+ // see TryImplicitIntConversion
+ //
+ if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
+ return true;
+
+ if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
+ return true;
+
+ if (expr_type == TypeManager.anonymous_method_type){
+ if (!TypeManager.IsDelegateType (target_type))
+ return false;
+
+ AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
+ return ame.ImplicitStandardConversionExists (target_type);
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Finds "most encompassed type" according to the spec (13.4.2)
+ /// amongst the methods in the MethodGroupExpr
+ /// </summary>
+ static Type FindMostEncompassedType (ArrayList types)
+ {
+ Type best = null;
+
+ if (types.Count == 0)
+ return null;
+
+ if (types.Count == 1)
+ return (Type) types [0];
+
+ EmptyExpression expr = EmptyExpression.Grab ();
+
+ foreach (Type t in types) {
+ if (best == null) {
+ best = t;
+ continue;
+ }
+
+ expr.SetType (t);
+ if (ImplicitStandardConversionExists (expr, best))
+ best = t;
+ }
+
+ expr.SetType (best);
+ foreach (Type t in types) {
+ if (best == t)
+ continue;
+ if (!ImplicitStandardConversionExists (expr, t)) {
+ best = null;
+ break;
+ }
+ }
+
+ EmptyExpression.Release (expr);
+
+ return best;
+ }
+
+ /// <summary>
+ /// Finds "most encompassing type" according to the spec (13.4.2)
+ /// amongst the types in the given set
+ /// </summary>
+ static Type FindMostEncompassingType (ArrayList types)
+ {
+ Type best = null;
+
+ if (types.Count == 0)
+ return null;
+
+ if (types.Count == 1)
+ return (Type) types [0];
+
+ EmptyExpression expr = EmptyExpression.Grab ();
+
+ foreach (Type t in types) {
+ if (best == null) {
+ best = t;
+ continue;
+ }
+
+ expr.SetType (best);
+ if (ImplicitStandardConversionExists (expr, t))
+ best = t;
+ }
+
+ foreach (Type t in types) {
+ if (best == t)
+ continue;
+ expr.SetType (t);
+ if (!ImplicitStandardConversionExists (expr, best)) {
+ best = null;
+ break;
+ }
+ }
+
+ EmptyExpression.Release (expr);
+
+ return best;
+ }
+
+ /// <summary>
+ /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
+ /// by making use of FindMostEncomp* methods. Applies the correct rules separately
+ /// for explicit and implicit conversion operators.
+ /// </summary>
+ static public Type FindMostSpecificSource (IList list,
+ Expression source, bool apply_explicit_conv_rules)
+ {
+ ArrayList src_types_set = new ArrayList ();
+
+ //
+ // If any operator converts from S then Sx = S
+ //
+ Type source_type = source.Type;
+ foreach (MethodBase mb in list){
+ ParameterData pd = TypeManager.GetParameterData (mb);
+ Type param_type = pd.ParameterType (0);
+
+ if (param_type == source_type)
+ return param_type;
+
+ src_types_set.Add (param_type);
+ }
+
+ //
+ // Explicit Conv rules
+ //
+ if (apply_explicit_conv_rules) {
+ ArrayList candidate_set = new ArrayList ();
+
+ foreach (Type param_type in src_types_set){
+ if (ImplicitStandardConversionExists (source, param_type))
+ candidate_set.Add (param_type);
+ }
+
+ if (candidate_set.Count != 0)
+ return FindMostEncompassedType (candidate_set);
+ }
+
+ //
+ // Final case
+ //
+ if (apply_explicit_conv_rules)
+ return FindMostEncompassingType (src_types_set);
+ else
+ return FindMostEncompassedType (src_types_set);
+ }
+
+ /// <summary>
+ /// Finds the most specific target Tx according to section 13.4.4
+ /// </summary>
+ static public Type FindMostSpecificTarget (IList list,
+ Type target, bool apply_explicit_conv_rules)
+ {
+ ArrayList tgt_types_set = new ArrayList ();
+
+ //
+ // If any operator converts to T then Tx = T
+ //
+ foreach (MethodInfo mi in list){
+ Type ret_type = mi.ReturnType;
+ if (ret_type == target)
+ return ret_type;
+
+ tgt_types_set.Add (ret_type);
+ }
+
+ //
+ // Explicit conv rules
+ //
+ if (apply_explicit_conv_rules) {
+ ArrayList candidate_set = new ArrayList ();
+
+ EmptyExpression expr = EmptyExpression.Grab ();
+
+ foreach (Type ret_type in tgt_types_set){
+ expr.SetType (ret_type);
+
+ if (ImplicitStandardConversionExists (expr, target))
+ candidate_set.Add (ret_type);
+ }
+
+ EmptyExpression.Release (expr);
+
+ if (candidate_set.Count != 0)
+ return FindMostEncompassingType (candidate_set);
+ }
+
+ //
+ // Okay, final case !
+ //
+ if (apply_explicit_conv_rules)
+ return FindMostEncompassedType (tgt_types_set);
+ else
+ return FindMostEncompassingType (tgt_types_set);
+ }
+
+ /// <summary>
+ /// User-defined Implicit conversions
+ /// </summary>
+ static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
+ Type target, Location loc)
+ {
+ return UserDefinedConversion (ec, source, target, loc, false);
+ }
+
+ /// <summary>
+ /// User-defined Explicit conversions
+ /// </summary>
+ static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
+ Type target, Location loc)
+ {
+ return UserDefinedConversion (ec, source, target, loc, true);
+ }
+
+ static void AddConversionOperators (ArrayList list,
+ Expression source, Type target_type,
+ bool look_for_explicit,
+ MethodGroupExpr mg)
+ {
+ if (mg == null)
+ return;
+
+ Type source_type = source.Type;
+ EmptyExpression expr = EmptyExpression.Grab ();
+ foreach (MethodInfo m in mg.Methods) {
+ ParameterData pd = TypeManager.GetParameterData (m);
+ Type return_type = m.ReturnType;
+ Type arg_type = pd.ParameterType (0);
+
+ if (source_type != arg_type) {
+ if (!ImplicitStandardConversionExists (source, arg_type)) {
+ if (!look_for_explicit)
+ continue;
+ expr.SetType (arg_type);
+ if (!ImplicitStandardConversionExists (expr, source_type))
+ continue;
+ }
+ }
+
+ if (target_type != return_type) {
+ expr.SetType (return_type);
+ if (!ImplicitStandardConversionExists (expr, target_type)) {
+ if (!look_for_explicit)
+ continue;
+ expr.SetType (target_type);
+ if (!ImplicitStandardConversionExists (expr, return_type))
+ continue;
+ }
+ }
+
+ list.Add (m);
+ }
+
+ EmptyExpression.Release (expr);
+ }
+
+ /// <summary>
+ /// Compute the user-defined conversion operator from source_type to target_type.
+ /// `look_for_explicit' controls whether we should also include the list of explicit operators
+ /// </summary>
+ static MethodInfo GetConversionOperator (Type container_type, Expression source, Type target_type, bool look_for_explicit)
+ {
+ ArrayList ops = new ArrayList (4);
+
+ Type source_type = source.Type;
+
+ if (source_type != TypeManager.decimal_type) {
+ AddConversionOperators (ops, source, target_type, look_for_explicit,
+ Expression.MethodLookup (container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
+ if (look_for_explicit) {
+ AddConversionOperators (ops, source, target_type, look_for_explicit,
+ Expression.MethodLookup (
+ container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
+ }
+ }
+
+ if (target_type != TypeManager.decimal_type) {
+ AddConversionOperators (ops, source, target_type, look_for_explicit,
+ Expression.MethodLookup (container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
+ if (look_for_explicit) {
+ AddConversionOperators (ops, source, target_type, look_for_explicit,
+ Expression.MethodLookup (
+ container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
+ }
+ }
+
+ if (ops.Count == 0)
+ return null;
+
+ Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
+ if (most_specific_source == null)
+ return null;
+
+ Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
+ if (most_specific_target == null)
+ return null;
+
+ MethodInfo method = null;
+
+ foreach (MethodInfo m in ops) {
+ if (m.ReturnType != most_specific_target)
+ continue;
+ if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source)
+ continue;
+ // Ambiguous: more than one conversion operator satisfies the signature.
+ if (method != null)
+ return null;
+ method = m;
+ }
+
+ return method;
+ }
+
+ static DoubleHash explicit_conv = new DoubleHash (100);
+ static DoubleHash implicit_conv = new DoubleHash (100);
+
+ /// <summary>
+ /// User-defined conversions
+ /// </summary>
+ static public Expression UserDefinedConversion (EmitContext ec, Expression source,
+ Type target, Location loc,
+ bool look_for_explicit)
+ {
+ Type source_type = source.Type;
+ MethodInfo method = null;
+
+ object o;
+ DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv;
+
+ if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
+ method = (MethodInfo) o;
+ } else {
+ method = GetConversionOperator (null, source, target, look_for_explicit);
+ if (!(source is Constant))
+ hash.Insert (source_type, target, method);
+ }
+
+ if (method == null)
+ return null;
+
+ Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0);
+
+ //
+ // This will do the conversion to the best match that we
+ // found. Now we need to perform an implict standard conversion
+ // if the best match was not the type that we were requested
+ // by target.
+ //
+ if (look_for_explicit)
+ source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
+ else
+ source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
+
+ if (source == null)
+ return null;
+
+ Expression e;
+ e = new UserCast (method, source, loc);
+ if (e.Type != target){
+ if (!look_for_explicit)
+ e = ImplicitConversionStandard (ec, e, target, loc);
+ else
+ e = ExplicitConversionStandard (ec, e, target, loc);
+ }
+
+ return e;
+ }
+
+ /// <summary>
+ /// Converts implicitly the resolved expression `expr' into the
+ /// `target_type'. It returns a new expression that can be used
+ /// in a context that expects a `target_type'.
+ /// </summary>
+ static public Expression ImplicitConversion (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Expression e;
+
+ if (target_type == null)
+ throw new Exception ("Target type is null");
+
+ e = ImplicitConversionStandard (ec, expr, target_type, loc);
+ if (e != null)
+ return e;
+
+ e = ImplicitUserConversion (ec, expr, target_type, loc);
+ if (e != null)
+ return e;
+
+ return null;
+ }
+
+
+ /// <summary>
+ /// Attempts to apply the `Standard Implicit
+ /// Conversion' rules to the expression `expr' into
+ /// the `target_type'. It returns a new expression
+ /// that can be used in a context that expects a
+ /// `target_type'.
+ ///
+ /// This is different from `ImplicitConversion' in that the
+ /// user defined implicit conversions are excluded.
+ /// </summary>
+ static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+ Expression e;
+#if GMCS_SOURCE
+ // TODO: refactor to be a part of constant infrastructure
+ if (expr is NullLiteral) {
+ if (TypeManager.IsNullableType (target_type))
+ return new Nullable.NullableLiteral (target_type, loc);
+ }
+
+ if (TypeManager.IsNullableType (target_type)) {
+ Type target = TypeManager.GetTypeArguments (target_type) [0];
+
+ if (TypeManager.IsNullableType (expr.Type)) {
+ e = new Nullable.LiftedConversion (
+ expr, target_type, false, false, loc).Resolve (ec);
+ if (e != null)
+ return e;
+ } else {
+ e = ImplicitConversion (ec, expr, target, loc);
+ if (e != null)
+ return Nullable.Wrap.Create (e, ec);
+ }
+ }
+#endif
+ if (expr.eclass == ExprClass.MethodGroup){
+ if (!TypeManager.IsDelegateType (target_type)){
+ return null;
+ }
+
+ //
+ // Only allow anonymous method conversions on post ISO_1
+ //
+ if (RootContext.Version != LanguageVersion.ISO_1){
+ MethodGroupExpr mg = expr as MethodGroupExpr;
+ if (mg != null)
+ return ImplicitDelegateCreation.Create (
+ ec, mg, target_type, loc);
+ }
+ }
+
+ if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
+ return expr;
+
+ e = ImplicitNumericConversion (expr, target_type);
+ if (e != null)
+ return e;
+
+ e = ImplicitReferenceConversion (expr, target_type);
+ if (e != null)
+ return e;
+
+ if (TypeManager.IsEnumType (target_type) && expr is IntLiteral){
+ IntLiteral i = (IntLiteral) expr;
+
+ if (i.Value == 0)
+ return new EnumConstant ((Constant) expr, target_type);
+ }
+
+ if (ec.InUnsafe) {
+ if (expr_type.IsPointer){
+ if (target_type == TypeManager.void_ptr_type)
+ return new EmptyCast (expr, target_type);
+
+ //
+ // yep, comparing pointer types cant be done with
+ // t1 == t2, we have to compare their element types.
+ //
+ if (target_type.IsPointer){
+ if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
+ return expr;
+
+ //return null;
+ }
+ }
+
+ if (expr_type == TypeManager.null_type && target_type.IsPointer)
+ return new EmptyCast (NullPointer.Null, target_type);
+ }
+
+ if (expr_type == TypeManager.anonymous_method_type){
+ AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
+
+ int errors = Report.Errors;
+
+ Expression conv = ame.Compatible (ec, target_type);
+ if (conv != null)
+ return conv;
+
+ //
+ // We return something instead of null, to avoid
+ // the duplicate error, since am.Compatible would have
+ // reported that already
+ //
+ if (errors != Report.Errors)
+ return new EmptyCast (expr, target_type);
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Attempts to perform an implicit constant conversion of the IntConstant
+ /// into a different data type using casts (See Implicit Constant
+ /// Expression Conversions)
+ /// </summary>
+ static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
+ {
+ int value = ic.Value;
+
+ if (target_type == TypeManager.sbyte_type){
+ if (value >= SByte.MinValue && value <= SByte.MaxValue)
+ return new SByteConstant ((sbyte) value, ic.Location);
+ } else if (target_type == TypeManager.byte_type){
+ if (value >= Byte.MinValue && value <= Byte.MaxValue)
+ return new ByteConstant ((byte) value, ic.Location);
+ } else if (target_type == TypeManager.short_type){
+ if (value >= Int16.MinValue && value <= Int16.MaxValue)
+ return new ShortConstant ((short) value, ic.Location);
+ } else if (target_type == TypeManager.ushort_type){
+ if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
+ return new UShortConstant ((ushort) value, ic.Location);
+ } else if (target_type == TypeManager.uint32_type){
+ if (value >= 0)
+ return new UIntConstant ((uint) value, ic.Location);
+ } else if (target_type == TypeManager.uint64_type){
+ //
+ // we can optimize this case: a positive int32
+ // always fits on a uint64. But we need an opcode
+ // to do it.
+ //
+ if (value >= 0)
+ return new ULongConstant ((ulong) value, ic.Location);
+ } else if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) value, ic.Location);
+ else if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) value, ic.Location);
+
+ if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
+ Type underlying = TypeManager.EnumToUnderlying (target_type);
+ Constant e = (Constant) ic;
+
+ //
+ // Possibly, we need to create a different 0 literal before passing
+ // to EnumConstant
+ //
+ if (underlying == TypeManager.int64_type)
+ e = new LongLiteral (0, ic.Location);
+ else if (underlying == TypeManager.uint64_type)
+ e = new ULongLiteral (0, ic.Location);
+
+ return new EnumConstant (e, target_type);
+ }
+
+ //
+ // If `target_type' is an interface and the type of `ic' implements the interface
+ // e.g. target_type is IComparable, IConvertible, IFormattable
+ //
+ if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type))
+ return new BoxedCast (ic, target_type);
+
+ return null;
+ }
+
+ /// <summary>
+ /// Attempts to implicitly convert `source' into `target_type', using
+ /// ImplicitConversion. If there is no implicit conversion, then
+ /// an error is signaled
+ /// </summary>
+ static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
+ Type target_type, Location loc)
+ {
+ Expression e = ImplicitConversion (ec, source, target_type, loc);
+ if (e != null)
+ return e;
+
+ source.Error_ValueCannotBeConverted (loc, target_type, false);
+ return null;
+ }
+
+ /// <summary>
+ /// Performs the explicit numeric conversions
+ ///
+ /// There are a few conversions that are not part of the C# standard,
+ /// they were interim hacks in the C# compiler that were supposed to
+ /// become explicit operators in the UIntPtr class and IntPtr class,
+ /// but for historical reasons it did not happen, so the C# compiler
+ /// ended up with these special hacks.
+ ///
+ /// See bug 59800 for details.
+ ///
+ /// The conversion are:
+ /// UIntPtr->SByte
+ /// UIntPtr->Int16
+ /// UIntPtr->Int32
+ /// IntPtr->UInt64
+ /// UInt64->IntPtr
+ /// SByte->UIntPtr
+ /// Int16->UIntPtr
+ ///
+ /// </summary>
+ public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+ Type real_target_type = target_type;
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to byte, ushort, uint, ulong, char, uintptr
+ //
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
+
+ // One of the built-in conversions that belonged in the class library
+ if (real_target_type == TypeManager.uintptr_type){
+ Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I1_U8);
+
+ return new OperatorCast (u8e, TypeManager.uintptr_type, true);
+ }
+ } else if (expr_type == TypeManager.byte_type){
+ //
+ // From byte to sbyte and char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
+ } else if (expr_type == TypeManager.short_type){
+ //
+ // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
+
+ // One of the built-in conversions that belonged in the class library
+ if (real_target_type == TypeManager.uintptr_type){
+ Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
+
+ return new OperatorCast (u8e, TypeManager.uintptr_type, true);
+ }
+ } else if (expr_type == TypeManager.ushort_type){
+ //
+ // From ushort to sbyte, byte, short, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
+ } else if (expr_type == TypeManager.int32_type){
+ //
+ // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
+
+ // One of the built-in conversions that belonged in the class library
+ if (real_target_type == TypeManager.uintptr_type){
+ Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
+
+ return new OperatorCast (u8e, TypeManager.uintptr_type, true);
+ }
+ } else if (expr_type == TypeManager.uint32_type){
+ //
+ // From uint to sbyte, byte, short, ushort, int, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
+ } else if (expr_type == TypeManager.int64_type){
+ //
+ // From long to sbyte, byte, short, ushort, int, uint, ulong, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
+ } else if (expr_type == TypeManager.uint64_type){
+ //
+ // From ulong to sbyte, byte, short, ushort, int, uint, long, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
+ if (real_target_type == TypeManager.int64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
+
+ // One of the built-in conversions that belonged in the class library
+ if (real_target_type == TypeManager.intptr_type){
+ return new OperatorCast (new EmptyCast (expr, TypeManager.int64_type),
+ TypeManager.intptr_type, true);
+ }
+ } else if (expr_type == TypeManager.char_type){
+ //
+ // From char to sbyte, byte, short
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
+ } else if (expr_type == TypeManager.float_type){
+ //
+ // From float to sbyte, byte, short,
+ // ushort, int, uint, long, ulong, char
+ // or decimal
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
+ if (real_target_type == TypeManager.int64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr, true);
+ } else if (expr_type == TypeManager.double_type){
+ //
+ // From double to sbyte, byte, short,
+ // ushort, int, uint, long, ulong,
+ // char, float or decimal
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
+ if (real_target_type == TypeManager.int64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
+ if (real_target_type == TypeManager.float_type)
+ return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
+ if (real_target_type == TypeManager.decimal_type)
+ return new CastToDecimal (expr, true);
+ } else if (expr_type == TypeManager.uintptr_type){
+ //
+ // Various built-in conversions that belonged in the class library
+ //
+ // from uintptr to sbyte, short, int32
+ //
+ if (real_target_type == TypeManager.sbyte_type){
+ Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
+ return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I1);
+ }
+ if (real_target_type == TypeManager.short_type){
+ Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
+ return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I2);
+ }
+ if (real_target_type == TypeManager.int32_type){
+ return new EmptyCast (new OperatorCast (expr, TypeManager.uint32_type, true),
+ TypeManager.int32_type);
+ }
+ } else if (expr_type == TypeManager.intptr_type){
+ if (real_target_type == TypeManager.uint64_type){
+ return new EmptyCast (new OperatorCast (expr, TypeManager.int64_type, true),
+ TypeManager.uint64_type);
+ }
+ } else if (expr_type == TypeManager.decimal_type) {
+ return new CastFromDecimal (expr, target_type).Resolve ();
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Returns whether an explicit reference conversion can be performed
+ /// from source_type to target_type
+ /// </summary>
+ public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
+ {
+ bool target_is_type_param = TypeManager.IsGenericParameter (target_type);
+ bool target_is_value_type = target_type.IsValueType;
+
+ if (source_type == target_type)
+ return true;
+
+ //
+ // From generic parameter to any type
+ //
+ if (TypeManager.IsGenericParameter (source_type))
+ return ExplicitTypeParameterConversionExists (source_type, target_type);
+
+ //
+ // From object to a generic parameter
+ //
+ if (source_type == TypeManager.object_type && target_is_type_param)
+ return true;
+
+ //
+ // From object to any reference type
+ //
+ if (source_type == TypeManager.object_type && !target_is_value_type)
+ return true;
+
+ //
+ // From any class S to any class-type T, provided S is a base class of T
+ //
+ if (TypeManager.IsSubclassOf (target_type, source_type))
+ return true;
+
+ //
+ // From any interface type S to any interface T provided S is not derived from T
+ //
+ if (source_type.IsInterface && target_type.IsInterface){
+ if (!TypeManager.IsSubclassOf (target_type, source_type))
+ return true;
+ }
+
+ //
+ // From any class type S to any interface T, provided S is not sealed
+ // and provided S does not implement T.
+ //
+ if (target_type.IsInterface && !source_type.IsSealed &&
+ !TypeManager.ImplementsInterface (source_type, target_type))
+ return true;
+
+ //
+ // From any interface-type S to to any class type T, provided T is not
+ // sealed, or provided T implements S.
+ //
+ if (source_type.IsInterface &&
+ (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
+ return true;
+
+
+ // From an array type S with an element type Se to an array type T with an
+ // element type Te provided all the following are true:
+ // * S and T differe only in element type, in other words, S and T
+ // have the same number of dimensions.
+ // * Both Se and Te are reference types
+ // * An explicit referenc conversions exist from Se to Te
+ //
+ if (source_type.IsArray && target_type.IsArray) {
+ if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
+
+ Type source_element_type = TypeManager.GetElementType (source_type);
+ Type target_element_type = TypeManager.GetElementType (target_type);
+
+ if (TypeManager.IsGenericParameter (source_element_type) ||
+ (!source_element_type.IsValueType && !target_element_type.IsValueType))
+ if (ExplicitReferenceConversionExists (source_element_type,
+ target_element_type))
+ return true;
+ }
+ }
+
+
+ // From System.Array to any array-type
+ if (source_type == TypeManager.array_type &&
+ target_type.IsArray){
+ return true;
+ }
+
+ //
+ // From System delegate to any delegate-type
+ //
+ if (source_type == TypeManager.delegate_type &&
+ TypeManager.IsDelegateType (target_type))
+ return true;
+
+ //
+ // From ICloneable to Array or Delegate types
+ //
+ if (source_type == TypeManager.icloneable_type &&
+ (target_type == TypeManager.array_type ||
+ target_type == TypeManager.delegate_type))
+ return true;
+
+ return false;
+ }
+
+ /// <summary>
+ /// Implements Explicit Reference conversions
+ /// </summary>
+ static Expression ExplicitReferenceConversion (Expression source, Type target_type)
+ {
+ Type source_type = source.Type;
+ bool target_is_type_param = TypeManager.IsGenericParameter (target_type);
+ bool target_is_value_type = target_type.IsValueType;
+
+ //
+ // From object to a generic parameter
+ //
+ if (source_type == TypeManager.object_type && target_is_type_param)
+ return new UnboxCast (source, target_type);
+
+ //
+ // Explicit type parameter conversion.
+ //
+
+ if (TypeManager.IsGenericParameter (source_type))
+ return ExplicitTypeParameterConversion (source, target_type);
+
+ //
+ // From object to any reference type
+ //
+ if (source_type == TypeManager.object_type && !target_is_value_type)
+ return new ClassCast (source, target_type);
+
+ //
+ // Unboxing conversion.
+ //
+ if (((source_type == TypeManager.enum_type &&
+ !(source is EmptyCast)) ||
+ source_type == TypeManager.value_type) && target_is_value_type)
+ return new UnboxCast (source, target_type);
+
+ //
+ // From any class S to any class-type T, provided S is a base class of T
+ //
+ if (TypeManager.IsSubclassOf (target_type, source_type))
+ return new ClassCast (source, target_type);
+
+ //
+ // From any interface type S to any interface T provided S is not derived from T
+ //
+ if (source_type.IsInterface && target_type.IsInterface){
+ if (TypeManager.ImplementsInterface (source_type, target_type))
+ return null;
+ else
+ return new ClassCast (source, target_type);
+ }
+
+ //
+ // From any class type S to any interface T, provides S is not sealed
+ // and provided S does not implement T.
+ //
+ if (target_type.IsInterface && !source_type.IsSealed) {
+ if (TypeManager.ImplementsInterface (source_type, target_type))
+ return null;
+ else
+ return new ClassCast (source, target_type);
+
+ }
+
+ //
+ // From any interface-type S to to any class type T, provided T is not
+ // sealed, or provided T implements S.
+ //
+ if (source_type.IsInterface) {
+ if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
+ if (target_type.IsClass)
+ return new ClassCast (source, target_type);
+ else
+ return new UnboxCast (source, target_type);
+ }
+
+ return null;
+ }
+
+ // From an array type S with an element type Se to an array type T with an
+ // element type Te provided all the following are true:
+ // * S and T differe only in element type, in other words, S and T
+ // have the same number of dimensions.
+ // * Both Se and Te are reference types
+ // * An explicit referenc conversions exist from Se to Te
+ //
+ if (source_type.IsArray && target_type.IsArray) {
+ if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
+
+ Type source_element_type = TypeManager.GetElementType (source_type);
+ Type target_element_type = TypeManager.GetElementType (target_type);
+
+ if (!source_element_type.IsValueType && !target_element_type.IsValueType)
+ if (ExplicitReferenceConversionExists (source_element_type,
+ target_element_type))
+ return new ClassCast (source, target_type);
+ }
+ }
+
+
+ // From System.Array to any array-type
+ if (source_type == TypeManager.array_type &&
+ target_type.IsArray) {
+ return new ClassCast (source, target_type);
+ }
+
+ //
+ // From System delegate to any delegate-type
+ //
+ if (source_type == TypeManager.delegate_type &&
+ TypeManager.IsDelegateType (target_type))
+ return new ClassCast (source, target_type);
+
+ //
+ // From ICloneable to Array or Delegate types
+ //
+ if (source_type == TypeManager.icloneable_type &&
+ (target_type == TypeManager.array_type ||
+ target_type == TypeManager.delegate_type))
+ return new ClassCast (source, target_type);
+
+ return null;
+ }
+
+ /// <summary>
+ /// Performs an explicit conversion of the expression `expr' whose
+ /// type is expr.Type to `target_type'.
+ /// </summary>
+ static public Expression ExplicitConversionCore (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+
+ // Explicit conversion includes implicit conversion and it used for enum underlying types too
+ Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
+ if (ne != null)
+ return ne;
+
+ //
+ // Unboxing conversions; only object types can be convertible to enum
+ //
+ if (expr_type == TypeManager.object_type && target_type.IsValueType)
+ return new UnboxCast (expr, target_type);
+
+ if (TypeManager.IsEnumType (expr_type)) {
+ if (expr is EnumConstant)
+ return ExplicitConversionCore (ec, ((EnumConstant) expr).Child, target_type, loc);
+
+ return ExplicitConversionCore (ec, new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)), target_type, loc);
+ }
+
+ if (TypeManager.IsEnumType (target_type)){
+ if (expr_type == TypeManager.enum_type)
+ return new UnboxCast (expr, target_type);
+
+ Expression ce = ExplicitConversionCore (ec, expr, TypeManager.EnumToUnderlying (target_type), loc);
+ if (ce != null)
+ return new EmptyCast (ce, target_type);
+ }
+
+ ne = ExplicitNumericConversion (expr, target_type);
+ if (ne != null)
+ return ne;
+
+ //
+ // Skip the ExplicitReferenceConversion because we can not convert
+ // from Null to a ValueType, and ExplicitReference wont check against
+ // null literal explicitly
+ //
+ if (expr_type != TypeManager.null_type){
+ ne = ExplicitReferenceConversion (expr, target_type);
+ if (ne != null)
+ return ne;
+ }
+
+ if (ec.InUnsafe){
+ ne = ExplicitUnsafe (expr, target_type);
+ if (ne != null)
+ return ne;
+ }
+
+ ne = ExplicitUserConversion (ec, expr, target_type, loc);
+ if (ne != null)
+ return ne;
+
+ return null;
+ }
+
+ public static Expression ExplicitUnsafe (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ if (target_type.IsPointer){
+ if (expr_type.IsPointer)
+ return new EmptyCast (expr, target_type);
+
+ if (expr_type == TypeManager.sbyte_type ||
+ expr_type == TypeManager.short_type ||
+ expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
+
+ if (expr_type == TypeManager.ushort_type ||
+ expr_type == TypeManager.uint32_type ||
+ expr_type == TypeManager.uint64_type ||
+ expr_type == TypeManager.byte_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
+ }
+
+ if (expr_type.IsPointer){
+ if (target_type == TypeManager.sbyte_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
+ else if (target_type == TypeManager.byte_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
+ else if (target_type == TypeManager.short_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
+ else if (target_type == TypeManager.ushort_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
+ else if (target_type == TypeManager.int32_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
+ else if (target_type == TypeManager.uint32_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
+ else if (target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ else if (target_type == TypeManager.int64_type){
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ }
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Same as ExplicitConversion, only it doesn't include user defined conversions
+ /// </summary>
+ static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
+ Type target_type, Location l)
+ {
+ int errors = Report.Errors;
+ Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
+ if (Report.Errors > errors)
+ return null;
+
+ if (ne != null)
+ return ne;
+
+ ne = ExplicitNumericConversion (expr, target_type);
+ if (ne != null)
+ return ne;
+
+ ne = ExplicitReferenceConversion (expr, target_type);
+ if (ne != null)
+ return ne;
+
+ if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
+ return new EmptyCast (expr, target_type);
+
+ expr.Error_ValueCannotBeConverted (l, target_type, true);
+ return null;
+ }
+
+ /// <summary>
+ /// Performs an explicit conversion of the expression `expr' whose
+ /// type is expr.Type to `target_type'.
+ /// </summary>
+ static public Expression ExplicitConversion (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Expression e;
+#if GMCS_SOURCE
+ Type expr_type = expr.Type;
+ if (TypeManager.IsNullableType (target_type)) {
+ if (TypeManager.IsNullableType (expr_type)) {
+ e = new Nullable.LiftedConversion (
+ expr, target_type, false, true, loc).Resolve (ec);
+ if (e != null)
+ return e;
+ } else if (expr_type == TypeManager.object_type) {
+ return new UnboxCast (expr, target_type);
+ } else {
+ Type target = TypeManager.GetTypeArguments (target_type) [0];
+
+ e = ExplicitConversionCore (ec, expr, target, loc);
+ if (e != null)
+ return Nullable.Wrap.Create (e, ec);
+ }
+ } else if (TypeManager.IsNullableType (expr_type)) {
+ Expression source = Nullable.Unwrap.Create (expr, ec);
+ if (source != null) {
+ e = ExplicitConversionCore (ec, source, target_type, loc);
+ if (e != null)
+ return e;
+ }
+ }
+#endif
+ e = ExplicitConversionCore (ec, expr, target_type, loc);
+ if (e != null)
+ return e;
+
+ expr.Error_ValueCannotBeConverted (loc, target_type, true);
+ return null;
+ }
+ }
+}
--- /dev/null
+%{
+//
+// cs-parser.jay: The Parser for the C# compiler
+//
+// Authors: Miguel de Icaza (miguel@gnu.org)
+// Ravi Pratap (ravi@ximian.com)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc
+//
+// TODO:
+// (1) Figure out why error productions dont work. `type-declaration' is a
+// great spot to put an `error' because you can reproduce it with this input:
+// "public X { }"
+//
+// Possible optimization:
+// Run memory profiler with parsing only, and consider dropping
+// arraylists where not needed. Some pieces can use linked lists.
+//
+using System.Text;
+using System.IO;
+using System;
+
+namespace Mono.CSharp
+{
+ using System.Collections;
+
+ /// <summary>
+ /// The C# Parser
+ /// </summary>
+ public class CSharpParser {
+ NamespaceEntry current_namespace;
+ TypeContainer current_container;
+ DeclSpace current_class;
+
+ IAnonymousHost anonymous_host;
+
+ /// <summary>
+ /// Current block is used to add statements as we find
+ /// them.
+ /// </summary>
+ Block current_block, top_current_block;
+
+ Delegate current_delegate;
+
+ AnonymousMethodExpression current_anonymous_method;
+
+ /// <summary>
+ /// This is used by the unary_expression code to resolve
+ /// a name against a parameter.
+ /// </summary>
+ Parameters current_local_parameters;
+
+ /// <summary>
+ /// Using during property parsing to describe the implicit
+ /// value parameter that is passed to the "set" and "get"accesor
+ /// methods (properties and indexers).
+ /// </summary>
+ Expression implicit_value_parameter_type;
+ Parameters indexer_parameters;
+
+ /// <summary>
+ /// Hack to help create non-typed array initializer
+ /// </summary>
+ public static Expression current_array_type;
+ Expression pushed_current_array_type;
+
+ /// <summary>
+ /// Used to determine if we are parsing the get/set pair
+ /// of an indexer or a property
+ /// </summmary>
+ bool parsing_indexer;
+
+ bool parsing_anonymous_method;
+
+ ///
+ /// An out-of-band stack.
+ ///
+ Stack oob_stack;
+
+ ///
+ /// Switch stack.
+ ///
+ Stack switch_stack;
+
+ static public int yacc_verbose_flag;
+
+ // Name of the file we are parsing
+ public string name;
+
+ ///
+ /// The current file.
+ ///
+ SourceFile file;
+
+ ///
+ /// Temporary Xml documentation cache.
+ /// For enum types, we need one more temporary store.
+ ///
+ string tmpComment;
+ string enumTypeComment;
+
+ /// Current attribute target
+ string current_attr_target;
+
+ /// assembly and module attribute definitions are enabled
+ bool global_attrs_enabled = true;
+ bool has_get, has_set;
+
+%}
+
+%token EOF
+%token NONE /* This token is never returned by our lexer */
+%token ERROR // This is used not by the parser, but by the tokenizer.
+ // do not remove.
+
+/*
+ *These are the C# keywords
+ */
+%token FIRST_KEYWORD
+%token ABSTRACT
+%token AS
+%token ADD
+%token ASSEMBLY
+%token BASE
+%token BOOL
+%token BREAK
+%token BYTE
+%token CASE
+%token CATCH
+%token CHAR
+%token CHECKED
+%token CLASS
+%token CONST
+%token CONTINUE
+%token DECIMAL
+%token DEFAULT
+%token DELEGATE
+%token DO
+%token DOUBLE
+%token ELSE
+%token ENUM
+%token EVENT
+%token EXPLICIT
+%token EXTERN
+%token FALSE
+%token FINALLY
+%token FIXED
+%token FLOAT
+%token FOR
+%token FOREACH
+%token GOTO
+%token IF
+%token IMPLICIT
+%token IN
+%token INT
+%token INTERFACE
+%token INTERNAL
+%token IS
+%token LOCK
+%token LONG
+%token NAMESPACE
+%token NEW
+%token NULL
+%token OBJECT
+%token OPERATOR
+%token OUT
+%token OVERRIDE
+%token PARAMS
+%token PRIVATE
+%token PROTECTED
+%token PUBLIC
+%token READONLY
+%token REF
+%token RETURN
+%token REMOVE
+%token SBYTE
+%token SEALED
+%token SHORT
+%token SIZEOF
+%token STACKALLOC
+%token STATIC
+%token STRING
+%token STRUCT
+%token SWITCH
+%token THIS
+%token THROW
+%token TRUE
+%token TRY
+%token TYPEOF
+%token UINT
+%token ULONG
+%token UNCHECKED
+%token UNSAFE
+%token USHORT
+%token USING
+%token VIRTUAL
+%token VOID
+%token VOLATILE
+%token WHILE
+%token ARGLIST
+%token PARTIAL
+
+/* C# keywords which are not really keywords */
+%token GET "get"
+%token SET "set"
+
+%left LAST_KEYWORD
+
+/* C# single character operators/punctuation. */
+%token OPEN_BRACE "{"
+%token CLOSE_BRACE "}"
+%token OPEN_BRACKET "["
+%token CLOSE_BRACKET "]"
+%token OPEN_PARENS "("
+%token CLOSE_PARENS ")"
+%token DOT "."
+%token COMMA ","
+%token COLON ":"
+%token SEMICOLON ";"
+%token TILDE "~"
+
+%token PLUS "+"
+%token MINUS "-"
+%token BANG "!"
+%token ASSIGN "="
+%token OP_LT "<"
+%token OP_GT ">"
+%token BITWISE_AND "&"
+%token BITWISE_OR "|"
+%token STAR "*"
+%token PERCENT "%"
+%token DIV "/"
+%token CARRET "^"
+%token INTERR "?"
+
+/* C# multi-character operators. */
+%token DOUBLE_COLON "::"
+%token OP_INC "++"
+%token OP_DEC "--"
+%token OP_SHIFT_LEFT "<<"
+%token OP_SHIFT_RIGHT ">>"
+%token OP_LE "<="
+%token OP_GE ">="
+%token OP_EQ "=="
+%token OP_NE "!="
+%token OP_AND "&&"
+%token OP_OR "||"
+%token OP_MULT_ASSIGN "*="
+%token OP_DIV_ASSIGN "/="
+%token OP_MOD_ASSIGN "%="
+%token OP_ADD_ASSIGN "+="
+%token OP_SUB_ASSIGN "-="
+%token OP_SHIFT_LEFT_ASSIGN "<<="
+%token OP_SHIFT_RIGHT_ASSIGN ">>="
+%token OP_AND_ASSIGN "&="
+%token OP_XOR_ASSIGN "^="
+%token OP_OR_ASSIGN "|="
+%token OP_PTR "->"
+
+/* Numbers */
+%token LITERAL_INTEGER "int literal"
+%token LITERAL_FLOAT "float literal"
+%token LITERAL_DOUBLE "double literal"
+%token LITERAL_DECIMAL "decimal literal"
+%token LITERAL_CHARACTER "character literal"
+%token LITERAL_STRING "string literal"
+
+%token IDENTIFIER
+%token CLOSE_PARENS_CAST
+%token CLOSE_PARENS_NO_CAST
+%token CLOSE_PARENS_OPEN_PARENS
+%token CLOSE_PARENS_MINUS
+
+/* Add precedence rules to solve dangling else s/r conflict */
+%nonassoc LOWPREC
+%nonassoc IF
+%nonassoc ELSE
+%right ASSIGN
+%left OP_OR
+%left OP_AND
+%left BITWISE_OR
+%left BITWISE_AND
+%left OP_SHIFT_LEFT OP_SHIFT_RIGHT
+%left PLUS MINUS
+%left STAR DIV PERCENT
+%right BANG CARRET UMINUS
+%nonassoc OP_INC OP_DEC
+%left OPEN_PARENS
+%left OPEN_BRACKET OPEN_BRACE
+%left DOT
+%nonassoc HIGHPREC
+
+%start compilation_unit
+%%
+
+compilation_unit
+ : outer_declarations opt_EOF
+ | outer_declarations global_attributes opt_EOF
+ | global_attributes opt_EOF
+ | opt_EOF /* allow empty files */
+ ;
+
+opt_EOF
+ : /* empty */
+ {
+ Lexer.check_incorrect_doc_comment ();
+ }
+ | EOF
+ {
+ Lexer.check_incorrect_doc_comment ();
+ }
+ ;
+
+outer_declarations
+ : outer_declaration
+ | outer_declarations outer_declaration
+ ;
+
+outer_declaration
+ : extern_alias_directive
+ | using_directive
+ | namespace_member_declaration
+ ;
+
+extern_alias_directives
+ : extern_alias_directive
+ | extern_alias_directives extern_alias_directive;
+
+extern_alias_directive
+ : EXTERN IDENTIFIER IDENTIFIER SEMICOLON
+ {
+ LocatedToken lt = (LocatedToken) $2;
+ string s = lt.Value;
+ if (s != "alias"){
+ Report.Error (1003, lt.Location, "'alias' expected");
+ } else if (RootContext.Version == LanguageVersion.ISO_1) {
+ Report.FeatureIsNotStandardized (lt.Location, "external alias");
+ } else {
+ lt = (LocatedToken) $3;
+ current_namespace.UsingExternalAlias (lt.Value, lt.Location);
+ }
+ }
+ ;
+
+using_directives
+ : using_directive
+ | using_directives using_directive
+ ;
+
+using_directive
+ : using_alias_directive
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ | using_namespace_directive
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ ;
+
+using_alias_directive
+ : USING IDENTIFIER ASSIGN
+ namespace_or_type_name SEMICOLON
+ {
+ LocatedToken lt = (LocatedToken) $2;
+ current_namespace.UsingAlias (lt.Value, (MemberName) $4, (Location) $1);
+ }
+ | USING error {
+ CheckIdentifierToken (yyToken, GetLocation ($2));
+ }
+ ;
+
+using_namespace_directive
+ : USING namespace_name SEMICOLON
+ {
+ current_namespace.Using ((MemberName) $2, (Location) $1);
+ }
+ ;
+
+//
+// Strictly speaking, namespaces don't have attributes but
+// we parse global attributes along with namespace declarations and then
+// detach them
+//
+namespace_declaration
+ : opt_attributes NAMESPACE namespace_or_type_name
+ {
+ MemberName name = (MemberName) $3;
+
+ if ($1 != null) {
+ Report.Error(1671, name.Location, "A namespace declaration cannot have modifiers or attributes");
+ }
+
+ current_namespace = new NamespaceEntry (
+ current_namespace, file, name.GetName ());
+ current_class = current_namespace.SlaveDeclSpace;
+ current_container = current_class.PartialContainer;
+ }
+ namespace_body opt_semicolon
+ {
+ current_namespace = current_namespace.Parent;
+ current_class = current_namespace.SlaveDeclSpace;
+ current_container = current_class.PartialContainer;
+ }
+ ;
+
+opt_semicolon
+ : /* empty */
+ | SEMICOLON
+ ;
+
+opt_comma
+ : /* empty */
+ | COMMA
+ ;
+
+namespace_name
+ : namespace_or_type_name
+ ;
+
+namespace_body
+ : OPEN_BRACE
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ opt_extern_alias_directives
+ opt_using_directives
+ opt_namespace_member_declarations
+ CLOSE_BRACE
+ ;
+
+opt_using_directives
+ : /* empty */
+ | using_directives
+ ;
+
+opt_extern_alias_directives
+ : /* empty */
+ | extern_alias_directives
+ ;
+
+opt_namespace_member_declarations
+ : /* empty */
+ | namespace_member_declarations
+ ;
+
+namespace_member_declarations
+ : namespace_member_declaration
+ | namespace_member_declarations namespace_member_declaration
+ ;
+
+namespace_member_declaration
+ : type_declaration
+ {
+ if ($1 != null) {
+ DeclSpace ds = (DeclSpace)$1;
+
+ if ((ds.ModFlags & (Modifiers.PRIVATE|Modifiers.PROTECTED)) != 0){
+ Report.Error (1527, ds.Location,
+ "Namespace elements cannot be explicitly declared as private, protected or protected internal");
+ }
+ }
+ current_namespace.DeclarationFound = true;
+ }
+ | namespace_declaration {
+ current_namespace.DeclarationFound = true;
+ }
+
+ | field_declaration {
+ Report.Error (116, ((MemberCore) $1).Location, "A namespace can only contain types and namespace declarations");
+ }
+ | method_declaration {
+ Report.Error (116, ((MemberCore) $1).Location, "A namespace can only contain types and namespace declarations");
+ }
+ ;
+
+type_declaration
+ : class_declaration
+ | struct_declaration
+ | interface_declaration
+ | enum_declaration
+ | delegate_declaration
+//
+// Enable this when we have handled all errors, because this acts as a generic fallback
+//
+// | error {
+// Console.WriteLine ("Token=" + yyToken);
+// Report.Error (1518, GetLocation ($1), "Expected class, struct, interface, enum or delegate");
+// }
+ ;
+
+//
+// Attributes 17.2
+//
+
+global_attributes
+ : attribute_sections
+{
+ if ($1 != null)
+ CodeGen.Assembly.AddAttributes (((Attributes)$1).Attrs);
+
+ $$ = $1;
+}
+
+opt_attributes
+ : /* empty */
+ {
+ global_attrs_enabled = false;
+ $$ = null;
+ }
+ | attribute_sections
+ {
+ global_attrs_enabled = false;
+ $$ = $1;
+ }
+ ;
+
+
+attribute_sections
+ : attribute_section
+ {
+ ArrayList sect = (ArrayList) $1;
+
+ if (global_attrs_enabled) {
+ if (current_attr_target == "module") {
+ CodeGen.Module.AddAttributes (sect);
+ $$ = null;
+ } else if (current_attr_target != null && current_attr_target.Length > 0) {
+ CodeGen.Assembly.AddAttributes (sect);
+ $$ = null;
+ } else {
+ $$ = new Attributes (sect);
+ }
+ if ($$ == null) {
+ if (RootContext.Documentation != null) {
+ Lexer.check_incorrect_doc_comment ();
+ Lexer.doc_state =
+ XmlCommentState.Allowed;
+ }
+ }
+ } else {
+ $$ = new Attributes (sect);
+ }
+ current_attr_target = null;
+ }
+ | attribute_sections attribute_section
+ {
+ Attributes attrs = $1 as Attributes;
+ ArrayList sect = (ArrayList) $2;
+
+ if (global_attrs_enabled) {
+ if (current_attr_target == "module") {
+ CodeGen.Module.AddAttributes (sect);
+ $$ = null;
+ } else if (current_attr_target == "assembly") {
+ CodeGen.Assembly.AddAttributes (sect);
+ $$ = null;
+ } else {
+ if (attrs == null)
+ attrs = new Attributes (sect);
+ else
+ attrs.AddAttributes (sect);
+ }
+ } else {
+ if (attrs == null)
+ attrs = new Attributes (sect);
+ else
+ attrs.AddAttributes (sect);
+ }
+ $$ = attrs;
+ current_attr_target = null;
+ }
+ ;
+
+attribute_section
+ : OPEN_BRACKET attribute_target_specifier attribute_list opt_comma CLOSE_BRACKET
+ {
+ $$ = $3;
+ }
+ | OPEN_BRACKET attribute_list opt_comma CLOSE_BRACKET
+ {
+ $$ = $2;
+ }
+ ;
+
+attribute_target_specifier
+ : attribute_target COLON
+ {
+ current_attr_target = (string)$1;
+ $$ = $1;
+ }
+ ;
+
+attribute_target
+ : IDENTIFIER
+ {
+ LocatedToken lt = (LocatedToken) $1;
+ CheckAttributeTarget (lt.Value, lt.Location);
+ $$ = lt.Value; // Location won't be required anymore.
+ }
+ | EVENT { $$ = "event"; }
+ | RETURN { $$ = "return"; }
+ ;
+
+attribute_list
+ : attribute
+ {
+ ArrayList attrs = new ArrayList (4);
+ attrs.Add ($1);
+
+ $$ = attrs;
+
+ }
+ | attribute_list COMMA attribute
+ {
+ ArrayList attrs = (ArrayList) $1;
+ attrs.Add ($3);
+
+ $$ = attrs;
+ }
+ ;
+
+attribute
+ : attribute_name opt_attribute_arguments
+ {
+ MemberName mname = (MemberName) $1;
+ object[] arguments = (object[]) $2;
+ MemberName left = mname.Left;
+ string identifier = mname.Name;
+
+ Expression left_expr = left == null ? null : left.GetTypeExpression ();
+
+ if (current_attr_target == "assembly" || current_attr_target == "module")
+ // FIXME: supply "nameEscaped" parameter here.
+ $$ = new GlobalAttribute (current_namespace, current_attr_target,
+ left_expr, identifier, arguments, mname.Location, lexer.IsEscapedIdentifier (mname.Location));
+ else
+ $$ = new Attribute (current_attr_target, left_expr, identifier, arguments, mname.Location, lexer.IsEscapedIdentifier (mname.Location));
+ }
+ ;
+
+attribute_name
+ : namespace_or_type_name { /* reserved attribute name or identifier: 17.4 */ }
+ ;
+
+opt_attribute_arguments
+ : /* empty */ { $$ = null; }
+ | OPEN_PARENS attribute_arguments CLOSE_PARENS
+ {
+ $$ = $2;
+ }
+ ;
+
+
+attribute_arguments
+ : opt_positional_argument_list
+ {
+ if ($1 == null)
+ $$ = null;
+ else {
+ $$ = new object [] { $1, null };
+ }
+ }
+ | positional_argument_list COMMA named_argument_list
+ {
+ $$ = new object[] { $1, $3 };
+ }
+ | named_argument_list
+ {
+ $$ = new object [] { null, $1 };
+ }
+ ;
+
+
+opt_positional_argument_list
+ : /* empty */ { $$ = null; }
+ | positional_argument_list
+ ;
+
+positional_argument_list
+ : expression
+ {
+ ArrayList args = new ArrayList (4);
+ args.Add (new Argument ((Expression) $1, Argument.AType.Expression));
+
+ $$ = args;
+ }
+ | positional_argument_list COMMA expression
+ {
+ ArrayList args = (ArrayList) $1;
+ args.Add (new Argument ((Expression) $3, Argument.AType.Expression));
+
+ $$ = args;
+ }
+ ;
+
+named_argument_list
+ : named_argument
+ {
+ ArrayList args = new ArrayList (4);
+ args.Add ($1);
+
+ $$ = args;
+ }
+ | named_argument_list COMMA named_argument
+ {
+ ArrayList args = (ArrayList) $1;
+ args.Add ($3);
+
+ $$ = args;
+ }
+ | named_argument_list COMMA expression
+ {
+ Report.Error (1016, ((Expression) $3).Location, "Named attribute argument expected");
+ $$ = null;
+ }
+ ;
+
+named_argument
+ : IDENTIFIER ASSIGN expression
+ {
+ // FIXME: keep location
+ $$ = new DictionaryEntry (
+ ((LocatedToken) $1).Value,
+ new Argument ((Expression) $3, Argument.AType.Expression));
+ }
+ ;
+
+
+class_body
+ : OPEN_BRACE opt_class_member_declarations CLOSE_BRACE
+ ;
+
+opt_class_member_declarations
+ : /* empty */
+ | class_member_declarations
+ ;
+
+class_member_declarations
+ : class_member_declaration
+ | class_member_declarations
+ class_member_declaration
+ ;
+
+class_member_declaration
+ : constant_declaration // done
+ | field_declaration // done
+ | method_declaration // done
+ | property_declaration // done
+ | event_declaration // done
+ | indexer_declaration // done
+ | operator_declaration // done
+ | constructor_declaration // done
+ | destructor_declaration // done
+ | type_declaration
+ ;
+
+struct_declaration
+ : opt_attributes
+ opt_modifiers
+ opt_partial
+ STRUCT member_name
+ {
+ MemberName name = MakeName ((MemberName) $5);
+ push_current_class (new Struct (
+ current_namespace, current_class, name, (int) $2,
+ (Attributes) $1), false, $3);
+
+ }
+ opt_class_base
+ {
+ if ($7 != null)
+ current_container.AddBasesForPart (current_class, (ArrayList) $7);
+
+ if (RootContext.Documentation != null)
+ current_container.DocComment = Lexer.consume_doc_comment ();
+ }
+ struct_body
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ opt_semicolon
+ {
+ $$ = pop_current_class ();
+ }
+ | opt_attributes opt_modifiers opt_partial STRUCT error {
+ CheckIdentifierToken (yyToken, GetLocation ($5));
+ }
+ ;
+
+struct_body
+ : OPEN_BRACE
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ opt_struct_member_declarations CLOSE_BRACE
+ ;
+
+opt_struct_member_declarations
+ : /* empty */
+ | struct_member_declarations
+ ;
+
+struct_member_declarations
+ : struct_member_declaration
+ | struct_member_declarations struct_member_declaration
+ ;
+
+struct_member_declaration
+ : constant_declaration
+ | field_declaration
+ | method_declaration
+ | property_declaration
+ | event_declaration
+ | indexer_declaration
+ | operator_declaration
+ | constructor_declaration
+ | type_declaration
+
+ /*
+ * This is only included so we can flag error 575:
+ * destructors only allowed on class types
+ */
+ | destructor_declaration
+ ;
+
+constant_declaration
+ : opt_attributes
+ opt_modifiers
+ CONST
+ type
+ constant_declarators
+ SEMICOLON
+ {
+ int modflags = (int) $2;
+ foreach (VariableDeclaration constant in (ArrayList) $5){
+ Location l = constant.Location;
+ if ((modflags & Modifiers.STATIC) != 0) {
+ Report.Error (504, l, "The constant `{0}' cannot be marked static", current_container.GetSignatureForError () + '.' + (string) constant.identifier);
+ continue;
+ }
+
+ Const c = new Const (
+ current_class, (Expression) $4, (string) constant.identifier,
+ (Expression) constant.expression_or_array_initializer, modflags,
+ (Attributes) $1, l);
+
+ if (RootContext.Documentation != null) {
+ c.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ current_container.AddConstant (c);
+ }
+ }
+ ;
+
+constant_declarators
+ : constant_declarator
+ {
+ ArrayList constants = new ArrayList (4);
+ if ($1 != null)
+ constants.Add ($1);
+ $$ = constants;
+ }
+ | constant_declarators COMMA constant_declarator
+ {
+ if ($3 != null) {
+ ArrayList constants = (ArrayList) $1;
+ constants.Add ($3);
+ }
+ }
+ ;
+
+constant_declarator
+ : IDENTIFIER ASSIGN constant_expression
+ {
+ $$ = new VariableDeclaration ((LocatedToken) $1, $3);
+ }
+ | IDENTIFIER
+ {
+ // A const field requires a value to be provided
+ Report.Error (145, ((LocatedToken) $1).Location, "A const field requires a value to be provided");
+ $$ = null;
+ }
+ ;
+
+field_declaration
+ : opt_attributes
+ opt_modifiers
+ type
+ variable_declarators
+ SEMICOLON
+ {
+ Expression type = (Expression) $3;
+ int mod = (int) $2;
+
+ current_array_type = null;
+
+ foreach (VariableDeclaration var in (ArrayList) $4){
+ Field field = new Field (current_class, type, mod, var.identifier,
+ (Attributes) $1, var.Location);
+
+ field.Initializer = var.expression_or_array_initializer;
+
+ if (RootContext.Documentation != null) {
+ field.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ current_container.AddField (field);
+ $$ = field; // FIXME: might be better if it points to the top item
+ }
+ }
+ | opt_attributes
+ opt_modifiers
+ FIXED
+ type
+ fixed_variable_declarators
+ SEMICOLON
+ {
+ Expression type = (Expression) $4;
+ int mod = (int) $2;
+
+ current_array_type = null;
+
+ foreach (VariableDeclaration var in (ArrayList) $5) {
+ FixedField field = new FixedField (current_class, type, mod, var.identifier,
+ (Expression)var.expression_or_array_initializer, (Attributes) $1, var.Location);
+
+ if (RootContext.Documentation != null) {
+ field.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ current_container.AddField (field);
+ $$ = field; // FIXME: might be better if it points to the top item
+ }
+ }
+ | opt_attributes
+ opt_modifiers
+ VOID
+ variable_declarators
+ SEMICOLON {
+ current_array_type = null;
+ Report.Error (670, (Location) $3, "Fields cannot have void type");
+ }
+ ;
+
+fixed_variable_declarators
+ : fixed_variable_declarator
+ {
+ ArrayList decl = new ArrayList (2);
+ decl.Add ($1);
+ $$ = decl;
+ }
+ | fixed_variable_declarators COMMA fixed_variable_declarator
+ {
+ ArrayList decls = (ArrayList) $1;
+ decls.Add ($3);
+ $$ = $1;
+ }
+ ;
+
+fixed_variable_declarator
+ : IDENTIFIER OPEN_BRACKET expression CLOSE_BRACKET
+ {
+ $$ = new VariableDeclaration ((LocatedToken) $1, $3);
+ }
+ | IDENTIFIER OPEN_BRACKET CLOSE_BRACKET
+ {
+ Report.Error (443, lexer.Location, "Value or constant expected");
+ $$ = new VariableDeclaration ((LocatedToken) $1, null);
+ }
+ ;
+
+variable_declarators
+ : variable_declarator
+ {
+ ArrayList decl = new ArrayList (4);
+ if ($1 != null)
+ decl.Add ($1);
+ $$ = decl;
+ }
+ | variable_declarators COMMA variable_declarator
+ {
+ ArrayList decls = (ArrayList) $1;
+ decls.Add ($3);
+ $$ = $1;
+ }
+ ;
+
+variable_declarator
+ : IDENTIFIER ASSIGN variable_initializer
+ {
+ $$ = new VariableDeclaration ((LocatedToken) $1, $3);
+ }
+ | IDENTIFIER
+ {
+ $$ = new VariableDeclaration ((LocatedToken) $1, null);
+ }
+ | IDENTIFIER OPEN_BRACKET opt_expression CLOSE_BRACKET
+ {
+ Report.Error (650, ((LocatedToken) $1).Location, "Syntax error, bad array declarator. To declare a managed array the rank specifier precedes the variable's identifier. " +
+ "To declare a fixed size buffer field, use the fixed keyword before the field type");
+ $$ = null;
+ }
+ ;
+
+variable_initializer
+ : expression
+ {
+ $$ = $1;
+ }
+ | array_initializer
+ {
+ $$ = $1;
+ }
+ | STACKALLOC type OPEN_BRACKET expression CLOSE_BRACKET
+ {
+ $$ = new StackAlloc ((Expression) $2, (Expression) $4, (Location) $1);
+ }
+ | ARGLIST
+ {
+ $$ = new ArglistAccess ((Location) $1);
+ }
+ | STACKALLOC type
+ {
+ Report.Error (1575, (Location) $1, "A stackalloc expression requires [] after type");
+ $$ = null;
+ }
+ ;
+
+method_declaration
+ : method_header {
+ anonymous_host = (IAnonymousHost) $1;
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+ method_body
+ {
+ Method method = (Method) $1;
+ method.Block = (ToplevelBlock) $3;
+ current_container.AddMethod (method);
+
+ anonymous_host = null;
+ current_local_parameters = null;
+
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ ;
+
+opt_error_modifier
+ : /* empty */
+ | modifiers
+ {
+ int m = (int) $1;
+ int i = 1;
+
+ while (m != 0){
+ if ((i & m) != 0){
+ Report.Error (1585, lexer.Location,
+ "Member modifier `{0}' must precede the member type and name",
+ Modifiers.Name (i));
+ }
+ m &= ~i;
+ i = i << 1;
+ }
+ }
+ ;
+
+method_header
+ : opt_attributes
+ opt_modifiers
+ type namespace_or_type_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ MemberName name = (MemberName) $4;
+
+ Method method = new Method (current_class, null, (Expression) $3, (int) $2,
+ false, name, (Parameters) $6, (Attributes) $1);
+
+ anonymous_host = method;
+ current_local_parameters = (Parameters) $6;
+
+ if (RootContext.Documentation != null)
+ method.DocComment = Lexer.consume_doc_comment ();
+
+ $$ = method;
+ }
+ | opt_attributes
+ opt_modifiers
+ VOID namespace_or_type_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ MemberName name = (MemberName) $4;
+
+ Method method = new Method (current_class, null, TypeManager.system_void_expr,
+ (int) $2, false, name, (Parameters) $6,
+ (Attributes) $1);
+
+ anonymous_host = method;
+ current_local_parameters = (Parameters) $6;
+
+ if (RootContext.Documentation != null)
+ method.DocComment = Lexer.consume_doc_comment ();
+
+ $$ = method;
+ }
+ | opt_attributes
+ opt_modifiers
+ type
+ modifiers namespace_or_type_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ MemberName name = (MemberName) $5;
+ Report.Error (1585, name.Location,
+ "Member modifier `{0}' must precede the member type and name", Modifiers.Name ((int) $4));
+
+ Method method = new Method (current_class, null, TypeManager.system_void_expr,
+ 0, false, name, (Parameters) $7, (Attributes) $1);
+
+ current_local_parameters = (Parameters) $7;
+
+ if (RootContext.Documentation != null)
+ method.DocComment = Lexer.consume_doc_comment ();
+
+ $$ = null;
+ }
+ ;
+
+method_body
+ : block
+ | SEMICOLON { $$ = null; }
+ ;
+
+opt_formal_parameter_list
+ : /* empty */ { $$ = Parameters.EmptyReadOnlyParameters; }
+ | formal_parameter_list
+ ;
+
+formal_parameter_list
+ : fixed_parameters
+ {
+ ArrayList pars_list = (ArrayList) $1;
+
+ Parameter [] pars = new Parameter [pars_list.Count];
+ pars_list.CopyTo (pars);
+
+ $$ = new Parameters (pars);
+ }
+ | fixed_parameters COMMA parameter_array
+ {
+ ArrayList pars_list = (ArrayList) $1;
+ pars_list.Add ($3);
+
+ Parameter [] pars = new Parameter [pars_list.Count];
+ pars_list.CopyTo (pars);
+
+ $$ = new Parameters (pars);
+ }
+ | fixed_parameters COMMA ARGLIST
+ {
+ ArrayList pars_list = (ArrayList) $1;
+ //pars_list.Add (new ArglistParameter (GetLocation ($3)));
+
+ Parameter [] pars = new Parameter [pars_list.Count];
+ pars_list.CopyTo (pars);
+
+ $$ = new Parameters (pars, true);
+ }
+ | parameter_array COMMA error
+ {
+ if ($1 != null)
+ Report.Error (231, ((Parameter) $1).Location, "A params parameter must be the last parameter in a formal parameter list");
+ $$ = null;
+ }
+ | fixed_parameters COMMA parameter_array COMMA error
+ {
+ if ($3 != null)
+ Report.Error (231, ((Parameter) $3).Location, "A params parameter must be the last parameter in a formal parameter list");
+ $$ = null;
+ }
+ | ARGLIST COMMA error
+ {
+ Report.Error (257, (Location) $1, "An __arglist parameter must be the last parameter in a formal parameter list");
+ $$ = null;
+ }
+ | fixed_parameters COMMA ARGLIST COMMA error
+ {
+ Report.Error (257, (Location) $3, "An __arglist parameter must be the last parameter in a formal parameter list");
+ $$ = null;
+ }
+ | parameter_array
+ {
+ $$ = new Parameters (new Parameter[] { (Parameter) $1 } );
+ }
+ | ARGLIST
+ {
+ $$ = new Parameters (new Parameter[0], true);
+ }
+ ;
+
+fixed_parameters
+ : fixed_parameter
+ {
+ ArrayList pars = new ArrayList (4);
+
+ pars.Add ($1);
+ $$ = pars;
+ }
+ | fixed_parameters COMMA fixed_parameter
+ {
+ ArrayList pars = (ArrayList) $1;
+
+ pars.Add ($3);
+ $$ = $1;
+ }
+ ;
+
+fixed_parameter
+ : opt_attributes
+ opt_parameter_modifier
+ type
+ IDENTIFIER
+ {
+ LocatedToken lt = (LocatedToken) $4;
+ $$ = new Parameter ((Expression) $3, lt.Value, (Parameter.Modifier) $2, (Attributes) $1, lt.Location);
+ }
+ | opt_attributes
+ opt_parameter_modifier
+ type
+ IDENTIFIER OPEN_BRACKET CLOSE_BRACKET
+ {
+ LocatedToken lt = (LocatedToken) $4;
+ Report.Error (1552, lt.Location, "Array type specifier, [], must appear before parameter name");
+ $$ = null;
+ }
+ | opt_attributes
+ opt_parameter_modifier
+ type
+ {
+ Report.Error (1001, GetLocation ($3), "Identifier expected");
+ $$ = null;
+ }
+ | opt_attributes
+ opt_parameter_modifier
+ type
+ error {
+ CheckIdentifierToken (yyToken, GetLocation ($4));
+ $$ = null;
+ }
+ | opt_attributes
+ opt_parameter_modifier
+ type
+ IDENTIFIER
+ ASSIGN
+ constant_expression
+ {
+ LocatedToken lt = (LocatedToken) $4;
+ Report.Error (241, lt.Location, "Default parameter specifiers are not permitted");
+ $$ = null;
+ }
+ ;
+
+opt_parameter_modifier
+ : /* empty */ { $$ = Parameter.Modifier.NONE; }
+ | parameter_modifier
+ ;
+
+parameter_modifier
+ : REF { $$ = Parameter.Modifier.REF; }
+ | OUT { $$ = Parameter.Modifier.OUT; }
+ ;
+
+parameter_array
+ : opt_attributes PARAMS type IDENTIFIER
+ {
+ LocatedToken lt = (LocatedToken) $4;
+ $$ = new ParamsParameter ((Expression) $3, lt.Value, (Attributes) $1, lt.Location);
+ note ("type must be a single-dimension array type");
+ }
+ | opt_attributes PARAMS parameter_modifier type IDENTIFIER
+ {
+ Report.Error (1611, (Location) $2, "The params parameter cannot be declared as ref or out");
+ $$ = null;
+ }
+ | opt_attributes PARAMS type error {
+ CheckIdentifierToken (yyToken, GetLocation ($4));
+ $$ = null;
+ }
+ ;
+
+property_declaration
+ : opt_attributes
+ opt_modifiers
+ type
+ namespace_or_type_name
+ {
+ if (RootContext.Documentation != null)
+ tmpComment = Lexer.consume_doc_comment ();
+ }
+ OPEN_BRACE
+ {
+ implicit_value_parameter_type = (Expression) $3;
+
+ lexer.PropertyParsing = true;
+ }
+ accessor_declarations
+ {
+ lexer.PropertyParsing = false;
+ has_get = has_set = false;
+ }
+ CLOSE_BRACE
+ {
+ if ($8 == null)
+ break;
+
+ Property prop;
+ Pair pair = (Pair) $8;
+ Accessor get_block = (Accessor) pair.First;
+ Accessor set_block = (Accessor) pair.Second;
+
+ MemberName name = (MemberName) $4;
+
+ prop = new Property (current_class, (Expression) $3, (int) $2,
+ false, name, (Attributes) $1, get_block, set_block);
+
+ current_container.AddProperty (prop);
+ implicit_value_parameter_type = null;
+
+ if (RootContext.Documentation != null)
+ prop.DocComment = ConsumeStoredComment ();
+
+ }
+ ;
+
+accessor_declarations
+ : get_accessor_declaration
+ {
+ $$ = new Pair ($1, null);
+ }
+ | get_accessor_declaration accessor_declarations
+ {
+ Pair pair = (Pair) $2;
+ pair.First = $1;
+ $$ = pair;
+ }
+ | set_accessor_declaration
+ {
+ $$ = new Pair (null, $1);
+ }
+ | set_accessor_declaration accessor_declarations
+ {
+ Pair pair = (Pair) $2;
+ pair.Second = $1;
+ $$ = pair;
+ }
+ | error
+ {
+ Report.Error (1014, GetLocation ($1), "A get or set accessor expected");
+ $$ = null;
+ }
+ ;
+
+get_accessor_declaration
+ : opt_attributes opt_modifiers GET
+ {
+ // If this is not the case, then current_local_parameters has already
+ // been set in indexer_declaration
+ if (parsing_indexer == false)
+ current_local_parameters = null;
+ else
+ current_local_parameters = indexer_parameters;
+ lexer.PropertyParsing = false;
+
+ anonymous_host = SimpleAnonymousHost.GetSimple ();
+ }
+ accessor_body
+ {
+ if (has_get) {
+ Report.Error (1007, (Location) $3, "Property accessor already defined");
+ break;
+ }
+ Accessor accessor = new Accessor ((ToplevelBlock) $5, (int) $2, (Attributes) $1, (Location) $3);
+ has_get = true;
+ current_local_parameters = null;
+ lexer.PropertyParsing = true;
+
+ SimpleAnonymousHost.Simple.Propagate (accessor);
+ anonymous_host = null;
+
+ if (RootContext.Documentation != null)
+ if (Lexer.doc_state == XmlCommentState.Error)
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+
+ $$ = accessor;
+ }
+ ;
+
+set_accessor_declaration
+ : opt_attributes opt_modifiers SET
+ {
+ Parameter [] args;
+ Parameter implicit_value_parameter = new Parameter (
+ implicit_value_parameter_type, "value",
+ Parameter.Modifier.NONE, null, (Location) $3);
+
+ if (parsing_indexer == false) {
+ args = new Parameter [1];
+ args [0] = implicit_value_parameter;
+ current_local_parameters = new Parameters (args);
+ } else {
+ Parameter [] fpars = indexer_parameters.FixedParameters;
+
+ if (fpars != null){
+ int count = fpars.Length;
+
+ args = new Parameter [count + 1];
+ fpars.CopyTo (args, 0);
+ args [count] = implicit_value_parameter;
+ } else
+ args = null;
+ current_local_parameters = new Parameters (
+ args);
+ }
+
+ lexer.PropertyParsing = false;
+
+ anonymous_host = SimpleAnonymousHost.GetSimple ();
+ }
+ accessor_body
+ {
+ if (has_set) {
+ Report.Error (1007, ((LocatedToken) $3).Location, "Property accessor already defined");
+ break;
+ }
+ Accessor accessor = new Accessor ((ToplevelBlock) $5, (int) $2, (Attributes) $1, (Location) $3);
+ has_set = true;
+ current_local_parameters = null;
+ lexer.PropertyParsing = true;
+
+ SimpleAnonymousHost.Simple.Propagate (accessor);
+ anonymous_host = null;
+
+ if (RootContext.Documentation != null
+ && Lexer.doc_state == XmlCommentState.Error)
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+
+ $$ = accessor;
+ }
+ ;
+
+accessor_body
+ : block
+ | SEMICOLON { $$ = null; }
+ ;
+
+interface_declaration
+ : opt_attributes
+ opt_modifiers
+ opt_partial
+ INTERFACE member_name
+ {
+ MemberName name = MakeName ((MemberName) $5);
+
+ push_current_class (new Interface (
+ current_namespace, current_class, name, (int) $2,
+ (Attributes) $1), true, $3);
+ }
+ opt_class_base
+ {
+ current_container.AddBasesForPart (current_class, (ArrayList) $7);
+
+ if (RootContext.Documentation != null) {
+ current_container.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ }
+ interface_body
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ opt_semicolon
+ {
+ $$ = pop_current_class ();
+ }
+ | opt_attributes opt_modifiers opt_partial INTERFACE error {
+ CheckIdentifierToken (yyToken, GetLocation ($5));
+ }
+ ;
+
+interface_body
+ : OPEN_BRACE
+ opt_interface_member_declarations
+ CLOSE_BRACE
+ ;
+
+opt_interface_member_declarations
+ : /* empty */
+ | interface_member_declarations
+ ;
+
+interface_member_declarations
+ : interface_member_declaration
+ | interface_member_declarations interface_member_declaration
+ ;
+
+interface_member_declaration
+ : interface_method_declaration
+ {
+ if ($1 == null)
+ break;
+
+ Method m = (Method) $1;
+
+ if (m.IsExplicitImpl)
+ Report.Error (541, m.Location, "`{0}': explicit interface declaration can only be declared in a class or struct",
+ m.GetSignatureForError ());
+
+ current_container.AddMethod (m);
+
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ | interface_property_declaration
+ {
+ if ($1 == null)
+ break;
+
+ Property p = (Property) $1;
+
+ if (p.IsExplicitImpl)
+ Report.Error (541, p.Location, "`{0}': explicit interface declaration can only be declared in a class or struct",
+ p.GetSignatureForError ());
+
+ current_container.AddProperty (p);
+
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ | interface_event_declaration
+ {
+ if ($1 != null){
+ Event e = (Event) $1;
+
+ if (e.IsExplicitImpl)
+ Report.Error (541, e.Location, "`{0}': explicit interface declaration can only be declared in a class or struct",
+ e.GetSignatureForError ());
+
+ current_container.AddEvent (e);
+ }
+
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ | interface_indexer_declaration
+ {
+ if ($1 == null)
+ break;
+
+ Indexer i = (Indexer) $1;
+
+ if (i.IsExplicitImpl)
+ Report.Error (541, i.Location, "`{0}': explicit interface declaration can only be declared in a class or struct",
+ i.GetSignatureForError ());
+
+ current_container.AddIndexer (i);
+
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ | delegate_declaration
+ {
+ if ($1 != null) {
+ Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants",
+ ((MemberCore)$1).GetSignatureForError ());
+ }
+ }
+ | class_declaration
+ {
+ if ($1 != null) {
+ Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants",
+ ((MemberCore)$1).GetSignatureForError ());
+ }
+ }
+ | struct_declaration
+ {
+ if ($1 != null) {
+ Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants",
+ ((MemberCore)$1).GetSignatureForError ());
+ }
+ }
+ | enum_declaration
+ {
+ if ($1 != null) {
+ Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants",
+ ((MemberCore)$1).GetSignatureForError ());
+ }
+ }
+ | interface_declaration
+ {
+ if ($1 != null) {
+ Report.Error (524, GetLocation ($1), "`{0}': Interfaces cannot declare classes, structs, interfaces, delegates, enumerations or constants",
+ ((MemberCore)$1).GetSignatureForError ());
+ }
+ }
+ | constant_declaration
+ {
+ Report.Error (525, GetLocation ($1), "Interfaces cannot contain fields or constants");
+ }
+ ;
+
+opt_new
+ : opt_modifiers
+ {
+ int val = (int) $1;
+ val = Modifiers.Check (Modifiers.NEW | Modifiers.UNSAFE, val, 0, GetLocation ($1));
+ $$ = val;
+ }
+ ;
+
+interface_method_declaration
+ : opt_attributes opt_new type namespace_or_type_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ SEMICOLON
+ {
+ $$ = new Method (current_class, null, (Expression) $3, (int) $2, true,
+ (MemberName) $4, (Parameters) $6, (Attributes) $1);
+ if (RootContext.Documentation != null)
+ ((Method) $$).DocComment = Lexer.consume_doc_comment ();
+ }
+ | opt_attributes opt_new type namespace_or_type_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ OPEN_BRACE opt_statement_list CLOSE_BRACE
+ {
+ $$ = new Method (current_class, null, (Expression) $3, (int) $2, true,
+ (MemberName) $4, (Parameters) $6, (Attributes) $1);
+
+ Report.Error (531, lexer.Location, "`{0}': interface members cannot have a definition",
+ ((Method)$$).GetSignatureForError ());
+ }
+ ;
+
+interface_property_declaration
+ : opt_attributes
+ opt_new
+ type IDENTIFIER
+ OPEN_BRACE
+ { lexer.PropertyParsing = true; }
+ accessor_declarations
+ {
+ has_get = has_set = false;
+ lexer.PropertyParsing = false;
+ }
+ CLOSE_BRACE
+ {
+ LocatedToken lt = (LocatedToken) $4;
+ MemberName name = new MemberName (lt.Value, lt.Location);
+
+ if ($3 == TypeManager.system_void_expr) {
+ Report.Error (547, lt.Location, "`{0}': property or indexer cannot have void type", lt.Value);
+ break;
+ }
+
+ Property p = null;
+ if ($7 == null) {
+ p = new Property (current_class, (Expression) $3, (int) $2, true,
+ name, (Attributes) $1,
+ null, null);
+
+ Report.Error (548, p.Location, "`{0}': property or indexer must have at least one accessor", p.GetSignatureForError ());
+ break;
+ }
+
+ Pair pair = (Pair) $7;
+ p = new Property (current_class, (Expression) $3, (int) $2, true,
+ name, (Attributes) $1,
+ (Accessor)pair.First, (Accessor)pair.Second);
+
+ if (pair.First != null && ((Accessor)(pair.First)).Block != null) {
+ Report.Error (531, p.Location, "`{0}.get': interface members cannot have a definition", p.GetSignatureForError ());
+ $$ = null;
+ break;
+ }
+
+ if (pair.Second != null && ((Accessor)(pair.Second)).Block != null) {
+ Report.Error (531, p.Location, "`{0}.set': interface members cannot have a definition", p.GetSignatureForError ());
+ $$ = null;
+ break;
+ }
+
+ if (RootContext.Documentation != null)
+ p.DocComment = Lexer.consume_doc_comment ();
+
+ $$ = p;
+ }
+ | opt_attributes
+ opt_new
+ type error {
+ CheckIdentifierToken (yyToken, GetLocation ($4));
+ $$ = null;
+ }
+ ;
+
+
+interface_event_declaration
+ : opt_attributes opt_new EVENT type IDENTIFIER SEMICOLON
+ {
+ LocatedToken lt = (LocatedToken) $5;
+ $$ = new EventField (current_class, (Expression) $4, (int) $2, true,
+ new MemberName (lt.Value, lt.Location),
+ (Attributes) $1);
+ if (RootContext.Documentation != null)
+ ((EventField) $$).DocComment = Lexer.consume_doc_comment ();
+ }
+ | opt_attributes opt_new EVENT type error {
+ CheckIdentifierToken (yyToken, GetLocation ($5));
+ $$ = null;
+ }
+ | opt_attributes opt_new EVENT type IDENTIFIER ASSIGN {
+ LocatedToken lt = (LocatedToken) $5;
+ Report.Error (68, lt.Location, "`{0}.{1}': event in interface cannot have initializer", current_container.Name, lt.Value);
+ $$ = null;
+ }
+ | opt_attributes opt_new EVENT type IDENTIFIER OPEN_BRACE
+ {
+ lexer.EventParsing = true;
+ }
+ event_accessor_declarations
+ {
+ lexer.EventParsing = false;
+ }
+ CLOSE_BRACE {
+ Report.Error (69, (Location) $3, "Event in interface cannot have add or remove accessors");
+ $$ = null;
+ }
+ ;
+
+interface_indexer_declaration
+ : opt_attributes opt_new type THIS
+ OPEN_BRACKET formal_parameter_list CLOSE_BRACKET
+ OPEN_BRACE
+ { lexer.PropertyParsing = true; }
+ accessor_declarations
+ {
+ has_get = has_set = false;
+ lexer.PropertyParsing = false;
+ }
+ CLOSE_BRACE
+ {
+ Indexer i = null;
+ if ($10 == null) {
+ i = new Indexer (current_class, (Expression) $3,
+ new MemberName (TypeContainer.DefaultIndexerName, (Location) $4),
+ (int) $2, true, (Parameters) $6, (Attributes) $1,
+ null, null);
+
+ Report.Error (548, i.Location, "`{0}': property or indexer must have at least one accessor", i.GetSignatureForError ());
+ break;
+ }
+
+ Pair pair = (Pair) $10;
+ i = new Indexer (current_class, (Expression) $3,
+ new MemberName (TypeContainer.DefaultIndexerName, (Location) $4),
+ (int) $2, true, (Parameters) $6, (Attributes) $1,
+ (Accessor)pair.First, (Accessor)pair.Second);
+
+ if (pair.First != null && ((Accessor)(pair.First)).Block != null) {
+ Report.Error (531, i.Location, "`{0}.get': interface members cannot have a definition", i.GetSignatureForError ());
+ $$ = null;
+ break;
+ }
+
+ if (pair.Second != null && ((Accessor)(pair.Second)).Block != null) {
+ Report.Error (531, i.Location, "`{0}.set': interface members cannot have a definition", i.GetSignatureForError ());
+ $$ = null;
+ break;
+ }
+
+ if (RootContext.Documentation != null)
+ i.DocComment = ConsumeStoredComment ();
+
+ $$ = i;
+ }
+ ;
+
+operator_declaration
+ : opt_attributes opt_modifiers operator_declarator
+ {
+ anonymous_host = SimpleAnonymousHost.GetSimple ();
+ }
+ operator_body
+ {
+ if ($3 == null)
+ break;
+
+ OperatorDeclaration decl = (OperatorDeclaration) $3;
+
+ Parameter [] param_list = new Parameter [decl.arg2type != null ? 2 : 1];
+
+ param_list[0] = new Parameter (decl.arg1type, decl.arg1name, Parameter.Modifier.NONE, null, decl.location);
+ if (decl.arg2type != null)
+ param_list[1] = new Parameter (decl.arg2type, decl.arg2name, Parameter.Modifier.NONE, null, decl.location);
+
+ Operator op = new Operator (
+ current_class, decl.optype, decl.ret_type, (int) $2,
+ new Parameters (param_list),
+ (ToplevelBlock) $5, (Attributes) $1, decl.location);
+
+ if (RootContext.Documentation != null) {
+ op.DocComment = tmpComment;
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+
+ SimpleAnonymousHost.Simple.Propagate (op);
+ anonymous_host = null;
+
+ // Note again, checking is done in semantic analysis
+ current_container.AddOperator (op);
+
+ current_local_parameters = null;
+ }
+ ;
+
+operator_body
+ : block
+ | SEMICOLON { $$ = null; }
+ ;
+operator_declarator
+ : type OPERATOR overloadable_operator
+ OPEN_PARENS type IDENTIFIER CLOSE_PARENS
+ {
+ LocatedToken lt = (LocatedToken) $6;
+ Operator.OpType op = (Operator.OpType) $3;
+ CheckUnaryOperator (op, lt.Location);
+
+ if (op == Operator.OpType.Addition)
+ op = Operator.OpType.UnaryPlus;
+
+ if (op == Operator.OpType.Subtraction)
+ op = Operator.OpType.UnaryNegation;
+
+ Parameter [] pars = new Parameter [1];
+ Expression type = (Expression) $5;
+
+ pars [0] = new Parameter (type, lt.Value, Parameter.Modifier.NONE, null, lt.Location);
+
+ current_local_parameters = new Parameters (pars);
+
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+
+ $$ = new OperatorDeclaration (op, (Expression) $1, type, lt.Value,
+ null, null, (Location) $2);
+ }
+ | type OPERATOR overloadable_operator
+ OPEN_PARENS
+ type IDENTIFIER COMMA
+ type IDENTIFIER
+ CLOSE_PARENS
+ {
+ LocatedToken ltParam1 = (LocatedToken) $6;
+ LocatedToken ltParam2 = (LocatedToken) $9;
+ CheckBinaryOperator ((Operator.OpType) $3, (Location) $2);
+
+ Parameter [] pars = new Parameter [2];
+
+ Expression typeL = (Expression) $5;
+ Expression typeR = (Expression) $8;
+
+ pars [0] = new Parameter (typeL, ltParam1.Value, Parameter.Modifier.NONE, null, ltParam1.Location);
+ pars [1] = new Parameter (typeR, ltParam2.Value, Parameter.Modifier.NONE, null, ltParam2.Location);
+
+ current_local_parameters = new Parameters (pars);
+
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+
+ $$ = new OperatorDeclaration ((Operator.OpType) $3, (Expression) $1,
+ typeL, ltParam1.Value,
+ typeR, ltParam2.Value, (Location) $2);
+ }
+ | conversion_operator_declarator
+ | type OPERATOR overloadable_operator
+ OPEN_PARENS
+ type IDENTIFIER COMMA
+ type IDENTIFIER COMMA
+ type IDENTIFIER
+ CLOSE_PARENS
+ {
+ Report.Error (1534, (Location) $2, "Overloaded binary operator `{0}' takes two parameters",
+ Operator.GetName ((Operator.OpType) $3));
+ $$ = null;
+ }
+ | type OPERATOR overloadable_operator
+ OPEN_PARENS CLOSE_PARENS
+ {
+ Report.Error (1535, (Location) $2, "Overloaded unary operator `{0}' takes one parameter",
+ Operator.GetName ((Operator.OpType) $3));
+ $$ = null;
+ }
+ ;
+
+overloadable_operator
+// Unary operators:
+ : BANG { $$ = Operator.OpType.LogicalNot; }
+ | TILDE { $$ = Operator.OpType.OnesComplement; }
+ | OP_INC { $$ = Operator.OpType.Increment; }
+ | OP_DEC { $$ = Operator.OpType.Decrement; }
+ | TRUE { $$ = Operator.OpType.True; }
+ | FALSE { $$ = Operator.OpType.False; }
+// Unary and binary:
+ | PLUS { $$ = Operator.OpType.Addition; }
+ | MINUS { $$ = Operator.OpType.Subtraction; }
+// Binary:
+ | STAR { $$ = Operator.OpType.Multiply; }
+ | DIV { $$ = Operator.OpType.Division; }
+ | PERCENT { $$ = Operator.OpType.Modulus; }
+ | BITWISE_AND { $$ = Operator.OpType.BitwiseAnd; }
+ | BITWISE_OR { $$ = Operator.OpType.BitwiseOr; }
+ | CARRET { $$ = Operator.OpType.ExclusiveOr; }
+ | OP_SHIFT_LEFT { $$ = Operator.OpType.LeftShift; }
+ | OP_SHIFT_RIGHT { $$ = Operator.OpType.RightShift; }
+ | OP_EQ { $$ = Operator.OpType.Equality; }
+ | OP_NE { $$ = Operator.OpType.Inequality; }
+ | OP_GT { $$ = Operator.OpType.GreaterThan; }
+ | OP_LT { $$ = Operator.OpType.LessThan; }
+ | OP_GE { $$ = Operator.OpType.GreaterThanOrEqual; }
+ | OP_LE { $$ = Operator.OpType.LessThanOrEqual; }
+ ;
+
+conversion_operator_declarator
+ : IMPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS
+ {
+ LocatedToken lt = (LocatedToken) $6;
+ Parameter [] pars = new Parameter [1];
+
+ pars [0] = new Parameter ((Expression) $5, lt.Value, Parameter.Modifier.NONE, null, lt.Location);
+
+ current_local_parameters = new Parameters (pars);
+
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+
+ $$ = new OperatorDeclaration (Operator.OpType.Implicit, (Expression) $3, (Expression) $5, lt.Value,
+ null, null, (Location) $2);
+ }
+ | EXPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS
+ {
+ LocatedToken lt = (LocatedToken) $6;
+ Parameter [] pars = new Parameter [1];
+
+ pars [0] = new Parameter ((Expression) $5, lt.Value, Parameter.Modifier.NONE, null, lt.Location);
+
+ current_local_parameters = new Parameters (pars);
+
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+
+ $$ = new OperatorDeclaration (Operator.OpType.Explicit, (Expression) $3, (Expression) $5, lt.Value,
+ null, null, (Location) $2);
+ }
+ | IMPLICIT error
+ {
+ syntax_error ((Location) $1, "'operator' expected");
+ }
+ | EXPLICIT error
+ {
+ syntax_error ((Location) $1, "'operator' expected");
+ }
+ ;
+
+constructor_declaration
+ : opt_attributes
+ opt_modifiers
+ constructor_declarator
+ constructor_body
+ {
+ Constructor c = (Constructor) $3;
+ c.Block = (ToplevelBlock) $4;
+ c.OptAttributes = (Attributes) $1;
+ c.ModFlags = (int) $2;
+
+ if (RootContext.Documentation != null)
+ c.DocComment = ConsumeStoredComment ();
+
+ if (c.Name == current_container.Basename){
+ if ((c.ModFlags & Modifiers.STATIC) != 0){
+ if ((c.ModFlags & Modifiers.Accessibility) != 0){
+ Report.Error (515, c.Location,
+ "`{0}': access modifiers are not allowed on static constructors",
+ c.GetSignatureForError ());
+ }
+
+ c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, (int) $2, Modifiers.PRIVATE, c.Location);
+
+ if (c.Initializer != null){
+ Report.Error (514, c.Location,
+ "`{0}': static constructor cannot have an explicit `this' or `base' constructor call",
+ c.GetSignatureForError ());
+ }
+ } else {
+ c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, (int) $2, Modifiers.PRIVATE, c.Location);
+ }
+ } else {
+ // We let another layer check the validity of the constructor.
+ //Console.WriteLine ("{0} and {1}", c.Name, current_container.Basename);
+ }
+
+ current_container.AddConstructor (c);
+
+ current_local_parameters = null;
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ ;
+
+constructor_declarator
+ : IDENTIFIER
+ {
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ }
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ current_local_parameters = (Parameters) $4;
+ }
+ opt_constructor_initializer
+ {
+ LocatedToken lt = (LocatedToken) $1;
+ $$ = new Constructor (current_class, lt.Value, 0, (Parameters) $4,
+ (ConstructorInitializer) $7, lt.Location);
+
+ anonymous_host = (IAnonymousHost) $$;
+ }
+ ;
+
+constructor_body
+ : block
+ | SEMICOLON { $$ = null; }
+ ;
+
+opt_constructor_initializer
+ : /* empty */ { $$ = null; }
+ | constructor_initializer
+ ;
+
+constructor_initializer
+ : COLON BASE OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ $$ = new ConstructorBaseInitializer ((ArrayList) $4, (Location) $2);
+ }
+ | COLON THIS OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ $$ = new ConstructorThisInitializer ((ArrayList) $4, (Location) $2);
+ }
+ | COLON error {
+ Report.Error (1018, (Location) $1, "Keyword this or base expected");
+ $$ = null;
+ }
+ ;
+
+opt_finalizer
+ : /* EMPTY */ { $$ = 0; }
+ | UNSAFE { $$ = Modifiers.UNSAFE; }
+ | EXTERN { $$ = Modifiers.EXTERN; }
+ ;
+
+destructor_declaration
+ : opt_attributes opt_finalizer TILDE
+ {
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+ }
+ IDENTIFIER OPEN_PARENS CLOSE_PARENS block
+ {
+ LocatedToken lt = (LocatedToken) $5;
+ if (lt.Value != current_container.Basename){
+ Report.Error (574, lt.Location, "Name of destructor must match name of class");
+ } else if (current_container.Kind != Kind.Class){
+ Report.Error (575, lt.Location, "Only class types can contain destructor");
+ } else {
+ Location l = lt.Location;
+
+ int m = (int) $2;
+ if (!RootContext.StdLib && current_container.Name == "System.Object")
+ m |= Modifiers.PROTECTED | Modifiers.VIRTUAL;
+ else
+ m |= Modifiers.PROTECTED | Modifiers.OVERRIDE;
+
+ Method d = new Destructor (
+ current_class, TypeManager.system_void_expr, m, "Finalize",
+ Parameters.EmptyReadOnlyParameters, (Attributes) $1, l);
+ if (RootContext.Documentation != null)
+ d.DocComment = ConsumeStoredComment ();
+
+ d.Block = (ToplevelBlock) $8;
+ current_container.AddMethod (d);
+ }
+ }
+ ;
+
+event_declaration
+ : opt_attributes
+ opt_modifiers
+ EVENT type variable_declarators SEMICOLON
+ {
+ current_array_type = null;
+ foreach (VariableDeclaration var in (ArrayList) $5) {
+
+ MemberName name = new MemberName (var.identifier,
+ var.Location);
+
+ EventField e = new EventField (
+ current_class, (Expression) $4, (int) $2, false, name,
+ (Attributes) $1);
+
+ e.Initializer = var.expression_or_array_initializer;
+
+ current_container.AddEvent (e);
+
+ if (RootContext.Documentation != null) {
+ e.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ }
+ }
+ | opt_attributes
+ opt_modifiers
+ EVENT type namespace_or_type_name
+ OPEN_BRACE
+ {
+ implicit_value_parameter_type = (Expression) $4;
+ lexer.EventParsing = true;
+ }
+ event_accessor_declarations
+ {
+ lexer.EventParsing = false;
+ }
+ CLOSE_BRACE
+ {
+ MemberName name = (MemberName) $5;
+
+ if ($8 == null){
+ Report.Error (65, (Location) $3, "`{0}.{1}': event property must have both add and remove accessors",
+ current_container.Name, name.ToString ());
+ $$ = null;
+ } else {
+ Pair pair = (Pair) $8;
+ if (pair.First == null || pair.Second == null)
+ // CS0073 is already reported, so no CS0065 here.
+ $$ = null;
+ else {
+ Event e = new EventProperty (
+ current_class, (Expression) $4, (int) $2, false, name,
+ (Attributes) $1, (Accessor) pair.First, (Accessor) pair.Second);
+ if (RootContext.Documentation != null) {
+ e.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+
+ current_container.AddEvent (e);
+ implicit_value_parameter_type = null;
+ }
+ }
+ }
+ | opt_attributes opt_modifiers EVENT type namespace_or_type_name error {
+ MemberName mn = (MemberName) $5;
+
+ if (mn.Left != null)
+ Report.Error (71, mn.Location, "An explicit interface implementation of an event must use property syntax");
+ else
+ Report.Error (71, mn.Location, "Event declaration should use property syntax");
+
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ ;
+
+event_accessor_declarations
+ : add_accessor_declaration remove_accessor_declaration
+ {
+ $$ = new Pair ($1, $2);
+ }
+ | remove_accessor_declaration add_accessor_declaration
+ {
+ $$ = new Pair ($2, $1);
+ }
+ | add_accessor_declaration { $$ = null; }
+ | remove_accessor_declaration { $$ = null; }
+ | error
+ {
+ Report.Error (1055, GetLocation ($1), "An add or remove accessor expected");
+ $$ = null;
+ }
+ | { $$ = null; }
+ ;
+
+add_accessor_declaration
+ : opt_attributes ADD
+ {
+ Parameter [] args = new Parameter [1];
+ Parameter implicit_value_parameter = new Parameter (
+ implicit_value_parameter_type, "value",
+ Parameter.Modifier.NONE, null, (Location) $2);
+
+ args [0] = implicit_value_parameter;
+
+ current_local_parameters = new Parameters (args);
+ lexer.EventParsing = false;
+ }
+ block
+ {
+ $$ = new Accessor ((ToplevelBlock) $4, 0, (Attributes) $1, (Location) $2);
+ lexer.EventParsing = true;
+ }
+ | opt_attributes ADD error {
+ Report.Error (73, (Location) $2, "An add or remove accessor must have a body");
+ $$ = null;
+ }
+ | opt_attributes modifiers ADD {
+ Report.Error (1609, (Location) $3, "Modifiers cannot be placed on event accessor declarations");
+ $$ = null;
+ }
+ ;
+
+remove_accessor_declaration
+ : opt_attributes REMOVE
+ {
+ Parameter [] args = new Parameter [1];
+ Parameter implicit_value_parameter = new Parameter (
+ implicit_value_parameter_type, "value",
+ Parameter.Modifier.NONE, null, (Location) $2);
+
+ args [0] = implicit_value_parameter;
+
+ current_local_parameters = new Parameters (args);
+ lexer.EventParsing = false;
+ }
+ block
+ {
+ $$ = new Accessor ((ToplevelBlock) $4, 0, (Attributes) $1, (Location) $2);
+ lexer.EventParsing = true;
+ }
+ | opt_attributes REMOVE error {
+ Report.Error (73, (Location) $2, "An add or remove accessor must have a body");
+ $$ = null;
+ }
+ | opt_attributes modifiers REMOVE {
+ Report.Error (1609, (Location) $3, "Modifiers cannot be placed on event accessor declarations");
+ $$ = null;
+ }
+ ;
+
+indexer_declaration
+ : opt_attributes opt_modifiers indexer_declarator
+ OPEN_BRACE
+ {
+ IndexerDeclaration decl = (IndexerDeclaration) $3;
+
+ implicit_value_parameter_type = decl.type;
+
+ lexer.PropertyParsing = true;
+ parsing_indexer = true;
+
+ indexer_parameters = decl.param_list;
+ anonymous_host = SimpleAnonymousHost.GetSimple ();
+ }
+ accessor_declarations
+ {
+ lexer.PropertyParsing = false;
+ has_get = has_set = false;
+ parsing_indexer = false;
+ }
+ CLOSE_BRACE
+ {
+ if ($6 == null)
+ break;
+
+ // The signature is computed from the signature of the indexer. Look
+ // at section 3.6 on the spec
+ Indexer indexer;
+ IndexerDeclaration decl = (IndexerDeclaration) $3;
+ Location loc = decl.location;
+ Pair pair = (Pair) $6;
+ Accessor get_block = (Accessor) pair.First;
+ Accessor set_block = (Accessor) pair.Second;
+
+ MemberName name;
+ if (decl.interface_type != null)
+ name = new MemberName (decl.interface_type, TypeContainer.DefaultIndexerName, loc);
+ else
+ name = new MemberName (TypeContainer.DefaultIndexerName, loc);
+
+ indexer = new Indexer (current_class, decl.type, name,
+ (int) $2, false, decl.param_list, (Attributes) $1,
+ get_block, set_block);
+
+ if (RootContext.Documentation != null)
+ indexer.DocComment = ConsumeStoredComment ();
+
+ current_container.AddIndexer (indexer);
+
+ current_local_parameters = null;
+ implicit_value_parameter_type = null;
+ indexer_parameters = null;
+ }
+ ;
+
+indexer_declarator
+ : type THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET
+ {
+ Parameters pars = (Parameters) $4;
+ if (pars.HasArglist) {
+ // "__arglist is not valid in this context"
+ Report.Error (1669, (Location) $2, "__arglist is not valid in this context");
+ } else if (pars.Empty){
+ Report.Error (1551, (Location) $2, "Indexers must have at least one parameter");
+ }
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+
+ $$ = new IndexerDeclaration ((Expression) $1, null, pars, (Location) $2);
+ }
+ | type namespace_or_type_name DOT THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET
+ {
+ Parameters pars = (Parameters) $6;
+
+ if (pars.HasArglist) {
+ // "__arglist is not valid in this context"
+ Report.Error (1669, (Location) $4, "__arglist is not valid in this context");
+ } else if (pars.Empty){
+ Report.Error (1551, (Location) $4, "Indexers must have at least one parameter");
+ }
+
+ MemberName name = (MemberName) $2;
+ $$ = new IndexerDeclaration ((Expression) $1, name, pars, (Location) $4);
+
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ }
+ ;
+
+enum_declaration
+ : opt_attributes
+ opt_modifiers
+ ENUM IDENTIFIER
+ opt_enum_base {
+ if (RootContext.Documentation != null)
+ enumTypeComment = Lexer.consume_doc_comment ();
+ }
+ enum_body
+ opt_semicolon
+ {
+ LocatedToken lt = (LocatedToken) $4;
+ Location enum_location = lt.Location;
+
+ MemberName name = MakeName (new MemberName (lt.Value, enum_location));
+ Enum e = new Enum (current_namespace, current_class, (Expression) $5, (int) $2,
+ name, (Attributes) $1);
+
+ if (RootContext.Documentation != null)
+ e.DocComment = enumTypeComment;
+
+
+ EnumMember em = null;
+ foreach (VariableDeclaration ev in (ArrayList) $7) {
+ em = new EnumMember (e, em, (Expression) ev.expression_or_array_initializer,
+ new MemberName (ev.identifier, ev.Location), ev.OptAttributes);
+
+// if (RootContext.Documentation != null)
+ em.DocComment = ev.DocComment;
+
+ e.AddEnumMember (em);
+ }
+
+ current_container.AddEnum (e);
+ $$ = e;
+
+ }
+ ;
+
+opt_enum_base
+ : /* empty */ { $$ = TypeManager.system_int32_expr; }
+ | COLON type { $$ = $2; }
+ ;
+
+enum_body
+ : OPEN_BRACE
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ opt_enum_member_declarations
+ {
+ // here will be evaluated after CLOSE_BLACE is consumed.
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ CLOSE_BRACE
+ {
+ $$ = $3;
+ }
+ ;
+
+opt_enum_member_declarations
+ : /* empty */ { $$ = new ArrayList (4); }
+ | enum_member_declarations opt_comma { $$ = $1; }
+ ;
+
+enum_member_declarations
+ : enum_member_declaration
+ {
+ ArrayList l = new ArrayList (4);
+
+ l.Add ($1);
+ $$ = l;
+ }
+ | enum_member_declarations COMMA enum_member_declaration
+ {
+ ArrayList l = (ArrayList) $1;
+
+ l.Add ($3);
+
+ $$ = l;
+ }
+ ;
+
+enum_member_declaration
+ : opt_attributes IDENTIFIER
+ {
+ VariableDeclaration vd = new VariableDeclaration (
+ (LocatedToken) $2, null, (Attributes) $1);
+
+ if (RootContext.Documentation != null) {
+ vd.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+
+ $$ = vd;
+ }
+ | opt_attributes IDENTIFIER
+ {
+ if (RootContext.Documentation != null) {
+ tmpComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.NotAllowed;
+ }
+ }
+ ASSIGN expression
+ {
+ VariableDeclaration vd = new VariableDeclaration (
+ (LocatedToken) $2, $5, (Attributes) $1);
+
+ if (RootContext.Documentation != null)
+ vd.DocComment = ConsumeStoredComment ();
+
+ $$ = vd;
+ }
+ ;
+
+delegate_declaration
+ : opt_attributes
+ opt_modifiers
+ DELEGATE type member_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ SEMICOLON
+ {
+ MemberName name = MakeName ((MemberName) $5);
+ Parameters p = (Parameters) $7;
+ if (p.HasArglist) {
+ // TODO: wrong location
+ Report.Error (1669, name.Location, "__arglist is not valid in this context");
+ }
+
+ Delegate del = new Delegate (current_namespace, current_class, (Expression) $4,
+ (int) $2, name, p, (Attributes) $1);
+
+ if (RootContext.Documentation != null) {
+ del.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+
+ current_container.AddDelegate (del);
+ $$ = del;
+ }
+ ;
+
+namespace_or_type_name
+ : member_name
+ | IDENTIFIER DOUBLE_COLON IDENTIFIER {
+ LocatedToken lt1 = (LocatedToken) $1;
+ LocatedToken lt2 = (LocatedToken) $3;
+ $$ = new MemberName (lt1.Value, lt2.Value, lt2.Location);
+ }
+ | namespace_or_type_name DOT IDENTIFIER {
+ LocatedToken lt = (LocatedToken) $3;
+ $$ = new MemberName ((MemberName) $1, lt.Value);
+ }
+ ;
+
+member_name
+ : IDENTIFIER {
+ LocatedToken lt = (LocatedToken) $1;
+ $$ = new MemberName (lt.Value, lt.Location);
+ }
+ ;
+
+/*
+ * Before you think of adding a return_type, notice that we have been
+ * using two rules in the places where it matters (one rule using type
+ * and another identical one that uses VOID as the return type). This
+ * gets rid of a shift/reduce couple
+ */
+type
+ : namespace_or_type_name
+ {
+ MemberName name = (MemberName) $1;
+ $$ = name.GetTypeExpression ();
+ }
+ | builtin_types
+ | array_type
+ | pointer_type
+ ;
+
+
+pointer_type
+ : type STAR
+ {
+ //
+ // Note that here only unmanaged types are allowed but we
+ // can't perform checks during this phase - we do it during
+ // semantic analysis.
+ //
+ $$ = new ComposedCast ((Expression) $1, "*", Lexer.Location);
+ }
+ | VOID STAR
+ {
+ $$ = new ComposedCast (TypeManager.system_void_expr, "*", (Location) $1);
+ }
+ ;
+
+non_expression_type
+ : builtin_types
+ | non_expression_type rank_specifier
+ {
+ Location loc = GetLocation ($1);
+ if (loc.IsNull)
+ loc = lexer.Location;
+ $$ = new ComposedCast ((Expression) $1, (string) $2, loc);
+ }
+ | non_expression_type STAR
+ {
+ Location loc = GetLocation ($1);
+ if (loc.IsNull)
+ loc = lexer.Location;
+ $$ = new ComposedCast ((Expression) $1, "*", loc);
+ }
+ | expression rank_specifiers
+ {
+ $$ = new ComposedCast ((Expression) $1, (string) $2);
+ }
+ | expression STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*");
+ }
+
+ //
+ // We need this because the parser will happily go and reduce IDENTIFIER STAR
+ // through this different path
+ //
+ | multiplicative_expression STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*");
+ }
+ ;
+
+type_list
+ : type
+ {
+ ArrayList types = new ArrayList (4);
+
+ types.Add ($1);
+ $$ = types;
+ }
+ | type_list COMMA type
+ {
+ ArrayList types = (ArrayList) $1;
+
+ types.Add ($3);
+ $$ = types;
+ }
+ ;
+
+/*
+ * replaces all the productions for isolating the various
+ * simple types, but we need this to reuse it easily in local_variable_type
+ */
+builtin_types
+ : OBJECT { $$ = TypeManager.system_object_expr; }
+ | STRING { $$ = TypeManager.system_string_expr; }
+ | BOOL { $$ = TypeManager.system_boolean_expr; }
+ | DECIMAL { $$ = TypeManager.system_decimal_expr; }
+ | FLOAT { $$ = TypeManager.system_single_expr; }
+ | DOUBLE { $$ = TypeManager.system_double_expr; }
+ | integral_type
+ ;
+
+integral_type
+ : SBYTE { $$ = TypeManager.system_sbyte_expr; }
+ | BYTE { $$ = TypeManager.system_byte_expr; }
+ | SHORT { $$ = TypeManager.system_int16_expr; }
+ | USHORT { $$ = TypeManager.system_uint16_expr; }
+ | INT { $$ = TypeManager.system_int32_expr; }
+ | UINT { $$ = TypeManager.system_uint32_expr; }
+ | LONG { $$ = TypeManager.system_int64_expr; }
+ | ULONG { $$ = TypeManager.system_uint64_expr; }
+ | CHAR { $$ = TypeManager.system_char_expr; }
+ | VOID { $$ = TypeManager.system_void_expr; }
+ ;
+
+array_type
+ : type rank_specifiers
+ {
+ $$ = current_array_type = new ComposedCast ((Expression) $1, (string) $2);
+ }
+ ;
+
+//
+// Expressions, section 7.5
+//
+primary_expression
+ : literal
+ {
+ // 7.5.1: Literals
+ }
+
+ | member_name
+ {
+ MemberName mn = (MemberName) $1;
+ $$ = mn.GetTypeExpression ();
+ }
+ | IDENTIFIER DOUBLE_COLON IDENTIFIER
+ {
+ LocatedToken lt1 = (LocatedToken) $1;
+ LocatedToken lt2 = (LocatedToken) $3;
+ $$ = new QualifiedAliasMember (lt1.Value, lt2.Value, lt2.Location);
+ }
+ | parenthesized_expression
+ | member_access
+ | invocation_expression
+ | element_access
+ | this_access
+ | base_access
+ | post_increment_expression
+ | post_decrement_expression
+ | new_expression
+ | typeof_expression
+ | sizeof_expression
+ | checked_expression
+ | unchecked_expression
+ | pointer_member_access
+ | anonymous_method_expression
+ ;
+
+literal
+ : boolean_literal
+ | integer_literal
+ | real_literal
+ | LITERAL_CHARACTER { $$ = new CharLiteral ((char) lexer.Value, lexer.Location); }
+ | LITERAL_STRING { $$ = new StringLiteral ((string) lexer.Value, lexer.Location); }
+ | NULL { $$ = new NullLiteral (lexer.Location); }
+ ;
+
+real_literal
+ : LITERAL_FLOAT { $$ = new FloatLiteral ((float) lexer.Value, lexer.Location); }
+ | LITERAL_DOUBLE { $$ = new DoubleLiteral ((double) lexer.Value, lexer.Location); }
+ | LITERAL_DECIMAL { $$ = new DecimalLiteral ((decimal) lexer.Value, lexer.Location); }
+ ;
+
+integer_literal
+ : LITERAL_INTEGER {
+ object v = lexer.Value;
+
+ if (v is int){
+ $$ = new IntLiteral ((int) v, lexer.Location);
+ } else if (v is uint)
+ $$ = new UIntLiteral ((UInt32) v, lexer.Location);
+ else if (v is long)
+ $$ = new LongLiteral ((Int64) v, lexer.Location);
+ else if (v is ulong)
+ $$ = new ULongLiteral ((UInt64) v, lexer.Location);
+ else
+ Console.WriteLine ("OOPS. Unexpected result from scanner");
+ }
+ ;
+
+boolean_literal
+ : TRUE { $$ = new BoolLiteral (true, lexer.Location); }
+ | FALSE { $$ = new BoolLiteral (false, lexer.Location); }
+ ;
+
+parenthesized_expression_0
+ : OPEN_PARENS expression CLOSE_PARENS
+ {
+ $$ = $2;
+ lexer.Deambiguate_CloseParens ($$);
+ // After this, the next token returned is one of
+ // CLOSE_PARENS_CAST, CLOSE_PARENS_NO_CAST (CLOSE_PARENS), CLOSE_PARENS_OPEN_PARENS
+ // or CLOSE_PARENS_MINUS.
+ }
+ | OPEN_PARENS expression error { CheckToken (1026, yyToken, "Expecting ')'", lexer.Location); }
+ ;
+
+parenthesized_expression
+ : parenthesized_expression_0 CLOSE_PARENS_NO_CAST
+ {
+ $$ = $1;
+ }
+ | parenthesized_expression_0 CLOSE_PARENS
+ {
+ $$ = $1;
+ }
+ | parenthesized_expression_0 CLOSE_PARENS_MINUS
+ {
+ // If a parenthesized expression is followed by a minus, we need to wrap
+ // the expression inside a ParenthesizedExpression for the CS0075 check
+ // in Binary.DoResolve().
+ $$ = new ParenthesizedExpression ((Expression) $1);
+ }
+ ;
+
+member_access
+ : primary_expression DOT IDENTIFIER
+ {
+ LocatedToken lt = (LocatedToken) $3;
+ $$ = new MemberAccess ((Expression) $1, lt.Value);
+ }
+ | predefined_type DOT IDENTIFIER
+ {
+ LocatedToken lt = (LocatedToken) $3;
+ // TODO: Location is wrong as some predefined types doesn't hold a location
+ $$ = new MemberAccess ((Expression) $1, lt.Value, lt.Location);
+ }
+ ;
+
+predefined_type
+ : builtin_types
+ ;
+
+invocation_expression
+ : primary_expression OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ if ($1 == null)
+ Report.Error (1, (Location) $2, "Parse error");
+ else
+ $$ = new Invocation ((Expression) $1, (ArrayList) $3);
+ }
+ | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS CLOSE_PARENS
+ {
+ $$ = new Invocation ((Expression) $1, new ArrayList ());
+ }
+ | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS primary_expression
+ {
+ $$ = new InvocationOrCast ((Expression) $1, (Expression) $3);
+ }
+ | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS non_simple_argument CLOSE_PARENS
+ {
+ ArrayList args = new ArrayList (1);
+ args.Add ($4);
+ $$ = new Invocation ((Expression) $1, args);
+ }
+ | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS OPEN_PARENS argument_list COMMA argument CLOSE_PARENS
+ {
+ ArrayList args = ((ArrayList) $4);
+ args.Add ($6);
+ $$ = new Invocation ((Expression) $1, args);
+ }
+ ;
+
+opt_argument_list
+ : /* empty */ { $$ = null; }
+ | argument_list
+ ;
+
+argument_list
+ : argument
+ {
+ ArrayList list = new ArrayList (4);
+ list.Add ($1);
+ $$ = list;
+ }
+ | argument_list COMMA argument
+ {
+ ArrayList list = (ArrayList) $1;
+ list.Add ($3);
+ $$ = list;
+ }
+ | argument_list error {
+ CheckToken (1026, yyToken, "Expected `,' or `)'", GetLocation ($2));
+ $$ = null;
+ }
+ ;
+
+argument
+ : expression
+ {
+ $$ = new Argument ((Expression) $1, Argument.AType.Expression);
+ }
+ | non_simple_argument
+ {
+ $$ = $1;
+ }
+ ;
+
+non_simple_argument
+ : REF variable_reference
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Ref);
+ }
+ | OUT variable_reference
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Out);
+ }
+ | ARGLIST OPEN_PARENS argument_list CLOSE_PARENS
+ {
+ ArrayList list = (ArrayList) $3;
+ Argument[] args = new Argument [list.Count];
+ list.CopyTo (args, 0);
+
+ Expression expr = new Arglist (args, (Location) $1);
+ $$ = new Argument (expr, Argument.AType.Expression);
+ }
+ | ARGLIST
+ {
+ $$ = new Argument (new ArglistAccess ((Location) $1), Argument.AType.ArgList);
+ }
+ ;
+
+variable_reference
+ : expression { note ("section 5.4"); $$ = $1; }
+ ;
+
+element_access
+ : primary_expression OPEN_BRACKET expression_list CLOSE_BRACKET
+ {
+ $$ = new ElementAccess ((Expression) $1, (ArrayList) $3);
+ }
+ | primary_expression rank_specifiers
+ {
+ // So the super-trick is that primary_expression
+ // can only be either a SimpleName or a MemberAccess.
+ // The MemberAccess case arises when you have a fully qualified type-name like :
+ // Foo.Bar.Blah i;
+ // SimpleName is when you have
+ // Blah i;
+
+ Expression expr = (Expression) $1;
+ if (expr is ComposedCast){
+ $$ = new ComposedCast (expr, (string) $2);
+ } else if (!(expr is SimpleName || expr is MemberAccess || expr is QualifiedAliasMember)){
+ Error_ExpectingTypeName (expr);
+ $$ = TypeManager.system_object_expr;
+ } else {
+ //
+ // So we extract the string corresponding to the SimpleName
+ // or MemberAccess
+ //
+ $$ = new ComposedCast (expr, (string) $2);
+ }
+ current_array_type = (Expression)$$;
+ }
+ ;
+
+expression_list
+ : expression
+ {
+ ArrayList list = new ArrayList (4);
+ list.Add ($1);
+ $$ = list;
+ }
+ | expression_list COMMA expression
+ {
+ ArrayList list = (ArrayList) $1;
+ list.Add ($3);
+ $$ = list;
+ }
+ ;
+
+this_access
+ : THIS
+ {
+ $$ = new This (current_block, (Location) $1);
+ }
+ ;
+
+base_access
+ : BASE DOT IDENTIFIER
+ {
+ LocatedToken lt = (LocatedToken) $3;
+ $$ = new BaseAccess (lt.Value, lt.Location);
+ }
+ | BASE OPEN_BRACKET expression_list CLOSE_BRACKET
+ {
+ $$ = new BaseIndexerAccess ((ArrayList) $3, (Location) $1);
+ }
+ | BASE error {
+ Report.Error (175, (Location) $1, "Use of keyword `base' is not valid in this context");
+ $$ = null;
+ }
+ ;
+
+post_increment_expression
+ : primary_expression OP_INC
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PostIncrement,
+ (Expression) $1, (Location) $2);
+ }
+ ;
+
+post_decrement_expression
+ : primary_expression OP_DEC
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PostDecrement,
+ (Expression) $1, (Location) $2);
+ }
+ ;
+
+new_expression
+ : object_or_delegate_creation_expression
+ | array_creation_expression
+ ;
+
+object_or_delegate_creation_expression
+ : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ $$ = new New ((Expression) $2, (ArrayList) $4, (Location) $1);
+ }
+ ;
+
+array_creation_expression
+ : NEW type OPEN_BRACKET expression_list CLOSE_BRACKET
+ opt_rank_specifier
+ opt_array_initializer
+ {
+ $$ = new ArrayCreation ((Expression) $2, (ArrayList) $4, (string) $6, (ArrayList) $7, (Location) $1);
+ }
+ | NEW type rank_specifiers array_initializer
+ {
+ $$ = new ArrayCreation ((Expression) $2, (string) $3, (ArrayList) $4, (Location) $1);
+ }
+ | NEW error
+ {
+ Report.Error (1031, (Location) $1, "Type expected");
+ $$ = null;
+ }
+ | NEW type error
+ {
+ Report.Error (1526, (Location) $1, "A new expression requires () or [] after type");
+ $$ = null;
+ }
+ ;
+
+opt_rank_specifier
+ : /* empty */
+ {
+ $$ = "";
+ }
+ | rank_specifiers
+ {
+ $$ = $1;
+ }
+ ;
+
+rank_specifiers
+ : rank_specifier opt_rank_specifier
+ {
+ $$ = (string) $2 + (string) $1;
+ }
+ ;
+
+rank_specifier
+ : OPEN_BRACKET opt_dim_separators CLOSE_BRACKET
+ {
+ $$ = "[" + (string) $2 + "]";
+ }
+ ;
+
+opt_dim_separators
+ : /* empty */
+ {
+ $$ = "";
+ }
+ | dim_separators
+ {
+ $$ = $1;
+ }
+ ;
+
+dim_separators
+ : COMMA
+ {
+ $$ = ",";
+ }
+ | dim_separators COMMA
+ {
+ $$ = (string) $1 + ",";
+ }
+ ;
+
+opt_array_initializer
+ : /* empty */
+ {
+ $$ = null;
+ }
+ | array_initializer
+ {
+ $$ = $1;
+ }
+ ;
+
+array_initializer
+ : OPEN_BRACE CLOSE_BRACE
+ {
+ ArrayList list = new ArrayList (4);
+ $$ = list;
+ }
+ | OPEN_BRACE variable_initializer_list opt_comma CLOSE_BRACE
+ {
+ $$ = (ArrayList) $2;
+ }
+ ;
+
+variable_initializer_list
+ : variable_initializer
+ {
+ ArrayList list = new ArrayList (4);
+ list.Add ($1);
+ $$ = list;
+ }
+ | variable_initializer_list COMMA variable_initializer
+ {
+ ArrayList list = (ArrayList) $1;
+ list.Add ($3);
+ $$ = list;
+ }
+ ;
+
+typeof_expression
+ : TYPEOF
+ {
+ pushed_current_array_type = current_array_type;
+ }
+ OPEN_PARENS type CLOSE_PARENS
+ {
+ Expression type = (Expression)$4;
+ if (type == TypeManager.system_void_expr)
+ $$ = new TypeOfVoid ((Location) $1);
+ else
+ $$ = new TypeOf (type, (Location) $1);
+ current_array_type = pushed_current_array_type;
+ }
+ ;
+
+sizeof_expression
+ : SIZEOF OPEN_PARENS type CLOSE_PARENS {
+ $$ = new SizeOf ((Expression) $3, (Location) $1);
+ }
+ ;
+
+checked_expression
+ : CHECKED OPEN_PARENS expression CLOSE_PARENS
+ {
+ $$ = new CheckedExpr ((Expression) $3, (Location) $1);
+ }
+ ;
+
+unchecked_expression
+ : UNCHECKED OPEN_PARENS expression CLOSE_PARENS
+ {
+ $$ = new UnCheckedExpr ((Expression) $3, (Location) $1);
+ }
+ ;
+
+pointer_member_access
+ : primary_expression OP_PTR IDENTIFIER
+ {
+ Expression deref;
+ LocatedToken lt = (LocatedToken) $3;
+
+ deref = new Unary (Unary.Operator.Indirection, (Expression) $1, lt.Location);
+ $$ = new MemberAccess (deref, lt.Value);
+ }
+ ;
+
+anonymous_method_expression
+ : DELEGATE opt_anonymous_method_signature
+ {
+ if (oob_stack == null)
+ oob_stack = new Stack (6);
+
+ oob_stack.Push (current_anonymous_method);
+ oob_stack.Push (current_local_parameters);
+ current_local_parameters = (Parameters)$2;
+
+ // Force the next block to be created as a ToplevelBlock
+ oob_stack.Push (current_block);
+ oob_stack.Push (top_current_block);
+
+ Location loc = (Location) $1;
+ current_anonymous_method = new AnonymousMethodExpression (
+ current_anonymous_method, null, current_container,
+ (Parameters) $2, (ToplevelBlock) top_current_block, loc);
+
+ parsing_anonymous_method = true;
+ }
+ block
+ {
+ Location loc = (Location) $1;
+ top_current_block = (Block) oob_stack.Pop ();
+ current_block = (Block) oob_stack.Pop ();
+
+ if (RootContext.Version == LanguageVersion.ISO_1){
+ Report.FeatureIsNotStandardized (loc, "anonymous methods");
+ $$ = null;
+ } else {
+ ToplevelBlock anon_block = (ToplevelBlock) $4;
+
+ anon_block.Parent = current_block;
+
+ current_anonymous_method.Block = anon_block;
+ if ((anonymous_host != null) && (current_anonymous_method.Parent == null))
+ anonymous_host.AddAnonymousMethod (current_anonymous_method);
+
+ $$ = current_anonymous_method;
+ }
+
+ current_local_parameters = (Parameters) oob_stack.Pop ();
+ current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop ();
+ }
+ ;
+
+opt_anonymous_method_signature
+ : /* empty */ { $$ = null; }
+ | anonymous_method_signature
+ ;
+
+anonymous_method_signature
+ : OPEN_PARENS opt_anonymous_method_parameter_list CLOSE_PARENS
+ {
+ if ($2 == null)
+ $$ = Parameters.EmptyReadOnlyParameters;
+ else {
+ ArrayList par_list = (ArrayList) $2;
+ Parameter [] pars = new Parameter [par_list.Count];
+ par_list.CopyTo (pars);
+ $$ = new Parameters (pars);
+ }
+ }
+ ;
+
+opt_anonymous_method_parameter_list
+ : /* empty */ { $$ = null; }
+ | anonymous_method_parameter_list { $$ = $1; }
+ ;
+
+anonymous_method_parameter_list
+ : anonymous_method_parameter
+ {
+ ArrayList a = new ArrayList (4);
+ a.Add ($1);
+ $$ = a;
+ }
+ | anonymous_method_parameter_list COMMA anonymous_method_parameter
+ {
+ ArrayList a = (ArrayList) $1;
+ a.Add ($3);
+ $$ = a;
+ }
+ ;
+
+anonymous_method_parameter
+ : opt_parameter_modifier type IDENTIFIER {
+ LocatedToken lt = (LocatedToken) $3;
+ $$ = new Parameter ((Expression) $2, lt.Value, (Parameter.Modifier) $1, null, lt.Location);
+ }
+ | PARAMS type IDENTIFIER {
+ Report.Error (1670, ((LocatedToken) $3).Location, "The `params' modifier is not allowed in anonymous method declaration");
+ $$ = null;
+ }
+ ;
+
+unary_expression
+ : primary_expression
+ | BANG prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.LogicalNot, (Expression) $2, (Location) $1);
+ }
+ | TILDE prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, (Location) $1);
+ }
+ | cast_expression
+ ;
+
+cast_list
+ : parenthesized_expression_0 CLOSE_PARENS_CAST unary_expression
+ {
+ $$ = new Cast ((Expression) $1, (Expression) $3);
+ }
+ | parenthesized_expression_0 CLOSE_PARENS_OPEN_PARENS cast_expression
+ {
+ $$ = new Cast ((Expression) $1, (Expression) $3);
+ }
+ ;
+
+cast_expression
+ : cast_list
+ | OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression
+ {
+ // TODO: wrong location
+ $$ = new Cast ((Expression) $2, (Expression) $4, lexer.Location);
+ }
+ ;
+
+ //
+ // The idea to split this out is from Rhys' grammar
+ // to solve the problem with casts.
+ //
+prefixed_unary_expression
+ : unary_expression
+ | PLUS prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.UnaryPlus, (Expression) $2, (Location) $1);
+ }
+ | MINUS prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, (Location) $1);
+ }
+ | OP_INC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement,
+ (Expression) $2, (Location) $1);
+ }
+ | OP_DEC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement,
+ (Expression) $2, (Location) $1);
+ }
+ | STAR prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.Indirection, (Expression) $2, (Location) $1);
+ }
+ | BITWISE_AND prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, (Location) $1);
+ }
+ ;
+
+pre_increment_expression
+ : OP_INC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement,
+ (Expression) $2, (Location) $1);
+ }
+ ;
+
+pre_decrement_expression
+ : OP_DEC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement,
+ (Expression) $2, (Location) $1);
+ }
+ ;
+
+multiplicative_expression
+ : prefixed_unary_expression
+ | multiplicative_expression STAR prefixed_unary_expression
+ {
+ $$ = new Binary (Binary.Operator.Multiply,
+ (Expression) $1, (Expression) $3);
+ }
+ | multiplicative_expression DIV prefixed_unary_expression
+ {
+ $$ = new Binary (Binary.Operator.Division,
+ (Expression) $1, (Expression) $3);
+ }
+ | multiplicative_expression PERCENT prefixed_unary_expression
+ {
+ $$ = new Binary (Binary.Operator.Modulus,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression
+ | additive_expression PLUS multiplicative_expression
+ {
+ $$ = new Binary (Binary.Operator.Addition,
+ (Expression) $1, (Expression) $3);
+ }
+ | additive_expression MINUS multiplicative_expression
+ {
+ $$ = new Binary (Binary.Operator.Subtraction,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+shift_expression
+ : additive_expression
+ | shift_expression OP_SHIFT_LEFT additive_expression
+ {
+ $$ = new Binary (Binary.Operator.LeftShift,
+ (Expression) $1, (Expression) $3);
+ }
+ | shift_expression OP_SHIFT_RIGHT additive_expression
+ {
+ $$ = new Binary (Binary.Operator.RightShift,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+relational_expression
+ : shift_expression
+ | relational_expression OP_LT shift_expression
+ {
+ $$ = new Binary (Binary.Operator.LessThan,
+ (Expression) $1, (Expression) $3);
+ }
+ | relational_expression OP_GT shift_expression
+ {
+ $$ = new Binary (Binary.Operator.GreaterThan,
+ (Expression) $1, (Expression) $3);
+ }
+ | relational_expression OP_LE shift_expression
+ {
+ $$ = new Binary (Binary.Operator.LessThanOrEqual,
+ (Expression) $1, (Expression) $3);
+ }
+ | relational_expression OP_GE shift_expression
+ {
+ $$ = new Binary (Binary.Operator.GreaterThanOrEqual,
+ (Expression) $1, (Expression) $3);
+ }
+ | relational_expression IS type
+ {
+ $$ = new Is ((Expression) $1, (Expression) $3, (Location) $2);
+ }
+ | relational_expression AS type
+ {
+ $$ = new As ((Expression) $1, (Expression) $3, (Location) $2);
+ }
+ ;
+
+equality_expression
+ : relational_expression
+ | equality_expression OP_EQ relational_expression
+ {
+ $$ = new Binary (Binary.Operator.Equality,
+ (Expression) $1, (Expression) $3);
+ }
+ | equality_expression OP_NE relational_expression
+ {
+ $$ = new Binary (Binary.Operator.Inequality,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+and_expression
+ : equality_expression
+ | and_expression BITWISE_AND equality_expression
+ {
+ $$ = new Binary (Binary.Operator.BitwiseAnd,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression CARRET and_expression
+ {
+ $$ = new Binary (Binary.Operator.ExclusiveOr,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression
+ | inclusive_or_expression BITWISE_OR exclusive_or_expression
+ {
+ $$ = new Binary (Binary.Operator.BitwiseOr,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+conditional_and_expression
+ : inclusive_or_expression
+ | conditional_and_expression OP_AND inclusive_or_expression
+ {
+ $$ = new Binary (Binary.Operator.LogicalAnd,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+conditional_or_expression
+ : conditional_and_expression
+ | conditional_or_expression OP_OR conditional_and_expression
+ {
+ $$ = new Binary (Binary.Operator.LogicalOr,
+ (Expression) $1, (Expression) $3);
+ }
+ ;
+
+conditional_expression
+ : conditional_or_expression
+ | conditional_or_expression INTERR expression COLON expression
+ {
+ $$ = new Conditional ((Expression) $1, (Expression) $3, (Expression) $5);
+ }
+ ;
+
+assignment_expression
+ : prefixed_unary_expression ASSIGN expression
+ {
+ $$ = new Assign ((Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_MULT_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.Multiply, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_DIV_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.Division, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_MOD_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.Modulus, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_ADD_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.Addition, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_SUB_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.Subtraction, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.LeftShift, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.RightShift, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_AND_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_OR_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3);
+ }
+ | prefixed_unary_expression OP_XOR_ASSIGN expression
+ {
+ $$ = new CompoundAssign (
+ Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3);
+ }
+ ;
+
+expression
+ : conditional_expression
+ | assignment_expression
+ ;
+
+constant_expression
+ : expression
+ ;
+
+boolean_expression
+ : expression
+ ;
+
+//
+// 10 classes
+//
+class_declaration
+ : opt_attributes
+ opt_modifiers
+ opt_partial
+ CLASS member_name
+ {
+ MemberName name = MakeName ((MemberName) $5);
+ int mod_flags = (int) $2;
+
+ push_current_class (new Class (
+ current_namespace, current_class, name,
+ mod_flags, (Attributes) $1), false, $3);
+ }
+ opt_class_base
+ {
+ if ($7 != null) {
+ if (current_class.Name == "System.Object") {
+ Report.Error (537, current_class.Location,
+ "The class System.Object cannot have a base " +
+ "class or implement an interface.");
+ }
+ current_container.AddBasesForPart (current_class, (ArrayList) $7);
+ }
+
+ if (RootContext.Documentation != null) {
+ current_container.DocComment = Lexer.consume_doc_comment ();
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ }
+ class_body
+ {
+ if (RootContext.Documentation != null)
+ Lexer.doc_state = XmlCommentState.Allowed;
+ }
+ opt_semicolon
+ {
+ $$ = pop_current_class ();
+ }
+ ;
+
+opt_partial
+ : /* empty */
+ { $$ = null; }
+ | PARTIAL
+ { $$ = $1; } // location
+ ;
+
+opt_modifiers
+ : /* empty */ { $$ = (int) 0; }
+ | modifiers
+ ;
+
+modifiers
+ : modifier
+ | modifiers modifier
+ {
+ int m1 = (int) $1;
+ int m2 = (int) $2;
+
+ if ((m1 & m2) != 0) {
+ Location l = lexer.Location;
+ Report.Error (1004, l, "Duplicate `{0}' modifier", Modifiers.Name (m2));
+ }
+ $$ = (int) (m1 | m2);
+ }
+ ;
+
+modifier
+ : NEW { $$ = Modifiers.NEW; }
+ | PUBLIC { $$ = Modifiers.PUBLIC; }
+ | PROTECTED { $$ = Modifiers.PROTECTED; }
+ | INTERNAL { $$ = Modifiers.INTERNAL; }
+ | PRIVATE { $$ = Modifiers.PRIVATE; }
+ | ABSTRACT { $$ = Modifiers.ABSTRACT; }
+ | SEALED { $$ = Modifiers.SEALED; }
+ | STATIC { $$ = Modifiers.STATIC; }
+ | READONLY { $$ = Modifiers.READONLY; }
+ | VIRTUAL { $$ = Modifiers.VIRTUAL; }
+ | OVERRIDE { $$ = Modifiers.OVERRIDE; }
+ | EXTERN { $$ = Modifiers.EXTERN; }
+ | VOLATILE { $$ = Modifiers.VOLATILE; }
+ | UNSAFE { $$ = Modifiers.UNSAFE; }
+ ;
+
+opt_class_base
+ : /* empty */ { $$ = null; }
+ | class_base { $$ = $1; }
+ ;
+
+class_base
+ : COLON type_list { $$ = $2; }
+ ;
+
+//
+// Statements (8.2)
+//
+
+//
+// A block is "contained" on the following places:
+// method_body
+// property_declaration as part of the accessor body (get/set)
+// operator_declaration
+// constructor_declaration
+// destructor_declaration
+// event_declaration as part of add_accessor_declaration or remove_accessor_declaration
+//
+block
+ : OPEN_BRACE
+ {
+ if (parsing_anonymous_method) {
+ top_current_block = new ToplevelBlock (
+ current_block, current_local_parameters, null, (Location) $1);
+ if (current_block != null)
+ current_block.AddAnonymousChild ((ToplevelBlock) top_current_block);
+ current_block = top_current_block;
+ parsing_anonymous_method = false;
+ } else if (current_block == null){
+ current_block = new ToplevelBlock ((ToplevelBlock) top_current_block, current_local_parameters, (Location) $1);
+ top_current_block = current_block;
+ } else {
+ current_block = new Block (current_block, (Location) $1, Location.Null);
+ }
+ }
+ opt_statement_list CLOSE_BRACE
+ {
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block.SetEndLocation ((Location) $4);
+ current_block = current_block.Parent;
+ if (current_block == null)
+ top_current_block = null;
+ }
+ ;
+
+opt_statement_list
+ : /* empty */
+ | statement_list
+ ;
+
+statement_list
+ : statement
+ | statement_list statement
+ ;
+
+statement
+ : declaration_statement
+ {
+ if ($1 != null && (Block) $1 != current_block){
+ current_block.AddStatement ((Statement) $1);
+ current_block = (Block) $1;
+ }
+ }
+ | valid_declaration_statement
+ {
+ current_block.AddStatement ((Statement) $1);
+ }
+ | labeled_statement
+ ;
+
+valid_declaration_statement
+ : block
+ | empty_statement
+ | expression_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ | try_statement
+ | checked_statement
+ | unchecked_statement
+ | lock_statement
+ | using_statement
+ | unsafe_statement
+ | fixed_statement
+ ;
+
+embedded_statement
+ : valid_declaration_statement
+ | declaration_statement
+ {
+ Report.Error (1023, GetLocation ($1), "An embedded statement may not be a declaration or labeled statement");
+ $$ = null;
+ }
+ | labeled_statement
+ {
+ Report.Error (1023, GetLocation ($1), "An embedded statement may not be a declaration or labeled statement");
+ $$ = null;
+ }
+ ;
+
+empty_statement
+ : SEMICOLON
+ {
+ $$ = EmptyStatement.Value;
+ }
+ ;
+
+labeled_statement
+ : IDENTIFIER COLON
+ {
+ LocatedToken lt = (LocatedToken) $1;
+ LabeledStatement labeled = new LabeledStatement (lt.Value, lt.Location);
+
+ if (current_block.AddLabel (labeled))
+ current_block.AddStatement (labeled);
+ }
+ statement
+ ;
+
+declaration_statement
+ : local_variable_declaration SEMICOLON
+ {
+ current_array_type = null;
+ if ($1 != null){
+ DictionaryEntry de = (DictionaryEntry) $1;
+ Expression e = (Expression) de.Key;
+
+ $$ = declare_local_variables (e, (ArrayList) de.Value, e.Location);
+ }
+ }
+
+ | local_constant_declaration SEMICOLON
+ {
+ current_array_type = null;
+ if ($1 != null){
+ DictionaryEntry de = (DictionaryEntry) $1;
+
+ $$ = declare_local_constants ((Expression) de.Key, (ArrayList) de.Value);
+ }
+ }
+ ;
+
+/*
+ * The following is from Rhys' grammar:
+ * > Types in local variable declarations must be recognized as
+ * > expressions to prevent reduce/reduce errors in the grammar.
+ * > The expressions are converted into types during semantic analysis.
+ */
+local_variable_type
+ : primary_expression opt_rank_specifier
+ {
+ // FIXME: Do something smart here regarding the composition of the type.
+
+ // Ok, the above "primary_expression" is there to get rid of
+ // both reduce/reduce and shift/reduces in the grammar, it should
+ // really just be "type_name". If you use type_name, a reduce/reduce
+ // creeps up. If you use namespace_or_type_name (which is all we need
+ // really) two shift/reduces appear.
+ //
+
+ // So the super-trick is that primary_expression
+ // can only be either a SimpleName or a MemberAccess.
+ // The MemberAccess case arises when you have a fully qualified type-name like :
+ // Foo.Bar.Blah i;
+ // SimpleName is when you have
+ // Blah i;
+
+ Expression expr = (Expression) $1;
+ if (!(expr is SimpleName || expr is MemberAccess || expr is ComposedCast || expr is QualifiedAliasMember)) {
+ Error_ExpectingTypeName (expr);
+ $$ = null;
+ } else {
+ //
+ // So we extract the string corresponding to the SimpleName
+ // or MemberAccess
+ //
+
+ if ((string) $2 == "")
+ $$ = $1;
+ else
+ $$ = new ComposedCast ((Expression) $1, (string) $2);
+ }
+ }
+ | builtin_types opt_rank_specifier
+ {
+ if ((string) $2 == "")
+ $$ = $1;
+ else
+ $$ = current_array_type = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
+ }
+ ;
+
+local_variable_pointer_type
+ : primary_expression STAR
+ {
+ Expression expr = (Expression) $1;
+
+ if (!(expr is SimpleName || expr is MemberAccess || expr is ComposedCast || expr is QualifiedAliasMember)) {
+ Error_ExpectingTypeName (expr);
+
+ $$ = null;
+ } else
+ $$ = new ComposedCast ((Expression) $1, "*");
+ }
+ | builtin_types STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
+ }
+ | VOID STAR
+ {
+ $$ = new ComposedCast (TypeManager.system_void_expr, "*", (Location) $1);
+ }
+ | local_variable_pointer_type STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*");
+ }
+ ;
+
+local_variable_declaration
+ : local_variable_type variable_declarators
+ {
+ if ($1 != null)
+ $$ = new DictionaryEntry ($1, $2);
+ else
+ $$ = null;
+ }
+ | local_variable_pointer_type opt_rank_specifier variable_declarators
+ {
+ if ($1 != null){
+ Expression t;
+
+ if ((string) $2 == "")
+ t = (Expression) $1;
+ else
+ t = new ComposedCast ((Expression) $1, (string) $2);
+ $$ = new DictionaryEntry (t, $3);
+ } else
+ $$ = null;
+ }
+ ;
+
+local_constant_declaration
+ : CONST local_variable_type constant_declarators
+ {
+ if ($2 != null)
+ $$ = new DictionaryEntry ($2, $3);
+ else
+ $$ = null;
+ }
+ ;
+
+expression_statement
+ : statement_expression SEMICOLON { $$ = $1; }
+ ;
+
+ //
+ // We have to do the wrapping here and not in the case above,
+ // because statement_expression is used for example in for_statement
+ //
+statement_expression
+ : expression
+ {
+ Expression expr = (Expression) $1;
+ ExpressionStatement s = expr as ExpressionStatement;
+ if (s == null) {
+ Report.Error (201, expr.Location, "Only assignment, call, increment, decrement, and new object expressions can be used as a statement");
+ $$ = null;
+ }
+ $$ = new StatementExpression (s);
+ }
+ | error
+ {
+ Report.Error (1002, GetLocation ($1), "Expecting `;'");
+ $$ = null;
+ }
+ ;
+
+object_creation_expression
+ : object_or_delegate_creation_expression
+ { note ("complain if this is a delegate maybe?"); }
+ ;
+
+selection_statement
+ : if_statement
+ | switch_statement
+ ;
+
+if_statement
+ : IF OPEN_PARENS boolean_expression CLOSE_PARENS
+ embedded_statement
+ {
+ Location l = (Location) $1;
+
+ $$ = new If ((Expression) $3, (Statement) $5, l);
+
+ // FIXME: location for warning should be loc property of $5.
+ if ($5 == EmptyStatement.Value)
+ Report.Warning (642, 3, l, "Possible mistaken empty statement");
+
+ }
+ | IF OPEN_PARENS boolean_expression CLOSE_PARENS
+ embedded_statement ELSE embedded_statement
+ {
+ Location l = (Location) $1;
+
+ $$ = new If ((Expression) $3, (Statement) $5, (Statement) $7, l);
+
+ // FIXME: location for warning should be loc property of $5 and $7.
+ if ($5 == EmptyStatement.Value)
+ Report.Warning (642, 3, l, "Possible mistaken empty statement");
+ if ($7 == EmptyStatement.Value)
+ Report.Warning (642, 3, l, "Possible mistaken empty statement");
+ }
+ ;
+
+switch_statement
+ : SWITCH OPEN_PARENS
+ {
+ if (switch_stack == null)
+ switch_stack = new Stack (2);
+ switch_stack.Push (current_block);
+ }
+ expression CLOSE_PARENS
+ switch_block
+ {
+ $$ = new Switch ((Expression) $4, (ArrayList) $6, (Location) $1);
+ current_block = (Block) switch_stack.Pop ();
+ }
+ ;
+
+switch_block
+ : OPEN_BRACE
+ opt_switch_sections
+ CLOSE_BRACE
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_switch_sections
+ : /* empty */
+ {
+ Report.Warning (1522, 1, lexer.Location, "Empty switch block");
+ $$ = new ArrayList ();
+ }
+ | switch_sections
+ ;
+
+switch_sections
+ : switch_section
+ {
+ ArrayList sections = new ArrayList (4);
+
+ sections.Add ($1);
+ $$ = sections;
+ }
+ | switch_sections switch_section
+ {
+ ArrayList sections = (ArrayList) $1;
+
+ sections.Add ($2);
+ $$ = sections;
+ }
+ ;
+
+switch_section
+ : switch_labels
+ {
+ current_block = current_block.CreateSwitchBlock (lexer.Location);
+ }
+ statement_list
+ {
+ Block topmost = current_block;
+
+ while (topmost.Implicit)
+ topmost = topmost.Parent;
+ $$ = new SwitchSection ((ArrayList) $1, topmost);
+ }
+ ;
+
+switch_labels
+ : switch_label
+ {
+ ArrayList labels = new ArrayList (4);
+
+ labels.Add ($1);
+ $$ = labels;
+ }
+ | switch_labels switch_label
+ {
+ ArrayList labels = (ArrayList) ($1);
+ labels.Add ($2);
+
+ $$ = labels;
+ }
+ ;
+
+switch_label
+ : CASE constant_expression COLON { $$ = new SwitchLabel ((Expression) $2, (Location) $1); }
+ | DEFAULT COLON { $$ = new SwitchLabel (null, (Location) $1); }
+ | error {
+ Report.Error (
+ 1523, GetLocation ($1),
+ "The keyword case or default must precede code in switch block");
+ }
+ ;
+
+iteration_statement
+ : while_statement
+ | do_statement
+ | for_statement
+ | foreach_statement
+ ;
+
+while_statement
+ : WHILE OPEN_PARENS boolean_expression CLOSE_PARENS embedded_statement
+ {
+ Location l = (Location) $1;
+ $$ = new While ((Expression) $3, (Statement) $5, l);
+ }
+ ;
+
+do_statement
+ : DO embedded_statement
+ WHILE OPEN_PARENS boolean_expression CLOSE_PARENS SEMICOLON
+ {
+ Location l = (Location) $1;
+
+ $$ = new Do ((Statement) $2, (Expression) $5, l);
+ }
+ ;
+
+for_statement
+ : FOR OPEN_PARENS
+ opt_for_initializer SEMICOLON
+ {
+ Block assign_block = new Block (current_block);
+ current_block = assign_block;
+
+ if ($3 is DictionaryEntry){
+ DictionaryEntry de = (DictionaryEntry) $3;
+
+ Expression type = (Expression) de.Key;
+ ArrayList var_declarators = (ArrayList) de.Value;
+
+ foreach (VariableDeclaration decl in var_declarators){
+
+ LocalInfo vi;
+
+ vi = current_block.AddVariable (type, decl.identifier, decl.Location);
+ if (vi == null)
+ continue;
+
+ Location l = lexer.Location;
+ Expression expr = decl.expression_or_array_initializer;
+
+ LocalVariableReference var;
+ var = new LocalVariableReference (assign_block, decl.identifier, l);
+
+ if (expr != null) {
+ Assign a = new Assign (var, expr, decl.Location);
+
+ assign_block.AddStatement (new StatementExpression (a));
+ }
+ }
+
+ // Note: the $$ below refers to the value of this code block, not of the LHS non-terminal.
+ // This can be referred to as $5 below.
+ $$ = null;
+ } else {
+ $$ = $3;
+ }
+ }
+ opt_for_condition SEMICOLON
+ opt_for_iterator CLOSE_PARENS
+ embedded_statement
+ {
+ Location l = (Location) $1;
+
+ For f = new For ((Statement) $5, (Expression) $6, (Statement) $8, (Statement) $10, l);
+
+ current_block.AddStatement (f);
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block = current_block.Parent;
+ }
+ ;
+
+opt_for_initializer
+ : /* empty */ { $$ = EmptyStatement.Value; }
+ | for_initializer
+ ;
+
+for_initializer
+ : local_variable_declaration
+ | statement_expression_list
+ ;
+
+opt_for_condition
+ : /* empty */ { $$ = null; }
+ | boolean_expression
+ ;
+
+opt_for_iterator
+ : /* empty */ { $$ = EmptyStatement.Value; }
+ | for_iterator
+ ;
+
+for_iterator
+ : statement_expression_list
+ ;
+
+statement_expression_list
+ : statement_expression
+ {
+ // CHANGE: was `null'
+ Statement s = (Statement) $1;
+ Block b = new Block (current_block, Block.Flags.Implicit, s.loc, lexer.Location);
+
+ b.AddStatement (s);
+ $$ = b;
+ }
+ | statement_expression_list COMMA statement_expression
+ {
+ Block b = (Block) $1;
+
+ b.AddStatement ((Statement) $3);
+ $$ = $1;
+ }
+ ;
+
+foreach_statement
+ : FOREACH OPEN_PARENS type IN expression CLOSE_PARENS
+ {
+ Report.Error (230, (Location) $1, "Type and identifier are both required in a foreach statement");
+ $$ = null;
+ }
+ | FOREACH OPEN_PARENS type IDENTIFIER IN
+ expression CLOSE_PARENS
+ {
+ Block foreach_block = new Block (current_block);
+ current_block = foreach_block;
+
+ LocatedToken lt = (LocatedToken) $4;
+ Location l = lt.Location;
+ LocalInfo vi;
+
+ vi = foreach_block.AddVariable ((Expression) $3, lt.Value, l);
+ if (vi != null) {
+ vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Foreach);
+
+ // Get a writable reference to this read-only variable.
+ //
+ // Note that the $$ here refers to the value of _this_ code block,
+ // not the value of the LHS non-terminal. This can be referred to as $8 below.
+ $$ = new LocalVariableReference (foreach_block, lt.Value, l, vi, false);
+ } else {
+ $$ = null;
+ }
+ }
+ embedded_statement
+ {
+ LocalVariableReference v = (LocalVariableReference) $8;
+ Location l = (Location) $1;
+
+ if (v != null) {
+ Foreach f = new Foreach ((Expression) $3, v, (Expression) $6, (Statement) $9, l);
+ current_block.AddStatement (f);
+ }
+
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block = current_block.Parent;
+ }
+ ;
+
+jump_statement
+ : break_statement
+ | continue_statement
+ | goto_statement
+ | return_statement
+ | throw_statement
+ | yield_statement
+ ;
+
+break_statement
+ : BREAK SEMICOLON
+ {
+ $$ = new Break ((Location) $1);
+ }
+ ;
+
+continue_statement
+ : CONTINUE SEMICOLON
+ {
+ $$ = new Continue ((Location) $1);
+ }
+ ;
+
+goto_statement
+ : GOTO IDENTIFIER SEMICOLON
+ {
+ LocatedToken lt = (LocatedToken) $2;
+ $$ = new Goto (lt.Value, lt.Location);
+ }
+ | GOTO CASE constant_expression SEMICOLON
+ {
+ $$ = new GotoCase ((Expression) $3, (Location) $1);
+ }
+ | GOTO DEFAULT SEMICOLON
+ {
+ $$ = new GotoDefault ((Location) $1);
+ }
+ ;
+
+return_statement
+ : RETURN opt_expression SEMICOLON
+ {
+ $$ = new Return ((Expression) $2, (Location) $1);
+ }
+ ;
+
+throw_statement
+ : THROW opt_expression SEMICOLON
+ {
+ $$ = new Throw ((Expression) $2, (Location) $1);
+ }
+ ;
+
+yield_statement
+ : IDENTIFIER RETURN expression SEMICOLON
+ {
+ LocatedToken lt = (LocatedToken) $1;
+ string s = lt.Value;
+ if (s != "yield"){
+ Report.Error (1003, lt.Location, "; expected");
+ $$ = null;
+ }
+ if (RootContext.Version == LanguageVersion.ISO_1){
+ Report.FeatureIsNotStandardized (lt.Location, "yield statement");
+ $$ = null;
+ }
+ if (anonymous_host == null){
+ Report.Error (204, lt.Location, "yield statement can only be used within a method, operator or property");
+ $$ = null;
+ } else {
+ anonymous_host.SetYields ();
+ $$ = new Yield ((Expression) $3, lt.Location);
+ }
+ }
+ | IDENTIFIER RETURN SEMICOLON
+ {
+ Report.Error (1627, (Location) $2, "Expression expected after yield return");
+ $$ = null;
+ }
+ | IDENTIFIER BREAK SEMICOLON
+ {
+ LocatedToken lt = (LocatedToken) $1;
+ string s = lt.Value;
+ if (s != "yield"){
+ Report.Error (1003, lt.Location, "; expected");
+ $$ = null;
+ }
+ if (RootContext.Version == LanguageVersion.ISO_1){
+ Report.FeatureIsNotStandardized (lt.Location, "yield statement");
+ $$ = null;
+ }
+ if (anonymous_host == null){
+ Report.Error (204, lt.Location, "yield statement can only be used within a method, operator or property");
+ $$ = null;
+ } else {
+ anonymous_host.SetYields ();
+ $$ = new YieldBreak (lt.Location);
+ }
+ }
+ ;
+
+opt_expression
+ : /* empty */
+ | expression
+ ;
+
+try_statement
+ : TRY block catch_clauses
+ {
+ Catch g = null;
+
+ ArrayList c = (ArrayList)$3;
+ for (int i = 0; i < c.Count; ++i) {
+ Catch cc = (Catch) c [i];
+ if (cc.IsGeneral) {
+ if (i != c.Count - 1)
+ Report.Error (1017, cc.loc, "Try statement already has an empty catch block");
+ g = cc;
+ c.RemoveAt (i);
+ i--;
+ }
+ }
+
+ // Now s contains the list of specific catch clauses
+ // and g contains the general one.
+
+ $$ = new Try ((Block) $2, c, g, null, ((Block) $2).loc);
+ }
+ | TRY block opt_catch_clauses FINALLY block
+ {
+ Catch g = null;
+ ArrayList s = new ArrayList (4);
+ ArrayList catch_list = (ArrayList) $3;
+
+ if (catch_list != null){
+ foreach (Catch cc in catch_list) {
+ if (cc.IsGeneral)
+ g = cc;
+ else
+ s.Add (cc);
+ }
+ }
+
+ $$ = new Try ((Block) $2, s, g, (Block) $5, ((Block) $2).loc);
+ }
+ | TRY block error
+ {
+ Report.Error (1524, (Location) $1, "Expected catch or finally");
+ $$ = null;
+ }
+ ;
+
+opt_catch_clauses
+ : /* empty */ { $$ = null; }
+ | catch_clauses
+ ;
+
+catch_clauses
+ : catch_clause
+ {
+ ArrayList l = new ArrayList (4);
+
+ l.Add ($1);
+ $$ = l;
+ }
+ | catch_clauses catch_clause
+ {
+ ArrayList l = (ArrayList) $1;
+
+ l.Add ($2);
+ $$ = l;
+ }
+ ;
+
+opt_identifier
+ : /* empty */ { $$ = null; }
+ | IDENTIFIER
+ ;
+
+catch_clause
+ : CATCH opt_catch_args
+ {
+ Expression type = null;
+
+ if ($2 != null) {
+ DictionaryEntry cc = (DictionaryEntry) $2;
+ type = (Expression) cc.Key;
+ LocatedToken lt = (LocatedToken) cc.Value;
+
+ if (lt != null){
+ ArrayList one = new ArrayList (4);
+
+ one.Add (new VariableDeclaration (lt, null));
+
+ current_block = new Block (current_block);
+ Block b = declare_local_variables (type, one, lt.Location);
+ current_block = b;
+ }
+ }
+ } block {
+ Expression type = null;
+ string id = null;
+ Block var_block = null;
+
+ if ($2 != null){
+ DictionaryEntry cc = (DictionaryEntry) $2;
+ type = (Expression) cc.Key;
+ LocatedToken lt = (LocatedToken) cc.Value;
+
+ if (lt != null){
+ id = lt.Value;
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ var_block = current_block;
+ current_block = current_block.Parent;
+ }
+ }
+
+ $$ = new Catch (type, id, (Block) $4, var_block, ((Block) $4).loc);
+ }
+ ;
+
+opt_catch_args
+ : /* empty */ { $$ = null; }
+ | catch_args
+ ;
+
+catch_args
+ : OPEN_PARENS type opt_identifier CLOSE_PARENS
+ {
+ $$ = new DictionaryEntry ($2, $3);
+ }
+ ;
+
+
+checked_statement
+ : CHECKED block
+ {
+ $$ = new Checked ((Block) $2);
+ }
+ ;
+
+unchecked_statement
+ : UNCHECKED block
+ {
+ $$ = new Unchecked ((Block) $2);
+ }
+ ;
+
+unsafe_statement
+ : UNSAFE
+ {
+ RootContext.CheckUnsafeOption ((Location) $1);
+ } block {
+ $$ = new Unsafe ((Block) $3);
+ }
+ ;
+
+fixed_statement
+ : FIXED OPEN_PARENS
+ type fixed_pointer_declarators
+ CLOSE_PARENS
+ {
+ ArrayList list = (ArrayList) $4;
+ Expression type = (Expression) $3;
+ Location l = (Location) $1;
+ int top = list.Count;
+
+ Block assign_block = new Block (current_block);
+ current_block = assign_block;
+
+ for (int i = 0; i < top; i++){
+ Pair p = (Pair) list [i];
+ LocalInfo v;
+
+ v = current_block.AddVariable (type, (string) p.First, l);
+ if (v == null)
+ continue;
+
+ v.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
+ v.Pinned = true;
+ p.First = v;
+ list [i] = p;
+ }
+ }
+ embedded_statement
+ {
+ Location l = (Location) $1;
+
+ Fixed f = new Fixed ((Expression) $3, (ArrayList) $4, (Statement) $7, l);
+
+ current_block.AddStatement (f);
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block = current_block.Parent;
+ }
+ ;
+
+fixed_pointer_declarators
+ : fixed_pointer_declarator {
+ ArrayList declarators = new ArrayList (4);
+ if ($1 != null)
+ declarators.Add ($1);
+ $$ = declarators;
+ }
+ | fixed_pointer_declarators COMMA fixed_pointer_declarator
+ {
+ ArrayList declarators = (ArrayList) $1;
+ if ($3 != null)
+ declarators.Add ($3);
+ $$ = declarators;
+ }
+ ;
+
+fixed_pointer_declarator
+ : IDENTIFIER ASSIGN expression
+ {
+ LocatedToken lt = (LocatedToken) $1;
+ // FIXME: keep location
+ $$ = new Pair (lt.Value, $3);
+ }
+ | IDENTIFIER
+ {
+ Report.Error (210, ((LocatedToken) $1).Location, "You must provide an initializer in a fixed or using statement declaration");
+ $$ = null;
+ }
+ ;
+
+lock_statement
+ : LOCK OPEN_PARENS expression CLOSE_PARENS
+ {
+ //
+ }
+ embedded_statement
+ {
+ $$ = new Lock ((Expression) $3, (Statement) $6, (Location) $1);
+ }
+ ;
+
+using_statement
+ : USING OPEN_PARENS resource_acquisition CLOSE_PARENS
+ {
+ Block assign_block = new Block (current_block);
+ current_block = assign_block;
+
+ if ($3 is DictionaryEntry){
+ DictionaryEntry de = (DictionaryEntry) $3;
+ Location l = (Location) $1;
+
+ Expression type = (Expression) de.Key;
+ ArrayList var_declarators = (ArrayList) de.Value;
+
+ ArrayList vars = new ArrayList (4);
+
+ foreach (VariableDeclaration decl in var_declarators){
+
+ LocalInfo vi = current_block.AddVariable (type, decl.identifier, decl.Location);
+ if (vi == null)
+ continue;
+ vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Using);
+
+ Expression expr = decl.expression_or_array_initializer;
+ if (expr == null) {
+ Report.Error (210, l, "You must provide an initializer in a fixed or using statement declaration");
+ }
+
+ LocalVariableReference var;
+
+ // Get a writable reference to this read-only variable.
+ var = new LocalVariableReference (assign_block, decl.identifier, l, vi, false);
+
+ // This is so that it is not a warning on using variables
+ vi.Used = true;
+
+ vars.Add (new DictionaryEntry (var, expr));
+
+ // Assign a = new Assign (var, expr, decl.Location);
+ // assign_block.AddStatement (new StatementExpression (a));
+ }
+
+ // Note: the $$ here refers to the value of this code block and not of the LHS non-terminal.
+ // It can be referred to as $5 below.
+ $$ = new DictionaryEntry (type, vars);
+ } else {
+ $$ = $3;
+ }
+ }
+ embedded_statement
+ {
+ Using u = new Using ($5, (Statement) $6, (Location) $1);
+ current_block.AddStatement (u);
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block = current_block.Parent;
+ }
+ ;
+
+resource_acquisition
+ : local_variable_declaration
+ | expression
+ ;
+
+%%
+
+// <summary>
+// A class used to pass around variable declarations and constants
+// </summary>
+public class VariableDeclaration {
+ public string identifier;
+ public Expression expression_or_array_initializer;
+ public Location Location;
+ public Attributes OptAttributes;
+ public string DocComment;
+
+ public VariableDeclaration (LocatedToken lt, object eoai, Attributes opt_attrs)
+ {
+ this.identifier = lt.Value;
+ if (eoai is ArrayList) {
+ if (CSharpParser.current_array_type == null)
+ Report.Error (622, lt.Location,
+ "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
+ this.expression_or_array_initializer = new ArrayCreation (CSharpParser.current_array_type, "", (ArrayList)eoai, lt.Location);
+ } else {
+ this.expression_or_array_initializer = (Expression)eoai;
+ }
+ this.Location = lt.Location;
+ this.OptAttributes = opt_attrs;
+ }
+
+ public VariableDeclaration (LocatedToken lt, object eoai) : this (lt, eoai, null)
+ {
+ }
+}
+
+// <summary>
+// A class used to hold info about an indexer declarator
+// </summary>
+public class IndexerDeclaration {
+ public Expression type;
+ public MemberName interface_type;
+ public Parameters param_list;
+ public Location location;
+
+ public IndexerDeclaration (Expression type, MemberName interface_type,
+ Parameters param_list, Location loc)
+ {
+ this.type = type;
+ this.interface_type = interface_type;
+ this.param_list = param_list;
+ this.location = loc;
+ }
+}
+
+//
+// We use this when we do not have an object in advance that is an IAnonymousHost
+//
+public class SimpleAnonymousHost : IAnonymousHost {
+ public static readonly SimpleAnonymousHost Simple = new SimpleAnonymousHost ();
+
+ bool yields;
+ ArrayList anonymous_methods;
+
+ public static SimpleAnonymousHost GetSimple () {
+ Simple.yields = false;
+ Simple.anonymous_methods = null;
+ return Simple;
+ }
+
+ public void SetYields ()
+ {
+ yields = true;
+ }
+
+ public void AddAnonymousMethod (AnonymousMethodExpression anonymous)
+ {
+ if (anonymous_methods == null)
+ anonymous_methods = new ArrayList ();
+ anonymous_methods.Add (anonymous);
+ }
+
+ public void Propagate (IAnonymousHost real_host)
+ {
+ if (yields)
+ real_host.SetYields ();
+ if (anonymous_methods != null) {
+ foreach (AnonymousMethodExpression ame in anonymous_methods)
+ real_host.AddAnonymousMethod (ame);
+ }
+ }
+}
+
+// <summary>
+// A class used to hold info about an operator declarator
+// </summary>
+public class OperatorDeclaration {
+ public Operator.OpType optype;
+ public Expression ret_type, arg1type, arg2type;
+ public string arg1name, arg2name;
+ public Location location;
+
+ public OperatorDeclaration (Operator.OpType op, Expression ret_type,
+ Expression arg1type, string arg1name,
+ Expression arg2type, string arg2name, Location location)
+ {
+ optype = op;
+ this.ret_type = ret_type;
+ this.arg1type = arg1type;
+ this.arg1name = arg1name;
+ this.arg2type = arg2type;
+ this.arg2name = arg2name;
+ this.location = location;
+ }
+
+}
+
+void Error_ExpectingTypeName (Expression expr)
+{
+ if (expr is Invocation){
+ Report.Error (1002, expr.Location, "Expecting `;'");
+ } else {
+ Report.Error (201, expr.Location, "Only assignment, call, increment, decrement, and new object expressions can be used as a statement");
+ }
+}
+
+void push_current_class (TypeContainer tc, bool is_interface, object partial_token)
+{
+ if (partial_token != null)
+ current_container = current_container.AddPartial (tc, is_interface);
+ else
+ current_container = current_container.AddTypeContainer (tc, is_interface);
+ current_class = tc;
+}
+
+DeclSpace pop_current_class ()
+{
+ DeclSpace retval = current_class;
+
+ current_class = current_class.Parent;
+ current_container = current_class.PartialContainer;
+
+ return retval;
+}
+
+// <summary>
+// Given the @class_name name, it creates a fully qualified name
+// based on the containing declaration space
+// </summary>
+MemberName
+MakeName (MemberName class_name)
+{
+ Namespace ns = current_namespace.NS;
+
+ if (current_container.Name.Length == 0){
+ if (ns.Name.Length != 0)
+ return new MemberName (ns.MemberName, class_name);
+ else
+ return class_name;
+ } else {
+ return new MemberName (current_container.MemberName, class_name);
+ }
+}
+
+Block declare_local_variables (Expression type, ArrayList variable_declarators, Location loc)
+{
+ Block implicit_block;
+ ArrayList inits = null;
+
+ //
+ // We use the `Used' property to check whether statements
+ // have been added to the current block. If so, we need
+ // to create another block to contain the new declaration
+ // otherwise, as an optimization, we use the same block to
+ // add the declaration.
+ //
+ // FIXME: A further optimization is to check if the statements
+ // that were added were added as part of the initialization
+ // below. In which case, no other statements have been executed
+ // and we might be able to reduce the number of blocks for
+ // situations like this:
+ //
+ // int j = 1; int k = j + 1;
+ //
+ if (current_block.Used)
+ implicit_block = new Block (current_block, Block.Flags.Implicit, loc, Location.Null);
+ else
+ implicit_block = current_block;
+
+ foreach (VariableDeclaration decl in variable_declarators){
+
+ if (implicit_block.AddVariable (type, decl.identifier, decl.Location) != null) {
+ if (decl.expression_or_array_initializer != null){
+ if (inits == null)
+ inits = new ArrayList (4);
+ inits.Add (decl);
+ }
+ }
+ }
+
+ if (inits == null)
+ return implicit_block;
+
+ foreach (VariableDeclaration decl in inits){
+ Assign assign;
+ Expression expr = decl.expression_or_array_initializer;
+
+ LocalVariableReference var;
+ var = new LocalVariableReference (implicit_block, decl.identifier, loc);
+
+ assign = new Assign (var, expr, decl.Location);
+
+ implicit_block.AddStatement (new StatementExpression (assign));
+ }
+
+ return implicit_block;
+}
+
+Block declare_local_constants (Expression type, ArrayList declarators)
+{
+ Block implicit_block;
+
+ if (current_block.Used)
+ implicit_block = new Block (current_block, Block.Flags.Implicit);
+ else
+ implicit_block = current_block;
+
+ foreach (VariableDeclaration decl in declarators){
+ implicit_block.AddConstant (type, decl.identifier, (Expression) decl.expression_or_array_initializer, decl.Location);
+ }
+
+ return implicit_block;
+}
+
+void CheckAttributeTarget (string a, Location l)
+{
+ switch (a) {
+
+ case "assembly" : case "module" : case "field" : case "method" : case "param" : case "property" : case "type" :
+ return;
+
+ default :
+ Report.Error (658, l, "`" + a + "' is an invalid attribute target");
+ break;
+ }
+
+}
+
+void CheckUnaryOperator (Operator.OpType op, Location l)
+{
+ switch (op) {
+
+ case Operator.OpType.LogicalNot:
+ case Operator.OpType.OnesComplement:
+ case Operator.OpType.Increment:
+ case Operator.OpType.Decrement:
+ case Operator.OpType.True:
+ case Operator.OpType.False:
+ case Operator.OpType.Addition:
+ case Operator.OpType.Subtraction:
+
+ break;
+
+ default :
+ Report.Error (1019, l, "Overloadable unary operator expected");
+ break;
+
+ }
+}
+
+void CheckBinaryOperator (Operator.OpType op, Location l)
+{
+ switch (op) {
+
+ case Operator.OpType.Addition:
+ case Operator.OpType.Subtraction:
+ case Operator.OpType.Multiply:
+ case Operator.OpType.Division:
+ case Operator.OpType.Modulus:
+ case Operator.OpType.BitwiseAnd:
+ case Operator.OpType.BitwiseOr:
+ case Operator.OpType.ExclusiveOr:
+ case Operator.OpType.LeftShift:
+ case Operator.OpType.RightShift:
+ case Operator.OpType.Equality:
+ case Operator.OpType.Inequality:
+ case Operator.OpType.GreaterThan:
+ case Operator.OpType.LessThan:
+ case Operator.OpType.GreaterThanOrEqual:
+ case Operator.OpType.LessThanOrEqual:
+ break;
+
+ default :
+ Report.Error (1020, l, "Overloadable binary operator expected");
+ break;
+ }
+
+}
+
+void syntax_error (Location l, string msg)
+{
+ Report.Error (1003, l, "Syntax error, " + msg);
+}
+
+void note (string s)
+{
+ // Used to put annotations
+}
+
+Tokenizer lexer;
+
+public Tokenizer Lexer {
+ get {
+ return lexer;
+ }
+}
+
+public CSharpParser (SeekableStreamReader reader, SourceFile file, ArrayList defines)
+{
+ this.name = file.Name;
+ this.file = file;
+ current_namespace = new NamespaceEntry (null, file, null);
+ current_class = current_namespace.SlaveDeclSpace;
+ current_container = current_class.PartialContainer; // == RootContest.ToplevelTypes
+
+ lexer = new Tokenizer (reader, file, defines);
+}
+
+public void parse ()
+{
+ int errors = Report.Errors;
+ try {
+ if (yacc_verbose_flag > 1)
+ yyparse (lexer, new yydebug.yyDebugSimple ());
+ else
+ yyparse (lexer);
+ Tokenizer tokenizer = lexer as Tokenizer;
+ tokenizer.cleanup ();
+ } catch (Exception e){
+ //
+ // Removed for production use, use parser verbose to get the output.
+ //
+ // Console.WriteLine (e);
+ if (Report.Errors == errors)
+ Report.Error (-25, lexer.Location, "Parsing error");
+ if (yacc_verbose_flag > 0)
+ Console.WriteLine (e);
+ }
+
+ if (RootContext.ToplevelTypes.NamespaceEntry != null)
+ throw new InternalErrorException ("who set it?");
+}
+
+static void CheckToken (int error, int yyToken, string msg, Location loc)
+{
+ if (yyToken >= Token.FIRST_KEYWORD && yyToken <= Token.LAST_KEYWORD)
+ Report.Error (error, loc, "{0}: `{1}' is a keyword", msg, yyNames [yyToken].ToLower ());
+ else
+ Report.Error (error, loc, msg);
+}
+
+void CheckIdentifierToken (int yyToken, Location loc)
+{
+ CheckToken (1041, yyToken, "Identifier expected", loc);
+}
+
+string ConsumeStoredComment ()
+{
+ string s = tmpComment;
+ tmpComment = null;
+ Lexer.doc_state = XmlCommentState.Allowed;
+ return s;
+}
+
+Location GetLocation (object obj)
+{
+ if (obj is MemberCore)
+ return ((MemberCore) obj).Location;
+ if (obj is MemberName)
+ return ((MemberName) obj).Location;
+ if (obj is LocatedToken)
+ return ((LocatedToken) obj).Location;
+ if (obj is Location)
+ return (Location) obj;
+ return lexer.Location;
+}
+
+/* end end end */
+}
--- /dev/null
+//
+// cs-tokenizer.cs: The Tokenizer for the C# compiler
+// This also implements the preprocessor
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+// Marek Safar (marek.safar@seznam.cz)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc
+//
+
+/*
+ * TODO:
+ * Make sure we accept the proper Unicode ranges, per the spec.
+ * Report error 1032
+*/
+
+using System;
+using System.Text;
+using System.Collections;
+using System.IO;
+using System.Globalization;
+using System.Reflection;
+
+namespace Mono.CSharp
+{
+ /// <summary>
+ /// Tokenizer for C# source code.
+ /// </summary>
+
+ public class Tokenizer : yyParser.yyInput
+ {
+ SeekableStreamReader reader;
+ SourceFile ref_name;
+ SourceFile file_name;
+ int ref_line = 1;
+ int line = 1;
+ int col = 0;
+ int previous_col;
+ int current_token;
+ bool handle_get_set = false;
+ bool handle_remove_add = false;
+ bool handle_assembly = false;
+ bool handle_constraints = false;
+ bool handle_typeof = false;
+ Location current_location;
+ Location current_comment_location = Location.Null;
+ ArrayList escapedIdentifiers = new ArrayList ();
+
+ //
+ // XML documentation buffer. The save point is used to divide
+ // comments on types and comments on members.
+ //
+ StringBuilder xml_comment_buffer;
+
+ //
+ // See comment on XmlCommentState enumeration.
+ //
+ XmlCommentState xmlDocState = XmlCommentState.Allowed;
+
+ //
+ // Whether tokens have been seen on this line
+ //
+ bool tokens_seen = false;
+
+ //
+ // Whether a token has been seen on the file
+ // This is needed because `define' is not allowed to be used
+ // after a token has been seen.
+ //
+ bool any_token_seen = false;
+
+ static Hashtable tokenValues;
+
+ private static Hashtable TokenValueName
+ {
+ get {
+ if (tokenValues == null)
+ tokenValues = GetTokenValueNameHash ();
+
+ return tokenValues;
+ }
+ }
+
+ private static Hashtable GetTokenValueNameHash ()
+ {
+ Type t = typeof (Token);
+ FieldInfo [] fields = t.GetFields ();
+ Hashtable hash = new Hashtable ();
+ foreach (FieldInfo field in fields) {
+ if (field.IsLiteral && field.IsStatic && field.FieldType == typeof (int))
+ hash.Add (field.GetValue (null), field.Name);
+ }
+ return hash;
+ }
+
+ //
+ // Returns a verbose representation of the current location
+ //
+ public string location {
+ get {
+ string det;
+
+ if (current_token == Token.ERROR)
+ det = "detail: " + error_details;
+ else
+ det = "";
+
+ // return "Line: "+line+" Col: "+col + "\n" +
+ // "VirtLine: "+ref_line +
+ // " Token: "+current_token + " " + det;
+ string current_token_name = TokenValueName [current_token] as string;
+ if (current_token_name == null)
+ current_token_name = current_token.ToString ();
+
+ return String.Format ("{0} ({1},{2}), Token: {3} {4}", ref_name.Name,
+ ref_line,
+ col,
+ current_token_name,
+ det);
+ }
+ }
+
+ public bool PropertyParsing {
+ get {
+ return handle_get_set;
+ }
+
+ set {
+ handle_get_set = value;
+ }
+ }
+
+ public bool AssemblyTargetParsing {
+ get {
+ return handle_assembly;
+ }
+
+ set {
+ handle_assembly = value;
+ }
+ }
+
+ public bool EventParsing {
+ get {
+ return handle_remove_add;
+ }
+
+ set {
+ handle_remove_add = value;
+ }
+ }
+
+ public bool ConstraintsParsing {
+ get {
+ return handle_constraints;
+ }
+
+ set {
+ handle_constraints = value;
+ }
+ }
+
+ public bool TypeOfParsing {
+ get {
+ return handle_typeof;
+ }
+
+ set {
+ handle_typeof = value;
+ }
+ }
+
+ public XmlCommentState doc_state {
+ get { return xmlDocState; }
+ set {
+ if (value == XmlCommentState.Allowed) {
+ check_incorrect_doc_comment ();
+ reset_doc_comment ();
+ }
+ xmlDocState = value;
+ }
+ }
+
+ public bool IsEscapedIdentifier (Location loc)
+ {
+ foreach (LocatedToken lt in escapedIdentifiers)
+ if (lt.Location.Equals (loc))
+ return true;
+ return false;
+ }
+
+ //
+ // Class variables
+ //
+ static CharArrayHashtable[] keywords;
+ static Hashtable keywordStrings = new Hashtable ();
+ static NumberStyles styles;
+ static NumberFormatInfo csharp_format_info;
+
+ //
+ // Values for the associated token returned
+ //
+ int putback_char;
+ Object val;
+
+ //
+ // Pre-processor
+ //
+ Hashtable defines;
+
+ const int TAKING = 1;
+ const int TAKEN_BEFORE = 2;
+ const int ELSE_SEEN = 4;
+ const int PARENT_TAKING = 8;
+ const int REGION = 16;
+
+ //
+ // pre-processor if stack state:
+ //
+ Stack ifstack;
+
+ static System.Text.StringBuilder string_builder;
+
+ const int max_id_size = 512;
+ static char [] id_builder = new char [max_id_size];
+
+ static CharArrayHashtable [] identifiers = new CharArrayHashtable [max_id_size + 1];
+
+ const int max_number_size = 512;
+ static char [] number_builder = new char [max_number_size];
+ static int number_pos;
+
+ //
+ // Details about the error encoutered by the tokenizer
+ //
+ string error_details;
+
+ public string error {
+ get {
+ return error_details;
+ }
+ }
+
+ public int Line {
+ get {
+ return ref_line;
+ }
+ }
+
+ public int Col {
+ get {
+ return col;
+ }
+ }
+
+ //
+ // This is used when the tokenizer needs to save
+ // the current position as it needs to do some parsing
+ // on its own to deamiguate a token in behalf of the
+ // parser.
+ //
+ Stack position_stack = new Stack (2);
+ class Position {
+ public int position;
+ public int ref_line;
+ public int col;
+ public int putback_char;
+ public int previous_col;
+#if GMCS_SOURCES
+ public int parsing_generic_less_than;
+#endif
+ public Position (Tokenizer t)
+ {
+ position = t.reader.Position;
+ ref_line = t.ref_line;
+ col = t.col;
+ putback_char = t.putback_char;
+ previous_col = t.previous_col;
+#if GMCS_SOURCES
+ parsing_generic_less_than = t.parsing_generic_less_than;
+#endif
+ }
+ }
+
+ public void PushPosition ()
+ {
+ position_stack.Push (new Position (this));
+ }
+
+ public void PopPosition ()
+ {
+ Position p = (Position) position_stack.Pop ();
+
+ reader.Position = p.position;
+ ref_line = p.ref_line;
+ col = p.col;
+ putback_char = p.putback_char;
+ previous_col = p.previous_col;
+
+ }
+
+ // Do not reset the position, ignore it.
+ public void DiscardPosition ()
+ {
+ position_stack.Pop ();
+ }
+
+ static void AddKeyword (string kw, int token) {
+ keywordStrings.Add (kw, kw);
+ if (keywords [kw.Length] == null) {
+ keywords [kw.Length] = new CharArrayHashtable (kw.Length);
+ }
+ keywords [kw.Length] [kw.ToCharArray ()] = token;
+ }
+
+ static void InitTokens ()
+ {
+ keywords = new CharArrayHashtable [64];
+
+ AddKeyword ("__arglist", Token.ARGLIST);
+ AddKeyword ("abstract", Token.ABSTRACT);
+ AddKeyword ("as", Token.AS);
+ AddKeyword ("add", Token.ADD);
+ AddKeyword ("assembly", Token.ASSEMBLY);
+ AddKeyword ("base", Token.BASE);
+ AddKeyword ("bool", Token.BOOL);
+ AddKeyword ("break", Token.BREAK);
+ AddKeyword ("byte", Token.BYTE);
+ AddKeyword ("case", Token.CASE);
+ AddKeyword ("catch", Token.CATCH);
+ AddKeyword ("char", Token.CHAR);
+ AddKeyword ("checked", Token.CHECKED);
+ AddKeyword ("class", Token.CLASS);
+ AddKeyword ("const", Token.CONST);
+ AddKeyword ("continue", Token.CONTINUE);
+ AddKeyword ("decimal", Token.DECIMAL);
+ AddKeyword ("default", Token.DEFAULT);
+ AddKeyword ("delegate", Token.DELEGATE);
+ AddKeyword ("do", Token.DO);
+ AddKeyword ("double", Token.DOUBLE);
+ AddKeyword ("else", Token.ELSE);
+ AddKeyword ("enum", Token.ENUM);
+ AddKeyword ("event", Token.EVENT);
+ AddKeyword ("explicit", Token.EXPLICIT);
+ AddKeyword ("extern", Token.EXTERN);
+ AddKeyword ("false", Token.FALSE);
+ AddKeyword ("finally", Token.FINALLY);
+ AddKeyword ("fixed", Token.FIXED);
+ AddKeyword ("float", Token.FLOAT);
+ AddKeyword ("for", Token.FOR);
+ AddKeyword ("foreach", Token.FOREACH);
+ AddKeyword ("goto", Token.GOTO);
+ AddKeyword ("get", Token.GET);
+ AddKeyword ("if", Token.IF);
+ AddKeyword ("implicit", Token.IMPLICIT);
+ AddKeyword ("in", Token.IN);
+ AddKeyword ("int", Token.INT);
+ AddKeyword ("interface", Token.INTERFACE);
+ AddKeyword ("internal", Token.INTERNAL);
+ AddKeyword ("is", Token.IS);
+ AddKeyword ("lock", Token.LOCK);
+ AddKeyword ("long", Token.LONG);
+ AddKeyword ("namespace", Token.NAMESPACE);
+ AddKeyword ("new", Token.NEW);
+ AddKeyword ("null", Token.NULL);
+ AddKeyword ("object", Token.OBJECT);
+ AddKeyword ("operator", Token.OPERATOR);
+ AddKeyword ("out", Token.OUT);
+ AddKeyword ("override", Token.OVERRIDE);
+ AddKeyword ("params", Token.PARAMS);
+ AddKeyword ("private", Token.PRIVATE);
+ AddKeyword ("protected", Token.PROTECTED);
+ AddKeyword ("public", Token.PUBLIC);
+ AddKeyword ("readonly", Token.READONLY);
+ AddKeyword ("ref", Token.REF);
+ AddKeyword ("remove", Token.REMOVE);
+ AddKeyword ("return", Token.RETURN);
+ AddKeyword ("sbyte", Token.SBYTE);
+ AddKeyword ("sealed", Token.SEALED);
+ AddKeyword ("set", Token.SET);
+ AddKeyword ("short", Token.SHORT);
+ AddKeyword ("sizeof", Token.SIZEOF);
+ AddKeyword ("stackalloc", Token.STACKALLOC);
+ AddKeyword ("static", Token.STATIC);
+ AddKeyword ("string", Token.STRING);
+ AddKeyword ("struct", Token.STRUCT);
+ AddKeyword ("switch", Token.SWITCH);
+ AddKeyword ("this", Token.THIS);
+ AddKeyword ("throw", Token.THROW);
+ AddKeyword ("true", Token.TRUE);
+ AddKeyword ("try", Token.TRY);
+ AddKeyword ("typeof", Token.TYPEOF);
+ AddKeyword ("uint", Token.UINT);
+ AddKeyword ("ulong", Token.ULONG);
+ AddKeyword ("unchecked", Token.UNCHECKED);
+ AddKeyword ("unsafe", Token.UNSAFE);
+ AddKeyword ("ushort", Token.USHORT);
+ AddKeyword ("using", Token.USING);
+ AddKeyword ("virtual", Token.VIRTUAL);
+ AddKeyword ("void", Token.VOID);
+ AddKeyword ("volatile", Token.VOLATILE);
+ AddKeyword ("while", Token.WHILE);
+ AddKeyword ("partial", Token.PARTIAL);
+#if GMCS_SOURCE
+ AddKeyword ("where", Token.WHERE);
+#endif
+ }
+
+ //
+ // Class initializer
+ //
+ static Tokenizer ()
+ {
+ InitTokens ();
+ csharp_format_info = NumberFormatInfo.InvariantInfo;
+ styles = NumberStyles.Float;
+
+ string_builder = new System.Text.StringBuilder ();
+ }
+
+ int GetKeyword (char[] id, int id_len)
+ {
+ /*
+ * Keywords are stored in an array of hashtables grouped by their
+ * length.
+ */
+
+ if ((id_len >= keywords.Length) || (keywords [id_len] == null))
+ return -1;
+ object o = keywords [id_len] [id];
+
+ if (o == null)
+ return -1;
+
+ int res = (int) o;
+
+ if (handle_get_set == false && (res == Token.GET || res == Token.SET))
+ return -1;
+ if (handle_remove_add == false && (res == Token.REMOVE || res == Token.ADD))
+ return -1;
+ if (handle_assembly == false && res == Token.ASSEMBLY)
+ return -1;
+#if GMCS_SOURCE
+ if (handle_constraints == false && res == Token.WHERE)
+ return -1;
+#endif
+ return res;
+
+ }
+
+ public Location Location {
+ get { return current_location; }
+ }
+
+ void define (string def)
+ {
+ if (!RootContext.AllDefines.Contains (def)){
+ RootContext.AllDefines [def] = true;
+ }
+ if (defines.Contains (def))
+ return;
+ defines [def] = true;
+ }
+
+ public Tokenizer (SeekableStreamReader input, SourceFile file, ArrayList defs)
+ {
+ this.ref_name = file;
+ this.file_name = file;
+ reader = input;
+
+ putback_char = -1;
+
+ if (defs != null){
+ defines = new Hashtable ();
+ foreach (string def in defs)
+ define (def);
+ }
+
+ xml_comment_buffer = new StringBuilder ();
+
+ //
+ // FIXME: This could be `Location.Push' but we have to
+ // find out why the MS compiler allows this
+ //
+ Mono.CSharp.Location.Push (file);
+ }
+
+ static bool is_identifier_start_character (char c)
+ {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || Char.IsLetter (c);
+ }
+
+ static bool is_identifier_part_character (char c)
+ {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);
+ }
+
+ public static bool IsKeyword (string s)
+ {
+ return keywordStrings [s] != null;
+ }
+
+ public static bool IsValidIdentifier (string s)
+ {
+ if (s == null || s.Length == 0)
+ return false;
+
+ if (!is_identifier_start_character (s [0]))
+ return false;
+
+ for (int i = 1; i < s.Length; i ++)
+ if (! is_identifier_part_character (s [i]))
+ return false;
+
+ return true;
+ }
+
+#if GMCS_SOURCE
+ bool parse_generic_dimension (out int dimension)
+ {
+ dimension = 1;
+
+ again:
+ int the_token = token ();
+ if (the_token == Token.OP_GENERICS_GT)
+ return true;
+ else if (the_token == Token.COMMA) {
+ dimension++;
+ goto again;
+ }
+
+ return false;
+ }
+
+ bool parse_less_than ()
+ {
+ start:
+ int the_token = token ();
+ if (the_token == Token.OPEN_BRACKET) {
+ do {
+ the_token = token ();
+ } while (the_token != Token.CLOSE_BRACKET);
+ the_token = token ();
+ }
+ switch (the_token) {
+ case Token.IDENTIFIER:
+ case Token.OBJECT:
+ case Token.STRING:
+ case Token.BOOL:
+ case Token.DECIMAL:
+ case Token.FLOAT:
+ case Token.DOUBLE:
+ case Token.SBYTE:
+ case Token.BYTE:
+ case Token.SHORT:
+ case Token.USHORT:
+ case Token.INT:
+ case Token.UINT:
+ case Token.LONG:
+ case Token.ULONG:
+ case Token.CHAR:
+ case Token.VOID:
+ break;
+
+ default:
+ return false;
+ }
+ again:
+ the_token = token ();
+
+ if (the_token == Token.OP_GENERICS_GT)
+ return true;
+ else if ((the_token == Token.COMMA) || (the_token == Token.DOT))
+ goto start;
+ else if (the_token == Token.INTERR || the_token == Token.STAR)
+ goto again;
+ else if (the_token == Token.OP_GENERICS_LT) {
+ if (!parse_less_than ())
+ return false;
+ goto again;
+ } else if (the_token == Token.OPEN_BRACKET) {
+ rank_specifiers:
+ the_token = token ();
+ if (the_token == Token.CLOSE_BRACKET)
+ goto again;
+ else if (the_token == Token.COMMA)
+ goto rank_specifiers;
+ return false;
+ }
+
+ return false;
+ }
+
+ int parsing_generic_less_than = 0;
+
+ public void PutbackNullable ()
+ {
+ if (nullable_pos < 0)
+ throw new Exception ();
+
+ current_token = -1;
+ val = null;
+ reader.Position = nullable_pos;
+
+ putback_char = '?';
+ }
+
+ public void PutbackCloseParens ()
+ {
+ putback_char = ')';
+ }
+
+
+ int nullable_pos = -1;
+
+ public void CheckNullable (bool is_nullable)
+ {
+ if (is_nullable)
+ nullable_pos = reader.Position;
+ else
+ nullable_pos = -1;
+ }
+#endif
+ int is_punct (char c, ref bool doread)
+ {
+ int d;
+ int t;
+
+ doread = false;
+
+ switch (c){
+ case '{':
+ val = Location;
+ return Token.OPEN_BRACE;
+ case '}':
+ val = Location;
+ return Token.CLOSE_BRACE;
+ case '[':
+ // To block doccomment inside attribute declaration.
+ if (doc_state == XmlCommentState.Allowed)
+ doc_state = XmlCommentState.NotAllowed;
+ return Token.OPEN_BRACKET;
+ case ']':
+ return Token.CLOSE_BRACKET;
+ case '(':
+ return Token.OPEN_PARENS;
+ case ')': {
+ if (deambiguate_close_parens == 0)
+ return Token.CLOSE_PARENS;
+
+ --deambiguate_close_parens;
+
+ PushPosition ();
+
+ // disable preprocessing directives when peeking
+ process_directives = false;
+ int new_token = xtoken ();
+ process_directives = true;
+
+ PopPosition ();
+
+ if (new_token == Token.OPEN_PARENS)
+ return Token.CLOSE_PARENS_OPEN_PARENS;
+ else if (new_token == Token.MINUS)
+ return Token.CLOSE_PARENS_MINUS;
+ else if (IsCastToken (new_token))
+ return Token.CLOSE_PARENS_CAST;
+ else
+ return Token.CLOSE_PARENS_NO_CAST;
+ }
+
+ case ',':
+ return Token.COMMA;
+ case ';':
+ val = Location;
+ return Token.SEMICOLON;
+ case '~':
+ val = Location;
+ return Token.TILDE;
+ case '?':
+ return Token.INTERR;
+ }
+#if GMCS_SOURCE
+ if (c == '<') {
+ if (parsing_generic_less_than++ > 0)
+ return Token.OP_GENERICS_LT;
+
+ if (handle_typeof) {
+ int dimension;
+ PushPosition ();
+ if (parse_generic_dimension (out dimension)) {
+ val = dimension;
+ DiscardPosition ();
+ return Token.GENERIC_DIMENSION;
+ }
+ PopPosition ();
+ }
+
+ // Save current position and parse next token.
+ PushPosition ();
+ bool is_generic_lt = parse_less_than ();
+ PopPosition ();
+
+ if (is_generic_lt) {
+ parsing_generic_less_than++;
+ return Token.OP_GENERICS_LT;
+ } else
+ parsing_generic_less_than = 0;
+
+ d = peekChar ();
+ if (d == '<'){
+ getChar ();
+ d = peekChar ();
+
+ if (d == '='){
+ doread = true;
+ return Token.OP_SHIFT_LEFT_ASSIGN;
+ }
+ return Token.OP_SHIFT_LEFT;
+ } else if (d == '='){
+ doread = true;
+ return Token.OP_LE;
+ }
+ return Token.OP_LT;
+ } else if (c == '>') {
+ if (parsing_generic_less_than > 0) {
+ parsing_generic_less_than--;
+ return Token.OP_GENERICS_GT;
+ }
+
+ d = peekChar ();
+ if (d == '>'){
+ getChar ();
+ d = peekChar ();
+
+ if (d == '='){
+ doread = true;
+ return Token.OP_SHIFT_RIGHT_ASSIGN;
+ }
+ return Token.OP_SHIFT_RIGHT;
+ } else if (d == '='){
+ doread = true;
+ return Token.OP_GE;
+ }
+ return Token.OP_GT;
+ }
+#endif
+ d = peekChar ();
+ if (c == '+'){
+
+ if (d == '+') {
+ val = Location;
+ t = Token.OP_INC;
+ }
+ else if (d == '=')
+ t = Token.OP_ADD_ASSIGN;
+ else {
+ val = Location;
+ return Token.PLUS;
+ }
+ doread = true;
+ return t;
+ }
+ if (c == '-'){
+ if (d == '-') {
+ val = Location;
+ t = Token.OP_DEC;
+ }
+ else if (d == '=')
+ t = Token.OP_SUB_ASSIGN;
+ else if (d == '>')
+ t = Token.OP_PTR;
+ else {
+ val = Location;
+ return Token.MINUS;
+ }
+ doread = true;
+ return t;
+ }
+
+ if (c == '!'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_NE;
+ }
+ val = Location;
+ return Token.BANG;
+ }
+
+ if (c == '='){
+ if (d == '='){
+ doread = true;
+ return Token.OP_EQ;
+ }
+ return Token.ASSIGN;
+ }
+
+ if (c == '&'){
+ if (d == '&'){
+ doread = true;
+ return Token.OP_AND;
+ } else if (d == '='){
+ doread = true;
+ return Token.OP_AND_ASSIGN;
+ }
+ val = Location;
+ return Token.BITWISE_AND;
+ }
+
+ if (c == '|'){
+ if (d == '|'){
+ doread = true;
+ return Token.OP_OR;
+ } else if (d == '='){
+ doread = true;
+ return Token.OP_OR_ASSIGN;
+ }
+ return Token.BITWISE_OR;
+ }
+
+ if (c == '*'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_MULT_ASSIGN;
+ }
+ val = Location;
+ return Token.STAR;
+ }
+
+ if (c == '/'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_DIV_ASSIGN;
+ }
+ return Token.DIV;
+ }
+
+ if (c == '%'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_MOD_ASSIGN;
+ }
+ return Token.PERCENT;
+ }
+
+ if (c == '^'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_XOR_ASSIGN;
+ }
+ return Token.CARRET;
+ }
+
+#if !GMCS_SOURCE
+ if (c == '<'){
+ if (d == '<'){
+ getChar ();
+ d = peekChar ();
+
+ if (d == '='){
+ doread = true;
+ return Token.OP_SHIFT_LEFT_ASSIGN;
+ }
+ return Token.OP_SHIFT_LEFT;
+ } else if (d == '='){
+ doread = true;
+ return Token.OP_LE;
+ }
+ return Token.OP_LT;
+ }
+
+ if (c == '>'){
+ if (d == '>'){
+ getChar ();
+ d = peekChar ();
+
+ if (d == '='){
+ doread = true;
+ return Token.OP_SHIFT_RIGHT_ASSIGN;
+ }
+ return Token.OP_SHIFT_RIGHT;
+ } else if (d == '='){
+ doread = true;
+ return Token.OP_GE;
+ }
+ return Token.OP_GT;
+ }
+#endif
+ if (c == ':'){
+ if (d == ':'){
+ doread = true;
+ return Token.DOUBLE_COLON;
+ }
+ val = Location;
+ return Token.COLON;
+ }
+
+ return Token.ERROR;
+ }
+
+ int deambiguate_close_parens = 0;
+
+ public void Deambiguate_CloseParens (object expression)
+ {
+ putback (')');
+
+ // When any binary operation is used we are sure it is not a cast
+ if (expression is Binary)
+ return;
+
+ deambiguate_close_parens++;
+ }
+
+ bool decimal_digits (int c)
+ {
+ int d;
+ bool seen_digits = false;
+
+ if (c != -1){
+ if (number_pos == max_number_size)
+ Error_NumericConstantTooLong ();
+ number_builder [number_pos++] = (char) c;
+ }
+
+ //
+ // We use peekChar2, because decimal_digits needs to do a
+ // 2-character look-ahead (5.ToString for example).
+ //
+ while ((d = peekChar2 ()) != -1){
+ if (d >= '0' && d <= '9'){
+ if (number_pos == max_number_size)
+ Error_NumericConstantTooLong ();
+ number_builder [number_pos++] = (char) d;
+ getChar ();
+ seen_digits = true;
+ } else
+ break;
+ }
+
+ return seen_digits;
+ }
+
+ static bool is_hex (int e)
+ {
+ return (e >= '0' && e <= '9') || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
+ }
+
+ static int real_type_suffix (int c)
+ {
+ int t;
+
+ switch (c){
+ case 'F': case 'f':
+ t = Token.LITERAL_FLOAT;
+ break;
+ case 'D': case 'd':
+ t = Token.LITERAL_DOUBLE;
+ break;
+ case 'M': case 'm':
+ t= Token.LITERAL_DECIMAL;
+ break;
+ default:
+ return Token.NONE;
+ }
+ return t;
+ }
+
+ int integer_type_suffix (ulong ul, int c)
+ {
+ bool is_unsigned = false;
+ bool is_long = false;
+
+ if (c != -1){
+ bool scanning = true;
+ do {
+ switch (c){
+ case 'U': case 'u':
+ if (is_unsigned)
+ scanning = false;
+ is_unsigned = true;
+ getChar ();
+ break;
+
+ case 'l':
+ if (!is_unsigned && (RootContext.WarningLevel >= 4)){
+ //
+ // if we have not seen anything in between
+ // report this error
+ //
+ Report.Warning (78, 4, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
+ }
+ //
+ // This goto statement causes the MS CLR 2.0 beta 1 csc to report an error, so
+ // work around that.
+ //
+ //goto case 'L';
+ if (is_long)
+ scanning = false;
+ is_long = true;
+ getChar ();
+ break;
+
+ case 'L':
+ if (is_long)
+ scanning = false;
+ is_long = true;
+ getChar ();
+ break;
+
+ default:
+ scanning = false;
+ break;
+ }
+ c = peekChar ();
+ } while (scanning);
+ }
+
+ if (is_long && is_unsigned){
+ val = ul;
+ return Token.LITERAL_INTEGER;
+ } else if (is_unsigned){
+ // uint if possible, or ulong else.
+
+ if ((ul & 0xffffffff00000000) == 0)
+ val = (uint) ul;
+ else
+ val = ul;
+ } else if (is_long){
+ // long if possible, ulong otherwise
+ if ((ul & 0x8000000000000000) != 0)
+ val = ul;
+ else
+ val = (long) ul;
+ } else {
+ // int, uint, long or ulong in that order
+ if ((ul & 0xffffffff00000000) == 0){
+ uint ui = (uint) ul;
+
+ if ((ui & 0x80000000) != 0)
+ val = ui;
+ else
+ val = (int) ui;
+ } else {
+ if ((ul & 0x8000000000000000) != 0)
+ val = ul;
+ else
+ val = (long) ul;
+ }
+ }
+ return Token.LITERAL_INTEGER;
+ }
+
+ //
+ // given `c' as the next char in the input decide whether
+ // we need to convert to a special type, and then choose
+ // the best representation for the integer
+ //
+ int adjust_int (int c)
+ {
+ try {
+ if (number_pos > 9){
+ ulong ul = (uint) (number_builder [0] - '0');
+
+ for (int i = 1; i < number_pos; i++){
+ ul = checked ((ul * 10) + ((uint)(number_builder [i] - '0')));
+ }
+ return integer_type_suffix (ul, c);
+ } else {
+ uint ui = (uint) (number_builder [0] - '0');
+
+ for (int i = 1; i < number_pos; i++){
+ ui = checked ((ui * 10) + ((uint)(number_builder [i] - '0')));
+ }
+ return integer_type_suffix (ui, c);
+ }
+ } catch (OverflowException) {
+ error_details = "Integral constant is too large";
+ Report.Error (1021, Location, error_details);
+ val = 0ul;
+ return Token.LITERAL_INTEGER;
+ }
+ catch (FormatException) {
+ Report.Error (1013, Location, "Invalid number");
+ val = 0ul;
+ return Token.LITERAL_INTEGER;
+ }
+ }
+
+ int adjust_real (int t)
+ {
+ string s = new String (number_builder, 0, number_pos);
+ const string error_details = "Floating-point constant is outside the range of type `{0}'";
+
+ switch (t){
+ case Token.LITERAL_DECIMAL:
+ try {
+ val = System.Decimal.Parse (s, styles, csharp_format_info);
+ } catch (OverflowException) {
+ val = 0m;
+ Report.Error (594, Location, error_details, "decimal");
+ }
+ break;
+ case Token.LITERAL_FLOAT:
+ try {
+ val = float.Parse (s, styles, csharp_format_info);
+ } catch (OverflowException) {
+ val = 0.0f;
+ Report.Error (594, Location, error_details, "float");
+ }
+ break;
+
+ case Token.LITERAL_DOUBLE:
+ case Token.NONE:
+ t = Token.LITERAL_DOUBLE;
+ try {
+ val = System.Double.Parse (s, styles, csharp_format_info);
+ } catch (OverflowException) {
+ val = 0.0;
+ Report.Error (594, Location, error_details, "double");
+ }
+ break;
+ }
+ return t;
+ }
+
+ int handle_hex ()
+ {
+ int d;
+ ulong ul;
+
+ getChar ();
+ while ((d = peekChar ()) != -1){
+ if (is_hex (d)){
+ number_builder [number_pos++] = (char) d;
+ getChar ();
+ } else
+ break;
+ }
+
+ string s = new String (number_builder, 0, number_pos);
+ try {
+ if (number_pos <= 8)
+ ul = System.UInt32.Parse (s, NumberStyles.HexNumber);
+ else
+ ul = System.UInt64.Parse (s, NumberStyles.HexNumber);
+ } catch (OverflowException){
+ error_details = "Integral constant is too large";
+ Report.Error (1021, Location, error_details);
+ val = 0ul;
+ return Token.LITERAL_INTEGER;
+ }
+ catch (FormatException) {
+ Report.Error (1013, Location, "Invalid number");
+ val = 0ul;
+ return Token.LITERAL_INTEGER;
+ }
+
+ return integer_type_suffix (ul, peekChar ());
+ }
+
+ //
+ // Invoked if we know we have .digits or digits
+ //
+ int is_number (int c)
+ {
+ bool is_real = false;
+ int type;
+
+ number_pos = 0;
+
+ if (c >= '0' && c <= '9'){
+ if (c == '0'){
+ int peek = peekChar ();
+
+ if (peek == 'x' || peek == 'X')
+ return handle_hex ();
+ }
+ decimal_digits (c);
+ c = getChar ();
+ }
+
+ //
+ // We need to handle the case of
+ // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER)
+ //
+ if (c == '.'){
+ if (decimal_digits ('.')){
+ is_real = true;
+ c = getChar ();
+ } else {
+ putback ('.');
+ number_pos--;
+ return adjust_int (-1);
+ }
+ }
+
+ if (c == 'e' || c == 'E'){
+ is_real = true;
+ if (number_pos == max_number_size)
+ Error_NumericConstantTooLong ();
+ number_builder [number_pos++] = 'e';
+ c = getChar ();
+
+ if (c == '+'){
+ if (number_pos == max_number_size)
+ Error_NumericConstantTooLong ();
+ number_builder [number_pos++] = '+';
+ c = -1;
+ } else if (c == '-') {
+ if (number_pos == max_number_size)
+ Error_NumericConstantTooLong ();
+ number_builder [number_pos++] = '-';
+ c = -1;
+ } else {
+ if (number_pos == max_number_size)
+ Error_NumericConstantTooLong ();
+ number_builder [number_pos++] = '+';
+ }
+
+ decimal_digits (c);
+ c = getChar ();
+ }
+
+ type = real_type_suffix (c);
+ if (type == Token.NONE && !is_real){
+ putback (c);
+ return adjust_int (c);
+ } else
+ is_real = true;
+
+ if (type == Token.NONE){
+ putback (c);
+ }
+
+ if (is_real)
+ return adjust_real (type);
+
+ Console.WriteLine ("This should not be reached");
+ throw new Exception ("Is Number should never reach this point");
+ }
+
+ //
+ // Accepts exactly count (4 or 8) hex, no more no less
+ //
+ int getHex (int count, out bool error)
+ {
+ int i;
+ int total = 0;
+ int c;
+ int top = count != -1 ? count : 4;
+
+ getChar ();
+ error = false;
+ for (i = 0; i < top; i++){
+ c = getChar ();
+
+ if (c >= '0' && c <= '9')
+ c = (int) c - (int) '0';
+ else if (c >= 'A' && c <= 'F')
+ c = (int) c - (int) 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ c = (int) c - (int) 'a' + 10;
+ else {
+ error = true;
+ return 0;
+ }
+
+ total = (total * 16) + c;
+ if (count == -1){
+ int p = peekChar ();
+ if (p == -1)
+ break;
+ if (!is_hex ((char)p))
+ break;
+ }
+ }
+ return total;
+ }
+
+ int escape (int c)
+ {
+ bool error;
+ int d;
+ int v;
+
+ d = peekChar ();
+ if (c != '\\')
+ return c;
+
+ switch (d){
+ case 'a':
+ v = '\a'; break;
+ case 'b':
+ v = '\b'; break;
+ case 'n':
+ v = '\n'; break;
+ case 't':
+ v = '\t'; break;
+ case 'v':
+ v = '\v'; break;
+ case 'r':
+ v = '\r'; break;
+ case '\\':
+ v = '\\'; break;
+ case 'f':
+ v = '\f'; break;
+ case '0':
+ v = 0; break;
+ case '"':
+ v = '"'; break;
+ case '\'':
+ v = '\''; break;
+ case 'x':
+ v = getHex (-1, out error);
+ if (error)
+ goto default;
+ return v;
+ case 'u':
+ v = getHex (4, out error);
+ if (error)
+ goto default;
+ return v;
+ case 'U':
+ v = getHex (8, out error);
+ if (error)
+ goto default;
+ return v;
+ default:
+ Report.Error (1009, Location, "Unrecognized escape sequence `\\{0}'", ((char)d).ToString ());
+ return d;
+ }
+ getChar ();
+ return v;
+ }
+
+ int getChar ()
+ {
+ int x;
+ if (putback_char != -1) {
+ x = putback_char;
+ putback_char = -1;
+ } else
+ x = reader.Read ();
+ if (x == '\n') {
+ line++;
+ ref_line++;
+ previous_col = col;
+ col = 0;
+ }
+ else
+ col++;
+ return x;
+ }
+
+ int peekChar ()
+ {
+ if (putback_char != -1)
+ return putback_char;
+ putback_char = reader.Read ();
+ return putback_char;
+ }
+
+ int peekChar2 ()
+ {
+ if (putback_char != -1)
+ return putback_char;
+ return reader.Peek ();
+ }
+
+ void putback (int c)
+ {
+ if (putback_char != -1){
+ Console.WriteLine ("Col: " + col);
+ Console.WriteLine ("Row: " + line);
+ Console.WriteLine ("Name: " + ref_name.Name);
+ Console.WriteLine ("Current [{0}] putting back [{1}] ", putback_char, c);
+ throw new Exception ("This should not happen putback on putback");
+ }
+ if (c == '\n' || col == 0) {
+ // It won't happen though.
+ line--;
+ ref_line--;
+ col = previous_col;
+ }
+ else
+ col--;
+ putback_char = c;
+ }
+
+ public bool advance ()
+ {
+ return peekChar () != -1;
+ }
+
+ public Object Value {
+ get {
+ return val;
+ }
+ }
+
+ public Object value ()
+ {
+ return val;
+ }
+
+ static bool IsCastToken (int token)
+ {
+ switch (token) {
+ case Token.BANG:
+ case Token.TILDE:
+ case Token.IDENTIFIER:
+ case Token.LITERAL_INTEGER:
+ case Token.LITERAL_FLOAT:
+ case Token.LITERAL_DOUBLE:
+ case Token.LITERAL_DECIMAL:
+ case Token.LITERAL_CHARACTER:
+ case Token.LITERAL_STRING:
+ case Token.BASE:
+ case Token.CHECKED:
+ case Token.DELEGATE:
+ case Token.FALSE:
+ case Token.FIXED:
+ case Token.NEW:
+ case Token.NULL:
+ case Token.SIZEOF:
+ case Token.THIS:
+ case Token.THROW:
+ case Token.TRUE:
+ case Token.TYPEOF:
+ case Token.UNCHECKED:
+ case Token.UNSAFE:
+#if GMCS_SOURCE
+ case Token.DEFAULT:
+#endif
+
+ //
+ // These can be part of a member access
+ //
+ case Token.INT:
+ case Token.UINT:
+ case Token.SHORT:
+ case Token.USHORT:
+ case Token.LONG:
+ case Token.ULONG:
+ case Token.DOUBLE:
+ case Token.FLOAT:
+ case Token.CHAR:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public int token ()
+ {
+ current_token = xtoken ();
+
+#if GMCS_SOURCE
+ if (current_token != Token.DEFAULT)
+ return current_token;
+
+ PushPosition();
+ int c = xtoken();
+ if (c == -1)
+ current_token = Token.ERROR;
+ else if (c == Token.OPEN_PARENS)
+ current_token = Token.DEFAULT_OPEN_PARENS;
+ else if (c == Token.COLON)
+ current_token = Token.DEFAULT_COLON;
+ else
+ PopPosition();
+#endif
+ return current_token;
+ }
+
+ static StringBuilder static_cmd_arg = new System.Text.StringBuilder ();
+
+ void get_cmd_arg (out string cmd, out string arg)
+ {
+ int c;
+
+ tokens_seen = false;
+ arg = "";
+ static_cmd_arg.Length = 0;
+
+ // skip over white space
+ while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))
+ ;
+
+ while ((c != -1) && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){
+ if (is_identifier_part_character ((char) c)){
+ static_cmd_arg.Append ((char) c);
+ c = getChar ();
+ } else {
+ putback (c);
+ break;
+ }
+ }
+
+ cmd = static_cmd_arg.ToString ();
+
+ if (c == '\n'){
+ return;
+ }
+
+ // skip over white space
+ while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))
+ ;
+
+ if (c == '\n'){
+ return;
+ } else if (c == '\r'){
+ return;
+ } else if (c == -1){
+ arg = "";
+ return;
+ }
+
+ static_cmd_arg.Length = 0;
+ static_cmd_arg.Append ((char) c);
+
+ while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r')){
+ static_cmd_arg.Append ((char) c);
+ }
+
+ arg = static_cmd_arg.ToString ().Trim ();
+ }
+
+ //
+ // Handles the #line directive
+ //
+ bool PreProcessLine (string arg)
+ {
+ if (arg.Length == 0)
+ return false;
+
+ if (arg == "default"){
+ ref_line = line;
+ ref_name = file_name;
+ Location.Push (ref_name);
+ return true;
+ } else if (arg == "hidden"){
+ //
+ // We ignore #line hidden
+ //
+ return true;
+ }
+
+ try {
+ int pos;
+
+ if ((pos = arg.IndexOf (' ')) != -1 && pos != 0){
+ ref_line = System.Int32.Parse (arg.Substring (0, pos));
+ pos++;
+
+ char [] quotes = { '\"' };
+
+ string name = arg.Substring (pos). Trim (quotes);
+ ref_name = Location.LookupFile (name);
+ file_name.HasLineDirective = true;
+ ref_name.HasLineDirective = true;
+ Location.Push (ref_name);
+ } else {
+ ref_line = System.Int32.Parse (arg);
+ }
+ } catch {
+ return false;
+ }
+
+ return true;
+ }
+
+ //
+ // Handles #define and #undef
+ //
+ void PreProcessDefinition (bool is_define, string arg)
+ {
+ if (arg.Length == 0 || arg == "true" || arg == "false"){
+ Report.Error (1001, Location, "Missing identifer to pre-processor directive");
+ return;
+ }
+
+ char[] whitespace = { ' ', '\t' };
+ if (arg.IndexOfAny (whitespace) != -1){
+ Report.Error (1025, Location, "Single-line comment or end-of-line expected");
+ return;
+ }
+
+ if (!is_identifier_start_character (arg [0]))
+ Report.Error (1001, Location, "Identifier expected: " + arg);
+
+ foreach (char c in arg.Substring (1)){
+ if (!is_identifier_part_character (c)){
+ Report.Error (1001, Location, "Identifier expected: " + arg);
+ return;
+ }
+ }
+
+ if (is_define){
+ if (defines == null)
+ defines = new Hashtable ();
+ define (arg);
+ } else {
+ if (defines == null)
+ return;
+ if (defines.Contains (arg))
+ defines.Remove (arg);
+ }
+ }
+
+ /// <summary>
+ /// Handles #pragma directive
+ /// </summary>
+ void PreProcessPragma (string arg)
+ {
+ const string warning = "warning";
+ const string w_disable = "warning disable";
+ const string w_restore = "warning restore";
+
+ if (arg == w_disable) {
+ Report.RegisterWarningRegion (Location).WarningDisable (line);
+ return;
+ }
+
+ if (arg == w_restore) {
+ Report.RegisterWarningRegion (Location).WarningEnable (line);
+ return;
+ }
+
+ if (arg.StartsWith (w_disable)) {
+ int[] codes = ParseNumbers (arg.Substring (w_disable.Length));
+ foreach (int code in codes) {
+ if (code != 0)
+ Report.RegisterWarningRegion (Location).WarningDisable (Location, code);
+ }
+ return;
+ }
+
+ if (arg.StartsWith (w_restore)) {
+ int[] codes = ParseNumbers (arg.Substring (w_restore.Length));
+ Hashtable w_table = Report.warning_ignore_table;
+ foreach (int code in codes) {
+ if (w_table != null && w_table.Contains (code))
+ Report.Warning (1635, 1, Location, String.Format ("Cannot restore warning `CS{0:0000}' because it was disabled globally", code));
+ Report.RegisterWarningRegion (Location).WarningEnable (Location, code);
+ }
+ return;
+ }
+
+ if (arg.StartsWith (warning)) {
+ Report.Warning (1634, 1, Location, "Expected disable or restore");
+ return;
+ }
+
+ Report.Warning (1633, 1, Location, "Unrecognized #pragma directive");
+ }
+
+ int[] ParseNumbers (string text)
+ {
+ string[] string_array = text.Split (',');
+ int[] values = new int [string_array.Length];
+ int index = 0;
+ foreach (string string_code in string_array) {
+ try {
+ values[index++] = int.Parse (string_code, System.Globalization.CultureInfo.InvariantCulture);
+ }
+ catch (FormatException) {
+ Report.Warning (1692, 1, Location, "Invalid number");
+ }
+ }
+ return values;
+ }
+
+ bool eval_val (string s)
+ {
+ if (s == "true")
+ return true;
+ if (s == "false")
+ return false;
+
+ if (defines == null)
+ return false;
+ if (defines.Contains (s))
+ return true;
+
+ return false;
+ }
+
+ bool pp_primary (ref string s)
+ {
+ s = s.Trim ();
+ int len = s.Length;
+
+ if (len > 0){
+ char c = s [0];
+
+ if (c == '('){
+ s = s.Substring (1);
+ bool val = pp_expr (ref s);
+ if (s.Length > 0 && s [0] == ')'){
+ s = s.Substring (1);
+ return val;
+ }
+ Error_InvalidDirective ();
+ return false;
+ }
+
+ if (is_identifier_start_character (c)){
+ int j = 1;
+
+ while (j < len){
+ c = s [j];
+
+ if (is_identifier_part_character (c)){
+ j++;
+ continue;
+ }
+ bool v = eval_val (s.Substring (0, j));
+ s = s.Substring (j);
+ return v;
+ }
+ bool vv = eval_val (s);
+ s = "";
+ return vv;
+ }
+ }
+ Error_InvalidDirective ();
+ return false;
+ }
+
+ bool pp_unary (ref string s)
+ {
+ s = s.Trim ();
+ int len = s.Length;
+
+ if (len > 0){
+ if (s [0] == '!'){
+ if (len > 1 && s [1] == '='){
+ Error_InvalidDirective ();
+ return false;
+ }
+ s = s.Substring (1);
+ return ! pp_primary (ref s);
+ } else
+ return pp_primary (ref s);
+ } else {
+ Error_InvalidDirective ();
+ return false;
+ }
+ }
+
+ bool pp_eq (ref string s)
+ {
+ bool va = pp_unary (ref s);
+
+ s = s.Trim ();
+ int len = s.Length;
+ if (len > 0){
+ if (s [0] == '='){
+ if (len > 2 && s [1] == '='){
+ s = s.Substring (2);
+ return va == pp_unary (ref s);
+ } else {
+ Error_InvalidDirective ();
+ return false;
+ }
+ } else if (s [0] == '!' && len > 1 && s [1] == '='){
+ s = s.Substring (2);
+
+ return va != pp_unary (ref s);
+
+ }
+ }
+
+ return va;
+
+ }
+
+ bool pp_and (ref string s)
+ {
+ bool va = pp_eq (ref s);
+
+ s = s.Trim ();
+ int len = s.Length;
+ if (len > 0){
+ if (s [0] == '&'){
+ if (len > 2 && s [1] == '&'){
+ s = s.Substring (2);
+ return (va & pp_and (ref s));
+ } else {
+ Error_InvalidDirective ();
+ return false;
+ }
+ }
+ }
+ return va;
+ }
+
+ //
+ // Evaluates an expression for `#if' or `#elif'
+ //
+ bool pp_expr (ref string s)
+ {
+ bool va = pp_and (ref s);
+ s = s.Trim ();
+ int len = s.Length;
+ if (len > 0){
+ char c = s [0];
+
+ if (c == '|'){
+ if (len > 2 && s [1] == '|'){
+ s = s.Substring (2);
+ return va | pp_expr (ref s);
+ } else {
+ Error_InvalidDirective ();
+ return false;
+ }
+ }
+ }
+
+ return va;
+ }
+
+ bool eval (string s)
+ {
+ bool v = pp_expr (ref s);
+ s = s.Trim ();
+ if (s.Length != 0){
+ return false;
+ }
+
+ return v;
+ }
+
+ void Error_NumericConstantTooLong ()
+ {
+ Report.Error (1021, Location, "Numeric constant too long");
+ }
+
+ void Error_InvalidDirective ()
+ {
+ Report.Error (1517, Location, "Invalid preprocessor directive");
+ }
+
+ void Error_UnexpectedDirective (string extra)
+ {
+ Report.Error (
+ 1028, Location,
+ "Unexpected processor directive (" + extra + ")");
+ }
+
+ void Error_TokensSeen ()
+ {
+ Report.Error (1032, Location,
+ "Cannot define or undefine preprocessor symbols after first token in file");
+ }
+
+ //
+ // Set to false to stop handling preprocesser directives
+ //
+ bool process_directives = true;
+
+ //
+ // if true, then the code continues processing the code
+ // if false, the code stays in a loop until another directive is
+ // reached.
+ //
+ bool handle_preprocessing_directive (bool caller_is_taking)
+ {
+ string cmd, arg;
+ bool region_directive = false;
+
+ get_cmd_arg (out cmd, out arg);
+
+ // Eat any trailing whitespaces and single-line comments
+ if (arg.IndexOf ("//") != -1)
+ arg = arg.Substring (0, arg.IndexOf ("//"));
+ arg = arg.TrimEnd (' ', '\t');
+
+ //
+ // The first group of pre-processing instructions is always processed
+ //
+ switch (cmd){
+ case "pragma":
+ if (RootContext.Version == LanguageVersion.ISO_1) {
+ Report.FeatureIsNotStandardized (Location, "#pragma");
+ return caller_is_taking;
+ }
+
+ PreProcessPragma (arg);
+ return caller_is_taking;
+
+ case "line":
+ if (!PreProcessLine (arg))
+ Report.Error (
+ 1576, Location,
+ "The line number specified for #line directive is missing or invalid");
+ return caller_is_taking;
+
+ case "region":
+ region_directive = true;
+ arg = "true";
+ goto case "if";
+
+ case "endregion":
+ region_directive = true;
+ goto case "endif";
+
+ case "if":
+ if (arg.Length == 0){
+ Error_InvalidDirective ();
+ return true;
+ }
+ bool taking = false;
+ if (ifstack == null)
+ ifstack = new Stack (2);
+
+ if (ifstack.Count == 0){
+ taking = true;
+ } else {
+ int state = (int) ifstack.Peek ();
+ if ((state & TAKING) != 0)
+ taking = true;
+ }
+
+ if (eval (arg) && taking){
+ int push = TAKING | TAKEN_BEFORE | PARENT_TAKING;
+ if (region_directive)
+ push |= REGION;
+ ifstack.Push (push);
+ return true;
+ } else {
+ int push = (taking ? PARENT_TAKING : 0);
+ if (region_directive)
+ push |= REGION;
+ ifstack.Push (push);
+ return false;
+ }
+
+ case "endif":
+ if (ifstack == null || ifstack.Count == 0){
+ Error_UnexpectedDirective ("no #if for this #endif");
+ return true;
+ } else {
+ int pop = (int) ifstack.Pop ();
+
+ if (region_directive && ((pop & REGION) == 0))
+ Report.Error (1027, Location, "Expected `#endif' directive");
+ else if (!region_directive && ((pop & REGION) != 0))
+ Report.Error (1038, Location, "#endregion directive expected");
+
+ if (!region_directive && arg.Length != 0) {
+ Report.Error (1025, Location, "Single-line comment or end-of-line expected");
+ }
+
+ if (ifstack.Count == 0)
+ return true;
+ else {
+ int state = (int) ifstack.Peek ();
+
+ if ((state & TAKING) != 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ case "elif":
+ if (ifstack == null || ifstack.Count == 0){
+ Error_UnexpectedDirective ("no #if for this #elif");
+ return true;
+ } else {
+ int state = (int) ifstack.Peek ();
+
+ if ((state & REGION) != 0) {
+ Report.Error (1038, Location, "#endregion directive expected");
+ return true;
+ }
+
+ if ((state & ELSE_SEEN) != 0){
+ Error_UnexpectedDirective ("#elif not valid after #else");
+ return true;
+ }
+
+ if ((state & (TAKEN_BEFORE | TAKING)) != 0)
+ return false;
+
+ if (eval (arg) && ((state & PARENT_TAKING) != 0)){
+ state = (int) ifstack.Pop ();
+ ifstack.Push (state | TAKING | TAKEN_BEFORE);
+ return true;
+ } else
+ return false;
+ }
+
+ case "else":
+ if (ifstack == null || ifstack.Count == 0){
+ Error_UnexpectedDirective ("no #if for this #else");
+ return true;
+ } else {
+ int state = (int) ifstack.Peek ();
+
+ if ((state & REGION) != 0) {
+ Report.Error (1038, Location, "#endregion directive expected");
+ return true;
+ }
+
+ if ((state & ELSE_SEEN) != 0){
+ Error_UnexpectedDirective ("#else within #else");
+ return true;
+ }
+
+ ifstack.Pop ();
+
+ bool ret;
+ if ((state & TAKEN_BEFORE) == 0){
+ ret = ((state & PARENT_TAKING) != 0);
+ } else
+ ret = false;
+
+ if (ret)
+ state |= TAKING;
+ else
+ state &= ~TAKING;
+
+ ifstack.Push (state | ELSE_SEEN);
+
+ return ret;
+ }
+ }
+
+ //
+ // These are only processed if we are in a `taking' block
+ //
+ if (!caller_is_taking)
+ return false;
+
+ switch (cmd){
+ case "define":
+ if (any_token_seen){
+ Error_TokensSeen ();
+ return true;
+ }
+ PreProcessDefinition (true, arg);
+ return true;
+
+ case "undef":
+ if (any_token_seen){
+ Error_TokensSeen ();
+ return true;
+ }
+ PreProcessDefinition (false, arg);
+ return true;
+
+ case "error":
+ Report.Error (1029, Location, "#error: '" + arg + "'");
+ return true;
+
+ case "warning":
+ Report.Warning (1030, 1, Location, "#warning: `{0}'", arg);
+ return true;
+ }
+
+ Report.Error (1024, Location, "Wrong preprocessor directive");
+ return true;
+
+ }
+
+ private int consume_string (bool quoted)
+ {
+ int c;
+ string_builder.Length = 0;
+
+ while ((c = getChar ()) != -1){
+ if (c == '"'){
+ if (quoted && peekChar () == '"'){
+ string_builder.Append ((char) c);
+ getChar ();
+ continue;
+ } else {
+ val = string_builder.ToString ();
+ return Token.LITERAL_STRING;
+ }
+ }
+
+ if (c == '\n'){
+ if (!quoted)
+ Report.Error (1010, Location, "Newline in constant");
+ }
+
+ if (!quoted){
+ c = escape (c);
+ if (c == -1)
+ return Token.ERROR;
+ }
+ string_builder.Append ((char) c);
+ }
+
+ Report.Error (1039, Location, "Unterminated string literal");
+ return Token.EOF;
+ }
+
+ private int consume_identifier (int s)
+ {
+ int res = consume_identifier (s, false);
+
+ if (doc_state == XmlCommentState.Allowed)
+ doc_state = XmlCommentState.NotAllowed;
+ switch (res) {
+ case Token.USING:
+ case Token.NAMESPACE:
+ check_incorrect_doc_comment ();
+ break;
+ }
+
+ if (res == Token.PARTIAL) {
+ // Save current position and parse next token.
+ PushPosition ();
+
+ int next_token = token ();
+ bool ok = (next_token == Token.CLASS) ||
+ (next_token == Token.STRUCT) ||
+ (next_token == Token.INTERFACE);
+
+ PopPosition ();
+
+ if (ok)
+ return res;
+
+// Report.Error (267, Location, "The `partial' modifier can be used only immediately before keyword `class', `struct', or `interface'");
+ val = new LocatedToken (Location, "partial");
+ return Token.IDENTIFIER;
+ }
+
+ return res;
+ }
+
+ private int consume_identifier (int s, bool quoted)
+ {
+ int pos = 1;
+ int c = -1;
+
+ id_builder [0] = (char) s;
+
+ current_location = new Location (ref_line, Col);
+
+ while ((c = getChar ()) != -1) {
+ loop:
+ if (is_identifier_part_character ((char) c)){
+ if (pos == max_id_size){
+ Report.Error (645, Location, "Identifier too long (limit is 512 chars)");
+ return Token.ERROR;
+ }
+
+ id_builder [pos++] = (char) c;
+// putback_char = -1;
+ } else if (c == '\\') {
+ c = escape (c);
+ goto loop;
+ } else {
+// putback_char = c;
+ putback (c);
+ break;
+ }
+ }
+
+ //
+ // Optimization: avoids doing the keyword lookup
+ // on uppercase letters and _
+ //
+ if (!quoted && (s >= 'a' || s == '_')){
+ int keyword = GetKeyword (id_builder, pos);
+ if (keyword != -1) {
+ val = Location;
+ return keyword;
+ }
+ }
+
+ //
+ // Keep identifiers in an array of hashtables to avoid needless
+ // allocations
+ //
+
+ if (identifiers [pos] != null) {
+ val = identifiers [pos][id_builder];
+ if (val != null) {
+ val = new LocatedToken (Location, (string) val);
+ if (quoted)
+ escapedIdentifiers.Add (val);
+ return Token.IDENTIFIER;
+ }
+ }
+ else
+ identifiers [pos] = new CharArrayHashtable (pos);
+
+ val = new String (id_builder, 0, pos);
+ if (RootContext.Version == LanguageVersion.ISO_1) {
+ for (int i = 1; i < id_builder.Length; i += 3) {
+ if (id_builder [i] == '_' && (id_builder [i - 1] == '_' || id_builder [i + 1] == '_')) {
+ Report.Error (1638, Location,
+ "`{0}': Any identifier with double underscores cannot be used when ISO language version mode is specified", val.ToString ());
+ break;
+ }
+ }
+ }
+
+ char [] chars = new char [pos];
+ Array.Copy (id_builder, chars, pos);
+
+ identifiers [pos] [chars] = val;
+
+ val = new LocatedToken (Location, (string) val);
+ if (quoted)
+ escapedIdentifiers.Add (val);
+ return Token.IDENTIFIER;
+ }
+
+ public int xtoken ()
+ {
+ int t;
+ bool doread = false;
+ int c;
+
+ // Whether we have seen comments on the current line
+ bool comments_seen = false;
+
+ val = null;
+ // optimization: eliminate col and implement #directive semantic correctly.
+ for (;(c = getChar ()) != -1;) {
+ if (c == ' ')
+ continue;
+
+ if (c == '\t') {
+ continue;
+ }
+
+ if (c == ' ' || c == '\f' || c == '\v' || c == 0xa0)
+ continue;
+
+ if (c == '\r') {
+ if (peekChar () == '\n')
+ getChar ();
+
+ any_token_seen |= tokens_seen;
+ tokens_seen = false;
+ comments_seen = false;
+ continue;
+ }
+
+ // Handle double-slash comments.
+ if (c == '/'){
+ int d = peekChar ();
+
+ if (d == '/'){
+ getChar ();
+ if (RootContext.Documentation != null && peekChar () == '/') {
+ getChar ();
+ // Don't allow ////.
+ if ((d = peekChar ()) != '/') {
+ update_comment_location ();
+ if (doc_state == XmlCommentState.Allowed)
+ handle_one_line_xml_comment ();
+ else if (doc_state == XmlCommentState.NotAllowed)
+ warn_incorrect_doc_comment ();
+ }
+ }
+ while ((d = getChar ()) != -1 && (d != '\n') && d != '\r')
+ if (d == '\n'){
+ }
+ any_token_seen |= tokens_seen;
+ tokens_seen = false;
+ comments_seen = false;
+ continue;
+ } else if (d == '*'){
+ getChar ();
+ bool docAppend = false;
+ if (RootContext.Documentation != null && peekChar () == '*') {
+ getChar ();
+ update_comment_location ();
+ // But when it is /**/, just do nothing.
+ if (peekChar () == '/') {
+ getChar ();
+ continue;
+ }
+ if (doc_state == XmlCommentState.Allowed)
+ docAppend = true;
+ else if (doc_state == XmlCommentState.NotAllowed)
+ warn_incorrect_doc_comment ();
+ }
+
+ int current_comment_start = 0;
+ if (docAppend) {
+ current_comment_start = xml_comment_buffer.Length;
+ xml_comment_buffer.Append (Environment.NewLine);
+ }
+
+ Location start_location = Location;
+
+ while ((d = getChar ()) != -1){
+ if (d == '*' && peekChar () == '/'){
+ getChar ();
+ comments_seen = true;
+ break;
+ }
+ if (docAppend)
+ xml_comment_buffer.Append ((char) d);
+
+ if (d == '\n'){
+ any_token_seen |= tokens_seen;
+ tokens_seen = false;
+ //
+ // Reset 'comments_seen' just to be consistent.
+ // It doesn't matter either way, here.
+ //
+ comments_seen = false;
+ }
+ }
+ if (!comments_seen)
+ Report.Error (1035, start_location, "End-of-file found, '*/' expected");
+
+ if (docAppend)
+ update_formatted_doc_comment (current_comment_start);
+ continue;
+ }
+ goto is_punct_label;
+ }
+
+
+ if (c == '\\' || is_identifier_start_character ((char)c)){
+ tokens_seen = true;
+ return consume_identifier (c);
+ }
+
+ is_punct_label:
+ current_location = new Location (ref_line, Col);
+ if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){
+ tokens_seen = true;
+ if (doread){
+ getChar ();
+ }
+ return t;
+ }
+
+ // white space
+ if (c == '\n'){
+ any_token_seen |= tokens_seen;
+ tokens_seen = false;
+ comments_seen = false;
+ continue;
+ }
+
+ if (c >= '0' && c <= '9'){
+ tokens_seen = true;
+ return is_number (c);
+ }
+
+ if (c == '.'){
+ tokens_seen = true;
+ int peek = peekChar ();
+ if (peek >= '0' && peek <= '9')
+ return is_number (c);
+ return Token.DOT;
+ }
+
+ /* For now, ignore pre-processor commands */
+ // FIXME: In C# the '#' is not limited to appear
+ // on the first column.
+ if (c == '#') {
+ // return NONE if we're not processing directives (during token peeks)
+ if (!process_directives)
+ return Token.NONE;
+
+ bool cont = true;
+ if (tokens_seen || comments_seen) {
+ error_details = "Preprocessor directives must appear as the first" +
+ " non-whitespace character on a line.";
+
+ Report.Error (1040, Location, error_details);
+
+ return Token.ERROR;
+ }
+
+ start_again:
+
+ cont = handle_preprocessing_directive (cont);
+
+ if (cont){
+ continue;
+ }
+
+ bool skipping = false;
+ for (;(c = getChar ()) != -1;){
+ if (c == '\n'){
+ skipping = false;
+ } else if (c == ' ' || c == '\t' || c == '\v' || c == '\r' || c == 0xa0)
+ continue;
+ else if (c != '#')
+ skipping = true;
+ if (c == '#' && !skipping)
+ goto start_again;
+ }
+ any_token_seen |= tokens_seen;
+ tokens_seen = false;
+ if (c == -1)
+ Report.Error (1027, Location, "Expected `#endif' directive");
+ continue;
+ }
+
+ if (c == '"')
+ return consume_string (false);
+
+ if (c == '\''){
+ c = getChar ();
+ tokens_seen = true;
+ if (c == '\''){
+ error_details = "Empty character literal";
+ Report.Error (1011, Location, error_details);
+ return Token.ERROR;
+ }
+ if (c == '\r' || c == '\n') {
+ Report.Error (1010, Location, "Newline in constant");
+ return Token.ERROR;
+ }
+ c = escape (c);
+ if (c == -1)
+ return Token.ERROR;
+ val = new System.Char ();
+ val = (char) c;
+ c = getChar ();
+
+ if (c != '\''){
+ error_details = "Too many characters in character literal";
+ Report.Error (1012, Location, error_details);
+
+ // Try to recover, read until newline or next "'"
+ while ((c = getChar ()) != -1){
+ if (c == '\n'){
+ break;
+ }
+ else if (c == '\'')
+ break;
+ }
+ return Token.ERROR;
+ }
+ return Token.LITERAL_CHARACTER;
+ }
+
+ if (c == '@') {
+ c = getChar ();
+ if (c == '"') {
+ tokens_seen = true;
+ return consume_string (true);
+ } else if (is_identifier_start_character ((char) c)){
+ return consume_identifier (c, true);
+ } else {
+ Report.Error (1646, Location, "Keyword, identifier, or string expected after verbatim specifier: @");
+ }
+ }
+
+ error_details = ((char)c).ToString ();
+
+ return Token.ERROR;
+ }
+
+ return Token.EOF;
+ }
+
+ //
+ // Handles one line xml comment
+ //
+ private void handle_one_line_xml_comment ()
+ {
+ int c;
+ while ((c = peekChar ()) == ' ')
+ getChar (); // skip heading whitespaces.
+ while ((c = peekChar ()) != -1 && c != '\n' && c != '\r') {
+ xml_comment_buffer.Append ((char) getChar ());
+ }
+ if (c == '\r' || c == '\n')
+ xml_comment_buffer.Append (Environment.NewLine);
+ }
+
+ //
+ // Remove heading "*" in Javadoc-like xml documentation.
+ //
+ private void update_formatted_doc_comment (int current_comment_start)
+ {
+ int length = xml_comment_buffer.Length - current_comment_start;
+ string [] lines = xml_comment_buffer.ToString (
+ current_comment_start,
+ length).Replace ("\r", "").Split ('\n');
+
+ // The first line starts with /**, thus it is not target
+ // for the format check.
+ for (int i = 1; i < lines.Length; i++) {
+ string s = lines [i];
+ int idx = s.IndexOf ('*');
+ string head = null;
+ if (idx < 0) {
+ if (i < lines.Length - 1)
+ return;
+ head = s;
+ } else
+ head = s.Substring (0, idx);
+ foreach (char c in head)
+ if (c != ' ')
+ return;
+ lines [i] = s.Substring (idx + 1);
+ }
+ xml_comment_buffer.Remove (current_comment_start, length);
+ xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines));
+ }
+
+ //
+ // Updates current comment location.
+ //
+ private void update_comment_location ()
+ {
+ if (current_comment_location.IsNull) {
+ // "-2" is for heading "//" or "/*"
+ current_comment_location =
+ new Location (ref_line, col - 2);
+ }
+ }
+
+ //
+ // Checks if there was incorrect doc comments and raise
+ // warnings.
+ //
+ public void check_incorrect_doc_comment ()
+ {
+ if (xml_comment_buffer.Length > 0)
+ warn_incorrect_doc_comment ();
+ }
+
+ //
+ // Raises a warning when tokenizer found incorrect doccomment
+ // markup.
+ //
+ private void warn_incorrect_doc_comment ()
+ {
+ if (doc_state != XmlCommentState.Error) {
+ doc_state = XmlCommentState.Error;
+ // in csc, it is 'XML comment is not placed on
+ // a valid language element'. But that does not
+ // make sense.
+ Report.Warning (1587, 2, Location, "XML comment is not placed on a valid language element");
+ }
+ }
+
+ //
+ // Consumes the saved xml comment lines (if any)
+ // as for current target member or type.
+ //
+ public string consume_doc_comment ()
+ {
+ if (xml_comment_buffer.Length > 0) {
+ string ret = xml_comment_buffer.ToString ();
+ reset_doc_comment ();
+ return ret;
+ }
+ return null;
+ }
+
+ void reset_doc_comment ()
+ {
+ xml_comment_buffer.Length = 0;
+ current_comment_location = Location.Null;
+ }
+
+ public void cleanup ()
+ {
+ if (ifstack != null && ifstack.Count >= 1) {
+ int state = (int) ifstack.Pop ();
+ if ((state & REGION) != 0)
+ Report.Error (1038, Location, "#endregion directive expected");
+// else
+// Report.Error (1027, Location, "Expected `#endif' directive");
+ }
+ }
+ }
+
+ //
+ // Indicates whether it accepts XML documentation or not.
+ //
+ public enum XmlCommentState {
+ // comment is allowed in this state.
+ Allowed,
+ // comment is not allowed in this state.
+ NotAllowed,
+ // once comments appeared when it is NotAllowed, then the
+ // state is changed to it, until the state is changed to
+ // .Allowed.
+ Error
+ }
+}
+
--- /dev/null
+//
+// decl.cs: Declaration base class for structs, classes, enums and interfaces.
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+// Marek Safar (marek.safar@seznam.cz)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc
+//
+// TODO: Move the method verification stuff from the class.cs and interface.cs here
+//
+
+using System;
+using System.Text;
+using System.Collections;
+using System.Globalization;
+using System.Reflection.Emit;
+using System.Reflection;
+
+#if BOOTSTRAP_WITH_OLDLIB
+using XmlElement = System.Object;
+#else
+using System.Xml;
+#endif
+
+namespace Mono.CSharp {
+
+ public class MemberName {
+ public readonly string Name;
+ public readonly TypeArguments TypeArguments;
+
+ public readonly MemberName Left;
+ public readonly Location Location;
+
+ public static readonly MemberName Null = new MemberName ("");
+
+ bool is_double_colon;
+
+ private MemberName (MemberName left, string name, bool is_double_colon,
+ Location loc)
+ {
+ this.Name = name;
+ this.Location = loc;
+ this.is_double_colon = is_double_colon;
+ this.Left = left;
+ }
+
+ private MemberName (MemberName left, string name, bool is_double_colon,
+ TypeArguments args, Location loc)
+ : this (left, name, is_double_colon, loc)
+ {
+ this.TypeArguments = args;
+ }
+
+ public MemberName (string name)
+ : this (name, Location.Null)
+ { }
+
+ public MemberName (string name, Location loc)
+ : this (null, name, false, loc)
+ { }
+
+ public MemberName (string name, TypeArguments args, Location loc)
+ : this (null, name, false, args, loc)
+ { }
+
+ public MemberName (MemberName left, string name)
+ : this (left, name, left != null ? left.Location : Location.Null)
+ { }
+
+ public MemberName (MemberName left, string name, Location loc)
+ : this (left, name, false, loc)
+ { }
+
+ public MemberName (MemberName left, string name, TypeArguments args, Location loc)
+ : this (left, name, false, args, loc)
+ { }
+
+ public MemberName (string alias, string name, Location loc)
+ : this (new MemberName (alias, loc), name, true, loc)
+ { }
+
+ public MemberName (MemberName left, MemberName right)
+ : this (left, right, right.Location)
+ { }
+
+ public MemberName (MemberName left, MemberName right, Location loc)
+ : this (null, right.Name, false, right.TypeArguments, loc)
+ {
+ if (right.is_double_colon)
+ throw new InternalErrorException ("Cannot append double_colon member name");
+ this.Left = (right.Left == null) ? left : new MemberName (left, right.Left);
+ }
+
+ public string GetName ()
+ {
+ return GetName (false);
+ }
+
+ public bool IsGeneric {
+ get {
+ if (TypeArguments != null)
+ return true;
+ else if (Left != null)
+ return Left.IsGeneric;
+ else
+ return false;
+ }
+ }
+
+ public string GetName (bool is_generic)
+ {
+ string name = is_generic ? Basename : Name;
+ string connect = is_double_colon ? "::" : ".";
+ if (Left != null)
+ return Left.GetName (is_generic) + connect + name;
+ else
+ return name;
+ }
+
+ public string GetTypeName ()
+ {
+ string connect = is_double_colon ? "::" : ".";
+ if (Left != null)
+ return Left.GetTypeName () + connect + MakeName (Name, TypeArguments);
+ else
+ return MakeName (Name, TypeArguments);
+ }
+
+ public Expression GetTypeExpression ()
+ {
+#if GMCS_SOURCE
+ if (IsUnbound) {
+ if (!CheckUnbound (Location))
+ return null;
+
+ return new UnboundTypeExpression (this, Location);
+ }
+#endif
+
+ if (Left == null) {
+ if (TypeArguments != null)
+ return new SimpleName (Basename, TypeArguments, Location);
+ else
+ return new SimpleName (Name, Location);
+ }
+
+ if (is_double_colon) {
+ if (Left.Left != null)
+ throw new InternalErrorException ("The left side of a :: should be an identifier");
+ return new QualifiedAliasMember (Left.Name, Name, Location);
+ }
+
+ Expression lexpr = Left.GetTypeExpression ();
+ return new MemberAccess (lexpr, Name, TypeArguments, Location);
+ }
+
+ public MemberName Clone ()
+ {
+ MemberName left_clone = Left == null ? null : Left.Clone ();
+ return new MemberName (left_clone, Name, is_double_colon, TypeArguments, Location);
+ }
+
+ public string Basename {
+ get {
+ if (TypeArguments != null)
+ return MakeName (Name, TypeArguments);
+ else
+ return Name;
+ }
+ }
+
+ public string FullName {
+ get {
+ if (TypeArguments != null)
+ return Name + "<" + TypeArguments + ">";
+ else
+ return Name;
+ }
+ }
+
+ public string MethodName {
+ get {
+ string connect = is_double_colon ? "::" : ".";
+ if (Left != null)
+ return Left.FullName + connect + Name;
+ else
+ return Name;
+ }
+ }
+
+ public override string ToString ()
+ {
+ string connect = is_double_colon ? "::" : ".";
+ if (Left != null)
+ return Left.FullName + connect + FullName;
+ else
+ return FullName;
+ }
+
+ public override bool Equals (object other)
+ {
+ return Equals (other as MemberName);
+ }
+
+ public bool Equals (MemberName other)
+ {
+ if (this == other)
+ return true;
+ if (other == null || Name != other.Name)
+ return false;
+ if (is_double_colon != other.is_double_colon)
+ return false;
+
+ if ((TypeArguments != null) &&
+ (other.TypeArguments == null || TypeArguments.Count != other.TypeArguments.Count))
+ return false;
+
+ if ((TypeArguments == null) && (other.TypeArguments != null))
+ return false;
+
+ if (Left == null)
+ return other.Left == null;
+
+ return Left.Equals (other.Left);
+ }
+
+ public override int GetHashCode ()
+ {
+ int hash = Name.GetHashCode ();
+ for (MemberName n = Left; n != null; n = n.Left)
+ hash ^= n.Name.GetHashCode ();
+ if (is_double_colon)
+ hash ^= 0xbadc01d;
+
+ if (TypeArguments != null)
+ hash ^= TypeArguments.Count << 5;
+
+ return hash & 0x7FFFFFFF;
+ }
+
+ public int CountTypeArguments {
+ get {
+ if (TypeArguments == null)
+ return 0;
+ else
+ return TypeArguments.Count;
+ }
+ }
+
+ public static string MakeName (string name, TypeArguments args)
+ {
+ if (args == null)
+ return name;
+ else
+ return name + "`" + args.Count;
+ }
+
+ public static string MakeName (string name, int count)
+ {
+ return name + "`" + count;
+ }
+
+ protected bool IsUnbound {
+ get {
+ if ((Left != null) && Left.IsUnbound)
+ return true;
+ else if (TypeArguments == null)
+ return false;
+ else
+ return TypeArguments.IsUnbound;
+ }
+ }
+
+ protected bool CheckUnbound (Location loc)
+ {
+ if ((Left != null) && !Left.CheckUnbound (loc))
+ return false;
+ if ((TypeArguments != null) && !TypeArguments.IsUnbound) {
+ Report.Error (1031, loc, "Type expected");
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Base representation for members. This is used to keep track
+ /// of Name, Location and Modifier flags, and handling Attributes.
+ /// </summary>
+ public abstract class MemberCore : Attributable, IResolveContext {
+ /// <summary>
+ /// Public name
+ /// </summary>
+
+ protected string cached_name;
+ public string Name {
+ get {
+ if (cached_name == null)
+ cached_name = MemberName.GetName (!(this is GenericMethod) && !(this is Method));
+ return cached_name;
+ }
+ }
+
+ // Is not readonly because of IndexerName attribute
+ private MemberName member_name;
+ public MemberName MemberName {
+ get { return member_name; }
+ }
+
+ /// <summary>
+ /// Modifier flags that the user specified in the source code
+ /// </summary>
+ public int ModFlags;
+
+ public readonly DeclSpace Parent;
+
+ /// <summary>
+ /// Location where this declaration happens
+ /// </summary>
+ public Location Location {
+ get { return member_name.Location; }
+ }
+
+ /// <summary>
+ /// XML documentation comment
+ /// </summary>
+ protected string comment;
+
+ /// <summary>
+ /// Represents header string for documentation comment
+ /// for each member types.
+ /// </summary>
+ public abstract string DocCommentHeader { get; }
+
+ [Flags]
+ public enum Flags {
+ Obsolete_Undetected = 1, // Obsolete attribute has not been detected yet
+ Obsolete = 1 << 1, // Type has obsolete attribute
+ ClsCompliance_Undetected = 1 << 2, // CLS Compliance has not been detected yet
+ ClsCompliant = 1 << 3, // Type is CLS Compliant
+ CloseTypeCreated = 1 << 4, // Tracks whether we have Closed the type
+ HasCompliantAttribute_Undetected = 1 << 5, // Presence of CLSCompliantAttribute has not been detected
+ HasClsCompliantAttribute = 1 << 6, // Type has CLSCompliantAttribute
+ ClsCompliantAttributeTrue = 1 << 7, // Type has CLSCompliant (true)
+ Excluded_Undetected = 1 << 8, // Conditional attribute has not been detected yet
+ Excluded = 1 << 9, // Method is conditional
+ TestMethodDuplication = 1 << 10, // Test for duplication must be performed
+ IsUsed = 1 << 11,
+ IsAssigned = 1 << 12, // Field is assigned
+ HasExplicitLayout = 1 << 13
+ }
+
+ /// <summary>
+ /// MemberCore flags at first detected then cached
+ /// </summary>
+ internal Flags caching_flags;
+
+ public MemberCore (DeclSpace parent, MemberName name, Attributes attrs)
+ : base (attrs)
+ {
+ this.Parent = parent;
+ member_name = name;
+ caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected;
+ }
+
+ protected virtual void SetMemberName (MemberName new_name)
+ {
+ member_name = new_name;
+ cached_name = null;
+ }
+
+ public abstract bool Define ();
+
+ public virtual string DocComment {
+ get {
+ return comment;
+ }
+ set {
+ comment = value;
+ }
+ }
+
+ //
+ // Returns full member name for error message
+ //
+ public virtual string GetSignatureForError ()
+ {
+ if (Parent == null || Parent.Parent == null)
+ return member_name.ToString ();
+
+ return String.Concat (Parent.GetSignatureForError (), '.', member_name.ToString ());
+ }
+
+ /// <summary>
+ /// Base Emit method. This is also entry point for CLS-Compliant verification.
+ /// </summary>
+ public virtual void Emit ()
+ {
+ if (!RootContext.VerifyClsCompliance)
+ return;
+
+ VerifyClsCompliance ();
+ }
+
+ public virtual bool IsUsed {
+ get { return (caching_flags & Flags.IsUsed) != 0; }
+ }
+
+ public void SetMemberIsUsed ()
+ {
+ caching_flags |= Flags.IsUsed;
+ }
+
+ /// <summary>
+ /// Returns instance of ObsoleteAttribute for this MemberCore
+ /// </summary>
+ public virtual ObsoleteAttribute GetObsoleteAttribute ()
+ {
+ // ((flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0) is slower, but why ?
+ if ((caching_flags & Flags.Obsolete_Undetected) == 0 && (caching_flags & Flags.Obsolete) == 0) {
+ return null;
+ }
+
+ caching_flags &= ~Flags.Obsolete_Undetected;
+
+ if (OptAttributes == null)
+ return null;
+
+ Attribute obsolete_attr = OptAttributes.Search (
+ TypeManager.obsolete_attribute_type);
+ if (obsolete_attr == null)
+ return null;
+
+ ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute ();
+ if (obsolete == null)
+ return null;
+
+ caching_flags |= Flags.Obsolete;
+ return obsolete;
+ }
+
+ /// <summary>
+ /// Checks for ObsoleteAttribute presence. It's used for testing of all non-types elements
+ /// </summary>
+ public virtual void CheckObsoleteness (Location loc)
+ {
+ if (Parent != null)
+ Parent.CheckObsoleteness (loc);
+
+ ObsoleteAttribute oa = GetObsoleteAttribute ();
+ if (oa == null) {
+ return;
+ }
+
+ AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
+ }
+
+ /// <summary>
+ /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
+ /// </summary>
+ public override bool IsClsComplianceRequired ()
+ {
+ if ((caching_flags & Flags.ClsCompliance_Undetected) == 0)
+ return (caching_flags & Flags.ClsCompliant) != 0;
+
+ if (GetClsCompliantAttributeValue () && IsExposedFromAssembly ()) {
+ caching_flags &= ~Flags.ClsCompliance_Undetected;
+ caching_flags |= Flags.ClsCompliant;
+ return true;
+ }
+
+ caching_flags &= ~Flags.ClsCompliance_Undetected;
+ return false;
+ }
+
+ /// <summary>
+ /// Returns true when MemberCore is exposed from assembly.
+ /// </summary>
+ public bool IsExposedFromAssembly ()
+ {
+ if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
+ return false;
+
+ DeclSpace parentContainer = Parent;
+ while (parentContainer != null && parentContainer.ModFlags != 0) {
+ if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
+ return false;
+ parentContainer = parentContainer.Parent;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Goes through class hierarchy and gets value of first found CLSCompliantAttribute.
+ /// If no is attribute exists then assembly CLSCompliantAttribute is returned.
+ /// </summary>
+ public virtual bool GetClsCompliantAttributeValue ()
+ {
+ if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0)
+ return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0;
+
+ caching_flags &= ~Flags.HasCompliantAttribute_Undetected;
+
+ if (OptAttributes != null) {
+ Attribute cls_attribute = OptAttributes.Search (
+ TypeManager.cls_compliant_attribute_type);
+ if (cls_attribute != null) {
+ caching_flags |= Flags.HasClsCompliantAttribute;
+ bool value = cls_attribute.GetClsCompliantAttributeValue ();
+ if (value)
+ caching_flags |= Flags.ClsCompliantAttributeTrue;
+ return value;
+ }
+ }
+
+ if (Parent.GetClsCompliantAttributeValue ()) {
+ caching_flags |= Flags.ClsCompliantAttributeTrue;
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
+ /// </summary>
+ protected bool HasClsCompliantAttribute {
+ get {
+ return (caching_flags & Flags.HasClsCompliantAttribute) != 0;
+ }
+ }
+
+ /// <summary>
+ /// It helps to handle error 102 & 111 detection
+ /// </summary>
+ public virtual bool MarkForDuplicationCheck ()
+ {
+ return false;
+ }
+
+ /// <summary>
+ /// The main virtual method for CLS-Compliant verifications.
+ /// The method returns true if member is CLS-Compliant and false if member is not
+ /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it
+ /// and add their extra verifications.
+ /// </summary>
+ protected virtual bool VerifyClsCompliance ()
+ {
+ if (!IsClsComplianceRequired ()) {
+ if (HasClsCompliantAttribute && RootContext.WarningLevel >= 2) {
+ if (!IsExposedFromAssembly ())
+ Report.Warning (3019, 2, Location, "CLS compliance checking will not be performed on `{0}' because it is not visible from outside this assembly", GetSignatureForError ());
+ if (!CodeGen.Assembly.IsClsCompliant)
+ Report.Warning (3021, 2, Location, "`{0}' does not need a CLSCompliant attribute because the assembly is not marked as CLS-compliant", GetSignatureForError ());
+ }
+ return false;
+ }
+
+ if (HasClsCompliantAttribute) {
+ if (CodeGen.Assembly.ClsCompliantAttribute == null && !CodeGen.Assembly.IsClsCompliant) {
+ Report.Error (3014, Location,
+ "`{0}' cannot be marked as CLS-compliant because the assembly is not marked as CLS-compliant",
+ GetSignatureForError ());
+ return false;
+ }
+
+ if (!Parent.IsClsComplianceRequired ()) {
+ Report.Warning (3018, 1, Location, "`{0}' cannot be marked as CLS-compliant because it is a member of non CLS-compliant type `{1}'",
+ GetSignatureForError (), Parent.GetSignatureForError ());
+ return false;
+ }
+ }
+
+ if (member_name.Name [0] == '_') {
+ Report.Error (3008, Location, "Identifier `{0}' is not CLS-compliant", GetSignatureForError () );
+ }
+ return true;
+ }
+
+ //
+ // Raised (and passed an XmlElement that contains the comment)
+ // when GenerateDocComment is writing documentation expectedly.
+ //
+ internal virtual void OnGenerateDocComment (XmlElement intermediateNode)
+ {
+ }
+
+ //
+ // Returns a string that represents the signature for this
+ // member which should be used in XML documentation.
+ //
+ public virtual string GetDocCommentName (DeclSpace ds)
+ {
+ if (ds == null || this is DeclSpace)
+ return DocCommentHeader + Name;
+ else
+ return String.Concat (DocCommentHeader, ds.Name, ".", Name);
+ }
+
+ //
+ // Generates xml doc comments (if any), and if required,
+ // handle warning report.
+ //
+ internal virtual void GenerateDocComment (DeclSpace ds)
+ {
+ DocUtil.GenerateDocComment (this, ds);
+ }
+
+ public override IResolveContext ResolveContext {
+ get { return this; }
+ }
+
+ #region IResolveContext Members
+
+ public DeclSpace DeclContainer {
+ get { return Parent; }
+ }
+
+ public virtual DeclSpace GenericDeclContainer {
+ get { return DeclContainer; }
+ }
+
+ public bool IsInObsoleteScope {
+ get {
+ if (GetObsoleteAttribute () != null)
+ return true;
+
+ return Parent == null ? false : Parent.IsInObsoleteScope;
+ }
+ }
+
+ public bool IsInUnsafeScope {
+ get {
+ if ((ModFlags & Modifiers.UNSAFE) != 0)
+ return true;
+
+ return Parent == null ? false : Parent.IsInUnsafeScope;
+ }
+ }
+
+ #endregion
+ }
+
+ /// <summary>
+ /// Base class for structs, classes, enumerations and interfaces.
+ /// </summary>
+ /// <remarks>
+ /// They all create new declaration spaces. This
+ /// provides the common foundation for managing those name
+ /// spaces.
+ /// </remarks>
+ public abstract class DeclSpace : MemberCore {
+ /// <summary>
+ /// This points to the actual definition that is being
+ /// created with System.Reflection.Emit
+ /// </summary>
+ public TypeBuilder TypeBuilder;
+
+ /// <summary>
+ /// If we are a generic type, this is the type we are
+ /// currently defining. We need to lookup members on this
+ /// instead of the TypeBuilder.
+ /// </summary>
+ public Type CurrentType;
+
+ //
+ // This is the namespace in which this typecontainer
+ // was declared. We use this to resolve names.
+ //
+ public NamespaceEntry NamespaceEntry;
+
+ private Hashtable Cache = new Hashtable ();
+
+ public readonly string Basename;
+
+ protected Hashtable defined_names;
+
+ public TypeContainer PartialContainer;
+
+ readonly bool is_generic;
+ readonly int count_type_params;
+ readonly int count_current_type_params;
+
+ //
+ // Whether we are Generic
+ //
+ public bool IsGeneric {
+ get {
+ if (is_generic)
+ return true;
+ else if (Parent != null)
+ return Parent.IsGeneric;
+ else
+ return false;
+ }
+ }
+
+ static string[] attribute_targets = new string [] { "type" };
+
+ public DeclSpace (NamespaceEntry ns, DeclSpace parent, MemberName name,
+ Attributes attrs)
+ : base (parent, name, attrs)
+ {
+ NamespaceEntry = ns;
+ Basename = name.Basename;
+ defined_names = new Hashtable ();
+ PartialContainer = null;
+ if (name.TypeArguments != null) {
+ is_generic = true;
+ count_type_params = count_current_type_params = name.TypeArguments.Count;
+ }
+ if (parent != null)
+ count_type_params += parent.count_type_params;
+ }
+
+ public override DeclSpace GenericDeclContainer {
+ get { return this; }
+ }
+
+ /// <summary>
+ /// Adds the member to defined_names table. It tests for duplications and enclosing name conflicts
+ /// </summary>
+ protected virtual bool AddToContainer (MemberCore symbol, string name)
+ {
+ MemberCore mc = (MemberCore) defined_names [name];
+
+ if (mc == null) {
+ defined_names.Add (name, symbol);
+ return true;
+ }
+
+ if (symbol.MarkForDuplicationCheck () && mc.MarkForDuplicationCheck ())
+ return true;
+
+ Report.SymbolRelatedToPreviousError (mc);
+ if ((mc.ModFlags & Modifiers.PARTIAL) != 0 && (symbol is ClassOrStruct || symbol is Interface)) {
+ Error_MissingPartialModifier (symbol);
+ return false;
+ }
+
+ if (this is RootTypes) {
+ Report.Error (101, symbol.Location,
+ "The namespace `{0}' already contains a definition for `{1}'",
+ ((DeclSpace)symbol).NamespaceEntry.GetSignatureForError (), symbol.MemberName.Name);
+ } else if (symbol is TypeParameter) {
+ Report.Error (692, symbol.Location,
+ "Duplicate type parameter `{0}'", name);
+ } else {
+ Report.Error (102, symbol.Location,
+ "The type `{0}' already contains a definition for `{1}'",
+ GetSignatureForError (), symbol.MemberName.Name);
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Returns the MemberCore associated with a given name in the declaration
+ /// space. It doesn't return method based symbols !!
+ /// </summary>
+ ///
+ public MemberCore GetDefinition (string name)
+ {
+ return (MemberCore)defined_names [name];
+ }
+
+ //
+ // root_types contains all the types. All TopLevel types
+ // hence have a parent that points to `root_types', that is
+ // why there is a non-obvious test down here.
+ //
+ public bool IsTopLevel {
+ get { return (Parent != null && Parent.Parent == null); }
+ }
+
+ public virtual void CloseType ()
+ {
+ if ((caching_flags & Flags.CloseTypeCreated) == 0){
+ try {
+ TypeBuilder.CreateType ();
+ } catch {
+ //
+ // The try/catch is needed because
+ // nested enumerations fail to load when they
+ // are defined.
+ //
+ // Even if this is the right order (enumerations
+ // declared after types).
+ //
+ // Note that this still creates the type and
+ // it is possible to save it
+ }
+ caching_flags |= Flags.CloseTypeCreated;
+ }
+ }
+
+ protected virtual TypeAttributes TypeAttr {
+ get { return CodeGen.Module.DefaultCharSetType; }
+ }
+
+ /// <remarks>
+ /// Should be overriten by the appropriate declaration space
+ /// </remarks>
+ public abstract TypeBuilder DefineType ();
+
+ /// <summary>
+ /// Define all members, but don't apply any attributes or do anything which may
+ /// access not-yet-defined classes. This method also creates the MemberCache.
+ /// </summary>
+ public virtual bool DefineMembers ()
+ {
+ if (((ModFlags & Modifiers.NEW) != 0) && IsTopLevel) {
+ Report.Error (1530, Location, "Keyword `new' is not allowed on namespace elements");
+ return false;
+ }
+ return true;
+ }
+
+ protected void Error_MissingPartialModifier (MemberCore type)
+ {
+ Report.Error (260, type.Location,
+ "Missing partial modifier on declaration of type `{0}'. Another partial declaration of this type exists",
+ type.GetSignatureForError ());
+ }
+
+ public override string GetSignatureForError ()
+ {
+ if (IsGeneric) {
+ return SimpleName.RemoveGenericArity (Name) + TypeParameter.GetSignatureForError (CurrentTypeParameters);
+ }
+ // Parent.GetSignatureForError
+ return Name;
+ }
+
+ public bool CheckAccessLevel (Type check_type)
+ {
+ TypeBuilder tb;
+ if (this is GenericMethod)
+ tb = Parent.TypeBuilder;
+ else
+ tb = TypeBuilder;
+
+ check_type = TypeManager.DropGenericTypeArguments (check_type);
+ if (check_type == tb)
+ return true;
+
+ if (TypeBuilder == null)
+ // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases().
+ // However, this is invoked again later -- so safe to return true.
+ // May also be null when resolving top-level attributes.
+ return true;
+
+ if (TypeManager.IsGenericParameter (check_type))
+ return true; // FIXME
+
+ TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
+
+ //
+ // Broken Microsoft runtime, return public for arrays, no matter what
+ // the accessibility is for their underlying class, and they return
+ // NonPublic visibility for pointers
+ //
+ if (check_type.IsArray || check_type.IsPointer)
+ return CheckAccessLevel (TypeManager.GetElementType (check_type));
+
+ switch (check_attr){
+ case TypeAttributes.Public:
+ return true;
+
+ case TypeAttributes.NotPublic:
+
+ if (TypeBuilder == null)
+ // FIXME: TypeBuilder will be null when invoked by Class.GetNormalBases().
+ // However, this is invoked again later -- so safe to return true.
+ // May also be null when resolving top-level attributes.
+ return true;
+ //
+ // This test should probably use the declaringtype.
+ //
+ return check_type.Assembly == TypeBuilder.Assembly ||
+ TypeManager.IsFriendAssembly (check_type.Assembly);
+
+ case TypeAttributes.NestedPublic:
+ return true;
+
+ case TypeAttributes.NestedPrivate:
+ return NestedAccessible (tb, check_type);
+
+ case TypeAttributes.NestedFamily:
+ //
+ // Only accessible to methods in current type or any subtypes
+ //
+ return FamilyAccessible (tb, check_type);
+
+ case TypeAttributes.NestedFamANDAssem:
+ return ((check_type.Assembly == tb.Assembly) ||
+ TypeManager.IsFriendAssembly (check_type.Assembly)) &&
+ FamilyAccessible (tb, check_type);
+
+ case TypeAttributes.NestedFamORAssem:
+ return (check_type.Assembly == tb.Assembly) ||
+ FamilyAccessible (tb, check_type) ||
+ TypeManager.IsFriendAssembly (check_type.Assembly);
+
+ case TypeAttributes.NestedAssembly:
+ return check_type.Assembly == tb.Assembly ||
+ TypeManager.IsFriendAssembly (check_type.Assembly);
+ }
+
+ Console.WriteLine ("HERE: " + check_attr);
+ return false;
+
+ }
+
+ protected bool NestedAccessible (Type tb, Type check_type)
+ {
+ Type declaring = check_type.DeclaringType;
+ return TypeBuilder == declaring ||
+ TypeManager.IsNestedChildOf (TypeBuilder, declaring);
+ }
+
+ protected bool FamilyAccessible (Type tb, Type check_type)
+ {
+ Type declaring = check_type.DeclaringType;
+ return TypeManager.IsNestedFamilyAccessible (TypeBuilder, declaring);
+ }
+
+ // Access level of a type.
+ const int X = 1;
+ enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope'
+ // Public Assembly Protected
+ Protected = (0 << 0) | (0 << 1) | (X << 2),
+ Public = (X << 0) | (X << 1) | (X << 2),
+ Private = (0 << 0) | (0 << 1) | (0 << 2),
+ Internal = (0 << 0) | (X << 1) | (0 << 2),
+ ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2),
+ }
+
+ static AccessLevel GetAccessLevelFromModifiers (int flags)
+ {
+ if ((flags & Modifiers.INTERNAL) != 0) {
+
+ if ((flags & Modifiers.PROTECTED) != 0)
+ return AccessLevel.ProtectedOrInternal;
+ else
+ return AccessLevel.Internal;
+
+ } else if ((flags & Modifiers.PROTECTED) != 0)
+ return AccessLevel.Protected;
+ else if ((flags & Modifiers.PRIVATE) != 0)
+ return AccessLevel.Private;
+ else
+ return AccessLevel.Public;
+ }
+
+ // What is the effective access level of this?
+ // TODO: Cache this?
+ AccessLevel EffectiveAccessLevel {
+ get {
+ AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags);
+ if (!IsTopLevel && (Parent != null))
+ return myAccess & Parent.EffectiveAccessLevel;
+ return myAccess;
+ }
+ }
+
+ // Return the access level for type `t'
+ static AccessLevel TypeEffectiveAccessLevel (Type t)
+ {
+ if (t.IsPublic)
+ return AccessLevel.Public;
+ if (t.IsNestedPrivate)
+ return AccessLevel.Private;
+ if (t.IsNotPublic)
+ return AccessLevel.Internal;
+
+ // By now, it must be nested
+ AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType);
+
+ if (t.IsNestedPublic)
+ return parentLevel;
+ if (t.IsNestedAssembly)
+ return parentLevel & AccessLevel.Internal;
+ if (t.IsNestedFamily)
+ return parentLevel & AccessLevel.Protected;
+ if (t.IsNestedFamORAssem)
+ return parentLevel & AccessLevel.ProtectedOrInternal;
+ if (t.IsNestedFamANDAssem)
+ throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways");
+
+ // nested private is taken care of
+
+ throw new Exception ("I give up, what are you?");
+ }
+
+ //
+ // This answers `is the type P, as accessible as a member M which has the
+ // accessability @flags which is declared as a nested member of the type T, this declspace'
+ //
+ public bool AsAccessible (Type p, int flags)
+ {
+ if (TypeManager.IsGenericParameter (p))
+ return true; // FIXME
+
+ //
+ // 1) if M is private, its accessability is the same as this declspace.
+ // we already know that P is accessible to T before this method, so we
+ // may return true.
+ //
+
+ if ((flags & Modifiers.PRIVATE) != 0)
+ return true;
+
+ while (p.IsArray || p.IsPointer || p.IsByRef)
+ p = TypeManager.GetElementType (p);
+
+ AccessLevel pAccess = TypeEffectiveAccessLevel (p);
+ AccessLevel mAccess = this.EffectiveAccessLevel &
+ GetAccessLevelFromModifiers (flags);
+
+ // for every place from which we can access M, we must
+ // be able to access P as well. So, we want
+ // For every bit in M and P, M_i -> P_1 == true
+ // or, ~ (M -> P) == 0 <-> ~ ( ~M | P) == 0
+
+ return ~ (~ mAccess | pAccess) == 0;
+ }
+
+ private Type LookupNestedTypeInHierarchy (string name)
+ {
+ // if the member cache has been created, lets use it.
+ // the member cache is MUCH faster.
+ if (MemberCache != null)
+ return MemberCache.FindNestedType (name);
+
+ // no member cache. Do it the hard way -- reflection
+ Type t = null;
+ for (Type current_type = TypeBuilder;
+ current_type != null && current_type != TypeManager.object_type;
+ current_type = current_type.BaseType) {
+ current_type = TypeManager.DropGenericTypeArguments (current_type);
+ if (current_type is TypeBuilder) {
+ TypeContainer tc = current_type == TypeBuilder
+ ? PartialContainer
+ : TypeManager.LookupTypeContainer (current_type);
+ if (tc != null)
+ t = tc.FindNestedType (name);
+ } else {
+ t = TypeManager.GetNestedType (current_type, name);
+ }
+
+ if (t != null && CheckAccessLevel (t))
+ return t;
+ }
+
+ return null;
+ }
+
+ //
+ // Public function used to locate types.
+ //
+ // Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
+ //
+ // Returns: Type or null if they type can not be found.
+ //
+ public FullNamedExpression LookupType (string name, Location loc, bool ignore_cs0104)
+ {
+ if (Cache.Contains (name))
+ return (FullNamedExpression) Cache [name];
+
+ FullNamedExpression e;
+ Type t = LookupNestedTypeInHierarchy (name);
+ if (t != null)
+ e = new TypeExpression (t, Location.Null);
+ else if (Parent != null)
+ e = Parent.LookupType (name, loc, ignore_cs0104);
+ else
+ e = NamespaceEntry.LookupNamespaceOrType (this, name, loc, ignore_cs0104);
+
+ Cache [name] = e;
+ return e;
+ }
+
+ /// <remarks>
+ /// This function is broken and not what you're looking for. It should only
+ /// be used while the type is still being created since it doesn't use the cache
+ /// and relies on the filter doing the member name check.
+ /// </remarks>
+ public abstract MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria);
+
+ /// <remarks>
+ /// If we have a MemberCache, return it. This property may return null if the
+ /// class doesn't have a member cache or while it's still being created.
+ /// </remarks>
+ public abstract MemberCache MemberCache {
+ get;
+ }
+
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+ {
+ if (a.Type == TypeManager.required_attr_type) {
+ Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types");
+ return;
+ }
+ TypeBuilder.SetCustomAttribute (cb);
+ }
+
+ //
+ // Extensions for generics
+ //
+ TypeParameter[] type_params;
+ TypeParameter[] type_param_list;
+
+ protected string GetInstantiationName ()
+ {
+ StringBuilder sb = new StringBuilder (Name);
+ sb.Append ("<");
+ for (int i = 0; i < type_param_list.Length; i++) {
+ if (i > 0)
+ sb.Append (",");
+ sb.Append (type_param_list [i].Name);
+ }
+ sb.Append (">");
+ return sb.ToString ();
+ }
+
+ bool check_type_parameter (ArrayList list, int start, string name)
+ {
+ for (int i = 0; i < start; i++) {
+ TypeParameter param = (TypeParameter) list [i];
+
+ if (param.Name != name)
+ continue;
+
+ Report.SymbolRelatedToPreviousError (Parent);
+ // TODO: Location is wrong (parent instead of child)
+ Report.Warning (693, 3, Location,
+ "Type parameter `{0}' has the same name as the type parameter from outer type `{1}'",
+ name, Parent.GetSignatureForError ());
+
+ return false;
+ }
+
+ return true;
+ }
+
+ TypeParameter[] initialize_type_params ()
+ {
+ if (type_param_list != null)
+ return type_param_list;
+
+ DeclSpace the_parent = Parent;
+ if (this is GenericMethod)
+ the_parent = null;
+
+ int start = 0;
+ TypeParameter[] parent_params = null;
+ if ((the_parent != null) && the_parent.IsGeneric) {
+ parent_params = the_parent.initialize_type_params ();
+ start = parent_params != null ? parent_params.Length : 0;
+ }
+
+ ArrayList list = new ArrayList ();
+ if (parent_params != null)
+ list.AddRange (parent_params);
+
+ int count = type_params != null ? type_params.Length : 0;
+ for (int i = 0; i < count; i++) {
+ TypeParameter param = type_params [i];
+ check_type_parameter (list, start, param.Name);
+ list.Add (param);
+ }
+
+ type_param_list = new TypeParameter [list.Count];
+ list.CopyTo (type_param_list, 0);
+ return type_param_list;
+ }
+
+ public virtual void SetParameterInfo (ArrayList constraints_list)
+ {
+ if (!is_generic) {
+ if (constraints_list != null) {
+ Report.Error (
+ 80, Location, "Constraints are not allowed " +
+ "on non-generic declarations");
+ }
+
+ return;
+ }
+
+ TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
+ type_params = new TypeParameter [names.Length];
+
+ //
+ // Register all the names
+ //
+ for (int i = 0; i < type_params.Length; i++) {
+ TypeParameterName name = names [i];
+
+ Constraints constraints = null;
+ if (constraints_list != null) {
+ int total = constraints_list.Count;
+ for (int ii = 0; ii < total; ++ii) {
+ Constraints constraints_at = (Constraints)constraints_list[ii];
+ // TODO: it is used by iterators only
+ if (constraints_at == null) {
+ constraints_list.RemoveAt (ii);
+ --total;
+ continue;
+ }
+ if (constraints_at.TypeParameter == name.Name) {
+ constraints = constraints_at;
+ constraints_list.RemoveAt(ii);
+ break;
+ }
+ }
+ }
+
+ type_params [i] = new TypeParameter (
+ Parent, this, name.Name, constraints, name.OptAttributes,
+ Location);
+
+ AddToContainer (type_params [i], name.Name);
+ }
+
+ if (constraints_list != null && constraints_list.Count > 0) {
+ foreach (Constraints constraint in constraints_list) {
+ Report.Error(699, constraint.Location, "`{0}': A constraint references nonexistent type parameter `{1}'",
+ GetSignatureForError (), constraint.TypeParameter);
+ }
+ }
+ }
+
+ public TypeParameter[] TypeParameters {
+ get {
+ if (!IsGeneric)
+ throw new InvalidOperationException ();
+ if (type_param_list == null)
+ initialize_type_params ();
+
+ return type_param_list;
+ }
+ }
+
+ public TypeParameter[] CurrentTypeParameters {
+ get {
+ if (!IsGeneric)
+ throw new InvalidOperationException ();
+ if (type_params != null)
+ return type_params;
+ else
+ return new TypeParameter [0];
+ }
+ }
+
+ public int CountTypeParameters {
+ get {
+ return count_type_params;
+ }
+ }
+
+ public int CountCurrentTypeParameters {
+ get {
+ return count_current_type_params;
+ }
+ }
+
+ public TypeParameterExpr LookupGeneric (string name, Location loc)
+ {
+ if (!IsGeneric)
+ return null;
+
+ TypeParameter [] current_params;
+ if (this is TypeContainer)
+ current_params = PartialContainer.CurrentTypeParameters;
+ else
+ current_params = CurrentTypeParameters;
+
+ foreach (TypeParameter type_param in current_params) {
+ if (type_param.Name == name)
+ return new TypeParameterExpr (type_param, loc);
+ }
+
+ if (Parent != null)
+ return Parent.LookupGeneric (name, loc);
+
+ return null;
+ }
+
+ public override string[] ValidAttributeTargets {
+ get { return attribute_targets; }
+ }
+
+ protected override bool VerifyClsCompliance ()
+ {
+ if (!base.VerifyClsCompliance ()) {
+ return false;
+ }
+
+ if (type_params != null) {
+ foreach (TypeParameter tp in type_params) {
+ if (tp.Constraints == null)
+ continue;
+
+ tp.Constraints.VerifyClsCompliance ();
+ }
+ }
+
+ IDictionary cache = TypeManager.AllClsTopLevelTypes;
+ string lcase = Name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
+ if (!cache.Contains (lcase)) {
+ cache.Add (lcase, this);
+ return true;
+ }
+
+ object val = cache [lcase];
+ if (val == null) {
+ Type t = AttributeTester.GetImportedIgnoreCaseClsType (lcase);
+ if (t == null)
+ return true;
+ Report.SymbolRelatedToPreviousError (t);
+ }
+ else {
+ Report.SymbolRelatedToPreviousError ((DeclSpace)val);
+ }
+#if GMCS_SOURCE
+ Report.Warning (3005, 1, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
+#else
+ Report.Error (3005, Location, "Identifier `{0}' differing only in case is not CLS-compliant", GetSignatureForError ());
+#endif
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// This is a readonly list of MemberInfo's.
+ /// </summary>
+ public class MemberList : IList {
+ public readonly IList List;
+ int count;
+
+ /// <summary>
+ /// Create a new MemberList from the given IList.
+ /// </summary>
+ public MemberList (IList list)
+ {
+ if (list != null)
+ this.List = list;
+ else
+ this.List = new ArrayList ();
+ count = List.Count;
+ }
+
+ /// <summary>
+ /// Concatenate the ILists `first' and `second' to a new MemberList.
+ /// </summary>
+ public MemberList (IList first, IList second)
+ {
+ ArrayList list = new ArrayList ();
+ list.AddRange (first);
+ list.AddRange (second);
+ count = list.Count;
+ List = list;
+ }
+
+ public static readonly MemberList Empty = new MemberList (new ArrayList ());
+
+ /// <summary>
+ /// Cast the MemberList into a MemberInfo[] array.
+ /// </summary>
+ /// <remarks>
+ /// This is an expensive operation, only use it if it's really necessary.
+ /// </remarks>
+ public static explicit operator MemberInfo [] (MemberList list)
+ {
+ Timer.StartTimer (TimerType.MiscTimer);
+ MemberInfo [] result = new MemberInfo [list.Count];
+ list.CopyTo (result, 0);
+ Timer.StopTimer (TimerType.MiscTimer);
+ return result;
+ }
+
+ // ICollection
+
+ public int Count {
+ get {
+ return count;
+ }
+ }
+
+ public bool IsSynchronized {
+ get {
+ return List.IsSynchronized;
+ }
+ }
+
+ public object SyncRoot {
+ get {
+ return List.SyncRoot;
+ }
+ }
+
+ public void CopyTo (Array array, int index)
+ {
+ List.CopyTo (array, index);
+ }
+
+ // IEnumerable
+
+ public IEnumerator GetEnumerator ()
+ {
+ return List.GetEnumerator ();
+ }
+
+ // IList
+
+ public bool IsFixedSize {
+ get {
+ return true;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return true;
+ }
+ }
+
+ object IList.this [int index] {
+ get {
+ return List [index];
+ }
+
+ set {
+ throw new NotSupportedException ();
+ }
+ }
+
+ // FIXME: try to find out whether we can avoid the cast in this indexer.
+ public MemberInfo this [int index] {
+ get {
+ return (MemberInfo) List [index];
+ }
+ }
+
+ public int Add (object value)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public void Clear ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public bool Contains (object value)
+ {
+ return List.Contains (value);
+ }
+
+ public int IndexOf (object value)
+ {
+ return List.IndexOf (value);
+ }
+
+ public void Insert (int index, object value)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public void Remove (object value)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public void RemoveAt (int index)
+ {
+ throw new NotSupportedException ();
+ }
+ }
+
+ /// <summary>
+ /// This interface is used to get all members of a class when creating the
+ /// member cache. It must be implemented by all DeclSpace derivatives which
+ /// want to support the member cache and by TypeHandle to get caching of
+ /// non-dynamic types.
+ /// </summary>
+ public interface IMemberContainer {
+ /// <summary>
+ /// The name of the IMemberContainer. This is only used for
+ /// debugging purposes.
+ /// </summary>
+ string Name {
+ get;
+ }
+
+ /// <summary>
+ /// The type of this IMemberContainer.
+ /// </summary>
+ Type Type {
+ get;
+ }
+
+ /// <summary>
+ /// Returns the IMemberContainer of the base class or null if this
+ /// is an interface or TypeManger.object_type.
+ /// This is used when creating the member cache for a class to get all
+ /// members from the base class.
+ /// </summary>
+ MemberCache BaseCache {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is an interface.
+ /// </summary>
+ bool IsInterface {
+ get;
+ }
+
+ /// <summary>
+ /// Returns all members of this class with the corresponding MemberTypes
+ /// and BindingFlags.
+ /// </summary>
+ /// <remarks>
+ /// When implementing this method, make sure not to return any inherited
+ /// members and check the MemberTypes and BindingFlags properly.
+ /// Unfortunately, System.Reflection is lame and doesn't provide a way to
+ /// get the BindingFlags (static/non-static,public/non-public) in the
+ /// MemberInfo class, but the cache needs this information. That's why
+ /// this method is called multiple times with different BindingFlags.
+ /// </remarks>
+ MemberList GetMembers (MemberTypes mt, BindingFlags bf);
+
+ /// <summary>
+ /// Return the container's member cache.
+ /// </summary>
+ MemberCache MemberCache {
+ get;
+ }
+ }
+
+ /// <summary>
+ /// The MemberCache is used by dynamic and non-dynamic types to speed up
+ /// member lookups. It has a member name based hash table; it maps each member
+ /// name to a list of CacheEntry objects. Each CacheEntry contains a MemberInfo
+ /// and the BindingFlags that were initially used to get it. The cache contains
+ /// all members of the current class and all inherited members. If this cache is
+ /// for an interface types, it also contains all inherited members.
+ ///
+ /// There are two ways to get a MemberCache:
+ /// * if this is a dynamic type, lookup the corresponding DeclSpace and then
+ /// use the DeclSpace.MemberCache property.
+ /// * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
+ /// TypeHandle instance for the type and then use TypeHandle.MemberCache.
+ /// </summary>
+ public class MemberCache {
+ public readonly IMemberContainer Container;
+ protected Hashtable member_hash;
+ protected Hashtable method_hash;
+
+ /// <summary>
+ /// Create a new MemberCache for the given IMemberContainer `container'.
+ /// </summary>
+ public MemberCache (IMemberContainer container)
+ {
+ this.Container = container;
+
+ Timer.IncrementCounter (CounterType.MemberCache);
+ Timer.StartTimer (TimerType.CacheInit);
+
+ // If we have a base class (we have a base class unless we're
+ // TypeManager.object_type), we deep-copy its MemberCache here.
+ if (Container.BaseCache != null)
+ member_hash = SetupCache (Container.BaseCache);
+ else
+ member_hash = new Hashtable ();
+
+ // If this is neither a dynamic type nor an interface, create a special
+ // method cache with all declared and inherited methods.
+ Type type = container.Type;
+ if (!(type is TypeBuilder) && !type.IsInterface &&
+ // !(type.IsGenericType && (type.GetGenericTypeDefinition () is TypeBuilder)) &&
+ !TypeManager.IsGenericType (type) &&
+ (Container.BaseCache == null || Container.BaseCache.method_hash != null)) {
+ method_hash = new Hashtable ();
+ AddMethods (type);
+ }
+
+ // Add all members from the current class.
+ AddMembers (Container);
+
+ Timer.StopTimer (TimerType.CacheInit);
+ }
+
+ public MemberCache (Type[] ifaces)
+ {
+ //
+ // The members of this cache all belong to other caches.
+ // So, 'Container' will not be used.
+ //
+ this.Container = null;
+
+ member_hash = new Hashtable ();
+ if (ifaces == null)
+ return;
+
+ foreach (Type itype in ifaces)
+ AddCacheContents (TypeManager.LookupMemberCache (itype));
+ }
+
+ /// <summary>
+ /// Bootstrap this member cache by doing a deep-copy of our base.
+ /// </summary>
+ static Hashtable SetupCache (MemberCache base_class)
+ {
+ Hashtable hash = new Hashtable ();
+
+ if (base_class == null)
+ return hash;
+
+ IDictionaryEnumerator it = base_class.member_hash.GetEnumerator ();
+ while (it.MoveNext ()) {
+ hash [it.Key] = ((ArrayList) it.Value).Clone ();
+ }
+
+ return hash;
+ }
+
+ /// <summary>
+ /// Add the contents of `cache' to the member_hash.
+ /// </summary>
+ void AddCacheContents (MemberCache cache)
+ {
+ IDictionaryEnumerator it = cache.member_hash.GetEnumerator ();
+ while (it.MoveNext ()) {
+ ArrayList list = (ArrayList) member_hash [it.Key];
+ if (list == null)
+ member_hash [it.Key] = list = new ArrayList ();
+
+ ArrayList entries = (ArrayList) it.Value;
+ for (int i = entries.Count-1; i >= 0; i--) {
+ CacheEntry entry = (CacheEntry) entries [i];
+
+ if (entry.Container != cache.Container)
+ break;
+ list.Add (entry);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Add all members from class `container' to the cache.
+ /// </summary>
+ void AddMembers (IMemberContainer container)
+ {
+ // We need to call AddMembers() with a single member type at a time
+ // to get the member type part of CacheEntry.EntryType right.
+ if (!container.IsInterface) {
+ AddMembers (MemberTypes.Constructor, container);
+ AddMembers (MemberTypes.Field, container);
+ }
+ AddMembers (MemberTypes.Method, container);
+ AddMembers (MemberTypes.Property, container);
+ AddMembers (MemberTypes.Event, container);
+ // Nested types are returned by both Static and Instance searches.
+ AddMembers (MemberTypes.NestedType,
+ BindingFlags.Static | BindingFlags.Public, container);
+ AddMembers (MemberTypes.NestedType,
+ BindingFlags.Static | BindingFlags.NonPublic, container);
+ }
+
+ void AddMembers (MemberTypes mt, IMemberContainer container)
+ {
+ AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
+ AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
+ AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
+ AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
+ }
+
+ /// <summary>
+ /// Add all members from class `container' with the requested MemberTypes and
+ /// BindingFlags to the cache. This method is called multiple times with different
+ /// MemberTypes and BindingFlags.
+ /// </summary>
+ void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
+ {
+ MemberList members = container.GetMembers (mt, bf);
+
+ foreach (MemberInfo member in members) {
+ string name = member.Name;
+
+ int pos = name.IndexOf ('<');
+ if (pos > 0)
+ name = name.Substring (0, pos);
+
+ // We use a name-based hash table of ArrayList's.
+ ArrayList list = (ArrayList) member_hash [name];
+ if (list == null) {
+ list = new ArrayList ();
+ member_hash.Add (name, list);
+ }
+
+ // When this method is called for the current class, the list will
+ // already contain all inherited members from our base classes.
+ // We cannot add new members in front of the list since this'd be an
+ // expensive operation, that's why the list is sorted in reverse order
+ // (ie. members from the current class are coming last).
+ list.Add (new CacheEntry (container, member, mt, bf));
+ }
+ }
+
+ /// <summary>
+ /// Add all declared and inherited methods from class `type' to the method cache.
+ /// </summary>
+ void AddMethods (Type type)
+ {
+ AddMethods (BindingFlags.Static | BindingFlags.Public |
+ BindingFlags.FlattenHierarchy, type);
+ AddMethods (BindingFlags.Static | BindingFlags.NonPublic |
+ BindingFlags.FlattenHierarchy, type);
+ AddMethods (BindingFlags.Instance | BindingFlags.Public, type);
+ AddMethods (BindingFlags.Instance | BindingFlags.NonPublic, type);
+ }
+
+ static ArrayList overrides = new ArrayList ();
+
+ void AddMethods (BindingFlags bf, Type type)
+ {
+ MethodBase [] members = type.GetMethods (bf);
+
+ Array.Reverse (members);
+
+ foreach (MethodBase member in members) {
+ string name = member.Name;
+
+ // We use a name-based hash table of ArrayList's.
+ ArrayList list = (ArrayList) method_hash [name];
+ if (list == null) {
+ list = new ArrayList ();
+ method_hash.Add (name, list);
+ }
+
+ MethodInfo curr = (MethodInfo) member;
+ while (curr.IsVirtual && (curr.Attributes & MethodAttributes.NewSlot) == 0) {
+ MethodInfo base_method = curr.GetBaseDefinition ();
+
+ if (base_method == curr)
+ // Not every virtual function needs to have a NewSlot flag.
+ break;
+
+ overrides.Add (curr);
+ list.Add (new CacheEntry (null, base_method, MemberTypes.Method, bf));
+ curr = base_method;
+ }
+
+ if (overrides.Count > 0) {
+ for (int i = 0; i < overrides.Count; ++i)
+ TypeManager.RegisterOverride ((MethodBase) overrides [i], curr);
+ overrides.Clear ();
+ }
+
+ // Unfortunately, the elements returned by Type.GetMethods() aren't
+ // sorted so we need to do this check for every member.
+ BindingFlags new_bf = bf;
+ if (member.DeclaringType == type)
+ new_bf |= BindingFlags.DeclaredOnly;
+
+ list.Add (new CacheEntry (Container, member, MemberTypes.Method, new_bf));
+ }
+ }
+
+ /// <summary>
+ /// Compute and return a appropriate `EntryType' magic number for the given
+ /// MemberTypes and BindingFlags.
+ /// </summary>
+ protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
+ {
+ EntryType type = EntryType.None;
+
+ if ((mt & MemberTypes.Constructor) != 0)
+ type |= EntryType.Constructor;
+ if ((mt & MemberTypes.Event) != 0)
+ type |= EntryType.Event;
+ if ((mt & MemberTypes.Field) != 0)
+ type |= EntryType.Field;
+ if ((mt & MemberTypes.Method) != 0)
+ type |= EntryType.Method;
+ if ((mt & MemberTypes.Property) != 0)
+ type |= EntryType.Property;
+ // Nested types are returned by static and instance searches.
+ if ((mt & MemberTypes.NestedType) != 0)
+ type |= EntryType.NestedType | EntryType.Static | EntryType.Instance;
+
+ if ((bf & BindingFlags.Instance) != 0)
+ type |= EntryType.Instance;
+ if ((bf & BindingFlags.Static) != 0)
+ type |= EntryType.Static;
+ if ((bf & BindingFlags.Public) != 0)
+ type |= EntryType.Public;
+ if ((bf & BindingFlags.NonPublic) != 0)
+ type |= EntryType.NonPublic;
+ if ((bf & BindingFlags.DeclaredOnly) != 0)
+ type |= EntryType.Declared;
+
+ return type;
+ }
+
+ /// <summary>
+ /// The `MemberTypes' enumeration type is a [Flags] type which means that it may
+ /// denote multiple member types. Returns true if the given flags value denotes a
+ /// single member types.
+ /// </summary>
+ public static bool IsSingleMemberType (MemberTypes mt)
+ {
+ switch (mt) {
+ case MemberTypes.Constructor:
+ case MemberTypes.Event:
+ case MemberTypes.Field:
+ case MemberTypes.Method:
+ case MemberTypes.Property:
+ case MemberTypes.NestedType:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// We encode the MemberTypes and BindingFlags of each members in a "magic"
+ /// number to speed up the searching process.
+ /// </summary>
+ [Flags]
+ protected enum EntryType {
+ None = 0x000,
+
+ Instance = 0x001,
+ Static = 0x002,
+ MaskStatic = Instance|Static,
+
+ Public = 0x004,
+ NonPublic = 0x008,
+ MaskProtection = Public|NonPublic,
+
+ Declared = 0x010,
+
+ Constructor = 0x020,
+ Event = 0x040,
+ Field = 0x080,
+ Method = 0x100,
+ Property = 0x200,
+ NestedType = 0x400,
+
+ MaskType = Constructor|Event|Field|Method|Property|NestedType
+ }
+
+ protected class CacheEntry {
+ public readonly IMemberContainer Container;
+ public readonly EntryType EntryType;
+ public readonly MemberInfo Member;
+
+ public CacheEntry (IMemberContainer container, MemberInfo member,
+ MemberTypes mt, BindingFlags bf)
+ {
+ this.Container = container;
+ this.Member = member;
+ this.EntryType = GetEntryType (mt, bf);
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("CacheEntry ({0}:{1}:{2})", Container.Name,
+ EntryType, Member);
+ }
+ }
+
+ /// <summary>
+ /// This is called each time we're walking up one level in the class hierarchy
+ /// and checks whether we can abort the search since we've already found what
+ /// we were looking for.
+ /// </summary>
+ protected bool DoneSearching (ArrayList list)
+ {
+ //
+ // We've found exactly one member in the current class and it's not
+ // a method or constructor.
+ //
+ if (list.Count == 1 && !(list [0] is MethodBase))
+ return true;
+
+ //
+ // Multiple properties: we query those just to find out the indexer
+ // name
+ //
+ if ((list.Count > 0) && (list [0] is PropertyInfo))
+ return true;
+
+ return false;
+ }
+
+ /// <summary>
+ /// Looks up members with name `name'. If you provide an optional
+ /// filter function, it'll only be called with members matching the
+ /// requested member name.
+ ///
+ /// This method will try to use the cache to do the lookup if possible.
+ ///
+ /// Unlike other FindMembers implementations, this method will always
+ /// check all inherited members - even when called on an interface type.
+ ///
+ /// If you know that you're only looking for methods, you should use
+ /// MemberTypes.Method alone since this speeds up the lookup a bit.
+ /// When doing a method-only search, it'll try to use a special method
+ /// cache (unless it's a dynamic type or an interface) and the returned
+ /// MemberInfo's will have the correct ReflectedType for inherited methods.
+ /// The lookup process will automatically restart itself in method-only
+ /// search mode if it discovers that it's about to return methods.
+ /// </summary>
+ ArrayList global = new ArrayList ();
+ bool using_global = false;
+
+ static MemberInfo [] emptyMemberInfo = new MemberInfo [0];
+
+ public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, string name,
+ MemberFilter filter, object criteria)
+ {
+ if (using_global)
+ throw new Exception ();
+
+ bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
+ bool method_search = mt == MemberTypes.Method;
+ // If we have a method cache and we aren't already doing a method-only search,
+ // then we restart a method search if the first match is a method.
+ bool do_method_search = !method_search && (method_hash != null);
+
+ ArrayList applicable;
+
+ // If this is a method-only search, we try to use the method cache if
+ // possible; a lookup in the method cache will return a MemberInfo with
+ // the correct ReflectedType for inherited methods.
+
+ if (method_search && (method_hash != null))
+ applicable = (ArrayList) method_hash [name];
+ else
+ applicable = (ArrayList) member_hash [name];
+
+ if (applicable == null)
+ return emptyMemberInfo;
+
+ //
+ // 32 slots gives 53 rss/54 size
+ // 2/4 slots gives 55 rss
+ //
+ // Strange: from 25,000 calls, only 1,800
+ // are above 2. Why does this impact it?
+ //
+ global.Clear ();
+ using_global = true;
+
+ Timer.StartTimer (TimerType.CachedLookup);
+
+ EntryType type = GetEntryType (mt, bf);
+
+ IMemberContainer current = Container;
+
+ bool do_interface_search = current.IsInterface;
+
+ // `applicable' is a list of all members with the given member name `name'
+ // in the current class and all its base classes. The list is sorted in
+ // reverse order due to the way how the cache is initialy created (to speed
+ // things up, we're doing a deep-copy of our base).
+
+ for (int i = applicable.Count-1; i >= 0; i--) {
+ CacheEntry entry = (CacheEntry) applicable [i];
+
+ // This happens each time we're walking one level up in the class
+ // hierarchy. If we're doing a DeclaredOnly search, we must abort
+ // the first time this happens (this may already happen in the first
+ // iteration of this loop if there are no members with the name we're
+ // looking for in the current class).
+ if (entry.Container != current) {
+ if (declared_only)
+ break;
+
+ if (!do_interface_search && DoneSearching (global))
+ break;
+
+ current = entry.Container;
+ }
+
+ // Is the member of the correct type ?
+ if ((entry.EntryType & type & EntryType.MaskType) == 0)
+ continue;
+
+ // Is the member static/non-static ?
+ if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
+ continue;
+
+ // Apply the filter to it.
+ if (filter (entry.Member, criteria)) {
+ if ((entry.EntryType & EntryType.MaskType) != EntryType.Method) {
+ do_method_search = false;
+ }
+
+ // Because interfaces support multiple inheritance we have to be sure that
+ // base member is from same interface, so only top level member will be returned
+ if (do_interface_search && global.Count > 0) {
+ bool member_already_exists = false;
+
+ foreach (MemberInfo mi in global) {
+ if (mi is MethodBase)
+ continue;
+
+ if (IsInterfaceBaseInterface (TypeManager.GetInterfaces (mi.DeclaringType), entry.Member.DeclaringType)) {
+ member_already_exists = true;
+ break;
+ }
+ }
+ if (member_already_exists)
+ continue;
+ }
+
+ global.Add (entry.Member);
+ }
+ }
+
+ Timer.StopTimer (TimerType.CachedLookup);
+
+ // If we have a method cache and we aren't already doing a method-only
+ // search, we restart in method-only search mode if the first match is
+ // a method. This ensures that we return a MemberInfo with the correct
+ // ReflectedType for inherited methods.
+ if (do_method_search && (global.Count > 0)){
+ using_global = false;
+
+ return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
+ }
+
+ using_global = false;
+ MemberInfo [] copy = new MemberInfo [global.Count];
+ global.CopyTo (copy);
+ return copy;
+ }
+
+ /// <summary>
+ /// Returns true if iterface exists in any base interfaces (ifaces)
+ /// </summary>
+ static bool IsInterfaceBaseInterface (Type[] ifaces, Type ifaceToFind)
+ {
+ foreach (Type iface in ifaces) {
+ if (iface == ifaceToFind)
+ return true;
+
+ Type[] base_ifaces = TypeManager.GetInterfaces (iface);
+ if (base_ifaces.Length > 0 && IsInterfaceBaseInterface (base_ifaces, ifaceToFind))
+ return true;
+ }
+ return false;
+ }
+
+ // find the nested type @name in @this.
+ public Type FindNestedType (string name)
+ {
+ ArrayList applicable = (ArrayList) member_hash [name];
+ if (applicable == null)
+ return null;
+
+ for (int i = applicable.Count-1; i >= 0; i--) {
+ CacheEntry entry = (CacheEntry) applicable [i];
+ if ((entry.EntryType & EntryType.NestedType & EntryType.MaskType) != 0)
+ return (Type) entry.Member;
+ }
+
+ return null;
+ }
+
+ //
+ // This finds the method or property for us to override. invocationType is the type where
+ // the override is going to be declared, name is the name of the method/property, and
+ // paramTypes is the parameters, if any to the method or property
+ //
+ // Because the MemberCache holds members from this class and all the base classes,
+ // we can avoid tons of reflection stuff.
+ //
+ public MemberInfo FindMemberToOverride (Type invocationType, string name, Type [] paramTypes, GenericMethod genericMethod, bool is_property)
+ {
+ ArrayList applicable;
+ if (method_hash != null && !is_property)
+ applicable = (ArrayList) method_hash [name];
+ else
+ applicable = (ArrayList) member_hash [name];
+
+ if (applicable == null)
+ return null;
+ //
+ // Walk the chain of methods, starting from the top.
+ //
+ for (int i = applicable.Count - 1; i >= 0; i--) {
+ CacheEntry entry = (CacheEntry) applicable [i];
+
+ if ((entry.EntryType & (is_property ? (EntryType.Property | EntryType.Field) : EntryType.Method)) == 0)
+ continue;
+
+ PropertyInfo pi = null;
+ MethodInfo mi = null;
+ FieldInfo fi = null;
+ Type [] cmpAttrs = null;
+
+ if (is_property) {
+ if ((entry.EntryType & EntryType.Field) != 0) {
+ fi = (FieldInfo)entry.Member;
+
+ // TODO: For this case we ignore member type
+ //fb = TypeManager.GetField (fi);
+ //cmpAttrs = new Type[] { fb.MemberType };
+ } else {
+ pi = (PropertyInfo) entry.Member;
+ cmpAttrs = TypeManager.GetArgumentTypes (pi);
+ }
+ } else {
+ mi = (MethodInfo) entry.Member;
+ cmpAttrs = TypeManager.GetParameterData (mi).Types;
+ }
+
+ if (fi != null) {
+ // TODO: Almost duplicate !
+ // Check visibility
+ switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
+ case FieldAttributes.PrivateScope:
+ continue;
+ case FieldAttributes.Private:
+ //
+ // A private method is Ok if we are a nested subtype.
+ // The spec actually is not very clear about this, see bug 52458.
+ //
+ if (!invocationType.Equals (entry.Container.Type) &&
+ !TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
+ continue;
+ break;
+ case FieldAttributes.FamANDAssem:
+ case FieldAttributes.Assembly:
+ //
+ // Check for assembly methods
+ //
+ if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
+ continue;
+ break;
+ }
+ return entry.Member;
+ }
+
+ //
+ // Check the arguments
+ //
+ if (cmpAttrs.Length != paramTypes.Length)
+ continue;
+
+ int j;
+ for (j = 0; j < cmpAttrs.Length; ++j)
+ if (!TypeManager.IsEqual (paramTypes [j], cmpAttrs [j]))
+ break;
+ if (j < cmpAttrs.Length)
+ continue;
+
+ //
+ // check generic arguments for methods
+ //
+ if (mi != null) {
+ Type [] cmpGenArgs = TypeManager.GetGenericArguments (mi);
+ if (genericMethod == null && cmpGenArgs.Length != 0)
+ continue;
+ if (genericMethod != null && cmpGenArgs.Length != genericMethod.TypeParameters.Length)
+ continue;
+ }
+
+ //
+ // get one of the methods because this has the visibility info.
+ //
+ if (is_property) {
+ mi = pi.GetGetMethod (true);
+ if (mi == null)
+ mi = pi.GetSetMethod (true);
+ }
+
+ //
+ // Check visibility
+ //
+ switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
+ case MethodAttributes.PrivateScope:
+ continue;
+ case MethodAttributes.Private:
+ //
+ // A private method is Ok if we are a nested subtype.
+ // The spec actually is not very clear about this, see bug 52458.
+ //
+ if (!invocationType.Equals (entry.Container.Type) &&
+ !TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
+ continue;
+ break;
+ case MethodAttributes.FamANDAssem:
+ case MethodAttributes.Assembly:
+ //
+ // Check for assembly methods
+ //
+ if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
+ continue;
+ break;
+ }
+ return entry.Member;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// The method is looking for conflict with inherited symbols (errors CS0108, CS0109).
+ /// We handle two cases. The first is for types without parameters (events, field, properties).
+ /// The second are methods, indexers and this is why ignore_complex_types is here.
+ /// The latest param is temporary hack. See DoDefineMembers method for more info.
+ /// </summary>
+ public MemberInfo FindMemberWithSameName (string name, bool ignore_complex_types, MemberInfo ignore_member)
+ {
+ ArrayList applicable = null;
+
+ if (method_hash != null)
+ applicable = (ArrayList) method_hash [name];
+
+ if (applicable != null) {
+ for (int i = applicable.Count - 1; i >= 0; i--) {
+ CacheEntry entry = (CacheEntry) applicable [i];
+ if ((entry.EntryType & EntryType.Public) != 0)
+ return entry.Member;
+ }
+ }
+
+ if (member_hash == null)
+ return null;
+ applicable = (ArrayList) member_hash [name];
+
+ if (applicable != null) {
+ for (int i = applicable.Count - 1; i >= 0; i--) {
+ CacheEntry entry = (CacheEntry) applicable [i];
+ if ((entry.EntryType & EntryType.Public) != 0 & entry.Member != ignore_member) {
+ if (ignore_complex_types) {
+ if ((entry.EntryType & EntryType.Method) != 0)
+ continue;
+
+ // Does exist easier way how to detect indexer ?
+ if ((entry.EntryType & EntryType.Property) != 0) {
+ Type[] arg_types = TypeManager.GetArgumentTypes ((PropertyInfo)entry.Member);
+ if (arg_types.Length > 0)
+ continue;
+ }
+ }
+ return entry.Member;
+ }
+ }
+ }
+ return null;
+ }
+
+ Hashtable locase_table;
+
+ /// <summary>
+ /// Builds low-case table for CLS Compliance test
+ /// </summary>
+ public Hashtable GetPublicMembers ()
+ {
+ if (locase_table != null)
+ return locase_table;
+
+ locase_table = new Hashtable ();
+ foreach (DictionaryEntry entry in member_hash) {
+ ArrayList members = (ArrayList)entry.Value;
+ for (int ii = 0; ii < members.Count; ++ii) {
+ CacheEntry member_entry = (CacheEntry) members [ii];
+
+ if ((member_entry.EntryType & EntryType.Public) == 0)
+ continue;
+
+ // TODO: Does anyone know easier way how to detect that member is internal ?
+ switch (member_entry.EntryType & EntryType.MaskType) {
+ case EntryType.Constructor:
+ continue;
+
+ case EntryType.Field:
+ if ((((FieldInfo)member_entry.Member).Attributes & (FieldAttributes.Assembly | FieldAttributes.Public)) == FieldAttributes.Assembly)
+ continue;
+ break;
+
+ case EntryType.Method:
+ if ((((MethodInfo)member_entry.Member).Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
+ continue;
+ break;
+
+ case EntryType.Property:
+ PropertyInfo pi = (PropertyInfo)member_entry.Member;
+ if (pi.GetSetMethod () == null && pi.GetGetMethod () == null)
+ continue;
+ break;
+
+ case EntryType.Event:
+ EventInfo ei = (EventInfo)member_entry.Member;
+ MethodInfo mi = ei.GetAddMethod ();
+ if ((mi.Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
+ continue;
+ break;
+ }
+ string lcase = ((string)entry.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture);
+ locase_table [lcase] = member_entry.Member;
+ break;
+ }
+ }
+ return locase_table;
+ }
+
+ public Hashtable Members {
+ get {
+ return member_hash;
+ }
+ }
+
+ /// <summary>
+ /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
+ /// </summary>
+ ///
+ // TODO: refactor as method is always 'this'
+ public static void VerifyClsParameterConflict (ArrayList al, MethodCore method, MemberInfo this_builder)
+ {
+ EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public;
+
+ for (int i = 0; i < al.Count; ++i) {
+ MemberCache.CacheEntry entry = (MemberCache.CacheEntry) al [i];
+
+ // skip itself
+ if (entry.Member == this_builder)
+ continue;
+
+ if ((entry.EntryType & tested_type) != tested_type)
+ continue;
+
+ MethodBase method_to_compare = (MethodBase)entry.Member;
+ AttributeTester.Result result = AttributeTester.AreOverloadedMethodParamsClsCompliant (
+ method.ParameterTypes, TypeManager.GetParameterData (method_to_compare).Types);
+
+ if (result == AttributeTester.Result.Ok)
+ continue;
+
+ IMethodData md = TypeManager.GetMethod (method_to_compare);
+
+ // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy.
+ // However it is exactly what csc does.
+ if (md != null && !md.IsClsComplianceRequired ())
+ continue;
+
+ Report.SymbolRelatedToPreviousError (entry.Member);
+ switch (result) {
+ case AttributeTester.Result.RefOutArrayError:
+ Report.Error (3006, method.Location, "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant", method.GetSignatureForError ());
+ continue;
+ case AttributeTester.Result.ArrayArrayError:
+ Report.Error (3007, method.Location, "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant", method.GetSignatureForError ());
+ continue;
+ }
+
+ throw new NotImplementedException (result.ToString ());
+ }
+ }
+ }
+}
--- /dev/null
+//
+// delegate.cs: Delegate Handler
+//
+// Authors:
+// Ravi Pratap (ravi@ximian.com)
+// Miguel de Icaza (miguel@ximian.com)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+//
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Holds Delegates
+ /// </summary>
+ public class Delegate : DeclSpace {
+ public Expression ReturnType;
+ public Parameters Parameters;
+
+ public ConstructorBuilder ConstructorBuilder;
+ public MethodBuilder InvokeBuilder;
+ public MethodBuilder BeginInvokeBuilder;
+ public MethodBuilder EndInvokeBuilder;
+
+ Type ret_type;
+
+ static string[] attribute_targets = new string [] { "type", "return" };
+
+ Expression instance_expr;
+ MethodBase delegate_method;
+ ReturnParameter return_attributes;
+
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.UNSAFE |
+ Modifiers.PRIVATE;
+
+ public Delegate (NamespaceEntry ns, DeclSpace parent, Expression type,
+ int mod_flags, MemberName name, Parameters param_list,
+ Attributes attrs)
+ : base (ns, parent, name, attrs)
+
+ {
+ this.ReturnType = type;
+ ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
+ IsTopLevel ? Modifiers.INTERNAL :
+ Modifiers.PRIVATE, name.Location);
+ Parameters = param_list;
+ }
+
+ public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
+ {
+ if (a.Target == AttributeTargets.ReturnValue) {
+ if (return_attributes == null)
+ return_attributes = new ReturnParameter (InvokeBuilder, Location);
+
+ return_attributes.ApplyAttributeBuilder (a, cb);
+ return;
+ }
+
+ base.ApplyAttributeBuilder (a, cb);
+ }
+
+ public override TypeBuilder DefineType ()
+ {
+ if (TypeBuilder != null)
+ return TypeBuilder;
+
+ if (TypeManager.multicast_delegate_type == null && !RootContext.StdLib) {
+ Namespace system = RootNamespace.Global.GetNamespace ("System", true);
+ TypeExpr expr = system.Lookup (this, "MulticastDelegate", Location) as TypeExpr;
+ TypeManager.multicast_delegate_type = expr.Type;
+ }
+
+ if (TypeManager.multicast_delegate_type == null)
+ Report.Error (-100, Location, "Internal error: delegate used before " +
+ "System.MulticastDelegate is resolved. This can only " +
+ "happen during corlib compilation, when using a delegate " +
+ "in any of the `core' classes. See bug #72015 for details.");
+
+ if (IsTopLevel) {
+ if (TypeManager.NamespaceClash (Name, Location))
+ return null;
+
+ ModuleBuilder builder = CodeGen.Module.Builder;
+
+ TypeBuilder = builder.DefineType (
+ Name, TypeAttr, TypeManager.multicast_delegate_type);
+ } else {
+ TypeBuilder builder = Parent.TypeBuilder;
+
+ string name = Name.Substring (1 + Name.LastIndexOf ('.'));
+ TypeBuilder = builder.DefineNestedType (
+ name, TypeAttr, TypeManager.multicast_delegate_type);
+ }
+
+ TypeManager.AddUserType (this);
+
+#if GMCS_SOURCE
+ if (IsGeneric) {
+ string[] param_names = new string [TypeParameters.Length];
+ for (int i = 0; i < TypeParameters.Length; i++)
+ param_names [i] = TypeParameters [i].Name;
+
+ GenericTypeParameterBuilder[] gen_params;
+ gen_params = TypeBuilder.DefineGenericParameters (param_names);
+
+ int offset = CountTypeParameters - CurrentTypeParameters.Length;
+ for (int i = offset; i < gen_params.Length; i++)
+ CurrentTypeParameters [i - offset].Define (gen_params [i]);
+
+ foreach (TypeParameter type_param in CurrentTypeParameters) {
+ if (!type_param.Resolve (this))
+ return null;
+ }
+
+ Expression current = new SimpleName (
+ MemberName.Basename, TypeParameters, Location);
+ current = current.ResolveAsTypeTerminal (this, false);
+ if (current == null)
+ return null;
+
+ CurrentType = current.Type;
+ }
+#endif
+
+ return TypeBuilder;
+ }
+
+ public override bool Define ()
+ {
+#if GMCS_SOURCE
+ if (IsGeneric) {
+ foreach (TypeParameter type_param in TypeParameters) {
+ if (!type_param.Resolve (this))
+ return false;
+ }
+
+ foreach (TypeParameter type_param in TypeParameters) {
+ if (!type_param.DefineType (this))
+ return false;
+ }
+
+ foreach (TypeParameter type_param in TypeParameters) {
+ if (!type_param.CheckDependencies ())
+ return false;
+ }
+ }
+#endif
+
+ // FIXME: POSSIBLY make this static, as it is always constant
+ //
+ Type [] const_arg_types = new Type [2];
+ const_arg_types [0] = TypeManager.object_type;
+ const_arg_types [1] = TypeManager.intptr_type;
+
+ const MethodAttributes ctor_mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |
+ MethodAttributes.HideBySig | MethodAttributes.Public;
+
+ ConstructorBuilder = TypeBuilder.DefineConstructor (ctor_mattr,
+ CallingConventions.Standard,
+ const_arg_types);
+
+ ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");
+ ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ Parameter [] fixed_pars = new Parameter [2];
+ fixed_pars [0] = new Parameter (TypeManager.object_type, "object",
+ Parameter.Modifier.NONE, null, Location);
+ fixed_pars [1] = new Parameter (TypeManager.intptr_type, "method",
+ Parameter.Modifier.NONE, null, Location);
+ Parameters const_parameters = new Parameters (fixed_pars);
+ const_parameters.Resolve (null);
+
+ TypeManager.RegisterMethod (ConstructorBuilder, const_parameters);
+
+
+ ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ //
+ // Here the various methods like Invoke, BeginInvoke etc are defined
+ //
+ // First, call the `out of band' special method for
+ // defining recursively any types we need:
+
+ if (!Parameters.Resolve (this))
+ return false;
+
+ //
+ // Invoke method
+ //
+
+ // Check accessibility
+ foreach (Type partype in Parameters.Types){
+ if (!Parent.AsAccessible (partype, ModFlags)) {
+ Report.Error (59, Location,
+ "Inconsistent accessibility: parameter type `" +
+ TypeManager.CSharpName (partype) + "' is less " +
+ "accessible than delegate `" + Name + "'");
+ return false;
+ }
+ }
+
+ ReturnType = ReturnType.ResolveAsTypeTerminal (this, false);
+ if (ReturnType == null)
+ return false;
+
+ ret_type = ReturnType.Type;
+
+ if (!Parent.AsAccessible (ret_type, ModFlags)) {
+ Report.Error (58, Location,
+ "Inconsistent accessibility: return type `" +
+ TypeManager.CSharpName (ret_type) + "' is less " +
+ "accessible than delegate `" + Name + "'");
+ return false;
+ }
+
+ if (RootContext.StdLib && (ret_type == TypeManager.arg_iterator_type || ret_type == TypeManager.typed_reference_type)) {
+ Method.Error1599 (Location, ret_type);
+ return false;
+ }
+
+ //
+ // We don't have to check any others because they are all
+ // guaranteed to be accessible - they are standard types.
+ //
+
+ CallingConventions cc = Parameters.CallingConvention;
+
+ const MethodAttributes mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot;
+
+ InvokeBuilder = TypeBuilder.DefineMethod ("Invoke",
+ mattr,
+ cc,
+ ret_type,
+ Parameters.Types);
+
+ InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ TypeManager.RegisterMethod (InvokeBuilder, Parameters);
+
+ //
+ // BeginInvoke
+ //
+
+ Parameters async_parameters = Parameters.MergeGenerated (Parameters,
+ new Parameter (TypeManager.asynccallback_type, "callback", Parameter.Modifier.NONE, null, Location),
+ new Parameter (TypeManager.object_type, "object", Parameter.Modifier.NONE, null, Location));
+
+ BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",
+ mattr, cc, TypeManager.iasyncresult_type, async_parameters.Types);
+
+ BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+ async_parameters.ApplyAttributes (BeginInvokeBuilder);
+ TypeManager.RegisterMethod (BeginInvokeBuilder, async_parameters);
+
+ //
+ // EndInvoke is a bit more interesting, all the parameters labeled as
+ // out or ref have to be duplicated here.
+ //
+
+ //
+ // Define parameters, and count out/ref parameters
+ //
+ Parameters end_parameters;
+ int out_params = 0;
+
+ foreach (Parameter p in Parameters.FixedParameters) {
+ if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0)
+ ++out_params;
+ }
+
+ if (out_params > 0) {
+ Type [] end_param_types = new Type [out_params];
+ Parameter [] end_params = new Parameter [out_params ];
+
+ int param = 0;
+ for (int i = 0; i < Parameters.FixedParameters.Length; ++i) {
+ Parameter p = Parameters.FixedParameters [i];
+ if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0)
+ continue;
+
+ end_param_types [param] = p.ExternalType();
+ end_params [param] = p;
+ ++param;
+ }
+ end_parameters = new Parameters (end_params, end_param_types);
+ }
+ else {
+ end_parameters = Parameters.EmptyReadOnlyParameters;
+ }
+
+ end_parameters = Parameters.MergeGenerated (end_parameters,
+ new Parameter (TypeManager.iasyncresult_type, "result", Parameter.Modifier.NONE, null, Location));
+
+ //
+ // Create method, define parameters, register parameters with type system
+ //
+ EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_parameters.Types);
+ EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ end_parameters.ApplyAttributes (EndInvokeBuilder);
+ TypeManager.RegisterMethod (EndInvokeBuilder, end_parameters);
+
+ return true;
+ }
+
+ public override void Emit ()
+ {
+ Parameters.ApplyAttributes (InvokeBuilder);
+
+ if (OptAttributes != null) {
+ OptAttributes.Emit ();
+ }
+
+ base.Emit ();
+ }
+
+ protected override TypeAttributes TypeAttr {
+ get {
+ return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
+ TypeAttributes.Class | TypeAttributes.Sealed |
+ base.TypeAttr;
+ }
+ }
+
+ public override string[] ValidAttributeTargets {
+ get {
+ return attribute_targets;
+ }
+ }
+
+ //TODO: duplicate
+ protected override bool VerifyClsCompliance ()
+ {
+ if (!base.VerifyClsCompliance ()) {
+ return false;
+ }
+
+ Parameters.VerifyClsCompliance ();
+
+ if (!AttributeTester.IsClsCompliant (ReturnType.Type)) {
+ Report.Error (3002, Location, "Return type of `{0}' is not CLS-compliant", GetSignatureForError ());
+ }
+ return true;
+ }
+
+ //
+ // Returns the MethodBase for "Invoke" from a delegate type, this is used
+ // to extract the signature of a delegate.
+ //
+ public static MethodGroupExpr GetInvokeMethod (Type container_type, Type delegate_type, Location loc)
+ {
+ Expression ml = Expression.MemberLookup (container_type, null, delegate_type,
+ "Invoke", loc);
+
+ MethodGroupExpr mg = ml as MethodGroupExpr;
+ if (mg == null) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return null;
+ }
+
+ return mg;
+ }
+
+ /// <summary>
+ /// Verifies whether the method in question is compatible with the delegate
+ /// Returns the method itself if okay and null if not.
+ /// </summary>
+ public static MethodBase VerifyMethod (Type container_type, Type delegate_type,
+ MethodGroupExpr old_mg, MethodBase mb,
+ Location loc)
+ {
+ MethodGroupExpr mg = GetInvokeMethod (container_type, delegate_type, loc);
+ if (mg == null)
+ return null;
+
+ if (old_mg.HasTypeArguments)
+ mg.HasTypeArguments = true;
+
+ MethodBase invoke_mb = mg.Methods [0];
+ ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
+
+#if GMCS_SOURCE
+ if (!mg.HasTypeArguments &&
+ !TypeManager.InferTypeArguments (invoke_pd, ref mb))
+ return null;
+#endif
+
+ ParameterData pd = TypeManager.GetParameterData (mb);
+
+ if (invoke_pd.Count != pd.Count)
+ return null;
+
+ for (int i = pd.Count; i > 0; ) {
+ i--;
+
+ Type invoke_pd_type = invoke_pd.ParameterType (i);
+ Type pd_type = pd.ParameterType (i);
+ Parameter.Modifier invoke_pd_type_mod = invoke_pd.ParameterModifier (i);
+ Parameter.Modifier pd_type_mod = pd.ParameterModifier (i);
+
+ invoke_pd_type_mod &= ~Parameter.Modifier.PARAMS;
+ pd_type_mod &= ~Parameter.Modifier.PARAMS;
+
+ if (invoke_pd_type_mod != pd_type_mod)
+ return null;
+
+ if (invoke_pd_type == pd_type)
+ continue;
+
+ if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (invoke_pd_type), pd_type))
+ return null;
+
+ if (RootContext.Version == LanguageVersion.ISO_1)
+ return null;
+ }
+
+ Type invoke_mb_retval = ((MethodInfo) invoke_mb).ReturnType;
+ Type mb_retval = ((MethodInfo) mb).ReturnType;
+ if (invoke_mb_retval == mb_retval)
+ return mb;
+
+ if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (mb_retval), invoke_mb_retval))
+ return null;
+
+ if (RootContext.Version == LanguageVersion.ISO_1)
+ return null;
+
+ return mb;
+ }
+
+ // <summary>
+ // Verifies whether the invocation arguments are compatible with the
+ // delegate's target method
+ // </summary>
+ public static bool VerifyApplicability (EmitContext ec, Type delegate_type,
+ ArrayList args, Location loc)
+ {
+ int arg_count;
+
+ if (args == null)
+ arg_count = 0;
+ else
+ arg_count = args.Count;
+
+ Expression ml = Expression.MemberLookup (
+ ec.ContainerType, delegate_type, "Invoke", loc);
+
+ MethodGroupExpr me = ml as MethodGroupExpr;
+ if (me == null) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!" + delegate_type);
+ return false;
+ }
+
+ MethodBase mb = me.Methods [0];
+ ParameterData pd = TypeManager.GetParameterData (mb);
+
+ int pd_count = pd.Count;
+
+ bool params_method = pd.HasParams;
+ bool is_params_applicable = false;
+ bool is_applicable = Invocation.IsApplicable (ec, me, args, arg_count, ref mb);
+
+ if (!is_applicable && params_method &&
+ Invocation.IsParamsMethodApplicable (ec, me, args, arg_count, ref mb))
+ is_applicable = is_params_applicable = true;
+
+ if (!is_applicable && !params_method && arg_count != pd_count) {
+ Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
+ TypeManager.CSharpName (delegate_type), arg_count.ToString ());
+ return false;
+ }
+
+ return Invocation.VerifyArgumentsCompat (
+ ec, args, arg_count, mb,
+ is_params_applicable || (!is_applicable && params_method),
+ delegate_type, false, loc);
+ }
+
+ /// <summary>
+ /// Verifies whether the delegate in question is compatible with this one in
+ /// order to determine if instantiation from the same is possible.
+ /// </summary>
+ public static bool VerifyDelegate (EmitContext ec, Type delegate_type, Location loc)
+ {
+ Expression ml = Expression.MemberLookup (
+ ec.ContainerType, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return false;
+ }
+
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];
+ ParameterData pd = TypeManager.GetParameterData (mb);
+
+ Expression probe_ml = Expression.MemberLookup (
+ ec.ContainerType, delegate_type, "Invoke", loc);
+
+ if (!(probe_ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return false;
+ }
+
+ MethodBase probe_mb = ((MethodGroupExpr) probe_ml).Methods [0];
+ ParameterData probe_pd = TypeManager.GetParameterData (probe_mb);
+
+ if (((MethodInfo) mb).ReturnType != ((MethodInfo) probe_mb).ReturnType)
+ return false;
+
+ if (pd.Count != probe_pd.Count)
+ return false;
+
+ for (int i = pd.Count; i > 0; ) {
+ i--;
+
+ if (pd.ParameterType (i) != probe_pd.ParameterType (i) ||
+ pd.ParameterModifier (i) != probe_pd.ParameterModifier (i))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static string FullDelegateDesc (Type del_type, MethodBase mb, ParameterData pd)
+ {
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
+ sb.Append (" ");
+ sb.Append (TypeManager.CSharpName (del_type));
+ sb.Append (pd.GetSignatureForError ());
+ return sb.ToString ();
+ }
+
+ // Hack around System.Reflection as found everywhere else
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList (2);
+
+ if ((mt & MemberTypes.Constructor) != 0) {
+ if (ConstructorBuilder != null && filter (ConstructorBuilder, criteria))
+ members.Add (ConstructorBuilder);
+ }
+
+ if ((mt & MemberTypes.Method) != 0) {
+ if (InvokeBuilder != null)
+ if (filter (InvokeBuilder, criteria))
+ members.Add (InvokeBuilder);
+
+ if (BeginInvokeBuilder != null)
+ if (filter (BeginInvokeBuilder, criteria))
+ members.Add (BeginInvokeBuilder);
+
+ if (EndInvokeBuilder != null)
+ if (filter (EndInvokeBuilder, criteria))
+ members.Add (EndInvokeBuilder);
+ }
+
+ return new MemberList (members);
+ }
+
+ public override MemberCache MemberCache {
+ get {
+ return null;
+ }
+ }
+
+ public Expression InstanceExpression {
+ get {
+ return instance_expr;
+ }
+ set {
+ instance_expr = value;
+ }
+ }
+
+ public MethodBase TargetMethod {
+ get {
+ return delegate_method;
+ }
+ set {
+ delegate_method = value;
+ }
+ }
+
+ public Type TargetReturnType {
+ get {
+ return ret_type;
+ }
+ }
+
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Delegate;
+ }
+ }
+
+ //
+ // Represents header string for documentation comment.
+ //
+ public override string DocCommentHeader {
+ get { return "T:"; }
+ }
+
+ }
+
+ //
+ // Base class for `NewDelegate' and `ImplicitDelegateCreation'
+ //
+ public abstract class DelegateCreation : Expression {
+ protected MethodBase constructor_method;
+ protected MethodBase delegate_method;
+ protected MethodGroupExpr method_group;
+ protected Expression delegate_instance_expression;
+
+ protected DelegateCreation () {}
+
+ public static void Error_NoMatchingMethodForDelegate (EmitContext ec, MethodGroupExpr mg, Type type, Location loc)
+ {
+ string method_desc;
+ MethodBase found_method = mg.Methods [0];
+
+ if (mg.Methods.Length > 1)
+ method_desc = found_method.Name;
+ else
+ method_desc = Invocation.FullMethodDesc (found_method);
+
+ Expression invoke_method = Expression.MemberLookup (
+ ec.ContainerType, type, "Invoke", MemberTypes.Method,
+ Expression.AllBindingFlags, loc);
+ MethodInfo method = ((MethodGroupExpr) invoke_method).Methods [0] as MethodInfo;
+
+ ParameterData param = TypeManager.GetParameterData (method);
+ string delegate_desc = Delegate.FullDelegateDesc (type, method, param);
+
+#if GMCS_SOURCE
+ if (!mg.HasTypeArguments &&
+ !TypeManager.InferTypeArguments (param, ref found_method)) {
+ Report.Error (411, loc, "The type arguments for " +
+ "method `{0}' cannot be infered from " +
+ "the usage. Try specifying the type " +
+ "arguments explicitly.", method_desc);
+ return;
+ }
+#endif
+ Report.SymbolRelatedToPreviousError (found_method);
+
+ if (RootContext.Version == LanguageVersion.ISO_1) {
+ Report.Error (410, loc, "The method `{0}' parameters and return type must be same as delegate `{1}' parameters and return type",
+ method_desc, delegate_desc);
+ return;
+ }
+
+ Type delegateType = method.ReturnType;
+ Type methodType = ((MethodInfo) found_method).ReturnType;
+ if (delegateType != methodType &&
+ !Convert.ImplicitReferenceConversionExists (new EmptyExpression (methodType), delegateType)) {
+ Report.Error (407, loc, "`{0}' has the wrong return type to match the delegate `{1}'", method_desc, delegate_desc);
+ } else {
+ Report.Error (123, loc, "The method `{0}' parameters do not match delegate `{1}' parameters",
+ TypeManager.CSharpSignature (found_method), delegate_desc);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (delegate_instance_expression == null || delegate_method.IsStatic)
+ ec.ig.Emit (OpCodes.Ldnull);
+ else
+ delegate_instance_expression.Emit (ec);
+
+ if (delegate_method.IsVirtual && !method_group.IsBase) {
+ ec.ig.Emit (OpCodes.Dup);
+ ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);
+ } else
+ ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);
+ }
+
+ protected bool ResolveConstructorMethod (EmitContext ec)
+ {
+ Expression ml = Expression.MemberLookupFinal(ec,
+ null, type, ".ctor", MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");
+ return false;
+ }
+
+ constructor_method = ((MethodGroupExpr) ml).Methods [0];
+ return true;
+ }
+
+ public static MethodBase ImplicitStandardConversionExists (MethodGroupExpr mg, Type targetType)
+ {
+ foreach (MethodInfo mi in mg.Methods){
+ MethodBase mb = Delegate.VerifyMethod (mg.DeclaringType, targetType, mg, mi, Location.Null);
+ if (mb != null)
+ return mb;
+ }
+ return null;
+ }
+
+ protected Expression ResolveMethodGroupExpr (EmitContext ec, MethodGroupExpr mg)
+ {
+ delegate_method = ImplicitStandardConversionExists (mg, type);
+
+ if (delegate_method == null) {
+ Error_NoMatchingMethodForDelegate (ec, mg, type, loc);
+ return null;
+ }
+
+ //
+ // Check safe/unsafe of the delegate
+ //
+ if (!ec.InUnsafe){
+ ParameterData param = TypeManager.GetParameterData (delegate_method);
+ int count = param.Count;
+
+ for (int i = 0; i < count; i++){
+ if (param.ParameterType (i).IsPointer){
+ Expression.UnsafeError (loc);
+ return null;
+ }
+ }
+ }
+
+ //TODO: implement caching when performance will be low
+ IMethodData md = TypeManager.GetMethod (delegate_method);
+ if (md == null) {
+ if (System.Attribute.GetCustomAttribute (delegate_method, TypeManager.conditional_attribute_type) != null) {
+ Report.SymbolRelatedToPreviousError (delegate_method);
+ Report.Error (1618, loc, "Cannot create delegate with `{0}' because it has a Conditional attribute", TypeManager.CSharpSignature (delegate_method));
+ return null;
+ }
+ } else {
+ md.SetMemberIsUsed ();
+ if (md.OptAttributes != null && md.OptAttributes.Search (TypeManager.conditional_attribute_type) != null) {
+ Report.SymbolRelatedToPreviousError (delegate_method);
+ Report.Error (1618, loc, "Cannot create delegate with `{0}' because it has a Conditional attribute", TypeManager.CSharpSignature (delegate_method));
+ return null;
+ }
+ }
+
+ if (mg.InstanceExpression != null)
+ delegate_instance_expression = mg.InstanceExpression.Resolve (ec);
+ else if (ec.IsStatic) {
+ if (!delegate_method.IsStatic) {
+ Report.Error (120, loc, "`{0}': An object reference is required for the nonstatic field, method or property",
+ TypeManager.CSharpSignature (delegate_method));
+ return null;
+ }
+ delegate_instance_expression = null;
+ } else
+ delegate_instance_expression = ec.GetThis (loc);
+
+ if (delegate_instance_expression != null && delegate_instance_expression.Type.IsValueType)
+ delegate_instance_expression = new BoxedCast (
+ delegate_instance_expression, TypeManager.object_type);
+
+ method_group = mg;
+ eclass = ExprClass.Value;
+ return this;
+ }
+ }
+
+ //
+ // Created from the conversion code
+ //
+ public class ImplicitDelegateCreation : DelegateCreation {
+
+ ImplicitDelegateCreation (Type t, Location l)
+ {
+ type = t;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ static public Expression Create (EmitContext ec, MethodGroupExpr mge,
+ Type target_type, Location loc)
+ {
+ ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, loc);
+ if (!d.ResolveConstructorMethod (ec))
+ return null;
+
+ return d.ResolveMethodGroupExpr (ec, mge);
+ }
+ }
+
+ //
+ // A delegate-creation-expression, invoked from the `New' class
+ //
+ public class NewDelegate : DelegateCreation {
+ public ArrayList Arguments;
+
+ //
+ // This constructor is invoked from the `New' expression
+ //
+ public NewDelegate (Type type, ArrayList Arguments, Location loc)
+ {
+ this.type = type;
+ this.Arguments = Arguments;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (Arguments == null || Arguments.Count != 1) {
+ Report.Error (149, loc,
+ "Method name expected");
+ return null;
+ }
+
+ if (!ResolveConstructorMethod (ec))
+ return null;
+
+ Argument a = (Argument) Arguments [0];
+
+ if (!a.ResolveMethodGroup (ec))
+ return null;
+
+ Expression e = a.Expr;
+
+ if (e is AnonymousMethodExpression && RootContext.Version != LanguageVersion.ISO_1)
+ return ((AnonymousMethodExpression) e).Compatible (ec, type);
+
+ MethodGroupExpr mg = e as MethodGroupExpr;
+ if (mg != null)
+ return ResolveMethodGroupExpr (ec, mg);
+
+ if (!TypeManager.IsDelegateType (e.Type)) {
+ Report.Error (149, loc, "Method name expected");
+ return null;
+ }
+
+ method_group = Expression.MemberLookup (
+ ec.ContainerType, type, "Invoke", MemberTypes.Method,
+ Expression.AllBindingFlags, loc) as MethodGroupExpr;
+
+ if (method_group == null) {
+ Report.Error (-200, loc, "Internal error ! Could not find Invoke method!");
+ return null;
+ }
+
+ // This is what MS' compiler reports. We could always choose
+ // to be more verbose and actually give delegate-level specifics
+ if (!Delegate.VerifyDelegate (ec, type, loc)) {
+ Report.Error (29, loc, "Cannot implicitly convert type '" + e.Type + "' " +
+ "to type '" + type + "'");
+ return null;
+ }
+
+ delegate_instance_expression = e;
+ delegate_method = method_group.Methods [0];
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+ }
+
+ public class DelegateInvocation : ExpressionStatement {
+
+ public Expression InstanceExpr;
+ public ArrayList Arguments;
+
+ MethodBase method;
+
+ public DelegateInvocation (Expression instance_expr, ArrayList args, Location loc)
+ {
+ this.InstanceExpr = instance_expr;
+ this.Arguments = args;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (InstanceExpr is EventExpr) {
+
+ EventInfo ei = ((EventExpr) InstanceExpr).EventInfo;
+
+ Expression ml = MemberLookup (
+ ec.ContainerType, ec.ContainerType, ei.Name,
+ MemberTypes.Event, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
+
+ if (ml == null) {
+ //
+ // If this is the case, then the Event does not belong
+ // to this Type and so, according to the spec
+ // cannot be accessed directly
+ //
+ // Note that target will not appear as an EventExpr
+ // in the case it is being referenced within the same type container;
+ // it will appear as a FieldExpr in that case.
+ //
+
+ Assign.error70 (ei, loc);
+ return null;
+ }
+ }
+
+
+ Type del_type = InstanceExpr.Type;
+ if (del_type == null)
+ return null;
+
+ if (Arguments != null){
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ if (!Delegate.VerifyApplicability (ec, del_type, Arguments, loc))
+ return null;
+
+ Expression lookup = Expression.MemberLookup (ec.ContainerType, del_type, "Invoke", loc);
+ if (!(lookup is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return null;
+ }
+
+ method = ((MethodGroupExpr) lookup).Methods [0];
+ type = ((MethodInfo) method).ReturnType;
+ eclass = ExprClass.Value;
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // Invocation on delegates call the virtual Invoke member
+ // so we are always `instance' calls
+ //
+ Invocation.EmitCall (ec, false, false, InstanceExpr, method, Arguments, loc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ //
+ // Pop the return value if there is one
+ //
+ if (method is MethodInfo){
+ Type ret = ((MethodInfo)method).ReturnType;
+ if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ }
+}
--- /dev/null
+//
+// driver.cs: The compiler command line driver.
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+// (C) 2004, 2005 Novell, Inc
+//
+
+namespace Mono.CSharp
+{
+ using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Collections;
+ using System.Collections.Specialized;
+ using System.IO;
+ using System.Text;
+ using System.Globalization;
+ using System.Diagnostics;
+
+ public enum Target {
+ Library, Exe, Module, WinExe
+ };
+
+ /// <summary>
+ /// The compiler driver.
+ /// </summary>
+ public class Driver
+ {
+
+ //
+ // Assemblies references to be linked. Initialized with
+ // mscorlib.dll here.
+ static ArrayList references;
+
+ //
+ // If any of these fail, we ignore the problem. This is so
+ // that we can list all the assemblies in Windows and not fail
+ // if they are missing on Linux.
+ //
+ static ArrayList soft_references;
+
+ //
+ // External aliases for assemblies.
+ //
+ static Hashtable external_aliases;
+
+ //
+ // Modules to be linked
+ //
+ static ArrayList modules;
+
+ // Lookup paths
+ static ArrayList link_paths;
+
+ // Whether we want to only run the tokenizer
+ static bool tokenize = false;
+
+ static string first_source;
+
+ static bool want_debugging_support = false;
+
+ static bool parse_only = false;
+ static bool timestamps = false;
+ static bool pause = false;
+ static bool show_counters = false;
+
+ //
+ // Whether to load the initial config file (what CSC.RSP has by default)
+ //
+ static bool load_default_config = true;
+
+ //
+ // A list of resource files
+ //
+ static Resources embedded_resources;
+ static string win32ResourceFile;
+ static string win32IconFile;
+
+ //
+ // An array of the defines from the command line
+ //
+ static ArrayList defines;
+
+ //
+ // Output file
+ //
+ static string output_file = null;
+
+ //
+ // Last time we took the time
+ //
+ static DateTime last_time, first_time;
+
+ //
+ // Encoding.
+ //
+ static Encoding encoding;
+
+ static public void Reset ()
+ {
+ want_debugging_support = false;
+ parse_only = false;
+ timestamps = false;
+ pause = false;
+ show_counters = false;
+ load_default_config = true;
+ embedded_resources = null;
+ win32ResourceFile = win32IconFile = null;
+ defines = null;
+ output_file = null;
+ encoding = null;
+ first_source = null;
+ }
+
+ public static void ShowTime (string msg)
+ {
+ if (!timestamps)
+ return;
+
+ DateTime now = DateTime.Now;
+ TimeSpan span = now - last_time;
+ last_time = now;
+
+ Console.WriteLine (
+ "[{0:00}:{1:000}] {2}",
+ (int) span.TotalSeconds, span.Milliseconds, msg);
+ }
+
+ public static void ShowTotalTime (string msg)
+ {
+ if (!timestamps)
+ return;
+
+ DateTime now = DateTime.Now;
+ TimeSpan span = now - first_time;
+ last_time = now;
+
+ Console.WriteLine (
+ "[{0:00}:{1:000}] {2}",
+ (int) span.TotalSeconds, span.Milliseconds, msg);
+ }
+
+ static void tokenize_file (SourceFile file)
+ {
+ Stream input;
+
+ try {
+ input = File.OpenRead (file.Name);
+ } catch {
+ Report.Error (2001, "Source file `" + file.Name + "' could not be found");
+ return;
+ }
+
+ using (input){
+ SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
+ Tokenizer lexer = new Tokenizer (reader, file, defines);
+ int token, tokens = 0, errors = 0;
+
+ while ((token = lexer.token ()) != Token.EOF){
+ tokens++;
+ if (token == Token.ERROR)
+ errors++;
+ }
+ Console.WriteLine ("Tokenized: " + tokens + " found " + errors + " errors");
+ }
+
+ return;
+ }
+
+ // MonoTODO("Change error code for aborted compilation to something reasonable")]
+ static void parse (SourceFile file)
+ {
+ CSharpParser parser;
+ Stream input;
+
+ try {
+ input = File.OpenRead (file.Name);
+ } catch {
+ Report.Error (2001, "Source file `" + file.Name + "' could not be found");
+ return;
+ }
+
+ SeekableStreamReader reader = new SeekableStreamReader (input, encoding);
+
+ // Check 'MZ' header
+ if (reader.Read () == 77 && reader.Read () == 90) {
+ Report.Error (2015, "Source file `{0}' is a binary file and not a text file", file.Name);
+ input.Close ();
+ return;
+ }
+
+ reader.Position = 0;
+ parser = new CSharpParser (reader, file, defines);
+ parser.ErrorOutput = Report.Stderr;
+ try {
+ parser.parse ();
+ } catch (Exception ex) {
+ Report.Error(666, "Compilation aborted: " + ex);
+ } finally {
+ input.Close ();
+ }
+ }
+
+ static void OtherFlags ()
+ {
+ Console.WriteLine (
+ "Other flags in the compiler\n" +
+ " --fatal Makes errors fatal\n" +
+ " --parse Only parses the source file\n" +
+ " --stacktrace Shows stack trace at error location\n" +
+ " --timestamp Displays time stamps of various compiler events\n" +
+ " --expect-error X Expect that error X will be encountered\n" +
+ " -2 Enables experimental C# features\n" +
+ " -v Verbose parsing (for debugging the parser)\n" +
+ " --mcs-debug X Sets MCS debugging level to X\n");
+ }
+
+ static void Usage ()
+ {
+ Console.WriteLine (
+ "Mono C# compiler, (C) 2001 - 2005 Novell, Inc.\n" +
+ "mcs [options] source-files\n" +
+ " --about About the Mono C# compiler\n" +
+ " -addmodule:MODULE Adds the module to the generated assembly\n" +
+ " -checked[+|-] Set default context to checked\n" +
+ " -codepage:ID Sets code page to the one in ID (number, utf8, reset)\n" +
+ " -clscheck[+|-] Disables CLS Compliance verifications" + Environment.NewLine +
+ " -define:S1[;S2] Defines one or more symbols (short: /d:)\n" +
+ " -debug[+|-], -g Generate debugging information\n" +
+ " -delaysign[+|-] Only insert the public key into the assembly (no signing)\n" +
+ " -doc:FILE XML Documentation file to generate\n" +
+ " -keycontainer:NAME The key pair container used to strongname the assembly\n" +
+ " -keyfile:FILE The strongname key file used to strongname the assembly\n" +
+ " -langversion:TEXT Specifies language version modes: ISO-1 or Default\n" +
+ " -lib:PATH1,PATH2 Adds the paths to the assembly link path\n" +
+ " -main:class Specified the class that contains the entry point\n" +
+ " -noconfig[+|-] Disables implicit references to assemblies\n" +
+ " -nostdlib[+|-] Does not load core libraries\n" +
+ " -nowarn:W1[,W2] Disables one or more warnings\n" +
+ " -optimize[+|-] Enables code optimalizations\n" +
+ " -out:FNAME Specifies output file\n" +
+ " -pkg:P1[,Pn] References packages P1..Pn\n" +
+ " -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" +
+ " -reference:ASS References the specified assembly (-r:ASS)\n" +
+ " -target:KIND Specifies the target (KIND is one of: exe, winexe,\n" +
+ " library, module), (short: /t:)\n" +
+ " -unsafe[+|-] Allows unsafe code\n" +
+ " -warnaserror[+|-] Treat warnings as errors\n" +
+ " -warn:LEVEL Sets warning level (the highest is 4, the default is 2)\n" +
+ " -help2 Show other help flags\n" +
+ "\n" +
+ "Resources:\n" +
+ " -linkresource:FILE[,ID] Links FILE as a resource\n" +
+ " -resource:FILE[,ID] Embed FILE as a resource\n" +
+ " -win32res:FILE Specifies Win32 resource file (.res)\n" +
+ " -win32icon:FILE Use this icon for the output\n" +
+ " @file Read response file for more options\n\n" +
+ "Options can be of the form -option or /option");
+ }
+
+ static void TargetUsage ()
+ {
+ Report.Error (2019, "Invalid target type for -target. Valid options are `exe', `winexe', `library' or `module'");
+ }
+
+ static void About ()
+ {
+ Console.WriteLine (
+ "The Mono C# compiler is (C) 2001-2005, Novell, Inc.\n\n" +
+ "The compiler source code is released under the terms of the GNU GPL\n\n" +
+
+ "For more information on Mono, visit the project Web site\n" +
+ " http://www.go-mono.com\n\n" +
+
+ "The compiler was written by Miguel de Icaza, Ravi Pratap, Martin Baulig, Marek Safar, Raja R Harinath");
+ Environment.Exit (0);
+ }
+
+ public static int counter1, counter2;
+
+ public static int Main (string[] args)
+ {
+#if GMCS_SOURCE
+ RootContext.Version = LanguageVersion.Default;
+#endif
+ Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
+
+ bool ok = MainDriver (args);
+
+ if (ok && Report.Errors == 0) {
+ if (Report.Warnings > 0) {
+ Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
+ }
+ if (show_counters){
+ Console.WriteLine ("Counter1: " + counter1);
+ Console.WriteLine ("Counter2: " + counter2);
+ }
+ if (pause)
+ Console.ReadLine ();
+ return 0;
+ } else {
+ Console.WriteLine("Compilation failed: {0} error(s), {1} warnings",
+ Report.Errors, Report.Warnings);
+ return 1;
+ }
+ }
+
+ static public void LoadAssembly (string assembly, bool soft)
+ {
+ LoadAssembly (assembly, null, soft);
+ }
+
+ static void Error6 (string name, string log)
+ {
+ if (log != null && log.Length > 0)
+ Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
+ Report.Error (6, "cannot find metadata file `{0}'", name);
+ }
+
+ static void Error9 (string type, string filename, string log)
+ {
+ if (log != null && log.Length > 0)
+ Report.ExtraInformation (Location.Null, "Log:\n" + log + "\n(log related to previous ");
+ Report.Error (9, "file `{0}' has invalid `{1}' metadata", filename, type);
+ }
+
+ static void BadAssembly (string filename, string log)
+ {
+ MethodInfo adder_method = AssemblyClass.AddModule_Method;
+
+ if (adder_method != null) {
+ AssemblyName an = new AssemblyName ();
+ an.Name = ".temp";
+ AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
+ try {
+ object m = null;
+ try {
+ m = adder_method.Invoke (ab, new object [] { filename });
+ } catch (TargetInvocationException ex) {
+ throw ex.InnerException;
+ }
+
+ if (m != null) {
+ Report.Error (1509, "referenced file `{0}' is not an assembly; try using the '-addmodule' option", filename);
+ return;
+ }
+ } catch (FileNotFoundException) {
+ // did the file get deleted during compilation? who cares? swallow the exception
+ } catch (BadImageFormatException) {
+ // swallow exception
+ } catch (FileLoadException) {
+ // swallow exception
+ }
+ }
+ Error9 ("assembly", filename, log);
+ }
+
+ static public void LoadAssembly (string assembly, string alias, bool soft)
+ {
+ Assembly a = null;
+ string total_log = "";
+
+ try {
+ try {
+ char[] path_chars = { '/', '\\' };
+
+ if (assembly.IndexOfAny (path_chars) != -1) {
+ a = Assembly.LoadFrom (assembly);
+ } else {
+ string ass = assembly;
+ if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
+ ass = assembly.Substring (0, assembly.Length - 4);
+ a = Assembly.Load (ass);
+ }
+ } catch (FileNotFoundException) {
+ bool err = !soft;
+ foreach (string dir in link_paths) {
+ string full_path = Path.Combine (dir, assembly);
+ if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
+ full_path += ".dll";
+
+ try {
+ a = Assembly.LoadFrom (full_path);
+ err = false;
+ break;
+ } catch (FileNotFoundException ff) {
+ total_log += ff.FusionLog;
+ }
+ }
+ if (err) {
+ Error6 (assembly, total_log);
+ return;
+ }
+ }
+
+ // Extern aliased refs require special handling
+ if (alias == null)
+ RootNamespace.Global.AddAssemblyReference (a);
+ else
+ RootNamespace.DefineRootNamespace (alias, a);
+
+ } catch (BadImageFormatException f) {
+ // .NET 2.0 throws this if we try to load a module without an assembly manifest ...
+ BadAssembly (f.FileName, f.FusionLog);
+ } catch (FileLoadException f) {
+ // ... while .NET 1.1 throws this
+ BadAssembly (f.FileName, f.FusionLog);
+ }
+ }
+
+ static public void LoadModule (string module)
+ {
+ Module m = null;
+ string total_log = "";
+
+ try {
+ try {
+ m = CodeGen.Assembly.AddModule (module);
+ } catch (FileNotFoundException) {
+ bool err = true;
+ foreach (string dir in link_paths) {
+ string full_path = Path.Combine (dir, module);
+ if (!module.EndsWith (".netmodule"))
+ full_path += ".netmodule";
+
+ try {
+ m = CodeGen.Assembly.AddModule (full_path);
+ err = false;
+ break;
+ } catch (FileNotFoundException ff) {
+ total_log += ff.FusionLog;
+ }
+ }
+ if (err) {
+ Error6 (module, total_log);
+ return;
+ }
+ }
+
+ RootNamespace.Global.AddModuleReference (m);
+
+ } catch (BadImageFormatException f) {
+ Error9 ("module", f.FileName, f.FusionLog);
+ } catch (FileLoadException f) {
+ Error9 ("module", f.FileName, f.FusionLog);
+ }
+ }
+
+ /// <summary>
+ /// Loads all assemblies referenced on the command line
+ /// </summary>
+ static public void LoadReferences ()
+ {
+ foreach (string r in references)
+ LoadAssembly (r, false);
+
+ foreach (string r in soft_references)
+ LoadAssembly (r, true);
+
+ foreach (DictionaryEntry entry in external_aliases)
+ LoadAssembly ((string) entry.Value, (string) entry.Key, false);
+
+ return;
+ }
+
+ static void SetupDefaultDefines ()
+ {
+ defines = new ArrayList ();
+ defines.Add ("__MonoCS__");
+ }
+
+ static string [] LoadArgs (string file)
+ {
+ StreamReader f;
+ ArrayList args = new ArrayList ();
+ string line;
+ try {
+ f = new StreamReader (file);
+ } catch {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder ();
+
+ while ((line = f.ReadLine ()) != null){
+ int t = line.Length;
+
+ for (int i = 0; i < t; i++){
+ char c = line [i];
+
+ if (c == '"' || c == '\''){
+ char end = c;
+
+ for (i++; i < t; i++){
+ c = line [i];
+
+ if (c == end)
+ break;
+ sb.Append (c);
+ }
+ } else if (c == ' '){
+ if (sb.Length > 0){
+ args.Add (sb.ToString ());
+ sb.Length = 0;
+ }
+ } else
+ sb.Append (c);
+ }
+ if (sb.Length > 0){
+ args.Add (sb.ToString ());
+ sb.Length = 0;
+ }
+ }
+
+ string [] ret_value = new string [args.Count];
+ args.CopyTo (ret_value, 0);
+
+ return ret_value;
+ }
+
+ //
+ // Returns the directory where the system assemblies are installed
+ //
+ static string GetSystemDir ()
+ {
+ return Path.GetDirectoryName (typeof (object).Assembly.Location);
+ }
+
+ //
+ // Given a path specification, splits the path from the file/pattern
+ //
+ static void SplitPathAndPattern (string spec, out string path, out string pattern)
+ {
+ int p = spec.LastIndexOf ('/');
+ if (p != -1){
+ //
+ // Windows does not like /file.cs, switch that to:
+ // "\", "file.cs"
+ //
+ if (p == 0){
+ path = "\\";
+ pattern = spec.Substring (1);
+ } else {
+ path = spec.Substring (0, p);
+ pattern = spec.Substring (p + 1);
+ }
+ return;
+ }
+
+ p = spec.LastIndexOf ('\\');
+ if (p != -1){
+ path = spec.Substring (0, p);
+ pattern = spec.Substring (p + 1);
+ return;
+ }
+
+ path = ".";
+ pattern = spec;
+ }
+
+ static void ProcessFile (string f)
+ {
+ if (first_source == null)
+ first_source = f;
+
+ Location.AddFile (f);
+ }
+
+ static void ProcessFiles ()
+ {
+ Location.Initialize ();
+
+ foreach (SourceFile file in Location.SourceFiles) {
+ if (tokenize) {
+ tokenize_file (file);
+ } else {
+ parse (file);
+ }
+ }
+ }
+
+ static void CompileFiles (string spec, bool recurse)
+ {
+ string path, pattern;
+
+ SplitPathAndPattern (spec, out path, out pattern);
+ if (pattern.IndexOf ('*') == -1){
+ ProcessFile (spec);
+ return;
+ }
+
+ string [] files = null;
+ try {
+ files = Directory.GetFiles (path, pattern);
+ } catch (System.IO.DirectoryNotFoundException) {
+ Report.Error (2001, "Source file `" + spec + "' could not be found");
+ return;
+ } catch (System.IO.IOException){
+ Report.Error (2001, "Source file `" + spec + "' could not be found");
+ return;
+ }
+ foreach (string f in files) {
+ ProcessFile (f);
+ }
+
+ if (!recurse)
+ return;
+
+ string [] dirs = null;
+
+ try {
+ dirs = Directory.GetDirectories (path);
+ } catch {
+ }
+
+ foreach (string d in dirs) {
+
+ // Don't include path in this string, as each
+ // directory entry already does
+ CompileFiles (d + "/" + pattern, true);
+ }
+ }
+
+ static void DefineDefaultConfig ()
+ {
+ //
+ // For now the "default config" is harcoded into the compiler
+ // we can move this outside later
+ //
+ string [] default_config = {
+ "System",
+ "System.Xml",
+#if false
+ //
+ // Is it worth pre-loading all this stuff?
+ //
+ "Accessibility",
+ "System.Configuration.Install",
+ "System.Data",
+ "System.Design",
+ "System.DirectoryServices",
+ "System.Drawing.Design",
+ "System.Drawing",
+ "System.EnterpriseServices",
+ "System.Management",
+ "System.Messaging",
+ "System.Runtime.Remoting",
+ "System.Runtime.Serialization.Formatters.Soap",
+ "System.Security",
+ "System.ServiceProcess",
+ "System.Web",
+ "System.Web.RegularExpressions",
+ "System.Web.Services",
+ "System.Windows.Forms"
+#endif
+ };
+
+ int p = 0;
+ foreach (string def in default_config)
+ soft_references.Insert (p++, def);
+ }
+
+ public static string OutputFile
+ {
+ set {
+ output_file = value;
+ }
+ get {
+ return Path.GetFileName (output_file);
+ }
+ }
+
+ static void SetWarningLevel (string s)
+ {
+ int level = -1;
+
+ try {
+ level = Int32.Parse (s);
+ } catch {
+ }
+ if (level < 0 || level > 4){
+ Report.Error (1900, "Warning level must be in the range 0-4");
+ return;
+ }
+ RootContext.WarningLevel = level;
+ }
+
+ static void SetupV2 ()
+ {
+ RootContext.Version = LanguageVersion.Default;
+ defines.Add ("__V2__");
+ }
+
+ static void Version ()
+ {
+ string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
+ Console.WriteLine ("Mono C# compiler version {0}", version);
+ Environment.Exit (0);
+ }
+
+ //
+ // Currently handles the Unix-like command line options, but will be
+ // deprecated in favor of the CSCParseOption, which will also handle the
+ // options that start with a dash in the future.
+ //
+ static bool UnixParseOption (string arg, ref string [] args, ref int i)
+ {
+ switch (arg){
+ case "-v":
+ CSharpParser.yacc_verbose_flag++;
+ return true;
+
+ case "--version":
+ Version ();
+ return true;
+
+ case "--parse":
+ parse_only = true;
+ return true;
+
+ case "--main": case "-m":
+ Report.Warning (-29, 1, "Compatibility: Use -main:CLASS instead of --main CLASS or -m CLASS");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ RootContext.MainClass = args [++i];
+ return true;
+
+ case "--unsafe":
+ Report.Warning (-29, 1, "Compatibility: Use -unsafe instead of --unsafe");
+ RootContext.Unsafe = true;
+ return true;
+
+ case "/?": case "/h": case "/help":
+ case "--help":
+ Usage ();
+ Environment.Exit (0);
+ return true;
+
+ case "--define":
+ Report.Warning (-29, 1, "Compatibility: Use -d:SYMBOL instead of --define SYMBOL");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ defines.Add (args [++i]);
+ return true;
+
+ case "--show-counters":
+ show_counters = true;
+ return true;
+
+ case "--expect-error": {
+ int code = 0;
+
+ try {
+ code = Int32.Parse (
+ args [++i], NumberStyles.AllowLeadingSign);
+ Report.ExpectedError = code;
+ } catch {
+ Report.Error (-14, "Invalid number specified");
+ }
+ return true;
+ }
+
+ case "--tokenize":
+ tokenize = true;
+ return true;
+
+ case "-o":
+ case "--output":
+ Report.Warning (-29, 1, "Compatibility: Use -out:FILE instead of --output FILE or -o FILE");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ OutputFile = args [++i];
+ return true;
+
+ case "--checked":
+ Report.Warning (-29, 1, "Compatibility: Use -checked instead of --checked");
+ RootContext.Checked = true;
+ return true;
+
+ case "--stacktrace":
+ Report.Stacktrace = true;
+ return true;
+
+ case "--linkresource":
+ case "--linkres":
+ Report.Warning (-29, 1, "Compatibility: Use -linkres:VALUE instead of --linkres VALUE");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Report.Error (5, "Missing argument to --linkres");
+ Environment.Exit (1);
+ }
+ if (embedded_resources == null)
+ embedded_resources = new Resources ();
+
+ embedded_resources.Add (false, args [++i], args [i]);
+ return true;
+
+ case "--resource":
+ case "--res":
+ Report.Warning (-29, 1, "Compatibility: Use -res:VALUE instead of --res VALUE");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Report.Error (5, "Missing argument to --resource");
+ Environment.Exit (1);
+ }
+ if (embedded_resources == null)
+ embedded_resources = new Resources ();
+
+ embedded_resources.Add (true, args [++i], args [i]);
+ return true;
+
+ case "--target":
+ Report.Warning (-29, 1, "Compatibility: Use -target:KIND instead of --target KIND");
+ if ((i + 1) >= args.Length){
+ Environment.Exit (1);
+ return true;
+ }
+
+ string type = args [++i];
+ switch (type){
+ case "library":
+ RootContext.Target = Target.Library;
+ RootContext.TargetExt = ".dll";
+ break;
+
+ case "exe":
+ RootContext.Target = Target.Exe;
+ break;
+
+ case "winexe":
+ RootContext.Target = Target.WinExe;
+ break;
+
+ case "module":
+ RootContext.Target = Target.Module;
+ RootContext.TargetExt = ".dll";
+ break;
+ default:
+ TargetUsage ();
+ break;
+ }
+ return true;
+
+ case "-r":
+ Report.Warning (-29, 1, "Compatibility: Use -r:LIBRARY instead of -r library");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+
+ string val = args [++i];
+ int idx = val.IndexOf ('=');
+ if (idx > -1) {
+ string alias = val.Substring (0, idx);
+ string assembly = val.Substring (idx + 1);
+ AddExternAlias (alias, assembly);
+ return true;
+ }
+
+ references.Add (val);
+ return true;
+
+ case "-L":
+ Report.Warning (-29, 1, "Compatibility: Use -lib:ARG instead of --L arg");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ link_paths.Add (args [++i]);
+ return true;
+
+ case "--nostdlib":
+ Report.Warning (-29, 1, "Compatibility: Use -nostdlib instead of --nostdlib");
+ RootContext.StdLib = false;
+ return true;
+
+ case "--fatal":
+ Report.Fatal = true;
+ return true;
+
+ case "--werror":
+ Report.Warning (-29, 1, "Compatibility: Use -warnaserror: option instead of --werror");
+ Report.WarningsAreErrors = true;
+ return true;
+
+ case "--nowarn":
+ Report.Warning (-29, 1, "Compatibility: Use -nowarn instead of --nowarn");
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ int warn = 0;
+
+ try {
+ warn = Int32.Parse (args [++i]);
+ } catch {
+ Usage ();
+ Environment.Exit (1);
+ }
+ Report.SetIgnoreWarning (warn);
+ return true;
+
+ case "--wlevel":
+ Report.Warning (-29, 1, "Compatibility: Use -warn:LEVEL instead of --wlevel LEVEL");
+ if ((i + 1) >= args.Length){
+ Report.Error (
+ 1900,
+ "--wlevel requires a value from 0 to 4");
+ Environment.Exit (1);
+ }
+
+ SetWarningLevel (args [++i]);
+ return true;
+
+ case "--mcs-debug":
+ if ((i + 1) >= args.Length){
+ Report.Error (5, "--mcs-debug requires an argument");
+ Environment.Exit (1);
+ }
+
+ try {
+ Report.DebugFlags = Int32.Parse (args [++i]);
+ } catch {
+ Report.Error (5, "Invalid argument to --mcs-debug");
+ Environment.Exit (1);
+ }
+ return true;
+
+ case "--about":
+ About ();
+ return true;
+
+ case "--recurse":
+ Report.Warning (-29, 1, "Compatibility: Use -recurse:PATTERN option instead --recurse PATTERN");
+ if ((i + 1) >= args.Length){
+ Report.Error (5, "--recurse requires an argument");
+ Environment.Exit (1);
+ }
+ CompileFiles (args [++i], true);
+ return true;
+
+ case "--timestamp":
+ timestamps = true;
+ last_time = first_time = DateTime.Now;
+ return true;
+
+ case "--pause":
+ pause = true;
+ return true;
+
+ case "--debug": case "-g":
+ Report.Warning (-29, 1, "Compatibility: Use -debug option instead of -g or --debug");
+ want_debugging_support = true;
+ return true;
+
+ case "--noconfig":
+ Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
+ load_default_config = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ //
+ // This parses the -arg and /arg options to the compiler, even if the strings
+ // in the following text use "/arg" on the strings.
+ //
+ static bool CSCParseOption (string option, ref string [] args, ref int i)
+ {
+ int idx = option.IndexOf (':');
+ string arg, value;
+
+ if (idx == -1){
+ arg = option;
+ value = "";
+ } else {
+ arg = option.Substring (0, idx);
+
+ value = option.Substring (idx + 1);
+ }
+
+ switch (arg){
+ case "/nologo":
+ return true;
+
+ case "/t":
+ case "/target":
+ switch (value){
+ case "exe":
+ RootContext.Target = Target.Exe;
+ break;
+
+ case "winexe":
+ RootContext.Target = Target.WinExe;
+ break;
+
+ case "library":
+ RootContext.Target = Target.Library;
+ RootContext.TargetExt = ".dll";
+ break;
+
+ case "module":
+ RootContext.Target = Target.Module;
+ RootContext.TargetExt = ".netmodule";
+ break;
+
+ default:
+ TargetUsage ();
+ break;
+ }
+ return true;
+
+ case "/out":
+ if (value.Length == 0){
+ Usage ();
+ Environment.Exit (1);
+ }
+ OutputFile = value;
+ return true;
+
+ case "/optimize":
+ case "/optimize+":
+ RootContext.Optimize = true;
+ return true;
+
+ case "/optimize-":
+ RootContext.Optimize = false;
+ return true;
+
+ case "/incremental":
+ case "/incremental+":
+ case "/incremental-":
+ // nothing.
+ return true;
+
+ case "/d":
+ case "/define": {
+ string [] defs;
+
+ if (value.Length == 0){
+ Usage ();
+ Environment.Exit (1);
+ }
+
+ defs = value.Split (new Char [] {';', ','});
+ foreach (string d in defs){
+ defines.Add (d);
+ }
+ return true;
+ }
+
+ case "/bugreport":
+ //
+ // We should collect data, runtime, etc and store in the file specified
+ //
+ Console.WriteLine ("To file bug reports, please visit: http://www.mono-project.com/Bugs");
+ return true;
+
+ case "/pkg": {
+ string packages;
+
+ if (value.Length == 0){
+ Usage ();
+ Environment.Exit (1);
+ }
+ packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
+
+ ProcessStartInfo pi = new ProcessStartInfo ();
+ pi.FileName = "pkg-config";
+ pi.RedirectStandardOutput = true;
+ pi.UseShellExecute = false;
+ pi.Arguments = "--libs " + packages;
+ Process p = null;
+ try {
+ p = Process.Start (pi);
+ } catch (Exception e) {
+ Report.Error (-27, "Couldn't run pkg-config: " + e.Message);
+ Environment.Exit (1);
+ }
+
+ if (p.StandardOutput == null){
+ Report.Warning (-27, 1, "Specified package did not return any information");
+ return true;
+ }
+ string pkgout = p.StandardOutput.ReadToEnd ();
+ p.WaitForExit ();
+ if (p.ExitCode != 0) {
+ Report.Error (-27, "Error running pkg-config. Check the above output.");
+ Environment.Exit (1);
+ }
+
+ if (pkgout != null){
+ string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
+ Split (new Char [] { ' ', '\t'});
+ args = AddArgs (args, xargs);
+ }
+
+ p.Close ();
+ return true;
+ }
+
+ case "/linkres":
+ case "/linkresource":
+ case "/res":
+ case "/resource":
+ if (embedded_resources == null)
+ embedded_resources = new Resources ();
+
+ bool embeded = arg.StartsWith ("/r");
+ string[] s = value.Split (',');
+ switch (s.Length) {
+ case 1:
+ if (s[0].Length == 0)
+ goto default;
+ embedded_resources.Add (embeded, s [0], Path.GetFileName (s[0]));
+ break;
+ case 2:
+ embedded_resources.Add (embeded, s [0], s [1]);
+ break;
+ case 3:
+ if (s [2] != "public" && s [2] != "private") {
+ Report.Error (1906, "Invalid resource visibility option `{0}'. Use either `public' or `private' instead", s [2]);
+ return true;
+ }
+ embedded_resources.Add (embeded, s [0], s [1], s [2] == "private");
+ break;
+ default:
+ Report.Error (-2005, "Wrong number of arguments for option `{0}'", option);
+ break;
+ }
+
+ return true;
+
+ case "/recurse":
+ if (value.Length == 0){
+ Report.Error (5, "-recurse requires an argument");
+ Environment.Exit (1);
+ }
+ CompileFiles (value, true);
+ return true;
+
+ case "/r":
+ case "/reference": {
+ if (value.Length == 0){
+ Report.Error (5, "-reference requires an argument");
+ Environment.Exit (1);
+ }
+
+ string [] refs = value.Split (new char [] { ';', ',' });
+ foreach (string r in refs){
+ string val = r;
+ int index = val.IndexOf ('=');
+ if (index > -1) {
+ string alias = r.Substring (0, index);
+ string assembly = r.Substring (index + 1);
+ AddExternAlias (alias, assembly);
+ return true;
+ }
+
+ references.Add (val);
+ }
+ return true;
+ }
+ case "/addmodule": {
+ if (value.Length == 0){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ string [] refs = value.Split (new char [] { ';', ',' });
+ foreach (string r in refs){
+ modules.Add (r);
+ }
+ return true;
+ }
+ case "/win32res": {
+ if (value.Length == 0) {
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ win32ResourceFile = value;
+ return true;
+ }
+ case "/win32icon": {
+ if (value.Length == 0) {
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ win32IconFile = value;
+ return true;
+ }
+ case "/doc": {
+ if (value.Length == 0){
+ Report.Error (2006, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ RootContext.Documentation = new Documentation (value);
+ return true;
+ }
+ case "/lib": {
+ string [] libdirs;
+
+ if (value.Length == 0){
+ Report.Error (5, "/lib requires an argument");
+ Environment.Exit (1);
+ }
+
+ libdirs = value.Split (new Char [] { ',' });
+ foreach (string dir in libdirs)
+ link_paths.Add (dir);
+ return true;
+ }
+
+ case "/debug-":
+ want_debugging_support = false;
+ return true;
+
+ case "/debug":
+ case "/debug+":
+ want_debugging_support = true;
+ return true;
+
+ case "/checked":
+ case "/checked+":
+ RootContext.Checked = true;
+ return true;
+
+ case "/checked-":
+ RootContext.Checked = false;
+ return true;
+
+ case "/clscheck":
+ case "/clscheck+":
+ return true;
+
+ case "/clscheck-":
+ RootContext.VerifyClsCompliance = false;
+ return true;
+
+ case "/unsafe":
+ case "/unsafe+":
+ RootContext.Unsafe = true;
+ return true;
+
+ case "/unsafe-":
+ RootContext.Unsafe = false;
+ return true;
+
+ case "/warnaserror":
+ case "/warnaserror+":
+ Report.WarningsAreErrors = true;
+ return true;
+
+ case "/warnaserror-":
+ Report.WarningsAreErrors = false;
+ return true;
+
+ case "/warn":
+ SetWarningLevel (value);
+ return true;
+
+ case "/nowarn": {
+ string [] warns;
+
+ if (value.Length == 0){
+ Report.Error (5, "/nowarn requires an argument");
+ Environment.Exit (1);
+ }
+
+ warns = value.Split (new Char [] {','});
+ foreach (string wc in warns){
+ try {
+ int warn = Int32.Parse (wc);
+ if (warn < 1) {
+ throw new ArgumentOutOfRangeException("warn");
+ }
+ Report.SetIgnoreWarning (warn);
+ } catch {
+ Report.Error (1904, String.Format("`{0}' is not a valid warning number", wc));
+ }
+ }
+ return true;
+ }
+
+ case "/noconfig-":
+ load_default_config = true;
+ return true;
+
+ case "/noconfig":
+ case "/noconfig+":
+ load_default_config = false;
+ return true;
+
+ case "/help2":
+ OtherFlags ();
+ Environment.Exit(0);
+ return true;
+
+ case "/help":
+ case "/?":
+ Usage ();
+ Environment.Exit (0);
+ return true;
+
+ case "/main":
+ case "/m":
+ if (value.Length == 0){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ RootContext.MainClass = value;
+ return true;
+
+ case "/nostdlib":
+ case "/nostdlib+":
+ RootContext.StdLib = false;
+ return true;
+
+ case "/nostdlib-":
+ RootContext.StdLib = true;
+ return true;
+
+ case "/fullpaths":
+ return true;
+
+ case "/keyfile":
+ if (value == String.Empty) {
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ RootContext.StrongNameKeyFile = value;
+ return true;
+ case "/keycontainer":
+ if (value == String.Empty) {
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ RootContext.StrongNameKeyContainer = value;
+ return true;
+ case "/delaysign+":
+ RootContext.StrongNameDelaySign = true;
+ return true;
+ case "/delaysign-":
+ RootContext.StrongNameDelaySign = false;
+ return true;
+
+ case "/v2":
+ case "/2":
+ Console.WriteLine ("The compiler option -2 is obsolete. Please use /langversion instead");
+ SetupV2 ();
+ return true;
+
+ case "/langversion":
+ switch (value.ToLower (CultureInfo.InvariantCulture)) {
+ case "iso-1":
+ RootContext.Version = LanguageVersion.ISO_1;
+ return true;
+
+ case "default":
+ SetupV2 ();
+ return true;
+ }
+ Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1' or `Default'", value);
+ return true;
+
+ case "/codepage":
+ switch (value) {
+ case "utf8":
+ encoding = new UTF8Encoding();
+ break;
+ case "reset":
+ encoding = Encoding.Default;
+ break;
+ default:
+ try {
+ encoding = Encoding.GetEncoding (
+ Int32.Parse (value));
+ } catch {
+ Report.Error (2016, "Code page `{0}' is invalid or not installed", value);
+ }
+ break;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ static void Error_WrongOption (string option)
+ {
+ Report.Error (2007, "Unrecognized command-line option: `{0}'", option);
+ }
+
+ static string [] AddArgs (string [] args, string [] extra_args)
+ {
+ string [] new_args;
+ new_args = new string [extra_args.Length + args.Length];
+
+ // if args contains '--' we have to take that into account
+ // split args into first half and second half based on '--'
+ // and add the extra_args before --
+ int split_position = Array.IndexOf (args, "--");
+ if (split_position != -1)
+ {
+ Array.Copy (args, new_args, split_position);
+ extra_args.CopyTo (new_args, split_position);
+ Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
+ }
+ else
+ {
+ args.CopyTo (new_args, 0);
+ extra_args.CopyTo (new_args, args.Length);
+ }
+
+ return new_args;
+ }
+
+ static void AddExternAlias (string identifier, string assembly)
+ {
+ if (assembly.Length == 0) {
+ Report.Error (1680, "Invalid reference alias '" + identifier + "='. Missing filename");
+ return;
+ }
+
+ if (!IsExternAliasValid (identifier)) {
+ Report.Error (1679, "Invalid extern alias for /reference. Alias '" + identifier + "' is not a valid identifier");
+ return;
+ }
+
+ // Could here hashtable throw an exception?
+ external_aliases [identifier] = assembly;
+ }
+
+ static bool IsExternAliasValid (string identifier)
+ {
+ if (identifier.Length == 0)
+ return false;
+ if (identifier [0] != '_' && !Char.IsLetter (identifier [0]))
+ return false;
+
+ for (int i = 1; i < identifier.Length; i++) {
+ char c = identifier [i];
+ if (Char.IsLetter (c) || Char.IsDigit (c))
+ continue;
+
+ UnicodeCategory category = Char.GetUnicodeCategory (c);
+ if (category != UnicodeCategory.Format || category != UnicodeCategory.NonSpacingMark ||
+ category != UnicodeCategory.SpacingCombiningMark ||
+ category != UnicodeCategory.ConnectorPunctuation)
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Parses the arguments, and drives the compilation
+ /// process.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// TODO: Mostly structured to debug the compiler
+ /// now, needs to be turned into a real driver soon.
+ /// </remarks>
+ // [MonoTODO("Change error code for unknown argument to something reasonable")]
+ internal static bool MainDriver (string [] args)
+ {
+ int i;
+ bool parsing_options = true;
+
+ encoding = Encoding.Default;
+
+ references = new ArrayList ();
+ external_aliases = new Hashtable ();
+ soft_references = new ArrayList ();
+ modules = new ArrayList ();
+ link_paths = new ArrayList ();
+
+ SetupDefaultDefines ();
+
+ //
+ // Setup defaults
+ //
+ // This is not required because Assembly.Load knows about this
+ // path.
+ //
+
+ Hashtable response_file_list = null;
+
+ for (i = 0; i < args.Length; i++){
+ string arg = args [i];
+ if (arg.Length == 0)
+ continue;
+
+ if (arg.StartsWith ("@")){
+ string [] extra_args;
+ string response_file = arg.Substring (1);
+
+ if (response_file_list == null)
+ response_file_list = new Hashtable ();
+
+ if (response_file_list.Contains (response_file)){
+ Report.Error (
+ 1515, "Response file `" + response_file +
+ "' specified multiple times");
+ Environment.Exit (1);
+ }
+
+ response_file_list.Add (response_file, response_file);
+
+ extra_args = LoadArgs (response_file);
+ if (extra_args == null){
+ Report.Error (2011, "Unable to open response file: " +
+ response_file);
+ return false;
+ }
+
+ args = AddArgs (args, extra_args);
+ continue;
+ }
+
+ if (parsing_options){
+ if (arg == "--"){
+ parsing_options = false;
+ continue;
+ }
+
+ if (arg.StartsWith ("-")){
+ if (UnixParseOption (arg, ref args, ref i))
+ continue;
+
+ // Try a -CSCOPTION
+ string csc_opt = "/" + arg.Substring (1);
+ if (CSCParseOption (csc_opt, ref args, ref i))
+ continue;
+
+ Error_WrongOption (arg);
+ return false;
+ } else {
+ if (arg [0] == '/'){
+ if (CSCParseOption (arg, ref args, ref i))
+ continue;
+
+ // Need to skip `/home/test.cs' however /test.cs is considered as error
+ if (arg.Length < 2 || arg.IndexOf ('/', 2) == -1) {
+ Error_WrongOption (arg);
+ return false;
+ }
+ }
+ }
+ }
+
+ CompileFiles (arg, false);
+ }
+
+ ProcessFiles ();
+
+ if (tokenize)
+ return true;
+
+ if (RootContext.ToplevelTypes.NamespaceEntry != null)
+ throw new InternalErrorException ("who set it?");
+
+ //
+ // If we are an exe, require a source file for the entry point
+ //
+ if (RootContext.Target == Target.Exe || RootContext.Target == Target.WinExe || RootContext.Target == Target.Module){
+ if (first_source == null){
+ Report.Error (2008, "No files to compile were specified");
+ return false;
+ }
+
+ }
+
+ //
+ // If there is nothing to put in the assembly, and we are not a library
+ //
+ if (first_source == null && embedded_resources == null){
+ Report.Error (2008, "No files to compile were specified");
+ return false;
+ }
+
+ if (Report.Errors > 0)
+ return false;
+
+ if (parse_only)
+ return true;
+
+ //
+ // Load Core Library for default compilation
+ //
+ if (RootContext.StdLib)
+ references.Insert (0, "mscorlib");
+
+ if (load_default_config)
+ DefineDefaultConfig ();
+
+ if (Report.Errors > 0){
+ return false;
+ }
+
+ //
+ // Load assemblies required
+ //
+ if (timestamps)
+ ShowTime ("Loading references");
+ link_paths.Add (GetSystemDir ());
+ link_paths.Add (Directory.GetCurrentDirectory ());
+ LoadReferences ();
+
+ if (timestamps)
+ ShowTime (" References loaded");
+
+ if (Report.Errors > 0){
+ return false;
+ }
+
+ //
+ // Quick hack
+ //
+ if (output_file == null){
+ if (first_source == null){
+ Report.Error (1562, "If no source files are specified you must specify the output file with -out:");
+ return false;
+ }
+
+ int pos = first_source.LastIndexOf ('.');
+
+ if (pos > 0)
+ output_file = first_source.Substring (0, pos) + RootContext.TargetExt;
+ else
+ output_file = first_source + RootContext.TargetExt;
+ }
+
+ if (!CodeGen.Init (output_file, output_file, want_debugging_support))
+ return false;
+
+ if (RootContext.Target == Target.Module) {
+ PropertyInfo module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+ if (module_only == null) {
+ Report.RuntimeMissingSupport (Location.Null, "/target:module");
+ Environment.Exit (1);
+ }
+
+ MethodInfo set_method = module_only.GetSetMethod (true);
+ set_method.Invoke (CodeGen.Assembly.Builder, BindingFlags.Default, null, new object[]{true}, null);
+ }
+
+ RootNamespace.Global.AddModuleReference (CodeGen.Module.Builder);
+
+ if (modules.Count > 0) {
+ foreach (string module in modules)
+ LoadModule (module);
+ }
+
+ //
+ // Before emitting, we need to get the core
+ // types emitted from the user defined types
+ // or from the system ones.
+ //
+ if (timestamps)
+ ShowTime ("Initializing Core Types");
+ if (!RootContext.StdLib){
+ RootContext.ResolveCore ();
+ if (Report.Errors > 0)
+ return false;
+ }
+
+ TypeManager.InitCoreTypes ();
+ if (timestamps)
+ ShowTime (" Core Types done");
+
+ CodeGen.Module.Resolve ();
+
+ //
+ // The second pass of the compiler
+ //
+ if (timestamps)
+ ShowTime ("Resolving tree");
+ RootContext.ResolveTree ();
+
+ if (Report.Errors > 0)
+ return false;
+ if (timestamps)
+ ShowTime ("Populate tree");
+ if (!RootContext.StdLib)
+ RootContext.BootCorlib_PopulateCoreTypes ();
+ RootContext.PopulateTypes ();
+
+ TypeManager.InitCodeHelpers ();
+
+ RootContext.DefineTypes ();
+
+ if (Report.Errors == 0 &&
+ RootContext.Documentation != null &&
+ !RootContext.Documentation.OutputDocComment (
+ output_file))
+ return false;
+
+ //
+ // Verify using aliases now
+ //
+ NamespaceEntry.VerifyAllUsing ();
+
+ if (Report.Errors > 0){
+ return false;
+ }
+
+ CodeGen.Assembly.Resolve ();
+
+ if (RootContext.VerifyClsCompliance) {
+ if (CodeGen.Assembly.IsClsCompliant) {
+ AttributeTester.VerifyModulesClsCompliance ();
+ TypeManager.LoadAllImportedTypes ();
+ }
+ }
+ if (Report.Errors > 0)
+ return false;
+
+ //
+ // The code generator
+ //
+ if (timestamps)
+ ShowTime ("Emitting code");
+ ShowTotalTime ("Total so far");
+ RootContext.EmitCode ();
+ if (timestamps)
+ ShowTime (" done");
+
+ if (Report.Errors > 0){
+ return false;
+ }
+
+ if (timestamps)
+ ShowTime ("Closing types");
+
+ RootContext.CloseTypes ();
+
+ PEFileKinds k = PEFileKinds.ConsoleApplication;
+
+ switch (RootContext.Target) {
+ case Target.Library:
+ case Target.Module:
+ k = PEFileKinds.Dll; break;
+ case Target.Exe:
+ k = PEFileKinds.ConsoleApplication; break;
+ case Target.WinExe:
+ k = PEFileKinds.WindowApplication; break;
+ }
+
+ if (RootContext.NeedsEntryPoint) {
+ MethodInfo ep = RootContext.EntryPoint;
+
+ if (ep == null) {
+ if (RootContext.MainClass != null) {
+ DeclSpace main_cont = RootContext.ToplevelTypes.GetDefinition (RootContext.MainClass) as DeclSpace;
+ if (main_cont == null) {
+ Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass);
+ return false;
+ }
+
+ if (!(main_cont is ClassOrStruct)) {
+ Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass);
+ return false;
+ }
+
+ Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ());
+ return false;
+ }
+
+ if (Report.Errors == 0)
+ Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
+ output_file);
+ return false;
+ }
+
+ CodeGen.Assembly.Builder.SetEntryPoint (ep, k);
+ } else if (RootContext.MainClass != null) {
+ Report.Error (2017, "Cannot specify -main if building a module or library");
+ }
+
+ if (embedded_resources != null){
+ if (RootContext.Target == Target.Module) {
+ Report.Error (1507, "Cannot link resource file when building a module");
+ return false;
+ }
+
+ embedded_resources.Emit ();
+ }
+
+ //
+ // Add Win32 resources
+ //
+
+ CodeGen.Assembly.Builder.DefineVersionInfoResource ();
+
+ if (win32ResourceFile != null) {
+ try {
+ CodeGen.Assembly.Builder.DefineUnmanagedResource (win32ResourceFile);
+ }
+ catch (ArgumentException) {
+ Report.RuntimeMissingSupport (Location.Null, "resource embeding");
+ }
+ }
+
+ if (win32IconFile != null) {
+ MethodInfo define_icon = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+ if (define_icon == null) {
+ Report.RuntimeMissingSupport (Location.Null, "resource embeding");
+ }
+ define_icon.Invoke (CodeGen.Assembly.Builder, new object [] { win32IconFile });
+ }
+
+ if (Report.Errors > 0)
+ return false;
+
+ CodeGen.Save (output_file);
+ if (timestamps) {
+ ShowTime ("Saved output");
+ ShowTotalTime ("Total");
+ }
+
+ Timer.ShowTimers ();
+
+ if (Report.ExpectedError != 0) {
+ if (Report.Errors == 0) {
+ Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
+ "No other errors reported.");
+
+ Environment.Exit (2);
+ } else {
+ Console.WriteLine ("Failed to report expected error " + Report.ExpectedError + ".\n" +
+ "However, other errors were reported.");
+
+ Environment.Exit (1);
+ }
+
+
+ return false;
+ }
+
+#if DEBUGME
+ Console.WriteLine ("Size of strings held: " + DeclSpace.length);
+ Console.WriteLine ("Size of strings short: " + DeclSpace.small);
+#endif
+ return (Report.Errors == 0);
+ }
+ }
+
+ class Resources
+ {
+ interface IResource
+ {
+ void Emit ();
+ string FileName { get; }
+ }
+
+ class EmbededResource : IResource
+ {
+ static MethodInfo embed_res;
+
+ static EmbededResource () {
+ Type[] argst = new Type [] {
+ typeof (string), typeof (string), typeof (ResourceAttributes)
+ };
+
+ embed_res = typeof (AssemblyBuilder).GetMethod (
+ "EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
+ null, CallingConventions.Any, argst, null);
+
+ if (embed_res == null) {
+ Report.RuntimeMissingSupport (Location.Null, "Resource embedding");
+ }
+ }
+
+ readonly object[] args;
+
+ public EmbededResource (string name, string file, bool isPrivate)
+ {
+ args = new object [3];
+ args [0] = name;
+ args [1] = file;
+ args [2] = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
+ }
+
+ public void Emit()
+ {
+ embed_res.Invoke (CodeGen.Assembly.Builder, args);
+ }
+
+ public string FileName {
+ get {
+ return (string)args [1];
+ }
+ }
+ }
+
+ class LinkedResource : IResource
+ {
+ readonly string file;
+ readonly string name;
+ readonly ResourceAttributes attribute;
+
+ public LinkedResource (string name, string file, bool isPrivate)
+ {
+ this.name = name;
+ this.file = file;
+ this.attribute = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
+ }
+
+ public void Emit ()
+ {
+ CodeGen.Assembly.Builder.AddResourceFile (name, Path.GetFileName(file), attribute);
+ }
+
+ public string FileName {
+ get {
+ return file;
+ }
+ }
+ }
+
+
+ IDictionary embedded_resources = new HybridDictionary ();
+
+ public void Add (bool embeded, string file, string name)
+ {
+ Add (embeded, file, name, false);
+ }
+
+ public void Add (bool embeded, string file, string name, bool isPrivate)
+ {
+ if (embedded_resources.Contains (name)) {
+ Report.Error (1508, "The resource identifier `{0}' has already been used in this assembly", name);
+ return;
+ }
+ IResource r = embeded ?
+ (IResource) new EmbededResource (name, file, isPrivate) :
+ new LinkedResource (name, file, isPrivate);
+
+ embedded_resources.Add (name, r);
+ }
+
+ public void Emit ()
+ {
+ foreach (IResource r in embedded_resources.Values) {
+ if (!File.Exists (r.FileName)) {
+ Report.Error (1566, "Error reading resource file `{0}'", r.FileName);
+ continue;
+ }
+
+ r.Emit ();
+ }
+ }
+ }
+
+ //
+ // This is the only public entry point
+ //
+ public class CompilerCallableEntryPoint : MarshalByRefObject {
+ public static bool InvokeCompiler (string [] args, TextWriter error)
+ {
+ Report.Stderr = error;
+ try {
+ return Driver.MainDriver (args) && Report.Errors == 0;
+ }
+ finally {
+ Report.Stderr = Console.Error;
+ Reset ();
+ }
+ }
+
+ public static int[] AllWarningNumbers {
+ get {
+ return Report.AllWarnings;
+ }
+ }
+
+ static void Reset ()
+ {
+ Driver.Reset ();
+ Location.Reset ();
+ RootContext.Reset ();
+ Report.Reset ();
+ TypeManager.Reset ();
+ TypeHandle.Reset ();
+ RootNamespace.Reset ();
+ NamespaceEntry.Reset ();
+ CodeGen.Reset ();
+ Attribute.Reset ();
+ AttributeTester.Reset ();
+ }
+ }
+}
--- /dev/null
+//
+// ecore.cs: Core of the Expression representation for the intermediate tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Marek Safar (marek.safar@seznam.cz)
+//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+//
+//
+
+namespace Mono.CSharp {
+ using System;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Text;
+
+ /// <remarks>
+ /// The ExprClass class contains the is used to pass the
+ /// classification of an expression (value, variable, namespace,
+ /// type, method group, property access, event access, indexer access,
+ /// nothing).
+ /// </remarks>
+ public enum ExprClass : byte {
+ Invalid,
+
+ Value,
+ Variable,
+ Namespace,
+ Type,
+ MethodGroup,
+ PropertyAccess,
+ EventAccess,
+ IndexerAccess,
+ Nothing,
+ }
+
+ /// <remarks>
+ /// This is used to tell Resolve in which types of expressions we're
+ /// interested.
+ /// </remarks>
+ [Flags]
+ public enum ResolveFlags {
+ // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
+ VariableOrValue = 1,
+
+ // Returns a type expression.
+ Type = 2,
+
+ // Returns a method group.
+ MethodGroup = 4,
+
+ // Mask of all the expression class flags.
+ MaskExprClass = 7,
+
+ // Disable control flow analysis while resolving the expression.
+ // This is used when resolving the instance expression of a field expression.
+ DisableFlowAnalysis = 8,
+
+ // Set if this is resolving the first part of a MemberAccess.
+ Intermediate = 16,
+
+ // Disable control flow analysis _of struct_ while resolving the expression.
+ // This is used when resolving the instance expression of a field expression.
+ DisableStructFlowAnalysis = 32,
+
+ }
+
+ //
+ // This is just as a hint to AddressOf of what will be done with the
+ // address.
+ [Flags]
+ public enum AddressOp {
+ Store = 1,
+ Load = 2,
+ LoadStore = 3
+ };
+
+ /// <summary>
+ /// This interface is implemented by variables
+ /// </summary>
+ public interface IMemoryLocation {
+ /// <summary>
+ /// The AddressOf method should generate code that loads
+ /// the address of the object and leaves it on the stack.
+ ///
+ /// The `mode' argument is used to notify the expression
+ /// of whether this will be used to read from the address or
+ /// write to the address.
+ ///
+ /// This is just a hint that can be used to provide good error
+ /// reporting, and should have no other side effects.
+ /// </summary>
+ void AddressOf (EmitContext ec, AddressOp mode);
+ }
+
+ /// <summary>
+ /// This interface is implemented by variables
+ /// </summary>
+ public interface IVariable {
+ VariableInfo VariableInfo {
+ get;
+ }
+
+ bool VerifyFixed ();
+ }
+
+ /// <remarks>
+ /// Base class for expressions
+ /// </remarks>
+ public abstract class Expression {
+ public ExprClass eclass;
+ protected Type type;
+ protected Location loc;
+
+ public Type Type {
+ get { return type; }
+ set { type = value; }
+ }
+
+ public virtual Location Location {
+ get { return loc; }
+ }
+
+ /// <summary>
+ /// Utility wrapper routine for Error, just to beautify the code
+ /// </summary>
+ public void Error (int error, string s)
+ {
+ Report.Error (error, loc, s);
+ }
+
+ // Not nice but we have broken hierarchy.
+ public virtual void CheckMarshalByRefAccess ()
+ {
+ }
+
+ public virtual bool GetAttributableValue (Type valueType, out object value)
+ {
+ Attribute.Error_AttributeArgumentNotValid (loc);
+ value = null;
+ return false;
+ }
+
+ public virtual string GetSignatureForError ()
+ {
+ return TypeManager.CSharpName (type);
+ }
+
+ public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
+ {
+ MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ must_do_cs1540_check = false; // by default we do not check for this
+
+ if (ma == MethodAttributes.Public)
+ return true;
+
+ //
+ // If only accessible to the current class or children
+ //
+ if (ma == MethodAttributes.Private)
+ return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
+ TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
+
+ if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
+ TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
+ if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
+ return true;
+ } else {
+ if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
+ return false;
+ }
+
+ // Family and FamANDAssem require that we derive.
+ // FamORAssem requires that we derive if in different assemblies.
+ if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
+ return false;
+
+ if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
+ must_do_cs1540_check = true;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Performs semantic analysis on the Expression
+ /// </summary>
+ ///
+ /// <remarks>
+ /// The Resolve method is invoked to perform the semantic analysis
+ /// on the node.
+ ///
+ /// The return value is an expression (it can be the
+ /// same expression in some cases) or a new
+ /// expression that better represents this node.
+ ///
+ /// For example, optimizations of Unary (LiteralInt)
+ /// would return a new LiteralInt with a negated
+ /// value.
+ ///
+ /// If there is an error during semantic analysis,
+ /// then an error should be reported (using Report)
+ /// and a null value should be returned.
+ ///
+ /// There are two side effects expected from calling
+ /// Resolve(): the the field variable "eclass" should
+ /// be set to any value of the enumeration
+ /// `ExprClass' and the type variable should be set
+ /// to a valid type (this is the type of the
+ /// expression).
+ /// </remarks>
+ public abstract Expression DoResolve (EmitContext ec);
+
+ public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ return null;
+ }
+
+ //
+ // This is used if the expression should be resolved as a type or namespace name.
+ // the default implementation fails.
+ //
+ public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+ {
+ return null;
+ }
+
+ //
+ // This is used to resolve the expression as a type, a null
+ // value will be returned if the expression is not a type
+ // reference
+ //
+ public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
+ {
+ TypeExpr te = ResolveAsBaseTerminal (ec, silent);
+ if (te == null)
+ return null;
+
+ if (!silent) {
+ ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
+ if (obsolete_attr != null && !ec.IsInObsoleteScope) {
+ AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
+ }
+ }
+
+ // Constrains don't need to be checked for overrides
+ GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
+ if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
+ te.loc = loc;
+ return te;
+ }
+
+ ConstructedType ct = te as ConstructedType;
+ if ((ct != null) && !ct.CheckConstraints (ec))
+ return null;
+
+ return te;
+ }
+
+ public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
+ {
+ int errors = Report.Errors;
+
+ FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
+
+ if (fne == null)
+ return null;
+
+ if (fne.eclass != ExprClass.Type) {
+ if (!silent && errors == Report.Errors)
+ fne.Error_UnexpectedKind (null, "type", loc);
+ return null;
+ }
+
+ TypeExpr te = fne as TypeExpr;
+
+ if (!te.CheckAccessLevel (ec.DeclContainer)) {
+ Report.SymbolRelatedToPreviousError (te.Type);
+ ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
+ return null;
+ }
+
+ te.loc = loc;
+ return te;
+ }
+
+ public static void ErrorIsInaccesible (Location loc, string name)
+ {
+ Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
+ }
+
+ protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
+ {
+ Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
+ + " The qualifier must be of type `{2}' or derived from it",
+ TypeManager.GetFullNameSignature (m),
+ TypeManager.CSharpName (qualifier),
+ TypeManager.CSharpName (container));
+
+ }
+
+ protected void Error_CannotAssign (string to, string roContext)
+ {
+ Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
+ to, roContext);
+ }
+
+ public static void Error_VoidInvalidInTheContext (Location loc)
+ {
+ Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
+ }
+
+ public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
+ {
+ if (Type.FullName == target.FullName){
+ Report.ExtraInformation (loc,
+ String.Format (
+ "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
+ Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
+
+ }
+
+ if (expl) {
+ Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
+ GetSignatureForError (), TypeManager.CSharpName (target));
+ return;
+ }
+
+ Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
+ bool b = Convert.ExplicitNumericConversion (e, target) != null;
+
+ if (b || Convert.ExplicitReferenceConversionExists (Type, target) ||
+ Convert.ExplicitUnsafe (e, target) != null || Convert.UserDefinedConversion (null, this, target, Location.Null, true) != null) {
+ Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
+ TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
+ return;
+ }
+
+ if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
+ Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
+ ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target));
+ return;
+ }
+
+ Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
+ Type == TypeManager.anonymous_method_type ?
+ "anonymous method" : "`" + GetSignatureForError () + "'",
+ TypeManager.CSharpName (target));
+ }
+
+ protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
+ {
+ Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
+ TypeManager.CSharpName (type), name);
+ }
+
+ protected static void Error_ValueAssignment (Location loc)
+ {
+ Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
+ }
+
+ ResolveFlags ExprClassToResolveFlags
+ {
+ get {
+ switch (eclass) {
+ case ExprClass.Type:
+ case ExprClass.Namespace:
+ return ResolveFlags.Type;
+
+ case ExprClass.MethodGroup:
+ return ResolveFlags.MethodGroup;
+
+ case ExprClass.Value:
+ case ExprClass.Variable:
+ case ExprClass.PropertyAccess:
+ case ExprClass.EventAccess:
+ case ExprClass.IndexerAccess:
+ return ResolveFlags.VariableOrValue;
+
+ default:
+ throw new Exception ("Expression " + GetType () +
+ " ExprClass is Invalid after resolve");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Resolves an expression and performs semantic analysis on it.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Currently Resolve wraps DoResolve to perform sanity
+ /// checking and assertion checking on what we expect from Resolve.
+ /// </remarks>
+ public Expression Resolve (EmitContext ec, ResolveFlags flags)
+ {
+ if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
+ return ResolveAsTypeStep (ec, false);
+
+ bool do_flow_analysis = ec.DoFlowAnalysis;
+ bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
+ if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
+ do_flow_analysis = false;
+ if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
+ omit_struct_analysis = true;
+
+ Expression e;
+ using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
+ if (this is SimpleName) {
+ bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
+ e = ((SimpleName) this).DoResolve (ec, intermediate);
+ } else {
+ e = DoResolve (ec);
+ }
+ }
+
+ if (e == null)
+ return null;
+
+ if ((flags & e.ExprClassToResolveFlags) == 0) {
+ e.Error_UnexpectedKind (flags, loc);
+ return null;
+ }
+
+ if (e.type == null && !(e is Namespace)) {
+ throw new Exception (
+ "Expression " + e.GetType () +
+ " did not set its type after Resolve\n" +
+ "called from: " + this.GetType ());
+ }
+
+ return e;
+ }
+
+ /// <summary>
+ /// Resolves an expression and performs semantic analysis on it.
+ /// </summary>
+ public Expression Resolve (EmitContext ec)
+ {
+ Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+
+ if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
+ ((MethodGroupExpr) e).ReportUsageError ();
+ return null;
+ }
+ return e;
+ }
+
+ public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
+ {
+ Expression e = Resolve (ec);
+ if (e == null)
+ return null;
+
+ Constant c = e as Constant;
+ if (c != null)
+ return c;
+
+ Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
+ return null;
+ }
+
+ /// <summary>
+ /// Resolves an expression for LValue assignment
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
+ /// checking and assertion checking on what we expect from Resolve
+ /// </remarks>
+ public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
+ {
+ int errors = Report.Errors;
+ bool out_access = right_side == EmptyExpression.OutAccess;
+
+ Expression e = DoResolveLValue (ec, right_side);
+
+ if (e != null && out_access && !(e is IMemoryLocation)) {
+ // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
+ // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
+
+ //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
+ // e.GetType () + " " + e.GetSignatureForError ());
+ e = null;
+ }
+
+ if (e == null) {
+ if (errors == Report.Errors) {
+ if (out_access)
+ Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
+ else
+ Error_ValueAssignment (loc);
+ }
+ return null;
+ }
+
+ if (e.eclass == ExprClass.Invalid)
+ throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
+
+ if (e.eclass == ExprClass.MethodGroup) {
+ ((MethodGroupExpr) e).ReportUsageError ();
+ return null;
+ }
+
+ if ((e.type == null) && !(e is ConstructedType))
+ throw new Exception ("Expression " + e + " did not set its type after Resolve");
+
+ return e;
+ }
+
+ /// <summary>
+ /// Emits the code for the expression
+ /// </summary>
+ ///
+ /// <remarks>
+ /// The Emit method is invoked to generate the code
+ /// for the expression.
+ /// </remarks>
+ public abstract void Emit (EmitContext ec);
+
+ public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ Emit (ec);
+ ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+ }
+
+ /// <summary>
+ /// Protected constructor. Only derivate types should
+ /// be able to be created
+ /// </summary>
+
+ protected Expression ()
+ {
+ eclass = ExprClass.Invalid;
+ type = null;
+ }
+
+ /// <summary>
+ /// Returns a literalized version of a literal FieldInfo
+ /// </summary>
+ ///
+ /// <remarks>
+ /// The possible return values are:
+ /// IntConstant, UIntConstant
+ /// LongLiteral, ULongConstant
+ /// FloatConstant, DoubleConstant
+ /// StringConstant
+ ///
+ /// The value returned is already resolved.
+ /// </remarks>
+ public static Constant Constantify (object v, Type t)
+ {
+ if (t == TypeManager.int32_type)
+ return new IntConstant ((int) v, Location.Null);
+ else if (t == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v, Location.Null);
+ else if (t == TypeManager.int64_type)
+ return new LongConstant ((long) v, Location.Null);
+ else if (t == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v, Location.Null);
+ else if (t == TypeManager.float_type)
+ return new FloatConstant ((float) v, Location.Null);
+ else if (t == TypeManager.double_type)
+ return new DoubleConstant ((double) v, Location.Null);
+ else if (t == TypeManager.string_type)
+ return new StringConstant ((string) v, Location.Null);
+ else if (t == TypeManager.short_type)
+ return new ShortConstant ((short)v, Location.Null);
+ else if (t == TypeManager.ushort_type)
+ return new UShortConstant ((ushort)v, Location.Null);
+ else if (t == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte)v, Location.Null);
+ else if (t == TypeManager.byte_type)
+ return new ByteConstant ((byte)v, Location.Null);
+ else if (t == TypeManager.char_type)
+ return new CharConstant ((char)v, Location.Null);
+ else if (t == TypeManager.bool_type)
+ return new BoolConstant ((bool) v, Location.Null);
+ else if (t == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v, Location.Null);
+ else if (TypeManager.IsEnumType (t)){
+ Type real_type = TypeManager.TypeToCoreType (v.GetType ());
+ if (real_type == t)
+ real_type = System.Enum.GetUnderlyingType (real_type);
+
+ Constant e = Constantify (v, real_type);
+
+ return new EnumConstant (e, t);
+ } else if (v == null && !TypeManager.IsValueType (t))
+ return new NullLiteral (Location.Null);
+ else
+ throw new Exception ("Unknown type for constant (" + t +
+ "), details: " + v);
+ }
+
+ /// <summary>
+ /// Returns a fully formed expression after a MemberLookup
+ /// </summary>
+ ///
+ public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
+ {
+ if (mi is EventInfo)
+ return new EventExpr ((EventInfo) mi, loc);
+ else if (mi is FieldInfo)
+ return new FieldExpr ((FieldInfo) mi, loc);
+ else if (mi is PropertyInfo)
+ return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
+ else if (mi is Type){
+ return new TypeExpression ((System.Type) mi, loc);
+ }
+
+ return null;
+ }
+
+ protected static ArrayList almostMatchedMembers = new ArrayList (4);
+
+ //
+ // FIXME: Probably implement a cache for (t,name,current_access_set)?
+ //
+ // This code could use some optimizations, but we need to do some
+ // measurements. For example, we could use a delegate to `flag' when
+ // something can not any longer be a method-group (because it is something
+ // else).
+ //
+ // Return values:
+ // If the return value is an Array, then it is an array of
+ // MethodBases
+ //
+ // If the return value is an MemberInfo, it is anything, but a Method
+ //
+ // null on error.
+ //
+ // FIXME: When calling MemberLookup inside an `Invocation', we should pass
+ // the arguments here and have MemberLookup return only the methods that
+ // match the argument count/type, unlike we are doing now (we delay this
+ // decision).
+ //
+ // This is so we can catch correctly attempts to invoke instance methods
+ // from a static body (scan for error 120 in ResolveSimpleName).
+ //
+ //
+ // FIXME: Potential optimization, have a static ArrayList
+ //
+
+ public static Expression MemberLookup (Type container_type, Type queried_type, string name,
+ MemberTypes mt, BindingFlags bf, Location loc)
+ {
+ return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
+ }
+
+ //
+ // Lookup type `queried_type' for code in class `container_type' with a qualifier of
+ // `qualifier_type' or null to lookup members in the current class.
+ //
+
+ public static Expression MemberLookup (Type container_type,
+ Type qualifier_type, Type queried_type,
+ string name, MemberTypes mt,
+ BindingFlags bf, Location loc)
+ {
+ almostMatchedMembers.Clear ();
+
+ MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
+ queried_type, mt, bf, name, almostMatchedMembers);
+
+ if (mi == null)
+ return null;
+
+ if (mi.Length > 1) {
+ bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
+ MemberInfo non_method = null;
+ ArrayList methods = new ArrayList (2);
+
+ foreach (MemberInfo m in mi) {
+ if (m is MethodBase) {
+ methods.Add (m);
+ continue;
+ }
+
+ if (non_method == null) {
+ non_method = m;
+ continue;
+ }
+
+ Report.SymbolRelatedToPreviousError (m);
+ Report.SymbolRelatedToPreviousError (non_method);
+ Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
+ TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
+ return null;
+ }
+
+ if (methods.Count == 0)
+ return null;
+
+ if (non_method != null) {
+ MethodBase method = (MethodBase) methods [0];
+
+ if (method.DeclaringType == non_method.DeclaringType) {
+ // Cannot happen with C# code, but is valid in IL
+ Report.SymbolRelatedToPreviousError (method);
+ Report.SymbolRelatedToPreviousError (non_method);
+ Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
+ TypeManager.GetFullNameSignature (non_method),
+ TypeManager.CSharpSignature (method));
+ return null;
+ }
+
+ if (is_interface) {
+ Report.SymbolRelatedToPreviousError (method);
+ Report.SymbolRelatedToPreviousError (non_method);
+ Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
+ TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
+ }
+ }
+
+ return new MethodGroupExpr (methods, loc);
+ }
+
+ if (mi [0] is MethodBase)
+ return new MethodGroupExpr (mi, loc);
+
+ return ExprClassFromMemberInfo (container_type, mi [0], loc);
+ }
+
+ public const MemberTypes AllMemberTypes =
+ MemberTypes.Constructor |
+ MemberTypes.Event |
+ MemberTypes.Field |
+ MemberTypes.Method |
+ MemberTypes.NestedType |
+ MemberTypes.Property;
+
+ public const BindingFlags AllBindingFlags =
+ BindingFlags.Public |
+ BindingFlags.Static |
+ BindingFlags.Instance;
+
+ public static Expression MemberLookup (Type container_type, Type queried_type,
+ string name, Location loc)
+ {
+ return MemberLookup (container_type, null, queried_type, name,
+ AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MemberLookup (Type container_type, Type qualifier_type,
+ Type queried_type, string name, Location loc)
+ {
+ return MemberLookup (container_type, qualifier_type, queried_type,
+ name, AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MethodLookup (Type container_type, Type queried_type,
+ string name, Location loc)
+ {
+ return MemberLookup (container_type, null, queried_type, name,
+ MemberTypes.Method, AllBindingFlags, loc);
+ }
+
+ /// <summary>
+ /// This is a wrapper for MemberLookup that is not used to "probe", but
+ /// to find a final definition. If the final definition is not found, we
+ /// look for private members and display a useful debugging message if we
+ /// find it.
+ /// </summary>
+ public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name, Location loc)
+ {
+ return MemberLookupFinal (ec, qualifier_type, queried_type, name,
+ AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name,
+ MemberTypes mt, BindingFlags bf,
+ Location loc)
+ {
+ Expression e;
+
+ int errors = Report.Errors;
+
+ e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
+
+ if (e == null && errors == Report.Errors)
+ // No errors were reported by MemberLookup, but there was an error.
+ MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
+
+ return e;
+ }
+
+ public static void MemberLookupFailed (Type container_type, Type qualifier_type,
+ Type queried_type, string name,
+ string class_name, bool complain_if_none_found,
+ Location loc)
+ {
+ if (almostMatchedMembers.Count != 0) {
+ for (int i = 0; i < almostMatchedMembers.Count; ++i) {
+ MemberInfo m = (MemberInfo) almostMatchedMembers [i];
+ for (int j = 0; j < i; ++j) {
+ if (m == almostMatchedMembers [j]) {
+ m = null;
+ break;
+ }
+ }
+ if (m == null)
+ continue;
+
+ Type declaring_type = m.DeclaringType;
+
+ Report.SymbolRelatedToPreviousError (m);
+ if (qualifier_type == null) {
+ Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
+ TypeManager.CSharpName (m.DeclaringType),
+ TypeManager.CSharpName (container_type));
+
+ } else if (qualifier_type != container_type &&
+ TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
+ // Although a derived class can access protected members of
+ // its base class it cannot do so through an instance of the
+ // base class (CS1540). If the qualifier_type is a base of the
+ // ec.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
+ Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
+ } else {
+ ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
+ }
+ }
+ almostMatchedMembers.Clear ();
+ return;
+ }
+
+ MemberInfo[] lookup = null;
+ if (queried_type == null) {
+ class_name = "global::";
+ } else {
+ lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
+ AllMemberTypes, AllBindingFlags |
+ BindingFlags.NonPublic, name, null);
+ }
+
+ if (lookup == null) {
+ if (!complain_if_none_found)
+ return;
+
+ if (class_name != null)
+ Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
+ name, class_name);
+ else
+ Error_TypeDoesNotContainDefinition (loc, queried_type, name);
+ return;
+ }
+
+ if (TypeManager.MemberLookup (queried_type, null, queried_type,
+ AllMemberTypes, AllBindingFlags |
+ BindingFlags.NonPublic, name, null) == null) {
+ if ((lookup.Length == 1) && (lookup [0] is Type)) {
+ Type t = (Type) lookup [0];
+
+ Report.Error (305, loc,
+ "Using the generic type `{0}' " +
+ "requires {1} type arguments",
+ TypeManager.CSharpName (t),
+ TypeManager.GetNumberOfTypeArguments (t).ToString ());
+ return;
+ }
+ }
+
+ MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
+ BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
+ if (name == ".ctor" && ml.Count == 0)
+ {
+ Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
+ return;
+ }
+
+ Report.SymbolRelatedToPreviousError (lookup [0]);
+ ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
+ }
+
+ /// <summary>
+ /// Returns an expression that can be used to invoke operator true
+ /// on the expression if it exists.
+ /// </summary>
+ static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
+ {
+ return GetOperatorTrueOrFalse (ec, e, true, loc);
+ }
+
+ /// <summary>
+ /// Returns an expression that can be used to invoke operator false
+ /// on the expression if it exists.
+ /// </summary>
+ static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
+ {
+ return GetOperatorTrueOrFalse (ec, e, false, loc);
+ }
+
+ static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
+ {
+ MethodBase method;
+ Expression operator_group;
+
+#if GMCS_SOURCE
+ if (TypeManager.IsNullableType (e.Type))
+ return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
+#endif
+
+ operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc);
+ if (operator_group == null)
+ return null;
+
+ ArrayList arguments = new ArrayList ();
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+ method = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) operator_group, arguments, false, loc);
+
+ if (method == null)
+ return null;
+
+ return new StaticCallExpr ((MethodInfo) method, arguments, loc);
+ }
+
+ /// <summary>
+ /// Resolves the expression `e' into a boolean expression: either through
+ /// an implicit conversion, or through an `operator true' invocation
+ /// </summary>
+ public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
+ {
+ e = e.Resolve (ec);
+ if (e == null)
+ return null;
+
+ if (e.Type == TypeManager.bool_type)
+ return e;
+
+ Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
+
+ if (converted != null)
+ return converted;
+
+ //
+ // If no implicit conversion to bool exists, try using `operator true'
+ //
+ converted = Expression.GetOperatorTrue (ec, e, loc);
+ if (converted == null){
+ e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
+ return null;
+ }
+ return converted;
+ }
+
+ public virtual string ExprClassName
+ {
+ get {
+ switch (eclass){
+ case ExprClass.Invalid:
+ return "Invalid";
+ case ExprClass.Value:
+ return "value";
+ case ExprClass.Variable:
+ return "variable";
+ case ExprClass.Namespace:
+ return "namespace";
+ case ExprClass.Type:
+ return "type";
+ case ExprClass.MethodGroup:
+ return "method group";
+ case ExprClass.PropertyAccess:
+ return "property access";
+ case ExprClass.EventAccess:
+ return "event access";
+ case ExprClass.IndexerAccess:
+ return "indexer access";
+ case ExprClass.Nothing:
+ return "null";
+ }
+ throw new Exception ("Should not happen");
+ }
+ }
+
+ /// <summary>
+ /// Reports that we were expecting `expr' to be of class `expected'
+ /// </summary>
+ public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
+ {
+ Error_UnexpectedKind (ds, expected, ExprClassName, loc);
+ }
+
+ public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
+ {
+ string name = GetSignatureForError ();
+ if (ds != null)
+ name = ds.GetSignatureForError () + '.' + name;
+
+ Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
+ name, was, expected);
+ }
+
+ public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
+ {
+ string [] valid = new string [4];
+ int count = 0;
+
+ if ((flags & ResolveFlags.VariableOrValue) != 0) {
+ valid [count++] = "variable";
+ valid [count++] = "value";
+ }
+
+ if ((flags & ResolveFlags.Type) != 0)
+ valid [count++] = "type";
+
+ if ((flags & ResolveFlags.MethodGroup) != 0)
+ valid [count++] = "method group";
+
+ if (count == 0)
+ valid [count++] = "unknown";
+
+ StringBuilder sb = new StringBuilder (valid [0]);
+ for (int i = 1; i < count - 1; i++) {
+ sb.Append ("', `");
+ sb.Append (valid [i]);
+ }
+ if (count > 1) {
+ sb.Append ("' or `");
+ sb.Append (valid [count - 1]);
+ }
+
+ Report.Error (119, loc,
+ "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
+ }
+
+ public static void UnsafeError (Location loc)
+ {
+ Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
+ }
+
+ //
+ // Load the object from the pointer.
+ //
+ public static void LoadFromPtr (ILGenerator ig, Type t)
+ {
+ if (t == TypeManager.int32_type)
+ ig.Emit (OpCodes.Ldind_I4);
+ else if (t == TypeManager.uint32_type)
+ ig.Emit (OpCodes.Ldind_U4);
+ else if (t == TypeManager.short_type)
+ ig.Emit (OpCodes.Ldind_I2);
+ else if (t == TypeManager.ushort_type)
+ ig.Emit (OpCodes.Ldind_U2);
+ else if (t == TypeManager.char_type)
+ ig.Emit (OpCodes.Ldind_U2);
+ else if (t == TypeManager.byte_type)
+ ig.Emit (OpCodes.Ldind_U1);
+ else if (t == TypeManager.sbyte_type)
+ ig.Emit (OpCodes.Ldind_I1);
+ else if (t == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Ldind_I8);
+ else if (t == TypeManager.int64_type)
+ ig.Emit (OpCodes.Ldind_I8);
+ else if (t == TypeManager.float_type)
+ ig.Emit (OpCodes.Ldind_R4);
+ else if (t == TypeManager.double_type)
+ ig.Emit (OpCodes.Ldind_R8);
+ else if (t == TypeManager.bool_type)
+ ig.Emit (OpCodes.Ldind_I1);
+ else if (t == TypeManager.intptr_type)
+ ig.Emit (OpCodes.Ldind_I);
+ else if (TypeManager.IsEnumType (t)) {
+ if (t == TypeManager.enum_type)
+ ig.Emit (OpCodes.Ldind_Ref);
+ else
+ LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
+ } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
+ ig.Emit (OpCodes.Ldobj, t);
+ else if (t.IsPointer)
+ ig.Emit (OpCodes.Ldind_I);
+ else
+ ig.Emit (OpCodes.Ldind_Ref);
+ }
+
+ //
+ // The stack contains the pointer and the value of type `type'
+ //
+ public static void StoreFromPtr (ILGenerator ig, Type type)
+ {
+ if (TypeManager.IsEnumType (type))
+ type = TypeManager.EnumToUnderlying (type);
+ if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
+ ig.Emit (OpCodes.Stind_I4);
+ else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Stind_I8);
+ else if (type == TypeManager.char_type || type == TypeManager.short_type ||
+ type == TypeManager.ushort_type)
+ ig.Emit (OpCodes.Stind_I2);
+ else if (type == TypeManager.float_type)
+ ig.Emit (OpCodes.Stind_R4);
+ else if (type == TypeManager.double_type)
+ ig.Emit (OpCodes.Stind_R8);
+ else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
+ type == TypeManager.bool_type)
+ ig.Emit (OpCodes.Stind_I1);
+ else if (type == TypeManager.intptr_type)
+ ig.Emit (OpCodes.Stind_I);
+ else if (type.IsValueType || TypeManager.IsGenericParameter (type))
+ ig.Emit (OpCodes.Stobj, type);
+ else
+ ig.Emit (OpCodes.Stind_Ref);
+ }
+
+ //
+ // Returns the size of type `t' if known, otherwise, 0
+ //
+ public static int GetTypeSize (Type t)
+ {
+ t = TypeManager.TypeToCoreType (t);
+ if (t == TypeManager.int32_type ||
+ t == TypeManager.uint32_type ||
+ t == TypeManager.float_type)
+ return 4;
+ else if (t == TypeManager.int64_type ||
+ t == TypeManager.uint64_type ||
+ t == TypeManager.double_type)
+ return 8;
+ else if (t == TypeManager.byte_type ||
+ t == TypeManager.sbyte_type ||
+ t == TypeManager.bool_type)
+ return 1;
+ else if (t == TypeManager.short_type ||
+ t == TypeManager.char_type ||
+ t == TypeManager.ushort_type)
+ return 2;
+ else if (t == TypeManager.decimal_type)
+ return 16;
+ else
+ return 0;
+ }
+
+ public static void Error_NegativeArrayIndex (Location loc)
+ {
+ Report.Error (248, loc, "Cannot create an array with a negative size");
+ }
+
+ protected void Error_CannotCallAbstractBase (string name)
+ {
+ Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
+ }
+
+ //
+ // Converts `source' to an int, uint, long or ulong.
+ //
+ public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
+ {
+ Expression target;
+
+ using (ec.With (EmitContext.Flags.CheckState, true)) {
+ target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
+ if (target == null)
+ target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
+ if (target == null)
+ target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
+ if (target == null)
+ target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
+
+ if (target == null) {
+ source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
+ return null;
+ }
+ }
+
+ //
+ // Only positive constants are allowed at compile time
+ //
+ if (target is Constant){
+ if (target is IntConstant){
+ if (((IntConstant) target).Value < 0){
+ Error_NegativeArrayIndex (loc);
+ return null;
+ }
+ }
+
+ if (target is LongConstant){
+ if (((LongConstant) target).Value < 0){
+ Error_NegativeArrayIndex (loc);
+ return null;
+ }
+ }
+
+ }
+
+ return target;
+ }
+
+ }
+
+ /// <summary>
+ /// This is just a base class for expressions that can
+ /// appear on statements (invocations, object creation,
+ /// assignments, post/pre increment and decrement). The idea
+ /// being that they would support an extra Emition interface that
+ /// does not leave a result on the stack.
+ /// </summary>
+ public abstract class ExpressionStatement : Expression {
+
+ public virtual ExpressionStatement ResolveStatement (EmitContext ec)
+ {
+ Expression e = Resolve (ec);
+ if (e == null)
+ return null;
+
+ ExpressionStatement es = e as ExpressionStatement;
+ if (es == null)
+ Error (201, "Only assignment, call, increment, decrement and new object " +
+ "expressions can be used as a statement");
+
+ return es;
+ }
+
+ /// <summary>
+ /// Requests the expression to be emitted in a `statement'
+ /// context. This means that no new value is left on the
+ /// stack after invoking this method (constrasted with
+ /// Emit that will always leave a value on the stack).
+ /// </summary>
+ public abstract void EmitStatement (EmitContext ec);
+ }
+
+ /// <summary>
+ /// This kind of cast is used to encapsulate the child
+ /// whose type is child.Type into an expression that is
+ /// reported to return "return_type". This is used to encapsulate
+ /// expressions which have compatible types, but need to be dealt
+ /// at higher levels with.
+ ///
+ /// For example, a "byte" expression could be encapsulated in one
+ /// of these as an "unsigned int". The type for the expression
+ /// would be "unsigned int".
+ ///
+ /// </summary>
+ public class EmptyCast : Expression {
+ protected readonly Expression child;
+
+ public EmptyCast (Expression child, Type return_type)
+ {
+ eclass = child.eclass;
+ loc = child.Location;
+ type = return_type;
+ this.child = child;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ child.Emit (ec);
+ }
+
+ public override bool GetAttributableValue (Type valueType, out object value)
+ {
+ return child.GetAttributableValue (valueType, out value);
+ }
+
+ }
+
+ /// <summary>
+ /// Performs a cast using an operator (op_Explicit or op_Implicit)
+ /// </summary>
+ public class OperatorCast : EmptyCast {
+ MethodInfo conversion_operator;
+ bool find_explicit;
+
+ public OperatorCast (Expression child, Type target_type) : this (child, target_type, false) {}
+
+ public OperatorCast (Expression child, Type target_type, bool find_explicit)
+ : base (child, target_type)
+ {
+ this.find_explicit = find_explicit;
+ }
+
+ // Returns the implicit operator that converts from
+ // 'child.Type' to our target type (type)
+ MethodInfo GetConversionOperator (bool find_explicit)
+ {
+ string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
+
+ MemberInfo [] mi;
+
+ mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
+ BindingFlags.Static | BindingFlags.Public, operator_name, null);
+
+ if (mi == null){
+ mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
+ BindingFlags.Static | BindingFlags.Public, operator_name, null);
+ }
+
+ foreach (MethodInfo oper in mi) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+
+ if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+ return oper;
+ }
+
+ return null;
+
+
+ }
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ child.Emit (ec);
+ conversion_operator = GetConversionOperator (find_explicit);
+
+ if (conversion_operator == null)
+ throw new InternalErrorException ("Outer conversion routine is out of sync");
+
+ ig.Emit (OpCodes.Call, conversion_operator);
+ }
+
+ }
+
+ /// <summary>
+ /// This is a numeric cast to a Decimal
+ /// </summary>
+ public class CastToDecimal : EmptyCast {
+ MethodInfo conversion_operator;
+
+ public CastToDecimal (Expression child)
+ : this (child, false)
+ {
+ }
+
+ public CastToDecimal (Expression child, bool find_explicit)
+ : base (child, TypeManager.decimal_type)
+ {
+ conversion_operator = GetConversionOperator (find_explicit);
+
+ if (conversion_operator == null)
+ throw new InternalErrorException ("Outer conversion routine is out of sync");
+ }
+
+ // Returns the implicit operator that converts from
+ // 'child.Type' to System.Decimal.
+ MethodInfo GetConversionOperator (bool find_explicit)
+ {
+ string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
+
+ MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
+ BindingFlags.Static | BindingFlags.Public, operator_name, null);
+
+ foreach (MethodInfo oper in mi) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+
+ if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+ return oper;
+ }
+
+ return null;
+ }
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ child.Emit (ec);
+
+ ig.Emit (OpCodes.Call, conversion_operator);
+ }
+ }
+
+ /// <summary>
+ /// This is an explicit numeric cast from a Decimal
+ /// </summary>
+ public class CastFromDecimal : EmptyCast
+ {
+ static IDictionary operators;
+
+ public CastFromDecimal (Expression child, Type return_type)
+ : base (child, return_type)
+ {
+ if (child.Type != TypeManager.decimal_type)
+ throw new InternalErrorException (
+ "The expected type is Decimal, instead it is " + child.Type.FullName);
+ }
+
+ // Returns the explicit operator that converts from an
+ // express of type System.Decimal to 'type'.
+ public Expression Resolve ()
+ {
+ if (operators == null) {
+ MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
+ TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
+ BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
+
+ operators = new System.Collections.Specialized.HybridDictionary ();
+ foreach (MethodInfo oper in all_oper) {
+ ParameterData pd = TypeManager.GetParameterData (oper);
+ if (pd.ParameterType (0) == TypeManager.decimal_type)
+ operators.Add (oper.ReturnType, oper);
+ }
+ }
+
+ return operators.Contains (type) ? this : null;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ child.Emit (ec);
+
+ ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
+ }
+ }
+
+
+ //
+ // Constant specialization of EmptyCast.
+ // We need to special case this since an empty cast of
+ // a constant is still a constant.
+ //
+ public class EmptyConstantCast : Constant
+ {
+ public readonly Constant child;
+
+ public EmptyConstantCast(Constant child, Type type)
+ : base (child.Location)
+ {
+ eclass = child.eclass;
+ this.child = child;
+ this.type = type;
+ }
+
+ public override string AsString ()
+ {
+ return child.AsString ();
+ }
+
+ public override object GetValue ()
+ {
+ return child.GetValue ();
+ }
+
+ public override Constant Reduce (bool inCheckedContext, Type target_type)
+ {
+ return child.Reduce (inCheckedContext, target_type);
+ }
+
+ public override Constant Increment ()
+ {
+ return child.Increment ();
+ }
+
+ public override bool IsDefaultValue
+ {
+ get { return child.IsDefaultValue; }
+ }
+
+ public override bool IsNegative
+ {
+ get { return child.IsNegative; }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ child.Emit (ec);
+ }
+
+ public override Constant ToType (Type type)
+ {
+ return child.ToType (type);
+ }
+ }
+
+
+ /// <summary>
+ /// This class is used to wrap literals which belong inside Enums
+ /// </summary>
+ public class EnumConstant : Constant {
+ public Constant Child;
+
+ public EnumConstant (Constant child, Type enum_type):
+ base (child.Location)
+ {
+ eclass = child.eclass;
+ this.Child = child;
+ type = enum_type;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Child.Emit (ec);
+ }
+
+ public override bool GetAttributableValue (Type valueType, out object value)
+ {
+ value = GetTypedValue ();
+ return true;
+ }
+
+ public override string GetSignatureForError()
+ {
+ return TypeManager.CSharpName (Type);
+ }
+
+ public override object GetValue ()
+ {
+ return Child.GetValue ();
+ }
+
+ public override object GetTypedValue ()
+ {
+ // FIXME: runtime is not ready to work with just emited enums
+ if (!RootContext.StdLib) {
+ return Child.GetValue ();
+ }
+
+ return System.Enum.ToObject (type, Child.GetValue ());
+ }
+
+ public override string AsString ()
+ {
+ return Child.AsString ();
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return Child.ConvertToDouble ();
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return Child.ConvertToFloat ();
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return Child.ConvertToULong ();
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return Child.ConvertToLong ();
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return Child.ConvertToUInt ();
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return Child.ConvertToInt ();
+ }
+
+ public override Constant Increment()
+ {
+ return new EnumConstant (Child.Increment (), type);
+ }
+
+ public override bool IsDefaultValue {
+ get {
+ return Child.IsDefaultValue;
+ }
+ }
+
+ public override bool IsZeroInteger {
+ get { return Child.IsZeroInteger; }
+ }
+
+ public override bool IsNegative {
+ get {
+ return Child.IsNegative;
+ }
+ }
+
+ public override Constant Reduce(bool inCheckedContext, Type target_type)
+ {
+ if (Child.Type == target_type)
+ return Child;
+
+ return Child.Reduce (inCheckedContext, target_type);
+ }
+
+ public override Constant ToType (Type type)
+ {
+ if (Type == type) {
+ // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
+ if (TypeManager.IsEnumType (type.UnderlyingSystemType))
+ return this;
+
+ if (type.UnderlyingSystemType != Child.Type)
+ Child = Child.ToType (type.UnderlyingSystemType);
+ return this;
+ }
+
+ if (!Convert.ImplicitStandardConversionExists (this, type)){
+ return null;
+ }
+
+ return Child.ToType (type);
+ }
+
+ }
+
+ /// <summary>
+ /// This kind of cast is used to encapsulate Value Types in objects.
+ ///
+ /// The effect of it is to box the value type emitted by the previous
+ /// operation.
+ /// </summary>
+ public class BoxedCast : EmptyCast {
+
+ public BoxedCast (Expression expr, Type target_type)
+ : base (expr, target_type)
+ {
+ eclass = ExprClass.Value;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ base.Emit (ec);
+
+ ec.ig.Emit (OpCodes.Box, child.Type);
+ }
+ }
+
+ public class UnboxCast : EmptyCast {
+ public UnboxCast (Expression expr, Type return_type)
+ : base (expr, return_type)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
+ Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
+ return base.DoResolveLValue (ec, right_side);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Type t = type;
+ ILGenerator ig = ec.ig;
+
+ base.Emit (ec);
+#if GMCS_SOURCE
+ if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
+ ig.Emit (OpCodes.Unbox_Any, t);
+ else
+#endif
+ {
+ ig.Emit (OpCodes.Unbox, t);
+
+ LoadFromPtr (ig, t);
+ }
+ }
+ }
+
+ /// <summary>
+ /// This is used to perform explicit numeric conversions.
+ ///
+ /// Explicit numeric conversions might trigger exceptions in a checked
+ /// context, so they should generate the conv.ovf opcodes instead of
+ /// conv opcodes.
+ /// </summary>
+ public class ConvCast : EmptyCast {
+ public enum Mode : byte {
+ I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
+ U1_I1, U1_CH,
+ I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
+ U2_I1, U2_U1, U2_I2, U2_CH,
+ I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
+ U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
+ I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
+ U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
+ CH_I1, CH_U1, CH_I2,
+ R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
+ R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
+ }
+
+ Mode mode;
+
+ public ConvCast (Expression child, Type return_type, Mode m)
+ : base (child, return_type)
+ {
+ mode = m;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("ConvCast ({0}, {1})", mode, child);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ base.Emit (ec);
+
+ if (ec.CheckState){
+ switch (mode){
+ case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
+ case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
+ case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
+ case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+
+ case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
+ case Mode.U1_CH: /* nothing */ break;
+
+ case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
+ case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
+ case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
+ case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
+ case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+
+ case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
+ case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
+ case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
+ case Mode.U2_CH: /* nothing */ break;
+
+ case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
+ case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
+ case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
+ case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
+ case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
+ case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+
+ case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
+ case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
+ case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
+ case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
+ case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
+ case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
+
+ case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
+ case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
+ case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
+ case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
+ case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
+ case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
+ case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+
+ case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
+ case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
+ case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
+ case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
+ case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
+ case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
+ case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
+ case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
+
+ case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
+ case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
+ case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
+
+ case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
+ case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
+ case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
+ case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
+ case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
+ case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
+ case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
+ case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+
+ case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
+ case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
+ case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
+ case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
+ case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
+ case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
+ case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
+ case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
+ case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
+ }
+ } else {
+ switch (mode){
+ case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
+ case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
+ case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
+ case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
+ case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.U2_CH: /* nothing */ break;
+
+ case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.I4_U4: /* nothing */ break;
+ case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
+ case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.U4_I4: /* nothing */ break;
+ case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
+ case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
+ case Mode.I8_U8: /* nothing */ break;
+ case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
+ case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
+ case Mode.U8_I8: /* nothing */ break;
+ case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
+
+ case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
+ case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
+ case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
+ case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
+ case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
+
+ case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
+ case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
+ case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
+ case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
+ case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
+ case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
+ case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
+ case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
+ case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
+ }
+ }
+ }
+ }
+
+ public class OpcodeCast : EmptyCast {
+ OpCode op, op2;
+ bool second_valid;
+
+ public OpcodeCast (Expression child, Type return_type, OpCode op)
+ : base (child, return_type)
+
+ {
+ this.op = op;
+ second_valid = false;
+ }
+
+ public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
+ : base (child, return_type)
+
+ {
+ this.op = op;
+ this.op2 = op2;
+ second_valid = true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ base.Emit (ec);
+ ec.ig.Emit (op);
+
+ if (second_valid)
+ ec.ig.Emit (op2);
+ }
+ }
+
+ /// <summary>
+ /// This kind of cast is used to encapsulate a child and cast it
+ /// to the class requested
+ /// </summary>
+ public class ClassCast : EmptyCast {
+ public ClassCast (Expression child, Type return_type)
+ : base (child, return_type)
+
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ base.Emit (ec);
+
+ if (TypeManager.IsGenericParameter (child.Type))
+ ec.ig.Emit (OpCodes.Box, child.Type);
+
+#if GMCS_SOURCE
+ if (type.IsGenericParameter)
+ ec.ig.Emit (OpCodes.Unbox_Any, type);
+ else
+#endif
+ ec.ig.Emit (OpCodes.Castclass, type);
+ }
+ }
+
+ /// <summary>
+ /// SimpleName expressions are formed of a single word and only happen at the beginning
+ /// of a dotted-name.
+ /// </summary>
+ public class SimpleName : Expression {
+ public string Name;
+ public readonly TypeArguments Arguments;
+ bool in_transit;
+
+ public SimpleName (string name, Location l)
+ {
+ Name = name;
+ loc = l;
+ }
+
+ public SimpleName (string name, TypeArguments args, Location l)
+ {
+ Name = name;
+ Arguments = args;
+ loc = l;
+ }
+
+ public SimpleName (string name, TypeParameter[] type_params, Location l)
+ {
+ Name = name;
+ loc = l;
+
+ Arguments = new TypeArguments (l);
+ foreach (TypeParameter type_param in type_params)
+ Arguments.Add (new TypeParameterExpr (type_param, l));
+ }
+
+ public static string RemoveGenericArity (string name)
+ {
+ int start = 0;
+ StringBuilder sb = new StringBuilder ();
+ while (start < name.Length) {
+ int pos = name.IndexOf ('`', start);
+ if (pos < 0) {
+ sb.Append (name.Substring (start));
+ break;
+ }
+
+ sb.Append (name.Substring (start, pos-start));
+
+ pos++;
+ while ((pos < name.Length) && Char.IsNumber (name [pos]))
+ pos++;
+
+ start = pos;
+ }
+
+ return sb.ToString ();
+ }
+
+ public SimpleName GetMethodGroup ()
+ {
+ return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
+ }
+
+ public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
+ {
+ if (ec.IsFieldInitializer)
+ Report.Error (236, l,
+ "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
+ name);
+ else
+ Report.Error (
+ 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
+ name);
+ }
+
+ public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
+ {
+ return resolved_to != null && resolved_to.Type != null &&
+ resolved_to.Type.Name == Name &&
+ (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return SimpleNameResolve (ec, null, false);
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ return SimpleNameResolve (ec, right_side, false);
+ }
+
+
+ public Expression DoResolve (EmitContext ec, bool intermediate)
+ {
+ return SimpleNameResolve (ec, null, intermediate);
+ }
+
+ private bool IsNestedChild (Type t, Type parent)
+ {
+ if (parent == null)
+ return false;
+
+ while (parent != null) {
+ parent = TypeManager.DropGenericTypeArguments (parent);
+ if (TypeManager.IsNestedChildOf (t, parent))
+ return true;
+
+ parent = parent.BaseType;
+ }
+
+ return false;
+ }
+
+ FullNamedExpression ResolveNested (IResolveContext ec, Type t)
+ {
+ if (!TypeManager.IsGenericTypeDefinition (t))
+ return null;
+
+ DeclSpace ds = ec.DeclContainer;
+ while (ds != null) {
+ if (IsNestedChild (t, ds.TypeBuilder))
+ break;
+
+ ds = ds.Parent;
+ }
+
+ if (ds == null)
+ return null;
+
+ Type[] gen_params = TypeManager.GetTypeArguments (t);
+
+ int arg_count = Arguments != null ? Arguments.Count : 0;
+
+ for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
+ if (arg_count + ds.CountTypeParameters == gen_params.Length) {
+ TypeArguments new_args = new TypeArguments (loc);
+ foreach (TypeParameter param in ds.TypeParameters)
+ new_args.Add (new TypeParameterExpr (param, loc));
+
+ if (Arguments != null)
+ new_args.Add (Arguments);
+
+ return new ConstructedType (t, new_args, loc);
+ }
+ }
+
+ return null;
+ }
+
+ public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+ {
+ FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
+ if (fne != null)
+ return fne.ResolveAsTypeStep (ec, silent);
+
+ int errors = Report.Errors;
+ fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
+
+ if (fne != null) {
+ if (fne.Type == null)
+ return fne;
+
+ FullNamedExpression nested = ResolveNested (ec, fne.Type);
+ if (nested != null)
+ return nested.ResolveAsTypeStep (ec, false);
+
+ if (Arguments != null) {
+ ConstructedType ct = new ConstructedType (fne, Arguments, loc);
+ return ct.ResolveAsTypeStep (ec, false);
+ }
+
+ return fne;
+ }
+
+ if (silent || errors != Report.Errors)
+ return null;
+
+ MemberCore mc = ec.DeclContainer.GetDefinition (Name);
+ if (mc != null) {
+ Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
+ return null;
+ }
+
+ string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
+ string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
+ foreach (Assembly a in RootNamespace.Global.Assemblies) {
+ Type type = a.GetType (fullname);
+ if (type != null) {
+ Report.SymbolRelatedToPreviousError (type);
+ Expression.ErrorIsInaccesible (loc, fullname);
+ return null;
+ }
+ }
+
+ Type t = ec.DeclContainer.NamespaceEntry.NS.LookForAnyGenericType (Name);
+ if (t != null) {
+ Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
+ return null;
+ }
+
+ NamespaceEntry.Error_NamespaceNotFound (loc, Name);
+ return null;
+ }
+
+ // TODO: I am still not convinced about this. If someone else will need it
+ // implement this as virtual property in MemberCore hierarchy
+ string GetMemberType (MemberCore mc)
+ {
+ if (mc is PropertyBase)
+ return "property";
+ if (mc is Indexer)
+ return "indexer";
+ if (mc is FieldBase)
+ return "field";
+ if (mc is MethodCore)
+ return "method";
+ if (mc is EnumMember)
+ return "enum";
+
+ return "type";
+ }
+
+ Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
+ {
+ if (in_transit)
+ return null;
+ in_transit = true;
+
+ Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
+ if (e == null)
+ return null;
+
+ if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
+ return e;
+
+ return null;
+ }
+
+ /// <remarks>
+ /// 7.5.2: Simple Names.
+ ///
+ /// Local Variables and Parameters are handled at
+ /// parse time, so they never occur as SimpleNames.
+ ///
+ /// The `intermediate' flag is used by MemberAccess only
+ /// and it is used to inform us that it is ok for us to
+ /// avoid the static check, because MemberAccess might end
+ /// up resolving the Name as a Type name and the access as
+ /// a static type access.
+ ///
+ /// ie: Type Type; .... { Type.GetType (""); }
+ ///
+ /// Type is both an instance variable and a Type; Type.GetType
+ /// is the static method not an instance method of type.
+ /// </remarks>
+ Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
+ {
+ Expression e = null;
+
+ //
+ // Stage 1: Performed by the parser (binding to locals or parameters).
+ //
+ Block current_block = ec.CurrentBlock;
+ if (current_block != null){
+ LocalInfo vi = current_block.GetLocalInfo (Name);
+ if (vi != null){
+ if (Arguments != null) {
+ Report.Error (307, loc,
+ "The variable `{0}' cannot be used with type arguments",
+ Name);
+ return null;
+ }
+
+ LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
+ if (right_side != null) {
+ return var.ResolveLValue (ec, right_side, loc);
+ } else {
+ ResolveFlags rf = ResolveFlags.VariableOrValue;
+ if (intermediate)
+ rf |= ResolveFlags.DisableFlowAnalysis;
+ return var.Resolve (ec, rf);
+ }
+ }
+
+ ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
+ if (pref != null) {
+ if (Arguments != null) {
+ Report.Error (307, loc,
+ "The variable `{0}' cannot be used with type arguments",
+ Name);
+ return null;
+ }
+
+ if (right_side != null)
+ return pref.ResolveLValue (ec, right_side, loc);
+ else
+ return pref.Resolve (ec);
+ }
+ }
+
+ //
+ // Stage 2: Lookup members
+ //
+
+ DeclSpace lookup_ds = ec.DeclContainer;
+ Type almost_matched_type = null;
+ ArrayList almost_matched = null;
+ do {
+ if (lookup_ds.TypeBuilder == null)
+ break;
+
+ e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
+ if (e != null)
+ break;
+
+ if (almost_matched == null && almostMatchedMembers.Count > 0) {
+ almost_matched_type = lookup_ds.TypeBuilder;
+ almost_matched = (ArrayList) almostMatchedMembers.Clone ();
+ }
+
+ lookup_ds =lookup_ds.Parent;
+ } while (lookup_ds != null);
+
+ if (e == null && ec.ContainerType != null)
+ e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
+
+ if (e == null) {
+ if (almost_matched == null && almostMatchedMembers.Count > 0) {
+ almost_matched_type = ec.ContainerType;
+ almost_matched = (ArrayList) almostMatchedMembers.Clone ();
+ }
+ e = ResolveAsTypeStep (ec, true);
+ }
+
+ if (e == null) {
+ if (almost_matched != null)
+ almostMatchedMembers = almost_matched;
+ if (almost_matched_type == null)
+ almost_matched_type = ec.ContainerType;
+ MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
+ return null;
+ }
+
+ if (e is TypeExpr) {
+ if (Arguments == null)
+ return e;
+
+ ConstructedType ct = new ConstructedType (
+ (FullNamedExpression) e, Arguments, loc);
+ return ct.ResolveAsTypeStep (ec, false);
+ }
+
+ if (e is MemberExpr) {
+ MemberExpr me = (MemberExpr) e;
+
+ Expression left;
+ if (me.IsInstance) {
+ if (ec.IsStatic || ec.IsFieldInitializer) {
+ //
+ // Note that an MemberExpr can be both IsInstance and IsStatic.
+ // An unresolved MethodGroupExpr can contain both kinds of methods
+ // and each predicate is true if the MethodGroupExpr contains
+ // at least one of that kind of method.
+ //
+
+ if (!me.IsStatic &&
+ (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
+ Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
+ return EmptyExpression.Null;
+ }
+
+ //
+ // Pass the buck to MemberAccess and Invocation.
+ //
+ left = EmptyExpression.Null;
+ } else {
+ left = ec.GetThis (loc);
+ }
+ } else {
+ left = new TypeExpression (ec.ContainerType, loc);
+ }
+
+ e = me.ResolveMemberAccess (ec, left, loc, null);
+ if (e == null)
+ return null;
+
+ me = e as MemberExpr;
+ if (me == null)
+ return e;
+
+ if (Arguments != null) {
+ MethodGroupExpr mg = me as MethodGroupExpr;
+ if (mg == null)
+ return null;
+
+ return mg.ResolveGeneric (ec, Arguments);
+ }
+
+ if (!me.IsStatic && (me.InstanceExpression != null) &&
+ TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
+ me.InstanceExpression.Type != me.DeclaringType &&
+ !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
+ (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
+ Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
+ TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
+ return null;
+ }
+
+ return (right_side != null)
+ ? me.DoResolveLValue (ec, right_side)
+ : me.DoResolve (ec);
+ }
+
+ return e;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // If this is ever reached, then we failed to
+ // find the name as a namespace
+ //
+
+ Error (103, "The name `" + Name +
+ "' does not exist in the class `" +
+ ec.DeclContainer.Name + "'");
+ }
+
+ public override string ToString ()
+ {
+ return Name;
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return Name;
+ }
+ }
+
+ /// <summary>
+ /// Represents a namespace or a type. The name of the class was inspired by
+ /// section 10.8.1 (Fully Qualified Names).
+ /// </summary>
+ public abstract class FullNamedExpression : Expression {
+ public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+ {
+ return this;
+ }
+
+ public abstract string FullName {
+ get;
+ }
+ }
+
+ /// <summary>
+ /// Expression that evaluates to a type
+ /// </summary>
+ public abstract class TypeExpr : FullNamedExpression {
+ override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
+ {
+ TypeExpr t = DoResolveAsTypeStep (ec);
+ if (t == null)
+ return null;
+
+ eclass = ExprClass.Type;
+ return t;
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ return ResolveAsTypeTerminal (ec, false);
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be called");
+ }
+
+ public virtual bool CheckAccessLevel (DeclSpace ds)
+ {
+ return ds.CheckAccessLevel (Type);
+ }
+
+ public virtual bool AsAccessible (DeclSpace ds, int flags)
+ {
+ return ds.AsAccessible (Type, flags);
+ }
+
+ public virtual bool IsClass {
+ get { return Type.IsClass; }
+ }
+
+ public virtual bool IsValueType {
+ get { return Type.IsValueType; }
+ }
+
+ public virtual bool IsInterface {
+ get { return Type.IsInterface; }
+ }
+
+ public virtual bool IsSealed {
+ get { return Type.IsSealed; }
+ }
+
+ public virtual bool CanInheritFrom ()
+ {
+ if (Type == TypeManager.enum_type ||
+ (Type == TypeManager.value_type && RootContext.StdLib) ||
+ Type == TypeManager.multicast_delegate_type ||
+ Type == TypeManager.delegate_type ||
+ Type == TypeManager.array_type)
+ return false;
+
+ return true;
+ }
+
+ protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
+
+ public abstract string Name {
+ get;
+ }
+
+ public override bool Equals (object obj)
+ {
+ TypeExpr tobj = obj as TypeExpr;
+ if (tobj == null)
+ return false;
+
+ return Type == tobj.Type;
+ }
+
+ public override int GetHashCode ()
+ {
+ return Type.GetHashCode ();
+ }
+
+ public override string ToString ()
+ {
+ return Name;
+ }
+ }
+
+ /// <summary>
+ /// Fully resolved Expression that already evaluated to a type
+ /// </summary>
+ public class TypeExpression : TypeExpr {
+ public TypeExpression (Type t, Location l)
+ {
+ Type = t;
+ eclass = ExprClass.Type;
+ loc = l;
+ }
+
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
+ {
+ return this;
+ }
+
+ public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
+ {
+ return this;
+ }
+
+ public override string Name {
+ get { return Type.ToString (); }
+ }
+
+ public override string FullName {
+ get { return Type.FullName; }
+ }
+ }
+
+ /// <summary>
+ /// Used to create types from a fully qualified name. These are just used
+ /// by the parser to setup the core types. A TypeLookupExpression is always
+ /// classified as a type.
+ /// </summary>
+ public sealed class TypeLookupExpression : TypeExpr {
+ readonly string name;
+
+ public TypeLookupExpression (string name)
+ {
+ this.name = name;
+ eclass = ExprClass.Type;
+ }
+
+ public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
+ {
+ // It's null for corlib compilation only
+ if (type == null)
+ return DoResolveAsTypeStep (ec);
+
+ return this;
+ }
+
+ static readonly char [] dot_array = { '.' };
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
+ {
+ // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
+ string rest = null;
+ string lookup_name = name;
+ int pos = name.IndexOf ('.');
+ if (pos >= 0) {
+ rest = name.Substring (pos + 1);
+ lookup_name = name.Substring (0, pos);
+ }
+
+ FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
+
+ if (resolved != null && rest != null) {
+ // Now handle the rest of the the name.
+ string [] elements = rest.Split (dot_array);
+ string element;
+ int count = elements.Length;
+ int i = 0;
+ while (i < count && resolved != null && resolved is Namespace) {
+ Namespace ns = resolved as Namespace;
+ element = elements [i++];
+ lookup_name += "." + element;
+ resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
+ }
+
+ if (resolved != null && resolved is TypeExpr) {
+ Type t = ((TypeExpr) resolved).Type;
+ while (t != null) {
+ if (!ec.DeclContainer.CheckAccessLevel (t)) {
+ resolved = null;
+ lookup_name = t.FullName;
+ break;
+ }
+ if (i == count) {
+ type = t;
+ return this;
+ }
+ t = TypeManager.GetNestedType (t, elements [i++]);
+ }
+ }
+ }
+
+ if (resolved == null) {
+ NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
+ return null;
+ }
+
+ if (!(resolved is TypeExpr)) {
+ resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
+ return null;
+ }
+
+ type = resolved.Type;
+ return this;
+ }
+
+ public override string Name {
+ get { return name; }
+ }
+
+ public override string FullName {
+ get { return name; }
+ }
+ }
+
+ /// <summary>
+ /// Represents an "unbound generic type", ie. typeof (Foo<>).
+ /// See 14.5.11.
+ /// </summary>
+ public class UnboundTypeExpression : TypeExpr
+ {
+ MemberName name;
+
+ public UnboundTypeExpression (MemberName name, Location l)
+ {
+ this.name = name;
+ loc = l;
+ }
+
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
+ {
+ Expression expr;
+ if (name.Left != null) {
+ Expression lexpr = name.Left.GetTypeExpression ();
+ expr = new MemberAccess (lexpr, name.Basename);
+ } else {
+ expr = new SimpleName (name.Basename, loc);
+ }
+
+ FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
+ if (fne == null)
+ return null;
+
+ type = fne.Type;
+ return new TypeExpression (type, loc);
+ }
+
+ public override string Name {
+ get { return name.FullName; }
+ }
+
+ public override string FullName {
+ get { return name.FullName; }
+ }
+ }
+
+ public class TypeAliasExpression : TypeExpr {
+ FullNamedExpression alias;
+ TypeExpr texpr;
+ TypeArguments args;
+ string name;
+
+ public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
+ {
+ this.alias = alias;
+ this.args = args;
+ loc = l;
+
+ eclass = ExprClass.Type;
+ if (args != null)
+ name = alias.FullName + "<" + args.ToString () + ">";
+ else
+ name = alias.FullName;
+ }
+
+ public override string Name {
+ get { return alias.FullName; }
+ }
+
+ public override string FullName {
+ get { return name; }
+ }
+
+ protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
+ {
+ texpr = alias.ResolveAsTypeTerminal (ec, false);
+ if (texpr == null)
+ return null;
+
+ Type type = texpr.Type;
+ int num_args = TypeManager.GetNumberOfTypeArguments (type);
+
+ if (args != null) {
+ if (num_args == 0) {
+ Report.Error (308, loc,
+ "The non-generic type `{0}' cannot " +
+ "be used with type arguments.",
+ TypeManager.CSharpName (type));
+ return null;
+ }
+
+ ConstructedType ctype = new ConstructedType (type, args, loc);
+ return ctype.ResolveAsTypeTerminal (ec, false);
+ } else if (num_args > 0) {
+ Report.Error (305, loc,
+ "Using the generic type `{0}' " +
+ "requires {1} type arguments",
+ TypeManager.CSharpName (type), num_args.ToString ());
+ return null;
+ }
+
+ return texpr;
+ }
+
+ public override bool CheckAccessLevel (DeclSpace ds)
+ {
+ return texpr.CheckAccessLevel (ds);
+ }
+
+ public override bool AsAccessible (DeclSpace ds, int flags)
+ {
+ return texpr.AsAccessible (ds, flags);
+ }
+
+ public override bool IsClass {
+ get { return texpr.IsClass; }
+ }
+
+ public override bool IsValueType {
+ get { return texpr.IsValueType; }
+ }
+
+ public override bool IsInterface {
+ get { return texpr.IsInterface; }
+ }
+
+ public override bool IsSealed {
+ get { return texpr.IsSealed; }
+ }
+ }
+
+ /// <summary>
+ /// This class denotes an expression which evaluates to a member
+ /// of a struct or a class.
+ /// </summary>
+ public abstract class MemberExpr : Expression
+ {
+ /// <summary>
+ /// The name of this member.
+ /// </summary>
+ public abstract string Name {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is an instance member.
+ /// </summary>
+ public abstract bool IsInstance {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is a static member.
+ /// </summary>
+ public abstract bool IsStatic {
+ get;
+ }
+
+ /// <summary>
+ /// The type which declares this member.
+ /// </summary>
+ public abstract Type DeclaringType {
+ get;
+ }
+
+ /// <summary>
+ /// The instance expression associated with this member, if it's a
+ /// non-static member.
+ /// </summary>
+ public Expression InstanceExpression;
+
+ public static void error176 (Location loc, string name)
+ {
+ Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
+ "with an instance reference, qualify it with a type name instead", name);
+ }
+
+ // TODO: possible optimalization
+ // Cache resolved constant result in FieldBuilder <-> expression map
+ public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ //
+ // Precondition:
+ // original == null || original.Resolve (...) ==> left
+ //
+
+ if (left is TypeExpr) {
+ if (!IsStatic) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
+ return null;
+ }
+
+ return this;
+ }
+
+ if (!IsInstance) {
+ if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
+ return this;
+
+ error176 (loc, GetSignatureForError ());
+ return null;
+ }
+
+ InstanceExpression = left;
+
+ return this;
+ }
+
+ protected void EmitInstance (EmitContext ec, bool prepare_for_load)
+ {
+ if (IsStatic)
+ return;
+
+ if (InstanceExpression == EmptyExpression.Null) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
+ return;
+ }
+
+ if (InstanceExpression.Type.IsValueType) {
+ if (InstanceExpression is IMemoryLocation) {
+ ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
+ } else {
+ LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
+ InstanceExpression.Emit (ec);
+ t.Store (ec);
+ t.AddressOf (ec, AddressOp.Store);
+ }
+ } else
+ InstanceExpression.Emit (ec);
+
+ if (prepare_for_load)
+ ec.ig.Emit (OpCodes.Dup);
+ }
+ }
+
+ /// <summary>
+ /// MethodGroup Expression.
+ ///
+ /// This is a fully resolved expression that evaluates to a type
+ /// </summary>
+ public class MethodGroupExpr : MemberExpr {
+ public MethodBase [] Methods;
+ bool has_type_arguments = false;
+ bool identical_type_name = false;
+ bool is_base;
+
+ public MethodGroupExpr (MemberInfo [] mi, Location l)
+ {
+ Methods = new MethodBase [mi.Length];
+ mi.CopyTo (Methods, 0);
+ eclass = ExprClass.MethodGroup;
+ type = TypeManager.object_type;
+ loc = l;
+ }
+
+ public MethodGroupExpr (ArrayList list, Location l)
+ {
+ Methods = new MethodBase [list.Count];
+
+ try {
+ list.CopyTo (Methods, 0);
+ } catch {
+ foreach (MemberInfo m in list){
+ if (!(m is MethodBase)){
+ Console.WriteLine ("Name " + m.Name);
+ Console.WriteLine ("Found a: " + m.GetType ().FullName);
+ }
+ }
+ throw;
+ }
+
+ loc = l;
+ eclass = ExprClass.MethodGroup;
+ type = TypeManager.object_type;
+ }
+
+ public override Type DeclaringType {
+ get {
+ //
+ // We assume that the top-level type is in the end
+ //
+ return Methods [Methods.Length - 1].DeclaringType;
+ //return Methods [0].DeclaringType;
+ }
+ }
+
+ public bool HasTypeArguments {
+ get {
+ return has_type_arguments;
+ }
+
+ set {
+ has_type_arguments = value;
+ }
+ }
+
+ public bool IdenticalTypeName {
+ get {
+ return identical_type_name;
+ }
+
+ set {
+ identical_type_name = value;
+ }
+ }
+
+ public bool IsBase {
+ get {
+ return is_base;
+ }
+ set {
+ is_base = value;
+ }
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return TypeManager.CSharpSignature (Methods [0]);
+ }
+
+ public override string Name {
+ get {
+ return Methods [0].Name;
+ }
+ }
+
+ public override bool IsInstance {
+ get {
+ foreach (MethodBase mb in Methods)
+ if (!mb.IsStatic)
+ return true;
+
+ return false;
+ }
+ }
+
+ public override bool IsStatic {
+ get {
+ foreach (MethodBase mb in Methods)
+ if (mb.IsStatic)
+ return true;
+
+ return false;
+ }
+ }
+
+ public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ if (!(left is TypeExpr) &&
+ original != null && original.IdenticalNameAndTypeName (ec, left, loc))
+ IdenticalTypeName = true;
+
+ return base.ResolveMemberAccess (ec, left, loc, original);
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (!IsInstance)
+ InstanceExpression = null;
+
+ if (InstanceExpression != null) {
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (InstanceExpression == null)
+ return null;
+ }
+
+ return this;
+ }
+
+ public void ReportUsageError ()
+ {
+ Report.Error (654, loc, "Method `" + DeclaringType + "." +
+ Name + "()' is referenced without parentheses");
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ ReportUsageError ();
+ }
+
+ bool RemoveMethods (bool keep_static)
+ {
+ ArrayList smethods = new ArrayList ();
+
+ foreach (MethodBase mb in Methods){
+ if (mb.IsStatic == keep_static)
+ smethods.Add (mb);
+ }
+
+ if (smethods.Count == 0)
+ return false;
+
+ Methods = new MethodBase [smethods.Count];
+ smethods.CopyTo (Methods, 0);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Removes any instance methods from the MethodGroup, returns
+ /// false if the resulting set is empty.
+ /// </summary>
+ public bool RemoveInstanceMethods ()
+ {
+ return RemoveMethods (true);
+ }
+
+ /// <summary>
+ /// Removes any static methods from the MethodGroup, returns
+ /// false if the resulting set is empty.
+ /// </summary>
+ public bool RemoveStaticMethods ()
+ {
+ return RemoveMethods (false);
+ }
+
+ public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
+ {
+#if GMCS_SOURCE
+ if (args.Resolve (ec) == false)
+ return null;
+
+ Type[] atypes = args.Arguments;
+
+ int first_count = 0;
+ MethodInfo first = null;
+
+ ArrayList list = new ArrayList ();
+ foreach (MethodBase mb in Methods) {
+ MethodInfo mi = mb as MethodInfo;
+ if ((mi == null) || !mi.IsGenericMethod)
+ continue;
+
+ Type[] gen_params = mi.GetGenericArguments ();
+
+ if (first == null) {
+ first = mi;
+ first_count = gen_params.Length;
+ }
+
+ if (gen_params.Length != atypes.Length)
+ continue;
+
+ list.Add (mi.MakeGenericMethod (atypes));
+ }
+
+ if (list.Count > 0) {
+ MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
+ new_mg.InstanceExpression = InstanceExpression;
+ new_mg.HasTypeArguments = true;
+ new_mg.IsBase = IsBase;
+ return new_mg;
+ }
+
+ if (first != null)
+ Report.Error (
+ 305, loc, "Using the generic method `{0}' " +
+ "requires {1} type arguments", Name,
+ first_count.ToString ());
+ else
+ Report.Error (
+ 308, loc, "The non-generic method `{0}' " +
+ "cannot be used with type arguments", Name);
+
+ return null;
+#else
+ throw new NotImplementedException ();
+#endif
+ }
+ }
+
+ /// <summary>
+ /// Fully resolved expression that evaluates to a Field
+ /// </summary>
+ public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
+ public readonly FieldInfo FieldInfo;
+ VariableInfo variable_info;
+
+ LocalTemporary temp;
+ bool prepared;
+ bool in_initializer;
+
+ public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
+ this (fi, l)
+ {
+ this.in_initializer = in_initializer;
+ }
+
+ public FieldExpr (FieldInfo fi, Location l)
+ {
+ FieldInfo = fi;
+ eclass = ExprClass.Variable;
+ type = TypeManager.TypeToCoreType (fi.FieldType);
+ loc = l;
+ }
+
+ public override string Name {
+ get {
+ return FieldInfo.Name;
+ }
+ }
+
+ public override bool IsInstance {
+ get {
+ return !FieldInfo.IsStatic;
+ }
+ }
+
+ public override bool IsStatic {
+ get {
+ return FieldInfo.IsStatic;
+ }
+ }
+
+ public override Type DeclaringType {
+ get {
+ return FieldInfo.DeclaringType;
+ }
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return TypeManager.GetFullNameSignature (FieldInfo);
+ }
+
+ public VariableInfo VariableInfo {
+ get {
+ return variable_info;
+ }
+ }
+
+ public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
+
+ Type t = fi.FieldType;
+
+ if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
+ IConstant ic = TypeManager.GetConstant (fi);
+ if (ic == null) {
+ if (fi.IsLiteral) {
+ ic = new ExternalConstant (fi);
+ } else {
+ ic = ExternalConstant.CreateDecimal (fi);
+ if (ic == null) {
+ return base.ResolveMemberAccess (ec, left, loc, original);
+ }
+ }
+ TypeManager.RegisterConstant (fi, ic);
+ }
+
+ bool left_is_type = left is TypeExpr;
+ if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
+ Report.SymbolRelatedToPreviousError (FieldInfo);
+ error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
+ return null;
+ }
+
+ if (ic.ResolveValue ()) {
+ if (!ec.IsInObsoleteScope)
+ ic.CheckObsoleteness (loc);
+ }
+
+ return ic.Value;
+ }
+
+ if (t.IsPointer && !ec.InUnsafe) {
+ UnsafeError (loc);
+ return null;
+ }
+
+ return base.ResolveMemberAccess (ec, left, loc, original);
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ return DoResolve (ec, false, false);
+ }
+
+ Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
+ {
+ if (!FieldInfo.IsStatic){
+ if (InstanceExpression == null){
+ //
+ // This can happen when referencing an instance field using
+ // a fully qualified type expression: TypeName.InstanceField = xxx
+ //
+ SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
+ return null;
+ }
+
+ // Resolve the field's instance expression while flow analysis is turned
+ // off: when accessing a field "a.b", we must check whether the field
+ // "a.b" is initialized, not whether the whole struct "a" is initialized.
+
+ if (lvalue_instance) {
+ using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
+ Expression right_side =
+ out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
+ InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
+ }
+ } else {
+ ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
+ InstanceExpression = InstanceExpression.Resolve (ec, rf);
+ }
+
+ if (InstanceExpression == null)
+ return null;
+
+ InstanceExpression.CheckMarshalByRefAccess ();
+ }
+
+ if (!in_initializer && !ec.IsFieldInitializer) {
+ ObsoleteAttribute oa;
+ FieldBase f = TypeManager.GetField (FieldInfo);
+ if (f != null) {
+ if (!ec.IsInObsoleteScope)
+ f.CheckObsoleteness (loc);
+
+ // To be sure that type is external because we do not register generated fields
+ } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
+ oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
+ if (oa != null)
+ AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
+ }
+ }
+
+ AnonymousContainer am = ec.CurrentAnonymousMethod;
+ if (am != null){
+ if (!FieldInfo.IsStatic){
+ if (!am.IsIterator && (ec.TypeContainer is Struct)){
+ Report.Error (1673, loc,
+ "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead",
+ "this");
+ return null;
+ }
+ }
+ }
+
+ // If the instance expression is a local variable or parameter.
+ IVariable var = InstanceExpression as IVariable;
+ if ((var == null) || (var.VariableInfo == null))
+ return this;
+
+ VariableInfo vi = var.VariableInfo;
+ if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
+ return null;
+
+ variable_info = vi.GetSubStruct (FieldInfo.Name);
+ return this;
+ }
+
+ static readonly int [] codes = {
+ 191, // instance, write access
+ 192, // instance, out access
+ 198, // static, write access
+ 199, // static, out access
+ 1648, // member of value instance, write access
+ 1649, // member of value instance, out access
+ 1650, // member of value static, write access
+ 1651 // member of value static, out access
+ };
+
+ static readonly string [] msgs = {
+ /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
+ /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
+ /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
+ /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
+ /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
+ /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
+ /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
+ /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
+ };
+
+ // The return value is always null. Returning a value simplifies calling code.
+ Expression Report_AssignToReadonly (Expression right_side)
+ {
+ int i = 0;
+ if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
+ i += 1;
+ if (IsStatic)
+ i += 2;
+ if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
+ i += 4;
+ Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
+
+ return null;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ IVariable var = InstanceExpression as IVariable;
+ if ((var != null) && (var.VariableInfo != null))
+ var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
+
+ bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
+ bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
+
+ Expression e = DoResolve (ec, lvalue_instance, out_access);
+
+ if (e == null)
+ return null;
+
+ FieldBase fb = TypeManager.GetField (FieldInfo);
+ if (fb != null)
+ fb.SetAssigned ();
+
+ if (FieldInfo.IsInitOnly) {
+ // InitOnly fields can only be assigned in constructors or initializers
+ if (!ec.IsFieldInitializer && !ec.IsConstructor)
+ return Report_AssignToReadonly (right_side);
+
+ if (ec.IsConstructor) {
+ Type ctype = ec.TypeContainer.CurrentType;
+ if (ctype == null)
+ ctype = ec.ContainerType;
+
+ // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
+ if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
+ return Report_AssignToReadonly (right_side);
+ // static InitOnly fields cannot be assigned-to in an instance constructor
+ if (IsStatic && !ec.IsStatic)
+ return Report_AssignToReadonly (right_side);
+ // instance constructors can't modify InitOnly fields of other instances of the same type
+ if (!IsStatic && !(InstanceExpression is This))
+ return Report_AssignToReadonly (right_side);
+ }
+ }
+
+ if (right_side == EmptyExpression.OutAccess &&
+ !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
+ Report.SymbolRelatedToPreviousError (DeclaringType);
+ Report.Warning (197, 1, loc,
+ "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
+ GetSignatureForError ());
+ }
+
+ return this;
+ }
+
+ public override void CheckMarshalByRefAccess ()
+ {
+ if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
+ Report.SymbolRelatedToPreviousError (DeclaringType);
+ Report.Warning (1690, 1, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
+ GetSignatureForError ());
+ }
+ }
+
+ public bool VerifyFixed ()
+ {
+ IVariable variable = InstanceExpression as IVariable;
+ // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
+ // We defer the InstanceExpression check after the variable check to avoid a
+ // separate null check on InstanceExpression.
+ return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
+ }
+
+ public override int GetHashCode ()
+ {
+ return FieldInfo.GetHashCode ();
+ }
+
+ public override bool Equals (object obj)
+ {
+ FieldExpr fe = obj as FieldExpr;
+ if (fe == null)
+ return false;
+
+ if (FieldInfo != fe.FieldInfo)
+ return false;
+
+ if (InstanceExpression == null || fe.InstanceExpression == null)
+ return true;
+
+ return InstanceExpression.Equals (fe.InstanceExpression);
+ }
+
+ public void Emit (EmitContext ec, bool leave_copy)
+ {
+ ILGenerator ig = ec.ig;
+ bool is_volatile = false;
+
+ FieldBase f = TypeManager.GetField (FieldInfo);
+ if (f != null){
+ if ((f.ModFlags & Modifiers.VOLATILE) != 0)
+ is_volatile = true;
+
+ f.SetMemberIsUsed ();
+ }
+
+ if (FieldInfo.IsStatic){
+ if (is_volatile)
+ ig.Emit (OpCodes.Volatile);
+
+ ig.Emit (OpCodes.Ldsfld, FieldInfo);
+ } else {
+ if (!prepared)
+ EmitInstance (ec, false);
+
+ if (is_volatile)
+ ig.Emit (OpCodes.Volatile);
+
+ IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
+ if (ff != null)
+ {
+ ig.Emit (OpCodes.Ldflda, FieldInfo);
+ ig.Emit (OpCodes.Ldflda, ff.Element);
+ }
+ else {
+ ig.Emit (OpCodes.Ldfld, FieldInfo);
+ }
+ }
+
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (!FieldInfo.IsStatic) {
+ temp = new LocalTemporary (this.Type);
+ temp.Store (ec);
+ }
+ }
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ {
+ FieldAttributes fa = FieldInfo.Attributes;
+ bool is_static = (fa & FieldAttributes.Static) != 0;
+ bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
+ ILGenerator ig = ec.ig;
+ prepared = prepare_for_load;
+
+ if (is_readonly && !ec.IsConstructor){
+ Report_AssignToReadonly (source);
+ return;
+ }
+
+ EmitInstance (ec, prepare_for_load);
+
+ source.Emit (ec);
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (!FieldInfo.IsStatic) {
+ temp = new LocalTemporary (this.Type);
+ temp.Store (ec);
+ }
+ }
+
+ FieldBase f = TypeManager.GetField (FieldInfo);
+ if (f != null){
+ if ((f.ModFlags & Modifiers.VOLATILE) != 0)
+ ig.Emit (OpCodes.Volatile);
+
+ f.SetAssigned ();
+ }
+
+ if (is_static)
+ ig.Emit (OpCodes.Stsfld, FieldInfo);
+ else
+ ig.Emit (OpCodes.Stfld, FieldInfo);
+
+ if (temp != null) {
+ temp.Emit (ec);
+ temp.Release (ec);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ILGenerator ig = ec.ig;
+
+ FieldBase f = TypeManager.GetField (FieldInfo);
+ if (f != null){
+ if ((f.ModFlags & Modifiers.VOLATILE) != 0){
+ Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
+ f.GetSignatureForError ());
+ return;
+ }
+
+ if ((mode & AddressOp.Store) != 0)
+ f.SetAssigned ();
+ if ((mode & AddressOp.Load) != 0)
+ f.SetMemberIsUsed ();
+ }
+
+ //
+ // Handle initonly fields specially: make a copy and then
+ // get the address of the copy.
+ //
+ bool need_copy;
+ if (FieldInfo.IsInitOnly){
+ need_copy = true;
+ if (ec.IsConstructor){
+ if (FieldInfo.IsStatic){
+ if (ec.IsStatic)
+ need_copy = false;
+ } else
+ need_copy = false;
+ }
+ } else
+ need_copy = false;
+
+ if (need_copy){
+ LocalBuilder local;
+ Emit (ec);
+ local = ig.DeclareLocal (type);
+ ig.Emit (OpCodes.Stloc, local);
+ ig.Emit (OpCodes.Ldloca, local);
+ return;
+ }
+
+
+ if (FieldInfo.IsStatic){
+ ig.Emit (OpCodes.Ldsflda, FieldInfo);
+ } else {
+ if (!prepared)
+ EmitInstance (ec, false);
+ ig.Emit (OpCodes.Ldflda, FieldInfo);
+ }
+ }
+ }
+
+ //
+ // A FieldExpr whose address can not be taken
+ //
+ public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
+ public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
+ {
+ }
+
+ public new void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
+ }
+ }
+
+ /// <summary>
+ /// Expression that evaluates to a Property. The Assign class
+ /// might set the `Value' expression if we are in an assignment.
+ ///
+ /// This is not an LValue because we need to re-write the expression, we
+ /// can not take data from the stack and store it.
+ /// </summary>
+ public class PropertyExpr : MemberExpr, IAssignMethod {
+ public readonly PropertyInfo PropertyInfo;
+
+ //
+ // This is set externally by the `BaseAccess' class
+ //
+ public bool IsBase;
+ MethodInfo getter, setter;
+ bool is_static;
+
+ bool resolved;
+
+ LocalTemporary temp;
+ bool prepared;
+
+ internal static PtrHashtable AccessorTable = new PtrHashtable ();
+
+ public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
+ {
+ PropertyInfo = pi;
+ eclass = ExprClass.PropertyAccess;
+ is_static = false;
+ loc = l;
+
+ type = TypeManager.TypeToCoreType (pi.PropertyType);
+
+ ResolveAccessors (containerType);
+ }
+
+ public override string Name {
+ get {
+ return PropertyInfo.Name;
+ }
+ }
+
+ public override bool IsInstance {
+ get {
+ return !is_static;
+ }
+ }
+
+ public override bool IsStatic {
+ get {
+ return is_static;
+ }
+ }
+
+ public override Type DeclaringType {
+ get {
+ return PropertyInfo.DeclaringType;
+ }
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return TypeManager.GetFullNameSignature (PropertyInfo);
+ }
+
+ void FindAccessors (Type invocation_type)
+ {
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly;
+
+ Type current = PropertyInfo.DeclaringType;
+ for (; current != null; current = current.BaseType) {
+ MemberInfo[] group = TypeManager.MemberLookup (
+ invocation_type, invocation_type, current,
+ MemberTypes.Property, flags, PropertyInfo.Name, null);
+
+ if (group == null)
+ continue;
+
+ if (group.Length != 1)
+ // Oooops, can this ever happen ?
+ return;
+
+ PropertyInfo pi = (PropertyInfo) group [0];
+
+ if (getter == null)
+ getter = pi.GetGetMethod (true);
+
+ if (setter == null)
+ setter = pi.GetSetMethod (true);
+
+ MethodInfo accessor = getter != null ? getter : setter;
+
+ if (!accessor.IsVirtual)
+ return;
+ }
+ }
+
+ //
+ // We also perform the permission checking here, as the PropertyInfo does not
+ // hold the information for the accessibility of its setter/getter
+ //
+ // TODO: can use TypeManager.GetProperty to boost performance
+ void ResolveAccessors (Type containerType)
+ {
+ FindAccessors (containerType);
+
+ if (getter != null) {
+ MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
+ IMethodData md = TypeManager.GetMethod (the_getter);
+ if (md != null)
+ md.SetMemberIsUsed ();
+
+ AccessorTable [getter] = PropertyInfo;
+ is_static = getter.IsStatic;
+ }
+
+ if (setter != null) {
+ MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
+ IMethodData md = TypeManager.GetMethod (the_setter);
+ if (md != null)
+ md.SetMemberIsUsed ();
+
+ AccessorTable [setter] = PropertyInfo;
+ is_static = setter.IsStatic;
+ }
+ }
+
+ bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
+ {
+ if (is_static) {
+ InstanceExpression = null;
+ return true;
+ }
+
+ if (InstanceExpression == null) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
+ return false;
+ }
+
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (lvalue_instance && InstanceExpression != null)
+ InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
+
+ if (InstanceExpression == null)
+ return false;
+
+ InstanceExpression.CheckMarshalByRefAccess ();
+
+ if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
+ !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
+ !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
+ !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
+ Report.SymbolRelatedToPreviousError (PropertyInfo);
+ Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
+ return false;
+ }
+
+ return true;
+ }
+
+ void Error_PropertyNotFound (MethodInfo mi, bool getter)
+ {
+ // TODO: correctly we should compare arguments but it will lead to bigger changes
+ if (mi is MethodBuilder) {
+ Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
+ return;
+ }
+
+ StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
+ sig.Append ('.');
+ ParameterData iparams = TypeManager.GetParameterData (mi);
+ sig.Append (getter ? "get_" : "set_");
+ sig.Append (Name);
+ sig.Append (iparams.GetSignatureForError ());
+
+ Report.SymbolRelatedToPreviousError (mi);
+ Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
+ Name, sig.ToString ());
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (resolved)
+ return this;
+
+ if (getter != null){
+ if (TypeManager.GetParameterData (getter).Count != 0){
+ Error_PropertyNotFound (getter, true);
+ return null;
+ }
+ }
+
+ if (getter == null){
+ //
+ // The following condition happens if the PropertyExpr was
+ // created, but is invalid (ie, the property is inaccessible),
+ // and we did not want to embed the knowledge about this in
+ // the caller routine. This only avoids double error reporting.
+ //
+ if (setter == null)
+ return null;
+
+ if (InstanceExpression != EmptyExpression.Null) {
+ Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
+ TypeManager.GetFullNameSignature (PropertyInfo));
+ return null;
+ }
+ }
+
+ bool must_do_cs1540_check = false;
+ if (getter != null &&
+ !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
+ PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
+ if (pm != null && pm.HasCustomAccessModifier) {
+ Report.SymbolRelatedToPreviousError (pm);
+ Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
+ TypeManager.CSharpSignature (getter));
+ }
+ else {
+ Report.SymbolRelatedToPreviousError (getter);
+ ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
+ }
+ return null;
+ }
+
+ if (!InstanceResolve (ec, false, must_do_cs1540_check))
+ return null;
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (IsBase && getter.IsAbstract) {
+ Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
+ return null;
+ }
+
+ if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+
+ resolved = true;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (right_side == EmptyExpression.OutAccess) {
+ Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
+ GetSignatureForError ());
+ return null;
+ }
+
+ if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
+ Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
+ GetSignatureForError ());
+ return null;
+ }
+
+ if (setter == null){
+ //
+ // The following condition happens if the PropertyExpr was
+ // created, but is invalid (ie, the property is inaccessible),
+ // and we did not want to embed the knowledge about this in
+ // the caller routine. This only avoids double error reporting.
+ //
+ if (getter == null)
+ return null;
+ Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
+ GetSignatureForError ());
+ return null;
+ }
+
+ if (TypeManager.GetParameterData (setter).Count != 1){
+ Error_PropertyNotFound (setter, false);
+ return null;
+ }
+
+ bool must_do_cs1540_check;
+ if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
+ PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
+ if (pm != null && pm.HasCustomAccessModifier) {
+ Report.SymbolRelatedToPreviousError (pm);
+ Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
+ TypeManager.CSharpSignature (setter));
+ }
+ else {
+ Report.SymbolRelatedToPreviousError (setter);
+ ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
+ }
+ return null;
+ }
+
+ if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
+ return null;
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (IsBase && setter.IsAbstract){
+ Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
+ public void Emit (EmitContext ec, bool leave_copy)
+ {
+ //
+ // Special case: length of single dimension array property is turned into ldlen
+ //
+ if ((getter == TypeManager.system_int_array_get_length) ||
+ (getter == TypeManager.int_array_get_length)){
+ Type iet = InstanceExpression.Type;
+
+ //
+ // System.Array.Length can be called, but the Type does not
+ // support invoking GetArrayRank, so test for that case first
+ //
+ if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
+ if (!prepared)
+ EmitInstance (ec, false);
+ ec.ig.Emit (OpCodes.Ldlen);
+ ec.ig.Emit (OpCodes.Conv_I4);
+ return;
+ }
+ }
+
+ Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
+
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (!is_static) {
+ temp = new LocalTemporary (this.Type);
+ temp.Store (ec);
+ }
+ }
+ }
+
+ //
+ // Implements the IAssignMethod interface for assignments
+ //
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ {
+ Expression my_source = source;
+
+ prepared = prepare_for_load;
+
+ if (prepared) {
+ source.Emit (ec);
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (!is_static) {
+ temp = new LocalTemporary (this.Type);
+ temp.Store (ec);
+ }
+ }
+ } else if (leave_copy) {
+ source.Emit (ec);
+ if (!is_static) {
+ temp = new LocalTemporary (this.Type);
+ temp.Store (ec);
+ }
+ my_source = temp;
+ }
+
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (my_source, Argument.AType.Expression));
+
+ Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
+
+ if (temp != null) {
+ temp.Emit (ec);
+ temp.Release (ec);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Fully resolved expression that evaluates to an Event
+ /// </summary>
+ public class EventExpr : MemberExpr {
+ public readonly EventInfo EventInfo;
+
+ bool is_static;
+ MethodInfo add_accessor, remove_accessor;
+
+ internal static PtrHashtable AccessorTable = new PtrHashtable ();
+
+ public EventExpr (EventInfo ei, Location loc)
+ {
+ EventInfo = ei;
+ this.loc = loc;
+ eclass = ExprClass.EventAccess;
+
+ add_accessor = TypeManager.GetAddMethod (ei);
+ remove_accessor = TypeManager.GetRemoveMethod (ei);
+ if (add_accessor != null)
+ AccessorTable [add_accessor] = ei;
+ if (remove_accessor != null)
+ AccessorTable [remove_accessor] = ei;
+
+ if (add_accessor.IsStatic || remove_accessor.IsStatic)
+ is_static = true;
+
+ if (EventInfo is MyEventBuilder){
+ MyEventBuilder eb = (MyEventBuilder) EventInfo;
+ type = eb.EventType;
+ eb.SetUsed ();
+ } else
+ type = EventInfo.EventHandlerType;
+ }
+
+ public override string Name {
+ get {
+ return EventInfo.Name;
+ }
+ }
+
+ public override bool IsInstance {
+ get {
+ return !is_static;
+ }
+ }
+
+ public override bool IsStatic {
+ get {
+ return is_static;
+ }
+ }
+
+ public override Type DeclaringType {
+ get {
+ return EventInfo.DeclaringType;
+ }
+ }
+
+ public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
+ SimpleName original)
+ {
+ //
+ // If the event is local to this class, we transform ourselves into a FieldExpr
+ //
+
+ if (EventInfo.DeclaringType == ec.ContainerType ||
+ TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
+ MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
+
+ if (mi != null) {
+ MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
+
+ if (ml == null) {
+ Report.Error (-200, loc, "Internal error!!");
+ return null;
+ }
+
+ InstanceExpression = null;
+
+ return ml.ResolveMemberAccess (ec, left, loc, original);
+ }
+ }
+
+ return base.ResolveMemberAccess (ec, left, loc, original);
+ }
+
+
+ bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
+ {
+ if (is_static) {
+ InstanceExpression = null;
+ return true;
+ }
+
+ if (InstanceExpression == null) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
+ return false;
+ }
+
+ InstanceExpression = InstanceExpression.DoResolve (ec);
+ if (InstanceExpression == null)
+ return false;
+
+ //
+ // This is using the same mechanism as the CS1540 check in PropertyExpr.
+ // However, in the Event case, we reported a CS0122 instead.
+ //
+ if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
+ InstanceExpression.Type != ec.ContainerType &&
+ ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
+ Report.SymbolRelatedToPreviousError (EventInfo);
+ ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
+ return false;
+ }
+
+ return true;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ return DoResolve (ec);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ bool must_do_cs1540_check;
+ if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
+ IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
+ Report.SymbolRelatedToPreviousError (EventInfo);
+ ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
+ return null;
+ }
+
+ if (!InstanceResolve (ec, must_do_cs1540_check))
+ return null;
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (InstanceExpression is This)
+ Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
+ else
+ Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
+ "(except on the defining type)", Name);
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return TypeManager.CSharpSignature (EventInfo);
+ }
+
+ public void EmitAddOrRemove (EmitContext ec, Expression source)
+ {
+ BinaryDelegate source_del = (BinaryDelegate) source;
+ Expression handler = source_del.Right;
+
+ Argument arg = new Argument (handler, Argument.AType.Expression);
+ ArrayList args = new ArrayList ();
+
+ args.Add (arg);
+
+ if (source_del.IsAddition)
+ Invocation.EmitCall (
+ ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
+ else
+ Invocation.EmitCall (
+ ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
+ }
+ }
+
+ public class TemporaryVariable : Expression, IMemoryLocation
+ {
+ LocalInfo li;
+ Variable var;
+
+ public TemporaryVariable (Type type, Location loc)
+ {
+ this.type = type;
+ this.loc = loc;
+ eclass = ExprClass.Value;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (li != null)
+ return this;
+
+ TypeExpr te = new TypeExpression (type, loc);
+ li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
+ if (!li.Resolve (ec))
+ return null;
+
+ if (ec.MustCaptureVariable (li)) {
+ ScopeInfo scope = li.Block.CreateScopeInfo ();
+ var = scope.AddLocal (li);
+ type = var.Type;
+ }
+
+ return this;
+ }
+
+ public Variable Variable {
+ get { return var != null ? var : li.Variable; }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Variable.EmitInstance (ec);
+ Variable.Emit (ec);
+ }
+
+ public void EmitLoadAddress (EmitContext ec)
+ {
+ Variable.EmitInstance (ec);
+ Variable.EmitAddressOf (ec);
+ }
+
+ public void Store (EmitContext ec, Expression right_side)
+ {
+ Variable.EmitInstance (ec);
+ right_side.Emit (ec);
+ Variable.EmitAssign (ec);
+ }
+
+ public void EmitThis (EmitContext ec)
+ {
+ Variable.EmitInstance (ec);
+ }
+
+ public void EmitStore (EmitContext ec)
+ {
+ Variable.EmitAssign (ec);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ EmitLoadAddress (ec);
+ }
+ }
+
+}
MethodInfo method;
Expression operator_group;
- operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
+ operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
if (operator_group == null) {
Error19 ();
return null;
Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
index, Parameter.GetModifierSignature (mod));
} else {
- Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'",
- index, Argument.FullDesc (a), expected_par.ParameterDesc (idx));
- }
+ string p1 = Argument.FullDesc (a);
+ string p2 = expected_par.ParameterDesc (idx);
+
+ //
+ // The parameter names are the same, most likely they come from different
+ // assemblies.
+ //
+ if (p1 == p2){
+ Report.Error (1503, loc,
+ "Argument {0}: Cannot conver from equally named types from different " +
+ "assemblies {0} (from {1}) and {2} (from {3})",
+ p1, a.Expr.Type.Assembly.FullName, p2,
+ expected_par.ParameterType (idx).Assembly.FullName);
+ } else
+ Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'",
+ index, p1, p2);
+ }
}
public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
--- /dev/null
+//
+// namespace.cs: Tracks namespaces
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Marek Safar (marek.safar@seznam.cz)
+//
+// (C) 2001 Ximian, Inc.
+//
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Reflection;
+
+namespace Mono.CSharp {
+
+ public class RootNamespace : Namespace {
+ static MethodInfo get_namespaces_method;
+
+ string alias_name;
+ Assembly referenced_assembly;
+
+ Hashtable all_namespaces;
+
+ static Hashtable root_namespaces;
+ public static GlobalRootNamespace Global;
+
+ static RootNamespace ()
+ {
+ get_namespaces_method = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ Reset ();
+ }
+
+ public static void Reset ()
+ {
+ root_namespaces = new Hashtable ();
+ Global = new GlobalRootNamespace ();
+ root_namespaces ["global"] = Global;
+ }
+
+ protected RootNamespace (string alias_name, Assembly assembly)
+ : base (null, String.Empty)
+ {
+ this.alias_name = alias_name;
+ referenced_assembly = assembly;
+
+ all_namespaces = new Hashtable ();
+ all_namespaces.Add ("", this);
+
+ if (referenced_assembly != null)
+ ComputeNamespaces (this.referenced_assembly);
+ }
+
+ public static void DefineRootNamespace (string name, Assembly assembly)
+ {
+ if (name == "global") {
+ // FIXME: Add proper error number
+ Report.Error (-42, "Cannot define an external alias named `global'");
+ return;
+ }
+ RootNamespace retval = GetRootNamespace (name);
+ if (retval == null || retval.referenced_assembly != assembly)
+ root_namespaces [name] = new RootNamespace (name, assembly);
+ }
+
+ public static RootNamespace GetRootNamespace (string name)
+ {
+ return (RootNamespace) root_namespaces [name];
+ }
+
+ public virtual Type LookupTypeReflection (string name, Location loc)
+ {
+ return GetTypeInAssembly (referenced_assembly, name);
+ }
+
+ public void RegisterNamespace (Namespace child)
+ {
+ if (child != this)
+ all_namespaces.Add (child.Name, child);
+ }
+
+ public bool IsNamespace (string name)
+ {
+ return all_namespaces.Contains (name);
+ }
+
+ protected void EnsureNamespace (string dotted_name)
+ {
+ if (dotted_name != null && dotted_name.Length != 0 && ! IsNamespace (dotted_name))
+ GetNamespace (dotted_name, true);
+ }
+
+ protected void ComputeNamespaces (Assembly assembly)
+ {
+ if (get_namespaces_method != null) {
+ string [] namespaces = (string []) get_namespaces_method.Invoke (assembly, null);
+ foreach (string ns in namespaces)
+ EnsureNamespace (ns);
+ return;
+ }
+
+ foreach (Type t in assembly.GetExportedTypes ())
+ EnsureNamespace (t.Namespace);
+ }
+
+ protected static Type GetTypeInAssembly (Assembly assembly, string name)
+ {
+ Type t = assembly.GetType (name);
+ if (t == null)
+ return null;
+
+ if (t.IsPointer)
+ throw new InternalErrorException ("Use GetPointerType() to get a pointer");
+
+ TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
+ if (ta == TypeAttributes.NestedPrivate)
+ return null;
+
+ if ((ta == TypeAttributes.NotPublic ||
+ ta == TypeAttributes.NestedAssembly ||
+ ta == TypeAttributes.NestedFamANDAssem) &&
+ !TypeManager.IsFriendAssembly (t.Assembly))
+ return null;
+
+ return t;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("RootNamespace ({0}::)", alias_name);
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return alias_name + "::";
+ }
+ }
+
+ public class GlobalRootNamespace : RootNamespace {
+ Assembly [] assemblies;
+ Module [] modules;
+
+ public GlobalRootNamespace ()
+ : base ("global", null)
+ {
+ assemblies = new Assembly [0];
+ }
+
+ public Assembly [] Assemblies {
+ get { return assemblies; }
+ }
+
+ public Module [] Modules {
+ get { return modules; }
+ }
+
+ public void AddAssemblyReference (Assembly a)
+ {
+ foreach (Assembly assembly in assemblies) {
+ if (a == assembly)
+ return;
+ }
+
+ int top = assemblies.Length;
+ Assembly [] n = new Assembly [top + 1];
+ assemblies.CopyTo (n, 0);
+ n [top] = a;
+ assemblies = n;
+
+ ComputeNamespaces (a);
+ }
+
+ public void AddModuleReference (Module m)
+ {
+ int top = modules != null ? modules.Length : 0;
+ Module [] n = new Module [top + 1];
+ if (modules != null)
+ modules.CopyTo (n, 0);
+ n [top] = m;
+ modules = n;
+
+ if (m == CodeGen.Module.Builder)
+ return;
+
+ foreach (Type t in m.GetTypes ())
+ EnsureNamespace (t.Namespace);
+ }
+
+ public override void Error_NamespaceDoesNotExist(DeclSpace ds, Location loc, string name)
+ {
+ Report.Error (400, loc, "The type or namespace name `{0}' could not be found in the global namespace (are you missing an assembly reference?)",
+ name);
+ }
+
+ public override Type LookupTypeReflection (string name, Location loc)
+ {
+ Type found_type = null;
+
+ foreach (Assembly a in assemblies) {
+ Type t = GetTypeInAssembly (a, name);
+ if (t == null)
+ continue;
+
+ if (found_type == null) {
+ found_type = t;
+ continue;
+ }
+
+ Report.SymbolRelatedToPreviousError (found_type);
+ Report.SymbolRelatedToPreviousError (t);
+ Report.Error (433, loc, "The imported type `{0}' is defined multiple times", name);
+
+ return found_type;
+ }
+
+ if (modules != null) {
+ foreach (Module module in modules) {
+ Type t = module.GetType (name);
+ if (t == null)
+ continue;
+
+ if (found_type == null) {
+ found_type = t;
+ continue;
+ }
+
+ Report.SymbolRelatedToPreviousError (t);
+ Report.SymbolRelatedToPreviousError (found_type);
+ Report.Warning (436, 2, loc, "Ignoring imported type `{0}' since the current assembly already has a declaration with the same name",
+ TypeManager.CSharpName (t));
+ return t;
+ }
+ }
+
+ return found_type;
+ }
+ }
+
+ /// <summary>
+ /// Keeps track of the namespaces defined in the C# code.
+ ///
+ /// This is an Expression to allow it to be referenced in the
+ /// compiler parse/intermediate tree during name resolution.
+ /// </summary>
+ public class Namespace : FullNamedExpression {
+
+ Namespace parent;
+ string fullname;
+ Hashtable namespaces;
+ IDictionary declspaces;
+ Hashtable cached_types;
+ RootNamespace root;
+
+ public readonly MemberName MemberName;
+
+ /// <summary>
+ /// Constructor Takes the current namespace and the
+ /// name. This is bootstrapped with parent == null
+ /// and name = ""
+ /// </summary>
+ public Namespace (Namespace parent, string name)
+ {
+ // Expression members.
+ this.eclass = ExprClass.Namespace;
+ this.Type = null;
+ this.loc = Location.Null;
+
+ this.parent = parent;
+
+ if (parent != null)
+ this.root = parent.root;
+ else
+ this.root = this as RootNamespace;
+
+ if (this.root == null)
+ throw new InternalErrorException ("Root namespaces must be created using RootNamespace");
+
+ string pname = parent != null ? parent.Name : "";
+
+ if (pname == "")
+ fullname = name;
+ else
+ fullname = parent.Name + "." + name;
+
+ if (fullname == null)
+ throw new InternalErrorException ("Namespace has a null fullname");
+
+ if (parent != null && parent.MemberName != MemberName.Null)
+ MemberName = new MemberName (parent.MemberName, name);
+ else if (name.Length == 0)
+ MemberName = MemberName.Null;
+ else
+ MemberName = new MemberName (name);
+
+ namespaces = new Hashtable ();
+ cached_types = new Hashtable ();
+
+ root.RegisterNamespace (this);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ public virtual void Error_NamespaceDoesNotExist (DeclSpace ds, Location loc, string name)
+ {
+ if (name.IndexOf ('`') > 0) {
+ FullNamedExpression retval = Lookup (ds, SimpleName.RemoveGenericArity (name), loc);
+ if (retval != null) {
+ Error_TypeArgumentsCannotBeUsed (retval.Type, loc, "type");
+ return;
+ }
+ } else {
+ Type t = LookForAnyGenericType (name);
+ if (t != null) {
+ Error_InvalidNumberOfTypeArguments (t, loc);
+ return;
+ }
+ }
+
+ Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
+ name, FullName);
+ }
+
+ public static void Error_InvalidNumberOfTypeArguments (Type t, Location loc)
+ {
+ Report.SymbolRelatedToPreviousError (t);
+ Report.Error (305, loc, "Using the generic type `{0}' requires `{1}' type argument(s)",
+ TypeManager.CSharpName(t), TypeManager.GetNumberOfTypeArguments(t).ToString());
+ }
+
+ public static void Error_TypeArgumentsCannotBeUsed(Type t, Location loc, string symbol)
+ {
+ Report.SymbolRelatedToPreviousError(t);
+ Report.Error(308, loc, "The non-generic {0} `{1}' cannot be used with the type argument(s)",
+ symbol, TypeManager.CSharpName(t));
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new InternalErrorException ("Expression tree referenced namespace " + fullname + " during Emit ()");
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return Name;
+ }
+
+ public Namespace GetNamespace (string name, bool create)
+ {
+ int pos = name.IndexOf ('.');
+
+ Namespace ns;
+ string first;
+ if (pos >= 0)
+ first = name.Substring (0, pos);
+ else
+ first = name;
+
+ ns = (Namespace) namespaces [first];
+ if (ns == null) {
+ if (!create)
+ return null;
+
+ ns = new Namespace (this, first);
+ namespaces.Add (first, ns);
+ }
+
+ if (pos >= 0)
+ ns = ns.GetNamespace (name.Substring (pos + 1), create);
+
+ return ns;
+ }
+
+ TypeExpr LookupType (string name, Location loc)
+ {
+ if (cached_types.Contains (name))
+ return cached_types [name] as TypeExpr;
+
+ Type t = null;
+ if (declspaces != null) {
+ DeclSpace tdecl = declspaces [name] as DeclSpace;
+ if (tdecl != null) {
+ //
+ // Note that this is not:
+ //
+ // t = tdecl.DefineType ()
+ //
+ // This is to make it somewhat more useful when a DefineType
+ // fails due to problems in nested types (more useful in the sense
+ // of fewer misleading error messages)
+ //
+ tdecl.DefineType ();
+ t = tdecl.TypeBuilder;
+ }
+ }
+ string lookup = t != null ? t.FullName : (fullname.Length == 0 ? name : fullname + "." + name);
+ Type rt = root.LookupTypeReflection (lookup, loc);
+ if (t == null)
+ t = rt;
+
+ TypeExpr te = t == null ? null : new TypeExpression (t, Location.Null);
+ cached_types [name] = te;
+ return te;
+ }
+
+ ///
+ /// Used for better error reporting only
+ ///
+ public Type LookForAnyGenericType (string typeName)
+ {
+ if (declspaces == null)
+ return null;
+
+ typeName = SimpleName.RemoveGenericArity (typeName);
+
+ foreach (DictionaryEntry de in declspaces) {
+ string type_item = (string) de.Key;
+ int pos = type_item.LastIndexOf ('`');
+ if (pos == typeName.Length && String.Compare (typeName, 0, type_item, 0, pos) == 0)
+ return ((DeclSpace) de.Value).TypeBuilder;
+ }
+ return null;
+ }
+
+ public FullNamedExpression Lookup (DeclSpace ds, string name, Location loc)
+ {
+ if (namespaces.Contains (name))
+ return (Namespace) namespaces [name];
+
+ TypeExpr te = LookupType (name, loc);
+ if (te == null || !ds.CheckAccessLevel (te.Type))
+ return null;
+
+ return te;
+ }
+
+ public void AddDeclSpace (string name, DeclSpace ds)
+ {
+ if (declspaces == null)
+ declspaces = new HybridDictionary ();
+ declspaces.Add (name, ds);
+ }
+
+ /// <summary>
+ /// The qualified name of the current namespace
+ /// </summary>
+ public string Name {
+ get { return fullname; }
+ }
+
+ public override string FullName {
+ get { return fullname; }
+ }
+
+ /// <summary>
+ /// The parent of this namespace, used by the parser to "Pop"
+ /// the current namespace declaration
+ /// </summary>
+ public Namespace Parent {
+ get { return parent; }
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("Namespace ({0})", Name);
+ }
+ }
+
+ public class NamespaceEntry {
+ Namespace ns;
+ NamespaceEntry parent, implicit_parent;
+ SourceFile file;
+ int symfile_id;
+ Hashtable aliases;
+ ArrayList using_clauses;
+ public bool DeclarationFound = false;
+ bool UsingFound;
+
+ public readonly DeclSpace SlaveDeclSpace;
+
+ ListDictionary extern_aliases;
+
+ static ArrayList entries = new ArrayList ();
+
+ public static void Reset ()
+ {
+ entries = new ArrayList ();
+ }
+
+ //
+ // This class holds the location where a using definition is
+ // done, and whether it has been used by the program or not.
+ //
+ // We use this to flag using clauses for namespaces that do not
+ // exist.
+ //
+ public class UsingEntry : IResolveContext {
+ public readonly MemberName Name;
+ readonly Expression Expr;
+ readonly NamespaceEntry NamespaceEntry;
+ readonly Location Location;
+
+ public UsingEntry (NamespaceEntry entry, MemberName name, Location loc)
+ {
+ Name = name;
+ Expr = name.GetTypeExpression ();
+ NamespaceEntry = entry;
+ Location = loc;
+ }
+
+ internal Namespace resolved;
+
+ public Namespace Resolve ()
+ {
+ if (resolved != null)
+ return resolved;
+
+ FullNamedExpression fne = Expr.ResolveAsTypeStep (this, false);
+ if (fne == null) {
+ Error_NamespaceNotFound (Location, Name.ToString ());
+ return null;
+ }
+
+ resolved = fne as Namespace;
+ if (resolved == null) {
+ Report.Error (138, Location,
+ "`{0} is a type not a namespace. A using namespace directive can only be applied to namespaces", Name.ToString ());
+ }
+ return resolved;
+ }
+
+ DeclSpace IResolveContext.DeclContainer {
+ get { return NamespaceEntry.SlaveDeclSpace; }
+ }
+
+ DeclSpace IResolveContext.GenericDeclContainer {
+ get { return NamespaceEntry.SlaveDeclSpace; }
+ }
+
+ bool IResolveContext.IsInObsoleteScope {
+ get { return false; }
+ }
+ bool IResolveContext.IsInUnsafeScope {
+ get { return false; }
+ }
+ }
+
+ public abstract class AliasEntry {
+ public readonly string Name;
+ public readonly NamespaceEntry NamespaceEntry;
+ public readonly Location Location;
+
+ protected AliasEntry (NamespaceEntry entry, string name, Location loc)
+ {
+ Name = name;
+ NamespaceEntry = entry;
+ Location = loc;
+ }
+
+ protected FullNamedExpression resolved;
+ bool error;
+
+ public FullNamedExpression Resolve ()
+ {
+ if (resolved != null || error)
+ return resolved;
+ resolved = DoResolve ();
+ if (resolved == null)
+ error = true;
+ return resolved;
+ }
+
+ protected abstract FullNamedExpression DoResolve ();
+ }
+
+ public class LocalAliasEntry : AliasEntry, IResolveContext {
+ public readonly Expression Alias;
+
+ public LocalAliasEntry (NamespaceEntry entry, string name, MemberName alias, Location loc) :
+ base (entry, name, loc)
+ {
+ Alias = alias.GetTypeExpression ();
+ }
+
+ protected override FullNamedExpression DoResolve ()
+ {
+ resolved = Alias.ResolveAsTypeStep (this, false);
+ if (resolved == null)
+ return null;
+
+ if (resolved.Type != null) {
+ TypeAttributes attr = resolved.Type.Attributes & TypeAttributes.VisibilityMask;
+ if (attr == TypeAttributes.NestedPrivate || attr == TypeAttributes.NestedFamily ||
+ ((attr == TypeAttributes.NestedFamORAssem || attr == TypeAttributes.NestedAssembly) &&
+ TypeManager.LookupDeclSpace (resolved.Type) == null)) {
+ Expression.ErrorIsInaccesible (Alias.Location, Alias.ToString ());
+ return null;
+ }
+ }
+
+ return resolved;
+ }
+
+ DeclSpace IResolveContext.DeclContainer {
+ get { return NamespaceEntry.SlaveDeclSpace; }
+ }
+
+ DeclSpace IResolveContext.GenericDeclContainer {
+ get { return NamespaceEntry.SlaveDeclSpace; }
+ }
+
+ bool IResolveContext.IsInObsoleteScope {
+ get { return false; }
+ }
+ bool IResolveContext.IsInUnsafeScope {
+ get { return false; }
+ }
+ }
+
+ public class ExternAliasEntry : AliasEntry {
+ public ExternAliasEntry (NamespaceEntry entry, string name, Location loc) :
+ base (entry, name, loc)
+ {
+ }
+
+ protected override FullNamedExpression DoResolve ()
+ {
+ resolved = RootNamespace.GetRootNamespace (Name);
+ if (resolved == null)
+ Report.Error (430, Location, "The extern alias '" + Name +
+ "' was not specified in a /reference option");
+
+ return resolved;
+ }
+ }
+
+ public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name)
+ {
+ this.parent = parent;
+ this.file = file;
+ entries.Add (this);
+ this.ID = entries.Count;
+
+ if (parent != null)
+ ns = parent.NS.GetNamespace (name, true);
+ else if (name != null)
+ ns = RootNamespace.Global.GetNamespace (name, true);
+ else
+ ns = RootNamespace.Global;
+ SlaveDeclSpace = new RootDeclSpace (this);
+ }
+
+ private NamespaceEntry (NamespaceEntry parent, SourceFile file, Namespace ns, bool slave)
+ {
+ this.parent = parent;
+ this.file = file;
+ // no need to add self to 'entries', since we don't have any aliases or using entries.
+ this.ID = -1;
+ this.IsImplicit = true;
+ this.ns = ns;
+ this.SlaveDeclSpace = slave ? new RootDeclSpace (this) : null;
+ }
+
+ //
+ // According to section 16.3.1 (using-alias-directive), the namespace-or-type-name is
+ // resolved as if the immediately containing namespace body has no using-directives.
+ //
+ // Section 16.3.2 says that the same rule is applied when resolving the namespace-name
+ // in the using-namespace-directive.
+ //
+ // To implement these rules, the expressions in the using directives are resolved using
+ // the "doppelganger" (ghostly bodiless duplicate).
+ //
+ NamespaceEntry doppelganger;
+ NamespaceEntry Doppelganger {
+ get {
+ if (!IsImplicit && doppelganger == null)
+ doppelganger = new NamespaceEntry (ImplicitParent, file, ns, true);
+ return doppelganger;
+ }
+ }
+
+ public readonly int ID;
+ public readonly bool IsImplicit;
+
+ public Namespace NS {
+ get { return ns; }
+ }
+
+ public NamespaceEntry Parent {
+ get { return parent; }
+ }
+
+ public NamespaceEntry ImplicitParent {
+ get {
+ if (parent == null)
+ return null;
+ if (implicit_parent == null) {
+ implicit_parent = (parent.NS == ns.Parent)
+ ? parent
+ : new NamespaceEntry (parent, file, ns.Parent, false);
+ }
+ return implicit_parent;
+ }
+ }
+
+ /// <summary>
+ /// Records a new namespace for resolving name references
+ /// </summary>
+ public void Using (MemberName name, Location loc)
+ {
+ if (DeclarationFound){
+ Report.Error (1529, loc, "A using clause must precede all other namespace elements except extern alias declarations");
+ return;
+ }
+
+ UsingFound = true;
+
+ if (name.Equals (ns.MemberName))
+ return;
+
+ if (using_clauses == null)
+ using_clauses = new ArrayList ();
+
+ foreach (UsingEntry old_entry in using_clauses) {
+ if (name.Equals (old_entry.Name)) {
+ Report.Warning (105, 3, loc, "The using directive for `{0}' appeared previously in this namespace", name.GetName ());
+ return;
+ }
+ }
+
+ UsingEntry ue = new UsingEntry (Doppelganger, name, loc);
+ using_clauses.Add (ue);
+ }
+
+ public void UsingAlias (string name, MemberName alias, Location loc)
+ {
+ if (DeclarationFound){
+ Report.Error (1529, loc, "A using clause must precede all other namespace elements except extern alias declarations");
+ return;
+ }
+
+ UsingFound = true;
+
+ if (aliases == null)
+ aliases = new Hashtable ();
+
+ if (aliases.Contains (name)) {
+ AliasEntry ae = (AliasEntry) aliases [name];
+ Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
+ Report.Error (1537, loc, "The using alias `{0}' appeared previously in this namespace", name);
+ return;
+ }
+
+ if (RootContext.Version == LanguageVersion.Default &&
+ name == "global" && RootContext.WarningLevel >= 2)
+ Report.Warning (440, 2, loc, "An alias named `global' will not be used when resolving 'global::';" +
+ " the global namespace will be used instead");
+
+ // FIXME: get correct error number. See if the above check can be merged
+ if (extern_aliases != null && extern_aliases.Contains (name)) {
+ AliasEntry ae = (AliasEntry) extern_aliases [name];
+ Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
+ Report.Error (1537, loc, "The using alias `{0}' appeared previously in this namespace", name);
+ return;
+ }
+
+ aliases [name] = new LocalAliasEntry (Doppelganger, name, alias, loc);
+ }
+
+ public void UsingExternalAlias (string name, Location loc)
+ {
+ if (UsingFound || DeclarationFound) {
+ Report.Error (439, loc, "An extern alias declaration must precede all other elements");
+ return;
+ }
+
+ // Share the extern_aliases field with the Doppelganger
+ if (extern_aliases == null) {
+ extern_aliases = new ListDictionary ();
+ Doppelganger.extern_aliases = extern_aliases;
+ }
+
+ if (extern_aliases.Contains (name)) {
+ AliasEntry ae = (AliasEntry) extern_aliases [name];
+ Report.SymbolRelatedToPreviousError (ae.Location, ae.Name);
+ Report.Error (1537, loc, "The using alias `{0}' appeared previously in this namespace", name);
+ return;
+ }
+
+ if (name == "global") {
+ Report.Error (1681, loc, "You cannot redefine the global extern alias");
+ return;
+ }
+
+ // Register the alias in aliases and extern_aliases, since we need both of them
+ // to keep things simple (different resolution scenarios)
+ ExternAliasEntry alias = new ExternAliasEntry (Doppelganger, name, loc);
+ extern_aliases [name] = alias;
+ }
+
+ public FullNamedExpression LookupNamespaceOrType (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
+ {
+ // Precondition: Only simple names (no dots) will be looked up with this function.
+ FullNamedExpression resolved = null;
+ for (NamespaceEntry curr_ns = this; curr_ns != null; curr_ns = curr_ns.ImplicitParent) {
+ if ((resolved = curr_ns.Lookup (ds, name, loc, ignore_cs0104)) != null)
+ break;
+ }
+ return resolved;
+ }
+
+ static void Error_AmbiguousTypeReference (Location loc, string name, FullNamedExpression t1, FullNamedExpression t2)
+ {
+ Report.Error (104, loc, "`{0}' is an ambiguous reference between `{1}' and `{2}'",
+ name, t1.FullName, t2.FullName);
+ }
+
+ // Looks-up a alias named @name in this and surrounding namespace declarations
+ public FullNamedExpression LookupAlias (string name)
+ {
+ AliasEntry entry = null;
+ for (NamespaceEntry n = this; n != null; n = n.ImplicitParent) {
+ if (n.extern_aliases != null && (entry = n.extern_aliases [name] as AliasEntry) != null)
+ break;
+ if (n.aliases != null && (entry = n.aliases [name] as AliasEntry) != null)
+ break;
+ }
+ return entry == null ? null : entry.Resolve ();
+ }
+
+ private FullNamedExpression Lookup (DeclSpace ds, string name, Location loc, bool ignore_cs0104)
+ {
+ //
+ // Check whether it's in the namespace.
+ //
+ FullNamedExpression fne = NS.Lookup (ds, name, loc);
+ if (fne != null)
+ return fne;
+
+ if (extern_aliases != null) {
+ AliasEntry entry = extern_aliases [name] as AliasEntry;
+ if (entry != null)
+ return entry.Resolve ();
+ }
+
+ if (IsImplicit)
+ return null;
+
+ //
+ // Check aliases.
+ //
+ if (aliases != null) {
+ AliasEntry entry = aliases [name] as AliasEntry;
+ if (entry != null)
+ return entry.Resolve ();
+ }
+
+ //
+ // Check using entries.
+ //
+ FullNamedExpression match = null;
+ foreach (Namespace using_ns in GetUsingTable ()) {
+ match = using_ns.Lookup (ds, name, loc);
+ if (match == null || !(match is TypeExpr))
+ continue;
+ if (fne != null) {
+ if (!ignore_cs0104)
+ Error_AmbiguousTypeReference (loc, name, fne, match);
+ return null;
+ }
+ fne = match;
+ }
+
+ return fne;
+ }
+
+ // Our cached computation.
+ readonly Namespace [] empty_namespaces = new Namespace [0];
+ Namespace [] namespace_using_table;
+ Namespace [] GetUsingTable ()
+ {
+ if (namespace_using_table != null)
+ return namespace_using_table;
+
+ if (using_clauses == null) {
+ namespace_using_table = empty_namespaces;
+ return namespace_using_table;
+ }
+
+ ArrayList list = new ArrayList (using_clauses.Count);
+
+ foreach (UsingEntry ue in using_clauses) {
+ Namespace using_ns = ue.Resolve ();
+ if (using_ns == null)
+ continue;
+
+ list.Add (using_ns);
+ }
+
+ namespace_using_table = new Namespace [list.Count];
+ list.CopyTo (namespace_using_table, 0);
+ return namespace_using_table;
+ }
+
+ readonly string [] empty_using_list = new string [0];
+
+ public int SymbolFileID {
+ get {
+ if (symfile_id == 0 && file.SourceFileEntry != null) {
+ int parent_id = parent == null ? 0 : parent.SymbolFileID;
+
+ string [] using_list = empty_using_list;
+ if (using_clauses != null) {
+ using_list = new string [using_clauses.Count];
+ for (int i = 0; i < using_clauses.Count; i++)
+ using_list [i] = ((UsingEntry) using_clauses [i]).Name.ToString ();
+ }
+
+ symfile_id = CodeGen.SymbolWriter.DefineNamespace (ns.Name, file.SourceFileEntry, using_list, parent_id);
+ }
+ return symfile_id;
+ }
+ }
+
+ static void MsgtryRef (string s)
+ {
+ Console.WriteLine (" Try using -r:" + s);
+ }
+
+ static void MsgtryPkg (string s)
+ {
+ Console.WriteLine (" Try using -pkg:" + s);
+ }
+
+ public static void Error_NamespaceNotFound (Location loc, string name)
+ {
+ Report.Error (246, loc, "The type or namespace name `{0}' could not be found. Are you missing a using directive or an assembly reference?",
+ name);
+
+ switch (name) {
+ case "Gtk": case "GtkSharp":
+ MsgtryPkg ("gtk-sharp");
+ break;
+
+ case "Gdk": case "GdkSharp":
+ MsgtryPkg ("gdk-sharp");
+ break;
+
+ case "Glade": case "GladeSharp":
+ MsgtryPkg ("glade-sharp");
+ break;
+
+ case "System.Drawing":
+ case "System.Web.Services":
+ case "System.Web":
+ case "System.Data":
+ case "System.Windows.Forms":
+ MsgtryRef (name);
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Used to validate that all the using clauses are correct
+ /// after we are finished parsing all the files.
+ /// </summary>
+ void VerifyUsing ()
+ {
+ if (extern_aliases != null) {
+ foreach (DictionaryEntry de in extern_aliases)
+ ((AliasEntry) de.Value).Resolve ();
+ }
+
+ if (using_clauses != null) {
+ foreach (UsingEntry ue in using_clauses)
+ ue.Resolve ();
+ }
+
+ if (aliases != null) {
+ foreach (DictionaryEntry de in aliases)
+ ((AliasEntry) de.Value).Resolve ();
+ }
+ }
+
+ /// <summary>
+ /// Used to validate that all the using clauses are correct
+ /// after we are finished parsing all the files.
+ /// </summary>
+ static public void VerifyAllUsing ()
+ {
+ foreach (NamespaceEntry entry in entries)
+ entry.VerifyUsing ();
+ }
+
+ public string GetSignatureForError ()
+ {
+ return ns.GetSignatureForError ();
+ }
+
+ public override string ToString ()
+ {
+ return ns.ToString ();
+ }
+ }
+}
--- /dev/null
+//
+// report.cs: report errors and warnings.
+//
+// Author: Miguel de Icaza (miguel@ximian.com)
+// Marek Safar (marek.safar@seznam.cz)
+//
+// (C) 2001 Ximian, Inc. (http://www.ximian.com)
+//
+
+using System;
+using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// This class is used to report errors and warnings t te user.
+ /// </summary>
+ public class Report {
+ /// <summary>
+ /// Errors encountered so far
+ /// </summary>
+ static public int Errors;
+
+ /// <summary>
+ /// Warnings encountered so far
+ /// </summary>
+ static public int Warnings;
+
+ /// <summary>
+ /// Whether errors should be throw an exception
+ /// </summary>
+ static public bool Fatal;
+
+ /// <summary>
+ /// Whether warnings should be considered errors
+ /// </summary>
+ static public bool WarningsAreErrors;
+
+ /// <summary>
+ /// Whether to dump a stack trace on errors.
+ /// </summary>
+ static public bool Stacktrace;
+
+ static public TextWriter Stderr = Console.Error;
+
+ //
+ // If the 'expected' error code is reported then the
+ // compilation succeeds.
+ //
+ // Used for the test suite to excercise the error codes
+ //
+ static int expected_error = 0;
+
+ //
+ // Keeps track of the warnings that we are ignoring
+ //
+ public static Hashtable warning_ignore_table;
+
+ static Hashtable warning_regions_table;
+
+ /// <summary>
+ /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
+ /// </summary>
+ static StringCollection extra_information = new StringCollection ();
+
+ //
+ // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
+ //
+ public static readonly int[] AllWarnings = new int[] {
+ 28, 67, 78,
+ 105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
+ 219, 251, 252, 253, 278, 282,
+ 419, 420, 429, 436, 440, 465, 467, 469,
+ 612, 618, 626, 628, 642, 649, 652, 658, 659, 660, 661, 665, 672, 675,
+ 1030,
+ 1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
+ 1616, 1633, 1634, 1635, 1690, 1691, 1692,
+ 1717, 1718, 1720,
+ 1901,
+ 2002, 2023,
+ 3005, 3012, 3018, 3019, 3021, 3022, 3023, 3026, 3027,
+#if GMCS_SOURCE
+ 402, 414, 693, 1058, 1700, 3024
+#endif
+ };
+
+ static Report ()
+ {
+ // Just to be sure that binary search is working
+ Array.Sort (AllWarnings);
+ }
+
+ public static void Reset ()
+ {
+ Errors = Warnings = 0;
+ WarningsAreErrors = false;
+ warning_ignore_table = null;
+ warning_regions_table = null;
+ }
+
+ abstract class AbstractMessage {
+
+ static void Check (int code)
+ {
+ if (code == expected_error) {
+ Environment.Exit (0);
+ }
+ }
+
+ public abstract bool IsWarning { get; }
+
+ public abstract string MessageType { get; }
+
+ public virtual void Print (int code, string location, string text)
+ {
+ if (code < 0)
+ code = 8000-code;
+
+ StringBuilder msg = new StringBuilder ();
+ if (location.Length != 0) {
+ msg.Append (location);
+ msg.Append (' ');
+ }
+ msg.AppendFormat ("{0} CS{1:0000}: {2}", MessageType, code, text);
+ Stderr.WriteLine (msg.ToString ());
+
+ foreach (string s in extra_information)
+ Stderr.WriteLine (s + MessageType + ")");
+
+ extra_information.Clear ();
+
+ if (Stacktrace)
+ Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
+
+ if (Fatal) {
+ if (!IsWarning || WarningsAreErrors)
+ throw new Exception (text);
+ }
+
+ Check (code);
+ }
+
+ public virtual void Print (int code, Location location, string text)
+ {
+ Print (code, location.IsNull ? "" : location.ToString (), text);
+ }
+ }
+
+ sealed class WarningMessage : AbstractMessage {
+ Location loc = Location.Null;
+ readonly int Level;
+
+ public WarningMessage (int level)
+ {
+ Level = level;
+ }
+
+ public override bool IsWarning {
+ get { return true; }
+ }
+
+ bool IsEnabled (int code)
+ {
+ if (RootContext.WarningLevel < Level)
+ return false;
+
+ if (warning_ignore_table != null) {
+ if (warning_ignore_table.Contains (code)) {
+ return false;
+ }
+ }
+
+ if (warning_regions_table == null || loc.Equals (Location.Null))
+ return true;
+
+ WarningRegions regions = (WarningRegions)warning_regions_table [loc.Name];
+ if (regions == null)
+ return true;
+
+ return regions.IsWarningEnabled (code, loc.Row);
+ }
+
+ public override void Print(int code, string location, string text)
+ {
+ if (!IsEnabled (code)) {
+ extra_information.Clear ();
+ return;
+ }
+
+ if (WarningsAreErrors) {
+ new ErrorMessage ().Print (code, location, text);
+ return;
+ }
+
+ Warnings++;
+ base.Print (code, location, text);
+ }
+
+ public override void Print(int code, Location location, string text)
+ {
+ loc = location;
+ base.Print (code, location, text);
+ }
+
+ public override string MessageType {
+ get {
+ return "warning";
+ }
+ }
+ }
+
+ sealed class ErrorMessage : AbstractMessage {
+
+ public override void Print(int code, string location, string text)
+ {
+ Errors++;
+ base.Print (code, location, text);
+ }
+
+ public override bool IsWarning {
+ get { return false; }
+ }
+
+ public override string MessageType {
+ get {
+ return "error";
+ }
+ }
+
+ }
+
+ public static void FeatureIsNotStandardized (Location loc, string feature)
+ {
+ Report.Error (1644, loc, "Feature `{0}' cannot be used because it is not part of the standardized ISO C# language specification", feature);
+ }
+
+ public static string FriendlyStackTrace (Exception e)
+ {
+ return FriendlyStackTrace (new StackTrace (e, true));
+ }
+
+ static string FriendlyStackTrace (StackTrace t)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ bool foundUserCode = false;
+
+ for (int i = 0; i < t.FrameCount; i++) {
+ StackFrame f = t.GetFrame (i);
+ MethodBase mb = f.GetMethod ();
+
+ if (!foundUserCode && mb.ReflectedType == typeof (Report))
+ continue;
+
+ foundUserCode = true;
+
+ sb.Append ("\tin ");
+
+ if (f.GetFileLineNumber () > 0)
+ sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ());
+
+ sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name);
+
+ bool first = true;
+ foreach (ParameterInfo pi in mb.GetParameters ()) {
+ if (!first)
+ sb.Append (", ");
+ first = false;
+
+ sb.Append (TypeManager.CSharpName (pi.ParameterType));
+ }
+ sb.Append (")\n");
+ }
+
+ return sb.ToString ();
+ }
+
+ public static void StackTrace ()
+ {
+ Console.WriteLine (FriendlyStackTrace (new StackTrace (true)));
+ }
+
+ public static bool IsValidWarning (int code)
+ {
+ return Array.BinarySearch (AllWarnings, code) >= 0;
+ }
+
+ static public void RuntimeMissingSupport (Location loc, string feature)
+ {
+ Report.Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
+ }
+
+ /// <summary>
+ /// In most error cases is very useful to have information about symbol that caused the error.
+ /// Call this method before you call Report.Error when it makes sense.
+ /// </summary>
+ static public void SymbolRelatedToPreviousError (Location loc, string symbol)
+ {
+ SymbolRelatedToPreviousError (loc.ToString (), symbol);
+ }
+
+ static public void SymbolRelatedToPreviousError (MemberInfo mi)
+ {
+ Type dt = TypeManager.DropGenericTypeArguments (mi.DeclaringType);
+ DeclSpace temp_ds = TypeManager.LookupDeclSpace (dt);
+ if (temp_ds == null) {
+ SymbolRelatedToPreviousError (dt.Assembly.Location, TypeManager.GetFullNameSignature (mi));
+ } else {
+ MethodBase mb = mi as MethodBase;
+ if (mb != null) {
+ mb = TypeManager.DropGenericMethodArguments (mb);
+ IMethodData md = TypeManager.GetMethod (mb);
+ SymbolRelatedToPreviousError (md.Location, md.GetSignatureForError ());
+ return;
+ }
+
+ MemberCore mc = temp_ds.GetDefinition (mi.Name);
+ SymbolRelatedToPreviousError (mc);
+ }
+ }
+
+ static public void SymbolRelatedToPreviousError (MemberCore mc)
+ {
+ SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
+ }
+
+ static public void SymbolRelatedToPreviousError (Type type)
+ {
+ type = TypeManager.DropGenericTypeArguments (type);
+
+ if (TypeManager.IsGenericParameter (type)) {
+ TypeParameter tp = TypeManager.LookupTypeParameter (type);
+ if (tp != null) {
+ SymbolRelatedToPreviousError (tp.Location, "");
+ return;
+ }
+ }
+
+ if (type is TypeBuilder) {
+ DeclSpace temp_ds = TypeManager.LookupDeclSpace (type);
+ SymbolRelatedToPreviousError (temp_ds.Location, TypeManager.CSharpName (type));
+ } else if (type.HasElementType) {
+ SymbolRelatedToPreviousError (type.GetElementType ());
+ } else {
+ SymbolRelatedToPreviousError (type.Assembly.Location, TypeManager.CSharpName (type));
+ }
+ }
+
+ static void SymbolRelatedToPreviousError (string loc, string symbol)
+ {
+ extra_information.Add (String.Format ("{0} (Location of the symbol related to previous ", loc));
+ }
+
+ public static void ExtraInformation (Location loc, string msg)
+ {
+ extra_information.Add (String.Format ("{0} {1}", loc, msg));
+ }
+
+ public static WarningRegions RegisterWarningRegion (Location location)
+ {
+ if (warning_regions_table == null)
+ warning_regions_table = new Hashtable ();
+
+ WarningRegions regions = (WarningRegions)warning_regions_table [location.Name];
+ if (regions == null) {
+ regions = new WarningRegions ();
+ warning_regions_table.Add (location.Name, regions);
+ }
+ return regions;
+ }
+
+ static public void Warning (int code, int level, Location loc, string message)
+ {
+ WarningMessage w = new WarningMessage (level);
+ w.Print (code, loc, message);
+ }
+
+ static public void Warning (int code, int level, Location loc, string format, string arg)
+ {
+ WarningMessage w = new WarningMessage (level);
+ w.Print (code, loc, String.Format (format, arg));
+ }
+
+ static public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
+ {
+ WarningMessage w = new WarningMessage (level);
+ w.Print (code, loc, String.Format (format, arg1, arg2));
+ }
+
+ static public void Warning (int code, int level, Location loc, string format, params string[] args)
+ {
+ WarningMessage w = new WarningMessage (level);
+ w.Print (code, loc, String.Format (format, args));
+ }
+
+ static public void Warning (int code, int level, string message)
+ {
+ Warning (code, level, Location.Null, message);
+ }
+
+ static public void Warning (int code, int level, string format, string arg)
+ {
+ Warning (code, level, Location.Null, format, arg);
+ }
+
+ static public void Warning (int code, int level, string format, string arg1, string arg2)
+ {
+ Warning (code, level, Location.Null, format, arg1, arg2);
+ }
+
+ static public void Warning (int code, int level, string format, params string[] args)
+ {
+ Warning (code, level, Location.Null, String.Format (format, args));
+ }
+
+ static public void Error (int code, Location loc, string error)
+ {
+ new ErrorMessage ().Print (code, loc, error);
+ }
+
+ static public void Error (int code, Location loc, string format, string arg)
+ {
+ new ErrorMessage ().Print (code, loc, String.Format (format, arg));
+ }
+
+ static public void Error (int code, Location loc, string format, string arg1, string arg2)
+ {
+ new ErrorMessage ().Print (code, loc, String.Format (format, arg1, arg2));
+ }
+
+ static public void Error (int code, Location loc, string format, params string[] args)
+ {
+ Error (code, loc, String.Format (format, args));
+ }
+
+ static public void Error (int code, string error)
+ {
+ Error (code, Location.Null, error);
+ }
+
+ static public void Error (int code, string format, string arg)
+ {
+ Error (code, Location.Null, format, arg);
+ }
+
+ static public void Error (int code, string format, string arg1, string arg2)
+ {
+ Error (code, Location.Null, format, arg1, arg2);
+ }
+
+ static public void Error (int code, string format, params string[] args)
+ {
+ Error (code, Location.Null, String.Format (format, args));
+ }
+
+ static public void SetIgnoreWarning (int code)
+ {
+ if (warning_ignore_table == null)
+ warning_ignore_table = new Hashtable ();
+
+ warning_ignore_table [code] = true;
+ }
+
+ static public int ExpectedError {
+ set {
+ expected_error = value;
+ }
+ get {
+ return expected_error;
+ }
+ }
+
+ public static int DebugFlags = 0;
+
+ [Conditional ("MCS_DEBUG")]
+ static public void Debug (string message, params object[] args)
+ {
+ Debug (4, message, args);
+ }
+
+ [Conditional ("MCS_DEBUG")]
+ static public void Debug (int category, string message, params object[] args)
+ {
+ if ((category & DebugFlags) == 0)
+ return;
+
+ StringBuilder sb = new StringBuilder (message);
+
+ if ((args != null) && (args.Length > 0)) {
+ sb.Append (": ");
+
+ bool first = true;
+ foreach (object arg in args) {
+ if (first)
+ first = false;
+ else
+ sb.Append (", ");
+ if (arg == null)
+ sb.Append ("null");
+ else if (arg is ICollection)
+ sb.Append (PrintCollection ((ICollection) arg));
+ else
+ sb.Append (arg);
+ }
+ }
+
+ Console.WriteLine (sb.ToString ());
+ }
+
+ static public string PrintCollection (ICollection collection)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ sb.Append (collection.GetType ());
+ sb.Append ("(");
+
+ bool first = true;
+ foreach (object o in collection) {
+ if (first)
+ first = false;
+ else
+ sb.Append (", ");
+ sb.Append (o);
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+ }
+ }
+
+ public enum TimerType {
+ FindMembers = 0,
+ TcFindMembers = 1,
+ MemberLookup = 2,
+ CachedLookup = 3,
+ CacheInit = 4,
+ MiscTimer = 5,
+ CountTimers = 6
+ }
+
+ public enum CounterType {
+ FindMembers = 0,
+ MemberCache = 1,
+ MiscCounter = 2,
+ CountCounters = 3
+ }
+
+ public class Timer
+ {
+ static DateTime[] timer_start;
+ static TimeSpan[] timers;
+ static long[] timer_counters;
+ static long[] counters;
+
+ static Timer ()
+ {
+ timer_start = new DateTime [(int) TimerType.CountTimers];
+ timers = new TimeSpan [(int) TimerType.CountTimers];
+ timer_counters = new long [(int) TimerType.CountTimers];
+ counters = new long [(int) CounterType.CountCounters];
+
+ for (int i = 0; i < (int) TimerType.CountTimers; i++) {
+ timer_start [i] = DateTime.Now;
+ timers [i] = TimeSpan.Zero;
+ }
+ }
+
+ [Conditional("TIMER")]
+ static public void IncrementCounter (CounterType which)
+ {
+ ++counters [(int) which];
+ }
+
+ [Conditional("TIMER")]
+ static public void StartTimer (TimerType which)
+ {
+ timer_start [(int) which] = DateTime.Now;
+ }
+
+ [Conditional("TIMER")]
+ static public void StopTimer (TimerType which)
+ {
+ timers [(int) which] += DateTime.Now - timer_start [(int) which];
+ ++timer_counters [(int) which];
+ }
+
+ [Conditional("TIMER")]
+ static public void ShowTimers ()
+ {
+ ShowTimer (TimerType.FindMembers, "- FindMembers timer");
+ ShowTimer (TimerType.TcFindMembers, "- TypeContainer.FindMembers timer");
+ ShowTimer (TimerType.MemberLookup, "- MemberLookup timer");
+ ShowTimer (TimerType.CachedLookup, "- CachedLookup timer");
+ ShowTimer (TimerType.CacheInit, "- Cache init");
+ ShowTimer (TimerType.MiscTimer, "- Misc timer");
+
+ ShowCounter (CounterType.FindMembers, "- Find members");
+ ShowCounter (CounterType.MemberCache, "- Member cache");
+ ShowCounter (CounterType.MiscCounter, "- Misc counter");
+ }
+
+ static public void ShowCounter (CounterType which, string msg)
+ {
+ Console.WriteLine ("{0} {1}", counters [(int) which], msg);
+ }
+
+ static public void ShowTimer (TimerType which, string msg)
+ {
+ Console.WriteLine (
+ "[{0:00}:{1:000}] {2} (used {3} times)",
+ (int) timers [(int) which].TotalSeconds,
+ timers [(int) which].Milliseconds, msg,
+ timer_counters [(int) which]);
+ }
+ }
+
+ public class InternalErrorException : Exception {
+ public InternalErrorException (Location loc, string text, Exception e)
+ : base (loc + " " + text, e)
+ {
+ }
+
+ public InternalErrorException ()
+ : base ("Internal error")
+ {
+ }
+
+ public InternalErrorException (string message)
+ : base (message)
+ {
+ }
+
+ public InternalErrorException (string message, params object[] args)
+ : base (String.Format (message, args))
+ { }
+ }
+
+ /// <summary>
+ /// Handles #pragma warning
+ /// </summary>
+ public class WarningRegions {
+
+ abstract class PragmaCmd
+ {
+ public int Line;
+
+ protected PragmaCmd (int line)
+ {
+ Line = line;
+ }
+
+ public abstract bool IsEnabled (int code, bool previous);
+ }
+
+ class Disable : PragmaCmd
+ {
+ int code;
+ public Disable (int line, int code)
+ : base (line)
+ {
+ this.code = code;
+ }
+
+ public override bool IsEnabled (int code, bool previous)
+ {
+ return this.code == code ? false : previous;
+ }
+ }
+
+ class DisableAll : PragmaCmd
+ {
+ public DisableAll (int line)
+ : base (line) {}
+
+ public override bool IsEnabled(int code, bool previous)
+ {
+ return false;
+ }
+ }
+
+ class Enable : PragmaCmd
+ {
+ int code;
+ public Enable (int line, int code)
+ : base (line)
+ {
+ this.code = code;
+ }
+
+ public override bool IsEnabled(int code, bool previous)
+ {
+ return this.code == code ? true : previous;
+ }
+ }
+
+ class EnableAll : PragmaCmd
+ {
+ public EnableAll (int line)
+ : base (line) {}
+
+ public override bool IsEnabled(int code, bool previous)
+ {
+ return true;
+ }
+ }
+
+
+ ArrayList regions = new ArrayList ();
+
+ public void WarningDisable (int line)
+ {
+ regions.Add (new DisableAll (line));
+ }
+
+ public void WarningDisable (Location location, int code)
+ {
+ if (CheckWarningCode (code, location))
+ regions.Add (new Disable (location.Row, code));
+ }
+
+ public void WarningEnable (int line)
+ {
+ regions.Add (new EnableAll (line));
+ }
+
+ public void WarningEnable (Location location, int code)
+ {
+ if (CheckWarningCode (code, location))
+ regions.Add (new Enable (location.Row, code));
+ }
+
+ public bool IsWarningEnabled (int code, int src_line)
+ {
+ bool result = true;
+ foreach (PragmaCmd pragma in regions) {
+ if (src_line < pragma.Line)
+ break;
+
+ result = pragma.IsEnabled (code, result);
+ }
+ return result;
+ }
+
+ static bool CheckWarningCode (int code, Location loc)
+ {
+ if (Report.IsValidWarning (code))
+ return true;
+
+ Report.Warning (1691, 1, loc, "`{0}' is not a valid warning number", code.ToString ());
+ return false;
+ }
+ }
+}