--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyVersion("0.25.99")]
+[assembly: AssemblyTitle ("Mono C# Compiler")]
+[assembly: AssemblyDescription ("Mono C# Compiler")]
+[assembly: AssemblyCopyright ("2001, 2002, 2003 Ximian, Inc.")]
+[assembly: AssemblyCompany ("Ximian, Inc.")]
--- /dev/null
+2003-07-22 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation.OverloadResolve): Follow the spec more
+ closely: we eliminate methods in base types when we have an
+ applicable method in a top-level type.
+
+ Please see section 14.5.5.1 for an exact description of what goes
+ on.
+
+ This fixes bug #45127 and a host of other related to corlib compilation.
+
+ * ecore.cs (MethodGroupExpr.DeclaringType): The element in the
+ array is the method corresponding to the top-level type (this is
+ because of the changes made to icall.c) so we change this
+ accordingly.
+
+ (MethodGroupExpr.Name): This too.
+
+ * typemanager.cs (GetElementType): New method which does the right
+ thing when compiling corlib.
+
+ * everywhere: Make use of the above in the relevant places.
+
+2003-07-22 Martin Baulig <martin@ximian.com>
+
+ * cs-parser.jay (invocation_expression): Moved
+ `OPEN_PARENS expression CLOSE_PARENS unary_expression' here from
+ `cast_expression', but create a InvocationOrCast which later
+ resolves to either an Invocation or a Cast.
+
+ * ecore.cs (ExpressionStatement.ResolveStatement): New virtual
+ method; call this before EmitStatement() to make sure that this
+ expression can be used as a statement.
+
+ * expression.cs (InvocationOrCast): New class; resolves to either
+ an Invocation or a Cast.
+
+ * statement.cs (StatementExpression): Call ResolveStatement() on
+ the ExpressionStatement before emitting it.
+
+2003-07-21 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (Invocation.VerifyArgumentsCompat): Check whether
+ `ref' and `out' attributes match; fixes #46220.
+ (MemberAccess.ResolveMemberAccess): You can't reference a type
+ through an expression; fixes #33180.
+ (Indexers.GetIndexersForType): Don't return the indexers from
+ interfaces the class implements; fixes #46502.
+
+2003-07-21 Martin Baulig <martin@ximian.com>
+
+ * class.cs (TypeContainer.CheckPairedOperators): Added CS0660 and
+ CS0661 checks; fixes bug #30442.
+
+2003-07-21 Martin Baulig <martin@ximian.com>
+
+ * decl.cs (AdditionResult): Added `Error'.
+
+ * enum.cs (AddEnumMember): Report a CS0076 if name is `value__'.
+
+ * typemanager.cs (TypeManager.ChangeType): Catch exceptions;
+ makes cs0031.cs actually work.
+
+2003-07-20 Martin Baulig <martin@ximian.com>
+
+ * namespace.cs: Fixed that bug which caused a crash when compiling
+ the debugger's GUI.
+
+2003-07-20 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (LookupTypeReflection): Never expose types which
+ are NotPublic, NestedPrivate, NestedAssembly, or
+ NestedFamANDAssem. We used to return these, and later do a check
+ that would report a meaningful error, but the problem is that we
+ would not get the real match, if there was a name override.
+
+2003-07-18 Miguel de Icaza <miguel@ximian.com>
+
+ * namespace.cs (Namespace, Name): Do not compute the namespace
+ name dynamically, compute it in the constructor. This reduced
+ memory usage by 1697 KB.
+
+ * driver.cs: Use --pause to pause at the end.
+
+2003-07-17 Peter Williams <peter@newton.cx>
+
+ * Makefile: Change the name of the test target so that it doesn't
+ conflict with the recursive test target.
+
+2003-07-17 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (LocalVariableReference.Emit, EmitAssign,
+ AddressOf): Do not use EmitThis, that was wrong, use the actual
+ this pointer.
+
+2003-07-15 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MethodData.Define): While checking if a method is an
+ interface implementation, improve the test: If we are not public
+ (use new test here: use the computed MethodAttributes directly,
+ instead of the parsed modifier flags) check if the `implementing'
+ method comes from an interface or not.
+
+ * pending.cs (VerifyPendingMethods): Slightly better error
+ message.
+
+ * makefile: add test target that does the mcs bootstrap.
+
+2003-07-16 Ravi Pratap <ravi@ximian.com>
+
+ * interface.cs (Define): Do nothing here since there are no
+ members to populate etc. Move the attribute emission out of here
+ since this was just totally the wrong place to put it. Attribute
+ application happens during the 'Emit' phase, not in the 'Define'
+ phase.
+
+ (Emit): Add this method and move the attribute emission here
+
+ * rootcontext.cs (EmitCode): Call the Emit method on interface
+ types too.
+
+2003-07-14 Ravi Pratap M <ravi@ximian.com>
+
+ * expression.cs (OverloadResolve): Report error only if Location
+ is not 'Null' which means that there was a probe going on.
+
+2003-07-14 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (ConditionalLogicalOperator): New public class to
+ implement user defined conditional logical operators.
+ This is section 14.11.2 in the spec and bug #40505.
+
+2003-07-14 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (FieldExpr.DoResolveLValue): Fixed bug #46198.
+
+2003-07-14 Martin Baulig <martin@ximian.com>
+
+ * codegen.cs (EmitContext.InFixedInitializer): New public field.
+
+ * ecore.cs (IVariable.VerifyFixed): New interface method.
+
+ * expression.cs (Unary.ResolveOperator): When resolving the `&'
+ operator, check whether the variable is actually fixed. Fixes bug
+ #36055. Set a variable definitely assigned when taking its
+ address as required by the spec.
+
+ * statement.cs (LocalInfo.IsFixed): New field.
+ (LocalInfo.MakePinned): Set `IsFixed' to true.
+
+2003-07-14 Ravi Pratap M <ravi@ximian.com>
+
+ * attribute.cs (Attribute.Resolve): While doing a Member lookup
+ for .ctors, ensure that we only ask for members declared in the
+ attribute type (BindingFlags.DeclaredOnly).
+
+ Fixes bug #43632.
+
+ * expression.cs (Error_WrongNumArguments): Report error 1501
+ correctly the way CSC does.
+
+2003-07-13 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (MemberAccess.ResolveAsTypeStep): Try to do a type
+ lookup on the fully qualified name, to make things like "X.X" work
+ where "X.X" is a fully qualified type name, but we also have a
+ namespace "X" in the using list. Fixes #41975.
+
+2003-07-13 Martin Baulig <martin@ximian.com>
+
+ * assign.cs (Assign.GetEmbeddedAssign): New protected virtual
+ function. If we're a CompoundAssign, we need to create an embedded
+ CompoundAssign, not an embedded Assign.
+ (Assign.DoResolve): Make this work for embedded CompoundAssign's.
+ Fixes #45854.
+
+2003-07-13 Martin Baulig <martin@ximian.com>
+
+ * typemanager.cs (TypeManager.IsNestedChildOf): Make this actually
+ work to fix bug #46088.
+
+2003-07-13 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Operator.Emit): Do not emit attributes here - it is
+ taken care of by the Method class that we delegate too. This takes
+ care of bug #45876.
+
+2003-07-10 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (TypeOfVoid): New class.
+ (TypeOf): Report a CS0673 if it's System.Void. Fixes #42264.
+
+2003-07-10 Martin Baulig <martin@ximian.com>
+
+ * class.cs (MethodCore.DoDefineParameters): Added CS0225 check;
+ bug #35957.
+
+2003-07-10 Martin Baulig <martin@ximian.com>
+
+ * rootcontext.cs (RootContext.NamespaceLookup): Take a DeclSpace,
+ not a NamespaceEntry, so we can use DeclSpace.CheckAccessLevel().
+
+ * decl.cs (DeclSpace.FindType): Use DeclSpace.CheckAccessLevel().
+
+ * typemanager.cs (TypeManager.IsAccessibleFrom): Removed.
+
+2003-07-10 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (ArrayCreation): Don't use a byte blob for arrays
+ of decimal. Fixes #42850.
+
+ NOTE: I also fixed the created byte blob, but this doesn't work on
+ the MS runtime and csc never produces any byte blobs for decimal
+ arrays.
+
+2003-07-10 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (StructInfo.GetStructInfo): Catch deep cycles in
+ structs; fixes #32068.
+ (Block.AddChildVariableNames): Fixed #44302.
+
+2003-07-07 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * namespace.cs: fixed compilation with csc. It's bugzilla #44302.
+
+2003-07-07 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs: And this test is onger needed.
+
+2003-07-08 Martin Baulig <martin@ximian.com>
+
+ * rootcontext.cs (RootContext.NamespaceLookup): Ignore
+ inaccessible types. Fixes #36313.
+
+ * decl.cs (DeclSpace.FindType): Ignore inaccessible types.
+
+ * namespace.cs (NamespaceEntry): Create implicit entries for all
+ namespaces; ie. if we have `namespace N1.N2.N3 { ... }', we create
+ implicit entries for N1.N2 and N1.
+
+2003-07-08 Martin Baulig <martin@ximian.com>
+
+ Rewrote the handling of namespaces to fix a lot of the issues
+ wrt. `using' aliases etc.
+
+ * namespace.cs (Namespace): Splitted this class into a
+ per-assembly `Namespace' and a per-file `NamespaceEntry'.
+
+ * typemanager.cs (TypeManager.IsNamespace): Removed.
+ (TypeManager.ComputeNamespaces): Only compute namespaces from
+ loaded assemblies here, not the namespaces from the assembly we're
+ currently compiling.
+
+2003-07-08 Martin Baulig <martin@ximian.com>
+
+ * rootcontext.cs, class.cs: Fixed the CS1530 reporting.
+
+2003-07-07 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: Reverted patch from Gonzalo, my previous patch
+ already fixed it.
+
+ I thought about the memory savings here, but LookupTypeReflection
+ is used under already very constrained scenarios. Compiling
+ corlib or mcs only exposes one hit, so it would not really reduce
+ any memory consumption.
+
+2003-07-07 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * typemanager.cs: fixes bug #45889 by only adding public types from
+ other assemblies to the list of known types.
+
+2003-07-07 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs (Attribute.Resolve): Add call to CheckAccessLevel
+ on the type we resolved.
+
+2003-07-05 Martin Baulig <martin@ximian.com>
+
+ * pending.cs (PendingImplementation.ParentImplements): Don't
+ create the proxy if the parent is abstract.
+
+ * class.cs (TypeContainer.DefineIndexers): Process explicit
+ interface implementations first. Fixes #37714.
+
+2003-07-04 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): Events are
+ defined recursively; but since we modify the input parameters
+ (left is set to `this' temporarily), we reset this value if the
+ left_is_explicit is false, which gives the original semantics to
+ the code.
+
+ * literal.cs (NullPointer): new class used to represent a null
+ literal in a pointer context.
+
+ * convert.cs (Convert.ImplicitReferenceConversion): Is the target
+ type is a pointer, use a NullPointer object instead of a
+ NullLiteral. Closes 43687
+
+ (ExplicitConversion): Convert pointer values using
+ the conv opcode to the proper type.
+
+ * ecore.cs (New): change ValueTypeVariable property into a method,
+ that returns whether the valuetype is suitable for being used.
+
+ * expression.cs (Binary.DoNumericPromotions): Only return if we
+ the int constant was a valid uint, and we can return both left and
+ right as uints. If not, we continue processing, to trigger the
+ type conversion. This fixes 39018.
+
+ * statement.cs (Block.EmitMeta): During constant resolution, set
+ the CurrentBlock property on the emitcontext, so that we resolve
+ constants propertly.
+
+2003-07-02 Martin Baulig <martin@ximian.com>
+
+ * codegen.cs (EmitContext.NeedExplicitReturn): New public variable.
+ (EmitContext.EmitTopBlock): Emit an explicit return if it's set.
+
+ * statement.cs (Try.Resolve): Set ec.NeedExplicitReturn rather
+ than emitting it here.
+
+ * statement.cs: Fixed some more flow analysis bugs.
+
+2003-07-02 Martin Baulig <martin@ximian.com>
+
+ * class.cs (MethodData.Define): When implementing interface
+ methods, set Final unless we're Virtual.
+
+ * decl.cs (MemberCore.CheckMethodAgainstBase): Make the CS0506
+ check work for interface methods.
+
+2003-07-01 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (EmitContext.This): Replaced this property with a
+ GetThis() method which takes a Location argument. This ensures
+ that we get the correct error location for a CS0188.
+
+2003-07-01 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs: (Convert.ConvertIntLiteral): Add test for
+ ImplicitStandardConversion.
+
+ * class.cs (TypeContainer.GetClassBases): Small bug fix for 45649.
+
+2003-07-01 Zoltan Varga <vargaz@freemail.hu>
+
+ * expression.cs (ResolveOperator): Fix Concat (string, string, string)
+ optimization.
+
+2003-06-30 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Constructor.Define): Turn off initlocals for unsafe
+ constructors.
+
+ (MethodData.Define): Turn off initlocals for unsafe methods.
+
+2003-06-29 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs (DeclSpace.CheckAccessLevel): Make this routine
+ complete; Fixes #37521.
+
+ * delegate.cs: Use Modifiers.TypeAttr to compute the
+ TypeAttributes, instead of rolling our own. This makes the flags
+ correct for the delegates.
+
+2003-06-28 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Constructor.Define): Set the private flag for static
+ constructors as well.
+
+ * cs-parser.jay (statement_expression): Set the return value to
+ null, to avoid a crash when we catch an error.
+
+2003-06-24 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Applied patch from Jackson that adds support for
+ extern and unsafe modifiers to destructor declarations.
+
+ * expression.cs: Report error 21 if the user is trying to index a
+ System.Array.
+
+ * driver.cs: Add an error message, suggested by the bug report.
+
+ * class.cs (TypeContainer.Emit): Only call EmitFieldInitializers
+ if we do not have a ": this ()" constructor initializer. Fixes 45149
+
+2003-06-14 Miguel de Icaza <miguel@ximian.com>
+
+ * namespace.cs: Add some information to reduce FAQs.
+
+2003-06-13 Miguel de Icaza <miguel@ximian.com>
+
+ * cfold.cs (BinaryFold): BitwiseAnd, BitwiseOr: handle other
+ underlying enumeration types. Fixes #43915.
+
+ * expression.cs: Treat ushort/short as legal values to be used in
+ bitwise operations.
+
+Wed Jun 4 13:19:04 CEST 2003 Paolo Molaro <lupus@ximian.com>
+
+ * delegate.cs: transfer custom attributes for paramenters from
+ the delegate declaration to Invoke and BeginInvoke.
+
+Tue Jun 3 11:11:08 CEST 2003 Paolo Molaro <lupus@ximian.com>
+
+ * attribute.cs: handle custom marshalers and emit marshal info
+ for fields, too.
+
+2003-05-28 Hector E. Gomez Morales <hgomez_36@flashmail.com>
+
+ * makefile.gnu: Added anonymous.cs to the compiler sources.
+
+2003-05-28 Miguel de Icaza <miguel@ximian.com>
+
+ * iterators.cs: Change the name of the proxy class to include two
+ underscores.
+
+ * cs-parser.jay: Update grammar to include anonymous methods.
+
+ * anonymous.cs: new file.
+
+2003-05-27 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Field.Define): Add missing test for pointers and
+ safety.
+
+2003-05-27 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayAccess.GetStoreOpCode): For System.IntPtr,
+ we use the stobj opcode.
+
+ (ArrayCreation.EmitDynamicInitializers): Revert Miguel's patch
+ since it wasn't the correct fix.
+
+ It still is puzzling that we are required to use stobj for IntPtr
+ which seems to be a ValueType.
+
+2003-05-26 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Consider using aliases
+ during regular simple name resolution. Now, the trick is that
+ instead of returning for processing the simplename, we do a
+ TypeManager.LookupType (ie, a rooted lookup as opposed to a
+ contextual lookup type). If a match is found, return that, if
+ not, return for further composition.
+
+ This fixes long-standing 30485.
+
+ * expression.cs (ArrayCreation.EmitDynamicInitializers): When
+ using the address to initialize an object, do an Stobj instead of
+ using the regular Stelem.
+
+ (IndexerAccess.Emit, IndexerAccess.EmitAssign):
+ Pass `is_base_indexer' to Invocation.EmitCall instead of false.
+ Because if we are a BaseIndexerAccess that value will be true.
+ Fixes 43643.
+
+ * statement.cs (GotoCase.Resolve): Return after reporting an
+ error, do not attempt to continue.
+
+ * expression.cs (PointerArithmetic.Emit): If our operand is a
+ long, convert our constants to match the operand before
+ multiplying. Convert to I type before adding. Fixes 43670.
+
+2003-05-14 Ravi Pratap <ravi@ximian.com>
+
+ * enum.cs (ImplicitConversionExists) : Rename to
+ ImplicitEnumConversionExists to remove ambiguity.
+
+ * ecore.cs (NullCast): New type of cast expression class which
+ basically is very similar to EmptyCast with the difference being
+ it still is a constant since it is used only to cast a null to
+ something else
+ (eg. (string) null)
+
+ * convert.cs (ImplicitReferenceConversion): When casting a null
+ literal, we return a NullCast.
+
+ * literal.cs (NullLiteralTyped): Remove - I don't see why this
+ should be around anymore.
+
+ The renaming (reported was slightly wrong). Corrections:
+
+ ConvertImplicitStandard -> ImplicitConversionStandard
+ ConvertExplicitStandard -> ExplicitConversionStandard
+
+ * expression.cs (StaticCallExpr.MakeSimpleCall): Resolve arguments
+ before passing them in !
+
+ * convert.cs (ImplicitConversionStandard): When comparing for
+ equal expr and target types, ensure that expr is not a
+ NullLiteral.
+
+ In general, we must not be checking (expr_type ==
+ target_type) in the top level conversion methods
+ (ImplicitConversion, ExplicitConversion etc). This checking is
+ done in the methods that they delegate to.
+
+2003-05-20 Miguel de Icaza <miguel@ximian.com>
+
+ * convert.cs: Move Error_CannotConvertType,
+ ImplicitReferenceConversion, ImplicitReferenceConversionExists,
+ ImplicitNumericConversion, ImplicitConversionExists,
+ ImplicitUserConversionExists, StandardConversionExists,
+ FindMostEncompassedType, FindMostSpecificSource,
+ FindMostSpecificTarget, ImplicitUserConversion,
+ ExplicitUserConversion, GetConversionOperators,
+ UserDefinedConversion, ConvertImplicit, ConvertImplicitStandard,
+ TryImplicitIntConversion, Error_CannotConvertImplicit,
+ ConvertImplicitRequired, ConvertNumericExplicit,
+ ExplicitReferenceConversionExists, ConvertReferenceExplicit,
+ ConvertExplicit, ConvertExplicitStandard from the ecore.cs into
+ its own file.
+
+ Perform the following renames:
+
+ StandardConversionExists -> ImplicitStandardConversionExists
+ ConvertImplicit -> ImplicitConversion
+ ConvertImplicitStandard -> ImplicitStandardConversion
+ TryImplicitIntConversion -> ImplicitIntConversion
+ ConvertImplicitRequired -> ImplicitConversionRequired
+ ConvertNumericExplicit -> ExplicitNumericConversion
+ ConvertReferenceExplicit -> ExplicitReferenceConversion
+ ConvertExplicit -> ExplicitConversion
+ ConvertExplicitStandard -> ExplicitStandardConversion
+
+2003-05-19 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (TypeInfo.StructInfo): Made this type protected.
+ (TypeInfo): Added support for structs having structs as fields.
+
+ * ecore.cs (FieldExpr): Implement IVariable.
+ (FieldExpr.DoResolve): Call VariableInfo.GetSubStruct() to get the
+ VariableInfo for the field.
+
+2003-05-18 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (This.DoResolve): Report a CS0027 if we're
+ emitting a field initializer.
+
+2003-05-18 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (This.ResolveBase): New public function.
+ (This.DoResolve): Check for CS0188.
+
+ * codegen.cs (EmitContext.This): Just call This.ResolveBase(), not
+ This.Resolve().
+
+ * ecore.cs (MethodGroupExpr.DoResolve): Set the
+ `instance_expression' to null if we don't have any non-static
+ methods.
+
+2003-05-18 Martin Baulig <martin@ximian.com>
+
+ Reworked the way how local variables and parameters are handled by
+ the flow analysis code.
+
+ * statement.cs (TypeInfo, VariableMap): New public classes.
+ (VariableInfo): New public class. This is now responsible for
+ checking whether a variable has been assigned. It is used for
+ parameters and local variables.
+ (Block.EmitMeta): Take the InternalParameters as argument; compute
+ the layout of the flow vectors here.
+ (Block.LocalMap, Block.ParameterMap): New public properties.
+ (FlowBranching): The .ctor doesn't get the InternalParameters
+ anymore since Block.EmitMeta() now computes the layout of the flow
+ vector.
+ (MyStructInfo): This class is now known as `StructInfo' and nested
+ in `TypeInfo'; we don't access this directly anymore.
+
+ * ecore.cs (IVariable): Added `VariableInfo VariableInfo'
+ property and removed IsAssigned(), IsFieldAssigned(),
+ SetAssigned() and SetFieldAssigned(); we now call them on the
+ VariableInfo so we don't need to duplicate this code everywhere.
+
+ * expression.cs (ParameterReference): Added `Block block' argument
+ to the .ctor.
+ (LocalVariableReference, ParameterReference, This): The new
+ VariableInfo class is now responsible for all the definite
+ assignment stuff.
+
+ * codegen.cs (EmitContext.IsVariableAssigned, SetVariableAssigned,
+ IsParameterAssigned, SetParameterAssigned): Removed.
+
+2003-05-18 Martin Baulig <martin@ximian.com>
+
+ * typemanager.cs (InitCoreTypes): Try calling
+ SetCorlibTypeBuilders() with 4 args; if that fails, fall back to
+ the 3-args-version. Corlib now also needs our `void_type'.
+ (GetMethod): Added overloaded version which takes an optional
+ `bool report_errors' to allow lookups of optional methods.
+
+2003-05-12 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (VariableInfo): Renamed to LocalInfo since it's
+ only used for locals and not for parameters.
+
+2003-05-12 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs (InternalParameters.ParameterType): Return the
+ ExternalType of the parameter.
+
+ * parameter.cs (Parameter.ExternalType): drop the two arguments,
+ they were unused.
+
+2003-05-11 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MethodData.Define): Do not set the `newslot' on
+ interface members, if they are also flagged as "override".
+
+ * expression.cs (UnaryMutator.EmitCode): Simple workaround to emit
+ better code for ++i and i++. This only works for static fields
+ and local variables.
+
+ * typemanager.cs (LookupDeclSpace): Add new method, sometimes we
+ want to pull the DeclSpace out of the builder_to_declspace instead
+ of the TypeBuilder (like in TypeContainer.FindMembers).
+
+ * class.cs (TypeContainer.FindMembers): Use LookupDeclSpace
+ instead of LookupTypeContainer. Fixes the crash on .NET for
+ looking up interface members.
+
+ * const.cs: Create our own emit context during the Definition
+ stage, so that constants are evaluated in the proper context, when
+ a recursive definition happens.
+
+2003-05-11 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Block.CreateSwitchBlock): New method. Creates a
+ new block for a switch section.
+ (Block.AddLabel, Block.LookupLabel): If we're a switch section, do
+ the adding/lookup in the switch block. Fixes #39828.
+
+2003-05-09 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (UnaryMutator.LoadOneAndEmitOp): Missing
+ functionality: I needed to convert the data after I had performed
+ the add/sub operation into the operands type size.
+
+ * ecore.cs (ImplicitReferenceConversion): When boxing an interface
+ pass the type for the box operation, otherwise the resulting
+ object would have been of type object.
+
+ (BoxedCast): Add constructor to specify the type to box as.
+
+2003-05-07 Miguel de Icaza <miguel@ximian.com>
+
+ * iterators.cs: I was reusing the `count' variable inadvertently,
+ take steps to not allow this to happen.
+
+2003-05-06 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs (Attribute.Resolve): Params attributes are encoded
+ by creating an array at the point where the params starts and
+ putting all those arguments there, then adjusting the size of the
+ array.
+
+2003-05-05 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (New.AddressOf): Implement interface
+ IMemoryLocation. This is used when the `new' operator is used in
+ the context of an invocation to a method on a value type.
+
+ See http://bugzilla.ximian.com/show_bug.cgi?id=#42390 for an
+ example.
+
+ * namespace.cs: Also check the using aliases here.
+
+ * driver.cs: Move the test for using validity after the types have
+ been entered, so we do a single pass that also includes the using
+ aliases.
+
+ * statement.cs (Try.Resolve): Avoid crashing if there is a failure
+ in the regular case. CreateSiblingForFinally is doing extra
+ error checking.
+
+ * attribute.cs (GetAttributeArgumentExpression): Store the result
+ on an out value, and use the return value to indicate failure
+ instead of using null (which is a valid return for Constant.GetValue).
+
+ * statement.cs: Perform the analysis flow for the increment
+ portion after the statement, because this will be the real flow of
+ execution. Fixes #42385
+
+ * codegen.cs (EmitContext.EmitArgument,
+ EmitContext.EmitStoreArgument): New helper functions when the
+ RemapToProxy flag is set.
+
+ * expression.cs (ParameterReference.EmitLdarg): Expose this useful
+ function.
+
+ Add support for remapping parameters.
+
+ * iterators.cs: Propagate parameter values; Store parameter
+ values in the proxy classes.
+
+2003-05-04 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr): Fix an obvious bug. static fields do not
+ need a proxy reference; I do not know what I was thinking
+
+ * cs-parser.jay (constructor_initializer): catch another error,
+ and display nice message.
+
+ (field_declaration): catch void field declaration
+ to flag a better error.
+
+ * class.cs (MemberBase.CheckBase): Report an error instead of a
+ warning if a new protected member is declared in a struct.
+ (Field.Define): catch the error of readonly/volatile.
+
+ * ecore.cs (FieldExpr.EmitAssign): reuse the field lookup.
+
+ (FieldExpr.AddressOf): ditto. Catch error where the address of a
+ volatile variable is taken
+
+2003-05-02 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Fixed.Resolve): Report an error if we are not in
+ an unsafe context.
+
+2003-05-01 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: reuse the code that handles type clashes for
+ delegates and enumerations.
+
+ * class.cs (Report28): Always report.
+
+ * expression.cs (EncodeAsAttribute): Allow nulls here.
+
+2003-04-28 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs (Attribute.GetAttributeArgumentExpression): Moved
+ the functionality for testing whether an expression is valid for
+ an attribute here. Also handle the case of arrays of elements
+ being stored.
+
+ * expression.cs (ArrayCreation.EncodeAsAttribute): Add support for
+ encoding a linear array into an array of objects that are suitable
+ to be passed to an CustomAttributeBuilder.
+
+ * delegate.cs: Check unsafe types being used outside of an Unsafe context.
+
+ * ecore.cs: (FieldExpr): Handle field remapping here.
+
+ * iteratators.cs: Pass the instance variable (if the method is an
+ instance method) to the constructors, so we can access the field
+ variables on the class.
+
+ TODO: Test this with structs. I think the THIS variable on
+ structs might have to be a pointer, and not a refenrece
+
+2003-04-27 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs (EmitContext.Mapvariable): Adds a mechanism to map
+ local variables to fields in a proxy class.
+
+ * iterators.cs (PopulateProxy): Rename our internal fields to
+ <XXX>.
+ Create a <THIS> field if we are an instance method, so we can
+ reference our parent container variables.
+ (MapVariable): Called back from the EmitContext code to enter a
+ new variable to field mapping into the proxy class (we just create
+ a FieldBuilder).
+
+ * expression.cs
+ (LocalVariableReference.{Emit,EmitAssign,AddressOf}): Add support
+ for using the remapped locals to fields.
+
+ I placed the code here, because that gives the same semantics to
+ local variables, and only changes the Emit code.
+
+ * statement.cs (Fixed.Resolve): it is not allowed to have fixed
+ statements inside iterators.
+ (VariableInfo): Add a FieldBuilder for the cases when we are
+ remapping local variables to fields in a proxy class
+
+ * ecore.cs (SimpleNameResolve): Avoid testing two times for
+ current_block != null.
+
+ * statement.cs (Swithc.SimpleSwitchEmit): Removed code that did
+ not cope with strings, as it has been moved to the
+ TableSwitchEmit. Fixed bug in switch generation.
+
+ * expression.cs (New.DoResolve): Provide more context for the user
+ when reporting an error.
+
+ * ecore.cs (Expression.LoadFromPtr): Use ldind_i when loading
+ pointers.
+
+ * expression.cs (MemberAccess.DoResolve): When we get a type back,
+ check the permissions for it. Note than in a type-resolution
+ context the check was already present in DeclSpace.ResolveType,
+ but was missing from the MemberAccess.
+
+ (ArrayCreation.CheckIndices): warn if the user has
+ more nested levels of expressions, but there are no more
+ dimensions specified. Avoids crash on bug 41906.
+
+2003-04-26 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Block): replace Implicit bool, for a generic
+ flags.
+ New flag: `Unchecked'. This is used during the EmitMeta phase
+ (which is out-of-line with the regular Resolve/Emit process for a
+ statement, as this is done ahead of time, but still gets a chance
+ to call constant resolve).
+
+ (Block.Flags): new enum for adding a new flag.
+
+ (Block.EmitMeta): track the state of unchecked.
+
+ (Unchecked): Set the "UnChecked" flags on any blocks we enclose,
+ to enable constant resolution to work there as well.
+
+2003-04-22 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (ienumerable_type): Also look up
+ System.Collections.IEnumerable.
+
+2003-04-21 Miguel de Icaza <miguel@ximian.com>
+
+ TODO: Test more than one conditional per method.
+
+ * class.cs (Indexer.Define): Report the location where the user is
+ referencing the unsupported feature.
+
+ (MethodData): Overload the use of `conditionals' to
+ minimize the creation of needless ArrayLists. This saves roughly
+ 212kb on my machine.
+
+ (Method): Implement the new IIteratorContainer interface.
+ (Method.SetYields): Implement the method by setting the ModFlags
+ to contain METHOD_YIELDS.
+
+ * expression.cs (Unary.ResolveOperator): Use expr_type, not Expr,
+ which just got set to null.
+
+ * iterators.cs: New file.
+
+ (Yield, YieldBreak): New statements.
+
+ * statement.cs (Return.Resolve): Flag an error if we are used in
+ an iterator method.
+
+ * codegen.cs (InIterator): New flag set if the code is being
+ compiled in an iterator method.
+
+ * modifiers.cs: New flag METHOD_YIELDS. This modifier is an
+ internal modifier, and we just use it to avoid adding extra
+ fields, as this is seldom used.
+
+ * cs-parser.jay: Add yield_statement (yield and yield break).
+
+ * driver.cs: New flag -v2 to turn on version 2 features.
+
+ * cs-tokenizer.cs (Tokenizer): Add yield and __yield to the
+ hashtable when v2 is enabled.
+
+2003-04-20 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (TypeManager.NamespaceClash): Use to check if
+ there is already a namespace defined with this name.
+
+ (TypeManager.InitCoreTypes): Remove the temporary workaround, as
+ people upgraded their corlibs.
+
+ (TypeManager.CoreLookupType): Use LookupTypeDirect, as we
+ always use fully qualified types, no need to use the compiler
+ front end.
+
+ (TypeManager.IsNamespace): Use binarysearch.
+
+ * class.cs (AddClass, AddStruct, AddInterface, AddEvent,
+ AddDelegate): I did not quite use the new IsValid API properly: I
+ have to pass the short-name and the fullname. I was passing only
+ the basename instead of the fullname sometimes.
+
+ (TypeContainer.DefineType): call NamespaceClash.
+
+ * interface.cs (Interface.DefineType): use NamespaceClash before
+ defining the type.
+
+ * delegate.cs (Delegate.DefineType): use NamespaceClash before
+ defining the type.
+
+ * enum.cs: (Enum.DefineType): use NamespaceClash before
+ defining the type.
+
+ * typemanager.cs (: 3-line patch that gives us some tasty 11%
+ speed increase. First, use the negative_hits cache when we get a
+ negative. Second, add the type with its full original name
+ instead of the new . and + encoded name (reflection uses + to
+ separate type from a nested type). Use LookupTypeReflection
+ directly which bypasses the type->name hashtable (that we already
+ know does not contain the type.
+
+ * decl.cs (DeclSpace.ResolveTypeExpr): track the
+ location/container type.
+
+ * driver.cs: When passing utf8, use directly the UTF8Encoding.
+
+2003-04-19 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs (ResolveTypeExpr): Mirror check acess here too.
+
+ * delegate.cs (NewDelegate.Resolve): Test whether an instance
+ method is being referenced in the method group from a static
+ context, and report error 120 if so.
+
+ * expression.cs, ecore.cs (Error_UnexpectedKind): New name for
+ Error118.
+
+ * typemanager.cs: Add intermediate namespaces (if a namespace A.B
+ is created, we create the A namespace).
+
+ * cs-parser.jay: A namespace also introduces a DeclarationFound.
+ Fixes #41591
+
+2003-04-18 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (GetReferenceType, GetPointerType): In .NET each
+ invocation to ModuleBuilder.GetType with the same values will
+ return a new type instance, so we need to cache its return
+ values.
+
+ * expression.cs (Binary.ResolveOperator): Only allow the compare
+ operators on enums if they are of the same type.
+
+ * ecore.cs (Expression.ImplicitReferenceConversion): handle target
+ types of ValueType on their own case. Before we were giving them
+ the same treatment as objects.
+
+ * decl.cs (DeclSpace.IsValid): IsValid takes the short name and
+ fullname. Short name is used to compare against container name.
+ Fullname is used to check against defined namespace names.
+
+ * class.cs (AddProperty, AddField, AddClass, AddStruct, AddEnum,
+ AddDelegate, AddEvent): Pass new parameter to DeclSpace.IsValid
+
+ (Method.CheckBase): Call parent.
+ (MemberBase.CheckBase): Check for protected members on sealed
+ classes.
+ (PropertyBase.CheckBase): Call parent.
+ (Field.Define): Call parent.
+
+ * report.cs: Negative error codes are now mapped to 8000 - code,
+ so that the display is render more nicely.
+
+ * typemanager.cs: Do not use try/catch, instead report a regular
+ error.
+
+ (GetPointerType, GetReferenceType): These methods provide
+ mechanisms to obtain the T* and T& from a T. We had the code
+ previously scattered around the code base, and it also used
+ TypeManager.LookupType that would go through plenty of caches.
+ This one goes directly to the type source.
+
+ In some places we did the Type.GetType followed by
+ ModuleBuilder.GetType, but not in others, so this unifies the
+ processing as well.
+
+ * namespace.cs (VerifyUsing): Perform a non-lazy approach to using
+ statements now that we have namespace information.
+
+ * typemanager.cs (IsNamespace): New method, returns whether the
+ string presented is a namespace or not.
+
+ (ComputeNamespaces): New public entry point, computes the list of
+ available namespaces, using the GetNamespaces API call in Mono, or
+ the slower version in MS.NET.
+
+ Now before we start the semantic analysis phase, we have a
+ complete list of namespaces including everything that the user has
+ provided.
+
+ Deleted old code to cache namespaces in .nsc files.
+
+2003-04-17 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: (TypeContainer.DefineDefaultConstructor): Use the
+ class/struct location definition Location for the implicit
+ constructor location.
+
+ (Operator.Define): Use the location of the operator for the
+ implicit Method definition.
+
+ (Constructor.Emit): use the constructor location for the implicit
+ base initializer constructor.
+
+ * ecore.cs: Remove ITypeExpression. This interface is now gone,
+ and the Expression class now contains two new methods:
+
+ ResolveAsTypeStep and ResolveAsTypeTerminal. This is used to
+ isolate type lookup from the rest of the resolution process.
+
+ Since we use Expressions to hold type definitions due to the way
+ we parse the input we have historically overloaded Resolve to
+ perform the Type lookups if a special flag is passed. Now this is
+ eliminated and two methods take their place.
+
+ The differences in the two methods between xStep and xTerminal is
+ that xStep is involved in our current lookup system that uses
+ SimpleNames to compose a name, while xTerminal is used just to
+ catch the case where the simplename lookup failed.
+
+2003-04-16 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ResolveMemberAccess): Remove redundant code.
+ TypeExpr expressions are always born fully resolved.
+
+ * interface.cs (PopulateMethod): Do not lookup the types twice.
+ We were doing it once during SemanticAnalysis and once during
+ PopulateMethod.
+
+ * cs-parser.jay: Due to our hack in the grammar, things like A.B[]
+ in local variable type definitions, were being returned as a
+ SimpleName (we decomposed everything into a string), that is
+ because primary_expression was being used instead of a type in the
+ grammar (reduce/reduce conflicts).
+
+ The part that was wrong is that we converted the expression into a
+ string (an oversimplification in one hand, compounded with primary
+ expressions doing string concatenation).
+
+ So things like:
+
+ A.B.C [] x;
+
+ Would return "A.B.C[]" as a SimpleName. This stopped things like
+ using clauses from working on this particular context. And a type
+ was being matched directly against "A.B.C[]".
+
+ We now use the correct approach, and allow for ComposedCast to be
+ part of the unary expression. So the "A.B.C []" become a composed
+ cast of "A.B.C" (as a nested group of MemberAccess with a
+ SimpleName at the end) plus the rank composition "[]".
+
+ Also fixes 35567
+
+2003-04-10 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs (CheckAccessLevel): Implement the NestedPrivate rules
+ for the access level checking.
+
+ * class.cs: Cosmetic changes. Renamed `TypeContainer parent' to
+ `TypeContainer container', because I kept getting confused when I
+ was debugging this code.
+
+ * expression.cs (Indexers): Instead of tracking getters/setters,
+ we now track them in parallel. We create one arraylist less, but
+ most importantly it is possible now for the LValue code to find a
+ matching get for a set.
+
+ (IndexerAccess.DoResolveLValue): Update the code.
+ GetIndexersForType has been modified already to extract all the
+ indexers from a type. The code assumed it did not.
+
+ Also make the code set the correct return type for the indexer.
+ This was fixed a long time ago for properties, but was missing for
+ indexers. It used to be void_type.
+
+ (Binary.Emit): Test first for doubles instead of
+ floats, as they are more common.
+
+ (Binary.EmitBranchable): Use the .un version of the branch opcodes
+ when dealing with floats and the <=, >= operators. This fixes bug
+ #39314
+
+ * statement.cs (Foreach.EmitArrayForeach): bug fix: The code used
+ to load the array value by emitting a load on the foreach variable
+ type. This was incorrect.
+
+ We now emit the code to load an element using the the array
+ variable type, and then we emit the conversion operator.
+
+ Fixed #40176
+
+2003-04-10 Zoltan Varga <vargaz@freemail.hu>
+
+ * attribute.cs: Avoid allocation of ArrayLists in the common case.
+
+2003-04-09 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MethodSignature.InheritableMemberSignatureCompare):
+ test for protection before we test for signatures.
+
+ (MethodSignature.ToString): implement.
+
+ * expression.cs (Unary.TryReduceNegative): Add missing minus sign
+ to the case where we reduced into a LongConstant.
+
+ * decl.cs (CheckAccessLevel): If the type is an array, we can not
+ depend on whether the information is acurrate, because the
+ Microsoft runtime will always claim that the array type is public,
+ regardless of the real state.
+
+ If the type is a pointer, another problem happens: the type is
+ reported as non-public in Microsoft.
+
+ In both cases we have to call CheckAccessLevel recursively with
+ the underlying type as the argument to be tested.
+
+2003-04-08 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs (Assign.Emit): If we are dealing with a compound
+ assignment expression, we should use the code path that stores the
+ intermediate result in a temporary value. This fixes #40903.
+
+ *expression.cs (Indirection.ToString): Provide ToString method for
+ debugging.
+
+2003-04-08 Zoltan Varga <vargaz@freemail.hu>
+
+ * class.cs: Null out fields holding references to Block objects so
+ they can be garbage collected.
+
+ * expression.cs (OverloadResolve): Remove unused local.
+
+2003-04-07 Martin Baulig <martin@ximian.com>
+
+ * codegen.cs (EmitContext.CurrentFile): New public field.
+ (EmitContext.Mark): Use the CurrentFile to check whether the
+ location is in the correct file.
+ (EmitContext.EmitTopBlock): Initialize CurrentFile here.
+
+2003-04-07 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (Expression.ResolveBoolean): Don't call ec.Mark().
+
+ * codegen.cs (EmitContext.EmitTopBlock): Don't call Mark() on the
+ location. [FIXME: The location argument which gets passed to this
+ method is sometimes wrong!]
+
+2003-04-07 Nick Drochak <ndrochak@gol.com>
+
+ * codegen.cs: Be more verbose when we can't find the symbol writer dll.
+
+2003-04-07 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Indirection.EmitAssign): We were using the
+ temporary, but returning immediately instead of continuing the
+ EmitAssing flow.
+
+2003-04-06 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Don't report an error
+ if it's a nested child, but also deriving from the outer class.
+ See test 190.cs.
+
+ * typemanager.cs (IsNestedChildOf): Make this work if it's a
+ nested child, but also deriving from the outer class. See
+ test-190.cs.
+ (FilterWithClosure): We may access private members of the outer
+ class if we're a nested child and deriving from the outer class.
+ (RealMemberLookup): Only set `closure_private_ok' if the
+ `original_bf' contained BindingFlags.NonPublic.
+
+2003-04-05 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (FlowBranching.UsageVector.MergeChildren): Fix bug #40670.
+
+2003-04-02 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Event.Define): Do not allow abstract events to have
+ initializers.
+
+2003-04-01 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add error productions for ADD/REMOVE missing a
+ block in event declarations.
+
+ * ecore.cs (FieldExpr.AddressOf): If our instance expression is a
+ value type, get its address.
+
+ * expression.cs (Is.Emit): For action `LeaveOnStack' we were
+ leaving a class on the stack instead of a boolean value (int
+ 0/1). Change the code so we compare against null, and then the
+ result against zero.
+
+ * class.cs (TypeContainer.GetClassBases): We were checking for the
+ parent class being sealed too late.
+
+ * expression.cs (Binary.Emit): For <= and >= when dealing with
+ floating point values, use cgt.un and clt.un instead of cgt and
+ clt alone.
+
+2003-04-01 Zoltan Varga <vargaz@freemail.hu>
+
+ * statement.cs: Apply the same optimization as MS: skip the
+ GetEnumerator returning an IEnumerator, and use the one returning a
+ CharEnumerator instead. This allows us to avoid the try-finally block
+ and the boxing.
+
+2003-03-31 Gaurav Vaish <gvaish_mono@lycos.com>
+
+ * cs-parser.jay: Attributes cannot be applied to
+ namespaces. Fixes #40473
+
+2003-03-31 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * class.cs:
+ (Add*): check if the name is valid using the full name for constants,
+ fields, properties and events.
+
+2003-03-28 Miguel de Icaza <miguel@ximian.com>
+
+ * enum.cs (Enum.DefineType, Enum.IsValidEnumConstant): Also allow
+ char constants to be part of the enumeration.
+
+ * expression.cs (Conditional.DoResolve): Add support for operator
+ true. Implements the missing functionality from 14.12
+
+ * class.cs (TypeContainer.CheckPairedOperators): Report error for missmatch on
+ operator true/false as required by the spec.
+
+ * expression.cs (Unary.ResolveOperator): In LogicalNot, do an
+ implicit conversion to boolean.
+
+ * statement.cs (Statement.ResolveBoolean): A boolean expression is
+ also one where the type implements `operator true'.
+
+ * ecore.cs (Expression.GetOperatorTrue): New helper routine to
+ get an expression that will invoke operator true based on an
+ expression.
+
+ (GetConversionOperators): Removed the hack that called op_True
+ here.
+
+ (Expression.ResolveBoolean): Move this from Statement.
+
+2003-03-17 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr): do not allow initialization of initonly
+ fields on derived classes
+
+2003-03-13 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Block.Emit): Call ig.BeginScope() and
+ ig.EndScope() when compiling with debugging info; call
+ LocalBuilder.SetLocalSymInfo _after_ opening the scope.
+
+2003-03-08 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Indexers): Do not construct immediately, allow
+ for new members to be appended as we go. Fixes 38143
+
+2003-03-07 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * expression.cs: save/restore context when resolving an unchecked
+ expression.
+
+2003-03-05 Miguel de Icaza <miguel@ximian.com>
+
+ * cfold.cs: Catch division by zero in modulus operator during
+ constant folding.
+
+2003-03-03 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs (Interface.DefineMembers): Avoid defining members
+ twice.
+
+2003-02-27 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: handle the +/- options for -noconfig
+
+ * statement.cs (Unckeched.Resolve): Also track the state of
+ unchecked in the Resolve phase.
+
+2003-02-27 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (Expression.MemberLookup): Don't create a
+ MethodGroupExpr for something which is not a method. Fixes #38291.
+
+2003-02-25 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MemberBase.CheckParameters): Also check that the type
+ is unmanaged if it is a pointer.
+
+ * expression.cs (SizeOf.Resolve): Add location information.
+
+ * statement.cs (Block.EmitMeta): Flag error (208) if a pointer to
+ a managed type is declared.
+
+ * expression.cs (Invocation.VerifyArgumentsCompat): Check for the
+ parameter modifiers as well. Fixes bug 38606
+
+ * class.cs: Very sad. Am backing out the speed up changes
+ introduced by the ArrayList -> Array in the TypeContainer, as they
+ were not actually that much faster, and introduced a bug (no error
+ reports on duplicated methods).
+
+ * assign.cs (CompoundAssign.DoLResolve): Resolve the original
+ source first, this will guarantee that we have a valid expression
+ before calling in lower levels functions that will require a
+ resolved object. Then use this original_source in the
+ target.ResolveLValue instead of the original source that was
+ passed to us.
+
+ Another change. Use target.Resolve instead of LValueResolve.
+ Although we are resolving for LValues, we will let the Assign code
+ take care of that (it will be called again from Resolve). This
+ basically allows code like this:
+
+ class X { X operator + (X x, object o) {} X this [int idx] { get; set; } }
+ class Y { void A (X x) { x [0] += o; }
+
+ The problem was that the indexer was trying to resolve for
+ set_Item (idx, object o) and never finding one. The real set_Item
+ was set_Item (idx, X). By delaying the process we get the right
+ semantics.
+
+ Fixes bug 36505
+
+2003-02-23 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Block.Emit): Override this and set ec.CurrentBlock
+ while calling DoEmit ().
+
+ * codegen.cs (EmitContext.Mark): Don't mark locations in other
+ source files; if you use the #line directive inside a method, the
+ compiler stops emitting line numbers for the debugger until it
+ reaches the end of the method or another #line directive which
+ restores the original file.
+
+2003-02-23 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (FlowBranching.UsageVector.MergeChildren): Fix bug #37708.
+
+2003-02-23 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (Block.AddChildVariableNames): We need to call this
+ recursively, not just for our immediate children.
+
+2003-02-23 Martin Baulig <martin@ximian.com>
+
+ * class.cs (Event.Define): Always make the field private, like csc does.
+
+ * typemanager.cs (TypeManager.RealMemberLookup): Make events
+ actually work, fixes bug #37521.
+
+2003-02-23 Miguel de Icaza <miguel@ximian.com>
+
+ * delegate.cs: When creating the various temporary "Parameters"
+ classes, make sure that we call the ComputeAndDefineParameterTypes
+ on those new parameters (just like we do with the formal ones), to
+ allow them to be resolved in the context of the DeclSpace.
+
+ This fixes the bug that Dick observed in Bugzilla #38530.
+
+2003-02-22 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ResolveMemberAccess): When resolving a constant,
+ do not attempt to pull a constant if the value was not able to
+ generate a valid constant.
+
+ * const.cs (LookupConstantValue): Do not report more errors than required.
+
+2003-02-19 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * expression.cs: fixes bug #38328.
+
+2003-02-18 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Changed all the various members that can be part of a
+ class from being an ArrayList to be an Array of the right type.
+ During the DefineType type_list, interface_list, delegate_list and
+ enum_list are turned into types, interfaces, delegates and enums
+ arrays.
+
+ And during the member population, indexer_list, event_list,
+ constant_list, field_list, instance_constructor_list, method_list,
+ operator_list and property_list are turned into their real arrays.
+
+ Although we could probably perform this operation earlier, for
+ good error reporting we need to keep the lists and remove the
+ lists for longer than required.
+
+ This optimization was triggered by Paolo profiling the compiler
+ speed on the output of `gen-sample-program.pl' perl script.
+
+ * decl.cs (DeclSpace.ResolveType): Set the ContainerType, so we do
+ not crash in methods like MemberLookupFailed that use this field.
+
+ This problem arises when the compiler fails to resolve a type
+ during interface type definition for example.
+
+2003-02-18 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Indexers.GetIndexersForType): Interfaces do not
+ inherit from System.Object, so we have to stop at null, not only
+ when reaching System.Object.
+
+2003-02-17 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: (Indexers.GetIndexersForType): Martin's fix used
+ DeclaredOnly because the parent indexer might have had a different
+ name, but did not loop until the top of the hierarchy was reached.
+
+ The problem this one fixes is 35492: when a class implemented an
+ indexer from an interface, we were getting the interface method
+ (which was abstract) and we were flagging an error (can not invoke
+ abstract method).
+
+ This also keeps bug 33089 functioning, and test-148 functioning.
+
+ * typemanager.cs (IsSpecialMethod): The correct way of figuring
+ out if a method is special is to see if it is declared in a
+ property or event, or whether it is one of the predefined operator
+ names. This should fix correctly #36804.
+
+2003-02-15 Miguel de Icaza <miguel@ximian.com>
+
+ The goal here is to remove the dependency on EmptyCast.Peel ().
+ Killing it completely.
+
+ The problem is that currently in a number of places where
+ constants are expected, we have to "probe" for an EmptyCast, and
+ Peel, which is not the correct thing to do, as this will be
+ repetitive and will likely lead to errors.
+
+ The idea is to remove any EmptyCasts that are used in casts that
+ can be reduced to constants, so we only have to cope with
+ constants.
+
+ This bug hunt was triggered by Bug 37363 and the desire to remove
+ the duplicate pattern where we were "peeling" emptycasts to check
+ whether they were constants. Now constants will always be
+ constants.
+
+ * ecore.cs: Use an enumconstant here instead of wrapping with
+ EmptyCast.
+
+ * expression.cs (Cast.TryReduce): Ah, the tricky EnumConstant was
+ throwing me off. By handling this we can get rid of a few hacks.
+
+ * statement.cs (Switch): Removed Peel() code.
+
+2003-02-14 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Location information for error 508
+
+ * expression.cs (New.DoResolve): Add a guard against double
+ resolution of an expression.
+
+ The New DoResolve might be called twice when initializing field
+ expressions (see EmitFieldInitializers, the call to
+ GetInitializerExpression will perform a resolve on the expression,
+ and later the assign will trigger another resolution
+
+ This leads to bugs (#37014)
+
+ * delegate.cs: The signature for EndInvoke should contain any ref
+ or out parameters as well. We were not doing this in the past.
+
+ * class.cs (Field.Define): Do not overwrite the type definition
+ inside the `volatile' group. Turns out that volatile enumerations
+ were changing the type here to perform a validity test, which
+ broke conversions.
+
+2003-02-12 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr.AddressOf): In the particular case of This
+ and structs, we do not want to load the instance variable
+
+ (ImplicitReferenceConversion, ImplicitReferenceConversionExists):
+ enum_type has to be handled like an object reference (implicit
+ conversions exists from this to object), but the regular IsClass
+ and IsValueType tests will never return true for this one.
+
+ Also we use TypeManager.IsValueType instead of type.IsValueType,
+ just for consistency with the rest of the code (this is only
+ needed if we ever use the construct exposed by test-180.cs inside
+ corlib, which we dont today).
+
+2003-02-12 Zoltan Varga <vargaz@freemail.hu>
+
+ * attribute.cs (ApplyAttributes): apply all MethodImplAttributes, not
+ just InternalCall.
+
+2003-02-09 Martin Baulig <martin@ximian.com>
+
+ * namespace.cs (Namespace..ctor): Added SourceFile argument.
+ (Namespace.DefineNamespaces): New static public method; this is
+ called when we're compiling with debugging to add all namespaces
+ to the symbol file.
+
+ * tree.cs (Tree.RecordNamespace): Added SourceFile argument and
+ pass it to the Namespace's .ctor.
+
+ * symbolwriter.cs (SymbolWriter.OpenMethod): Added TypeContainer
+ and MethodBase arguments; pass the namespace ID to the symwriter;
+ pass the MethodBase instead of the token to the symwriter.
+ (SymbolWriter.DefineNamespace): New method to add a namespace to
+ the symbol file.
+
+2003-02-09 Martin Baulig <martin@ximian.com>
+
+ * symbolwriter.cs: New file. This is a wrapper around
+ ISymbolWriter with a cleaner API. We'll dynamically Invoke()
+ methods here in near future.
+
+2003-02-09 Martin Baulig <martin@ximian.com>
+
+ * codegen.cs (EmitContext.Mark): Just pass the arguments to
+ ILGenerator.MarkSequencePoint() which are actually used by the
+ symbol writer.
+
+2003-02-09 Martin Baulig <martin@ximian.com>
+
+ * location.cs (SourceFile): New public sealed class. This
+ contains the name and an index which is used in the location's token.
+ (Location): Reserve an appropriate number of bits in the token for
+ the source file instead of walking over that list, this gives us a
+ really huge performance improvement when compiling with debugging.
+
+ * driver.cs (Driver.parse, Driver.tokenize_file): Take a
+ `SourceFile' argument instead of a string.
+ (Driver.ProcessFile): Add all the files via Location.AddFile(),
+ but don't parse/tokenize here, we need to generate the list of all
+ source files before we do that.
+ (Driver.ProcessFiles): New static function. Parses/tokenizes all
+ the files.
+
+ * cs-parser.jay (CSharpParser): Take a `SourceFile' argument
+ instead of a string.
+
+ * cs-tokenizer.cs (Tokenizer): Take `SourceFile' argument instead
+ of a string.
+
+2003-02-09 Martin Baulig <martin@ximian.com>
+
+ * cs-tokenizer.cs (Tokenizer.PreProcessLine): Also reset the
+ filename on `#line default'.
+
+Sat Feb 8 17:03:16 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * statement.cs: don't clear the pinned var when the fixed statement
+ returns from the method (fixes bug#37752).
+
+Sat Feb 8 12:58:06 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * typemanager.cs: fix from mathpup@mylinuxisp.com (Marcus Urban)
+ to IsValueType.
+
+2003-02-07 Martin Baulig <martin@ximian.com>
+
+ * driver.cs: Removed the `--debug-args' command line argument.
+
+ * codegen.cs (CodeGen.SaveSymbols): Removed, this is now done
+ automatically by the AsssemblyBuilder.
+ (CodeGen.InitializeSymbolWriter): We don't need to call any
+ initialization function on the symbol writer anymore. This method
+ doesn't take any arguments.
+
+2003-02-03 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: (AddAssemblyAndDeps, LoadAssembly): Enter the types
+ from referenced assemblies as well.
+
+2003-02-02 Martin Baulig <martin@ximian.com>
+
+ * class.cs (MethodData.Emit): Generate debugging info for external methods.
+
+2003-02-02 Martin Baulig <martin@ximian.com>
+
+ * class.cs (Constructor.Emit): Open the symbol writer before
+ emitting the constructor initializer.
+ (ConstructorInitializer.Emit): Call ec.Mark() to allow
+ single-stepping through constructor initializers.
+
+2003-01-30 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Handle error 549: do not allow virtual methods in
+ sealed classes.
+
+2003-02-01 Jackson Harper <jackson@latitudegeo.com>
+
+ * decl.cs: Check access levels when resolving types
+
+2003-01-31 Jackson Harper <jackson@latitudegeo.com>
+
+ * statement.cs: Add parameters and locals set in catch blocks that might
+ return to set vector
+
+2003-01-29 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Operator): Set the SpecialName flags for operators.
+
+ * expression.cs (Invocation.DoResolve): Only block calls to
+ accessors and operators on SpecialName methods.
+
+ (Cast.TryReduce): Handle conversions from char constants.
+
+
+Tue Jan 28 17:30:57 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * statement.cs: small memory and time optimization in FlowBranching.
+
+2003-01-28 Pedro Mart <yoros@wanadoo.es>
+
+ * expression.cs (IndexerAccess.DoResolveLValue): Resolve the same
+ problem that the last fix but in the other sid (Set).
+
+ * expression.cs (IndexerAccess.DoResolve): Fix a problem with a null
+ access when there is no indexer in the hierarchy.
+
+2003-01-27 Jackson Harper <jackson@latitudegeo.com>
+
+ * class.cs: Combine some if statements.
+
+2003-01-27 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * driver.cs: fixed bug #37187.
+
+2003-01-27 Pedro Martinez Juliá <yoros@wanadoo.es>
+
+ * expression.cs (IndexerAccess.DoResolve): Before trying to resolve
+ any indexer, it's needed to build a list with all the indexers in the
+ hierarchy (AllGetters), else we have problems. Fixes #35653.
+
+2003-01-23 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MethodData.Define): It is wrong for an interface
+ implementation to be static in both cases: explicit and implicit.
+ We were only handling this in one case.
+
+ Improve the if situation there to not have negations.
+
+ * class.cs (Field.Define): Turns out that we do not need to check
+ the unsafe bit on field definition, only on usage. Remove the test.
+
+2003-01-22 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * driver.cs: use assembly.Location instead of Codebase (the latest
+ patch made mcs fail when using MS assemblies).
+
+2003-01-21 Tim Haynes <thaynes@openlinksw.com>
+
+ * driver.cs: use DirectorySeparatorChar instead of a hardcoded "/" to
+ get the path to *corlib.dll.
+
+2003-01-21 Nick Drochak <ndrochak@gol.com>
+
+ * cs-tokenizer.cs:
+ * pending.cs:
+ * typemanager.cs: Remove compiler warnings
+
+2003-01-20 Duncan Mak <duncan@ximian.com>
+
+ * AssemblyInfo.cs: Bump the version number to 0.19.
+
+2003-01-20 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * cs-tokenizer.cs: little fixes to line numbering when #line is used.
+
+2003-01-18 Zoltan Varga <vargaz@freemail.hu>
+
+ * class.cs (Constructor::Emit): Emit debugging info for constructors.
+
+2003-01-17 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Small fix: we were not comparing the constructor
+ name correctly. Thanks to Zoltan for the initial pointer.
+
+2003-01-16 Jackson Harper <jackson@latitudegeo.com>
+
+ * cs-tokenizer.cs: Set file name when specified with #line
+
+2003-01-15 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Only perform the constructor checks here if we
+ are named like the class; This will help provider a better
+ error. The constructor path is taken when a type definition is
+ not found, but most likely the user forgot to add the type, so
+ report that rather than the constructor error.
+
+Tue Jan 14 10:36:49 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs, rootcontext.cs: small changes to avoid unnecessary memory
+ allocations.
+
+2003-01-13 Jackson Harper <jackson@latitudegeo.com>
+
+ * cs-parser.jay: Add cleanup call.
+
+2003-01-13 Duncan Mak <duncan@ximian.com>
+
+ * cs-tokenizer.cs (Cleanup): Rename to 'cleanup' to make it more
+ consistent with other methods.
+
+2003-01-13 Jackson Harper <jackson@latitudegeo.com>
+
+ * cs-tokenizer.cs: Add Cleanup method, also fix #region error messages.
+
+Sun Jan 12 19:58:42 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * attribute.cs: only set GuidAttr to true when we have a
+ GuidAttribute.
+
+2003-01-09 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * ecore.cs:
+ * expression.cs:
+ * typemanager.cs: fixes to allow mcs compile corlib with the new
+ Type.IsSubclassOf fix.
+
+2003-01-08 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (LocalVariableReference.DoResolve): Classify a
+ constant as a value, not as a variable. Also, set the type for
+ the variable.
+
+ * cs-parser.jay (fixed_statement): take a type instead of a
+ pointer_type, so we can produce a better error message later.
+
+ * statement.cs (Fixed.Resolve): Flag types that are not pointers
+ as an error.
+
+ (For.DoEmit): Make inifinite loops have a
+ non-conditional branch back.
+
+ (Fixed.DoEmit): First populate the pinned variables, then emit the
+ statement, then clear the variables. Before I was emitting the
+ code once for each fixed piece.
+
+
+2003-01-08 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (FlowBranching.MergeChild): A break in a
+ SWITCH_SECTION does not leave a loop. Fixes #36155.
+
+2003-01-08 Martin Baulig <martin@ximian.com>
+
+ * statement.cs (FlowBranching.CheckOutParameters): `struct_params'
+ lives in the same number space than `param_map'. Fixes #36154.
+
+2003-01-07 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (constructor_declaration): Set the
+ Constructor.ModFlags before probing for it. This makes the
+ compiler report 514, 515 and 132 (the code was there, but got
+ broken).
+
+ * statement.cs (Goto.Resolve): Set `Returns' to ALWAYS.
+ (GotoDefault.Resolve): Set `Returns' to ALWAYS.
+ (GotoCase.Resolve): Set `Returns' to ALWAYS.
+
+Tue Jan 7 18:32:24 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * enum.cs: create the enum static fields using the enum type.
+
+Tue Jan 7 18:23:44 CET 2003 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs: don't try to create the ParamBuilder for the return
+ type if it's not needed (and handle it breaking for the ms runtime
+ anyway).
+
+2003-01-06 Jackson Harper <jackson@latitudegeo.com>
+
+ * cs-tokenizer.cs: Add REGION flag to #region directives, and add checks to make sure that regions are being poped correctly
+
+2002-12-29 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs (get_cmd_arg): Fixups to allow \r to terminate
+ the command. This showed up while compiling the JANET source
+ code, which used \r as its only newline separator.
+
+2002-12-28 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method.Define): If we are an operator (because it
+ reuses our code), then set the SpecialName and HideBySig. #36128
+
+2002-12-22 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr.DoResolve): Instead of throwing an
+ exception, report error 120 `object reference required'.
+
+ * driver.cs: Add --pause option, used during to measure the size
+ of the process as it goes with --timestamp.
+
+ * expression.cs (Invocation.DoResolve): Do not allow methods with
+ SpecialName to be invoked.
+
+2002-12-21 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Small fix to the parser: compute the ascii
+ number before adding it.
+
+2002-12-21 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (StandardImplicitConversion): When in an unsafe
+ context, we allow conversion between void * to any other pointer
+ type. This fixes bug #35973.
+
+2002-12-20 Jackson Harper <jackson@latitudegeo.com>
+
+ * codegen.cs: Use Path.GetFileNameWithoutExtension so an exception
+ is not thrown when extensionless outputs are used
+
+2002-12-20 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * rootcontext.cs: fixed compilation of corlib.
+
+2002-12-19 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs (Attributes.Contains): Add new method.
+
+ * class.cs (MethodCore.LabelParameters): if the parameter is an
+ `out' parameter, check that no attribute `[In]' has been passed.
+
+ * enum.cs: Handle the `value__' name in an enumeration.
+
+2002-12-14 Jaroslaw Kowalski <jarek@atm.com.pl>
+
+ * decl.cs: Added special case to allow overrides on "protected
+ internal" methods
+
+2002-12-18 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (Attributes.AddAttributeSection): Rename to this
+ since it makes much more sense.
+
+ (Attributes.ctor): Don't require a Location parameter.
+
+ * rootcontext.cs (AddGlobalAttributeSection): Rename again.
+
+ * attribute.cs (ApplyAttributes): Remove extra Location parameters
+ since we already have that information per attribute.
+
+ * everywhere : make appropriate changes.
+
+ * class.cs (LabelParameters): Write the code which actually
+ applies attributes to the return type. We can't do this on the MS
+ .NET runtime so we flag a warning in the case an exception is
+ thrown.
+
+2002-12-18 Miguel de Icaza <miguel@ximian.com>
+
+ * const.cs: Handle implicit null conversions here too.
+
+2002-12-17 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (MethodCore.LabelParameters): Remove the extra
+ Type [] parameter since it is completely unnecessary. Instead
+ pass in the method's attributes so that we can extract
+ the "return" attribute.
+
+2002-12-17 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (parse): Use Report.Error to flag errors instead
+ of ignoring it and letting the compile continue.
+
+ * typemanager.cs (ChangeType): use an extra argument to return an
+ error condition instead of throwing an exception.
+
+2002-12-15 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Unary.TryReduce): mimic the code for the regular
+ code path. Perform an implicit cast in the cases where we can
+ implicitly convert to one of the integral types, and then reduce
+ based on that constant. This fixes bug #35483.
+
+2002-12-14 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * typemanager.cs: fixed cut & paste error in GetRemoveMethod.
+
+2002-12-13 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * namespace.cs: fixed bug #35489.
+
+2002-12-12 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Remove some dead code.
+
+ * cs-parser.jay: Estimate the number of methods needed
+ (RootContext.MethodCount);
+
+ * cs-tokenizer.cs: Use char arrays for parsing identifiers and
+ numbers instead of StringBuilders.
+
+ * support.cs (PtrHashtable): Add constructor with initial size;
+ We can now reduce reallocations of the method table.
+
+2002-12-10 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (ApplyAttributes): Keep track of the emitted
+ attributes on a per-target basis. This fixes bug #35413.
+
+2002-12-10 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (MainDriver): On rotor encoding 28591 does not exist,
+ default to the Windows 1252 encoding.
+
+ (UnixParseOption): Support version, thanks to Alp for the missing
+ pointer.
+
+ * AssemblyInfo.cs: Add nice assembly information.
+
+ * cs-tokenizer.cs: Add fix from Felix to the #if/#else handler
+ (bug 35169).
+
+ * cs-parser.jay: Allow a trailing comma before the close bracked
+ in the attribute_section production.
+
+ * ecore.cs (FieldExpr.AddressOf): Until I figure out why the
+ address of the instance was being taken, I will take this out,
+ because we take the address of the object immediately here.
+
+2002-12-09 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (AreMultipleAllowed): Take care of the most
+ obvious case where attribute type is not in the current assembly -
+ stupid me ;-)
+
+2002-12-08 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (SimpleName.DoResolve): First perform lookups on using
+ definitions, instead of doing that afterwards.
+
+ Also we use a nice little hack, depending on the constructor, we
+ know if we are a "composed" name or a simple name. Hence, we
+ avoid the IndexOf test, and we avoid
+
+ * codegen.cs: Add code to assist in a bug reporter to track down
+ the source of a compiler crash.
+
+2002-12-07 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (Attribute.ApplyAttributes) : Keep track of which attribute
+ types have been emitted for a given element and flag an error
+ if something which does not have AllowMultiple set is used more
+ than once.
+
+ * typemanager.cs (RegisterAttributeAllowMultiple): Keep track of
+ attribute types and their corresponding AllowMultiple properties
+
+ (AreMultipleAllowed): Check the property for a given type.
+
+ * attribute.cs (Attribute.ApplyAttributes): Register the AllowMultiple
+ property in the case we have a TypeContainer.
+
+ (Attributes.AddAttribute): Detect duplicates and just skip on
+ adding them. This trivial fix catches a pretty gross error in our
+ attribute emission - global attributes were being emitted twice!
+
+ Bugzilla bug #33187 is now fixed.
+
+2002-12-06 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs (pp_expr): Properly recurse here (use pp_expr
+ instead of pp_and).
+
+ * expression.cs (Binary.ResolveOperator): I can only use the
+ Concat (string, string, string) and Concat (string, string,
+ string, string) if the child is actually a concatenation of
+ strings.
+
+2002-12-04 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Small fix, because decimal_digits is used in a
+ context where we need a 2-character lookahead.
+
+ * pending.cs (PendingImplementation): Rework so we can keep track
+ of interface types all the time, and flag those which were
+ implemented by parents as optional.
+
+2002-12-03 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary.ResolveOperator): Use
+ String.Concat(string,string,string) or
+ String.Concat(string,string,string,string) when possible.
+
+ * typemanager: More helper methods.
+
+
+Tue Dec 3 19:32:04 CET 2002 Paolo Molaro <lupus@ximian.com>
+
+ * pending.cs: remove the bogus return from GetMissingInterfaces()
+ (see the 2002-11-06 entry: the mono runtime is now fixed in cvs).
+
+2002-12-02 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * namespace.cs: avoid duplicated 'using xxx' being added to
+ using_clauses. This prevents mcs from issuing and 'ambiguous type' error
+ when we get more than one 'using' statement for the same namespace.
+ Report a CS0105 warning for it.
+
+2002-11-30 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs (consume_identifier): use read directly, instead
+ of calling getChar/putback, uses internal knowledge of it.
+
+ (xtoken): Reorder tokenizer so most common patterns are checked
+ first. This reduces the compilation time in another 5% (from 8.11s
+ average to 7.73s for bootstrapping mcs on my Mobile p4/1.8ghz).
+
+ The parsing time is 22% of the compilation in mcs, and from that
+ 64% is spent on the tokenization process.
+
+ I tried using a binary search for keywords, but this is slower
+ than the hashtable. Another option would be to do a couple of
+ things:
+
+ * Not use a StringBuilder, instead use an array of chars,
+ with a set value. Notice that this way we could catch
+ the 645 error without having to do it *afterwards*.
+
+ * We could write a hand-parser to avoid the hashtable
+ compares altogether.
+
+ The identifier consumption process takes 37% of the tokenization
+ time. Another 15% is spent on is_number. 56% of the time spent
+ on is_number is spent on Int64.Parse:
+
+ * We could probably choose based on the string length to
+ use Int32.Parse or Int64.Parse and avoid all the 64-bit
+ computations.
+
+ Another 3% is spend on wrapping `xtoken' in the `token' function.
+
+ Handle 0xa0 as whitespace (#34752)
+
+2002-11-26 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (IsCLRType): New routine to tell whether a type
+ is one of the builtin types.
+
+ Maybe it needs to use TypeCodes to be faster. Maybe we could use
+ typecode in more places instead of doing pointer comparissions.
+ We could leverage some knowledge about the way the typecodes are
+ laid out.
+
+ New code to cache namespaces in assemblies, it is currently not
+ invoked, to be used soon.
+
+ * decl.cs (DeclSpace.MakeFQN): Simple optimization.
+
+ * expression.cs (Binary.ResolveOperator): specially handle
+ strings, and do not perform user-defined operator overloading for
+ built-in types.
+
+2002-11-24 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Avoid calling Char.IsDigit which is an
+ internalcall as it is a pretty simple operation; Avoid whenever
+ possible to call Char.IsLetter.
+
+ (consume_identifier): Cut by half the number of
+ hashtable calls by merging the is_keyword and GetKeyword behavior.
+
+ Do not short-circuit, because if we do, we
+ report errors (ie, #if false && true would produce an invalid
+ directive error);
+
+
+2002-11-24 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (Cast.TryReduce): If we're in checked syntax,
+ check constant ranges and report a CS0221. Fixes #33186.
+
+2002-11-24 Martin Baulig <martin@ximian.com>
+
+ * cs-parser.jay: Make this work for uninitialized variable
+ declarations in the `for' initializer. Fixes #32416.
+
+2002-11-24 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (Expression.ConvertExplicit): Make casting from/to
+ System.Enum actually work. Fixes bug #32269, added verify-6.cs.
+
+2002-11-24 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (Binary.DoNumericPromotions): Added `check_user_conv'
+ argument; if true, we also check for user-defined conversions.
+ This is only needed if both arguments are of a user-defined type.
+ Fixes #30443, added test-175.cs.
+ (Binary.ForceConversion): Pass the location argument to ConvertImplicit.
+
+ * ecore.cs (Expression.ImplicitUserConversionExists): New method.
+
+2002-11-24 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (ArrayAccess.GetStoreOpcode): New public static
+ function to get the store opcode.
+ (Invocation.EmitParams): Call ArrayAccess.GetStoreOpcode() and
+ only emit the Ldelema if the store opcode is Stobj. You must run
+ both test-34 and test-167 to test this. Fixes #34529.
+
+2002-11-23 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (Expression.MemberLookup): Added additional
+ `qualifier_type' argument which is used when we're being called
+ from MemberAccess.DoResolve() and null if we're called from a
+ SimpleName lookup.
+ (Expression.MemberLookupFailed): New method to report errors; this
+ does the CS1540 check and reports the correct error message.
+
+ * typemanager.cs (MemberLookup): Added additional `qualifier_type'
+ argument for the CS1540 check and redone the way how we're dealing
+ with private members. See the comment in the source code for details.
+ (FilterWithClosure): Reverted this back to revision 1.197; renamed
+ `closure_start_type' to `closure_qualifier_type' and check whether
+ it's not null. It was not this filter being broken, it was just
+ being called with the wrong arguments.
+
+ * expression.cs (MemberAccess.DoResolve): use MemberLookupFinal()
+ and pass it the correct `qualifier_type'; this also does the error
+ handling for us.
+
+2002-11-22 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Invocation.EmitParams): If the we are dealing
+ with a non-built-in value type, load its address as well.
+
+ (ArrayCreation): Use a a pretty constant instead
+ of the hardcoded value 2. Use 6 instead of 2 for the number of
+ static initializers.
+
+ (ArrayCreation.EmitDynamicInitializers): Peel enumerations,
+ because they are not really value types, just glorified integers.
+
+ * driver.cs: Do not append .exe, the CSC compiler does not do it.
+
+ * ecore.cs: Remove redundant code for enumerations, make them use
+ the same code path as everything else, fixes the casting issue
+ with enumerations in Windows.Forms.
+
+ * attribute.cs: Do only cast to string if it is a string, the
+ validation happens later.
+
+ * typemanager.cs: Temproary hack to avoid a bootstrap issue until
+ people upgrade their corlibs.
+
+ * ecore.cs: Oops, enumerations were not following the entire code path
+
+2002-11-21 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (FilterWithClosure): Commented out the test for
+ 1540 in typemanager.cs, as it has problems when accessing
+ protected methods from a parent class (see test-174.cs).
+
+ * attribute.cs (Attribute.ValidateGuid): new method.
+ (Attribute.Resolve): Use above.
+
+2002-11-19 Miguel de Icaza <miguel@ximian.com>
+
+ * enum.cs: In FindMembers, perform a recursive lookup for values. (34308)
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Remove the special
+ handling for enumerations, as we only needed the TypeContainer
+ functionality to begin with (this is required for the fix below to
+ work for enums that reference constants in a container class for
+ example).
+
+ * codegen.cs (EmitContext): Make TypeContainer a DeclSpace.
+
+ * enum.cs (Enum.Define): Use `this' instead of parent, so we have
+ a valid TypeBuilder to perform lookups on.o
+
+ * class.cs (InheritableMemberSignatureCompare): Use true in the
+ call to GetGetMethod and GetSetMethod, because we are comparing
+ the signature, and we need to get the methods *even* if they are
+ private.
+
+ (PropertyBase.CheckBase): ditto.
+
+ * statement.cs (Switch.ResolveAndReduce, Block.EmitMeta,
+ GotoCase.Resolve): Use Peel on EmpytCasts.
+
+ * ecore.cs (EmptyCast): drop child, add Peel method.
+
+2002-11-17 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (EmptyCast.Child): New public property.
+
+ * statement.cs (SwitchLabel.ResolveAndReduce): Check whether the
+ label resolved to an EmptyCast. Fixes #34162.
+ (GotoCase.Resolve): Likewise.
+ (Block.EmitMeta): Likewise.
+
+2002-11-17 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (Invocation.BetterConversion): Prefer int over
+ uint; short over ushort; long over ulong for integer literals.
+ Use ImplicitConversionExists instead of StandardConversionExists
+ since we also need to check for user-defined implicit conversions.
+ Fixes #34165. Added test-173.cs.
+
+2002-11-16 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (Binary.EmitBranchable): Eliminate comparisions
+ with the `true' and `false' literals. Fixes #33151.
+
+2002-11-16 Martin Baulig <martin@ximian.com>
+
+ * typemanager.cs (RealMemberLookup): Reverted Miguel's patch from
+ October 22nd; don't do the cs1540 check for static members.
+
+ * ecore.cs (PropertyExpr.ResolveAccessors): Rewrote this; we're
+ now using our own filter here and doing the cs1540 check again.
+
+2002-11-16 Martin Baulig <martin@ximian.com>
+
+ * support.cs (InternalParameters): Don't crash if we don't have
+ any fixed parameters. Fixes #33532.
+
+2002-11-16 Martin Baulig <martin@ximian.com>
+
+ * decl.cs (MemberCache.AddMethods): Use BindingFlags.FlattenHierarchy
+ when looking up static methods to make this work on Windows.
+ Fixes #33773.
+
+2002-11-16 Martin Baulig <martin@ximian.com>
+
+ * ecore.cs (PropertyExpr.VerifyAssignable): Check whether we have
+ a setter rather than using PropertyInfo.CanWrite.
+
+2002-11-15 Nick Drochak <ndrochak@gol.com>
+
+ * class.cs: Allow acces to block member by subclasses. Fixes build
+ breaker.
+
+2002-11-14 Martin Baulig <martin@ximian.com>
+
+ * class.cs (Constructor.Emit): Added the extern/block check.
+ Fixes bug #33678.
+
+2002-11-14 Martin Baulig <martin@ximian.com>
+
+ * expression.cs (IndexerAccess.DoResolve): Do a DeclaredOnly
+ iteration while looking for indexers, this is needed because the
+ indexer may have a different name in our base classes. Fixed the
+ error reporting (no indexers at all, not get accessor, no
+ overloaded match). Fixes bug #33089.
+ (IndexerAccess.DoResolveLValue): Likewise.
+
+2002-11-14 Martin Baulig <martin@ximian.com>
+
+ * class.cs (PropertyBase.CheckBase): Make this work for multiple
+ indexers. Fixes the first part of bug #33089.
+ (MethodSignature.InheritableMemberSignatureCompare): Added support
+ for properties.
+
+2002-11-13 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (Attribute.Resolve): Catch the
+ NullReferenceException and report it since it isn't supposed to
+ happen.
+
+2002-11-12 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary.EmitBranchable): Also handle the cases for
+ LogicalOr and LogicalAnd that can benefit from recursively
+ handling EmitBranchable. The code now should be nice for Paolo.
+
+2002-11-08 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (LookupType): Added a negative-hit hashtable for
+ the Type lookups, as we perform quite a number of lookups on
+ non-Types. This can be removed once we can deterministically tell
+ whether we have a type or a namespace in advance.
+
+ But this might require special hacks from our corlib.
+
+ * TODO: updated.
+
+ * ecore.cs (TryImplicitIntConversion): Handle conversions to float
+ and double which avoids a conversion from an integer to a double.
+
+ * expression.cs: tiny optimization, avoid calling IsConstant,
+ because it effectively performs the lookup twice.
+
+2002-11-06 Miguel de Icaza <miguel@ximian.com>
+
+ But a bogus return here to keep the semantics of the old code
+ until the Mono runtime is fixed.
+
+ * pending.cs (GetMissingInterfaces): New method used to remove all
+ the interfaces that are already implemented by our parent
+ classes from the list of pending methods.
+
+ * interface.cs: Add checks for calls after ResolveTypeExpr.
+
+2002-11-05 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Class.Emit): Report warning 67: event not used if the
+ warning level is beyond 3.
+
+ * ecore.cs (Expression.ConvertExplicit): Missed a check for expr
+ being a NullLiteral.
+
+ * cs-parser.jay: Fix, Gonzalo reverted the order of the rank
+ specifiers.
+
+ * class.cs (TypeContainer.GetClassBases): Cover a missing code
+ path that might fail if a type can not be resolved.
+
+ * expression.cs (Binary.Emit): Emit unsigned versions of the
+ operators.
+
+ * driver.cs: use error 5.
+
+2002-11-02 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
+
+ * cs-parser.jay: simplified a rule and 5 SR conflicts dissapeared.
+
+2002-11-01 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (switch_section): A beautiful patch from Martin
+ Baulig that fixed 33094.
+
+2002-10-31 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (PropertyExpr.DoResolveLValue, PropertyExpr.DoResolve):
+ Check whether the base is abstract and report an error if so.
+
+ * expression.cs (IndexerAccess.DoResolveLValue,
+ IndexerAccess.DoResolve): ditto.
+
+ (Invocation.DoResolve): ditto.
+
+ (Invocation.FullMethodDesc): Improve the report string.
+
+ * statement.cs (Block): Eliminate IsVariableDefined as it is
+ basically just a wrapper for GetVariableInfo.
+
+ * ecore.cs (SimpleName): Use new
+
+ * support.cs (ReflectionParamter.ParameterType): We unwrap the
+ type, as we return the actual parameter ref/unref state on a
+ different call.
+
+2002-10-30 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs: Return proper flags REF/OUT fixing the previous
+ commit.
+
+ * expression.cs: Reverted last patch, that was wrong. Is_ref is
+ not used to mean `ref' but `ref or out' in ParameterReference
+
+ * delegate.cs (FullDelegateDesc): use ParameterDesc to get the
+ full type signature instead of calling TypeManger.CSharpName
+ ourselves.
+
+ * support.cs (InternalParameters.ParameterDesc): Do not compare
+ directly to the modflags, because REF/OUT will actually be bitsets
+ if set.
+
+ * delegate.cs (VerifyMethod): Check also the modifiers.
+
+ * cs-tokenizer.cs: Fix bug where floating point values with an
+ exponent where a sign was missing was ignored.
+
+ * driver.cs: Allow multiple assemblies to be specified in a single
+ /r: argument
+
+2002-10-28 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Ugly. We had to add a multiplicative_expression,
+ because identifiers after a parenthesis would end up in this kind
+ of production, and we needed to desamiguate it for having casts
+ like:
+
+ (UserDefinedType *) xxx
+
+2002-10-24 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (RealMemberLookup): when we deal with a subclass,
+ we should set on the Bindingflags.NonPublic, but not turn on
+ private_ok. private_ok controls whether a Private member is
+ returned (this is chekced on the filter routine), while the
+ BindingFlags.NonPublic just controls whether private/protected
+ will be allowed. This fixes the problem part of the problem of
+ private properties being allowed to be used in derived classes.
+
+ * expression.cs (BaseAccess): Provide an DoResolveLValue method,
+ so we can call the children DoResolveLValue method (this will
+ properly signal errors on lvalue assignments to base properties)
+
+ * ecore.cs (PropertyExpr.ResolveAccessors): If both setter and
+ getter are null, and we have a property info, we know that this
+ happened because the lookup failed, so we report an error 122 for
+ protection level violation.
+
+ We also silently return if setter and getter are null in the
+ resolve functions, this condition only happens if we have flagged
+ the error before. This is the other half of the problem.
+
+ (PropertyExpr.ResolveAccessors): Turns out that PropertyInfo does
+ not have accessibility information, that is why we were returning
+ true in the filter function in typemanager.cs.
+
+ To properly report 122 (property is inaccessible because of its
+ protection level) correctly, we report this error in ResolveAccess
+ by failing if both the setter and the getter are lacking (ie, the
+ lookup failed).
+
+ DoResolve and DoLResolve have been modified to check for both
+ setter/getter being null and returning silently, the reason being
+ that I did not want to put the knowledge about this error in upper
+ layers, like:
+
+ int old = Report.Errors;
+ x = new PropertyExpr (...);
+ if (old != Report.Errors)
+ return null;
+ else
+ return x;
+
+ So the property expr is returned, but it is invalid, so the error
+ will be flagged during the resolve process.
+
+ * class.cs: Remove InheritablePropertySignatureCompare from the
+ class, as we no longer depend on the property signature to compute
+ whether it is possible to implement a method or not.
+
+ The reason is that calling PropertyInfo.GetGetMethod will return
+ null (in .NET, in Mono it works, and we should change this), in
+ cases where the Get Method does not exist in that particular
+ class.
+
+ So this code:
+
+ class X { public virtual int A { get { return 1; } } }
+ class Y : X { }
+ class Z : Y { public override int A { get { return 2; } } }
+
+ Would fail in Z because the parent (Y) would not have the property
+ defined. So we avoid this completely now (because the alternative
+ fix was ugly and slow), and we now depend exclusively on the
+ method names.
+
+ (PropertyBase.CheckBase): Use a method-base mechanism to find our
+ reference method, instead of using the property.
+
+ * typemanager.cs (GetPropertyGetter, GetPropertySetter): These
+ routines are gone now.
+
+ * typemanager.cs (GetPropertyGetter, GetPropertySetter): swap the
+ names, they were incorrectly named.
+
+ * cs-tokenizer.cs: Return are more gentle token on failure.
+
+ * pending.cs (PendingImplementation.InterfaceMethod): This routine
+ had an out-of-sync index variable, which caused it to remove from
+ the list of pending methods the wrong method sometimes.
+
+2002-10-22 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (PropertyExpr): Do not use PropertyInfo.CanRead,
+ CanWrite, because those refer to this particular instance of the
+ property, and do not take into account the fact that we can
+ override single members of a property.
+
+ Constructor requires an EmitContext. The resolution process does
+ not happen here, but we need to compute the accessors before,
+ because the resolution does not always happen for properties.
+
+ * typemanager.cs (RealMemberLookup): Set private_ok if we are a
+ subclass, before we did not update this flag, but we did update
+ bindingflags.
+
+ (GetAccessors): Drop this routine, as it did not work in the
+ presence of partially overwritten set/get methods.
+
+ Notice that this broke the cs1540 detection, but that will require
+ more thinking.
+
+2002-10-22 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * class.cs:
+ * codegen.cs:
+ * driver.cs: issue a warning instead of an error if we don't support
+ debugging for the platform. Also ignore a couple of errors that may
+ arise when trying to write the symbols. Undo my previous patch.
+
+2002-10-22 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * driver.cs: ignore /debug switch except for Unix platforms.
+
+2002-10-23 Nick Drochak <ndrochak@gol.com>
+
+ * makefile: Remove mcs2.exe and mcs3.exe on 'make clean'
+
+2002-10-21 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Do not make mcs-debug conditional, so we do not break
+ builds that use it.
+
+ * statement.cs (UsageVector.MergeChildren): I would like Martin to
+ review this patch. But basically after all the children variables
+ have been merged, the value of "Breaks" was not being set to
+ new_breaks for Switch blocks. I think that it should be set after
+ it has executed. Currently I set this to the value of new_breaks,
+ but only if new_breaks is FlowReturn.ALWAYS, which is a bit
+ conservative, but I do not understand this code very well.
+
+ I did not break anything in the build, so that is good ;-)
+
+ * cs-tokenizer.cs: Also allow \r in comments as a line separator.
+
+2002-10-20 Mark Crichton <crichton@gimp.org>
+
+ * cfold.cs: Fixed compile blocker. Really fixed it this time.
+
+2002-10-20 Nick Drochak <ndrochak@gol.com>
+
+ * cfold.cs: Fixed compile blocker.
+
+2002-10-20 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: I was chekcing the key, not the file.
+
+2002-10-19 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (UserDefinedConversion): Get rid of the bogus error
+ message that we were generating - we just need to silently return
+ a null.
+
+2002-10-19 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Event.Define): Change my previous commit, as this
+ breaks the debugger. This is a temporary hack, as it seems like
+ the compiler is generating events incorrectly to begin with.
+
+ * expression.cs (Binary.ResolveOperator): Added support for
+ "U operator - (E x, E y)"
+
+ * cfold.cs (BinaryFold): Added support for "U operator - (E x, E
+ y)".
+
+ * ecore.cs (FieldExpr.AddressOf): We had a special code path for
+ init-only variables, but this path did not take into account that
+ there might be also instance readonly variables. Correct this
+ problem.
+
+ This fixes bug 32253
+
+ * delegate.cs (NewDelegate.DoResolve): Catch creation of unsafe
+ delegates as well.
+
+ * driver.cs: Change the extension for modules to `netmodule'
+
+ * cs-parser.jay: Improved slightly the location tracking for
+ the debugger symbols.
+
+ * class.cs (Event.Define): Use Modifiers.FieldAttr on the
+ modifiers that were specified instead of the hardcoded value
+ (FamAndAssem). This was basically ignoring the static modifier,
+ and others. Fixes 32429.
+
+ * statement.cs (Switch.SimpleSwitchEmit): Simplified the code, and
+ fixed a bug in the process (32476)
+
+ * expression.cs (ArrayAccess.EmitAssign): Patch from
+ hwang_rob@yahoo.ca that fixes bug 31834.3
+
+2002-10-18 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Make the module extension .netmodule.
+
+2002-10-16 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Report an error if the resource file is not found
+ instead of crashing.
+
+ * ecore.cs (PropertyExpr.EmitAssign): Pass IsBase instead of
+ false, like Emit does.
+
+2002-10-16 Nick Drochak <ndrochak@gol.com>
+
+ * typemanager.cs: Remove unused private member. Also reported mcs
+ bug to report this as a warning like csc.
+
+2002-10-15 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Statement.Emit): Made this a virtual method; emits
+ the line number info and calls DoEmit().
+ (Statement.DoEmit): New protected abstract method, formerly knows
+ as Statement.Emit().
+
+ * codegen.cs (EmitContext.Mark): Check whether we have a symbol writer.
+
+2002-10-11 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Following the comment from 2002-09-26 to AddMethod, I
+ have fixed a remaining problem: not every AddXXXX was adding a
+ fully qualified name.
+
+ Now everyone registers a fully qualified name in the DeclSpace as
+ being defined instead of the partial name.
+
+ Downsides: we are slower than we need to be due to the excess
+ copies and the names being registered this way.
+
+ The reason for this is that we currently depend (on the corlib
+ bootstrap for instance) that types are fully qualified, because
+ we dump all the types in the namespace, and we should really have
+ types inserted into the proper namespace, so we can only store the
+ basenames in the defined_names array.
+
+2002-10-10 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (ArrayAccess.EmitStoreOpcode): Reverted the patch
+ from bug #31834, see the bug report for a testcase which is
+ miscompiled.
+
+2002-10-10 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (EmitContext.Breaks): Removed, we're now using the
+ flow analysis code for this.
+
+ * statement.cs (Do, While, For): Tell the flow analysis code about
+ infinite loops.
+ (FlowBranching.UsageVector): Added support for infinite loops.
+ (Block.Resolve): Moved the dead code elimination here and use flow
+ analysis to do it.
+
+2002-10-09 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Field.Define): Catch cycles on struct type
+ definitions.
+
+ * typemanager.cs (IsUnmanagedtype): Do not recursively check
+ fields if the fields are static. We only need to check instance
+ fields.
+
+ * expression.cs (As.DoResolve): Test for reference type.
+
+ * statement.cs (Using.ResolveExpression): Use
+ ConvertImplicitRequired, not ConvertImplicit which reports an
+ error on failture
+ (Using.ResolveLocalVariableDecls): ditto.
+
+ * expression.cs (Binary.ResolveOperator): Report errors in a few
+ places where we had to.
+
+ * typemanager.cs (IsUnmanagedtype): Finish implementation.
+
+2002-10-08 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Use StoreFromPtr instead of extracting the type
+ and then trying to use Stelem. Patch is from hwang_rob@yahoo.ca
+
+ * ecore.cs (ImplicitReferenceConversion): It is possible to assign
+ an enumeration value to a System.Enum, but System.Enum is not a
+ value type, but an class type, so we need to box.
+
+ (Expression.ConvertExplicit): One codepath could return
+ errors but not flag them. Fix this. Fixes #31853
+
+ * parameter.cs (Resolve): Do not allow void as a parameter type.
+
+2002-10-06 Martin Baulig <martin@gnome.org>
+
+ * statemenc.cs (FlowBranching.SetParameterAssigned): Don't crash
+ if it's a class type and not a struct. Fixes #31815.
+
+2002-10-06 Martin Baulig <martin@gnome.org>
+
+ * statement.cs: Reworked the flow analysis code a bit to make it
+ usable for dead code elimination.
+
+2002-10-06 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * cs-parser.jay: allow empty source files. Fixes bug #31781.
+
+2002-10-04 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ComposedCast.DoResolveType): A quick workaround
+ to fix the test 165, will investigate deeper.
+
+2002-10-04 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (FlowBranching.UsageVector.MergeChildren): Make
+ finally blocks actually work.
+ (Try.Resolve): We don't need to create a sibling for `finally' if
+ there is no finally block.
+
+2002-10-04 Martin Baulig <martin@gnome.org>
+
+ * class.cs (Constructor.Define): The default accessibility for a
+ non-default constructor is private, not public.
+
+2002-10-04 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Constructor): Make AllowedModifiers public, add
+ EXTERN.
+
+ * cs-parser.jay: Perform the modifiers test here, as the
+ constructor for the Constructor class usually receives a zero
+ because of the way we create it (first we create, later we
+ customize, and we were never checking the modifiers).
+
+ * typemanager.cs (Typemanager.LookupTypeDirect): This new function
+ is a version of LookupTypeReflection that includes the type-name
+ cache. This can be used as a fast path for functions that know
+ the fully qualified name and are only calling into *.GetType() to
+ obtain a composed type.
+
+ This is also used by TypeManager.LookupType during its type
+ composition.
+
+ (LookupType): We now also track the real type name, as sometimes
+ we can get a quey for the real type name from things like
+ ComposedCast. This fixes bug 31422.
+
+ * expression.cs (ComposedCast.Resolve): Since we are obtaining a
+ complete type fullname, it does not have to go through the type
+ resolution system to obtain the composed version of the type (for
+ obtaining arrays or pointers).
+
+ (Conditional.Emit): Use the EmitBoolExpression to
+ generate nicer code, as requested by Paolo.
+
+ (ArrayCreation.CheckIndices): Use the patch from
+ hwang_rob@yahoo.ca to validate the array initializers.
+
+2002-10-03 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (ConstructorInitializer.Emit): simplify code by using
+ Invocation.EmitCall, and at the same time, fix the bugs in calling
+ parent constructors that took variable arguments.
+
+ * ecore.cs (Expression.ConvertNumericExplicit,
+ Expression.ImplicitNumericConversion): Remove the code that
+ manually wrapped decimal (InternalTypeConstructor call is now gone
+ as well).
+
+ * expression.cs (Cast.TryReduce): Also handle decimal types when
+ trying to perform a constant fold on the type.
+
+ * typemanager.cs (IsUnmanagedtype): Partially implemented.
+
+ * parameter.cs: Removed ResolveAndDefine, as it was not needed, as
+ that only turned off an error report, and did nothing else.
+
+2002-10-02 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Handle and ignore /fullpaths
+
+2002-10-01 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary.ResolveOperator): Catch the case where
+ DoNumericPromotions returns true,
+
+ (Binary.DoNumericPromotions): Simplify the code, and the tests.
+
+2002-09-27 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (EventExpr.Emit): Instead of emitting an exception,
+ report error 70.
+
+2002-09-26 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (ConvertNumericExplicit): It is not enough that the
+ conversion exists, but it is also required that the conversion be
+ performed. This manifested in "(Type64Enum) 2".
+
+ * class.cs (TypeManager.AddMethod): The fix is not to change
+ AddEnum, because that one was using a fully qualified name (every
+ DeclSpace derivative does), but to change the AddMethod routine
+ that was using an un-namespaced name. This now correctly reports
+ the duplicated name.
+
+ Revert patch until I can properly fix it. The issue
+ is that we have a shared Type space across all namespaces
+ currently, which is wrong.
+
+ Options include making the Namespace a DeclSpace, and merge
+ current_namespace/current_container in the parser.
+
+2002-09-25 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Improve error reporting when we get a different
+ kind of expression in local_variable_type and
+ local_variable_pointer_type.
+
+ Propagate this to avoid missleading errors being reported.
+
+ * ecore.cs (ImplicitReferenceConversion): treat
+ TypeManager.value_type as a target just like object_type. As
+ code like this:
+
+ ValueType v = 1;
+
+ Is valid, and needs to result in the int 1 being boxed before it
+ is assigned to the value type v.
+
+ * class.cs (TypeContainer.AddEnum): Use the basename, not the name
+ to validate the enumeration name.
+
+ * expression.cs (ArrayAccess.EmitAssign): Mimic the same test from
+ EmitDynamicInitializers for the criteria to use Ldelema. Thanks
+ to hwang_rob@yahoo.ca for finding the bug and providing a patch.
+
+ * ecore.cs (TryImplicitIntConversion): When doing an
+ implicit-enumeration-conversion, check if the type is 64-bits and
+ perform a conversion before passing to EnumConstant.
+
+2002-09-23 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs (Error_AmbiguousTypeReference); New routine used to
+ report ambiguous type references. Unlike the MS version, we
+ report what the ambiguity is. Innovation at work ;-)
+
+ (DeclSpace.FindType): Require a location argument to
+ display when we display an ambiguous error.
+
+ * ecore.cs: (SimpleName.DoResolveType): Pass location to FindType.
+
+ * interface.cs (GetInterfaceTypeByName): Pass location to FindType.
+
+ * expression.cs (EmitDynamicInitializers): Apply patch from
+ hwang_rob@yahoo.ca that fixes the order in which we emit our
+ initializers.
+
+2002-09-21 Martin Baulig <martin@gnome.org>
+
+ * delegate.cs (Delegate.VerifyApplicability): Make this work if the
+ delegate takes no arguments.
+
+2002-09-20 Miguel de Icaza <miguel@ximian.com>
+
+ * constant.cs: Use Conv_U8 instead of Conv_I8 when loading longs
+ from integers.
+
+ * expression.cs: Extract the underlying type.
+
+ * ecore.cs (StoreFromPtr): Use TypeManager.IsEnumType instad of IsEnum
+
+ * decl.cs (FindType): Sorry about this, fixed the type lookup bug.
+
+2002-09-19 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer.DefineType): We can not use the nice
+ PackingSize with the size set to 1 DefineType method, because it
+ will not allow us to define the interfaces that the struct
+ implements.
+
+ This completes the fixing of bug 27287
+
+ * ecore.cs (Expresion.ImplicitReferenceConversion): `class-type S'
+ means also structs. This fixes part of the problem.
+ (Expresion.ImplicitReferenceConversionExists): ditto.
+
+ * decl.cs (DeclSparce.ResolveType): Only report the type-not-found
+ error if there were no errors reported during the type lookup
+ process, to avoid duplicates or redundant errors. Without this
+ you would get an ambiguous errors plus a type not found. We have
+ beaten the user enough with the first error.
+
+ (DeclSparce.FindType): Emit a warning if we have an ambiguous
+ reference.
+
+ * ecore.cs (SimpleName.DoResolveType): If an error is emitted
+ during the resolution process, stop the lookup, this avoids
+ repeated error reports (same error twice).
+
+ * rootcontext.cs: Emit a warning if we have an ambiguous reference.
+
+ * typemanager.cs (LookupType): Redo the type lookup code to match
+ the needs of System.Reflection.
+
+ The issue is that System.Reflection requires references to nested
+ types to begin with a "+" sign instead of a dot. So toplevel
+ types look like: "NameSpace.TopLevelClass", and nested ones look
+ like "Namespace.TopLevelClass+Nested", with arbitrary nesting
+ levels.
+
+2002-09-19 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (EmitContext.EmitTopBlock): If control flow analysis
+ says that a method always returns or always throws an exception,
+ don't report the CS0161.
+
+ * statement.cs (FlowBranching.UsageVector.MergeChildren): Always
+ set `Returns = new_returns'.
+
+2002-09-19 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): When resolving
+ to an enum constant, check for a CS0176.
+
+2002-09-18 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer.CheckPairedOperators): Now we check
+ for operators that must be in pairs and report errors.
+
+ * ecore.cs (SimpleName.DoResolveType): During the initial type
+ resolution process, when we define types recursively, we must
+ check first for types in our current scope before we perform
+ lookups in the enclosing scopes.
+
+ * expression.cs (MakeByteBlob): Handle Decimal blobs.
+
+ (Invocation.VerifyArgumentsCompat): Call
+ TypeManager.TypeToCoreType on the parameter_type.GetElementType.
+ I thought we were supposed to always call this, but there are a
+ few places in the code where we dont do it.
+
+2002-09-17 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Add support in -linkres and -resource to specify the
+ name of the identifier.
+
+2002-09-16 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (StandardConversionExists): Sync with the conversion
+ code: allow anything-* to void* conversions.
+
+ (FindMostSpecificSource): Use an Expression argument
+ instead of a Type, because we might be handed over a Literal which
+ gets a few more implicit conversions that plain types do not. So
+ this information was being lost.
+
+ Also, we drop the temporary type-holder expression when not
+ required.
+
+2002-09-17 Martin Baulig <martin@gnome.org>
+
+ * class.cs (PropertyBase.CheckBase): Don't check the base class if
+ this is an explicit interface implementation.
+
+2002-09-17 Martin Baulig <martin@gnome.org>
+
+ * class.cs (PropertyBase.CheckBase): Make this work for indexers with
+ different `IndexerName' attributes.
+
+ * expression.cs (BaseIndexerAccess): Rewrote this class to use IndexerAccess.
+ (IndexerAccess): Added special protected ctor for BaseIndexerAccess and
+ virtual CommonResolve().
+
+2002-09-16 Miguel de Icaza <miguel@ximian.com>
+
+ * enum.cs (LookupEnumValue): Use the EnumConstant declared type,
+ and convert that to the UnderlyingType.
+
+ * statement.cs (Foreach.Resolve): Indexers are just like variables
+ or PropertyAccesses.
+
+ * cs-tokenizer.cs (consume_string): Track line numbers and columns
+ inside quoted strings, we were not doing this before.
+
+2002-09-16 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (MethodGroupExpr.DoResolve): If we have an instance expression,
+ resolve it. This is needed for the definite assignment check of the
+ instance expression, fixes bug #29846.
+ (PropertyExpr.DoResolve, EventExpr.DoResolve): Likewise.
+
+2002-09-16 Nick Drochak <ndrochak@gol.com>
+
+ * parameter.cs: Fix compile error. Cannot reference static member
+ from an instance object. Is this an mcs bug?
+
+2002-09-14 Martin Baulig <martin@gnome.org>
+
+ * decl.cs (MemberCache.SetupCacheForInterface): Don't add an interface
+ multiple times. Fixes bug #30295, added test-166.cs.
+
+2002-09-14 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Block.Emit): Don't emit unreachable code.
+ (Switch.SimpleSwitchEmit, Switch.TableSwitchEmit): Check for missing
+ `break' statements.
+ (Goto.Emit, Continue.Emit): Set ec.Breaks = true.
+
+2002-09-14 Martin Baulig <martin@gnome.org>
+
+ * parameter.cs (Parameter.Attributes): Make this work if Modifier.ISBYREF
+ is set.
+
+2002-09-14 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.IsNestedChildOf): This must return false
+ if `type == parent' since in this case `type.IsSubclassOf (parent)' will
+ be false on the ms runtime.
+
+2002-09-13 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Include the member name in
+ the CS0038 error message.
+
+2002-09-12 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (CheckedExpr, UnCheckedExpr): If we have a
+ constant inside, return it.
+
+2002-09-12 Martin Baulig <martin@gnome.org>
+
+ * cfold.cs (ConstantFold.DoConstantNumericPromotions): Check whether an
+ implicit conversion can be done between enum types.
+
+ * enum.cs (Enum.LookupEnumValue): If the value is an EnumConstant,
+ check whether an implicit conversion to the current enum's UnderlyingType
+ exists and report an error if not.
+
+ * codegen.cs (CodeGen.Init): Delete the symbol file when compiling
+ without debugging support.
+
+ * delegate.cs (Delegate.CloseDelegate): Removed, use CloseType instead.
+ Fixes bug #30235. Thanks to Ricardo Fernández Pascual.
+
+2002-09-12 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.IsNestedChildOf): New method.
+
+ * ecore.cs (IMemberExpr.DeclaringType): New property.
+ (SimpleName.SimpleNameResolve): Check whether we're accessing a
+ nonstatic member of an outer type (CS0038).
+
+2002-09-11 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Activate the using-error detector at warning level
+ 4 (at least for MS-compatible APIs).
+
+ * namespace.cs (VerifyUsing): Small buglett fix.
+
+ * pending.cs (PendingImplementation): pass the container pointer.
+
+ * interface.cs (GetMethods): Allow for recursive definition. Long
+ term, I would like to move every type to support recursive
+ definitions, not the current ordering mechanism that we have right
+ now.
+
+ The situation is this: Attributes are handled before interfaces,
+ so we can apply attributes to interfaces. But some attributes
+ implement interfaces, we will now handle the simple cases
+ (recursive definitions will just get an error).
+
+ * parameter.cs: Only invalidate types at the end if we fail to
+ lookup all types.
+
+2002-09-09 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (PropertyExpr.Emit): Also check for
+ TypeManager.system_int_array_get_length so this'll also work when
+ compiling corlib. Fixes #30003.
+
+2002-09-09 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (ArrayCreation.MakeByteBlob): Added support for enums
+ and throw an exception if we can't get the type's size. Fixed #30040,
+ added test-165.cs.
+
+2002-09-09 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (PropertyExpr.DoResolve): Added check for static properies.
+
+ * expression.cs (SizeOf.DoResolve): Sizeof is only allowed in unsafe
+ context. Fixes bug #30027.
+
+ * delegate.cs (NewDelegate.Emit): Use OpCodes.Ldvirtftn for
+ virtual functions. Fixes bug #30043, added test-164.cs.
+
+2002-09-08 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs : Fix a small NullRef crash thanks to my stupidity.
+
+2002-09-08 Nick Drochak <ndrochak@gol.com>
+
+ * driver.cs: Use an object to get the windows codepage since it's not a
+ static property.
+
+2002-09-08 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (For.Emit): for infinite loops (test == null)
+ return whether there is a break inside, not always "true".
+
+ * namespace.cs (UsingEntry): New struct to hold the name of the
+ using definition, the location where it is defined, and whether it
+ has been used in a successful type lookup.
+
+ * rootcontext.cs (NamespaceLookup): Use UsingEntries instead of
+ strings.
+
+ * decl.cs: ditto.
+
+2002-09-06 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs : Fix incorrect code which relied on catching
+ a NullReferenceException to detect a null being passed in
+ where an object was expected.
+
+2002-09-06 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Try): flag the catch variable as assigned
+
+ * expression.cs (Cast): Simplified by using ResolveType instead of
+ manually resolving.
+
+ * statement.cs (Catch): Fix bug by using ResolveType.
+
+2002-09-06 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (BetterConversion): Special case for when we have
+ a NullLiteral as the argument and we have to choose between string
+ and object types - we choose string the way csc does.
+
+ * attribute.cs (Attribute.Resolve): Catch the
+ NullReferenceException and report error #182 since the Mono
+ runtime no more has the bug and having this exception raised means
+ we tried to select a constructor which takes an object and is
+ passed a null.
+
+2002-09-05 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation.OverloadResolve): Flag a nicer error
+ message (1502, 1503) when we can't locate a method after overload
+ resolution. This is much more informative and closes the bug
+ Miguel reported.
+
+ * interface.cs (PopulateMethod): Return if there are no argument
+ types. Fixes a NullReferenceException bug.
+
+ * attribute.cs (Attribute.Resolve): Ensure we allow TypeOf
+ expressions too. Previously we were checking only in one place for
+ positional arguments leaving out named arguments.
+
+ * ecore.cs (ImplicitNumericConversion): Conversion from underlying
+ type to the enum type is not allowed. Remove code corresponding to
+ that.
+
+ (ConvertNumericExplicit): Allow explicit conversions from
+ the underlying type to enum type. This precisely follows the spec
+ and closes a bug filed by Gonzalo.
+
+2002-09-04 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * compiler.csproj:
+ * compiler.csproj.user: patch from Adam Chester (achester@bigpond.com).
+
+2002-09-03 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (SwitchLabel.ResolveAndReduce): In the string case,
+ it was important that we stored the right value after the
+ reduction in `converted'.
+
+2002-09-04 Martin Baulig <martin@gnome.org>
+
+ * location.cs (Location.SymbolDocument): Use full pathnames for the
+ source files.
+
+2002-08-30 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ComposedCast): Use DeclSparce.ResolveType instead
+ of the expression resolve mechanism, because that will catch the
+ SimpleName error failures.
+
+ (Conditional): If we can not resolve the
+ expression, return, do not crash.
+
+2002-08-29 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * cs-tokenizer.cs:
+ (location): display token name instead of its number.
+
+2002-08-28 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Binary.ResolveOperator): Don't silently return
+ but return an error if an operator cannot be applied between two
+ enum types.
+
+2002-08-28 Martin Baulig <martin@gnome.org>
+
+ * class.cs (Constructor.Define): Set the permission attributes
+ correctly instead of making all constructors public.
+
+2002-08-28 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.DoResolve): Do a TypeManager.MemberLook
+ for private members before reporting a CS0103; if we find anything,
+ it's a CS0122.
+
+2002-08-28 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.FilterWithClosure): It's not enough
+ to check whether `closure_start_type == closure_invocation_type',
+ we also need to check whether `m.DeclaringType == closure_invocation_type'
+ before bypassing the permission checks. We might be accessing
+ protected/private members from the base class.
+ (TypeManager.RealMemberLookup): Only set private_ok if private
+ members were requested via BindingFlags.NonPublic.
+
+ * ecore.cs (MethodGroupExpr.IsExplicitImpl): New property.
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): Set
+ MethodGroupExpr.IsExplicitImpl if appropriate.
+ (Invocation.DoResolve): Don't report the CS0120 for explicit
+ interface implementations.
+
+2002-08-27 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Invocation.DoResolve): If this is a static
+ method and we don't have an InstanceExpression, we must report
+ a CS0120.
+
+2002-08-25 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Binary.ResolveOperator): Don't allow `!=' and
+ `==' between a valuetype and an object.
+
+2002-08-25 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (TypeExpr): Provide a ToString method.
+
+2002-08-24 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (CodeGen.InitMonoSymbolWriter): The symbol file is
+ now called proggie.dbg and it's a binary file.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * decl.cs (MemberCache.AddMethods): Ignore varargs methods.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * struct.cs (MyStructInfo.ctor): Make this work with empty
+ structs; it's not allowed to use foreach() on null.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (CodeGen.InitMonoSymbolWriter): Tell the symbol
+ writer the full pathname of the generated assembly.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * statements.cs (FlowBranching.UsageVector.MergeChildren):
+ A `finally' block never returns or breaks; improved handling of
+ unreachable code.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Throw.Resolve): Allow `throw null'.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): If this is an
+ EventExpr, don't do a DeclaredOnly MemberLookup, but check whether
+ `ee.EventInfo.DeclaringType == ec.ContainerType'. The
+ MemberLookup would return a wrong event if this is an explicit
+ interface implementation and the class has an event with the same
+ name.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Block.AddChildVariableNames): New public method.
+ (Block.AddChildVariableName): Likewise.
+ (Block.IsVariableNameUsedInChildBlock): Likewise.
+ (Block.AddVariable): Check whether a variable name has already
+ been used in a child block.
+
+ * cs-parser.jay (declare_local_variables): Mark all variable names
+ from the current block as being used in a child block in the
+ implicit block.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (CodeGen.InitializeSymbolWriter): Abort if we can't
+ find the symbol writer.
+
+ * driver.cs: csc also allows the arguments to /define being
+ separated by commas, not only by semicolons.
+
+2002-08-23 Martin Baulig <martin@gnome.org>
+
+ * interface.cs (Interface.GetMembers): Added static check for events.
+
+2002-08-15 Martin Baulig <martin@gnome.org>
+
+ * class.cs (MethodData.EmitDestructor): In the Expression.MemberLookup
+ call, use ec.ContainerType.BaseType as queried_type and invocation_type.
+
+ * ecore.cs (Expression.MemberLookup): Added documentation and explained
+ why the MethodData.EmitDestructor() change was necessary.
+
+2002-08-20 Martin Baulig <martin@gnome.org>
+
+ * class.cs (TypeContainer.FindMembers): Added static check for events.
+
+ * decl.cs (MemberCache.AddMembers): Handle events like normal members.
+
+ * typemanager.cs (TypeHandle.GetMembers): When queried for events only,
+ use Type.GetEvents(), not Type.FindMembers().
+
+2002-08-20 Martin Baulig <martin@gnome.org>
+
+ * decl.cs (MemberCache): Added a special method cache which will
+ be used for method-only searched. This ensures that a method
+ search will return a MethodInfo with the correct ReflectedType for
+ inherited methods.
+
+2002-08-20 Martin Baulig <martin@gnome.org>
+
+ * decl.cs (DeclSpace.FindMembers): Made this public.
+
+2002-08-20 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * delegate.cs: fixed build on windows.
+ [FIXME: Filed as bug #29150: MCS must report these errors.]
+
+2002-08-19 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (StandardConversionExists): Return a false
+ if we are trying to convert the void type to anything else
+ since that is not allowed.
+
+ * delegate.cs (DelegateInvocation.DoResolve): Ensure that
+ we flag error 70 in the event an event is trying to be accessed
+ directly from outside the declaring type.
+
+2002-08-20 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs, decl.cs: Moved MemberList, IMemberContainer and
+ MemberCache from typemanager.cs to decl.cs.
+
+2002-08-19 Martin Baulig <martin@gnome.org>
+
+ * class.cs (TypeContainer): Implement IMemberContainer.
+ (TypeContainer.DefineMembers): Create the MemberCache.
+ (TypeContainer.FindMembers): Do better BindingFlags checking; only
+ return public members if BindingFlags.Public was given, check
+ whether members are static.
+
+2002-08-16 Martin Baulig <martin@gnome.org>
+
+ * decl.cs (DeclSpace.Define): Splitted this in Define and
+ DefineMembers. DefineMembers is called first and initializes the
+ MemberCache.
+
+ * rootcontext.cs (RootContext.DefineMembers): New function. Calls
+ DefineMembers() on all our DeclSpaces.
+
+ * class.cs (TypeContainer.Define): Moved all code to DefineMembers(),
+ but call DefineMembers() on all nested interfaces. We call their
+ Define() in our new Define() function.
+
+ * interface.cs (Interface): Implement IMemberContainer.
+ (Interface.Define): Moved all code except the attribute stuf to
+ DefineMembers().
+ (Interface.DefineMembers): Initialize the member cache.
+
+ * typemanager.cs (IMemberFinder): Removed this interface, we don't
+ need this anymore since we can use MemberCache.FindMembers directly.
+
+2002-08-19 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (MemberCache): When creating the cache for an
+ interface type, add all inherited members.
+ (TypeManager.MemberLookup_FindMembers): Changed `ref bool searching'
+ to `out bool used_cache' and documented it.
+ (TypeManager.MemberLookup): If we already used the cache in the first
+ iteration, we don't need to do the interfaces check.
+
+2002-08-19 Martin Baulig <martin@gnome.org>
+
+ * decl.cs (DeclSpace.FindMembers): New abstract method. Moved this
+ here from IMemberFinder and don't implement this interface anymore.
+ (DeclSpace.MemberCache): Moved here from IMemberFinder.
+
+ * typemanager.cs (IMemberFinder): This interface is now only used by
+ classes which actually support the member cache.
+ (TypeManager.builder_to_member_finder): Renamed to builder_to_declspace
+ since we only put DeclSpaces into this Hashtable.
+ (MemberLookup_FindMembers): Use `builder_to_declspace' if the type is
+ a dynamic type and TypeHandle.GetTypeHandle() otherwise.
+
+2002-08-16 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (ICachingMemberFinder): Removed.
+ (IMemberFinder.MemberCache): New property.
+ (TypeManager.FindMembers): Merged this with RealFindMembers().
+ This function will never be called from TypeManager.MemberLookup()
+ so we can't use the cache here, just the IMemberFinder.
+ (TypeManager.MemberLookup_FindMembers): Check whether the
+ IMemberFinder has a MemberCache and call the cache's FindMembers
+ function.
+ (MemberCache): Rewrote larger parts of this yet another time and
+ cleaned it up a bit.
+
+2002-08-15 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (LoadArgs): Support quoting.
+
+ (Usage): Show the CSC-like command line arguments.
+
+ Improved a few error messages.
+
+2002-08-15 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (IMemberContainer.Type): New property.
+ (IMemberContainer.IsInterface): New property.
+
+ The following changes are conditional to BROKEN_RUNTIME, which is
+ defined at the top of the file.
+
+ * typemanager.cs (MemberCache.MemberCache): Don't add the base
+ class'es members, but add all members from TypeHandle.ObjectType
+ if we're an interface.
+ (MemberCache.AddMembers): Set the Declared flag if member.DeclaringType
+ is the current type.
+ (MemberCache.CacheEntry.Container): Removed this field.
+ (TypeHandle.GetMembers): Include inherited members.
+
+2002-08-14 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * typemanager.cs: fixed compilation and added a comment on a field that
+ is never used.
+
+2002-08-15 Martin Baulig <martin@gnome.org>
+
+ * class.cs (ConstructorInitializer.Resolve): In the
+ Expression.MemberLookup call, use the queried_type as
+ invocation_type.
+
+ * typemanager.cs (IMemberContainer.GetMembers): Removed the `bool
+ declared' attribute, it's always true.
+ (IMemberContainer.Parent, IMemberContainer.Name): New properties.
+ (TypeManager.MemberLookup_FindMembers): [FIXME FIXME FIXME] Added
+ temporary wrapper for FindMembers which tells MemberLookup whether
+ members from the base classes are included in the return value.
+ This will go away soon.
+ (TypeManager.MemberLookup): Use this temporary hack here; once the
+ new MemberCache is completed, we don't need to do the DeclaredOnly
+ looping here anymore since the MemberCache will take care of this.
+ (TypeManager.IsSubclassOrNestedChildOf): Allow `type == parent'.
+ (MemberCache): When creating the MemberCache for a class, get
+ members from the current class and all its base classes.
+ (MemberCache.CacheEntry.Container): New field. This is a
+ temporary hack until the Mono runtime is fixed to distinguish
+ between ReflectedType and DeclaringType. It allows us to use MCS
+ with both the MS runtime and the unfixed Mono runtime without
+ problems and without accecting performance.
+ (MemberCache.SearchMembers): The DeclaredOnly looping from
+ TypeManager.MemberLookup is now done here.
+
+2002-08-14 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (MyStructInfo.MyStructInfo): Don't call
+ Type.GetFields on dynamic types but get the fields from the
+ corresponding TypeContainer.
+ (MyStructInfo.GetStructInfo): Added check for enum types.
+
+ * typemanager.cs (MemberList.IsSynchronized): Implemented.
+ (MemberList.SyncRoot): Implemented.
+ (TypeManager.FilterWithClosure): No need to check permissions if
+ closure_start_type == closure_invocation_type, don't crash if
+ closure_invocation_type is null.
+
+2002-08-13 Martin Baulig <martin@gnome.org>
+
+ Rewrote TypeContainer.FindMembers to use a member cache. This
+ gives us a speed increase of about 35% for the self-hosting MCS
+ build and of about 15-20% for the class libs (both on GNU/Linux).
+
+ * report.cs (Timer): New class to get enhanced profiling. This
+ whole class is "TIMER" conditional since it remarkably slows down
+ compilation speed.
+
+ * class.cs (MemberList): New class. This is an IList wrapper
+ which we're now using instead of passing MemberInfo[]'s around to
+ avoid copying this array unnecessarily.
+ (IMemberFinder.FindMember): Return a MemberList, not a MemberInfo [].
+ (ICachingMemberFinder, IMemberContainer): New interface.
+ (TypeManager.FilterWithClosure): If `criteria' is null, the name
+ has already been checked, otherwise use it for the name comparision.
+ (TypeManager.FindMembers): Renamed to RealMemberFinder and
+ provided wrapper which tries to use ICachingMemberFinder.FindMembers
+ if possible. Returns a MemberList, not a MemberInfo [].
+ (TypeHandle): New class, implements IMemberContainer. We create
+ one instance of this class per type, it contains a MemberCache
+ which is used to do the member lookups.
+ (MemberCache): New class. Each instance of this class contains
+ all members of a type and a name-based hash table.
+ (MemberCache.FindMembers): This is our new member lookup
+ function. First, it looks up all members of the requested name in
+ the hash table. Then, it walks this list and sorts out all
+ applicable members and returns them.
+
+2002-08-13 Martin Baulig <martin@gnome.org>
+
+ In addition to a nice code cleanup, this gives us a performance
+ increase of about 1.4% on GNU/Linux - not much, but it's already
+ half a second for the self-hosting MCS compilation.
+
+ * typemanager.cs (IMemberFinder): New interface. It is used by
+ TypeManager.FindMembers to call FindMembers on a TypeContainer,
+ Enum, Delegate or Interface.
+ (TypeManager.finder_to_member_finder): New PtrHashtable.
+ (TypeManager.finder_to_container): Removed.
+ (TypeManager.finder_to_delegate): Removed.
+ (TypeManager.finder_to_interface): Removed.
+ (TypeManager.finder_to_enum): Removed.
+
+ * interface.cs (Interface): Implement IMemberFinder.
+
+ * delegate.cs (Delegate): Implement IMemberFinder.
+
+ * enum.cs (Enum): Implement IMemberFinder.
+
+ * class.cs (TypeContainer): Implement IMemberFinder.
+
+2002-08-12 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (TypeExpr.DoResolveType): Mark this as virtual.
+
+2002-08-12 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (ITypeExpression): New interface for expressions which
+ resolve to a type.
+ (TypeExpression): Renamed to TypeLookupExpression.
+ (Expression.DoResolve): If we're doing a types-only lookup, the
+ expression must implement the ITypeExpression interface and we
+ call DoResolveType() on it.
+ (SimpleName): Implement the new ITypeExpression interface.
+ (SimpleName.SimpleNameResolve): Removed the ec.OnlyLookupTypes
+ hack, the situation that we're only looking up types can't happen
+ anymore when this method is called. Moved the type lookup code to
+ DoResolveType() and call it.
+ (SimpleName.DoResolveType): This ITypeExpression interface method
+ is now doing the types-only lookup.
+ (TypeExpr, TypeLookupExpression): Implement ITypeExpression.
+ (ResolveFlags): Added MaskExprClass.
+
+ * expression.cs (MemberAccess): Implement the ITypeExpression
+ interface.
+ (MemberAccess.DoResolve): Added support for a types-only lookup
+ when we're called via ITypeExpression.DoResolveType().
+ (ComposedCast): Implement the ITypeExpression interface.
+
+ * codegen.cs (EmitContext.OnlyLookupTypes): Removed. Call
+ Expression.Resolve() with ResolveFlags.Type instead.
+
+2002-08-12 Martin Baulig <martin@gnome.org>
+
+ * interface.cs (Interface.Define): Apply attributes.
+
+ * attribute.cs (Attribute.ApplyAttributes): Added support for
+ interface attributes.
+
+2002-08-11 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Block.Emit): Only check the "this" variable if we
+ do not always throw an exception.
+
+ * ecore.cs (PropertyExpr.DoResolveLValue): Implemented, check
+ whether the property has a set accessor.
+
+2002-08-11 Martin Baulig <martin@gnome.org>
+
+ Added control flow analysis support for structs.
+
+ * ecore.cs (ResolveFlags): Added `DisableFlowAnalysis' to resolve
+ with control flow analysis turned off.
+ (IVariable): New interface.
+ (SimpleName.SimpleNameResolve): If MemberAccess.ResolveMemberAccess
+ returns an IMemberExpr, call DoResolve/DoResolveLValue on it.
+ (FieldExpr.DoResolve): Resolve the instance expression with flow
+ analysis turned off and do the definite assignment check after the
+ resolving when we know what the expression will resolve to.
+
+ * expression.cs (LocalVariableReference, ParameterReference):
+ Implement the new IVariable interface, only call the flow analysis
+ code if ec.DoFlowAnalysis is true.
+ (This): Added constructor which takes a Block argument. Implement
+ the new IVariable interface.
+ (MemberAccess.DoResolve, MemberAccess.DoResolveLValue): Call
+ DoResolve/DoResolveLValue on the result of ResolveMemberLookup().
+ This does the definite assignment checks for struct members.
+
+ * class.cs (Constructor.Emit): If this is a non-static `struct'
+ constructor which doesn't have any initializer, call
+ Block.AddThisVariable() to tell the flow analysis code that all
+ struct elements must be initialized before control returns from
+ the constructor.
+
+ * statement.cs (MyStructInfo): New public class.
+ (UsageVector.this [VariableInfo vi]): Added `int field_idx'
+ argument to this indexer. If non-zero, check an individual struct
+ member, not the whole struct.
+ (FlowBranching.CheckOutParameters): Check struct members.
+ (FlowBranching.IsVariableAssigned, SetVariableAssigned): Added
+ overloaded versions of these methods which take an additional
+ `int field_idx' argument to check struct members.
+ (FlowBranching.IsParameterAssigned, SetParameterAssigned): Added
+ overloaded versions of these methods which take an additional
+ `string field_name' argument to check struct member.s
+ (VariableInfo): Implement the IVariable interface.
+ (VariableInfo.StructInfo): New public property. Returns the
+ MyStructInfo instance of the variable if it's a struct or null.
+ (Block.AddThisVariable): New public method. This is called from
+ Constructor.Emit() for non-static `struct' constructor which do
+ not have any initializer. It creates a special variable for the
+ "this" instance variable which will be checked by the flow
+ analysis code to ensure that all of the struct's fields are
+ initialized before control returns from the constructor.
+ (UsageVector): Added support for struct members. If a
+ variable/parameter is a struct with N members, we reserve a slot
+ in the usage vector for each member. A struct is considered fully
+ initialized if either the struct itself (slot 0) or all its
+ members are initialized.
+
+2002-08-08 Martin Baulig <martin@gnome.org>
+
+ * driver.cs (Driver.MainDriver): Only report an error CS5001
+ if there were no compilation errors.
+
+ * codegen.cs (EmitContext.EmitContext): Use the DeclSpace's
+ `UnsafeContext' property to determine whether the parent is in
+ unsafe context rather than checking the parent's ModFlags:
+ classes nested in an unsafe class are unsafe as well.
+
+2002-08-08 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (UsageVector.MergeChildren): Distinguish between
+ `Breaks' and `Returns' everywhere, don't set `Breaks' anymore if
+ we return. Added test17() and test18() to test-154.cs.
+
+2002-08-08 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.FilterWithClosure): If we have
+ Family access, make sure the invoking type isn't a subclass of the
+ queried type (that'd be a CS1540).
+
+ * ecore.cs (Expression.MemberLookup): Added overloaded version of
+ this method which takes an additional `Type invocation_type'.
+
+ * expression.cs (BaseAccess.DoResolve): Use the base type as
+ invocation and query type.
+ (MemberAccess.DoResolve): If the lookup failed and we're about to
+ report a CS0122, try a lookup with the ec.ContainerType - if this
+ succeeds, we must report a CS1540.
+
+2002-08-08 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (IMemberExpr): Added `bool IsInstance' property.
+ (MethodGroupExpr): Implement the IMemberExpr interface.
+
+ * expression (MemberAccess.ResolveMemberAccess): No need to have
+ any special code for MethodGroupExprs anymore, they're now
+ IMemberExprs.
+
+2002-08-08 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.FilterWithClosure): Check Assembly,
+ Family, FamANDAssem and FamORAssem permissions.
+ (TypeManager.IsSubclassOrNestedChildOf): New public method.
+
+2002-08-08 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (FlowBranchingType): Added LOOP_BLOCK.
+ (UsageVector.MergeChildren): `break' breaks unless we're in a switch
+ or loop block.
+
+Thu Aug 8 10:28:07 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * driver.cs: implemented /resource option to embed managed resources.
+
+2002-08-07 Martin Baulig <martin@gnome.org>
+
+ * class.cs (FieldBase.Initializer): Renamed to `init' and made private.
+ (FieldBase.HasFieldInitializer): New public property.
+ (FieldBase.GetInitializerExpression): New public method. Resolves and
+ returns the field initializer and makes sure it is only resolved once.
+ (TypeContainer.EmitFieldInitializers): Call
+ FieldBase.GetInitializerExpression to get the initializer, this ensures
+ that it isn't resolved multiple times.
+
+ * codegen.cs (EmitContext): Added `bool IsFieldInitialier'. This tells
+ the resolving process (SimpleName/MemberLookup) that we're currently
+ emitting a field initializer (which must not access any instance members,
+ this is an error CS0236).
+
+ * ecore.cs (SimpleName.Error_ObjectRefRequired): Added EmitContext
+ argument, if the `IsFieldInitializer' flag is set, we must report and
+ error CS0236 and not an error CS0120.
+
+2002-08-07 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (IMemberExpr): New public interface.
+ (FieldExpr, PropertyExpr, EventExpr): Implement IMemberExpr.
+ (SimpleName.SimpleNameResolve): Call MemberAccess.ResolveMemberAccess
+ if the expression is an IMemberExpr.
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): Allow `left'
+ to be null, implicitly default to `this' if we're non-static in
+ this case. Simplified the code a lot by using the new IMemberExpr
+ interface. Also fixed bug #28176 here.
+
+2002-08-06 Martin Baulig <martin@gnome.org>
+
+ * cs-parser.jay (SimpleLookup): Removed. We need to create
+ ParameterReferences during semantic analysis so that we can do a
+ type-only search when resolving Cast, TypeOf and SizeOf.
+ (block): Pass the `current_local_parameters' to the Block's
+ constructor.
+
+ * class.cs (ConstructorInitializer): Added `Parameters parameters'
+ argument to the constructor.
+ (ConstructorInitializer.Resolve): Create a temporary implicit
+ block with the parameters.
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Resolve parameter
+ references here if we aren't doing a type-only search.
+
+ * statement.cs (Block): Added constructor which takes a
+ `Parameters parameters' argument.
+ (Block.Parameters): New public property.
+
+ * support.cs (InternalParameters.Parameters): Renamed `parameters'
+ to `Parameters' and made it public readonly.
+
+2002-08-06 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.Warning): Made this public as well.
+
+ * report.cs (Report.Debug): Print the contents of collections.
+
+2002-08-06 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.ResolveFlags): New [Flags] enum. This is
+ used to tell Resolve() which kinds of expressions it may return.
+ (Expression.Resolve): Added overloaded version of this method which
+ takes a `ResolveFlags flags' argument. This can be used to tell
+ Resolve() which kinds of expressions it may return. Reports a
+ CS0118 on error.
+ (Expression.ResolveWithSimpleName): Removed, use Resolve() with
+ ResolveFlags.SimpleName.
+ (Expression.Error118): Added overloaded version of this method which
+ takes a `ResolveFlags flags' argument. It uses the flags to determine
+ which kinds of expressions are allowed.
+
+ * expression.cs (Argument.ResolveMethodGroup): New public method.
+ Resolves an argument, but allows a MethodGroup to be returned.
+ This is used when invoking a delegate.
+
+ * TODO: Updated a bit.
+
+2002-08-06 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ Fixed compilation with csc.
+
+ * ecore.cs: Expression.Error made public. Is this correct? Should
+ Warning be made public too?
+
+ * expression.cs: use ea.Location instead of ea.loc.
+ [FIXME: Filed as bug #28607: MCS must report these errors.]
+
+2002-08-06 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.loc): Moved the location here instead of
+ duplicating it in all derived classes.
+ (Expression.Location): New public property.
+ (Expression.Error, Expression.Warning): Made them non-static and
+ removed the location argument.
+ (Expression.Warning): Added overloaded version which takes an
+ `int level' argument.
+ (Expression.Error118): Make this non-static and removed the
+ expression and location arguments.
+ (TypeExpr): Added location argument to the constructor.
+
+ * expression.cs (StaticCallExpr): Added location argument to
+ the constructor.
+ (Indirection, PointerArithmetic): Likewise.
+ (CheckedExpr, UnCheckedExpr): Likewise.
+ (ArrayAccess, IndexerAccess, UserCast, ArrayPtr): Likewise.
+ (StringPtr): Likewise.
+
+
+2002-08-05 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (BaseAccess.DoResolve): Actually report errors.
+
+ * assign.cs (Assign.DoResolve): Check whether the source
+ expression is a value or variable.
+
+ * statement.cs (Try.Resolve): Set ec.InTry/InCatch/InFinally
+ while resolving the corresponding blocks.
+
+ * interface.cs (Interface.GetInterfaceTypeByName): Actually report
+ an error, don't silently return null.
+
+ * statement.cs (Block.AddVariable): Do the error reporting here
+ and distinguish between CS0128 and CS0136.
+ (Block.DoResolve): Report all unused labels (warning CS0164).
+ (LabeledStatement): Pass the location to the constructor.
+ (LabeledStatement.HasBeenReferenced): New property.
+ (LabeledStatement.Resolve): Set it to true here.
+
+ * statement.cs (Return.Emit): Return success even after reporting
+ a type mismatch error (CS0126 or CS0127), this is what csc does and
+ it avoids confusing the users with any consecutive errors.
+
+2002-08-05 Martin Baulig <martin@gnome.org>
+
+ * enum.cs (Enum.LookupEnumValue): Catch circular definitions.
+
+ * const.cs (Const.LookupConstantValue): Catch circular definitions.
+
+ * expression.cs (MemberAccess.DoResolve): Silently return if an
+ error has already been reported.
+
+ * ecore.cs (Expression.MemberLookupFinal): Silently return if an
+ error has already been reported.
+
+2002-08-05 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (UsageVector): Only initialize the `parameters'
+ vector if we actually have any "out" parameters.
+
+2002-08-05 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Binary.ResolveOperator): When combining delegates,
+ they must have the same type.
+
+2002-08-05 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.GetArgumentTypes): Don't call
+ PropertyInfo.GetIndexParameters() on dynamic types, this doesn't
+ work with the ms runtime and we also don't need it: if we're a
+ PropertyBuilder and not in the `indexer_arguments' hash, then we
+ are a property and not an indexer.
+
+ * class.cs (TypeContainer.AsAccessible): Use Type.IsArray,
+ Type.IsPointer and Type.IsByRef instead of Type.HasElementType
+ since the latter one doesn't work with the ms runtime.
+
+2002-08-03 Martin Baulig <martin@gnome.org>
+
+ Fixed bugs #27998 and #22735.
+
+ * class.cs (Method.IsOperator): New public field.
+ (Method.CheckBase): Report CS0111 if there's already a method
+ with the same parameters in the current class. Report CS0508 when
+ attempting to change the return type of an inherited method.
+ (MethodData.Emit): Report CS0179 if a method doesn't have a body
+ and it's not marked abstract or extern.
+ (PropertyBase): New abstract base class for Property and Indexer.
+ (PropertyBase.CheckBase): Moved here from Property and made it work
+ for indexers.
+ (PropertyBase.Emit): Moved here from Property.Emit, Indexer.Emit is
+ the same so we can reuse it there.
+ (Property, Indexer): Derive from PropertyBase.
+ (MethodSignature.inheritable_property_signature_filter): New delegate
+ to find properties and indexers.
+
+ * decl.cs (MemberCore.CheckMethodAgainstBase): Added `string name'
+ argument and improved error reporting.
+
+ * parameter.cs (Parameters.GetEmptyReadOnlyParameters): Renamed to
+ EmptyReadOnlyParameters and made it a property.
+
+ * typemanager.cs (TypeManager.GetArgumentTypes): Added overloaded
+ version of this method which takes a `PropertyInfo indexer'.
+ (TypeManager.RegisterIndexer): New method.
+
+ * class.cs: Added myself as author of this file :-)
+
+2002-08-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * class.cs: fixed compilation on windoze.
+
+2002-08-03 Martin Baulig <martin@gnome.org>
+
+ * interface.cs (Interface.GetInterfaceBases): Check whether all
+ base interfaces are at least as accessible than the current one.
+
+ * class.cs (TypeContainer.GetClassBases): Check whether base types
+ are at least as accessible than the current type.
+ (TypeContainer.AsAccessible): Implemented and made non-static.
+ (MemberBase.CheckParameters): Report errors if the accessibility
+ checks fail.
+
+ * delegate.cs (Delegate.Delegate): The default visibility is
+ internal for top-level types and private for nested types.
+ (Delegate.Define): Report errors if the accessibility checks fail.
+
+ * enum.cs (Enum.Enum): The default visibility is internal for
+ top-level types and private for nested types.
+ (Enum.DefineType): Compute the correct visibility.
+
+ * modifiers.cs (Modifiers.TypeAttr): Added a version of this
+ function which takes a `bool is_toplevel' instead of a TypeContainer.
+
+ * typemanager.cs (TypeManager.IsBuiltinType): `void' is also a
+ builtin type.
+
+2002-08-02 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (LocalVariableReferenc): Added constructor which
+ takes additional `VariableInfo vi' and `bool is_readonly' arguments.
+ (LocalVariableReference.IsReadOnly): New property.
+ (LocalVariableReference.DoResolveLValue): Report a CS1604 if the
+ variable is readonly, use our own readonly flag to do this; you can
+ use the new constructor to get a writable reference to a read-only
+ variable.
+
+ * cs-parser.jay (foreach_statement, using_statement): Get a writable
+ reference to the local variable.
+
+2002-08-01 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs (ResolveCore): Also include System.Exception
+
+ * statement.cs (Block.Emit): Do not emit the dead-code warnings if
+ we reach an EmptyStatement.
+
+ (Catch.DoResolve, Throw.DoResolve): Throwing the System.Exception
+ is also fine.
+
+ * expression.cs (Binary.ResolveOperator): Check error result in
+ two places.
+
+ use brtrue/brfalse directly and avoid compares to null.
+
+2002-08-02 Martin Baulig <martin@gnome.org>
+
+ * class.cs (TypeContainer.Define): Define all nested interfaces here.
+ Fixes bug #28407, added test-155.cs.
+
+2002-08-01 Martin Baulig <martin@gnome.org>
+
+ * class.cs (Event.EmitDefaultMethod): Make this work with static
+ events. Fixes #28311, added verify-3.cs.
+
+2002-08-01 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (ForeachHelperMethods): Added `enumerator_type' and
+ `is_disposable' fields.
+ (Foreach.GetEnumeratorFilter): Set `hm.enumerator_type' and
+ `hm.is_disposable' if we're using the collection pattern.
+ (Foreach.EmitCollectionForeach): Use the correct type for the
+ enumerator's local variable, only emit the try/finally block if
+ necessary (fixes #27713).
+
+2002-08-01 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.report118): Renamed to Error118 and made
+ it public static.
+
+ * statement.cs (Throw.Resolve): Check whether the expression is of
+ the correct type (CS0118) and whether the type derives from
+ System.Exception (CS0155).
+ (Catch.Resolve): New method. Do the type lookup here and check
+ whether it derives from System.Exception (CS0155).
+ (Catch.CatchType, Catch.IsGeneral): New public properties.
+
+ * typemanager.cs (TypeManager.exception_type): Added.
+
+2002-07-31 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Updated About function.
+
+2002-07-31 Martin Baulig <martin@gnome.org>
+
+ Implemented Control Flow Analysis.
+
+ * codegen.cs (EmitContext.DoFlowAnalysis): New public variable.
+ (EmitContext.CurrentBranching): Added.
+ (EmitContext.StartFlowBranching): Added.
+ (EmitContext.EndFlowBranching): Added.
+ (EmitContext.KillFlowBranching): Added.
+ (EmitContext.IsVariableAssigned): Added.
+ (EmitContext.SetVariableAssigned): Added.
+ (EmitContext.IsParameterAssigned): Added.
+ (EmitContext.SetParameterAssigned): Added.
+ (EmitContext.EmitTopBlock): Added `InternalParameters ip' argument.
+ Added control flow analysis stuff here.
+
+ * expression.cs (Unary.DoResolve): If the operator is Oper.AddressOf,
+ resolve the expression as lvalue.
+ (LocalVariableReference.DoResolve): Check whether the variable has
+ already been assigned.
+ (ParameterReference.DoResolveLValue): Override lvalue resolve to mark
+ the parameter as assigned here.
+ (ParameterReference.DoResolve): Check whether the parameter has already
+ been assigned.
+ (Argument.Resolve): If it's a `ref' or `out' argument, resolve the
+ expression as lvalue.
+
+ * statement.cs (FlowBranching): New class for the flow analysis code.
+ (Goto): Resolve the label in Resolve, not in Emit; added flow analysis.
+ (LabeledStatement.IsDefined): New public property.
+ (LabeledStatement.AddUsageVector): New public method to tell flow
+ analyis that the label may be reached via a forward jump.
+ (GotoCase): Lookup and resolve the label in Resolve, not in Emit; added
+ flow analysis.
+ (VariableInfo.Number): New public field. This is used by flow analysis
+ to number all locals of a block.
+ (Block.CountVariables): New public property. This is the number of
+ local variables in this block (including the locals from all parent
+ blocks).
+ (Block.EmitMeta): Number all the variables.
+
+ * statement.cs: Added flow analysis support to all classes.
+
+2002-07-31 Martin Baulig <martin@gnome.org>
+
+ * driver.cs: Added "--mcs-debug" argument if MCS_DEBUG is defined.
+ To get debugging messages, compile mcs with /define:MCS_DEBUG and
+ then use this argument.
+
+ * report.cs (Report.Debug): Renamed to conditional to "MCS_DEBUG".
+
+ * makefile.gnu (MCS_FLAGS): Include $(MCS_DEFINES), the user may
+ use this to specify /define options.
+
+2002-07-29 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Fixed): Moved all code that does variable lookups
+ and resolvings from Emit to Resolve.
+
+ * statement.cs (For): Moved all code that does variable lookups
+ and resolvings from Emit to Resolve.
+
+ * statement.cs (Using): Moved all code that does variable lookups
+ and resolvings from Emit to Resolve.
+
+2002-07-29 Martin Baulig <martin@gnome.org>
+
+ * attribute.cs (Attribute.Resolve): Explicitly catch a
+ System.NullReferenceException when creating the
+ CustromAttributeBuilder and report a different warning message.
+
+2002-07-29 Martin Baulig <martin@gnome.org>
+
+ * support.cs (ParameterData.ParameterName): Added method to
+ get the name of a parameter.
+
+ * typemanager.cs (TypeManager.IsValueType): New public method.
+
+2002-07-29 Martin Baulig <martin@gnome.org>
+
+ * parameter.cs (Parameter.Modifier): Added `ISBYREF = 8'. This
+ is a flag which specifies that it's either ref or out.
+ (Parameter.GetParameterInfo (DeclSpace, int, out bool)): Changed
+ the out parameter to `out Parameter.Modifier mod', also set the
+ Parameter.Modifier.ISBYREF flag on it if it's either ref or out.
+
+ * support.cs (InternalParameters.ParameterModifier): Distinguish
+ between Parameter.Modifier.OUT and Parameter.Modifier.REF, set the
+ Parameter.Modifier.ISBYREF flag if it's either ref or out.
+
+ * expression.cs (Argument.GetParameterModifier): Distinguish
+ between Parameter.Modifier.OUT and Parameter.Modifier.REF, set the
+ Parameter.Modifier.ISBYREF flag if it's either ref or out.
+
+2002-07-29 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (ParameterReference.ParameterReference): Added
+ `Location loc' argument to the constructor.
+
+ * cs-parser.jay: Pass location to ParameterReference.
+
+2002-07-28 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Try): Initialize the location.
+
+ * cs-parser.jay: pass location to Try.
+
+ * expression.cs (Unary.Reduce): Change the prototype to return
+ whether a constant fold could be performed or not. The result is
+ returned in an out parameters. In the case of Indirection and
+ AddressOf, we want to perform the full tests.
+
+2002-07-26 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Statement.Emit): Flag dead code.
+
+2002-07-27 Andrew Birkett <andy@nobugs.org>
+
+ * expression.cs (Unary.Reduce): Handle AddressOf and Indirection.
+
+2002-07-27 Martin Baulig <martin@gnome.org>
+
+ * class.cs (MethodData.Define): Put back call to
+ TypeManager.AddMethod(), accidentally commented this out.
+
+ * report.cs (Debug): New public method to print debugging information,
+ this is `[Conditional ("DEBUG")]'.
+
+2002-07-26 Martin Baulig <martin@gnome.org>
+
+ * cs-parser.jay (CSharpParser): Added `Stack switch_stack'.
+ (switch_statement): Push the current_block to the switch_stack and
+ pop it again when we're done with the switch.
+ (switch_section): The new block is a child of the current_block.
+ Fixes bug #24007, added test-152.cs.
+
+2002-07-27 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Invocation.EmitArguments): When calling a varargs
+ function with only its fixed arguments, we need to pass an empty
+ array.
+
+2002-07-27 Martin Baulig <martin@gnome.org>
+
+ Mono 0.13 has been released.
+
+2002-07-25 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Rename --resource to --linkres, because that is what
+ we do currently, we dont support --resource yet.
+
+ * cs-tokenizer.cs: Fix test for reporting endif mismatches.
+
+2002-07-25 Martin Baulig <martin@gnome.org>
+
+ * class.cs (MethodData): New public class. This is a `method builder'
+ class for a method or one accessor of a Property/Indexer/Event.
+ (MethodData.GetMethodFlags): Moved here from MemberBase.
+ (MethodData.ApplyAttributes): Likewise.
+ (MethodData.ApplyObsoleteAttribute): Likewise.
+ (MethodData.ApplyConditionalAttribute): Likewise.
+ (MethodData.ApplyDllImportAttribute): Likewise.
+ (MethodData.CheckAbstractAndExternal): Likewise.
+ (MethodData.Define): Formerly knows as MemberBase.DefineMethod().
+ (MethodData.Emit): Formerly known as Method.Emit().
+ (MemberBase): Moved everything which was specific to a single
+ accessor/method to MethodData.
+ (Method): Create a new MethodData and call Define() and Emit() on it.
+ (Property, Indexer, Event): Create a new MethodData objects for each
+ accessor and call Define() and Emit() on them.
+
+2002-07-25 Martin Baulig <martin@gnome.org>
+
+ Made MethodCore derive from MemberBase to reuse the code from there.
+ MemberBase now also checks for attributes.
+
+ * class.cs (MethodCore): Derive from MemberBase, not MemberCore.
+ (MemberBase.GetMethodFlags): Moved here from class Method and marked
+ as virtual.
+ (MemberBase.DefineAccessor): Renamed to DefineMethod(), added
+ `CallingConventions cc' and `Attributes opt_attrs' arguments.
+ (MemberBase.ApplyAttributes): New virtual method; applies the
+ attributes to a method or accessor.
+ (MemberBase.ApplyObsoleteAttribute): New protected virtual method.
+ (MemberBase.ApplyConditionalAttribute): Likewise.
+ (MemberBase.ApplyDllImportAttribute): Likewise.
+ (MemberBase.CheckAbstractAndExternal): Likewise.
+ (MethodCore.ParameterTypes): This is now a property instead of a
+ method, it's initialized from DoDefineParameters().
+ (MethodCore.ParameterInfo): Removed the set accessor.
+ (MethodCore.DoDefineParameters): New protected virtual method to
+ initialize ParameterTypes and ParameterInfo.
+ (Method.GetReturnType): We can now simply return the MemberType.
+ (Method.GetMethodFlags): Override the MemberBase version and add
+ the conditional flags.
+ (Method.CheckBase): Moved some code from Define() here, call
+ DoDefineParameters() here.
+ (Method.Define): Use DoDefine() and DefineMethod() from MemberBase
+ here to avoid some larger code duplication.
+ (Property.Emit, Indexer.Emit): Call CheckAbstractAndExternal() to
+ ensure that abstract and external accessors don't declare a body.
+
+ * attribute.cs (Attribute.GetValidPieces): Make this actually work:
+ `System.Attribute.GetCustomAttributes (attr.Type)' does a recursive
+ lookup in the attribute's parent classes, so we need to abort as soon
+ as we found the first match.
+ (Attribute.Obsolete_GetObsoleteMessage): Return the empty string if
+ the attribute has no arguments.
+
+ * typemanager.cs (TypeManager.AddMethod): Now takes a MemberBase instead
+ of a Method.
+
+2002-07-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * cs-parser.jay: reverted previous patch.
+
+2002-07-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * cs-parser.jay: fixed bug #22119.
+
+2002-07-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * attribute.cs: fixed compilation. The error was:
+ "attribute.cs(571,17): error CS0177: The out parameter 'is_error' must
+ be assigned to before control leaves the current method."
+ [FIXME: Filed as bug #28186: MCS must report this error.]
+
+2002-07-25 Martin Baulig <martin@gnome.org>
+
+ * attribute.cs (Attribute.Conditional_GetConditionName): New static
+ method to pull the condition name ouf of a Conditional attribute.
+ (Attribute.Obsolete_GetObsoleteMessage): New static method to pull
+ the obsolete message and error flag out of an Obsolete attribute.
+
+ * class.cs (Method.GetMethodFlags): New public method to get the
+ TypeManager.MethodFlags for this method.
+ (Method.ApplyConditionalAttribute, Method.ApplyObsoleteAttribute): New
+ private methods.
+ (Method.Define): Get and apply the Obsolete and Conditional attributes;
+ if we're overriding a virtual function, set the new private variable
+ `parent_method'; call the new TypeManager.AddMethod().
+
+ * typemanager.cs (TypeManager.AddMethod): New static method. Stores
+ the MethodBuilder and the Method in a PtrHashtable.
+ (TypeManager.builder_to_method): Added for this purpose.
+ (TypeManager.MethodFlags): Added IsObsoleteError.
+ (TypeManager.GetMethodFlags): Added `Location loc' argument. Lookup
+ Obsolete and Conditional arguments in MethodBuilders. If we discover
+ an Obsolete attribute, emit an appropriate warning 618 / error 619 with
+ the message from the attribute.
+
+2002-07-24 Martin Baulig <martin@gnome.org>
+
+ * cs-tokenizer.cs: Eat up trailing whitespaces and one-line comments in
+ preprocessor directives, ensure that the argument to #define/#undef is
+ exactly one identifier and that it's actually an identifier.
+
+ Some weeks ago I did a `#define DEBUG 1' myself and wondered why this
+ did not work ....
+
+2002-07-24 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Foreach.ForeachHelperMethods): Added `Type element_type',
+ initialize it to TypeManager.object_type in the constructor.
+ (Foreach.GetEnumeratorFilter): Set `hm.element_type' to the return type
+ of the `hm.get_current' method if we're using the collection pattern.
+ (Foreach.EmitCollectionForeach): Use `hm.element_type' as the source type
+ for the explicit conversion to make it work when we're using the collection
+ pattern and the `Current' property has a different return type than `object'.
+ Fixes #27713.
+
+2002-07-24 Martin Baulig <martin@gnome.org>
+
+ * delegate.cs (Delegate.VerifyMethod): Simply return null if the method
+ does not match, but don't report any errors. This method is called in
+ order for all methods in a MethodGroupExpr until a matching method is
+ found, so we don't want to bail out if the first method doesn't match.
+ (NewDelegate.DoResolve): If none of the methods in the MethodGroupExpr
+ matches, report the 123. Fixes #28070.
+
+2002-07-24 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (ArrayAccess.EmitStoreOpcode): Moved the
+ TypeManager.TypeToCoreType() to the top of the method so the
+ following equality checks will work. Fixes #28107.
+
+2002-07-24 Martin Baulig <martin@gnome.org>
+
+ * cfold.cs (ConstantFold.DoConstantNumericPromotions): "If either
+ operand is of type uint, and the other operand is of type sbyte,
+ short or int, the operands are converted to type long." -
+ Actually do what this comment already told us. Fixes bug #28106,
+ added test-150.cs.
+
+2002-07-24 Martin Baulig <martin@gnome.org>
+
+ * class.cs (MethodBase): New abstract class. This is now a base
+ class for Property, Indexer and Event to avoid some code duplication
+ in their Define() and DefineMethods() methods.
+ (MethodBase.DoDefine, MethodBase.DefineAccessor): Provide virtual
+ generic methods for Define() and DefineMethods().
+ (FieldBase): Derive from MemberBase, not MemberCore.
+ (Property): Derive from MemberBase, not MemberCore.
+ (Property.DefineMethod): Moved all the code from this method to the
+ new MethodBase.DefineAccessor(), just call it with appropriate
+ argumetnts.
+ (Property.Define): Call the new Property.DoDefine(), this does some
+ sanity checks and we don't need to duplicate the code everywhere.
+ (Event): Derive from MemberBase, not MemberCore.
+ (Event.Define): Use the new MethodBase.DefineAccessor() to define the
+ accessors, this will also make them work with interface events.
+ (Indexer): Derive from MemberBase, not MemberCore.
+ (Indexer.DefineMethod): Removed, call MethodBase.DefineAccessor() insstead.
+ (Indexer.Define): Use the new MethodBase functions.
+
+ * interface.cs (InterfaceEvent.InterfaceEvent): Added `Location loc'
+ argument to the constructor.
+ (Interface.FindMembers): Added support for interface events.
+ (Interface.PopluateEvent): Implemented.
+
+ Added test-149.cs for this. This also fixes bugs #26067 and #24256.
+
+2002-07-22 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer.AddMethod): Adding methods do not use IsValid,
+ but this is required to check for a method name being the same as
+ the containing class.
+
+ Handle this now.
+
+2002-07-22 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * interface.cs: initialize variable.
+
+2002-07-23 Martin Baulig <martin@gnome.org>
+
+ Implemented the IndexerName attribute in interfaces.
+
+ * class.cs (TypeContainer.DefineIndexers): Don't set the indexer
+ name if this is an explicit interface implementation.
+ (Indexer.InterfaceIndexerName): New public variable. If we're
+ implementing an interface indexer, this is the IndexerName in that
+ interface. Otherwise, it's the IndexerName.
+ (Indexer.DefineMethod): If we're implementing interface indexer,
+ set InterfaceIndexerName. Use the new Pending.IsInterfaceIndexer
+ and Pending.ImplementIndexer methods.
+ (Indexer.Define): Also define the PropertyBuilder if we're
+ implementing an interface indexer and this is neither an explicit
+ interface implementation nor do the IndexerName match the one in
+ the interface.
+
+ * pending.cs (TypeAndMethods): Added `MethodInfo [] need_proxy'.
+ If a method is defined here, then we always need to create a proxy
+ for it. This is used when implementing interface indexers.
+ (Pending.IsInterfaceIndexer): New public method.
+ (Pending.ImplementIndexer): New public method.
+ (Pending.InterfaceMethod): Added `MethodInfo need_proxy' argument.
+ This is used when implementing interface indexers to define a proxy
+ if necessary.
+ (Pending.VerifyPendingMethods): Look in the `need_proxy' array and
+ define a proxy if necessary.
+
+ * interface.cs (Interface.IndexerName): New public variable.
+ (Interface.PopulateIndexer): Set the IndexerName.
+ (Interface.DefineIndexers): New private method. Populate all the
+ indexers and make sure their IndexerNames match.
+
+ * typemanager.cs (IndexerPropertyName): Added support for interface
+ indexers.
+
+2002-07-22 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (EmitContext.HasReturnLabel): New public variable.
+ (EmitContext.EmitTopBlock): Always mark the ReturnLabel and emit a
+ ret if HasReturnLabel.
+ (EmitContext.TryCatchLevel, LoopBeginTryCatchLevel): New public
+ variables.
+
+ * statement.cs (Do.Emit, While.Emit, For.Emit, Foreach.Emit): Save
+ and set the ec.LoopBeginTryCatchLevel.
+ (Try.Emit): Increment the ec.TryCatchLevel while emitting the block.
+ (Continue.Emit): If the ec.LoopBeginTryCatchLevel is smaller than
+ the current ec.TryCatchLevel, the branch goes out of an exception
+ block. In this case, we need to use Leave and not Br.
+
+2002-07-22 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Try.Emit): Emit an explicit ret after the end of the
+ block unless the block does not always return or it is contained in
+ another try { ... } catch { ... } block. Fixes bug #26506.
+ Added verify-1.cs to the test suite.
+
+2002-07-22 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Switch.TableSwitchEmit): If we don't have a default,
+ then we do not always return. Fixes bug #24985.
+
+2002-07-22 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Invocation.OverloadedResolve): Do the BetterFunction()
+ lookup on a per-class level; ie. walk up the class hierarchy until we
+ found at least one applicable method, then choose the best among them.
+ Fixes bug #24463 and test-29.cs.
+
+2002-07-22 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.ArrayContainsMethod): Don't check the
+ return types of the methods. The return type is not part of the
+ signature and we must not check it to make the `new' modifier work.
+ Fixes bug #27999, also added test-147.cs.
+ (TypeManager.TypeToCoreType): Added TypeManager.type_type.
+
+ * expression.cs (Invocation.DoResolve): Call TypeManager.TypeToCoreType()
+ on the method's return type.
+
+2002-07-21 Martin Baulig <martin@gnome.org>
+
+ * assign.cs: Make this work if the rightmost source is a constant and
+ we need to do an implicit type conversion. Also adding a few more tests
+ to test-38.cs which should have caught this.
+
+ * makefile.gnu: Disable debugging, there's already the mcs-mono2.exe
+ target in the makefile for this. The makefile.gnu is primarily intended
+ for end-users who don't want to debug the compiler.
+
+2002-07-21 Martin Baulig <martin@gnome.org>
+
+ * assign.cs: Improved the Assign class so it can now handle embedded
+ assignments (X = Y = Z = something). As a side-effect this'll now also
+ consume less local variables. test-38.cs now passes with MCS, added
+ a few new test cases to that test.
+
+2002-07-20 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Binary.EmitBranchable): Emit correct unsigned branch
+ instructions. Fixes bug #27977, also added test-146.cs.
+
+2002-07-19 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * cs-tokenizer.cs: fixed getHex ().
+
+2002-07-19 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Invocation.EmitParams): Use TypeManager.LookupType(),
+ not Type.GetType() to lookup the array type. This is needed when
+ we're constructing an array of a user-defined type.
+ (ArrayAccess.EmitDynamicInitializers): Only emit the Ldelema for
+ single-dimensional arrays, but also for single-dimensial arrays of
+ type decimal.
+
+2002-07-19 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (New.DoEmit): Create a new LocalTemporary each time
+ this function is called, it's not allowed to share LocalBuilders
+ among ILGenerators.
+
+2002-07-19 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Argument.Resolve): Report an error 118 when trying
+ to pass a type as argument.
+
+2002-07-18 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.ImplicitNumericConversion): Don't emit a
+ Conv_R_Un for the signed `long' type.
+
+2002-07-15 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MemberAccess.DoResolve): Do not reuse the field
+ `expr' for the temporary result, as that will fail if we do
+ multiple resolves on the same expression.
+
+2002-07-05 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (SimpleNameResolve): Use ec.DeclSpace instead of
+ ec.TypeContainer for looking up aliases.
+
+ * class.cs (TypeContainer): Remove LookupAlias from here.
+
+ * decl.cs (DeclSpace); Move here.
+
+2002-07-01 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (FindMembers): Only call filter if the constructor
+ bulider is not null.
+
+ Also handle delegates in `NestedTypes' now. Now we will perform
+ type lookups using the standard resolution process. This also
+ fixes a bug.
+
+ * decl.cs (DeclSpace.ResolveType): New type resolution routine.
+ This uses Expressions (the limited kind that can be parsed by the
+ tree) instead of strings.
+
+ * expression.cs (ComposedCast.ToString): Implement, used to flag
+ errors since now we have to render expressions.
+
+ (ArrayCreation): Kill FormElementType. Use ComposedCasts in
+ FormArrayType.
+
+ * ecore.cs (SimpleName.ToString): ditto.
+
+ * cs-parser.jay: Instead of using strings to assemble types, use
+ Expressions to assemble the type (using SimpleName, ComposedCast,
+ MemberAccess). This should fix the type lookups in declarations,
+ because we were using a different code path for this.
+
+ * statement.cs (Block.Resolve): Continue processing statements
+ even when there is an error.
+
+2002-07-17 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Event.Define): Also remove the `remove' method from
+ the list of pending items.
+
+ * expression.cs (ParameterReference): Use ldarg.N (0..3) to
+ generate more compact code.
+
+2002-07-17 Martin Baulig <martin@gnome.org>
+
+ * const.cs (Const.LookupConstantValue): Add support for constant
+ `unchecked' and `checked' expressions.
+ Also adding test case test-140.cs for this.
+
+2002-07-17 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Foreach.GetEnumeratorFilter): When compiling corlib,
+ check whether mi.ReturnType implements the IEnumerator interface; the
+ `==' and the IsAssignableFrom() will fail in this situation.
+
+2002-07-16 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (SimpleName.SimpleNameResolve) : Apply Gonzalo's fix
+ here too.
+
+2002-07-16 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * expression.cs: fixed bug #27811.
+
+2002-07-14 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ParameterReference.AddressOf): Patch from Paolo
+ Molaro: when we are a ref, the value already contains a pointer
+ value, do not take the address of it.
+
+2002-07-14 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * removed mb-parser.jay and mb-tokenizer.cs
+
+Sat Jul 13 19:38:03 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * expression.cs: check against the building corlib void type.
+
+Sat Jul 13 19:35:58 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * ecore.cs: fix for valuetype static readonly fields: when
+ initializing them, we need their address, not the address of a copy.
+
+Sat Jul 13 17:32:53 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * typemanager.cs: register also enum_type in corlib.
+
+Sat Jul 13 15:59:47 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs: allow calling this (but not base) initializers in structs.
+
+Sat Jul 13 15:12:06 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * ecore.cs: make sure we compare against the building base types
+ in GetTypeSize ().
+
+Sat Jul 13 15:10:32 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * typemanager.cs: fix TypeToCoreType() to handle void and object
+ (corlib gets no more typerefs after this change).
+
+2002-07-12 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ArrayCreation.EmitArrayArguments): use
+ Conv.Ovf.U4 for unsigned and Conv.Ovf.I4 for signed.
+
+ (ArrayAccess.LoadArrayAndArguments): Use Conv_Ovf_I and
+ Conv_Ovf_I_Un for the array arguments. Even if C# allows longs as
+ array indexes, the runtime actually forbids them.
+
+ * ecore.cs (ExpressionToArrayArgument): Move the conversion code
+ for array arguments here.
+
+ * expression.cs (EmitLoadOpcode): System.Char is a U2, use that
+ instead of the default for ValueTypes.
+
+ (New.DoEmit): Use IsValueType instead of
+ IsSubclassOf (value_type)
+ (New.DoResolve): ditto.
+ (Invocation.EmitCall): ditto.
+
+ * assign.cs (Assign): ditto.
+
+ * statement.cs (Unsafe): Ok, so I got the semantics wrong.
+ Statements *are* currently doing part of their resolution during
+ Emit.
+
+ Expressions do always resolve during resolve, but statements are
+ only required to propagate resolution to their children.
+
+2002-07-11 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (CSCParseOption): Finish the /r: and /lib: support.
+
+ (LoadAssembly): Do not add the dll if it is already specified
+
+ (MainDriver): Add the System directory to the link path at the end,
+ after all the other -L arguments.
+
+ * expression.cs (ArrayAccess.EmitLoadOpcode): I was using the
+ wrong opcode for loading bytes and bools (ldelem.i1 instead of
+ ldelem.u1) and using the opposite for sbytes.
+
+ This fixes Digger, and we can finally run it.
+
+ * driver.cs (UnixParseOption): Move the option parsing here.
+ (CSCParseOption): Implement CSC-like parsing of options.
+
+ We now support both modes of operation, the old Unix way, and the
+ new CSC-like way. This should help those who wanted to make cross
+ platform makefiles.
+
+ The only thing broken is that /r:, /reference: and /lib: are not
+ implemented, because I want to make those have the same semantics
+ as the CSC compiler has, and kill once and for all the confussion
+ around this. Will be doing this tomorrow.
+
+ * statement.cs (Unsafe.Resolve): The state is checked during
+ resolve, not emit, so we have to set the flags for IsUnsfe here.
+
+2002-07-10 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): Since we can
+ not catch the Error_ObjectRefRequired in SimpleName (as it is
+ possible to have a class/instance variable name that later gets
+ deambiguated), we have to check this here.
+
+2002-07-10 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer.GetFieldFromEvent): Move away from here,
+ make static and put into Expression.
+
+ (Event.Define): Register the private field of the event with the
+ TypeManager so that GetFieldFromEvent can get at it.
+
+ (TypeManager.RegisterPrivateFieldOfEvent): Implement to
+ keep track of the private field associated with an event which
+ has no accessors.
+
+ (TypeManager.GetPrivateFieldOfEvent): Implement to get at the
+ private field.
+
+ * ecore.cs (GetFieldFromEvent): RE-write to use the above methods.
+
+2002-07-10 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary.EmitBranchable): this routine emits the
+ Binary expression in a branchable context. This basically means:
+ we need to branch somewhere, not just get the value on the stack.
+
+ This works together with Statement.EmitBoolExpression.
+
+ * statement.cs (Statement.EmitBoolExpression): Use
+ EmitBranchable.
+
+2002-07-09 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (For): Reduce the number of jumps in loops.
+
+ (For): Implement loop inversion for the For statement.
+
+ (Break): We can be breaking out of a Try/Catch controlled section
+ (foreach might have an implicit try/catch clause), so we need to
+ use Leave instead of Br.
+
+ * ecore.cs (FieldExpr.AddressOf): Fix for test-139 (augmented
+ now). If the instace expression supports IMemoryLocation, we use
+ the AddressOf method from the IMemoryLocation to extract the
+ address instead of emitting the instance.
+
+ This showed up with `This', as we were emitting the instance
+ always (Emit) instead of the Address of This. Particularly
+ interesting when This is a value type, as we dont want the Emit
+ effect (which was to load the object).
+
+2002-07-08 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs: Pass the entry point to the DefinePInvokeMethod
+
+ * statement.cs (Checked): Set the CheckedState during the resolve
+ process too, as the ConvCast operations track the checked state on
+ the resolve process, and not emit.
+
+ * cs-parser.jay (namespace_member_declaration): Flag that we have
+ found a declaration when we do. This is used to flag error 1529
+
+ * driver.cs: Report ok when we display the help only.
+
+2002-07-06 Andrew Birkett <adb@tardis.ed.ac.uk>
+
+ * cs-tokenizer.cs (xtoken): Improve handling of string literals.
+
+2002-07-04 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs (define): We also have to track locally the
+ defines. AllDefines is just used for the Conditional Attribute,
+ but we also need the local defines for the current source code.
+
+2002-07-03 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (While, For, Do): These loops can exit through a
+ Break statement, use this information to tell whether the
+ statement is the last piece of code.
+
+ (Break): Flag that we break.
+
+ * codegen.cs (EmitContexts): New `Breaks' state variable.
+
+2002-07-03 Martin Baulig <martin@gnome.org>
+
+ * class.cs (TypeContainer.MethodModifiersValid): Allow override
+ modifiers in method declarations in structs. Otherwise, you won't
+ be able to override things like Object.Equals().
+
+2002-07-02 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method, Property, Indexer): Do not allow the public
+ modifier to be used in explicit interface implementations.
+
+ (TypeContainer.MethodModifiersValid): Catch virtual, abstract and
+ override modifiers in method declarations in structs
+
+2002-07-02 Andrew Birkett <adb@tardis.ed.ac.uk>
+
+ * cs-tokenizer.cs (adjust_int, adjust_real): Do not abort on
+ integer or real overflow, report an error
+
+2002-07-02 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.InitCoreTypes): When compiling
+ corlib, dynamically call AssemblyBuilder.SetCorlibTypeBuilders()
+ to tell the runtime about our newly created System.Object and
+ System.ValueType types.
+
+2002-07-02 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (This): Use Stobj/Ldobj when we are a member of a
+ struct instead of Ldarg/Starg.
+
+2002-07-02 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Indirection.Indirection): Call
+ TypeManager.TypeToCoreType() on `expr.Type.GetElementType ()'.
+
+2002-07-02 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (ArrayAccess.EmitStoreOpcode): If the type is a
+ ValueType, call TypeManager.TypeToCoreType() on it.
+ (Invocations.EmitParams): Call TypeManager.TypeToCoreType() on
+ the OpCodes.Newarr argument.
+
+2002-07-02 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Invocation.EmitCall): When compiling corlib,
+ replace all calls to the system's System.Array type to calls to
+ the newly created one.
+
+ * typemanager.cs (TypeManager.InitCodeHelpers): Added a few more
+ System.Array methods.
+ (TypeManager.InitCoreTypes): When compiling corlib, get the methods
+ from the system's System.Array type which must be replaced.
+
+Tue Jul 2 19:05:05 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * typemanager.cs: load unverifiable_code_ctor so we can build
+ corlib using the correct type. Avoid using GetTypeCode() with
+ TypeBuilders.
+ * rootcontext.cs: uses TypeManager.unverifiable_code_ctor and
+ TypeManager.object_type to allow building corlib.
+
+Tue Jul 2 19:03:19 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * ecore.cs: handle System.Enum separately in LoadFromPtr().
+
+2002-07-01 Martin Baulig <martin@gnome.org>
+
+ * class.cs: Make the last change actually work, we need to check
+ whether `ifaces != null' to avoid a crash.
+
+Mon Jul 1 16:15:03 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs: when we build structs without fields that implement
+ interfaces, we need to add the interfaces separately, since there is
+ no API to both set the size and add the interfaces at type creation
+ time.
+
+Mon Jul 1 14:50:47 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * expression.cs: the dimension arguments to the array constructors
+ need to be converted if they are a long.
+
+Mon Jul 1 12:26:12 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs: don't emit ldarg.0 if there is no parent constructor
+ (fixes showstopper for corlib).
+
+2002-06-29 Martin Baulig <martin@gnome.org>
+
+ MCS now compiles corlib on GNU/Linux :-)
+
+ * attribute.cs (Attribute.ApplyAttributes): Treat Accessors like Method,
+ ie. check for MethodImplOptions.InternalCall.
+
+ * class.cs (TypeContainer.DefineType): When compiling corlib, both parent
+ and TypeManager.attribute_type are null, so we must explicitly check
+ whether parent is not null to find out whether it's an attribute type.
+ (Property.Emit): Always call Attribute.ApplyAttributes() on the GetBuilder
+ and SetBuilder, not only if the property is neither abstract nor external.
+ This is necessary to set the MethodImplOptions on the accessor methods.
+ (Indexer.Emit): Call Attribute.ApplyAttributes() on the GetBuilder and
+ SetBuilder, see Property.Emit().
+
+ * rootcontext.cs (RootContext.PopulateTypes): When compiling corlib, don't
+ populate "System.Object", "System.ValueType" and "System.Attribute" since
+ they've already been populated from BootCorlib_PopulateCoreTypes().
+
+2002-06-29 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.ImplicitReferenceConversionExists): If expr
+ is the NullLiteral, we also need to make sure that target_type is not
+ an enum type.
+
+2002-06-29 Martin Baulig <martin@gnome.org>
+
+ * rootcontext.cs (RootContext.ResolveCore): We must initialize
+ `TypeManager.multicast_delegate_type' and `TypeManager.delegate_type'
+ before calling BootstrapCorlib_ResolveDelegate ().
+
+2002-06-27 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * statement.cs: fixed build-breaker. All tests passed ok.
+
+2002-06-27 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.VerifyUnManaged): Added explicit check
+ for System.Decimal when compiling corlib.
+
+2002-06-27 Martin Baulig <martin@gnome.org>
+
+ * statement.cs (Switch.TableSwitchEmit): Make this work with empty
+ switch blocks which contain nothing but a default clause.
+
+2002-06-26 Andrew <adb@tardis.ed.ac.uk>
+
+ * ../errors/cs1501-3.cs: Added new test for struct ctr typechecks.
+
+2002-06-27 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (PropertyExpr.PropertyExpr): Call
+ TypeManager.TypeToCoreType() on the `pi.PropertyType'.
+
+ * typemanager.cs (TypeManager.TypeToCoreType): Return if the type
+ is already a TypeBuilder.
+
+2002-06-27 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.ImplicitReferenceConversionExists): Use
+ `target_type == TypeManager.array_type', not IsAssignableFrom() in
+ the "from an array-type to System.Array" case. This makes it work
+ when compiling corlib.
+
+2002-06-27 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.SimpleNameResolve): If the expression is a
+ non-static PropertyExpr, set its InstanceExpression. This makes
+ the `ICollection.Count' property work in System/Array.cs.
+
+2002-06-25 Andrew Birkett <adb@tardis.ed.ac.uk>
+
+ * driver.cs: Made error handling more consistent. Errors now
+ tracked by Report class, so many methods which used to return int
+ now return void. Main() now prints success/failure and
+ errors/warnings message.
+
+ Renamed '--probe' compiler argument to '--expect-error'. Removed
+ the magic number return values (123 and 124). Now, if the
+ expected error occurs, the compiler exits with success (exit value
+ 0). If the compilation completes without seeing that particular
+ error, the compiler exits with failure (exit value 1). The
+ makefile in mcs/errors has been changed to handle the new behaviour.
+
+ * report.cs: Made 'expected error' number a property and renamed
+ it from 'Probe' to 'ExpectedError'.
+
+ * genericparser.cs: Removed error handling support, since it is
+ now all done by Report class.
+
+ * cs-parser.jay, mb-parser.jay: Errors are tracked by Report
+ class, so parse() no longer returns an int.
+
+ * namespace.cs: Use Report.Error instead of GenericParser.error
+
+2002-06-22 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer.AddMethod, TypeContainer.AddIndexer,
+ TypeContainer.AddOperator): At the front of the list put the
+ explicit implementations, so they get resolved/defined first.
+
+2002-06-21 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer.VerifyImplements): Verifies that a given
+ interface type is implemented by this TypeContainer. Used during
+ explicit interface implementation.
+
+ (Property.Define, Indexer.Define, Method.Define): Validate that
+ the given interface in the explicit implementation is one of the
+ base classes for the containing type.
+
+ Also if we are explicitly implementing an interface, but there is
+ no match in the pending implementation table, report an error.
+
+ (Property.Define): Only define the property if we are
+ not explicitly implementing a property from an interface. Use the
+ correct name also for those properties (the same CSC uses,
+ although that is really not needed).
+
+ (Property.Emit): Do not emit attributes for explicitly implemented
+ properties, as there is no TypeBuilder.
+
+ (Indexer.Emit): ditto.
+
+ Hiding then means that we do not really *implement* a pending
+ implementation, which makes code fail.
+
+2002-06-22 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.Constantify): Call TypeManager.TypeToCoreType() on
+ the return value of Object.GetType(). [FIXME: we need to do this whenever
+ we get a type back from the reflection library].
+
+Fri Jun 21 13:37:57 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * typemanager.cs: make ExpandInterfaces() slip duplicated interfaces.
+
+2002-06-20 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs: Return null if we can not look up the type.
+
+ * class.cs (TypeContainer.GetClassBases): Use ExpandInterfaces on
+ the interface types found.
+
+ * interface.cs (Interface.GetInterfaceBases): Use ExpandInterfaces on the
+ interface types found.
+
+ * typemanager.cs (GetInterfaces): Make this routine returns alll
+ the interfaces and work around the lame differences between
+ System.Type and System.Reflection.Emit.TypeBuilder in the results
+ result for GetInterfaces.
+
+ (ExpandInterfaces): Given an array of interface types, expand and
+ eliminate repeated ocurrences of an interface. This expands in
+ context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
+ be IA, IB, IC.
+
+2002-06-21 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.EnumToUnderlying): It's now safe to call this function
+ on System.Enum.
+
+2002-06-21 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (TypeManager.TypeToCoreType): New function. When compiling corlib
+ and called with one of the core types, return the corresponding typebuilder for
+ that type.
+
+ * expression.cs (ArrayAccess.DoResolve): Call TypeManager.TypeToCoreType() on the
+ element type.
+
+2002-06-21 Martin Baulig <martin@gnome.org>
+
+ * ecore.cs (Expression.ExplicitReferenceConversionExists): Use
+ `target_type.IsArray' instead of `target_type.IsSubclassOf (TypeManager.array_type)'.
+ (Expression.ConvertReferenceExplicit): Likewise.
+
+ * expression.cs (ElementAccess.DoResolve): Likewise.
+ (ElementAccess.DoResolveLValue): Likewise.
+
+2002-06-10 Martin Baulig <martin@gnome.org>
+
+ * interface.cs (Interface.PopulateIndexer): When creating the setter, we need to
+ add the "value" parameter to the parameter list.
+
+ * statement.cs (Fixed.Emit): Pass the return value of the child block's Emit()
+ to our caller.
+
+2002-06-19 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ArrayCreation.ExpressionToArrayArgument): Convert
+ the argument to an int, uint, long or ulong, per the spec. Also
+ catch negative constants in array creation.
+
+Thu Jun 20 17:56:48 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs: do not allow the same interface to appear twice in
+ the definition list.
+
+Wed Jun 19 22:33:37 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * ecore.cs: don't use ldlen with System.Array.
+
+Wed Jun 19 20:57:40 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * ecore.cs: stobj requires a type argument. Handle indirect stores on enums.
+
+Wed Jun 19 20:17:59 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * modifiers.cs: produce correct field attributes for protected
+ internal. Easy fix so miguel can work on ther harder stuff:-)
+
+2002-06-18 Miguel de Icaza <miguel@ximian.com>
+
+ * pending.cs: New file. Move the code from class.cs here.
+ Support clearning the pending flag for all methods (when not doing
+ explicit interface implementation).
+
+Tue Jun 18 10:36:22 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * rootcontext.cs: added a couple more types needed to bootstrap.
+
+2002-06-17 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (GetConstructor): Use DeclaredOnly to look the
+ constructor in the type, instead of any constructor in the type
+ hierarchy. Thanks to Paolo for finding this bug (it showed up as
+ a bug in the Mono runtime when applying the params attribute).
+
+2002-06-16 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * changed namespace.cs to use "GenericParser.error(...)" instead of "CSharpParser.error(...)"
+
+2002-06-14 Rachel Hestilow <hestilow@ximian.com>
+
+ * expression.cs (Unary.ResolveOperator): Use TypeManager
+ to resolve the type.
+
+2002-06-13 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (enum_member_declaration): Pass in the attributes
+ attached.
+
+ * enum.cs (AddEnumMember): Add support to store the attributes associated
+ with each member too.
+
+ * attribute.cs (CheckAttribute, ApplyAttributes): Update to handle
+ field builders too - this takes care of the enum member case.
+
+2002-06-10 Rachel Hestilow <hestilow@ximian.com>
+
+ * typemanager.cs (TypeManager.VerifyUnManaged): Allow
+ address-of operator on both value types and pointers.
+
+2002-06-10 Martin Baulig <martin@gnome.org>
+
+ * interface.cs (Interface.PopulateIndexer): Add the indexer's
+ PropertyBuilder to the `property_builders' list.
+
+ * expression.cs (Indexers.GetIndexersForTypeOrInterface): New private method.
+ (Indexers.GetIndexersForType): Call GetIndexersForTypeOrInterface() on the
+ `lookup_type' and all its interfaces. Unfortunately, Type.FindMembers() won't
+ find any indexers which are inherited from an interface.
+
+2002-06-09 Martin Baulig <martin@gnome.org>
+
+ * const.cs (Const.LookupConstantValue): Convert `Expr' to a literal of
+ the same type as the constant if necessary. There's also a test-130.cs
+ for this.
+
+ * enum.cs (Enum.ChangeEnumType): Moved to typemanager.cs and made public.
+
+ * typemanager.cs (TypeManager.ChangeType): Previously known as
+ Enum.ChangeEnumType().
+
+2002-06-09 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Cast.TryReduce): Added support for consts.
+
+2002-06-08 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Accessor): Hold attributes information so we can pass
+ it along.
+
+ * cs-parser.jay (get_accessor_declaration, set_accessor_declaration):
+ Modify to pass in attributes attached to the methods.
+
+ (add_accessor_declaration, remove_accessor_declaration): Ditto.
+
+ * attribute.cs (ApplyAttributes, CheckAttribute): Update accordingly
+ to handle the Accessor kind :-)
+
+ * class.cs (Property.Emit, Event.Emit): Apply attributes to the accessors
+
+2002-06-08 Martin Baulig <martin@gnome.org>
+
+ * expression.cs (Unary.TryReduceNegative): Added support for
+ ULongConstants.
+
+2002-06-08 Martin Baulig <martin@gnome.org>
+
+ * enum.cs (Enum.LookupEnumValue): Don't report an error if the
+ name can't be found in the `defined_names' - the caller will do a
+ MemberLookup in this case and thus find methods in System.Enum
+ such as Enum.IsDefined().
+
+2002-06-08 Martin Baulig <martin@gnome.org>
+
+ * enum.cs (Enum.ChangeEnumType): This is a custom version of
+ Convert.ChangeType() which works with TypeBuilder created types.
+ (Enum.LookupEnumValue, Enum.Define): Use it here.
+
+ * class.cs (TypeContainer.RegisterRequiredImplementations): Added
+ `TypeBuilder.BaseType != null' check.
+ (TypeContainer.FindMembers): Only lookup parent members if we
+ actually have a parent.
+ (Method.EmitDestructor): Added `ec.ContainerType.BaseType != null' check.
+ (ConstructorInitializer.Resolve): Likewise.
+
+ * interface.cs (Interface.FindMembers): Added
+ `TypeBuilder.BaseType != null' check.
+
+ * rootcontext.cs (RootContext.ResolveCore): Added
+ "System.Runtime.CompilerServices.IndexerNameAttribute" to
+ classes_second_stage.
+
+ * typemanager.cs (TypeManager.InitCoreTypes): Don't initialize
+ debug_type and trace_type when compiling with --nostdlib.
+
+2002-06-07 Martin Baulig <martin@gnome.org>
+
+ * class.cs (TypeContainer): Added `have_nonstatic_fields' field.
+ (AddField): Set it to true when adding a non-static field.
+ (DefineType): Use `have_nonstatic_fields' to find out whether we
+ have non-static fields, not `Fields != null'.
+
+2002-06-02 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (SimpleNameResolve): Removed simple bug (we were
+ dereferencing a null on the static-field code path)
+
+2002-05-30 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (InitMonoSymbolWriter): Added `string[] args' argument
+ to take command line arguments. Use reflection to call the new
+ custom `Initialize' function on the symbol writer and pass it the
+ command line arguments.
+
+ * driver.cs (--debug-args): New command line argument to pass command
+ line arguments to the symbol writer.
+
+2002-05-28 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs (DoResolve): Forgot to do the implicit conversion to
+ the target type for indexers and properties. Thanks to Joe for
+ catching this.
+
+2002-05-27 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (MethodFlags): returns the method flags
+ (Obsolete/ShouldIgnore) that control warning emission and whether
+ the invocation should be made, or ignored.
+
+ * expression.cs (Invocation.Emit): Remove previous hack, we should
+ not do this on matching a base type, we should do this based on an attribute
+
+ Only emit calls to System.Diagnostics.Debug and
+ System.Diagnostics.Trace if the TRACE and DEBUG defines are passed
+ on the command line.
+
+ * rootcontext.cs: Global settings for tracing and debugging.
+
+ * cs-tokenizer.cs (define): New utility function to track
+ defines. Set the global settings for TRACE and DEBUG if found.
+
+2002-05-25 Ravi Pratap <ravi@ximian.com>
+
+ * interface.cs (Populate*): Pass in the TypeContainer as well as
+ the DeclSpace as parameters so that we can create EmitContexts and
+ then use that to apply attributes etc.
+
+ (PopulateMethod, PopulateEvent, PopulateProperty)
+ (PopulateIndexer): Apply attributes everywhere.
+
+ * attribute.cs (CheckAttribute): Include InterfaceMethod, InterfaceEvent
+ etc.
+
+ (ApplyAttributes): Update accordingly.
+
+ We now apply interface attributes for all members too.
+
+2002-05-26 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Indexer.Define); Correctly check if we are explicit
+ implementation (instead of checking the Name for a ".", we
+ directly look up if the InterfaceType was specified).
+
+ Delay the creation of the PropertyBuilder.
+
+ Only create the PropertyBuilder if we are not an explicit
+ interface implementation. This means that explicit interface
+ implementation members do not participate in regular function
+ lookups, and hence fixes another major ambiguity problem in
+ overload resolution (that was the visible effect).
+
+ (DefineMethod): Return whether we are doing an interface
+ implementation.
+
+ * typemanager.cs: Temporary hack until we get attributes in
+ interfaces (Ravi is working on that) and we get IndexerName
+ support in interfaces.
+
+ * interface.cs: Register the indexers as properties.
+
+ * attribute.cs (Attribute.Resolve): Catch the error, and emit a
+ warning, I have verified that this is a bug in the .NET runtime
+ (JavaScript suffers of the same problem).
+
+ * typemanager.cs (MemberLookup): When looking up members for
+ interfaces, the parent of an interface is the implicit
+ System.Object (so we succeed in searches of Object methods in an
+ interface method invocation. Example: IEnumerable x; x.ToString
+ ())
+
+2002-05-25 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Event): Events should also register if they do
+ implement the methods that an interface requires.
+
+ * typemanager.cs (MemberLookup); use the new GetInterfaces
+ method.
+
+ (GetInterfaces): The code used to lookup interfaces for a type is
+ used in more than one place, factor it here.
+
+ * driver.cs: Track the errors at the bottom of the file, we kept
+ on going.
+
+ * delegate.cs (NewDelegate.Emit): We have to emit a null as the
+ instance if the method we are calling is static!
+
+2002-05-24 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs (ApplyAttributes): Make this function filter out
+ the IndexerName attribute (as that attribute in reality is never
+ applied) and return the string constant for the IndexerName
+ attribute.
+
+ * class.cs (TypeContainer.Emit): Validate that all the indexers
+ have the same IndexerName attribute, and if so, set the
+ DefaultName attribute on the class.
+
+ * typemanager.cs: The return value might contain other stuff (not
+ only methods). For instance, consider a method with an "Item"
+ property and an Item method.
+
+ * class.cs: If there is a problem with the parameter types,
+ return.
+
+2002-05-24 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (ImplicitConversionExists): Wrapper function which also
+ looks at user defined conversion after making a call to
+ StandardConversionExists - we need this for overload resolution.
+
+ * expression.cs : Update accordingly the various method calls.
+
+ This fixes 2 bugs filed against implicit user defined conversions
+
+2002-05-22 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: Track the result of the assignment.
+
+2002-05-21 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MemberAccess): Improved error reporting for
+ inaccessible members.
+
+2002-05-22 Martin Baulig <martin@gnome.org>
+
+ * makefile (mcs-mono2.exe): New target. This is mcs compiled with
+ itself with debugging support.
+
+2002-05-22 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs ("System.Runtime.InteropServices.StructLayoutAttribute"):
+ Removed, this isn't needed anymore.
+
+2002-05-20 Martin Baulig <martin@gnome.org>
+
+ * typemanager.cs (InitEnumUnderlyingTypes): "System.Char" can't
+ be underlying type for an enum.
+
+2002-05-20 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (InitEnumUnderlyingTypes): New helper function
+ that splits out the loading of just the core types.
+
+ * rootcontext.cs (ResolveCore): Split the struct resolution in
+ two, so we can load the enumeration underlying types before any
+ enums are used.
+
+ * expression.cs (Is): Bandaid until we fix properly Switch (see
+ bug #24985 for details).
+
+ * typemanager.cs (ImplementsInterface): The hashtable will contain
+ a null if there are no interfaces implemented.
+
+2002-05-18 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (indexer_declarator): It is fine to have array
+ parameters
+
+2002-05-17 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: (RegisterBuilder): New function used to register
+ TypeBuilders that implement interfaces. Since
+ TypeBuilder.GetInterfaces (as usual) does not work with lame
+ Reflection.Emit.
+ (AddUserType): register interfaces.
+
+ (ImplementsInterface): Use the builder_to_ifaces hash if we are
+ dealing with TypeBuilder. Also, arrays are showing up as
+ SymbolTypes, which are not TypeBuilders, but whose GetInterfaces
+ methods can not be invoked on them!
+
+ * ecore.cs (ExplicitReferenceConversionExists): Made public.
+ (ImplicitReferenceConversionExists): Split out from
+ StandardConversionExists.
+
+ * expression.cs (As): We were only implementing one of the three
+ cases for the as operator. We now implement them all.
+ (Is): Implement the various other cases for Is as well.
+
+ * typemanager.cs (CACHE): New define used to control if we want or
+ not the FindMembers cache. Seems to have a negative impact on
+ performance currently
+
+ (MemberLookup): Nested types have full acess to
+ enclosing type members
+
+ Remove code that coped with instance/static returns for events, we
+ now catch this in RealFindMembers.
+
+ (RealFindMembers): only perform static lookup if the instance
+ lookup did not return a type or an event.
+
+2002-05-17 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs (CompoundAssign): We pass more semantic information
+ now to Compound Assignments than we did before: now we have all
+ the information at hand, and now we resolve the target *before* we
+ do the expression expansion, which allows the "CacheValue" method
+ to have the effect we intended (before, a [x] += 1 would generate
+ two differen ArrayAccess expressions from the ElementAccess,
+ during the resolution process).
+
+ (CompoundAssign.DoResolve): Resolve target and original_source here.
+
+2002-05-16 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ArrayAccess): dropped debugging information.
+
+ * typemanager.cs: Small bug fix: I was always returning i_members,
+ instead of one of i_members or s_members (depending on which had
+ the content).
+
+ * assign.cs (IAssignMethod.CacheTemporaries): New method. This
+ method is invoked before any code generation takes place, and it
+ is a mechanism to inform that the expression will be invoked more
+ than once, and that the method should use temporary values to
+ avoid having side effects
+
+ (Assign.Emit): Call CacheTemporaries in the IAssignMethod.
+
+ * ecore.cs (Expression.CacheTemporaries): Provide empty default
+ implementation.
+
+ * expression.cs (Indirection, ArrayAccess): Add support for
+ CacheTemporaries in these two bad boys.
+
+ * ecore.cs (LoadFromPtr): figure out on our own if we need to use
+ ldobj or ldind_ref.
+ (StoreFromPtr): Handle stobj as well.
+
+ * expression.cs (UnaryMutator): Share more code.
+
+ * typemanager.cs (FindMembers): Thanks to Paolo for tracking this
+ down: I was not tracking the Filter function as well, which
+ was affecting the results of the cache.
+
+2002-05-15 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs: Remove the hack to handle the CharSet property on
+ StructLayouts.
+
+2002-05-14 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs (DoResolve): More uglyness, we now only try to
+ resolve the attribute partially, to extract the CharSet
+ information (only if we are a StructLayout attribute). Otherwise
+
+ (GetExtraTypeInfo): Add some code to conditionally kill in the
+ future this. I am more and more convinced that the .NET
+ framework has special code to handle the attribute setting on
+ certain elements.
+
+ * expression.cs (IsParamsMethodApplicable): Revert my previous
+ foreach change here, it was wrong.
+
+2002-05-13 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: (pp_primary): Eat the ')' at the end.
+ (pp_expr): do not abort on unknown input, just return.
+ (eval): abort if there are pending chars.
+
+ * attribute.cs (Attribute.Resolve): Positional parameters are
+ optional. Deal with that case.
+
+ * class.cs (DefineType): Call Attribute.GetExtraTypeInfo to fetch
+ the Ansi/Unicode/Auto information for the type.
+
+ (TypeContainer.DefineType): instantiate the EmitContext here, as
+ we will be using it during the type definition (to resolve
+ attributes) and during the emit phase.
+
+ * attribute.cs (Attribute.GetExtraTypeInfo): This routine is used
+ to pull type information out of the attributes
+
+ (Attribute.Resolve): track the constructor builder, and allow for
+ multiple invocations (structs and classes will use this).
+
+ * ecore.cs (MemberLookupFinal): new version with all the
+ parameters customizable.
+
+ * expression.cs (New.DoResolve): Use MemberLookupFinal to locate
+ constructors. Return if the result value is null (as the error
+ would have been flagged already by MemberLookupFinal)
+
+ Do not allow instances of abstract classes or interfaces to be
+ created.
+
+ * class.cs: (MethodSignature.InheritableMemberSignatureCompare):
+ We have to compare the assembly property here when dealing with
+ FamANDAssem and Assembly access modifiers, because we might be
+ creating an assembly from *modules* (that means that we are not
+ getting TypeBuilders for types defined in other modules that are
+ part of this assembly).
+
+ (Method.Emit): If the method is marked abstract and has a body,
+ emit an error.
+
+ (TypeContainer.DefineMembers): If both the defined member and the
+ parent name match are methods, then do not emit any warnings: let
+ the Method.Define routine take care of flagging warnings. But if
+ there is a mismatch (method overrides something else, or method is
+ overriwritten by something, then emit warning).
+
+ (MethodSignature.MemberSignatureCompare): If the sig.ret_type is
+ set to null, this means `do not check for the return type on the
+ signature'.
+
+ (Method.Define): set the return type for the method signature to
+ null, so that we get methods with the same name and parameters and
+ different return types. This is used to flag warning 114 (you are
+ hiding a method, and you probably want to use the new/override
+ keywords instead).
+
+ * typemanager.cs (MemberLookup): Implemented proper access
+ control, closing a long standing set of bug reports. The problem
+ was that the Framework only has two bits: Public and NonPublic,
+ and NonPublic includes private and protected methods, but we need
+ to enforce the FamANDAssem, FamOrAssem and Family.
+
+2002-05-11 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (GotoCase): Return true: Ammounts to giving up
+ knowledge on whether we return or not, and letting the other case
+ be responsible for it.
+
+2002-05-10 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Do not load directories for each file processed, only
+ do it if there is a pattern.
+
+ * ecore.cs: Report readonly assigns here as well, as we might have
+ been resolved only by MemberAccess.
+
+ (SimpleName.SimpleNameResolve): Also be useful for LValue
+ resolution. We need this to propagate assign to local readonly variables
+
+ * typemanager.cs: Use a ptrhashtable for the criteria, because we
+ do not want to reuse potential criteria memory.
+
+ * class.cs (MyEventBuilder): Set reflected_type;
+
+ * ecore.cs (Constantify): Added support for constifying bools.
+
+ (RootContext.LookupType): Added a cache for values looked up in
+ the declaration space.
+
+ * typemanager.cs (FindMembers): Now is a front-end to
+ RealFindMembers, and provides a two-level hashtable-based cache to
+ the request.
+
+ 15% performance improvement: from 22.5 to 19.2 seconds.
+
+ * expression.cs (IsParamsMethodApplicable): use foreach.
+ (Invocation.DoResolve): ditto.
+ (New.DoResolve): ditto.
+ (ArrayCreation.DoResolve): ditto.
+
+ * ecore.cs (FindMostEncompassingType): use foreach.
+
+ * delegate.cs (NewDelegate.DoResolve): Use foreach
+
+ * ecore.cs (Expression.FindMostSpecificSource): Use foreach.
+ (RemoveMethods): use foreach.
+
+ * expression.cs (Invocation.MakeUnionSet): Optimization: Use two
+ nested foreach statements instead of for, and also break out of
+ the inner loop once a match is found.
+
+ (Invocation.OverloadResolve): Use foreach, simplify the code.
+
+2002-05-08 Miguel de Icaza <miguel@ximian.com>
+
+ * cfold.cs (BinaryFold): During an enumeration evaluation context,
+ we actually unwrap the expression to allow for extra information
+ to be extracted.
+
+ * expression.cs: Use Shr_Un on unsigned operations.
+
+2002-05-08 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (FindMostEncompass*): Fix trivial bug where the set of
+ applicable operators was not being considered correctly. This closes
+ the bug Miguel reported.
+
+Wed May 8 16:40:50 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * attribute.cs: check that the type derives from System.Attribute
+ and report the correct error in that case (moved the duplicate code to
+ its own method, too).
+
+Wed May 8 11:50:31 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+ * attribute.cs: lookup attribute type name as the spec says: first the
+ bare attribute name and then name + "Attribute" (nant compiles with
+ mcs after this fix).
+
+2002-05-07 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Unary.TryReduceNegative): Ah! Tricky! Tricky!
+ Because of the way we parse things, we should try to see if a
+ UIntConstant can fit in an integer.
+
+2002-05-07 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (GetConversionOperators): Do not pick up op_True operators
+ when we are in an explicit context.
+
+ (ConvertReferenceExplicit): When converting from Iface type S to Class
+ T make sure the rules are implemented as an OR.
+
+ * parameter.cs (ParameterType): Make it a property for now although the
+ purpose really isn't anything immediate.
+
+ * expression.cs (Is*Applicable): Do better checking on the parameter type
+ of a ref/out parameter. The ones from the system assemblies are already
+ marked with the correct type so we don't need to do any correction.
+
+ * ecore.cs (StandardConversionExists): Conversion from Interface types to
+ the object type is standard too so include that.
+
+2002-05-06 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (StandardConversionExists): Augment with missing code:
+ deal with IntConstant, LongConstants and Enumerations.
+
+ * assign.cs: Report the error, instead of failing silently
+
+ * rootcontext.cs (AddGlobalAttributes): Track attributes on the
+ typecontainer that they are declared, because the
+ typecontainer/namespace will have the list of using clauses that
+ need to be applied.
+
+ Assembly Attributes were escaping the normal registration
+ mechanism.
+
+ (EmitCode): Apply attributes within an EmitContext that represents
+ the container they were declared on.
+
+ * cs-parser.jay: Track bases for structs. How did I get this wrong?
+
+2002-05-06 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (FindMostEncompassingType, FindMostEncompassedType):
+ Revamp completely - make much cleaner as we now operate only
+ on a set of Types.
+
+ (FindMostSpecificSource, FindMostSpecificTarget): New methods
+ to implement the logic detailed in the spec more correctly.
+
+ (UserDefinedConversion): Update accordingly.
+
+2002-05-06 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: Return flow analysis information up.
+
+ * cs-tokenizer.cs (adjust_real): Share code between LITERAL_DOUBLE
+ and the default.
+
+ (token): Do not consume an extra character before calling
+ decimal_digits.
+
+2002-05-06 Piers Haken <piersh@friskit.com>
+
+ * cs-parser.jay: add 'override' attribute to System.Object.Finalize
+
+2002-05-06 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Constructor.Emit): Set the IsStatic flag in the
+ EmitContext during the instance constructor initializer
+ resolution, to stop access to instance variables.
+
+ This is mandated by the spec, last paragraph of the `constructor
+ initializers' section.
+
+2002-05-05 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay, class.cs (Accessor): new class used to represent
+ an accessor (get or set). In the past we used `null' to represent
+ a missing accessor. But this is ambiguous because there was no
+ way to tell in abstract indexers/properties if one of them was
+ specified.
+
+ Now there is a way of addressing that.
+
+ * expression.cs (Indexers.GetIndexersForType): Use TypeManager.MemberLookup
+ instead of FindMembers.
+
+ * class.cs (TypeContainer.EmitFieldInitializer): Do not typecast
+ the result of Assign.Resolve as Assign, but rather as ExpressionStatement.
+
+ * attribute.cs: Treat indexers and properties as the same in terms
+ of applying attributes
+
+ * ecore.cs (FindMostEncompassedType): Use statically initialized
+ EmptyExpressions()s like we do elsewhere to avoid creating useless
+ objects (and we take this out of the tight loop).
+
+ (GetConversionOperators): Move the code to extract the actual
+ operators to a separate routine to clean things up.
+
+2002-05-04 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr): Remove un-needed tests for null, since now
+ events are always registered FieldBuilders.
+
+ * class.cs (FieldBase): New class shared by Fields
+
+ * delegate.cs: If we are a toplevel delegate, use our full name.
+ If we are a nested delegate, then only use our tail name.
+
+2002-05-02 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (IsApplicable): Ensure that we add the "&" to
+ ref/out types before comparing it with the type of the argument.
+
+ (IsParamsMethodApplicable): Ditto.
+
+ (Argument.Type): Use TypeManager.LookupType instead of Type.GetType -
+ silly me ;-)
+
+ * delegate.cs : Handle the case when we have more than one applicable
+ method. Flag an error only when we finish checking all.
+
+2002-05-02 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Add support for boolean static initializers.
+
+2002-05-01 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs: Use proper cast for Events, since we use a MyEventBuilder.
+
+ * parameter.cs (ComputeParameterTypes,
+ ComputeAndDefineParameterTypes): Better error handling: now we
+ clear the `types' cache if we fail during any of the type lookups.
+ We also return the status code correctly to our caller
+
+ * delegate.cs: If we fail to define a delegate, abort the extra
+ steps.
+
+ * expression.cs (Binary.ResolveOperator): for
+ operator==(object,object) and operator !=(object, object) we also
+ have to verify that there is an implicit conversion from one to
+ the other.
+
+ (ArrayAccess.DoResolve): Array Access can operate on
+ non-variables.
+
+2002-04-30 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs (CompoundAssign): A new class used as a "flag" that
+ the assignment actually is happening as part of a compound
+ assignment operator.
+
+ During compound assignment, a few new rules exist to enable things
+ like:
+
+ byte b |= 1 + 2
+
+ From the spec:
+
+ x op= y can be evaluated as x = (T) (x op y) (ie, an explicit cast
+ to the type of x) if y is implicitly convertible to the type of x,
+ and the operator is a builtin operator and the return type of the
+ operator is explicitly convertible to the type of x.
+
+ * rootcontext.cs: Reset warning level to 2. 4 catches various
+ "interesting" features in mcs, we must clean this up at some
+ point, but currently am trying to kill other bugs ;-)
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Perform member lookups
+ in container classes as well.
+
+ * expression.cs (Binary.ResolveOperator): Handle string case
+ before anything else (as operator overloading does emit an error
+ before doing anything else).
+
+ This code could go away when we move to a table driven model, but
+ i could not come up with a good plan last night.
+
+2002-04-30 Lawrence Pit <loz@cable.a2000.nl>
+
+ * typemanager.cs (CSharpName): reimplementation using regex.
+ * class.cs: added null check for fields in Emit
+ * rootcontext.cs: set warninglevel to 4
+
+2002-04-29 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (CSharpName): reimplemented with Lupus
+ suggestion.
+
+2002-04-28 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (If): correclty implement Resolve, because we were
+ not catching sem errors in there. The same process is needed
+ everywhere else.
+ (Return, StatementExpression, For, While, Do, Throw, Lock): Implement Resolve
+
+
+ (Statement.Warning_DeadCodeFound): Factorize code.
+ (While): Report dead code here too.
+
+ (Statement): Added Resolve virtual method to allow
+ for resolution split from the emit code.
+
+2002-04-26 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (EmitBoolExpression): No longer try to resolve the
+ expression here.
+ (MakeBoolean): New utility function that resolve, implicitly
+ converts to boolean and tags the expression.
+
+
+ (If, Do): Implement dead code elimination.
+ (While): Implement loop inversion
+
+ (Do, While, For, If): Resolve the expression prior to calling our
+ code generation.
+
+2002-04-22 Lawrence Pit <loz@cable.a2000.nl>
+
+ * class.cs:
+ - added method Report28 (warning: program has more than one entry point)
+ - added method IsEntryPoint, implements paragraph 10.1 of the spec
+ - modified method Method.Define, the part at the end of the method
+
+ * rootcontext.cs: added static public Location EntryPointLocation;
+
+ * ../errors/cs0028.cs : Add test case for the above warning.
+
+ * typemanager.cs:
+ - modified method CSharpName to allow arrays of primitive type to
+ be printed nicely (e.g. instead of System.Int32[][] it now prints
+ int[][])
+ - added method CSharpSignature: returns the signature of a method
+ in string format to be used in reporting errors, warnings, etc.
+
+ * support.cs: InternalParameters.ParameterDesc variable tmp initialized
+ with String.Empty.
+
+2002-04-26 Ravi Pratap <ravi@ximian.com>
+
+ * delegate.cs (Define): Fix extremely silly bug where I was
+ setting the type of the 'object' parameter of the BeginInvoke
+ method to System.IAsyncResult instead of System.Object ;-)
+
+2002-04-26 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (ConstructorInitializer.Resolve): Also use DeclaredOnly
+ here.
+
+ (Constructor.Emit): return if we fail to initialize the
+ constructor. Another door closed!
+
+ * expression.cs (New.DoResolve): Improve error message (from -6 to
+ 1501). Use DeclaredOnly lookup to find the exact constructor.
+
+ * typemanager.cs (MemberLookup): If DeclaredOnly is set, do not
+ loop. This is useful.
+
+ * cs-parser.jay: Adjust the default parameters so that destructors
+ have the proper signature.
+
+2002-04-26 Martin Baulig <martin@gnome.org>
+
+ * driver.cs (LoadAssembly): If `assembly' contains any characters
+ which are only valid in path names and not in assembly names
+ (currently slash, backslash and point), use Assembly.LoadFrom ()
+ instead of Assembly.Load () on the `assembly' (before iteration
+ over the link_paths).
+
+2002-04-26 Martin Baulig <martin@gnome.org>
+
+ * cs-tokenizer.cs (is_hex): Correctly handle lowercase chars.
+
+2002-04-25 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Property): use the new typemanager.MemberLookup
+
+ (TypeContainer.MemberLookup): Implement using the
+ TypeManager.MemberLookup now.
+
+ * typemanager.cs: Make MemberLookup a function of the TypeManager,
+ and return MemberInfos, so that these can be used without an
+ EmitContext (what we had before).
+
+2002-04-24 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Fix the case where the argument to params if the
+ type of the params. I omitted handling this before. Fixed
+
+2002-04-22 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Call BootCorlib_PopulateCoreType
+
+ * class.cs (Property.CheckBase): Check for properties only, not
+ for all members.
+
+ * interface.cs: Temporary hack: try/catch around the
+ CustomAttributeBuilder, because I am getting an exception that I
+ do not understand.
+
+ * rootcontext.cs (BootCorlib_PopulateCoreType): Populate some
+ types whose definitions are required to be there (attributes are
+ defined before standard types).
+
+ Compute definitions as we boot the various types, as they are used
+ immediately (value_type class will need object_type, but if we do
+ not initialize object_type, we will pass a null, which will let
+ the runtime pick the System.Object from the existing corlib, which
+ is not what we want).
+
+2002-04-22 Patrik Torstensson <totte@labs2.com>
+
+ * cs-tokenizer.cs: fixed a number of trim() issues.
+
+2002-04-22 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Argument.Type): Ensure that we return the correct
+ type when we have out or ref parameters [in which case we
+ append a "&"].
+
+2002-04-22 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Property, Indexer): Allow extern modifier in there.
+
+ * typemanager.cs (InitBaseTypes): Initializes object_type and
+ value_type, since those will be used early on during the bootstrap
+ process to compile corlib.
+
+ (InitCoreTypes): Move code from here to InitBaseTypes.
+
+2002-04-21 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (PropertyExpr): Optimize calls to Array::get_Length on
+ single-dimension arrays as using the ldlen opcode.
+
+ Daniel Lewis discovered this optimization.
+
+ * typemanager.cs: Add signature for System.Array::get_Length
+
+2002-04-20 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * statement.cs: report the error when the foreach does not apply to an
+ array nor a collection.
+
+2002-04-19 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Add implicit conversions to the operator ~.
+
+ * constant.cs (DecimalConstant.Emit): Emit decimal value.
+
+ * typemanager.cs: Locate the decimal constructor.
+
+2002-04-17 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * attribute.cs: use the new property of TypeOf.
+ * expression.cs: added 'get' property around typearg.
+
+ These changes fix a build breaker reported by NickD. Is this the
+ correct way to fix? If not, please, revert my changes and make it
+ work :-).
+
+2002-04-17 Miguel de Icaza <miguel@ximian.com>
+
+ * attribute.cs: Add support for typeof in attribute invocations.
+ I am not sure that this is right though.
+
+2002-04-14 Duncan Mak <duncan@ximian.com>
+
+ * cfold.cs (BinaryFold): Catch DivideByZeroException in the
+ Binary.Operator.Division case.
+
+2002-04-13 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (DefineType): Ensure that we do a proper check on
+ attribute types and also register it with the TypeManager.
+
+ (TypeContainer.Targets): The default for attribute types is
+ AttributeTargets.All.
+
+ * attribute.cs (ApplyAttributes): Registering the attribute type
+ is done elsewhere, not when we discover we have a Usage attribute.
+
+2002-04-12 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (VerifyArgumentsCompat): Implement Miguel's suggestion
+ and get rid of is_delegate parameter.
+
+ * everywhere : update.
+
+2002-04-12 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (compilation_unit): Revamp completely to use
+ some new ideas that I got from Rhys' grammar to solve the problems
+ with assembly level attributes.
+
+ (outer_declaration): New grammar production.
+
+ (attribute_sections): Add.
+
+ (opt_attributes): Base on attribute_sections
+
+ (namespace_declaration): Allow opt_attributes to tackle the case
+ when we have assembly level attributes - we are clever in this
+ regard now ;-)
+
+ * attribute.cs (ApplyAttributes): Do not worry about assembly
+ attributes in the non-global context.
+
+ * rootcontext.cs (AddGlobalAttributes): Go back to using this
+ instead of SetGlobalAttributes.
+
+ * class.cs, rootcontext.cs : Ensure we define and generate
+ attribute types before anything else.
+
+ * attribute.cs (CheckAttribute and GetValidPlaces): Handle the exception
+ and flag the new error -20 for the case when the attribute type
+ does not have valid targets specified. csc does not catch this.
+
+ * ../errors/errors.txt : update for error # -20
+
+2002-04-11 Ravi Pratap <ravi@ximian.com>
+
+ * support.cs (InternalParameters.ParameterModifier): Do some null
+ checking and return sane values.
+
+ * class.cs (Method.Define): If we are a PInvoke method, ensure
+ that we are static and extern. Report error # 601
+
+ * ../errors/cs0601.cs : Add test case for the above error.
+
+2002-04-07 Ravi Pratap <ravi@ximian.com>
+
+ * rootcontext.cs (attribute_types): We need to keep type of
+ all attribute types separately and emit code for them first.
+
+ (RegisterAttribute) : Implement.
+
+ * class.cs (DefineType): Check if the current Type is a custom
+ attribute type and register it accordingly.
+
+ * rootcontext.cs (AddGlobalAttributes): Fix silly bug where we were
+ adding the first attribute twice and rename to
+
+ (SetGlobalAttributes): this.
+
+ * rootcontext.cs (NamespaceLookup): Run through the aliases too and perform
+ lookups.
+
+ * attribute.cs (ApplyAttributes): Take an additional argument telling us
+ if we are processing global arguments. Hmm, I am unsure of this.
+
+2002-04-12 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * expression.cs: added static array of strings to avoid calling
+ Enum.ToString () for Operator in Binary. Significant recover of
+ performance.
+
+2002-04-10 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (FindMembers): Allow the Builders of the various
+ members to be null. If they are skip them. This only happens
+ during the PInvoke declaration.
+
+2002-04-09 Miguel de Icaza <miguel@ximian.com>
+
+ * parameter.cs (Parameters.ComputeParameterTypes): Flag the
+ failure, so we do not keep going afterwards.
+
+ * expression.cs: (Invocation.OverloadResolve): I believe Ravi
+ wanted to pass `false' as the `is_delegate' argument. If this is
+ the case, why not use delegate_type == null to mean `is_delegate =
+ false' and anything else as is_delegate = true.
+
+Tue Apr 9 05:40:12 2002 Piers Haken <piersh@friskit.com>
+
+ * statement.cs: fixed SimpleSwitchEmit to make 'goto case' goto the
+ code for the section, not the beginning of the tests.
+
+2002-04-08 Miguel de Icaza <miguel@ximian.com>
+
+ * cfold.cs: Handle operator + (Enum x, Underlying x)
+
+ * expression.cs (Binary): same. Warn about errors where we have
+ Enum/Enum in operator + as well.
+
+Mon Apr 8 06:29:03 2002 Piers Haken <piersh@friskit.com>
+
+ * statement.cs:
+ - added support for switch(bool)
+ - optimize loading of I8/U8 constants (ldc.i4, iconv_i8)
+ - add TableSwitchEmit() to handle table-based switch statements
+
+2002-04-05 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation.OverloadResolve): Factor out code which
+ does parameter compatibility checking with arguments so that we can
+ re-use the code even from Delegate.VerifyApplicability
+
+ (VerifyArgumentsCompat): Move above code here.
+
+ * delegate.cs (VerifyApplicability): Get rid of duplicate code
+ and instead make a call to the above method.
+
+2002-03-31 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (attribute_type): Corresponds to System.Attribute.
+ We use it to keep track of classes which are attribute types.
+
+2002-04-02 Miguel de Icaza <miguel@ximian.com>
+
+ * delegate.cs (Delegate.Define): Correctly define the types in the
+ presence of fixed and array parameters.
+
+ * class.cs (TypeContainers.FindMembers): Use NonPublic flag while
+ doing FindMembers.
+
+ * ecore.cs (Expression.MemberLookup): Reset binding flags to not
+ include NonPublic after the first iteration.
+
+ * class.cs (Indexer.CheckBase): Only check if both parents are
+ non-null.
+
+ * cs-parser.jay (accessor_body): If empty, set to null.
+
+ * ecore.cs (SimpleName.SimpleNameResolve): We did not have the
+ same code path here to resolve constants names that we did have in
+ MemberAccess.DoResolve. There is too much code duplicated here.
+
+2002-04-01 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs, makefile: Drop Statementcollection and just use ArrayLists
+
+ * ecore.cs: Optimize UserDefinedConversion by minimizing the calls
+ to MakeUnionSet.
+
+ * cs-tokenizer.cs: Reuse a single StringBuilder for assembling
+ tokens, numbers and strings.
+
+ * ecore.cs (MethodGroupExpr): Make Emit warn about missing
+ parenthesis.
+
+ * delegate.cs: Use ComputeAndDefineParameterTypes for both the
+ asyncronous parameters and the regular parameters.
+
+ * codegen.cs (CodeGen.Init): Use the constructor that allows us to
+ specify the target directory.
+
+ * expression.cs: (This.DoResolve): Simplify
+ (As.Emit): Optimize, do not generate IsInst if the expression is
+ always of the given type.
+
+ (Is.DoResolve): Bug fix, we were reporting both always/never for
+ the is expression.
+
+ * (Invocation.MakeUnionSet): Simplify vastly and optimize, we were
+ creating too many unnecessary arrays.
+
+2002-03-31 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (EmitFieldInitializer): Use Assign expression to assign
+ fields instead of rolling our own initializer. Takes care of all
+ implicit conversions, and drops unnecessary static checks/argument.
+
+2002-03-31 Dick Porter <dick@ximian.com>
+
+ * driver.cs: use the GetDirectories() return values properly, and
+ use "/" as path separator.
+
+2002-03-30 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Unary): Optimize - - expr into expr.
+ (Binary): Optimize a + (-b) into a -b.
+
+ * codegen.cs (CodeGen): Made all methods static.
+
+2002-03-29 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs:
+
+ * decl.cs: Rename `definition' into `TypeBuilder' and drop the
+ TypeBuilder property.
+
+ * cs-parser.jay: Drop the use of RecordXXX and use RecordDecl
+ instead.
+
+ * tree.cs: Removed the various RecordXXXX, and replaced with a
+ single RecordDecl. Removed all the accessor methods, and just
+ left a single access point Type
+
+ * enum.cs: Rename DefineEnum to DefineType.
+
+ * decl.cs: New abstract method `DefineType' used to unify the
+ Defines for Enumerations, Interfaces, TypeContainers and
+ Delegates.
+
+ (FindType): Moved LookupInterfaceOrClass here. Moved the
+ LookupBaseClasses method that used to live in class.cs and
+ interface.cs here, and renamed to FindType.
+
+ * delegate.cs: Implement DefineType. Take advantage of the
+ refactored pattern for locating the parent builder without taking
+ the parent_builder argument (which we know does not work if we are
+ nested, and triggering a toplevel definition).
+
+2002-03-28 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs (MemberCore.CheckMethodAgainstBase): Test if the
+ accessibility of a member has changed during override and report
+ an error if so.
+
+ * class.cs (Method.Define, Property.Define): Only complain on
+ overrides if the method is private, any other accessibility is
+ fine (and since we just checked the permission is the same, we are
+ good to go).
+
+ * cs-tokenizer.cs: only line, region, endregion, if, endif, else
+ and elif are processed always. The other pre-processing
+ directives are only processed if we are "taking" the path
+
+2002-03-29 Martin Baulig <martin@gnome.org>
+
+ * class.cs (Method.Emit): Only emit symbolic debugging info if the
+ current location is not Null.
+
+ * codegen.cs (CodeGen.SaveSymbols): Split out symbol writing code into
+ a separate method so we can profile it.
+
+ * driver.cs (ShowTime): We need to use `(int) span.TotalSeconds' since
+ `span.Seconds' are just seconds, but no minutes or hours.
+ (MainDriver): Profile the CodeGen.SaveSymbols calls.
+
+2002-03-28 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method.Define), (Property.Define), (Indexer.Define):
+ Remove the gratuitous set of Final:
+
+ // If an interface implementation, then we can set Final.
+ if (((flags & MethodAttributes.Abstract) == 0) &&
+ implementing.DeclaringType.IsInterface)
+ flags |= MethodAttributes.Final;
+
+ I do not know what I was smoking when I used that.
+
+
+ * cs-parser.jay, delegate.cs: Make Delegate be a DeclSpace, first
+ step into fixing the name resolution issues for delegates and
+ unifying the toplevel name resolution.
+
+2002-03-28 Martin Baulig <martin@gnome.org>
+
+ * class.cs (Method.Emit): If we have a symbol writer, call its
+ OpenMethod(), CloseMethod() and SetMethodSourceRange() methods to
+ tell it about the current method.
+
+ * codegen.cs (EmitContext.Mark): New public method. Tell the symbol
+ writer that we're going to emit the first byte of IL code for a new
+ statement (a new source line).
+ (EmitContext.EmitTopBlock): If we have a symbol writer, call
+ EmitContext.Mark() before emitting any code.
+
+ * location.cs (SymbolDocument): Return null when we're Null.
+
+ * statement.cs (Statement): Moved the `Location loc' variable here.
+ (Statement.EmitBoolExpression): If we have a symbol writer, call
+ ec.Mark() before emitting any code to tell it that we're at the
+ beginning of a new statement.
+ (StatementExpression): Added `Location' argument to the constructor.
+ (Block): Added public readonly variable `StartLocation' and public
+ variable `EndLocation'. The latter is to be set using SetEndLocation().
+ (Block): Added constructor which takes a start and end location.
+ (Block.SetEndLocation): New method. This sets the end location.
+ (Block.EmitMeta): If we have a symbol writer, tell it the names of the
+ local variables we create.
+ (Block.Emit): If we have a symbol writer, call ec.Mark() before emitting
+ each statement and do also mark the begin and end of the block.
+
+ * cs-parser.jay (block : OPEN_BRACE): Use the new `Block' constructor to
+ tell it the current lexer.Location, use Location.Null for the end of the
+ block.
+ (block : OPEN_BRACE opt_statement_list CLOSE_BRACE): When closing the
+ current block, set its end location using SetEndLocation().
+ (statement_expression): StatementExpression constructor now takes the
+ lexer.Location as additional argument.
+ (for_statement, declare_local_variables): Likewise.
+ (declare_local_variables): When creating a new implicit block, use the
+ new Block constructor and pass it the lexer.Location.
+
+2002-03-28 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (Expression.MemberLookup): On interfaces, lookup
+ members also on the parent interfaces recursively.
+
+2002-03-27 Miguel de Icaza <miguel@ximian.com>
+
+ * report.cs: Use new formats, since Gonzalo finished the missing
+ bits.
+
+ * expression.cs (Binary.ResolveOperator): added missing operator|
+ operator& and operator^ for bool/bool.
+
+ * cs-parser.jay: CheckDef now takes a Location argument that is
+ used to report errors more precisly (instead of reporting the end
+ of a definition, we try to track something which is a lot closer
+ to the source of the problem).
+
+ * cs-tokenizer.cs: Track global token use, so we can properly flag
+ the use of #define/#undef after the first token has been seen.
+
+ Also, rename the reportXXXX to Error_DescriptiveName
+
+ * decl.cs (DeclSpace.IsTopLevel): Move property here from
+ TypeContainer, so that Enum and Interface can use this too.
+
+ * class.cs (TypeContainer.LookupInterfaceOrClass,
+ GetInterfaceOrClass, GetClassBases, DefineType): Drop the
+ `builder' argument. Typically this was used to pass the parent
+ builder (a ModuleBuilder or a TypeBuilder from whoever triggered
+ the definition).
+
+ The problem is that a nested class could trigger the definition of
+ a toplevel class, and the builder would be obviously wrong in that
+ case.
+
+ So we drop this argument, and we compute dynamically the
+ TypeBuilder/ModuleBuilder (the correct information was available
+ to us anyways from DeclSpace.Parent)
+
+ * interface.cs (Interface.DefineInterface): Drop builder
+ parameter cleanup like class.cs
+
+ * enum.cs (Enum.DefineEnum): Drop builder parameter. Clean up
+ like class.cs
+
+ * statement.cs (Switch.EmitObjectInteger): Emit short/ushort
+ values.
+
+ (Try.Emit): Propagate the returns value from the statement.
+
+ (Return.Emit): Even if we are leavning
+
+ * driver.cs: Catch IOExpcetion for Directory.GetFiles as well.
+
+ * modifiers.cs: Fix the computation of MethodAttributes flags.
+
+Tue Mar 26 21:14:36 CET 2002 Paolo Molaro <lupus@ximian.com>
+
+ * driver.cs: allow compilation of files that start with '/'.
+ Add a default case when checking the argument of --target.
+
+2002-03-25 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs: Implement the same search algorithm for types in
+ the interface code.
+
+ * delegate.cs: Do not allow multiple definition.
+
+ * Recovered ChangeLog that got accidentally amputated
+
+ * interface.cs (Interface.DefineInterface): Prevent from double definitions.
+
+ * rootcontext.cs: Load manually enum to allow core classes to
+ contain enumerations.
+
+ * enum.cs, ecore.cs, driver.cs, attribute.cs, class.cs, expression.cs:
+ Update to new static methods in TypeManager.
+
+ * typemanager.cs (GetMethod, GetConstructor): Use our
+ implementation of FindMembers to find the members, since during
+ corlib compilation, the types are TypeBuilders and GetMethod and
+ GetConstructor do not work.
+
+ Make all methods in TypeManager static.
+
+ (InitCodeHelpers): Split the functionality from
+ the InitCodeTypes function.
+
+ * driver.cs: Call InitCodeHelpers after we have populated the
+ types.
+
+ * cs-parser.jay (delegate_declaration): we did not used to compute
+ the delegate name correctly for void delegates.
+
+2002-03-24 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs (RootContext): Init the interface_resolve_order
+ and type_container_resolve_order always.
+
+ (ResolveCore, BootstrapCorlib_ResolveClass,
+ BootstrapCorlib_ResolveStruct): New functions to bootstrap the
+ compiler when compiling with --nostdlib
+
+ * class.cs (TypeContainer.DefineType): Check that our parent is
+ not null. This test is most important when we are bootstraping
+ the core types.
+
+ * codegen.cs: Split out the symbol writing code.
+
+2002-03-25 Martin Baulig <martin@gnome.org>
+
+ * driver.cs (-g): Made -g an alias for --debug.
+
+2002-03-24 Martin Baulig <martin@gnome.org>
+
+ * codegen.cs (SymbolWriter): New public variable. Returns the
+ current symbol writer.
+ (CodeGen): Added `bool want_debugging_support' argument to the
+ constructor. If true, tell the ModuleBuild that we want debugging
+ support and ask it for the ISymbolWriter.
+ (Save): If we have a symbol writer, call it's Close() method after
+ saving the assembly.
+
+ * driver.c (--debug): New command line argument to create a
+ debugger information file.
+
+ * location.cs (SymbolDocument): New public property. Returns an
+ ISymbolDocumentWriter object for the current source file or null
+ if we don't have a symbol writer.
+
+2002-03-21 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (LoadAssembly): Correctly return when all the paths
+ have been tried and not before.
+
+ * statement.cs (Switch.Emit): return the actual coverage for this
+ statement (returns/not-returns)
+
+ (Switch.SimpleSwitchEmit): Do not generate jumps to the end of the
+ switch of the statement if we are the last switch section. That
+ kills two problems: try/catch problems (we used to emit an empty
+ nop at the end) and switch statements where all branches would
+ return.
+
+2002-03-19 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Add default assemblies (the equivalent to the
+ Microsoft CSC.RSP file)
+
+ * cs-tokenizer.cs: When updating `cols and setting it to zero,
+ also update tokens_seen and set it to false.
+
+ * driver.cs: Implement --recurse for Mike.
+
+ * driver.cs (SplitPathAndPattern): Small bug fix, I was not
+ correctly splitting out the paths.
+
+2002-03-18 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs (Interface.PopulateProperty): Instead of using
+ `parent' as the declaration space for the set parameters, use
+ `this'
+
+ * support.cs (InternalParameters): InternalParameters constructor
+ takes a DeclSpace instead of a TypeContainer.
+
+ * expression.cs (ArrayCreation.EmitDynamicInitializers): If value
+ types are being initialized, load the address of it before calling
+ the function.
+
+ (New): Provide a mechanism to disable the generation of local
+ value type temporaries when the caller will be providing us with
+ an address to store it.
+
+ (ArrayCreation.EmitDynamicInitializers): Use it.
+
+2002-03-17 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Invocation.EmitArguments): Only probe for array
+ property if there is more than one argument. Sorry about that.
+
+ * class.cs (Invocation.EmitArguments): Fix to emit arguments for
+ empty param arrays.
+
+ * class.cs (Method.LabelParameters): Fix incorrect code path that
+ prevented the `ParamArrayAttribute' from being applied to the
+ params attribute.
+
+2002-03-16 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs (ReflectionParameters): Correctly compute whether the
+ last argument is a params array. Fixes the problem with
+ string.Split ('a')
+
+ * typemanager.cs: Make the assemblies array always be non-null
+ (empty, but non-null)
+
+ * tree.cs (RecordDecl): New function that abstracts the recording
+ of names. This reports error 101, and provides a pointer to the
+ previous declaration. Fixes a crash in the compiler.
+
+ * cs-parser.jay (constructor_declaration): Update to new grammar,
+ and provide a constructor_body that can be empty.
+
+2002-03-15 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Add support for --resources.
+
+ * expression.cs: (FetchGetMethod, FetchAddressMethod, EmitAssign):
+ Make all types for the various array helper methods be integer.
+
+ * ecore.cs (Expression.ConvertNumericExplicit): Pass the
+ CheckState to ConvCast.
+
+ (ConvCast): Now it takes a `checked' state argument, to avoid
+ depending on the emit context for the conversion, and just using
+ the resolve time setting.
+
+ * expression.cs (ArrayCreation.EmitArrayArguments): New function,
+ instead of Invocation.EmitArguments. We do not emit the original
+ arguments, instead we emit those which have been converted to
+ unsigned int expressions.
+
+ * statement.cs (Block.EmitMeta): Drop tracking of indexes.
+
+ * codegen.cs: ditto.
+
+ * expression.cs (LocalVariableReference): Drop the use of the
+ Store function that depended on the variable index.
+
+ * statement.cs (VariableInfo): Drop the `Idx' property from this
+ class, as this is not taking into account the indexes for
+ temporaries tat we generate during the execution, getting the
+ indexes wrong.
+
+ * class.cs: First emit class initializers, then call the parent
+ constructor.
+
+ * expression.cs (Binary): Fix opcode emision.
+ (UnaryMutator.EmitCode): Support checked code generation
+
+ * ecore.cs (MemberLookup): TypeManager.FindMembers will return
+ matches for events for both the Static and Instance scans,
+ pointing to the same element. Fix that.
+
+2002-03-14 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs (ResolveTree): Always set the
+ interface_resolve_order, because nested interfaces will be calling
+ into us.
+
+ * class.cs (GetInterfaceOrClass): Track the same resolution
+ process used by TypeManager.LookupType. This fixes the nested
+ type lookups in class declarations (separate path from
+ LookupType).
+
+ (TypeContainer.DefineType): Also define nested interfaces.
+ (TypeContainer.RegisterOrder): New public function used to
+ register the order in which child interfaces need to be closed.
+
+ Nested interfaces need to be closed after their parents have been
+ created.
+
+ * interface.cs (InterfaceAttr): Put all the logic for computing
+ the interface attribute here.
+
+ (DefineInterface): Register our interface order with the
+ RootContext or with the TypeContainer depending on the case.
+
+2002-03-12 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: rework foreach statement to work with the new
+ changes to the policy on SimpleNames.
+
+ * report.cs: support Stacktrace on warnings as well.
+
+ * makefile: drop --unsafe and /unsafe from the compile.
+
+2002-03-13 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (StandardConversionExists): Modify to take an Expression
+ as the first parameter. Ensure we do null -> reference type conversion
+ checking.
+
+ * Everywhere : update calls accordingly, making use of MyEmptyExpr to store
+ temporary Expression objects.
+
+Wed Mar 13 12:32:40 CET 2002 Paolo Molaro <lupus@ximian.com>
+
+ * interface.cs: workaround bug in method overloading resolution
+ (there is already a bugzilla bug for it).
+
+2002-03-12 Miguel de Icaza <miguel@ximian.com>
+
+ We could also solve this problem by having a separate path for
+ performing type lookups, instead of DoResolve, we could have a
+ ResolveType entry point, and only participating pieces of the
+ production (simplename, deref, array) would implement this.
+
+ * codegen.cs (EmitContext): New field OnlyLookupTypes used to
+ signal SimpleName to only resolve type names and not attempt to
+ resolve anything else.
+
+ * expression.cs (Cast): Set the flag.
+
+ * ecore.cs (SimpleName): Use the OnlyLookupTypes flag
+
+ * class.cs: Only report 108 if there is no `new' modifier.
+
+ * cs-parser.jay: rework foreach statement to work with the new
+ changes to the policy on SimpleNames.
+
+ * report.cs: support Stacktrace on warnings as well.
+
+ * makefile: drop --unsafe and /unsafe from the compile.
+
+2002-03-11 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Perform local variable
+ lookups here, instead of doing that at parse time. This means
+ that our grammar will not introduce `LocalVariableReferences' as
+ expressions at this point. That solves the problem of code like
+ this:
+
+ class X {
+ static void Main ()
+ { int X = 1;
+ { X x = null }}}
+
+ This is only half the fix. The full fix requires parameters to
+ also be handled in this way.
+
+ * Everywhere: Use ec.DeclSpace on calls to LookupType, as this
+ makes the use more obvious of the DeclSpace. The
+ ec.TypeContainer.TypeBuilder is now only used to pull the
+ TypeBuilder for it.
+
+ My theory is that I can get rid of the TypeBuilder completely from
+ the EmitContext, and have typecasts where it is used (from
+ DeclSpace to where it matters).
+
+ The only pending problem is that the code that implements Aliases
+ is on TypeContainer, and probably should go in DeclSpace.
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Perform local variable
+ lookups here, instead of doing that at parse time. This means
+ that our grammar will not introduce `LocalVariableReferences' as
+ expressions at this point. That solves the problem of code like
+ this:
+
+ class X {
+ static void Main ()
+ { int X = 1;
+ { X x = null }}}
+
+ This is only half the fix. The full fix requires parameters to
+ also be handled in this way.
+
+ * class.cs (Property.DefineMethod): When implementing an interface
+ method, set newslot, when implementing an abstract method, do not
+ set the flag (before we tried never setting it, or always setting
+ it, which is the difference).
+ (Indexer.DefineMethod): same.
+ (Method.DefineMethod): same.
+
+ * ecore.cs: Only set the status used flag if we get back a Field.
+
+ * attribute.cs: Temporary hack, so Paolo can keep working.
+
+2002-03-08 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (Attribute.UnmanagedType): This is to keep track of
+ the unmanaged type in the case we have a MarshalAs attribute.
+
+ (Resolve): Handle the case when we are parsing the special MarshalAs
+ attribute [we need to store the unmanaged type to use later]
+
+ * typemanager.cs (marshal_as_attr_type): Built in type for the
+ MarshalAs Attribute.
+
+ * attribute.cs (ApplyAttributes): Recognize the MarshalAs attribute
+ on parameters and accordingly set the marshalling info.
+
+2002-03-09 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Optimizing slightly by removing redundant code after
+ we switched to the `NoTypes' return value.
+ (Property.DefineMethod): use NoTypes here too.
+
+ This fixes the bug I introduced in my last batch of changes.
+
+2002-03-05 Ravi Pratap <ravi@ximian.com>
+
+ * tree.cs (RecordEnum): Add. We now keep track of enums too.
+
+ * class.cs (LookupInterfaceOrClass): Check against the list of recorded
+ Enums since those are types too.
+
+ * cs-parser.jay (enum_declaration): Record enums as we parse them.
+
+ * enum.cs (DefineEnum): Return if the TypeBuilder has already been defined
+ thanks to a call during the lookup process.
+
+2002-03-07 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Foreach): Lots of work to accomodate a particular
+ kind of foreach statement that I had not kept in mind. It is
+ possible to have foreachs on classes that provide a GetEnumerator
+ method that return objects that implement the "pattern" for using
+ a foreach, there is no need to support GetEnumerator
+ specifically.
+
+ This is needed to compile nant.
+
+ * decl.cs: Only report 114 if the member is not `Finalize' and if
+ the warning level is at least 2.
+
+ * class.cs: Moved the compare function from Method to
+ MethodSignature.
+
+ (MethodSignature.InheritableMemberSignatureCompare): Add new
+ filter function that is used to extract inheritable methods from a
+ class.
+
+ (Method.Define): Use the new `inheritable_method_signature_filter'
+ delegate
+
+ * cs-tokenizer.cs (get_cmd_arg): Do not add white space to the
+ command.
+
+2002-03-06 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (Expression.ConvertReferenceExplicit): Removed dead code.
+
+ * cs-parser.jay: Add opt_semicolon to the interface declaration.
+
+ * expression.cs: Pass location information to
+ ConvertImplicitStandard.
+
+ * class.cs: Added debugging code to track return values from
+ interfaces.
+
+2002-03-05 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Is.DoResolve): If either side of the `is' is an
+ interface, do not flag the warning.
+
+ * ecore.cs (ImplicitReferenceConversion): We need a separate test
+ for interfaces
+
+ * report.cs: Allow for --fatal to be used with --probe.
+
+ * typemanager.cs (NoTypes): Move the definition for the empty Type
+ array here.
+
+ * class.cs (TypeContainer.FindMembers): Also look for methods defined by
+ properties.
+ (TypeContainer.DefineProxy): New function used to proxy to parent
+ implementations when implementing interfaces.
+ (TypeContainer.ParentImplements): used to lookup if our parent
+ implements a public function that is required by an interface.
+ (TypeContainer.VerifyPendingMethods): Hook this up.
+
+ * typemanager.cs (TypeManager, AddModule, AddAssembly): Make the
+ `modules' and `assemblies' arraylists into arrays. We only grow
+ these are the very early start up of the program, so this improves
+ the speedof LookupType (nicely measured).
+
+ * expression.cs (MakeByteBlob): Replaced unsafe code with
+ BitConverter, as suggested by Paolo.
+
+ * cfold.cs (ConstantFold.Binary): Special case: perform constant
+ folding of string concatenation, but if either side is a string,
+ and the other is not, then return null, and let the runtime use
+ the concatenation on the string plus the object (using
+ `Object.ToString').
+
+2002-03-04 Miguel de Icaza <miguel@ximian.com>
+
+ Constant Folding has been implemented now.
+
+ * expression.cs (Unary.Reduce): Do not throw an exception, catch
+ the error instead on types that are not supported in one's
+ complement.
+
+ * constant.cs (Constant and all children): New set of functions to
+ perform implict and explicit conversions.
+
+ * ecore.cs (EnumConstant): Implement the new functions to perform
+ conversion by proxying to the child expression.
+
+ * codegen.cs: (ConstantCheckState): Constant evaluation has its
+ own separate setting that can not be turned off from the command
+ line using --unchecked or --checked and is only controlled using
+ the checked/unchecked statements and expressions. This setting is
+ used by the constant folder to flag errors.
+
+ * expression.cs (CheckedExpr, UncheckedExpr): Set the
+ ConstantCheckState as well.
+
+ During Resolve, they also have to flag the state, because the
+ constant folder runs completely in the Resolve phase.
+
+ * statement.cs (Checked, Unchecked): Set the ConstantCheckState as
+ well.
+
+2002-03-01 Miguel de Icaza <miguel@ximian.com>
+
+ * cfold.cs: New file, this file contains the constant folder.
+
+ * ecore.cs (IMemoryLocation.AddressOf): Now takes an extra
+ argument to track whether we are using the resulting address to
+ load or store a value and provide better error messages.
+
+ (FieldExpr.Emit, FieldExpr.EmitAssign, FieldExpr.AddressOf): Use
+ new AddressOf arguments.
+
+ * statement.cs (Foreach.EmitCollectionForeach): Update
+
+ * expression.cs (Argument.Emit): Call AddressOf with proper
+ arguments to track usage.
+
+ (New.DoEmit): Call AddressOf with new arguments.
+
+ (Unary.Emit): Adjust AddressOf call.
+
+2002-03-01 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (member_access): Change the case for pre-defined types
+ to use a MemberAccess instead of a SimpleName. Thanks to Felix again for
+ this suggestion.
+
+ * class.cs (Operator::Emit): If we are abstract or extern, we don't have
+ a method body.
+
+ * attribute.cs (CheckAttribute, ApplyAttribute): Ensure that we treat operators
+ essentially like methods and apply attributes like MethodImplOptions to them too.
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Perform a check on ec.TypeContainer.TypeBuilder
+ not being null.
+
+ * codegen.cs (EmitContext): The constructor now takes in an extra argument specifying the
+ DeclSpace as the distinction is important. We provide sane defaults as usually the TypeContainer
+ is the DeclSpace.
+
+ * Update code everywhere accordingly.
+
+ * ecore.cs : Change references to ec.TypeContainer to ec.DeclSpace where appropriate.
+
+ * cs-parser.jay (enum_declaration): Set the current namespace of the enum.
+
+2002-02-28 Ravi Pratap <ravi@ximian.com>
+
+ * rootcontext.cs (LookupType): As we cycle through the chain of namespaces
+ try performing lookups against those instead of jumping straight into using
+ the 'using' clauses.
+
+ (ImplicitParent): Add. Thanks to Felix Arrese-Igor for this idea.
+
+ (LookupType): Perform lookups in implicit parents too.
+
+ * class.cs (GetInterfaceOrClass): Modify to perform the exact same lookup
+ sequence as RootContext.LookupType.
+
+ * rootcontext.cs (NamespaceLookup): Split out code from LookupType which tries
+ the various cases of namespace lookups into this method.
+
+2002-03-01 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add support for [Attribute ()] (empty arguments
+ in positional arguments)
+
+ * class.cs (Operator): Update the AllowedModifiers to contain
+ extern.
+
+ * cs-parser.jay: Update operator declaration to allow for the
+ operator body to be empty.
+
+ * cs-tokenizer.cs: Added '\u' unicode support in strings and hex
+ values.
+
+2002-02-27 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method.Emit): Label parameters.
+
+ * driver.cs: Return 1 or 0 as the program exit code.
+
+2002-02-26 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Special case the `null' object when trying to
+ auto-compute the type, as anything can be explicitly converted to
+ that.
+
+ * ecore.cs (Expression.ConvertExplicit): Bug fix, thanks for
+ spotting this Paolo.
+
+ (Expression.ImplicitNumericConversion): Perform comparissions of
+ the type using the underlying type in the case of an enumeration
+ rather than using the enumeration type for the compare.
+
+ Cope with the underlying == type case, which is not possible to
+ catch before.
+
+ (Expression.ConvertNumericExplicit): Perform comparissions of
+ the type using the underlying type in the case of an enumeration
+ rather than using the enumeration type for the compare.
+
+ * driver.cs: If the user does not supply an extension, assume .exe
+
+ * cs-parser.jay (if_statement): Rewrote so that we can track the
+ location for the if statement.
+
+ * expression.cs (Binary.ConstantFold): Only concat strings when
+ the operation is "+", not everything ;-)
+
+ * statement.cs (Statement.EmitBoolExpression): Take a location
+ argument.
+ (If, While, Do): Track location.
+
+ * expression.cs (Binary.ResolveOperator): In the object + string
+ case, I was missing a call to ConvertImplicit
+
+2002-02-25 Ravi Pratap <ravi@ximian.com>
+
+ * parameter.cs (Parameter.ExternalType): Take in extra DeclSpace and
+ Location arguments. Ensure we use RootContext.LookupType to do our work
+ and not try to do a direct Type.GetType and ModuleBuilder.GetType
+
+ * interface.cs (PopulateMethod): Handle the type of the parameter being
+ null gracefully.
+
+ * expression.cs (Invocation.BetterFunction): Handle the case when we
+ have a params method with no fixed arguments and a call is made with no
+ arguments.
+
+2002-02-25 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Add support for the quote-escape-sequence in
+ the verbatim-string-literal
+
+ * support.cs (InternalParameters.ParameterModifier): handle null
+ fixed parameters.
+ (InternalParameters.ParameterType): ditto.
+
+ * parameter.cs (VerifyArgs): Also check if the fixed parameter is
+ duplicating the name of the variable parameter.
+ (GetParameterByName): Fix bug where we were not looking up array
+ paramters if they were the only present (thanks Paolo!).
+ (GetParameterInfo): We only have an empty set of types if both
+ fixed and array are set to null.
+ (GetParameterInfo-idx): Handle FixedParameter == null
+
+ * cs-parser.jay: Handle the case where there is no catch
+ statements (missing null test).
+
+2002-02-22 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (MainDriver): Be conservative on our command line
+ handling.
+
+ Catch DirectoryNotFoundException when calling GetFiles.
+
+ (SplitPathAndPattern): Used to split the input specification into
+ a path and a pattern that we can feed to Directory.GetFiles.
+
+2002-02-21 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Fixed): Implement the last case of the Fixed
+ statement (string handling).
+
+ * expression.cs (StringPtr): New class used to return a char * to
+ a string; Used by the Fixed statement.
+
+ * typemanager.cs: Add char_ptr_type. Add get_OffsetToStringData method.
+
+ * expression.cs (Binary.ResolveOperator): Remove redundant
+ MemberLookup pn parent type.
+ Optimize union call, we do not need a union if the types are the same.
+ (Unary.ResolveOperator): REmove redundant MemberLookup on parent
+ type.
+
+ Specialize the use of MemberLookup everywhere, instead of using
+ the default settings.
+
+ (StackAlloc): Implement stackalloc keyword.
+
+ * cs-parser.jay: Add rule to parse stackalloc.
+
+ * driver.cs: Handle /h, /help, /?
+
+ * expression.cs (MakeByteBlob): Removed the hacks we had in place
+ before we supported unsafe code.
+
+ * makefile: add --unsafe to the self compilation of mcs.
+
+2002-02-20 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (PointerArithmetic): New class that is used to
+ perform pointer arithmetic.
+ (Binary.Resolve): Handle pointer arithmetic
+ Handle pointer comparission.
+ (ArrayPtr): Utility expression class that is used to take the
+ address of an array.
+
+ (ElementAccess): Implement array access for pointers
+
+ * statement.cs (Fixed): Implement fixed statement for arrays, we
+ are missing one more case before we are done.
+
+ * expression.cs (Indirection): Implement EmitAssign and set the
+ ExprClass to Variable. This allows pointer dereferences to be
+ treated as variables, and to have values assigned to them.
+
+ * ecore.cs (Expression.StoreFromPtr): New utility function to
+ store values dereferencing.
+
+2002-02-20 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Binary.ResolveOperator): Ensure that we are
+ not trying to operate on a void type - this fixes the reported
+ bug.
+
+ * decl.cs (CheckMethodAgainstBase): Do not allow overriding if
+ the parent implementation is sealed.
+
+ * ../errors/cs0239.cs : Add.
+
+ * attribute.cs (ApplyAttributes): Handle Modulebuilders too.
+
+ * typemanager.cs (unverifiable_code_type): Corresponds to
+ System.Security.UnverifiableCodeAttribute. We need to emit this for modules
+ which have unsafe code in them.
+
+ * rootcontext.cs (EmitCode): Emit the above attribute when we are in an
+ unsafe context.
+
+2002-02-19 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Add support for @"litreal strings"
+
+ Make tokenizer accept pre-processor directives
+ on any column (remove the old C-like limitation).
+
+ * rootcontext.cs (EmitCode): Emit any global attributes.
+ (AddGlobalAttributes): Used to keep track of assembly attributes.
+
+ * attribute.cs (ApplyAttributes): Support AssemblyAttributes.
+
+ * cs-parser.jay: Add support for global attributes.
+
+2002-02-17 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Indirection): New helper class. Unary will
+ create Indirection classes to be able to implement the
+ IMemoryLocation interface on it.
+
+2002-02-16 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (fixed_statement): reference the right statement.
+
+ * statement.cs (Fixed.Emit): Finish implementing the fixed
+ statement for the &x case.
+
+2002-02-14 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Property.Define, Method.Define): Remove newslot when
+ `implementing'.
+
+ * modifiers.cs: My use of NewSlot when `Abstract' was set was
+ wrong. NewSlot should only be used if the `new' keyword is present.
+
+ * driver.cs (GetSystemDir): Use CodeBase instead of FullName for
+ locating our system dir. Sorry about this.
+
+2002-02-13 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (GetSystemDir): Compute correctly the location of our
+ system assemblies. I was using the compiler directory instead of
+ the library directory.
+
+2002-02-13 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (BetterFunction): Put back in what Miguel commented out
+ since it is the correct fix. The problem is elsewhere ;-)
+
+ (IsParamsMethodApplicable): Fix bug where we were not checking that the fixed
+ parameters of the parms method are themselves compatible or not !
+
+ (StandardConversionExists): Fix very dangerous bug where we were forgetting
+ to check that a class implements an interface before saying that an implicit
+ conversion was allowed. Use ImplementsInterface to do the checking.
+
+2002-02-13 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method.Define): Track whether we are an explicit
+ implementation or not. And only call DefineMethodOverride if we
+ are an explicit implementation.
+
+ (Property.DefineMethod): Ditto.
+
+2002-02-11 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (BetterFunction): Catch hideous bug which was
+ preventing us from detecting ambiguous calls due to implicit casts i.e
+ cs0121.
+
+2002-01-29 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs (Pair): Remove un-needed method. I figured why I was
+ getting the error in cs-parser.jay, the variable in a foreach loop
+ is readonly, and the compiler does not really treat this as a variable.
+
+ * cs-parser.jay (fixed_statement): Fix grammar. Use ASSIGN
+ instead of EQUALS in grammar.
+
+ * typemanager.cs (VerifyUnmanaged): Report correct error (208)
+
+ * expression.cs (Unary.DoResolve): Check whether the argument is
+ managed or not.
+
+2002-01-28 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs: Api for Pair to set a value. Despite the fact that
+ the variables are public the MS C# compiler refuses to compile
+ code that accesses the field if the variable is part of a foreach
+ statement.
+
+ * statement.cs (Fixed): Begin implementation of the fixed
+ statement.
+
+ (Block.AddVariable): Return the VariableInfo on success and null
+ on failure instead of true/false.
+
+ * cs-parser.jay (foreach): Catch errors on variables already
+ defined (we were ignoring this value before) and properly unwind
+ the block hierarchy
+
+ (fixed_statement): grammar for the fixed statement.
+
+2002-01-25 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (UnaryMutator.IsIncrementableNumber): Allow also
+ pointer types to be incretemented.
+
+ (SizeOf): Implement.
+
+ * cs-parser.jay (pointer_member_access): Implement
+ expr->IDENTIFIER production.
+
+ * expression.cs (IndexerAccess.DoResolve, ArrayAccess.DoResolve,
+ MemberAccess.DoResolve, Invocation.DoResolve): Check for pointers
+ on safe contexts.
+
+ (Unary): Implement indirection.
+
+ * ecore.cs (Expression.UnsafeError): Reports error 214 (pointer
+ use in non-unsafe context).
+
+ (SimpleName.DoResolve): Check for pointers in field access on safe
+ contexts.
+
+ (Expression.LoadFromPtr): Factor the load-indirect code in this
+ function. This was duplicated in UnboxCast and ParameterReference
+
+2002-01-24 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ComposedCast): report an error if a pointer cast
+ is used in a safe region.
+
+ * ecore.cs (Expression.ConvertExplicit): Add rules for implicit
+ pointer type casts in unsafe context.
+
+ * codegen.cs (EmitContext): Set up IsUnsafe.
+
+ * cs-parser.jay (non_expression_type): Add productions for pointer
+ casts.
+
+ * expression.cs (Invocation.EmitCall): Remove chunk of buggy
+ code. We should not use force into static mode if the method is
+ not virtual. Fixes bug in MIS
+
+ * statement.cs (Do.Emit, While.Emit, For.Emit,
+ Statement.EmitBoolExpression): Add support to Do and While to
+ propagate infinite loop as `I do return' semantics.
+
+ Improve the For case to also test for boolean constants.
+
+ * attribute.cs (Attribute.ApplyAttributes): Add ParameterBuilder
+ to the list of attributes we can add.
+
+ Remove `EmitContext' argument.
+
+ * class.cs (Method.Define): Apply parameter attributes.
+ (Constructor.Define): Apply parameter attributes.
+ (MethodCore.LabelParameters): Move here the core of labeling
+ parameters.
+
+ * support.cs (ReflectionParameters.ParameterModifier,
+ InternalParameters.ParameterModifier): Use IsByRef on the type and
+ only return the OUT bit for these parameters instead of in/out/ref
+ flags.
+
+ This is because I miss-understood things. The ParameterInfo.IsIn
+ and IsOut represent whether the parameter has the [In] and [Out]
+ attributes set.
+
+2002-01-22 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr.Emit): Release temporaries.
+
+ * assign.cs (LocalTemporary.Release): new function.
+
+ * codegen.cs (EmitContext.GetTemporaryStorage,
+ EmitContext.FreeTemporaryStorage): Rework the way we deal with
+ temporary storage. Now we can "put back" localbuilders when we
+ are done with them
+
+2002-01-21 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (FieldExpr.Emit): Handle initonly fields specially: we
+ need to make a copy of the variable to generate verifiable code.
+
+2002-01-19 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Compute dynamically the system directory.
+
+ * ecore.cs (CopyNewMethods): reworked, exposed, made public.
+ Slower, but more generally useful. Used by the abstract
+ registering implementation.
+
+ * expression.cs (ResolveMemberAccess): Reorder the way we evaluate
+ the rules for the special rule on Type/instances. First check if
+ we have the same name, and if so, try that special static path
+ rather than the instance path.
+
+2002-01-18 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Emit 642 (warning: possible empty statement) for
+ for, while and if.
+
+ * class.cs (TypeBuilder.DefineType): Do not allow inheritance from
+ Enum, ValueType, Delegate or Array for non-corlib compiles.
+
+ * cs-tokenizer.cs: Catch long identifiers (645)
+
+ * typemanager.cs (IndexerPropetyName): Ravi never tested this
+ piece of code.
+
+ * class.cs (TypeContainer.RegisterRequiredImplementations): Bug
+ fix, we were returning too early, so we were not registering
+ pending methods from abstract classes.
+
+ Do not register pending methods if the class is abstract.
+
+ * expression.cs (Conditional.DoResolve): Report circular implicit
+ conversions when we neecd to compute it for conditional
+ expressions.
+
+ (Is.DoResolve): If the expression is always of the provided type,
+ flag warning 183. If the expression can not ever be of the
+ provided type flag warning 184.
+
+ * class.cs: Catch 169 as well.
+
+ * ecore.cs (FieldExpr): For now in AddressOf mark as assigned and
+ read.
+
+2002-01-18 Nick Drochak <ndrochak@gol.com>
+
+ * makefile: remove path to beta2 csc.exe. path to csc.exe must be in PATH instead.
+
+2002-01-17 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs: (PopulateMethod): Check for pointers being defined
+ only if the unsafe context is active.
+ (PopulateProperty): ditto.
+ (PopulateIndexer): ditto.
+
+ * class.cs (Method, Method.Define): Allow `unsafe' modifier to be
+ specified. If pointers are present, make sure that they are
+ present in an unsafe context.
+ (Constructor, Constructor.Define): ditto.
+ (Field, Field.Define): ditto.
+ (Property, Property.Define): ditto.
+ (Event, Event.Define): ditto.
+
+ * interface.cs (Interface.GetInterfaceTypeByName): Only lookup the
+ hashtable if there are classes or structs defined.
+
+ * expression.cs (LocalVariableReference.DoResolve): Simplify this
+ code, as the constant resolution moved.
+
+ * statement.cs (Block.EmitMeta): Resolve all constants as we emit
+ the metadata, so we can flag error 133.
+
+ * decl.cs (MemberCore.UnsafeOK): New function to test that a
+ pointer is being declared in an unsafe context.
+
+2002-01-16 Miguel de Icaza <miguel@ximian.com>
+
+ * modifiers.cs (Modifiers.Check): Require a Location argument.
+ Report error 227 for Unsafe use.
+
+ * typemanager.cs: Remove IsPointerType, we should be using Type.IsPointer
+
+ * statement.cs (For.Emit): If the test is null, then report that
+ we do `return', as we wont reach anything afterwards.
+
+ (Switch.SwitchGoverningType): Track the expression that matched
+ the conversion.
+
+ * driver.cs: Allow negative numbers as an error code to flag.
+
+ * cs-parser.jay: Handle 1551.
+
+ * namespace.cs: Add 1537 checking (repeated using alias namespaces).
+
+2002-01-15 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Report 1518 (type declaration can only contain
+ class, struct, interface, enum or delegate)
+
+ (switch_label): Report 1523 (keywords `case' or `default' must
+ preced code)
+
+ (opt_switch_sections): Report 1522 (empty switch)
+
+ * driver.cs: Report 1515 (response file specified multiple times)
+ Report 1516 (Source file specified multiple times).
+
+ * expression.cs (Argument.Resolve): Signal 1510
+
+ (BaseAccess.Resolve, BaseIndexer.Resolve): Signal 1511 (base
+ access not allowed in static code)
+
+2002-01-11 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (IsPointerType): Utility method which we are going
+ to need a lot.
+
+ * ecore.cs (ImplicitReferenceConversion): A pointer type cannot be cast to
+ the object type, so we take care of that.
+
+ * expression.cs (FullMethodDesc): Also include the return type in descriptions.
+
+ * support.cs (ParameterDesc): Fix minor bug which was causing params tags to be
+ added to non-params parameters :-)
+
+ * typemanager.cs (CSharpName): Include 'void' type too.
+
+ (void_ptr_type): Include in the set of core types.
+
+ * ecore.cs (ConvertImplicit): Make use of ConvertImplicitStandard instead of
+ duplicating code.
+
+ (ConvertImplicitStandard): Handle standard implicit pointer conversions when we have
+ an unsafe context.
+
+ * cs-parser.jay (local_variable_pointer_type): Add support for 'void *' as I had
+ completely forgotten about it.
+
+2002-01-10 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (pointer_type): Add. This begins our implementation
+ of parsing rules for unsafe code.
+
+ (unsafe_statement): Implement.
+
+ (embedded_statement): Modify to include the above.
+
+ * statement.cs (Unsafe): Implement new class for unsafe blocks.
+
+ * codegen.cs (EmitContext.InUnsafe): Add. This determines
+ if the current context is an unsafe one.
+
+ * cs-parser.jay (local_variable_pointer_type): Since local variable types
+ are handled differently, we need separate rules for them.
+
+ (local_variable_declaration): Update to use local_variable_pointer_type
+ to allow variable declarations of unmanaged pointer types.
+
+ * expression.cs (Unary.ResolveOperator): Ensure that the '&' operator is used only
+ in unsafe contexts.
+
+ * ../errors/cs0214.cs : Add.
+
+2002-01-16 Nick Drochak <ndrochak@gol.com>
+
+ * makefile: remove 'response' file when cleaning.
+
+2002-01-15 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Report 1524.
+
+2002-01-14 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (RegisterMethod): drop checking if we have
+ registered this from here
+
+2002-01-12 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method.EmitDestructor): Implement calling our base
+ destructor.
+
+ * statement.cs (Try.Emit): Fix to reset the InFinally to the old
+ value of InFinally.
+
+ * codegen.cs (EmitContext.EmitTopBlock): Destructors will call
+ this routine and will wrap the call in a try/catch block. Deal
+ with the case.
+
+2002-01-11 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (Expression.MemberLookup): instead of taking a
+ parameter `same_type' that was used to tell whether we could
+ access private members we compute our containing type from the
+ EmitContext.
+
+ (FieldExpr): Added partial support for volatile fields. This does
+ not work for volatile fields exposed from assemblies, as I can not
+ figure out how to extract the modreq from it.
+
+ Updated all the source files to use this.
+
+ * codegen.cs (EmitContext): Compute ContainerType ahead of time,
+ because it is referenced by MemberLookup very often.
+
+2002-01-09 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (IndexerPropertyName): If we have a TypeBuilder, use
+ TypeBuilder.GetCustomAttributes to retrieve what we need.
+
+ Get rid of redundant default_member_attr_type as this is the same as
+ default_member_type which already exists.
+
+ * interface.cs, attribute.cs : Update accordingly.
+
+2002-01-08 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: Enable IndexerPropertyName again. It does not
+ work for TYpeBuilders though. Ravi, can you please fix this?
+
+ * cs-tokenizer.cs: Accept _ as a name in pp-expressions.
+
+ * expression.cs (Argument.Emit): Handle the case of ref objects
+ being passed to ref functions;
+
+ (ParameterReference.EmitLoad): Loads the content of the pointer
+ without dereferencing.
+
+2002-01-07 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Implemented the pre-processing expressions.
+
+2002-01-08 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Indexer.DefineMethod): Incorporate the interface
+ type in the name of the method if we are doing explicit interface
+ implementation.
+
+ * expression.cs (ConversionExists): Remove as it is completely obsolete.
+
+ (BetterConversion): Fix extremely trivial bug where we were referring to
+ ConversionExists instead of StandardConversionExists ! Hooray, things are fine
+ again !
+
+ * ../errors/bug16.cs : Add although we have fixed it.
+
+2002-01-07 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (BaseIndexer): Begin implementation.
+
+ * class.cs (TypeContainer.IsInterfaceMethod): Bug fix.
+
+ * cs-parser.jay (indexer_declarator): Use qualified_identifier
+ production directly to remove a shift/reduce, and implement
+ explicit interface implementation.
+
+ * cs-tokenizer.cs: Fix tokenizer, it was consuming one extra char
+ after a floating point suffix.
+
+ * expression.cs (DoNumericPromotions): Improved the conversion for
+ uint/uint. If we have a constant, we avoid doing a typecast to a
+ larger type.
+
+ * class.cs (Indexer): Implement explicit interface implementation
+ for indexers.
+
+Sat Jan 5 16:08:23 CET 2002 Paolo Molaro <lupus@ximian.com>
+
+ * class.cs: make the default instance constructor public and hidebysig.
+
+2001-01-03 Ravi Pratap <ravi@ximian.com>
+
+ * interface.cs (EmitDefaultMemberAttr): Make this helper method static
+ so we can call it from elsewhere.
+
+ * class.cs (TypeContainer.Emit): Emit the attribute here too. The rule is that
+ we emit it internally if the class has a defined indexer; otherwise the user
+ emits it by decorating the class definition with the DefaultMemberAttribute.
+
+ * attribute.cs (ApplyAttributes): Perform checks to see that the DefaultMember
+ attribute is not used on a type which defines an indexer.
+
+ * cs-tokenizer.cs (get_cmd_arg): Ensure we trim whitespace and also include the tab
+ character when we skip whitespace.
+
+ * ../errors/cs0646.cs : Add.
+
+2002-01-03 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (SimpleName.ResolveSimpleName): Report error 120
+ again.
+
+ * makefile: Add practical target `mcs3.exe' which builds the third
+ generation compiler.
+
+ * expression.cs (New): Fix structures constructor calling.
+
+ * class.cs (Property, Method, Indexer): Emit Final flag on the
+ method if we are an interface implementation and we are not
+ abstract.
+
+ * ecore.cs (PropertyExpr): New public field `IsBase', tells
+ whether this property is referencing a `base' method.
+
+ * expression.cs (Invocation.EmitCall): take an extra argument:
+ is_base, this is used to determine whether the `call' or
+ `callvirt' opcode should be used.
+
+
+ * delegate.cs: update EmitCall.
+
+ * class.cs (Method.Define): Set NewSlot for the cases where we are
+ not implementing an interface method.
+
+ (Property.Define): ditto.
+
+2002-01-02 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: (Tokenizer.escape): Escape '\r' as '\r' not as
+ 'r'. Allows mcs to parse itself fully.
+
+2002-01-02 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation.num_automatic_initializers): Keep track
+ of the number of initializers that require the InitializeArray method.
+
+ (CheckIndices): Store the Expression in all cases - not the plain value. Also
+ update the above field where necessary.
+
+ (MakeByteBlob): Update accordingly.
+
+ (DoEmit): Call EmitStaticInitializers only if the number of initializers is
+ greater than 2.
+
+ (EmitDynamicInitializers): Update in accordance with the new optimization.
+
+ (ArrayAccess.EmitStoreOpcode): Include char type along with short and ushort - the
+ same OpCode applies.
+
+ * cs-parser.jay : Fix some glaring errors I introduced.
+
+2002-01-01 Ravi Pratap <ravi@ximian.com>
+
+ * parameters.cs (AddVariable, AddConstant): Pass in current_local_parameters
+ so that we can check for name clashes there too.
+
+ * typemanager.cs (default_member_attr_type): The attribute that we need to emit
+ for interface indexers.
+
+ * interfaces.cs (Define): Emit the default member attribute.
+
+ * expression.cs (MakeByteBlob): Fix extremely trivial bug where the wrong
+ variable was being referred to while setting the value ;-)
+
+2002-01-01 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MakeByteBlob): Optimize: we do not need to fill
+ byte-by-byte information when we know the data is zero.
+
+ Make the block always a multiple of 4, because
+ DefineInitializedData has a bug.
+
+ * assign.cs: Fix, we should assign from the temporary, not from
+ the source.
+
+ * expression.cs (MakeByteBlob): Fix my incorrect code.
+
+2001-12-31 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (EnumToUnderlying): This function is used to get
+ the underlying type from an enumeration, because it does not
+ always work.
+
+ * constant.cs: Use the I4_S form for values between -128 and 127.
+
+ * statement.cs (Block.LookupLabel): Looks up a label.
+ (Block): Drop support for labeled blocks.
+
+ (LabeledStatement): New kind of statement that represents a label
+ only.
+
+ (Goto): Finally implement this bad boy.
+
+ * cs-parser.jay: Update to reflect new mechanism to implement
+ labels.
+
+2001-12-30 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs (EmitContext.This): a codegen property that keeps the
+ a single instance of this instead of creating many different this
+ instances.
+
+ * delegate.cs (Delegate.DoResolve): Update to use the property;
+
+ * ecore.cs (SimpleName.SimpleNameResolve): Ditto
+
+ * expression.cs (BaseAccess.DoResolve): Ditto.
+
+2001-12-29 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (methodimpl_attr_type): Add to hold the type
+ corresponding to System.Runtime.CompilerServices.MethodImplAttribute.
+
+ (InitCoreTypes): Update accordingly.
+
+ * attribute.cs (Resolve): Remember if the attribute is a MethodImplAttribute
+ so we can quickly store the state.
+
+ (ApplyAttributes): Set the correct implementation flags
+ for InternalCall methods.
+
+2001-12-29 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (EmitCall): if a method is not virtual, then do
+ not use callvirt on it.
+
+ (ArrayAccess.EmitAssign): storing non-builtin value types (ie,
+ user defined stuff) requires the use of stobj, which takes an
+ address on the stack instead of an array and an index. So emit
+ the Ldelema operation for it.
+
+ (EmitStoreOpcode): Use stobj for valuetypes.
+
+ (UnaryMutator.EmitCode): Use the right 1 value depending on
+ whether we are dealing with int64/uint64, float or doubles.
+
+ * class.cs (TypeContainer.AddConstructor): Fix the logic to define
+ constructors that I implemented last night.
+
+ (Constructor.IsDefault): Fix to work properly for static
+ constructors.
+
+ * cs-parser.jay (CheckDef): report method signature errors.
+ Update error number 103 to be 132.
+
+ * decl.cs: New AdditionResult enumeration value: MethodExists.
+ Although we do this check for methods later on in the semantic
+ analysis, catching repeated default constructors is so easy that
+ we catch these here.
+
+ * expression.cs (Binary.DoNumericPromotions): Fix the uint64 type
+ promotions code.
+
+ (ParameterReference.EmitAssign, Emit): handle
+ bools as bytes.
+
+ (ArrayAccess.EmitLoadOpcode): Handle bool type here.
+ (ArrayAccess.EmitStoreOpcode): ditto.
+
+ * cs-tokenizer.cs (is_punct): Eliminated empty computation.
+
+ * expression.cs (MakeByteBlob): Complete all the missing types
+ (uint, short, ushort, byte, sbyte)
+
+ * class.cs: Only init instance field initializers on instance
+ constructors.
+
+ Rename `constructors' to instance_constructors.
+
+ (TypeContainer.AddConstructor): Only add constructors to the list
+ if it is not static.
+
+ Make sure that we handle default_static_constructor independently
+ everywhere where we handle instance_constructors
+
+2001-12-28 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs: Do not lookup or create a base initializer for a
+ static constructor.
+
+ (ConstructorInitializer.Resolve): use the proper type to lookup
+ for constructors.
+
+ * cs-parser.jay: Report error 1585 (modifiers between type and name).
+
+ * enum.cs, interface.cs: Remove CloseType, this is taken care by
+ in DeclSpace.
+
+ * decl.cs: CloseType is now an virtual method, the default
+ implementation just closes this type.
+
+2001-12-28 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (DefinePInvokeMethod): Set the implementation flags
+ to PreserveSig by default. Also emit HideBySig on such methods.
+
+ Basically, set the defaults to standard values.
+
+ * expression.cs (Invocation.BetterFunction): We need to make sure that for each
+ argument, if candidate is better, it can't be worse than the best !
+
+ (Invocation): Re-write bits to differentiate between methods being
+ applicable in their expanded form and their normal form - for params
+ methods of course.
+
+ Get rid of use_standard everywhere as only standard conversions are allowed
+ in overload resolution.
+
+ More spec conformance.
+
+2001-12-27 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Add --timestamp, to see where the compiler spends
+ most of its time.
+
+ * ecore.cs (SimpleName.DoResolve): Do not create an implicit
+ `this' in static code.
+
+ (SimpleName.DoResolve): Implement in terms of a helper function
+ that allows static-references to be passed upstream to
+ MemberAccess.
+
+ (Expression.ResolveWithSimpleName): Resolve specially simple
+ names when called by MemberAccess to implement the special
+ semantics.
+
+ (Expression.ImplicitReferenceConversion): Handle conversions from
+ Null to reference types before others, as Null's type is
+ System.Object.
+
+ * expression.cs (Invocation.EmitCall): Handle the special case of
+ calling methods declared on a reference type from a ValueType
+ (Base classes System.Object and System.Enum)
+
+ (MemberAccess.Resolve): Only perform lookups on Enumerations if
+ the left hand side is a TypeExpr, not on every enumeration.
+
+ (Binary.Resolve): If types are reference types, then do a cast to
+ object on operators != and == of both arguments.
+
+ * typemanager.cs (FindMembers): Extract instance and static
+ members if requested.
+
+ * interface.cs (PopulateProperty): Use void_type instead of null
+ as the return type for the setter method.
+
+ (PopulateIndexer): ditto.
+
+2001-12-27 Ravi Pratap <ravi@ximian.com>
+
+ * support.cs (ReflectionParameters): Fix minor bug where we
+ were examining the wrong parameter for the ParamArray attribute.
+
+ Cope with requests for the type of the parameter at position
+ greater than the params parameter's. We now return the element
+ type of the params array as that makes more sense.
+
+ * expression.cs (Invocation.IsParamsMethodApplicable): Update
+ accordingly as we no longer have to extract the element type
+ ourselves.
+
+ (Invocation.OverloadResolve): Update.
+
+2001-12-27 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Foreach.GetEnumeratorFilter): Do not compare
+ against IEnumerator, test whether the return value is a descendant
+ of the IEnumerator interface.
+
+ * class.cs (Indexer.Define): Use an auxiliary method to implement
+ the other bits of the method definition. Begin support for
+ explicit interface implementation.
+
+ (Property.DefineMethod): Use TypeManager.void_type instead of null
+ for an empty return value.
+
+2001-12-26 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): if we are
+ dealing with a FieldExpr which is composed of a FieldBuilder, in
+ the code path we did extract the constant, but we should have
+ obtained the underlying value to be able to cast it (otherwise we
+ end up in an infinite loop, this is what Ravi was running into).
+
+ (ArrayCreation.UpdateIndices): Arrays might be empty.
+
+ (MemberAccess.ResolveMemberAccess): Add support for section
+ 14.5.4.1 that deals with the special case of E.I when E is a type
+ and something else, that I can be a reference to a static member.
+
+ (ArrayCreation.MakeByteBlob): It is not an error to not be able to
+ handle a particular array type to create byte blobs, it is just
+ something we dont generate byteblobs for.
+
+ * cs-tokenizer.cs (get_cmd_arg): Ignore \r in commands and
+ arguments.
+
+ * location.cs (Push): remove the key from the hashtable that we
+ are about to add. This happens for empty files.
+
+ * driver.cs: Dispose files after we have parsed them.
+
+ (tokenize): new function that only runs the tokenizer on its
+ input, for speed testing.
+
+2001-12-26 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Event.Define): Define the private field only if there
+ are no accessors defined.
+
+ * expression.cs (ResolveMemberAccess): If there is no associated
+ field with the event, that means we have an event defined with its
+ own accessors and we should flag error cs0070 since transforming
+ ourselves into a field is not valid in that case.
+
+ * ecore.cs (SimpleName.DoResolve): Same as above.
+
+ * attribute.cs (DefinePInvokeMethod): Set the default calling convention
+ and charset to sane values.
+
+2001-12-25 Ravi Pratap <ravi@ximian.com>
+
+ * assign.cs (DoResolve): Perform check on events only if they
+ are being accessed outside the declaring type.
+
+ * cs-parser.jay (event_declarations): Update rules to correctly
+ set the type of the implicit parameter etc.
+
+ (add_accessor, remove_accessor): Set current local parameters.
+
+ * expression.cs (Binary): For delegate addition and subtraction,
+ cast the return value from the method into the appropriate delegate
+ type.
+
+2001-12-24 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (RegisterDelegateData, GetDelegateData): Get rid
+ of these as the workaround is unnecessary.
+
+ * delegate.cs (NewDelegate.DoResolve): Get rid of bits which registered
+ delegate data - none of that is needed at all.
+
+ Re-write bits to extract the instance expression and the delegate method
+ correctly.
+
+ * expression.cs (Binary.ResolveOperator): Handle the '-' binary operator
+ on delegates too.
+
+ * attribute.cs (ApplyAttributes): New method to take care of common tasks
+ of attaching attributes instead of duplicating code everywhere.
+
+ * everywhere : Update code to do attribute emission using the above method.
+
+2001-12-23 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (IsParamsMethodApplicable): if there are not
+ parameters, return immediately.
+
+ * ecore.cs: The 0 literal can be implicity converted to an enum
+ type.
+
+ (SimpleName.DoResolve): First lookup the type, then lookup the
+ members.
+
+ (FieldExpr.Emit): If the InstanceExpression is a ValueType, we
+ want to get its address. If the InstanceExpression is not
+ addressable, store the result in a temporary variable, then get
+ the address of it.
+
+ * codegen.cs: Only display 219 errors on warning level or above.
+
+ * expression.cs (ArrayAccess): Make it implement the
+ IMemoryLocation interface.
+
+ (Binary.DoResolve): handle the operator == (object a, object b)
+ and operator != (object a, object b) without incurring into a
+ BoxedCast (because 5 != o should never be performed).
+
+ Handle binary enumerator operators.
+
+ (EmitLoadOpcode): Use Ldelema if the object we are loading is a
+ value type, otherwise use Ldelem_ref.
+
+ Use precomputed names;
+
+ (AddressOf): Implement address of
+
+ * cs-parser.jay (labeled_statement): Fix recursive block
+ addition by reworking the production.
+
+ * expression.cs (New.DoEmit): New has a special case:
+
+ If we are dealing with a ValueType, we have a few
+ situations to deal with:
+
+ * The target of New is a ValueType variable, that is
+ easy, we just pass this as the variable reference
+
+ * The target of New is being passed as an argument,
+ to a boxing operation or a function that takes a
+ ValueType.
+
+ In this case, we need to create a temporary variable
+ that is the argument of New.
+
+
+2001-12-23 Ravi Pratap <ravi@ximian.com>
+
+ * rootcontext.cs (LookupType): Check that current_type is not null before
+ going about looking at nested types.
+
+ * ecore.cs (EventExpr.EmitAddOrRemove): Rename from EmitAssign as we do
+ not implement the IAssignMethod interface any more.
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): Handle EventExprs specially
+ where we tranform them into FieldExprs if they are being resolved from within
+ the declaring type.
+
+ * ecore.cs (SimpleName.DoResolve): Do the same here.
+
+ * assign.cs (DoResolve, Emit): Clean up code considerably.
+
+ * ../errors/bug10.cs : Add.
+
+ * ../errors/cs0070.cs : Add.
+
+ * typemanager.cs : Use PtrHashtable for Delegate data hashtable etc.
+
+ * assign.cs : Get rid of EventIsLocal everywhere.
+
+2001-12-23 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (ConvertIntLiteral): finished the implementation.
+
+ * statement.cs (SwitchLabel): Convert the value we are using as a
+ key before looking up the table.
+
+2001-12-22 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs (EmitTopBlock): Require a Location argument now.
+
+ * cs-parser.jay (constructor_declarator): We need to setup
+ current_local_parameters before we parse the
+ opt_constructor_initializer, to allow the variables to be bound
+ to the constructor arguments.
+
+ * rootcontext.cs (LookupType): First lookup nested classes in our
+ class and our parents before we go looking outside our class.
+
+ * expression.cs (ConstantFold): Extract/debox the values at the
+ beginnning.
+
+ * rootcontext.cs (EmitCode): Resolve the constants first before we
+ resolve the types. This is not really needed, but it helps debugging.
+
+ * statement.cs: report location.
+
+ * cs-parser.jay: pass location to throw statement.
+
+ * driver.cs: Small bug fix.
+
+ * report.cs: Updated format to be 4-zero filled digits.
+
+2001-12-22 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (CheckIndices): Fix minor bug where the wrong
+ variable was being referred to ;-)
+
+ (DoEmit): Do not call EmitStaticInitializers when the
+ underlying type is System.Object.
+
+2001-12-21 Ravi Pratap <ravi@ximian.com>
+
+ * ecore.cs (EventExpr.Resolve): Implement to correctly set the type
+ and do the usual workaround for SRE.
+
+ * class.cs (MyEventBuilder.EventType): New member to get at the type
+ of the event, quickly.
+
+ * expression.cs (Binary.ResolveOperator): Handle delegate addition.
+
+ * assign.cs (Assign.DoResolve): Handle the case when the target
+ is an EventExpr and perform the necessary checks.
+
+ * ecore.cs (EventExpr.EmitAssign): Implement the IAssignMethod
+ interface.
+
+ (SimpleName.MemberStaticCheck): Include check for EventExpr.
+
+ (EventExpr): Set the type in the constructor itself since we
+ are meant to be born fully resolved.
+
+ (EventExpr.Define): Revert code I wrote earlier.
+
+ * delegate.cs (NewDelegate.Resolve): Handle the case when the MethodGroup's
+ instance expression is null. The instance expression is a This in that case
+ or a null, depending on whether it is a static method or not.
+
+ Also flag an error if the reference to a method is ambiguous i.e the MethodGroupExpr
+ refers to more than one method.
+
+ * assign.cs (DoResolve): Check whether the event belongs to the same Type container
+ and accordingly flag errors.
+
+2001-12-21 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Throw.Emit): Add support for re-throwing exceptions.
+
+2001-12-22 Miguel de Icaza <miguel@ximian.com>
+
+ * location.cs (ToString): Provide useful rutine.
+
+2001-12-21 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (Expression.ConvertIntLiteral): Do not return Constant
+ objects, return the actual integral boxed.
+
+ * statement.cs (SwitchLabel): define an ILLabel for each
+ SwitchLabel.
+
+ (Switch.CheckSwitch): If the value is a Literal, extract
+ the underlying literal.
+
+ Also in the unused hashtable we had, add the SwitchLabel so we can
+ quickly look this value up.
+
+ * constant.cs: Implement a bunch of new constants. Rewrite
+ Literal based on this. Made changes everywhere to adapt to this.
+
+ * expression.cs (Expression.MakeByteBlob): Optimize routine by
+ dereferencing array only once, and also copes with enumrations.
+
+ bytes are two bytes wide, not one.
+
+ (Cast): Perform constant conversions.
+
+ * ecore.cs (TryImplicitIntConversion): Return literals instead of
+ wrappers to the literals here.
+
+ * expression.cs (DoNumericPromotions): long literals can converted
+ to ulong implicity (this is taken care of elsewhere, but I was
+ missing this spot).
+
+ * ecore.cs (Expression.Literalize): Make the return type Literal,
+ to improve type checking.
+
+ * rootcontext.cs: Lookup for nested classes in our class hierarchy.
+
+2001-12-20 Miguel de Icaza <miguel@ximian.com>
+
+ * literal.cs: Revert code from ravi that checked the bounds. The
+ bounds are sane by the definition of the type itself.
+
+ * typemanager.cs: Fix implementation of ImplementsInterface. We
+ need to actually look up in our parent hierarchy for interfaces
+ implemented.
+
+ * const.cs: Use the underlying type for enumerations
+
+ * delegate.cs: Compute the basename for the delegate creation,
+ that should fix the delegate test case, and restore the correct
+ Type Lookup semantics in rootcontext
+
+ * rootcontext.cs: Revert Ravi's last patch. The correct way of
+ referencing a nested type with the Reflection API is using the "+"
+ sign.
+
+ * cs-parser.jay: Do not require EOF token at the end.
+
+2001-12-20 Ravi Pratap <ravi@ximian.com>
+
+ * rootcontext.cs (LookupType): Concatenate type names with
+ a '.' instead of a '+' The test suite passes again.
+
+ * enum.cs (Enum.DefineEnum): Set RTSpecialName on the 'value__'
+ field of the enumeration.
+
+ * expression.cs (MemberAccess.ResolveMemberAccess): Add support for
+ the case when the member is an EventExpr.
+
+ * ecore.cs (EventExpr.InstanceExpression): Every event which is not
+ static has an associated instance expression.
+
+ * typemanager.cs (RegisterEvent): The usual workaround, now for events.
+
+ (GetAddMethod, GetRemoveMethod): Workarounds, as usual.
+
+ * class.cs (Event.Define): Register event and perform appropriate checks
+ for error #111.
+
+ We define the Add and Remove methods even if the use provides none because
+ in that case, we provide default implementations ourselves.
+
+ Define a private field of the type of the event. This is done by the CSC compiler
+ and we should be doing it too ;-)
+
+ * typemanager.cs (delegate_combine_delegate_delegate, delegate_remove_delegate_delegate):
+ More methods we use in code we generate.
+
+ (multicast_delegate_type, delegate_type): Two separate types since the distinction
+ is important.
+
+ (InitCoreTypes): Update accordingly for the above.
+
+ * class.cs (Event.Emit): Generate code for default accessors that we provide
+
+ (EmitDefaultMethod): Do the job in the above.
+
+ * delegate.cs (DefineDelegate): Use TypeManager.multicast_delegate_type in the
+ appropriate place.
+
+2001-12-20 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Indexer.Define): Fix bug, we were setting both Get/Set
+ builders even if we were missing one.
+
+ * interface.cs, class.cs, enum.cs: When calling DefineNestedType
+ pass the Basename as our class name instead of the Name. The
+ basename will be correctly composed for us.
+
+ * parameter.cs (Paramters): Now takes a Location argument.
+
+ * decl.cs (DeclSpace.LookupType): Removed convenience function and
+ make all the code call directly LookupType in RootContext and take
+ this chance to pass the Location information everywhere.
+
+ * Everywhere: pass Location information.
+
+2001-12-19 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Constructor.Define): Updated way of detecting the
+ length of the parameters.
+
+ (TypeContainer.DefineType): Use basename as the type name for
+ nested types.
+
+ (TypeContainer.Define): Do not recursively define types here, as
+ definition is taken care in order by the RootContext.
+
+ * tree.cs: Keep track of namespaces in a per-file basis.
+
+ * parameter.cs (Parameter.ComputeSignature): Update to use
+ DeclSpace.
+
+ (Parameters.GetSignature): ditto.
+
+ * interface.cs (InterfaceMethod.GetSignature): Take a DeclSpace
+ instead of a TypeContainer.
+
+ (Interface.SemanticAnalysis): Use `this' instead of our parent to
+ resolve names. Because we need to be resolve in our context, not
+ our parents.
+
+ * driver.cs: Implement response files.
+
+ * class.cs (TypeContainer.DefineType): If we are defined, do not
+ redefine ourselves.
+
+ (Event.Emit): Emit the code for add/remove handlers.
+ (Event.Define): Save the MethodBuilders for add/remove.
+
+ * typemanager.cs: Use pair here too.
+
+ * cs-parser.jay: Replaced use of DictionaryEntry for Pair because
+ DictionaryEntry requires the first argument to be non-null.
+
+ (enum_declaration): Compute full name for registering the
+ enumeration.
+
+ (delegate_declaration): Instead of using
+ formal_parameter_list, use opt_formal_parameter_list as the list
+ can be empty.
+
+ * cs-tokenizer.cs (PropertyParsing): renamed from `properties'
+ (EventParsing): New property that controls whether `add' and
+ `remove' are returned as tokens or identifiers (for events);
+
+2001-12-19 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Event.Define): Revamp use of EventBuilder completely. We now
+ use MyEventBuilder only and let it wrap the real builder for us.
+
+ (MyEventBuilder): Revamp constructor etc.
+
+ Implement all operations that we perform on EventBuilder in precisely the same
+ way here too.
+
+ (FindMembers): Update to use the EventBuilder member.
+
+ (Event.Emit): Update accordingly.
+
+2001-12-18 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (MyEventBuilder.Set*): Chain to the underlying builder
+ by calling the appropriate methods.
+
+ (GetCustomAttributes): Make stubs as they cannot possibly do anything
+ useful.
+
+ (Event.Emit): Use MyEventBuilder everywhere - even to set attributes.
+
+2001-12-17 Ravi Pratap <ravi@ximian.com>
+
+ * delegate.cs (Delegate.Populate): Check that the return type
+ and various parameters types are indeed accessible.
+
+ * class.cs (Constructor.Define): Same here.
+
+ (Field.Define): Ditto.
+
+ (Event.Define): Ditto.
+
+ (Operator.Define): Check that the underlying Method defined itself
+ correctly - so it's MethodBuilder should not be null.
+
+ * delegate.cs (DelegateInvocation.DoResolve): Bale out if the type of the Instance
+ expression happens to be null.
+
+ * class.cs (MyEventBuilder): Workaround for SRE lameness. Implement various abstract
+ members but as of now we don't seem to be able to do anything really useful with it.
+
+ (FindMembers): Handle events separately by returning the MyEventBuilder of the event,
+ not the EventBuilder.
+
+2001-12-18 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Add support for defines.
+ Add support for #if, #elif, #else, #endif
+
+ (eval_var): evaluates a variable.
+ (eval): stubbed for evaluating functions.
+
+ * cs-parser.jay: Pass the defines information
+
+ * driver.cs: Add --define command line option.
+
+ * decl.cs: Move MemberCore here.
+
+ Make it the base class for DeclSpace. This allows us to catch and
+ report 108 and 109 for everything now.
+
+ * class.cs (TypeContainer.Define): Extract all the members
+ before populating and emit the warning 108 (new keyword required
+ to override) instead of having each member implement this.
+
+ (MemberCore.Define): New abstract method, we will be using this in
+ the warning reporting engine in Populate.
+
+ (Operator.Define): Adjust to new MemberCore protocol.
+
+ * const.cs (Const): This does not derive from Expression, it is a
+ temporary object we use to create fields, it is a MemberCore.
+
+ * class.cs (Method.Define): Allow the entry point to be in a
+ specific class.
+
+ * driver.cs: Rewrite the argument handler to clean it up a bit.
+
+ * rootcontext.cs: Made it just an auxiliary namespace feature by
+ making everything static.
+
+ * driver.cs: Adapt code to use RootContext type name instead of
+ instance variable.
+
+ * delegate.cs: Remove RootContext argument.
+
+ * class.cs: (Struct, TypeContainer, Class): Remove RootContext
+ argument.
+
+ * class.cs (Event.Define): The lookup can fail.
+
+ * cs-tokenizer.cs: Begin implementation of pre-procesor.
+
+ * expression.cs: Resolve the this instance before invoking the code.
+
+2001-12-17 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add a production in element_access that allows
+ the thing to become a "type" reference. This way we can parse
+ things like "(string [])" as a type.
+
+ Note that this still does not handle the more complex rules of
+ casts.
+
+
+ * delegate.cs (Delegate.Populate): Register the delegage constructor builder here.
+
+ * ecore.cs: (CopyNewMethods): new utility function used to
+ assemble the list of methods from running FindMembers.
+
+ (MemberLookup): Rework FindMembers so that
+
+2001-12-16 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer): Remove Delegates who fail to be
+ defined.
+
+ * delegate.cs (Populate): Verify that we dont get null return
+ values. TODO: Check for AsAccessible.
+
+ * cs-parser.jay: Use basename to emit error 574 (destructor should
+ have the same name as container class), not the full name.
+
+ * cs-tokenizer.cs (adjust_int): Fit the integer in the best
+ possible representation.
+
+ Also implements integer type suffixes U and L.
+
+2001-12-15 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ArrayCreation.DoResolve): We need to do the
+ argument resolution *always*.
+
+ * decl.cs: Make this hold the namespace. Hold the root context as
+ well.
+ (LookupType): Move here.
+
+ * enum.cs, class.cs, interface.cs: Adapt to new hierarchy.
+
+ * location.cs (Row, Name): Fixed the code, it was always returning
+ references to the first file.
+
+ * interface.cs: Register properties defined through interfaces.
+
+ * driver.cs: Add support for globbing on the command line
+
+ * class.cs (Field): Make it derive from MemberCore as well.
+ (Event): ditto.
+
+2001-12-15 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Event::Define): Check that the type of the event is a delegate
+ type else flag error #66.
+
+ Also, re-use TypeContainer.MethodModifiersValid here too as the rules are the
+ same.
+
+ * attribute.cs (DefinePInvokeMethod): Handle named arguments and process
+ values of EntryPoint, CharSet etc etc.
+
+ Pass in the values to TypeBuilder.DefinePInvokeMethod; determine Type etc neatly.
+
+ * class.cs (FindMembers): If a method is in transit, its MethodBuilder will
+ be null and we should ignore this. I am not sure if this is really clean. Apparently,
+ there's no way of avoiding hitting this because the call is coming from SimpleName.DoResolve,
+ which needs this to do its work.
+
+ * ../errors/cs0066.cs : Add.
+
+2001-12-14 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: (GetPropertyGetter, GetPropertyGetter): New
+ helper functions.
+
+ * class.cs: (MethodSignature.MethodSignature): Removed hack that
+ clears out the parameters field.
+ (MemberSignatureCompare): Cleanup
+
+ (MemberCore): New base class used to share code between MethodCore
+ and Property.
+
+ (RegisterRequiredImplementations) BindingFlags.Public requires
+ either BindingFlags.Instace or Static. Use instance here.
+
+ (Property): Refactored code to cope better with the full spec.
+
+ * parameter.cs (GetParameterInfo): Return an empty array instead
+ of null on error.
+
+ * class.cs (Property): Abstract or extern properties have no bodies.
+
+ * parameter.cs (GetParameterInfo): return a zero-sized array.
+
+ * class.cs (TypeContainer.MethodModifiersValid): Move all the
+ method modifier validation to the typecontainer so we can reuse
+ this on properties.
+
+ (MethodCore.ParameterTypes): return an empty sized array of types.
+
+ (Property.Define): Test property modifier validity.
+
+ Add tests for sealed/override too.
+
+ (Method.Emit): abstract or extern methods have no bodies.
+
+2001-12-14 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Method.IsPInvoke): Get rid of it as it is an expensive
+ thing.
+
+ (Method::Define, ::Emit): Modify accordingly.
+
+ * expression.cs (Invocation::OverloadResolve): Handle error # 121.
+
+ (ArrayCreation::MakeByteBlob): Handle floats and doubles.
+
+ * makefile: Pass in /unsafe.
+
+2001-12-13 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MakeKey): Kill routine.
+
+ * class.cs (TypeContainer.Define): Correctly define explicit
+ method implementations (they require the full interface name plus
+ the method name).
+
+ * typemanager.cs: Deply the PtrHashtable here and stop using the
+ lame keys. Things work so much better.
+
+ This of course broke everyone who depended on `RegisterMethod' to
+ do the `test for existance' test. This has to be done elsewhere.
+
+ * support.cs (PtrHashtable): A hashtable that avoid comparing with
+ the object stupid Equals method (because, that like fails all over
+ the place). We still do not use it.
+
+ * class.cs (TypeContainer.SetRequiredInterface,
+ TypeContainer.RequireMethods): Killed these two routines and moved
+ all the functionality to RegisterRequiredImplementations.
+
+ (TypeContainer.RegisterRequiredImplementations): This routine now
+ registers all the implementations required in an array for the
+ interfaces and abstract methods. We use an array of structures
+ which can be computed ahead of time to reduce memory usage and we
+ also assume that lookups are cheap as most classes will not
+ implement too many interfaces.
+
+ We also avoid creating too many MethodSignatures.
+
+ (TypeContainer.IsInterfaceMethod): Update and optionally does not
+ clear the "pending" bit if we find that there are problems with
+ the declaration.
+
+ (TypeContainer.VerifyPendingMethods): Update to report errors of
+ methods that look like implementations but are not.
+
+ (TypeContainer.Define): Add support for explicit interface method
+ implementation.
+
+2001-12-12 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: Keep track of the parameters here instead of
+ being a feature of the TypeContainer.
+
+ * class.cs: Drop the registration of parameters here, as
+ InterfaceMethods are also interface declarations.
+
+ * delegate.cs: Register methods with the TypeManager not only with
+ the TypeContainer. This code was buggy.
+
+ * interface.cs: Full registation here.
+
+2001-12-11 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Remove reducer for binary expressions, it can not
+ be done this way.
+
+ * const.cs: Put here the code that used to go into constant.cs
+
+ * constant.cs: Put here the code for constants, this is a new base
+ class for Literals.
+
+ * literal.cs: Make Literal derive from Constant.
+
+2001-12-09 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Return.Emit): Report error 157 if the user
+ attempts to return from a finally block.
+
+ (Return.Emit): Instead of emitting a return, jump to the end of
+ the function.
+
+ * codegen.cs (EmitContext): ReturnValue, ReturnLabel: new
+ LocalBuilder to store the result of the function. ReturnLabel is
+ the target where we jump.
+
+
+2001-12-09 Radek Doulik <rodo@ximian.com>
+
+ * cs-parser.jay: remember alias in current namespace
+
+ * ecore.cs (SimpleName::DoResolve): use aliases for types or
+ namespaces
+
+ * class.cs (LookupAlias): lookup alias in my_namespace
+
+ * namespace.cs (UsingAlias): add alias, namespace_or_type pair to
+ aliases hashtable
+ (LookupAlias): lookup alias in this and if needed in parent
+ namespaces
+
+2001-12-08 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs:
+
+ * rootcontext.cs: (ModuleBuilder) Made static, first step into
+ making things static. I need this to avoid passing the
+ TypeContainer when calling ParameterType.
+
+ * support.cs (InternalParameters.ParameterType): Remove ugly hack
+ that did string manipulation to compute the type and then call
+ GetType. Use Parameter.ParameterType instead.
+
+ * cs-tokenizer.cs: Consume the suffix for floating values.
+
+ * expression.cs (ParameterReference): figure out whether this is a
+ reference parameter or not. Kill an extra variable by computing
+ the arg_idx during emission.
+
+ * parameter.cs (Parameters.GetParameterInfo): New overloaded
+ function that returns whether a parameter is an out/ref value or not.
+
+ (Parameter.ParameterType): The type of the parameter (base,
+ without ref/out applied).
+
+ (Parameter.Resolve): Perform resolution here.
+ (Parameter.ExternalType): The full type (with ref/out applied).
+
+ * statement.cs (Using.Emit, Using.EmitExpression): Implement
+ support for expressions on the using statement.
+
+2001-12-07 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Using.EmitLocalVariableDecls): Split the
+ localvariable handling of the using statement.
+
+ (Block.EmitMeta): Keep track of variable count across blocks. We
+ were reusing slots on separate branches of blocks.
+
+ (Try.Emit): Emit the general code block, we were not emitting it.
+
+ Check the type of the declaration to be an IDisposable or
+ something that can be implicity converted to it.
+
+ Emit conversions if required.
+
+ * ecore.cs (EmptyExpression): New utility class.
+ (Expression.ImplicitConversionExists): New utility function.
+
+2001-12-06 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Using): Implement.
+
+ * expression.cs (LocalVariableReference): Support read only variables.
+
+ * statement.cs: Remove the explicit emit for the Leave opcode.
+ (VariableInfo): Add a readonly field.
+
+2001-12-05 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (ConvCast): new class used to encapsulate the various
+ explicit integer conversions that works in both checked and
+ unchecked contexts.
+
+ (Expression.ConvertNumericExplicit): Use new ConvCast class to
+ properly generate the overflow opcodes.
+
+2001-12-04 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: The correct type for the EmptyExpression is the
+ element_type, not the variable type. Ravi pointed this out.
+
+2001-12-04 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Method::Define): Handle PInvoke methods specially
+ by using DefinePInvokeMethod instead of the usual one.
+
+ * attribute.cs (DefinePInvokeMethod): Implement as this is what is called
+ above to do the task of extracting information and defining the method.
+
+2001-12-04 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation::EmitStaticInitializers): Get rid
+ of the condition for string type.
+
+ (Emit): Move that here.
+
+ (ArrayCreation::CheckIndices): Keep string literals in their expression
+ form.
+
+ (EmitDynamicInitializers): Handle strings appropriately.
+
+2001-12-04 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs (EmitContext): Replace multiple variables with a
+ single pointer to the current Switch statement.
+
+ * statement.cs (GotoDefault, Switch): Adjust to cleaned up
+ EmitContext.
+
+2001-12-03 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs
+
+ * statement.cs (GotoDefault), cs-parser.jay: Implement `goto
+ default'.
+
+ (Foreach.Emit): Foreach on arrays was not setting
+ up the loop variables (for break/continue).
+
+ (GotoCase): Semi-implented.
+
+2001-12-03 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (CheckAttribute): Handle system attributes by using
+ Attribute.GetAttributes to examine information we need.
+
+ (GetValidPlaces): Same here.
+
+ * class.cs (Method::Define): Catch invalid use of extern and abstract together.
+
+ * typemanager.cs (dllimport_type): Core type for System.DllImportAttribute.
+
+ * class.cs (Method.IsPinvoke): Used to determine if we are a PInvoke method.
+
+ (Method::Define): Set appropriate flags if we have a DllImport attribute.
+
+ (Method::Emit): Handle the case when we are a PInvoke method.
+
+2001-12-03 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Use ResolveWithSimpleName on compound names.
+
+2001-12-02 Ravi Pratap <ravi@ximian.com>
+
+ * constant.cs (EmitConstant): Make sure we resolve the associated expression
+ before trying to reduce it.
+
+ * typemanager.cs (RegisterConstant, LookupConstant): Implement.
+
+ * constant.cs (LookupConstantValue): Implement.
+
+ (EmitConstant): Use the above in emitting the constant.
+
+ * expression.cs (MemberAccess::ResolveMemberAccess): Handle constants
+ that are user-defined by doing a LookupConstantValue on them.
+
+ (SimpleName::DoResolve): When we have a FieldExpr, cope with constants
+ too, like above.
+
+2001-11-29 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (BaseAccess, BaseIndexer): Also split this out.
+
+ (BaseAccess.DoResolve): Implement.
+
+ (MemberAccess.DoResolve): Split this routine into a
+ ResolveMemberAccess routine that can be used independently
+
+2001-11-28 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Probe, Is, As): Split Probe in two classes Is and
+ As that share bits of the implementation. Is returns a boolean,
+ while As returns the Type that is being probed.
+
+2001-12-01 Ravi Pratap <ravi@ximian.com>
+
+ * enum.cs (LookupEnumValue): Re-write various bits, return an object value
+ instead of a Literal - much easier.
+
+ (EnumInTransit): Remove - utterly useless :-)
+
+ (Populate): Re-write bits - remove duplicate code etc. The code is much neater now.
+
+ * expression.cs (MemberLookup): Cope with user-defined enums when they are in transit.
+
+ * enum.cs (LookupEnumValue): Auto-compute next values by going down the dependency
+ chain when we have no associated expression.
+
+2001-11-30 Ravi Pratap <ravi@ximian.com>
+
+ * constant.cs (Define): Use Location while reporting the errror.
+
+ Also emit a warning when 'new' is used and there is no inherited
+ member to hide.
+
+ * enum.cs (EnumInTransit): Used to tell if an enum type is in the process of being
+ populated.
+
+ (LookupEnumValue): Implement to lookup an enum member's value and define it
+ if necessary.
+
+ (Populate): Re-write accordingly to use the above routine.
+
+2001-11-27 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (This): Fix prototype for DoResolveLValue to
+ override the base class DoResolveLValue.
+
+ * cs-parser.cs: Report errors cs574 and cs575 (destructor
+ declarations)
+
+ * ecore.cs (FieldExpr.EmitAssign): Handle value types specially
+ (we need to load the address of the field here). This fixes
+ test-22.
+
+ (FieldExpr.DoResolveLValue): Call the DoResolve
+ function to initialize the Instance expression.
+
+ * statement.cs (Foreach.Emit): Fix the bug where we did not invoke
+ correctly the GetEnumerator operation on a value type.
+
+ * cs-parser.jay: Add more simple parsing error catches.
+
+ * statement.cs (Switch): Add support for string switches.
+ Handle null specially.
+
+ * literal.cs (NullLiteral): Make NullLiteral objects singletons.
+
+2001-11-28 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (local_constant_declaration): Use declare_local_constant.
+
+ (declare_local_constant): New helper function.
+
+ * statement.cs (AddConstant): Keep a separate record of constants
+
+ (IsConstant): Implement to determine if a variable is a constant.
+
+ (GetConstantExpression): Implement.
+
+ * expression.cs (LocalVariableReference): Handle the case when it is a constant.
+
+ * statement.cs (IsVariableDefined): Re-write.
+
+2001-11-27 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::FindMembers): Look for constants
+ in the case when we are looking for MemberTypes.Field
+
+ * expression.cs (MemberAccess::DoResolve): Check that in the
+ case we are a FieldExpr and a Literal, we are not being accessed
+ by an instance reference.
+
+ * cs-parser.jay (local_constant_declaration): Implement.
+
+ (declaration_statement): Implement for constant declarations.
+
+2001-11-26 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Switch): Catch double defaults.
+
+ (Switch): More work on the switch() statement
+ implementation. It works for integral values now, need to finish
+ string support.
+
+
+2001-11-24 Miguel de Icaza <miguel@ximian.com>
+
+ * ecore.cs (Expression.ConvertIntLiteral): New function to convert
+ integer literals into other integer literals. To be used by
+ switch.
+
+2001-11-24 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation): Get rid of ArrayExprs : we save
+ some memory.
+
+ (EmitDynamicInitializers): Cope with the above since we extract data
+ directly from ArrayData now.
+
+ (ExpectInitializers): Keep track of whether initializers are mandatory
+ or not.
+
+ (Bounds): Make it a hashtable to prevent the same dimension being
+ recorded for every element in that dimension.
+
+ (EmitDynamicInitializers): Fix bug which prevented the Set array method
+ from being found.
+
+ Also fix bug which was causing the indices to be emitted in the reverse
+ order.
+
+2001-11-24 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ArrayCreation): Implement the bits that Ravi left
+ unfinished. They do not work, because the underlying code is
+ sloppy.
+
+2001-11-22 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Remove bogus fixme.
+
+ * statement.cs (Switch, SwitchSection, SwithLabel): Started work
+ on Switch statement.
+
+2001-11-23 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (IsDelegateType, IsEnumType): Fix logic to determine
+ the same.
+
+ * expression.cs (ArrayCreation::CheckIndices): Get rid of the require_constant
+ parameter. Apparently, any expression is allowed.
+
+ (ValidateInitializers): Update accordingly.
+
+ (CheckIndices): Fix some tricky bugs thanks to recursion.
+
+ * delegate.cs (NewDelegate::DoResolve): Re-write large portions as
+ I was being completely brain-dead.
+
+ (VerifyMethod, VerifyApplicability, VerifyDelegate): Make static
+ and re-write acordingly.
+
+ (DelegateInvocation): Re-write accordingly.
+
+ * expression.cs (ArrayCreation::Emit): Handle string initialization separately.
+
+ (MakeByteBlob): Handle types more correctly.
+
+ * expression.cs (ArrayCreation:Emit): Write preliminary code to do
+ initialization from expressions but it is incomplete because I am a complete
+ Dodo :-|
+
+2001-11-22 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (If.Emit): Fix a bug that generated incorrect code
+ on If. Basically, we have to return `true' (ie, we do return to
+ our caller) only if both branches of the if return.
+
+ * expression.cs (Binary.Emit): LogicalOr and LogicalAnd are
+ short-circuit operators, handle them as short circuit operators.
+
+ (Cast.DoResolve): Resolve type.
+ (Cast.Cast): Take an expression as the target type.
+
+ * cs-parser.jay (cast_expression): Remove old hack that only
+ allowed a limited set of types to be handled. Now we take a
+ unary_expression and we resolve to a type during semantic
+ analysis.
+
+ Use the grammar productions from Rhys to handle casts (this is
+ not complete like Rhys syntax yet, we fail to handle that corner
+ case that C# has regarding (-x), but we will get there.
+
+2001-11-22 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (EmitFieldInitializer): Take care of the case when we have a
+ field which is an array type.
+
+ * cs-parser.jay (declare_local_variables): Support array initialization too.
+
+ * typemanager.cs (MakeKey): Implement.
+
+ (everywhere): Use the above appropriately.
+
+ * cs-parser.jay (for_statement): Update for array initialization while
+ declaring variables.
+
+ * ecore.cs : The error message was correct, it's the variable's names that
+ were misleading ;-) Make the code more readable.
+
+ (MemberAccess::DoResolve): Fix the code which handles Enum literals to set
+ the correct type etc.
+
+ (ConvertExplicit): Handle Enum types by examining the underlying type.
+
+2001-11-21 Ravi Pratap <ravi@ximian.com>
+
+ * parameter.cs (GetCallingConvention): Always return
+ CallingConventions.Standard for now.
+
+2001-11-22 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary.ResolveOperator): Update the values of `l'
+ and `r' after calling DoNumericPromotions.
+
+ * ecore.cs: Fix error message (the types were in the wrong order).
+
+ * statement.cs (Foreach.ProbeCollectionType): Need to pass
+ BindingFlags.Instance as well
+
+ * ecore.cs (Expression.TryImplicitIntConversion): Wrap the result
+ implicit int literal conversion in an empty cast so that we
+ propagate the right type upstream.
+
+ (UnboxCast): new class used to unbox value types.
+ (Expression.ConvertExplicit): Add explicit type conversions done
+ by unboxing.
+
+ (Expression.ImplicitNumericConversion): Oops, forgot to test for
+ the target type before applying the implicit LongLiterals to ULong
+ literal cast.
+
+2001-11-21 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay (for_statement): Reworked the way For works: now
+ we declare manually any variables that are introduced in
+ for_initializer to solve the problem of having out-of-band code
+ emition (that is what got for broken).
+
+ (declaration_statement): Perform the actual variable declaration
+ that used to be done in local_variable_declaration here.
+
+ (local_variable_declaration): Do not declare anything, just pass
+ the information on a DictionaryEntry
+
+2001-11-20 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation::CheckIndices): The story continues :-) Complete
+ re-write of the logic to now make it recursive.
+
+ (UpdateIndices): Re-write accordingly.
+
+ Store element data in a separate ArrayData list in the above methods.
+
+ (MakeByteBlob): Implement to dump the array data into a byte array.
+
+2001-11-19 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation): Factor out some code from ValidateInitializers
+ into CheckIndices.
+
+ * constant.cs (Define): Implement.
+
+ (EmitConstant): Re-write fully.
+
+ Pass in location info.
+
+ * class.cs (Populate, Emit): Call Constant::Define and Constant::EmitConstant
+ respectively.
+
+ * cs-parser.jay (constant_declarator): Use VariableDeclaration instead of
+ DictionaryEntry since we need location info too.
+
+ (constant_declaration): Update accordingly.
+
+ * expression.cs (ArrayCreation): Make ValidateInitializers simpler by factoring
+ code into another method : UpdateIndices.
+
+2001-11-18 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation::ValidateInitializers): Update to perform
+ some type checking etc.
+
+2001-11-17 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation::ValidateInitializers): Implement
+ bits to provide dimension info if the user skips doing that.
+
+ Update second constructor to store the rank correctly.
+
+2001-11-16 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ArrayCreation::ValidateInitializers): Poke around
+ and try to implement.
+
+ * ../errors/cs0150.cs : Add.
+
+ * ../errors/cs0178.cs : Add.
+
+2001-11-16 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: Implement foreach on multi-dimensional arrays.
+
+ * parameter.cs (Parameters.GetParameterByName): Also lookup the
+ name of the params argument.
+
+ * expression.cs: Use EmitStoreOpcode to get the right opcode while
+ initializing the array.
+
+ (ArrayAccess.EmitStoreOpcode): move the opcode generation here, so
+ we can use this elsewhere.
+
+ * statement.cs: Finish implementation of foreach for single
+ dimension arrays.
+
+ * cs-parser.jay: Use an out-of-band stack to pass information
+ around, I wonder why I need this.
+
+ foreach_block: Make the new foreach_block the current_block.
+
+ * parameter.cs (Parameters.GetEmptyReadOnlyParameters): New
+ function used to return a static Parameters structure. Used for
+ empty parameters, as those are created very frequently.
+
+ * cs-parser.jay, class.cs: Use GetEmptyReadOnlyParameters
+
+2001-11-15 Ravi Pratap <ravi@ximian.com>
+
+ * interface.cs : Default modifier is private, not public. The
+ make verify test passes again.
+
+2001-11-15 Ravi Pratap <ravi@ximian.com>
+
+ * support.cs (ReflectionParameters): Fix logic to determine
+ whether the last parameter is a params one. Test 9 passes again.
+
+ * delegate.cs (Populate): Register the builders we define with
+ RegisterParameterForBuilder. Test 19 passes again.
+
+ * cs-parser.jay (property_declaration): Reference $6 instead
+ of $$ to get at the location.
+
+ (indexer_declaration): Similar stuff.
+
+ (attribute): Ditto.
+
+ * class.cs (Property): Register parameters for the Get and Set methods
+ if they exist. Test 23 passes again.
+
+ * expression.cs (ArrayCreation::Emit): Pass null for the method in the
+ call to EmitArguments as we are sure there aren't any params arguments.
+ Test 32 passes again.
+
+ * suppor.cs (ParameterDesc, ParameterModifier): Fix trivial bug causing
+ IndexOutOfRangeException.
+
+ * class.cs (Property::Define): Register property using TypeManager.RegisterProperty
+ Test 33 now passes again.
+
+2001-11-15 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Kill horrendous hack ($??? = lexer.Location) that
+ broke a bunch of things. Will have to come up with a better way
+ of tracking locations.
+
+ * statement.cs: Implemented foreach for single dimension arrays.
+
+2001-11-09 Miguel de Icaza <miguel@ximian.com>
+
+ * enum.cs (Enum.Emit): Delay the lookup of loc until we run into
+ an error. This removes the lookup from the critical path.
+
+ * cs-parser.jay: Removed use of temporary_loc, which is completely
+ broken.
+
+2001-11-14 Miguel de Icaza <miguel@ximian.com>
+
+ * support.cs (ReflectionParameters.ParameterModifier): Report
+ whether the argument is a PARAMS argument or not.
+
+ * class.cs: Set the attribute `ParamArrayAttribute' on the
+ parameter argument.
+
+ * typemanager.cs: Define param_array_type (ParamArrayAttribute)
+ and cons_param_array_attribute (ConstructorInfo for
+ ParamArrayAttribute).,
+
+ * codegen.cs: Emit the return using the `Return' statement, that
+ way we can report the error correctly for missing return values.
+
+ * class.cs (Method.Emit): Clean up.
+
+ * expression.cs (Argument.Resolve): Take another argument: the
+ location where this argument is used. Notice that this is not
+ part of the "Argument" class as to reduce the size of the
+ structure (we know the approximate location anyways).
+
+ Test if the argument is a variable-reference, if not, then
+ complain with a 206.
+
+ (Argument.Emit): Emit addresses of variables.
+
+ (Argument.FullDesc): Simplify.
+
+ (Invocation.DoResolve): Update for Argument.Resolve.
+
+ (ElementAccess.DoResolve): ditto.
+
+ * delegate.cs (DelegateInvocation.Emit): Invocation of Invoke
+ method should be virtual, as this method is always virtual.
+
+ (NewDelegate.DoResolve): Update for Argument.Resolve.
+
+ * class.cs (ConstructorInitializer.DoResolve): ditto.
+
+ * attribute.cs (Attribute.Resolve): ditto.
+
+2001-11-13 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Foreach.Emit): Use EmitAssign instead of Store.
+
+ * expression.cs (ParameterReference): Drop IStackStorage and implement
+ IAssignMethod instead.
+
+ (LocalVariableReference): ditto.
+
+ * ecore.cs (FieldExpr): Drop IStackStorage and implement
+ IAssignMethod instead.
+
+2001-11-13 Miguel de Icaza <miguel@ximian.com>
+
+ * parameter.cs, expression.cs, class.cs, ecore.cs: Made all
+ enumerations that are used in heavily used structures derive from
+ byte in a laughable and pathetic attempt to reduce memory usage.
+ This is the kind of pre-optimzations that you should not do at
+ home without adult supervision.
+
+ * expression.cs (UnaryMutator): New class, used to handle ++ and
+ -- separatedly from the other unary operators. Cleans up the
+ code, and kills the ExpressionStatement dependency in Unary.
+
+ (Unary): Removed `method' and `Arguments' from this class, making
+ it smaller, and moving it all to SimpleCall, so I can reuse this
+ code in other locations and avoid creating a lot of transient data
+ strucutres when not required.
+
+ * cs-parser.jay: Adjust for new changes.
+
+2001-11-11 Miguel de Icaza <miguel@ximian.com>
+
+ * enum.cs (Enum.Populate): If there is a failure during
+ definition, return
+
+ * cs-parser.jay (opt_enum_base): we used to catch type errors
+ here, but this is really incorrect. The type error should be
+ catched during semantic analysis.
+
+2001-12-11 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (operator_declarator, conversion_operator_declarator): Set
+ current_local_parameters as expected since I, in my stupidity, had forgotten
+ to do this :-)
+
+ * attribute.cs (GetValidPlaces): Fix stupid bug.
+
+ * class.cs (Method::Emit): Perform check on applicability of attributes.
+
+ (Constructor::Emit): Ditto.
+
+ (Field::Emit): Ditto.
+
+ (Field.Location): Store location information.
+
+ (Property, Event, Indexer, Operator): Ditto.
+
+ * cs-parser.jay (field_declaration): Pass in location for each field.
+
+ * ../errors/cs0592.cs : Add.
+
+2001-11-12 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (attribute_usage_type): New static member for System.AttributeUsage.
+
+ (InitCoreTypes): Update accordingly.
+
+ (RegisterAttrType, LookupAttr): Implement.
+
+ * attribute.cs (Attribute.Targets, AllowMultiple, Inherited): New fields to hold
+ info about the same.
+
+ (Resolve): Update to populate the above as necessary.
+
+ (Error592): Helper.
+
+ (GetValidPlaces): Helper to the above.
+
+ (CheckAttribute): Implement to perform validity of attributes on declarative elements.
+
+ * class.cs (TypeContainer::Emit): Update attribute emission code to perform checking etc.
+
+2001-11-12 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (Attribute::Resolve): Expand to handle named arguments too.
+
+ * ../errors/cs0617.cs : Add.
+
+2001-11-11 Ravi Pratap <ravi@ximian.com>
+
+ * enum.cs (Emit): Rename to Populate to be more consistent with what
+ we expect it to do and when exactly it is called.
+
+ * class.cs, rootcontext.cs : Update accordingly.
+
+ * typemanager.cs (RegisterField, GetValue): Workarounds for the fact that
+ FieldInfo.GetValue does not work on dynamic types ! S.R.E lameness strikes again !
+
+ * enum.cs (Populate): Register fields with TypeManager.RegisterField.
+
+ * expression.cs (MemberAccess.DoResolve): Adjust code to obtain the value
+ of a fieldinfo using the above, when dealing with a FieldBuilder.
+
+2001-11-10 Ravi Pratap <ravi@ximian.com>
+
+ * ../errors/cs0031.cs : Add.
+
+ * ../errors/cs1008.cs : Add.
+
+ * ../errrors/cs0543.cs : Add.
+
+ * enum.cs (DefineEnum): Check the underlying type and report an error if not a valid
+ enum type.
+
+ (FindMembers): Implement.
+
+ * typemanager.cs (FindMembers): Re-write to call the appropriate methods for
+ enums and delegates too.
+
+ (enum_types): Rename to builder_to_enum.
+
+ (delegate_types): Rename to builder_to_delegate.
+
+ * delegate.cs (FindMembers): Implement.
+
+2001-11-09 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (IsEnumType): Implement.
+
+ * enum.cs (Emit): Re-write parts to account for the underlying type
+ better and perform checking etc.
+
+ (GetNextDefaultValue): Helper to ensure we don't overshoot max value
+ of the underlying type.
+
+ * literal.cs (GetValue methods everywhere): Perform bounds checking and return
+ value
+
+ * enum.cs (error31): Helper to report error #31.
+
+ * cs-parser.jay (enum_declaration): Store location of each member too.
+
+ * enum.cs (member_to_location): New hashtable.
+
+ (AddEnumMember): Update location hashtable.
+
+ (Emit): Use the location of each member while reporting errors.
+
+2001-11-09 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: A for_initializer if is a
+ local_variable_declaration really ammount to have an implicit
+ block with the variable declaration and no initializer for for.
+
+ * statement.cs (For.Emit): Cope with null initializers.
+
+ This fixes the infinite loop on for initializers.
+
+2001-11-08 Miguel de Icaza <miguel@ximian.com>
+
+ * enum.cs: More cleanup.
+
+ * ecore.cs: Remove dead code.
+
+ * class.cs (Property.Emit): More simplification.
+ (Event.Emit): ditto.
+
+ Reworked to have less levels of indentation.
+
+2001-11-08 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Property): Emit attributes.
+
+ (Field): Ditto.
+
+ (Event): Ditto.
+
+ (Indexer): Ditto.
+
+ (Operator): Ditto.
+
+ * enum.cs (Emit): Ditto.
+
+ * rootcontext.cs (ResolveTree, EmitCode, CloseTypes): Do the same for
+ Enums too.
+
+ * class.cs (Field, Event, etc.): Move attribute generation into the
+ Emit method everywhere.
+
+ * enum.cs (Enum): Revamp to use the same definition semantics as delegates so
+ we have a DefineEnum, CloseEnum etc. The previous way of doing things was not right
+ as we had no way of defining nested enums !
+
+ * rootcontext.cs : Adjust code accordingly.
+
+ * typemanager.cs (AddEnumType): To keep track of enum types separately.
+
+2001-11-07 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (EvalConstantExpression): Move into ecore.cs
+
+ * enum.cs (Enum): Rename some members and make them public and readonly
+ according to our convention.
+
+ * modifiers.cs (EnumAttr): Implement as we need to set only visibility flags,
+ nothing else.
+
+ * enum.cs (Enum::Define): Use the above instead of TypeAttr.
+
+ (Enum::Emit): Write a simple version for now which doesn't try to compute
+ expressions. I shall modify this to be more robust in just a while.
+
+ * class.cs (TypeContainer::Emit): Make sure we include Enums too.
+
+ (TypeContainer::CloseType): Create the Enum types too.
+
+ * attribute.cs (Resolve): Use the new Reduce method instead of EvalConstantExpression.
+
+ * expression.cs (EvalConstantExpression): Get rid of completely.
+
+ * enum.cs (Enum::Emit): Use the new expression reducer. Implement assigning
+ user-defined values and other cases.
+
+ (IsValidEnumLiteral): Helper function.
+
+ * expression.cs (ExprClassfromMemberInfo): Modify to not do any literalizing
+ out there in the case we had a literal FieldExpr.
+
+ (MemberAccess:DoResolve): Do the literalizing of the FieldExpr here.
+
+ (Literalize): Revamp a bit to take two arguments.
+
+ (EnumLiteral): New class which derives from Literal to wrap enum literals.
+
+2001-11-06 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (compilation_unit): Remove extra opt_attributes for now.
+
+ * expression.cs (ArrayCreation::ValidateInitializers): Implement.
+
+ (Resolve): Use the above to ensure we have proper initializers.
+
+2001-11-05 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Expression::EvalConstantExpression): New method to
+ evaluate constant expressions.
+
+ * attribute.cs (Attribute::Resolve): Modify bits to use the above function.
+
+2001-11-07 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ArrayCreation.Emit): Some bits to initialize data
+ in an array.
+
+ (Binary.ResolveOperator): Handle operator != (object a, object b)
+ and operator == (object a, object b);
+
+ (Binary.DoNumericPromotions): Indicate whether the numeric
+ promotion was possible.
+
+ (ArrayAccess.DoResolve, ArrayAccess.Emit, ArrayAccess.EmitAssign):
+ Implement.
+
+ Made the ArrayAccess implement interface IAssignMethod instead of
+ IStackStore as the order in which arguments are passed reflects
+ this.
+
+ * assign.cs: Instead of using expr.ExprClass to select the way of
+ assinging, probe for the IStackStore/IAssignMethod interfaces.
+
+ * typemanager.cs: Load InitializeArray definition.
+
+ * rootcontext.cs (RootContext.MakeStaticData): Used to define
+ static data that can be used to initialize arrays.
+
+2001-11-05 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Handle operator== and operator!= for booleans.
+
+ (Conditioal.Reduce): Implement reducer for the ?: operator.
+
+ (Conditional.Resolve): Implement dead code elimination.
+
+ (Binary.Resolve): Catch string literals and return a new
+ concatenated string.
+
+ (Unary.Reduce): Implement reduction of unary expressions.
+
+ * ecore.cs: Split out the expression core handling here.
+
+ (Expression.Reduce): New method used to perform constant folding
+ and CSE. This is needed to support constant-expressions.
+
+ * statement.cs (Statement.EmitBoolExpression): Pass true and false
+ targets, and optimize for !x.
+
+2001-11-04 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (Attribute::Resolve): Implement guts. Note that resolution
+ of an attribute gives us a CustomAttributeBuilder which we use accordingly to
+ set custom atttributes.
+
+ * literal.cs (Literal::GetValue): New abstract method to return the actual
+ value of the literal, cast as an object.
+
+ (*Literal): Implement GetValue method.
+
+ * cs-parser.jay (positional_argument_list, named_argument_list): Add not just plain
+ expressions to the arraylist but objects of type Argument.
+
+ * class.cs (TypeContainer::Emit): Emit our attributes too.
+
+ (Method::Emit, Constructor::Emit): Ditto.
+
+ * cs-parser.jay (constructor_declaration): Set attributes too, which we seemed
+ to be ignoring earlier.
+
+2001-11-03 Ravi Pratap <ravi@ximian.com>
+
+ * attribute.cs (AttributeSection::Define): Implement to do the business
+ of constructing a CustomAttributeBuilder.
+
+ (Attribute): New trivial class. Increases readability of code.
+
+ * cs-parser.jay : Update accordingly.
+
+ (positional_argument_list, named_argument_list, named_argument): New rules
+
+ (attribute_arguments): Use the above so that we are more correct.
+
+2001-11-02 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation::IsParamsMethodApplicable): Implement
+ to perform all checks for a method with a params parameter.
+
+ (Invocation::OverloadResolve): Update to use the above method and therefore
+ cope correctly with params method invocations.
+
+ * support.cs (InternalParameters::ParameterDesc): Provide a desc for
+ params too.
+
+ * class.cs (ConstructorInitializer::Resolve): Make sure we look for Non-public
+ constructors in our parent too because we can't afford to miss out on
+ protected ones ;-)
+
+ * attribute.cs (AttributeSection): New name for the class Attribute
+
+ Other trivial changes to improve readability.
+
+ * cs-parser.jay (opt_attributes, attribute_section etc.): Modify to
+ use the new class names.
+
+2001-11-01 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Method::Define): Complete definition for params types too
+
+ (Indexer::Define): Ditto.
+
+ * support.cs (InternalParameters::ParameterType, ParameterDesc, ParameterModifier):
+ Cope everywhere with a request for info about the array parameter.
+
+2001-11-01 Ravi Pratap <ravi@ximian.com>
+
+ * tree.cs (RecordNamespace): Fix up to check for the correct key.
+
+ * cs-parser.jay (GetQualifiedIdentifier): New Helper method used in
+ local_variable_type to extract the string corresponding to the type.
+
+ (local_variable_type): Fixup the action to use the new helper method.
+
+ * codegen.cs : Get rid of RefOrOutParameter, it's not the right way to
+ go.
+
+ * expression.cs : Clean out code which uses the above.
+
+2001-10-31 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (RegisterMethod): Check if we already have an existing key
+ and bale out if necessary by returning a false.
+
+ (RegisterProperty): Ditto.
+
+ * class.cs (everywhere): Check the return value from TypeManager.RegisterMethod
+ and print out appropriate error messages.
+
+ * interface.cs (everywhere): Ditto.
+
+ * cs-parser.jay (property_declaration, event_declaration, indexer_declaration): Pass
+ location to constructor.
+
+ * class.cs (Property, Event, Indexer): Update accordingly.
+
+ * ../errors/cs111.cs : Added.
+
+ * expression.cs (Invocation::IsApplicable): New static method to determine applicability
+ of a method, as laid down by the spec.
+
+ (Invocation::OverloadResolve): Use the above method.
+
+2001-10-31 Ravi Pratap <ravi@ximian.com>
+
+ * support.cs (InternalParameters): Get rid of crap taking in duplicate info. We
+ now take a TypeContainer and a Parameters object.
+
+ (ParameterData): Modify return type of ParameterModifier method to be
+ Parameter.Modifier and not a string.
+
+ (ReflectionParameters, InternalParameters): Update accordingly.
+
+ * expression.cs (Argument::GetParameterModifier): Same here.
+
+ * support.cs (InternalParameters::ParameterType): Find a better way of determining
+ if we are a ref/out parameter. Actually, the type shouldn't be holding the '&'
+ symbol in it at all so maybe this is only for now.
+
+2001-10-30 Ravi Pratap <ravi@ximian.com>
+
+ * support.cs (InternalParameters): Constructor now takes an extra argument
+ which is the actual Parameters class.
+
+ (ParameterDesc): Update to provide info on ref/out modifiers.
+
+ * class.cs (everywhere): Update call to InternalParameters to pass in
+ the second argument too.
+
+ * support.cs (ParameterData): Add ParameterModifier, which is a method
+ to return the modifier info [ref/out etc]
+
+ (InternalParameters, ReflectionParameters): Implement the above.
+
+ * expression.cs (Argument::ParameterModifier): Similar function to return
+ info about the argument's modifiers.
+
+ (Invocation::OverloadResolve): Update to take into account matching modifiers
+ too.
+
+ * class.cs (Indexer::Define): Actually define a Parameter object and put it onto
+ a new SetFormalParameters object which we pass to InternalParameters.
+
+2001-10-30 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (NewArray): Merge into the ArrayCreation class.
+
+2001-10-29 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (NewArray): Merge classes NewBuiltinArray and
+ NewUserdefinedArray into one as there wasn't much of a use in having
+ two separate ones.
+
+ * expression.cs (Argument): Change field's name to ArgType from Type.
+
+ (Type): New readonly property which returns the proper type, taking into
+ account ref/out modifiers.
+
+ (everywhere): Adjust code accordingly for the above.
+
+ * codegen.cs (EmitContext.RefOrOutParameter): New field to determine
+ whether we are emitting for a ref or out parameter.
+
+ * expression.cs (Argument::Emit): Use the above field to set the state.
+
+ (LocalVariableReference::Emit): Update to honour the flag and emit the
+ right stuff.
+
+ * parameter.cs (Attributes): Set the correct flags for ref parameters.
+
+ * expression.cs (Argument::FullDesc): New function to provide a full desc.
+
+ * support.cs (ParameterData): Add method ParameterDesc to the interface.
+
+ (ReflectionParameters, InternalParameters): Implement the above method.
+
+ * expression.cs (Invocation::OverloadResolve): Use the new desc methods in
+ reporting errors.
+
+ (Invocation::FullMethodDesc): Ditto.
+
+2001-10-29 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add extra production for the second form of array
+ creation.
+
+ * expression.cs (ArrayCreation): Update to reflect the above
+ change.
+
+ * Small changes to prepare for Array initialization.
+
+2001-10-28 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (ImplementsInterface): interface might be null;
+ Deal with this problem;
+
+ Also, we do store negative hits on the cache (null values), so use
+ this instead of calling t.GetInterfaces on the type everytime.
+
+2001-10-28 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (IsBuiltinType): New method to help determine the same.
+
+ * expression.cs (New::DoResolve): Get rid of array creation code and instead
+ split functionality out into different classes.
+
+ (New::FormArrayType): Move into NewBuiltinArray.
+
+ (Invocation::EmitArguments): Get rid of the MethodBase argument. Appears
+ quite useless.
+
+ (NewBuiltinArray): New class to handle creation of built-in arrays.
+
+ (NewBuiltinArray::DoResolve): Implement guts of array creation. Also take into
+ account creation of one-dimensional arrays.
+
+ (::Emit): Implement to use Newarr and Newobj opcodes accordingly.
+
+ (NewUserdefinedArray::DoResolve): Implement.
+
+ * cs-parser.jay (local_variable_type): Fix up to add the rank to the variable too.
+
+ * typemanager.cs (AddModule): Used to add a ModuleBuilder to the list of modules
+ we maintain inside the TypeManager. This is necessary to perform lookups on the
+ module builder.
+
+ (LookupType): Update to perform GetType on the module builders too.
+
+ * driver.cs (Driver): Add the ModuleBuilder to the list maintained by the TypeManager.
+
+ * exprssion.cs (NewUserdefinedArray::Emit): Implement.
+
+2001-10-23 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (New::DoResolve): Implement guts of array creation.
+
+ (New::FormLookupType): Rename to FormArrayType and modify ever so slightly.
+
+2001-10-27 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Fix bug I introduced lsat night that broke
+ Delegates.
+
+ (Expression.Resolve): Report a 246 error (can not resolve name)
+ if we find a SimpleName in the stream.
+
+ (Expression.ResolveLValue): Ditto.
+
+ (Expression.ResolveWithSimpleName): This function is a variant of
+ ResolveName, this one allows SimpleNames to be returned without a
+ warning. The only consumer of SimpleNames is MemberAccess
+
+2001-10-26 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Invocation::DoResolve): Catch SimpleNames that
+ might arrive here. I have my doubts that this is correct.
+
+ * statement.cs (Lock): Implement lock statement.
+
+ * cs-parser.jay: Small fixes to support `lock' and `using'
+
+ * cs-tokenizer.cs: Remove extra space
+
+ * driver.cs: New flag --checked, allows to turn on integer math
+ checking.
+
+ * typemanger.cs: Load methodinfos for Threading.Monitor.Enter and
+ Threading.Monitor.Exit
+
+2001-10-23 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (IndexerAccess::DoResolveLValue): Set the
+ Expression Class to be IndexerAccess.
+
+ Notice that Indexer::DoResolve sets the eclass to Value.
+
+2001-10-22 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer::Emit): Emit code for indexers.
+
+ * assign.cs (IAssignMethod): New interface implemented by Indexers
+ and Properties for handling assignment.
+
+ (Assign::Emit): Simplify and reuse code.
+
+ * expression.cs (IndexerAccess, PropertyExpr): Implement
+ IAssignMethod, clean up old code.
+
+2001-10-22 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (ImplementsInterface): New method to determine if a type
+ implements a given interface. Provides a nice cache too.
+
+ * expression.cs (ImplicitReferenceConversion): Update checks to use the above
+ method.
+
+ (ConvertReferenceExplicit): Ditto.
+
+ * delegate.cs (Delegate::Populate): Update to define the parameters on the
+ various methods, with correct names etc.
+
+ * class.cs (Operator::OpType): New members Operator.UnaryPlus and
+ Operator.UnaryNegation.
+
+ * cs-parser.jay (operator_declarator): Be a little clever in the case where
+ we have a unary plus or minus operator.
+
+ * expression.cs (Unary): Rename memebers of Operator enum to UnaryPlus and
+ UnaryMinus.
+
+ * everywhere : update accordingly.
+
+ * everywhere : Change Negate and BitComplement to LogicalNot and OnesComplement
+ respectively.
+
+ * class.cs (Method::Define): For the case where we are implementing a method
+ inherited from an interface, we need to set the MethodAttributes.Final flag too.
+ Also set MethodAttributes.NewSlot and MethodAttributes.HideBySig.
+
+2001-10-21 Ravi Pratap <ravi@ximian.com>
+
+ * interface.cs (FindMembers): Implement to work around S.R.E
+ lameness.
+
+ * typemanager.cs (IsInterfaceType): Implement.
+
+ (FindMembers): Update to handle interface types too.
+
+ * expression.cs (ImplicitReferenceConversion): Re-write bits which
+ use IsAssignableFrom as that is not correct - it doesn't work.
+
+ * delegate.cs (DelegateInvocation): Derive from ExpressionStatement
+ and accordingly override EmitStatement.
+
+ * expression.cs (ConvertReferenceExplicit): Re-write similary, this time
+ using the correct logic :-)
+
+2001-10-19 Ravi Pratap <ravi@ximian.com>
+
+ * ../errors/cs-11.cs : Add to demonstrate error -11
+
+2001-10-17 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs (Assign::Resolve): Resolve right hand side first, and
+ then pass this as a hint to ResolveLValue.
+
+ * expression.cs (FieldExpr): Add Location information
+
+ (FieldExpr::LValueResolve): Report assignment to readonly
+ variable.
+
+ (Expression::ExprClassFromMemberInfo): Pass location information.
+
+ (Expression::ResolveLValue): Add new method that resolves an
+ LValue.
+
+ (Expression::DoResolveLValue): Default invocation calls
+ DoResolve.
+
+ (Indexers): New class used to keep track of indexers in a given
+ Type.
+
+ (IStackStore): Renamed from LValue, as it did not really describe
+ what this did. Also ResolveLValue is gone from this interface and
+ now is part of Expression.
+
+ (ElementAccess): Depending on the element access type
+
+ * typemanager.cs: Add `indexer_name_type' as a Core type
+ (System.Runtime.CompilerServices.IndexerNameAttribute)
+
+ * statement.cs (Goto): Take a location.
+
+2001-10-18 Ravi Pratap <ravi@ximian.com>
+
+ * delegate.cs (Delegate::VerifyDelegate): New method to verify
+ if two delegates are compatible.
+
+ (NewDelegate::DoResolve): Update to take care of the case when
+ we instantiate a delegate from another delegate.
+
+ * typemanager.cs (FindMembers): Don't even try to look up members
+ of Delegate types for now.
+
+2001-10-18 Ravi Pratap <ravi@ximian.com>
+
+ * delegate.cs (NewDelegate): New class to take care of delegate
+ instantiation.
+
+ * expression.cs (New): Split the delegate related code out into
+ the NewDelegate class.
+
+ * delegate.cs (DelegateInvocation): New class to handle delegate
+ invocation.
+
+ * expression.cs (Invocation): Split out delegate related code into
+ the DelegateInvocation class.
+
+2001-10-17 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (New::DoResolve): Implement delegate creation fully
+ and according to the spec.
+
+ (New::DoEmit): Update to handle delegates differently.
+
+ (Invocation::FullMethodDesc): Fix major stupid bug thanks to me
+ because of which we were printing out arguments in reverse order !
+
+ * delegate.cs (VerifyMethod): Implement to check if the given method
+ matches the delegate.
+
+ (FullDelegateDesc): Implement.
+
+ (VerifyApplicability): Implement.
+
+ * expression.cs (Invocation::DoResolve): Update to accordingly handle
+ delegate invocations too.
+
+ (Invocation::Emit): Ditto.
+
+ * ../errors/cs1593.cs : Added.
+
+ * ../errors/cs1594.cs : Added.
+
+ * delegate.cs (InstanceExpression, TargetMethod): New properties.
+
+2001-10-16 Ravi Pratap <ravi@ximian.com>
+
+ * typemanager.cs (intptr_type): Core type for System.IntPtr
+
+ (InitCoreTypes): Update for the same.
+
+ (iasyncresult_type, asynccallback_type): Ditto.
+
+ * delegate.cs (Populate): Fix to use System.Intptr as it is indeed
+ correct.
+
+ * typemanager.cs (AddDelegateType): Store a pointer to the Delegate class
+ too.
+
+ * delegate.cs (ConstructorBuilder, InvokeBuilder, ...): New members to hold
+ the builders for the 4 members of a delegate type :-)
+
+ (Populate): Define the BeginInvoke and EndInvoke methods on the delegate
+ type.
+
+ * expression.cs (New::DoResolve): Implement guts for delegate creation.
+
+ * ../errors/errors.txt : Update for an error (-11) which only we catch :-)
+
+2001-10-15 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Break::Emit): Implement.
+ (Continue::Emit): Implement.
+
+ (For::Emit): Track old being/end loops; Set Begin loop, ack end loop
+ (While::Emit): Track old being/end loops; Set Begin loop, ack end loop
+ (Do::Emit): Track old being/end loops; Set Begin loop, ack end loop
+ (Foreach::Emit): Track old being/end loops; Set Begin loop, ack
+ end loop
+
+ * codegen.cs (EmitContext::LoopEnd, EmitContext::LoopBegin): New
+ properties that track the label for the current loop (begin of the
+ loop and end of the loop).
+
+2001-10-15 Ravi Pratap <ravi@ximian.com>
+
+ * delegate.cs (Emit): Get rid of it as there doesn't seem to be any ostensible
+ use of emitting anything at all.
+
+ * class.cs, rootcontext.cs : Get rid of calls to the same.
+
+ * delegate.cs (DefineDelegate): Make sure the class we define is also sealed.
+
+ (Populate): Define the constructor correctly and set the implementation
+ attributes.
+
+ * typemanager.cs (delegate_types): New hashtable to hold delegates that
+ have been defined.
+
+ (AddDelegateType): Implement.
+
+ (IsDelegateType): Implement helper method.
+
+ * delegate.cs (DefineDelegate): Use AddDelegateType instead of AddUserType.
+
+ * expression.cs (New::DoResolve): Check if we are trying to instantiate a delegate type
+ and accordingly handle it.
+
+ * delegate.cs (Populate): Take TypeContainer argument.
+ Implement bits to define the Invoke method. However, I still haven't figured out
+ how to take care of the native int bit :-(
+
+ * cs-parser.jay (delegate_declaration): Fixed the bug that I had introduced :-)
+ Qualify the name of the delegate, not its return type !
+
+ * expression.cs (ImplicitReferenceConversion): Implement guts of implicit array
+ conversion.
+
+ (StandardConversionExists): Checking for array types turns out to be recursive.
+
+ (ConvertReferenceExplicit): Implement array conversion.
+
+ (ExplicitReferenceConversionExists): New method to determine precisely that :-)
+
+2001-10-12 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (delegate_declaration): Store the fully qualified
+ name as it is a type declaration.
+
+ * delegate.cs (ReturnType, Name): Rename members to these. Make them
+ readonly.
+
+ (DefineDelegate): Renamed from Define. Does the same thing essentially,
+ as TypeContainer::DefineType.
+
+ (Populate): Method in which all the definition of the various methods (Invoke)
+ etc is done.
+
+ (Emit): Emit any code, if necessary. I am not sure about this really, but let's
+ see.
+
+ (CloseDelegate): Finally creates the delegate.
+
+ * class.cs (TypeContainer::DefineType): Update to define delegates.
+ (Populate, Emit and CloseType): Do the same thing here too.
+
+ * rootcontext.cs (ResolveTree, PopulateTypes, EmitCode, CloseTypes): Include
+ delegates in all these operations.
+
+2001-10-14 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: LocalTemporary: a new expression used to
+ reference a temporary that has been created.
+
+ * assign.cs: Handle PropertyAccess back here, so that we can
+ provide the proper semantic access to properties.
+
+ * expression.cs (Expression::ConvertReferenceExplicit): Implement
+ a few more explicit conversions.
+
+ * modifiers.cs: `NEW' modifier maps to HideBySig.
+
+ * expression.cs (PropertyExpr): Make this into an
+ ExpressionStatement, and support the EmitStatement code path.
+
+ Perform get/set error checking, clean up the interface.
+
+ * assign.cs: recognize PropertyExprs as targets, and if so, turn
+ them into toplevel access objects.
+
+2001-10-12 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: PropertyExpr::PropertyExpr: use work around the
+ SRE.
+
+ * typemanager.cs: Keep track here of our PropertyBuilders again to
+ work around lameness in SRE.
+
+2001-10-11 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (LValue::LValueResolve): New method in the
+ interface, used to perform a second resolution pass for LValues.
+
+ (This::DoResolve): Catch the use of this in static methods.
+
+ (This::LValueResolve): Implement.
+
+ (This::Store): Remove warning, assigning to `this' in structures
+ is
+
+ (Invocation::Emit): Deal with invocation of
+ methods on value types. We need to pass the address to structure
+ methods rather than the object itself. (The equivalent code to
+ emit "this" for structures leaves the entire structure on the
+ stack instead of a pointer to it).
+
+ (ParameterReference::DoResolve): Compute the real index for the
+ argument based on whether the method takes or not a `this' pointer
+ (ie, the method is static).
+
+ * codegen.cs (EmitContext::GetTemporaryStorage): Used to store
+ value types returned from functions when we need to invoke a
+ method on the sturcture.
+
+
+2001-10-11 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::DefineType): Method to actually do the business of
+ defining the type in the Modulebuilder or Typebuilder. This is to take
+ care of nested types which need to be defined on the TypeBuilder using
+ DefineNestedMethod.
+
+ (TypeContainer::GetClassBases): Implement. Essentially the code from the
+ methods in RootContext, only ported to be part of TypeContainer.
+
+ (TypeContainer::GetInterfaceOrClass): Ditto.
+
+ (TypeContainer::LookupInterfaceOrClass, ::MakeFQN): Ditto.
+
+ * interface.cs (Interface::DefineInterface): New method. Does exactly
+ what RootContext.CreateInterface did earlier, only it takes care of nested types
+ too.
+
+ (Interface::GetInterfaces): Move from RootContext here and port.
+
+ (Interface::GetInterfaceByName): Same here.
+
+ * rootcontext.cs (ResolveTree): Re-write.
+
+ (PopulateTypes): Re-write.
+
+ * class.cs (TypeContainer::Populate): Populate nested types too.
+ (TypeContainer::Emit): Emit nested members too.
+
+ * typemanager.cs (AddUserType): Do not make use of the FullName property,
+ instead just use the name argument passed in as it is already fully
+ qualified.
+
+ (FindMembers): Check in the Builders to TypeContainer mapping instead of the name
+ to TypeContainer mapping to see if a type is user-defined.
+
+ * class.cs (TypeContainer::CloseType): Implement.
+
+ (TypeContainer::DefineDefaultConstructor): Use Basename, not Name while creating
+ the default constructor.
+
+ (TypeContainer::Populate): Fix minor bug which led to creating default constructors
+ twice.
+
+ (Constructor::IsDefault): Fix up logic to determine if it is the default constructor
+
+ * interface.cs (CloseType): Create the type here.
+
+ * rootcontext.cs (CloseTypes): Re-write to recursively close types by running through
+ the hierarchy.
+
+ Remove all the methods which are now in TypeContainer.
+
+2001-10-10 Ravi Pratap <ravi@ximian.com>
+
+ * delegate.cs (Define): Re-write bits to define the delegate
+ correctly.
+
+2001-10-10 Miguel de Icaza <miguel@ximian.com>
+
+ * makefile: Renamed the compiler to `mcs.exe' instead of compiler.exe
+
+ * expression.cs (ImplicitReferenceConversion): handle null as well
+ as a source to convert to any reference type.
+
+ * statement.cs (Return): Perform any implicit conversions to
+ expected return type.
+
+ Validate use of return statement.
+
+ * codegen.cs (EmitContext): Pass the expected return type here.
+
+ * class.cs (Method, Constructor, Property): Pass expected return
+ type to EmitContext.
+
+2001-10-09 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Make DoResolve take an EmitContext instead of a
+ TypeContainer.
+
+ Replaced `l' and `location' for `loc', for consistency.
+
+ (Error, Warning): Remove unneeded Tc argument.
+
+ * assign.cs, literal.cs, constant.cs: Update to new calling
+ convention.
+
+ * codegen.cs: EmitContext now contains a flag indicating whether
+ code is being generated in a static method or not.
+
+ * cs-parser.jay: DecomposeQI, new function that replaces the old
+ QualifiedIdentifier. Now we always decompose the assembled
+ strings from qualified_identifier productions into a group of
+ memberaccesses.
+
+2001-10-08 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs: Deal with field-less struct types correctly now
+ by passing the size option to Define Type.
+
+ * class.cs: Removed hack that created one static field.
+
+2001-10-07 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: Moved most of the code generation here.
+
+2001-10-09 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (New::DoResolve): Revert changes for array creation, doesn't
+ seem very right.
+
+ (ElementAccess): Remove useless bits for now - keep checks as the spec
+ says.
+
+2001-10-08 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ElementAccess::DoResolve): Remove my crap code
+ and start performing checks according to the spec.
+
+2001-10-07 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (type_suffix*): Remove - they are redundant. Use
+ rank_specifiers instead.
+
+ (rank_specifiers): Change the order in which the rank specifiers are stored
+
+ (local_variable_declaration): Use opt_rank_specifier instead of type_suffixes.
+
+ * expression.cs (ElementAccess): Implement the LValue interface too.
+
+2001-10-06 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ConvertExplicitStandard): Add. Same as ConvertExplicit
+ except that user defined conversions are not included.
+
+ (UserDefinedConversion): Update to use the ConvertExplicitStandard to
+ perform the conversion of the return type, if necessary.
+
+ (New::DoResolve): Check whether we are creating an array or an object
+ and accordingly do the needful.
+
+ (New::Emit): Same here.
+
+ (New::DoResolve): Implement guts of array creation.
+
+ (New::FormLookupType): Helper function.
+
+2001-10-07 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs: Removed most of the code generation here, and move the
+ corresponding code generation bits to the statement classes.
+
+ Added support for try/catch/finalize and throw.
+
+ * cs-parser.jay: Added support for try/catch/finalize.
+
+ * class.cs: Catch static methods having the flags override,
+ virtual or abstract.
+
+ * expression.cs (UserCast): This user cast was not really doing
+ what it was supposed to do. Which is to be born in fully resolved
+ state. Parts of the resolution were being performed at Emit time!
+
+ Fixed this code.
+
+2001-10-05 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs: Implicity convert the result from UserCast.
+
+2001-10-05 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Expression::FindMostEncompassingType): Fix bug which
+ prevented it from working correctly.
+
+ (ConvertExplicit): Make the first try, a call to ConvertImplicitStandard, not
+ merely ConvertImplicit.
+
+2001-10-05 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: Make the LookupTypeContainer function static,
+ and not per-instance.
+
+ * class.cs: Make static FindMembers (the one that takes a Type
+ argument).
+
+ * codegen.cs: Add EmitForeach here.
+
+ * cs-parser.jay: Make foreach a toplevel object instead of the
+ inline expansion, as we need to perform semantic analysis on it.
+
+2001-10-05 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Expression::ImplicitUserConversion): Rename to
+ UserDefinedConversion.
+
+ (Expression::UserDefinedConversion): Take an extra argument specifying
+ whether we look for explicit user conversions too.
+
+ (Expression::ImplicitUserConversion): Make it a call to UserDefinedConversion.
+
+ (UserDefinedConversion): Incorporate support for user defined explicit conversions.
+
+ (ExplicitUserConversion): Make it a call to UserDefinedConversion
+ with the appropriate arguments.
+
+ * cs-parser.jay (cast_expression): Record location too.
+
+ * expression.cs (Cast): Record location info.
+
+ (Expression::ConvertExplicit): Take location argument.
+
+ (UserImplicitCast): Change name to UserCast. Take an extra constructor argument
+ to determine if we are doing explicit conversions.
+
+ (UserCast::Emit): Update accordingly.
+
+ (Expression::ConvertExplicit): Report an error if everything fails.
+
+ * ../errors/cs0030.cs : Add.
+
+2001-10-04 Miguel de Icaza <miguel@ximian.com>
+
+ * modifiers.cs: If the ABSTRACT keyword is present, also set the
+ virtual and newslot bits.
+
+ * class.cs (TypeContainer::RegisterRequiredImplementations):
+ Record methods we need.
+
+ (TypeContainer::MakeKey): Helper function to make keys for
+ MethodBases, since the Methodbase key is useless.
+
+ (TypeContainer::Populate): Call RegisterRequiredImplementations
+ before defining the methods.
+
+ Create a mapping for method_builders_to_methods ahead of time
+ instead of inside a tight loop.
+
+ (::RequireMethods): Accept an object as the data to set into the
+ hashtable so we can report interface vs abstract method mismatch.
+
+2001-10-03 Miguel de Icaza <miguel@ximian.com>
+
+ * report.cs: Make all of it static.
+
+ * rootcontext.cs: Drop object_type and value_type computations, as
+ we have those in the TypeManager anyways.
+
+ Drop report instance variable too, now it is a global.
+
+ * driver.cs: Use try/catch on command line handling.
+
+ Add --probe option to debug the error reporting system with a test
+ suite.
+
+ * report.cs: Add support for exiting program when a probe
+ condition is reached.
+
+2001-10-03 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Binary::DoNumericPromotions): Fix the case when
+ we do a forcible conversion regardless of type, to check if
+ ForceConversion returns a null.
+
+ (Binary::error19): Use location to report error.
+
+ (Unary::error23): Use location here too.
+
+ * ../errors/cs0019.cs : Check in.
+
+ * ../errors/cs0023.cs : Check in.
+
+ * expression.cs (Expression.MemberLookup): Return null for a rather esoteric
+ case of a non-null MethodInfo object with a length of 0 !
+
+ (Binary::ResolveOperator): Flag error if overload resolution fails to find
+ an applicable member - according to the spec :-)
+ Also fix logic to find members in base types.
+
+ (Unary::ResolveOperator): Same here.
+
+ (Unary::report23): Change name to error23 and make first argument a TypeContainer
+ as I was getting thoroughly confused between this and error19 :-)
+
+ * expression.cs (Expression::ImplicitUserConversion): Re-write fully
+ (::FindMostEncompassedType): Implement.
+ (::FindMostEncompassingType): Implement.
+ (::StandardConversionExists): Implement.
+
+ (UserImplicitCast): Re-vamp. We now need info about most specific
+ source and target types so that we can do the necessary conversions.
+
+ (Invocation::MakeUnionSet): Completely re-write to make sure we form a proper
+ mathematical union with no duplicates.
+
+2001-10-03 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs (RootContext::PopulateTypes): Populate containers
+ in order from base classes to child classes, so that we can in
+ child classes look up in our parent for method names and
+ attributes (required for handling abstract, virtual, new, override
+ constructs: we need to instrospect our base class, and if we dont
+ populate the classes in order, the introspection might be
+ incorrect. For example, a method could query its parent before
+ the parent has any methods and would determine that the parent has
+ no abstract methods (while it could have had them)).
+
+ (RootContext::CreateType): Record the order in which we define the
+ classes.
+
+2001-10-02 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer::Populate): Also method definitions can
+ fail now, keep track of this.
+
+ (TypeContainer::FindMembers): Implement support for
+ DeclaredOnly/noDeclaredOnly flag.
+
+ (Constructor::Emit) Return the ConstructorBuilder.
+
+ (Method::Emit) Return the MethodBuilder.
+ Check for abstract or virtual methods to be public.
+
+ * rootcontext.cs (RootContext::CreateType): Register all the
+ abstract methods required for the class to be complete and the
+ interface methods that must be implemented.
+
+ * cs-parser.jay: Report error 501 (method requires body if it is
+ not marked abstract or extern).
+
+ * expression.cs (TypeOf::Emit): Implement.
+
+ * typemanager.cs: runtime_handle_type, new global type.
+
+ * class.cs (Property::Emit): Generate code for properties.
+
+2001-10-02 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Unary::ResolveOperator): Find operators on base type
+ too - we now conform exactly to the spec.
+
+ (Binary::ResolveOperator): Same here.
+
+ * class.cs (Operator::Define): Fix minor quirk in the tests.
+
+ * ../errors/cs0215.cs : Added.
+
+ * ../errors/cs0556.cs : Added.
+
+ * ../errors/cs0555.cs : Added.
+
+2001-10-01 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-tokenizer.cs: Reimplemented Location to be a struct with a
+ single integer which is really efficient
+
+2001-10-01 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Expression::ImplicitUserConversion): Use location
+ even in the case when we are examining True operators.
+
+ * class.cs (Operator::Define): Perform extensive checks to conform
+ with the rules for operator overloading in the spec.
+
+ * expression.cs (Expression::ImplicitReferenceConversion): Implement
+ some of the other conversions mentioned in the spec.
+
+ * typemanager.cs (array_type): New static member for the System.Array built-in
+ type.
+
+ (cloneable_interface): For System.ICloneable interface.
+
+ * driver.cs (Driver::Driver): Initialize TypeManager's core types even before
+ we start resolving the tree and populating types.
+
+ * ../errors/errors.txt : Update for error numbers -7, -8, -9, -10
+
+2001-10-01 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Expression::ExprClassFromMemberInfo,
+ Expression::Literalize): Create literal expressions from
+ FieldInfos which are literals.
+
+ (ConvertNumericExplicit, ImplicitNumericConversion): Fix a few
+ type casts, because they were wrong. The test suite in tests
+ caught these ones.
+
+ (ImplicitNumericConversion): ushort to ulong requires a widening
+ cast.
+
+ Int32 constant to long requires widening cast as well.
+
+ * literal.cs (LongLiteral::EmitLong): Do not generate i4 constants
+ for integers because the type on the stack is not i4.
+
+2001-09-30 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (report118): require location argument.
+
+ * parameter.cs: Do not dereference potential null value.
+
+ * class.cs: Catch methods that lack the `new' keyword when
+ overriding a name. Report warnings when `new' is used without
+ anything being there to override.
+
+ * modifiers.cs: Handle `NEW' as MethodAttributes.NewSlot.
+
+ * class.cs: Only add constructor to hashtable if it is non-null
+ (as now constructors can fail on define).
+
+ (TypeManager, Class, Struct): Take location arguments.
+
+ Catch field instance initialization in structs as errors.
+
+ accepting_filter: a new filter for FindMembers that is static so
+ that we dont create an instance per invocation.
+
+ (Constructor::Define): Catch errors where a struct constructor is
+ parameterless
+
+ * cs-parser.jay: Pass location information for various new
+ constructs.
+
+ * delegate.cs (Delegate): take a location argument.
+
+ * driver.cs: Do not call EmitCode if there were problesm in the
+ Definition of the types, as many Builders wont be there.
+
+ * decl.cs (Decl::Decl): Require a location argument.
+
+ * cs-tokenizer.cs: Handle properly hex constants that can not fit
+ into integers, and find the most appropiate integer for it.
+
+ * literal.cs: Implement ULongLiteral.
+
+ * rootcontext.cs: Provide better information about the location of
+ failure when CreateType fails.
+
+2001-09-29 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs (RootContext::PopulateTypes): Populates structs
+ as well.
+
+ * expression.cs (Binary::CheckShiftArguments): Add missing type
+ computation.
+ (Binary::ResolveOperator): Add type to the logical and and logical
+ or, Bitwise And/Or and Exclusive Or code paths, it was missing
+ before.
+
+ (Binary::DoNumericPromotions): In the case where either argument
+ is ulong (and most signed types combined with ulong cause an
+ error) perform implicit integer constant conversions as well.
+
+2001-09-28 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (UserImplicitCast): Method should always be
+ non-null.
+ (Invocation::BetterConversion): Simplified test for IntLiteral.
+
+ (Expression::ImplicitNumericConversion): Split this routine out.
+ Put the code that performs implicit constant integer conversions
+ here.
+
+ (Expression::Resolve): Become a wrapper around DoResolve so we can
+ check eclass and type being set after resolve.
+
+ (Invocation::Badness): Remove this dead function
+
+ (Binary::ResolveOperator): Do not compute the expensive argumnets
+ unless we have a union for it.
+
+ (Probe::Emit): Is needs to do an isinst and then
+ compare against null.
+
+ (::CanConvert): Added Location argument. If the Location argument
+ is null (Location.Null), then we do not report errors. This is
+ used by the `probe' mechanism of the Explicit conversion. We do
+ not want to generate an error for something that the user
+ explicitly requested to be casted. But the pipeline for an
+ explicit cast first tests for potential implicit casts.
+
+ So for now, if the Location is null, it means `Probe only' to
+ avoid adding another argument. Might have to revise this
+ strategy later.
+
+ (ClassCast): New class used to type cast objects into arbitrary
+ classes (used in Explicit Reference Conversions).
+
+ Implement `as' as well.
+
+ Reverted all the patches from Ravi below: they were broken:
+
+ * The use of `level' as a mechanism to stop recursive
+ invocations is wrong. That was there just to catch the
+ bug with a strack trace but not as a way of addressing
+ the problem.
+
+ To fix the problem we have to *understand* what is going
+ on and the interactions and come up with a plan, not
+ just get things going.
+
+ * The use of the type conversion cache that I proposed
+ last night had an open topic: How does this work across
+ protection domains. A user defined conversion might not
+ be public in the location where we are applying the
+ conversion, a different conversion might be selected
+ (ie, private A->B (better) but public B->A (worse),
+ inside A, A->B applies, but outside it, B->A will
+ apply).
+
+ * On top of that (ie, even if the above is solved),
+ conversions in a cache need to be abstract. Ie, `To
+ convert from an Int to a Short use an OpcodeCast', not
+ `To convert from an Int to a Short use the OpcodeCast on
+ the variable 5' (which is what this patch was doing).
+
+2001-09-28 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation::ConversionExists): Re-write to use
+ the conversion cache
+
+ (Expression::ConvertImplicit): Automatic bailing out if level != 0. Also
+ cache all conversions done, not just user-defined ones.
+
+ (Invocation::BetterConversion): The real culprit. Use ConversionExists
+ to determine if a conversion exists instead of acutually trying to
+ perform the conversion. It's faster too.
+
+ (Expression::ConvertExplicit): Modify to use ConversionExists to check
+ and only then attempt the implicit conversion.
+
+2001-09-28 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (ConvertImplicit): Use a cache for conversions
+ already found. Check level of recursion and bail out if necessary.
+
+2001-09-28 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (string_concat_string_string, string_concat_object_object):
+ Export standard methods that we expect for string operations.
+
+ * statement.cs (Block::UsageWarning): Track usage of variables and
+ report the errors for not used variables.
+
+ * expression.cs (Conditional::Resolve, ::Emit): Implement ?:
+ operator.
+
+2001-09-27 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs: remove unnneded code
+
+ * expression.cs: Removed BuiltinTypeAccess class
+
+ Fix the order in which implicit conversions are
+ done.
+
+ The previous fixed dropped support for boxed conversions (adding a
+ test to the test suite now)
+
+ (UserImplicitCast::CanConvert): Remove test for source being null,
+ that code is broken. We should not feed a null to begin with, if
+ we do, then we should track the bug where the problem originates
+ and not try to cover it up here.
+
+ Return a resolved expression of type UserImplicitCast on success
+ rather than true/false. Ravi: this is what I was talking about,
+ the pattern is to use a static method as a "constructor" for
+ objects.
+
+ Also, do not create arguments until the very last minute,
+ otherwise we always create the arguments even for lookups that
+ will never be performed.
+
+ (UserImplicitCast::Resolve): Eliminate, objects of type
+ UserImplicitCast are born in a fully resolved state.
+
+ * typemanager.cs (InitCoreTypes): Init also value_type
+ (System.ValueType).
+
+ * expression.cs (Cast::Resolve): First resolve the child expression.
+
+ (LValue): Add new method AddressOf to be used by
+ the `&' operator.
+
+ Change the argument of Store to take an EmitContext instead of an
+ ILGenerator, because things like FieldExpr need to be able to call
+ their children expression to generate the instance code.
+
+ (Expression::Error, Expression::Warning): Sugar functions for
+ reporting errors.
+
+ (Expression::MemberLookup): Accept a TypeContainer instead of a
+ Report as the first argument.
+
+ (Expression::ResolvePrimary): Killed. I still want to improve
+ this as currently the code is just not right.
+
+ (Expression::ResolveMemberAccess): Simplify, but it is still
+ wrong.
+
+ (Unary::Resolve): Catch errors in AddressOf operators.
+
+ (LocalVariableReference::Emit, ::Store, ::AddressOf): typecast
+ index to a byte for the short-version, or the compiler will choose
+ the wrong Emit call, which generates the wrong data.
+
+ (ParameterReference::Emit, ::Store): same.
+
+ (FieldExpr::AddressOf): Implement.
+
+ * typemanager.cs: TypeManager: made public variable instead of
+ property.
+
+ * driver.cs: document --fatal.
+
+ * report.cs (ErrorMessage, WarningMessage): new names for the old
+ Error and Warning classes.
+
+ * cs-parser.jay (member_access): Turn built-in access to types
+ into a normal simplename
+
+2001-09-27 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation::BetterConversion): Fix to cope
+ with q being null, since this was introducing a bug.
+
+ * expression.cs (ConvertImplicit): Do built-in conversions first.
+
+2001-09-27 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (UserImplicitCast::Resolve): Fix bug.
+
+2001-09-27 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::AddConstructor): Fix a stupid bug
+ I had introduced long ago (what's new ?).
+
+ * expression.cs (UserImplicitCast::CanConvert): Static method to do
+ the work of all the checking.
+ (ConvertImplicit): Call CanConvert and only then create object if necessary.
+ (UserImplicitCast::CanConvert, ::Resolve): Re-write.
+
+ (Unary::Operator): Rename Add and Subtract to Addition and Subtraction because
+ that is the right way.
+
+ (Invocation::MakeUnionSet): Convenience function to make unions of sets for
+ overloading resolution. Use everywhere instead of cutting and pasting code.
+
+ (Binary::ResolveOperator): Use MakeUnionSet.
+
+ (UserImplicitCast::CanConvert, ::Resolve): Update to take care of the case when
+ we have to convert to bool types. Not complete yet.
+
+2001-09-27 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (TypeManager::CSharpName): support ushort.
+
+ * expression.cs (Expression::TryImplicitIntConversion): Attempts
+ to provide an expression that performsn an implicit constant int
+ conversion (section 6.1.6).
+ (Expression::ConvertImplicitRequired): Reworked to include
+ implicit constant expression conversions.
+
+ (Expression::ConvertNumericExplicit): Finished.
+
+ (Invocation::Emit): If InstanceExpression is null, then it means
+ that we perform a call on this.
+
+2001-09-26 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Unary::Emit): Remove some dead code.
+ (Probe): Implement Resolve and Emit for `is'.
+ (Expression::ConvertImplicitRequired): Attempt to do constant
+ expression conversions here. Maybe should be moved to
+ ConvertImplicit, but I am not sure.
+ (Expression::ImplicitLongConstantConversionPossible,
+ Expression::ImplicitIntConstantConversionPossible): New functions
+ that tell whether is it possible to apply an implicit constant
+ expression conversion.
+
+ (ConvertNumericExplicit): Started work on explicit numeric
+ conversions.
+
+ * cs-parser.jay: Update operator constants.
+
+ * parameter.cs (Parameters::GetParameterInfo): Hook up VerifyArgs
+ (Parameters::GetSignature): Hook up VerifyArgs here.
+ (Parameters::VerifyArgs): Verifies that no two arguments have the
+ same name.
+
+ * class.cs (Operator): Update the operator names to reflect the
+ ones that the spec expects (as we are just stringizing the
+ operator names).
+
+ * expression.cs (Unary::ResolveOperator): Fix bug: Use
+ MethodInfo's ReturnType instead of LookupMethodByBuilder as the
+ previous usage did only work for our methods.
+ (Expression::ConvertImplicit): Handle decimal implicit numeric
+ conversions as well.
+ (Expression::InternalTypeConstructor): Used to invoke constructors
+ on internal types for default promotions.
+
+ (Unary::Emit): Implement special handling for the pre/post
+ increment/decrement for overloaded operators, as they need to have
+ the same semantics as the other operators.
+
+ (Binary::ResolveOperator): ditto.
+ (Invocation::ConversionExists): ditto.
+ (UserImplicitCast::Resolve): ditto.
+
+2001-09-26 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Unary::Emit and Binary::Emit): If we have an overloaded
+ operator, return after emitting body. Regression tests pass again !
+
+ * expression.cs (ConvertImplicit): Take TypeContainer as first argument
+ (Unary::ForceConversion, Binary::ForceConversion): Ditto.
+ (Invocation::OverloadResolve): Ditto.
+ (Invocation::BetterFunction, BetterConversion, ConversionExists): Ditto.
+
+ * everywhere : update calls to the above methods accordingly.
+
+2001-09-26 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs (Assign): Make it inherit from ExpressionStatement.
+
+ * expression.cs (ExpressionStatement): New base class used for
+ expressions that can appear in statements, so that we can provide
+ an alternate path to generate expression that do not leave a value
+ on the stack.
+
+ (Expression::Emit, and all the derivatives): We no longer return
+ whether a value is left on the stack or not. Every expression
+ after being emitted leaves a single value on the stack.
+
+ * codegen.cs (EmitContext::EmitStatementExpression): Use the
+ facilties of ExpressionStatement if possible.
+
+ * cs-parser.jay: Update statement_expression.
+
+2001-09-25 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Change the wording of message
+
+2001-09-25 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Binary::ResolveOperator): Had forgottten to set
+ the type of the expression to the return type of the method if
+ we have an overloaded operator match ! The regression tests pass again !
+ (Unary::ResolveOperator): Ditto.
+
+ * expression.cs (Invocation::ConversionExists): Correct the member lookup
+ to find "op_Implicit", not "implicit" ;-)
+ (UserImplicitCast): New class to take care of user-defined implicit conversions.
+ (ConvertImplicit, ForceConversion): Take TypeContainer argument
+
+ * everywhere : Correct calls to the above accordingly.
+
+ * expression.cs (UserImplicitCast::Resolve, ::Emit): Implement.
+ (ConvertImplicit): Do user-defined conversion if it exists.
+
+2001-09-24 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs: track location.
+ (Resolve): Use implicit conversions on assignment.
+
+ * literal.cs: Oops. Not good, Emit of short access values should
+ pass (Bytes) or the wrong argument will be selected.
+
+ * expression.cs (Unary::Emit): Emit code for -expr.
+
+ (Unary::ResolveOperator): Handle `Substract' for non-constants
+ (substract from zero from the non-constants).
+ Deal with Doubles as well.
+
+ (Expression::ConvertImplicitRequired): New routine that reports an
+ error if no implicit conversion exists.
+
+ (Invocation::OverloadResolve): Store the converted implicit
+ expressions if we make them
+
+2001-09-24 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (ConstructorInitializer): Take a Location argument.
+ (ConstructorBaseInitializer): Same here.
+ (ConstructorThisInitializer): Same here.
+
+ * cs-parser.jay : Update all calls accordingly.
+
+ * expression.cs (Unary, Binary, New): Take location argument.
+ Update accordingly everywhere.
+
+ * cs-parser.jay : Update all calls to the above to take a location
+ argument.
+
+ * class.cs : Ditto.
+
+2001-09-24 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation::BetterFunction): Take TypeContainer argument
+ (Invocation::BetterConversion): Same here
+ (Invocation::ConversionExists): Ditto.
+
+ (Invocation::ConversionExists): Implement.
+
+2001-09-22 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (OverloadResolve): Improve some more to catch errors 1502 and 1503
+ Also take an additional TypeContainer argument.
+
+ * All over : Pass in TypeContainer as argument to OverloadResolve.
+
+ * typemanager.cs (CSharpName): Update to check for the string type and return
+ that too.
+
+ * expression.cs (Invocation::FullMethodDesc): New static method to return a string fully describing
+ a given method.
+
+2001-09-21 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Invocation::OverloadResolve): Re-write to conform more to the spec.
+ (Invocation::BetterFunction): Implement.
+ (Invocation::BetterConversion): Implement.
+ (Invocation::ConversionExists): Skeleton, no implementation yet.
+
+ Okay, things work fine !
+
+2001-09-21 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs: declare and load enum_type, delegate_type and
+ void_type.
+
+ * expression.cs (Expression::Emit): Now emit returns a value that
+ tells whether a value is left on the stack or not. This strategy
+ might be reveted tomorrow with a mechanism that would address
+ multiple assignments.
+ (Expression::report118): Utility routine to report mismatches on
+ the ExprClass.
+
+ (Unary::Report23): Report impossible type/operator combination
+ utility function.
+
+ (Unary::IsIncrementableNumber): Whether the type can be
+ incremented or decremented with add.
+ (Unary::ResolveOperator): Also allow enumerations to be bitwise
+ complemented.
+ (Unary::ResolveOperator): Implement ++, !, ~,
+
+ (Invocation::Emit): Deal with new Emit convetion.
+
+ * All Expression derivatives: Updated their Emit method to return
+ whether they leave values on the stack or not.
+
+ * codegen.cs (CodeGen::EmitStatement): Pop values left on the
+ stack for expressions that are statements.
+
+2001-09-20 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (LValue): New interface. Must be implemented by
+ LValue objects.
+ (LocalVariableReference, ParameterReference, FieldExpr): Implement
+ LValue interface.
+
+ * assign.cs (Assign::Emit, Assign::Resolve): Use new LValue
+ interface for generating code, simplifies the code.
+
+2001-09-20 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (everywhere): Comment out return statements in ::Resolve
+ methods to avoid the warnings.
+
+2001-09-20 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs (parse): Report error 2001 if we can not open the
+ source file.
+
+ * expression.cs (SimpleName::ResolveSimpleName): Error if we can
+ not resolve it.
+
+ * cs-parser.jay (QualifierIdentifier): Pass location to SimpleName
+ object.
+
+ * statement.cs (Block::EmitMeta): Reuse the count across all the variables,
+ otherwise nested blocks end up with the same index.
+
+ * codegen.cs (CodeGen::EmitTopBlock): Pass initial sequence
+
+ * expression.cs: Instead of having FIXMEs in the Resolve
+ functions, throw exceptions so it is obvious that we are facing a
+ bug.
+
+ * cs-parser.jay (invocation_expression): Pass Location information.
+
+ * codegen.cs (CodeGen::Save, CodeGen::CodeGen, CodeGen::Basename):
+ Use a basename for those routines because .NET does not like paths
+ on them.
+
+ * class.cs (TypeContainer::AddMethod): Do not call DefineName if the name was
+ already defined.
+
+2001-09-19 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (TypeManager::CoreLookupType): A function to make sure that we
+ are loading the correct data types (throws an exception if not).
+ (TypeManager::InitCoreTypes): Use CoreLookupType
+
+ * expression.cs (Unary::ResolveOperator): return the child
+ expression for expressions which are just +expr.
+ (Unary::ResolveOperator): Return negative literals for -LITERAL
+ expressions (otherwise they are Unary {Literal}).
+ (Invocation::Badness): Take into account `Implicit constant
+ expression conversions'.
+
+ * literal.cs (LongLiteral): Implement long literal class.
+ (IntLiteral): export the `Value' of the intliteral.
+
+2001-09-19 Ravi Pratap <ravi@ximian.com>
+
+ * expression.cs (Binary::Emit): Finally get the emission right ! Woo!
+
+ * class.cs (Operator::Define): Change the methodname prefix to 'op_'
+ instead of 'Operator'
+
+ * expression.cs (Binary::ResolveOperator): Update accordingly.
+ (Unary::Operator): Change names to 'Add' and 'Subtract' instead 'Plus'
+ and 'Minus'
+
+ * cs-parser.jay (unary_expression): Update to use the new names.
+
+ * gen-treedump.cs (GetUnary): Same here.
+
+ * expression.cs (Unary::Resolve): Implement.
+ (Binary::ResolveOperator): Re-write bits to quietly continue if no overloaded
+ operators are found instead of making noise ;-)
+ (Unary::ResolveOperator): New method to do precisely the same thing which
+ Binary::ResolveOperator does for Binary expressions.
+ (Unary.method, .Arguments): Add.
+ (Unary::OperName): Implement.
+ (Unary::ForceConversion): Copy and Paste !
+
+ * class.cs (Operator::Define): Fix a small bug for the case when we have
+ a unary operator.
+
+ * expression.cs (Unary::Emit): Implement. Need to find the right Opcodes
+ for the inbuilt operators. Only overloading works for now ;-)
+
+2001-09-18 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (CheckedExpr::Resolve, CheckedExpr::Emit,
+ UnCheckedExpr::Resolve, UnCheckedExpr::Emit): Implement.
+
+ * expression.cs (This::Emit): Implement.
+ (This::Resolve): Implement.
+ (TypeOf:Resolve): Implement.
+ (Expression::ResolveSimpleName): Add an implicit this to instance
+ field references.
+ (MemberAccess::Resolve): Deal with Parameters and Fields.
+ Bind instance variable to Field expressions.
+ (FieldExpr::Instance): New field used to track the expression that
+ represents the object instance.
+ (FieldExpr::Resolve): Track potential errors from MemberLookup not
+ binding
+ (FieldExpr::Emit): Implement.
+
+ * codegen.cs (EmitIf, EmitStatement, EmitBlock): Propagate whether
+ the last instruction contains a return opcode to avoid generating
+ the last `ret' instruction (this generates correct code, and it is
+ nice to pass the peverify output).
+
+ * class.cs (TypeContainer::EmitFieldInitializers): Implement field
+ initializer for static and instance variables.
+ (Constructor::Emit): Allow initializer to be null in the case of
+ static constructors. Only emit initializer for instance
+ constructors.
+
+ (TypeContainer::FindMembers): Return a null array if there are no
+ matches.
+
+ Also fix the code for the MemberTypes.Method branch, as it was not
+ scanning that for operators (or tried to access null variables before).
+
+ * assign.cs (Assign::Emit): Handle instance and static fields.
+
+ * TODO: Updated.
+
+ * driver.cs: Stop compilation if there are parse errors.
+
+ * cs-parser.jay (constructor_declaration): Provide default base
+ initializer for non-static constructors.
+ (constructor_declarator): Do not provide a default base
+ initializers if none was specified.
+ Catch the fact that constructors should not have parameters.
+
+ * class.cs: Do not emit parent class initializers for static
+ constructors, that should be flagged as an error.
+
+2001-09-18 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (RegisterMethodBuilder): Remove : it's unnecessary.
+ Move back code into TypeContainer::Populate.
+
+2001-09-18 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::AddConstructor): Fix the check to
+ compare against Name, not Basename.
+ (Operator::OpType): Change Plus and Minus to Add and Subtract.
+
+ * cs-parser.jay : Update accordingly.
+
+ * class.cs (TypeContainer::FindMembers): For the case where we are searching
+ for methods, don't forget to look into the operators too.
+ (RegisterMethodBuilder): Helper method to take care of this for
+ methods, constructors and operators.
+ (Operator::Define): Completely revamp.
+ (Operator.OperatorMethod, MethodName): New fields.
+ (TypeContainer::Populate): Move the registering of builders into
+ RegisterMethodBuilder.
+ (Operator::Emit): Re-write.
+
+ * expression.cs (Binary::Emit): Comment out code path to emit method
+ invocation stuff for the case when we have a user defined operator. I am
+ just not able to get it right !
+
+2001-09-17 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Expression::OverloadResolve): Drop TypeContainer
+ argument.
+
+ (Expression::MemberLookup): Provide a version that allows to
+ specify the MemberTypes and BindingFlags.
+
+ * statement.cs (Block::GetVariableInfo): Forgot to recurse here,
+ so it was not fetching variable information from outer blocks.
+
+ * modifiers.cs: (Modifiers::TypeAttr): Invert condition on
+ Beforefieldinit as it was buggy.
+
+ * rootcontext.cs (::LookupInterfaceOrClass): Removed an Error -200
+ that Ravi put here.
+
+ * class.cs (Constructor::Emit): Only emit if block is not null.
+ (TypeContainer::EmitDefaultConstructor): Removed routine, now we
+ deal with this by semantically definining it as if the user had
+ done it.
+
+ (TypeContainer::FindMembers): Removed ad-hoc hack to deal with
+ constructors as we now "emit" them at a higher level.
+
+ (TypeContainer::DefineDefaultConstructor): Used to define the
+ default constructors if none was provided.
+
+ (ConstructorInitializer): Add methods Resolve and Emit.
+
+ * expression.cs: Cast to ConstructorInfo instead of MethodInfo
+
+2001-09-17 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::EmitDefaultConstructor): Register
+ the default constructor builder with our hashtable for methodbuilders
+ to methodcores.
+
+ * expression.cs (Invocation::OverloadResolve): Add a check for pd == null
+ and argument_count is 0 in which case we have a match.
+ (Binary::ResolveOperator): More null checking and miscellaneous coding
+ style cleanup.
+
+2001-09-17 Ravi Pratap <ravi@ximian.com>
+
+ * rootcontext.cs (IsNameSpace): Compare against null.
+
+ * everywhere : Correct spelling to 'Greater' and to 'Subtract'
+
+ * class.cs (Operator::OpType): Change names to match the ones in Binary::Operator
+ and Unary::Operator.
+
+ * cs-parser.jay (operator_declaration, CheckBinaryOperator, CheckUnaryOperator): Update
+ accordingly.
+
+ * expression.cs (Binary::method): New member to hold the MethodBase for the case when
+ we have overloaded operators.
+ (Binary::ResolveOperator): Implement the part which does the operator overload
+ resolution.
+
+ * class.cs (Operator::Emit): Implement.
+ (TypeContainer::Emit): Emit the operators we have too.
+
+ * expression.cs (Binary::Emit): Update to emit the appropriate code for
+ the case when we have a user-defined operator.
+
+2001-09-17 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs: Fix bug: tree.Namespaces might be null.
+
+2001-09-16 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (EmitStaticFieldInitializers, EmitFieldInitializers): Make public.
+ (TypeContainer::EmitConstructor): Remove and move code into Contructor::Emit.
+ (Constructor::Emit): Implement.
+ (EmitStaticFieldInitializers, EmitFieldInitializers): Ensure we return immediately
+ if we have no work to do.
+ (TypeContainer::Emit): Pass in TypeContainer as argument to the constructor's
+ Emit method.
+
+ * interface.cs (Interface::InterfaceAttr): Re-write to be more correct and complete.
+ (Interface::IsTopLevel): Add. Same as TypeContainer::IsTopLevel.
+
+ * class.cs (TypeContainer::IsTopLevel): Modify to use parent.Parent instead
+ of parent.parent.
+
+2001-09-15 Ravi Pratap <ravi@ximian.com>
+
+ * tree.cs (Tree::namespaces): New hashtable to keep track of namespaces
+ in the source.
+ (Tree::RecordNamespace): Method to do what the name says ;-)
+ (Tree::Namespaces): Property to get at the namespaces hashtable.
+
+ * cs-parser.jay (namespace_declaration): Call RecordNamespace to
+ keep track.
+
+ * rootcontext.cs (IsNamespace): Fixed it :-)
+
+2001-09-14 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer::FindMembers): Add support for
+ constructors.
+ (MethodCore): New class that encapsulates both the shared aspects
+ of a Constructor and a Method.
+ (Method, Constructor): Factored pieces into MethodCore.
+
+ * driver.cs: Added --fatal which makes errors throw exceptions.
+ Load System assembly as well as part of the standard library.
+
+ * report.cs: Allow throwing exceptions on errors for debugging.
+
+ * modifiers.cs: Do not use `parent', instead use the real type
+ container to evaluate permission settings.
+
+ * class.cs: Put Ravi's patch back in. He is right, and we will
+ have to cope with the
+
+2001-09-14 Ravi Pratap <ravi@ximian.com>
+
+ * modifiers.cs (TypeAttr, MethodAttr, FieldAttr): Map protected internal to
+ FamORAssem, not FamANDAssem.
+
+2001-09-14 Miguel de Icaza <miguel@ximian.com>
+
+ * driver.cs: Added --parse option that only parses its input files
+ and terminates.
+
+ * class.cs: Reverted last change from Ravi to IsTopLevel. That is
+ incorrect. IsTopLevel is not used to tell whether an object is
+ root_types or not (that can be achieved by testing this ==
+ root_types). But to see if this is a top-level *class* (not
+ necessarly our "toplevel" container).
+
+2001-09-14 Ravi Pratap <ravi@ximian.com>
+
+ * enum.cs (Enum::Define): Modify to call the Lookup method on the
+ parent instead of a direct call to GetType.
+
+2001-09-14 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::TypeAttr): Remove property code and move it into
+ Modifiers.TypeAttr. This should just be a call to that method.
+
+ * modifiers.cs (TypeAttr): Re-write and take an extra argument, the TypeContainer
+ object so that we can determine if we are top-level or not.
+
+ * delegate.cs (Delegate::Define): Update call to TypeAttr method to pass in the
+ TypeContainer too.
+
+ * enum.cs (Enum::Define): Ditto.
+
+ * modifiers.cs (FieldAttr): Re-write.
+
+ * class.cs (TypeContainer::IsTopLevel): Change accessibility to public.
+ (TypeContainer::HaveStaticConstructor): New property to provide access
+ to precisely that info.
+
+ * modifiers.cs (MethodAttr): Re-write.
+ (EventAttr): Remove altogether as there seems to be no ostensible use for it.
+
+ * class.cs (TypeContainer::IsTopLevel): Re-write. root_types doesn't seem to be the parent
+ of top-level types as claimed.
+
+2001-09-13 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (MemberLookup): Fruitless attempt to lookup
+ constructors. Maybe I need to emit default constructors? That
+ might be it (currently .NET emits this for me automatically).
+ (Invocation::OverloadResolve): Cope with Arguments == null.
+ (Invocation::EmitArguments): new function, shared by the new
+ constructor and us.
+ (Invocation::Emit): Handle static and instance methods. Emit
+ proper call instruction for virtual or non-virtual invocations.
+ (New::Emit): Implement.
+ (New::Resolve): Implement.
+ (MemberAccess:Resolve): Implement.
+ (MethodGroupExpr::InstanceExpression): used conforming to the spec
+ to track instances.
+ (FieldExpr::Resolve): Set type.
+
+ * support.cs: Handle empty arguments.
+
+ * cs-parser.jay (CompositeLookup, QualifierIdentifier,
+ SimpleLookup): Auxiliary routines to help parse a qualifier
+ identifier.
+
+ Update qualifier_identifier rule.
+
+ * codegen.cs: Removed debugging messages.
+
+ * class.cs: Make this a global thing, this acts just as a "key" to
+ objects that we might have around.
+
+ (Populate): Only initialize method_builders_to_methods once.
+
+ * expression.cs (PropertyExpr): Initialize type from the
+ PropertyType.
+
+ * codegen.cs (EmitContext::EmitBoolExpression): Use propper
+ Resolve pattern. Attempt to implicitly convert value to boolean.
+ Emit code.
+
+ * expression.cs: Set the type for the int32/int32 argument case.
+ (Binary::ResolveOperator): Set the return type to boolean for
+ comparission operators
+
+ * typemanager.cs: Remove debugging print code.
+
+ (Invocation::Resolve): resolve type.
+
+ * class.cs: Allocate a MemberInfo of the correct size, as the code
+ elsewhere depends on the test to reflect the correct contents.
+
+ (Method::) Keep track of parameters, due to System.Reflection holes
+
+ (TypeContainer::Populate): Keep track of MethodBuilders to Method
+ mapping here.
+
+ (TypeContainer::FindMembers): Use ArrayList and then copy an array
+ of the exact size and return that.
+
+ (Class::LookupMethodByBuilder): New function that maps
+ MethodBuilders to its methods. Required to locate the information
+ on methods because System.Reflection bit us again.
+
+ * support.cs: New file, contains an interface ParameterData and
+ two implementations: ReflectionParameters and InternalParameters
+ used to access Parameter information. We will need to grow this
+ as required.
+
+ * expression.cs (Invocation::GetParameterData): implement a cache
+ and a wrapper around the ParameterData creation for methods.
+ (Invocation::OverloadResolve): Use new code.
+
+2001-09-13 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::EmitField): Remove and move into
+ (Field::Define): here and modify accordingly.
+ (Field.FieldBuilder): New member.
+ (TypeContainer::Populate): Update accordingly.
+ (TypeContainer::FindMembers): Implement.
+
+2001-09-13 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: (VariableInfo::VariableType): New field to be
+ initialized with the full type once it is resolved.
+
+2001-09-12 Miguel de Icaza <miguel@ximian.com>
+
+ * parameter.cs (GetParameterInfo): Use a type cache to compute
+ things only once, and to reuse this information
+
+ * expression.cs (LocalVariableReference::Emit): Implement.
+ (OpcodeCast::Emit): fix.
+
+ (ParameterReference::Resolve): Implement.
+ (ParameterReference::Emit): Implement.
+
+ * cs-parser.jay: Fix bug introduced by Ravi, variable initializers
+ that are expressions need to stay as Expressions.
+
+ * typemanager.cs (CSharpName): Returns the C# name of a type if
+ possible.
+
+ * expression.cs (Expression::ConvertImplicit): New function that
+ implements implicit type conversions.
+
+ (Expression::ImplicitReferenceConversion): Implements implicit
+ reference conversions.
+
+ (EmptyCast): New type for transparent casts.
+
+ (OpcodeCast): New type for casts of types that are performed with
+ a sequence of bytecodes.
+
+ (BoxedCast): New type used for casting value types into reference
+ types. Emits a box opcode.
+
+ (Binary::DoNumericPromotions): Implements numeric promotions of
+ and computation of the Binary::Type.
+
+ (Binary::EmitBranchable): Optimization.
+
+ (Binary::Emit): Implement code emission for expressions.
+
+ * typemanager.cs (TypeManager): Added two new core types: sbyte
+ and byte.
+
+2001-09-12 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::FindMembers): Method which does exactly
+ what Type.FindMembers does, only we don't have to use reflection. No
+ implementation yet.
+
+ * typemanager.cs (typecontainers): New hashtable to hold the corresponding
+ typecontainer objects as we need to get at them.
+ (TypeManager::AddUserType): Overload to take an extra argument, the TypeContainer.
+
+ * rootcontext.cs : Correspondingly modify called to AddUserType to pass the
+ typecontainer object.
+
+ * expression.cs (MemberLookup): Modify signature to take a RootContext object instead
+ of just a Report object.
+
+2001-09-11 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Event::Define): Go back to using the prefixes "add_" and
+ "remove_"
+ (TypeContainer::Populate): Now define the delegates of the type too.
+ (TypeContainer.Delegates): Property to access the list of delegates defined
+ in the type.
+
+ * delegates.cs (Delegate::Define): Implement partially.
+
+ * modifiers.cs (TypeAttr): Handle more flags.
+
+2001-09-11 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Indexer::Define): Fix for loop iteration condition to be just <
+ and not <=
+ (Operator::Define): Re-write logic to get types by using the LookupType method
+ instead of blindly doing a Type.GetType ! How stupid can I get ;-) ?
+ (Indexer::Define): Ditto.
+ (Event::Define): Ditto.
+ (Property::Define): Ditto.
+
+2001-09-10 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::Populate): Now define operators too.
+ (TypeContainer.Operators): New property to access the list of operators
+ in a type.
+ (Operator.OperatorMethodBuilder): New member to hold the method builder
+ for the operator we are defining.
+ (Operator::Define): Implement.
+
+2001-09-10 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Event::Define): Make the prefixes of the accessor methods
+ addOn_ and removeOn_
+
+ * genericparser.cs (GenericParser::error): Overloaded method to handle the case
+ of the location being passed in too. Ideally, this should go later since all
+ error reporting should be done through the Report object.
+
+ * class.cs (TypeContainer.Indexers): New property to access the list of indexers.
+ (Populate): Iterate thru the indexers we have and define them too.
+ (Indexer.GetMethodBuilder, .SetMethodBuilder): New members to hold the method builders
+ for the get and set accessors.
+ (Indexer::Define): Implement.
+
+2001-09-09 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (Binary::Resolve): Beginning of it. I scratched
+ my previous implementation, did not work.
+
+ * typemanager.cs: Add a couple of missing types (the longs).
+
+ * literal.cs: Use TypeManager.bool_type instead of getting it.
+
+ * expression.cs (EventExpr): New kind of expressions.
+ (Expressio::ExprClassFromMemberInfo): finish
+
+2001-09-08 Miguel de Icaza <miguel@ximian.com>
+
+ * assign.cs: Emit stores to static fields differently.
+
+2001-09-08 Ravi Pratap <ravi@ximian.com>
+
+ * Merge in changes and adjust code to tackle conflicts. Backed out my
+ code in Assign::Resolve ;-)
+
+2001-09-08 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (CheckAttributeTarget): Modify call to error to use
+ instead Report.Error and also pass in the location.
+ (CSharpParser::Lexer): New readonly property to return the reference
+ to the Tokenizer object.
+ (declare_local_variables): Use Report.Error with location instead of plain
+ old error.
+ (CheckDef): Ditto.
+
+ * class.cs (Operator::CheckUnaryOperator): Move into cs-parser.jay.
+ (Operator.CheckBinaryOperator): Ditto.
+
+ * cs-parser.jay (operator_declarator): Update accordingly.
+
+ * cs-parser.jay (CheckUnaryOperator): Modify to use Report.Error
+ (CheckBinaryOperator): Same here.
+
+ * rootcontext.cs (LookupType): Add an extra lookup which simply does a lookup
+ on the name without any prefixes of namespace names etc. This is because we
+ already might have something already fully qualified like
+ 'System.Console.WriteLine'
+
+ * assign.cs (Resolve): Begin implementation. Stuck ;-)
+
+2001-09-07 Ravi Pratap <ravi@ximian.com>
+
+ * cs-tokenizer.cs (location): Return a string which also contains
+ the file name.
+
+ * expression.cs (ElementAccess): New class for expressions of the
+ type 'element access.'
+ (BaseAccess): New class for expressions of the type 'base access.'
+ (CheckedExpr, UnCheckedExpr): New classes for Checked and Unchecked expressions
+ respectively.
+
+ * cs-parser.jay (element_access): Implement action.
+ (base_access): Implement actions.
+ (checked_expression, unchecked_expression): Implement.
+
+ * cs-parser.jay (local_variable_type): Correct and implement.
+ (type_suffixes, type_suffix_list, type_suffix): Implement actions.
+
+ * cs-tokenizer.cs (real_type_suffix): Comment out the extra getchar.
+
+ * cs-parser.jay (rank_specifiers): Remove space while concatenating the type's
+ name and the specifiers.
+
+ * interface.cs (InterfaceAttr): New property to return the corresponding TypeAttributes
+
+ * rootcontext.cs (CreateInterface): Use the InterfaceAttr property instead of
+ making them all public ;-)
+
+ * cs-parser.jay (error): Remove entirely as we have an implementation in the base
+ class anyways.
+
+2001-09-07 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (ExprClassFromMemberInfo): Return FieldExpr and
+ PropertyExprs.
+ (FieldExpr, PropertyExprs): New resolved expressions.
+ (SimpleName::MemberStaticCheck): Perform static checks for access
+ to non-static fields on static methods. Maybe this should be
+ generalized for MemberAccesses.
+ (SimpleName::ResolveSimpleName): More work on simple name
+ resolution.
+
+ * cs-parser.jay (primary_expression/qualified_identifier): track
+ the parameter index.
+
+ * codegen.cs (CodeGen::Save): Catch save exception, report error.
+ (EmitContext::EmitBoolExpression): Chain to expression generation
+ instead of temporary hack.
+ (::EmitStatementExpression): Put generic expression code generation.
+
+ * assign.cs (Assign::Emit): Implement variable assignments to
+ local variables, parameters and fields.
+
+2001-09-06 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Block::GetVariableInfo): New method, returns the
+ VariableInfo for a variable name in a block.
+ (Block::GetVariableType): Implement in terms of GetVariableInfo
+
+ * literal.cs (IntLiteral::Emit, FloatLiteral::Emit,
+ DoubleLiteral::Emit, CharLiteral::Emit, BoolLiteral::Emit): Implement
+
+2001-09-06 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (operator_declaration): Continue on my quest : update
+ to take attributes argument.
+ (event_declaration): Ditto.
+ (enum_declaration): Ditto.
+ (indexer_declaration): Ditto.
+
+ * class.cs (Operator::Operator): Update constructor accordingly.
+ (Event::Event): Ditto.
+
+ * delegate.cs (Delegate::Delegate): Same here.
+
+ * enum.cs (Enum::Enum): Same here.
+
+2001-09-05 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (CheckAttributeTarget): Update to use the right error number.
+
+ * ../tests/cs0658.cs : New file to demonstrate error 0658.
+
+ * attribute.cs (Attributes): New class to encapsulate all attributes which were
+ being passed around as an arraylist.
+ (Attributes::AddAttribute): Method to add attribute sections.
+
+ * cs-parser.jay (opt_attributes): Modify actions to use the new Attributes class.
+ (struct_declaration): Update accordingly.
+ (constant_declaration): Update.
+ (field_declaration): Update.
+ (method_header): Update.
+ (fixed_parameter): Update.
+ (parameter_array): Ditto.
+ (property_declaration): Ditto.
+ (destructor_declaration): Ditto.
+
+ * class.cs (Struct::Struct): Update constructors accordingly.
+ (Class::Class): Ditto.
+ (Field::Field): Ditto.
+ (Method::Method): Ditto.
+ (Property::Property): Ditto.
+ (TypeContainer::OptAttribute): update property's return type.
+
+ * interface.cs (Interface.opt_attributes): New member.
+ (Interface::Interface): Update to take the extra Attributes argument.
+
+ * parameter.cs (Parameter::Parameter): Ditto.
+
+ * constant.cs (Constant::Constant): Ditto.
+
+ * interface.cs (InterfaceMemberBase): New OptAttributes field.
+ (InterfaceMemberBase::InterfaceMemberBase): Update constructor to take
+ the attributes as a parameter.
+ (InterfaceProperty): Update constructor call.
+ (InterfaceEvent): Ditto.
+ (InterfaceMethod): Ditto.
+ (InterfaceIndexer): Ditto.
+
+ * cs-parser.jay (interface_indexer_declaration): Update call to constructor to
+ pass the attributes too.
+ (interface_event_declaration): Ditto.
+ (interface_property_declaration): Ditto.
+ (interface_method_declaration): Ditto.
+ (interface_declaration): Ditto.
+
+2001-09-05 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (Method::Define): Track the "static Main" definition to
+ create an entry point.
+
+ * rootcontext.cs (RootContext::EntryPoint): MethodInfo that holds the
+ EntryPoint if we find it.
+
+ * codegen.cs (EmitContext::EmitInvocation): Emit invocations.
+ (EmitContext::ig): Make this variable public.
+
+ * driver.cs: Make the default output file be the first file name
+ with the .exe extension.
+
+ Detect empty compilations
+
+ Handle various kinds of output targets. Handle --target and
+ rename -t to --dumper.
+
+ * expression.cs, literal.cs, assign.cs, constant.cs: All `Resolve'
+ methods inherited from Expression return now an Expression. This
+ will is used during the tree rewriting as we resolve them during
+ semantic analysis.
+
+ (Expression::MemberLookup): Implements the MemberLookup (7.3) from
+ the spec. Missing entirely is the information about
+ accessability of elements of it.
+
+ (Expression::ExprClassFromMemberInfo): New constructor for
+ Expressions that creates a fully initialized Expression based on
+ a MemberInfo that is one of Eventinfo, FieldINfo, PropertyInfo or
+ a Type.
+
+ (Invocation::Resolve): Begin implementing resolution of invocations.
+
+ * literal.cs (StringLiteral): Implement Emit.
+
+2001-09-05 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (error): Add new modifier because we are hiding an inherited
+ member.
+
+2001-09-04 Ravi Pratap <ravi@ximian.com>
+
+ * cs-parser.jay (attribute_arguments): Implement actions.
+ (attribute): Fix bug in production. Implement action.
+ (attribute_list): Implement.
+ (attribute_target): Implement.
+ (attribute_target_specifier, opt_target_specifier): Implement
+ (CheckAttributeTarget): New method to check if the attribute target
+ is valid.
+ (attribute_section): Implement.
+ (opt_attributes): Implement.
+
+ * attribute.cs : New file to handle attributes.
+ (Attribute): Class to hold attribute info.
+
+ * cs-parser.jay (opt_attribute_target_specifier): Remove production
+ (attribute_section): Modify production to use 2 different rules to
+ achieve the same thing. 1 s/r conflict down !
+ Clean out commented, useless, non-reducing dimension_separator rules.
+
+ * class.cs (TypeContainer.attributes): New member to hold list
+ of attributes for a type.
+ (Struct::Struct): Modify to take one more argument, the attribute list.
+ (Class::Class): Ditto.
+ (Field::Field): Ditto.
+ (Method::Method): Ditto.
+ (Property::Property): Ditto.
+
+ * cs-parser.jay (struct_declaration): Update constructor call to
+ pass in the attributes too.
+ (class_declaration): Ditto.
+ (constant_declaration): Ditto.
+ (field_declaration): Ditto.
+ (method_header): Ditto.
+ (fixed_parameter): Ditto.
+ (parameter_array): Ditto.
+ (property_declaration): Ditto.
+
+ * constant.cs (Constant::Constant): Update constructor similarly.
+ Use System.Collections.
+
+ * parameter.cs (Parameter::Parameter): Update as above.
+
+2001-09-02 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (TypeContainer::AddDelegate): New method to add a delegate.
+ (TypeContainer.delegates): New member to hold list of delegates.
+
+ * cs-parser.jay (delegate_declaration): Implement the action correctly
+ this time as I seem to be on crack ;-)
+
+2001-09-02 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs (RootContext::IsNamespace): new function, used to
+ tell whether an identifier represents a namespace.
+
+ * expression.cs (NamespaceExpr): A namespace expression, used only
+ temporarly during expression resolution.
+ (Expression::ResolveSimpleName, ::ResolvePrimary, ::ResolveName):
+ utility functions to resolve names on expressions.
+
+2001-09-01 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs: Add hook for StatementExpressions.
+
+ * class.cs: Fix inverted test for static flag in methods.
+
+2001-09-02 Ravi Pratap <ravi@ximian.com>
+
+ * class.cs (Operator::CheckUnaryOperator): Correct error number used
+ to make it coincide with MS' number.
+ (Operator::CheckBinaryOperator): Ditto.
+
+ * ../errors/errors.txt : Remove error numbers added earlier.
+
+ * ../errors/cs1019.cs : Test case for error # 1019
+
+ * ../errros/cs1020.cs : Test case for error # 1020
+
+ * cs-parser.jay : Clean out commented cruft.
+ (dimension_separators, dimension_separator): Comment out. Ostensibly not
+ used anywhere - non-reducing rule.
+ (namespace_declarations): Non-reducing rule - comment out.
+
+ * enum.cs (Enum::AddEnum): Rename to AddEnumMember as I was getting confused
+ with TypeContainer::AddEnum.
+
+ * delegate.cs : New file for delegate handling classes.
+ (Delegate): Class for declaring delegates.
+
+ * makefile : Update.
+
+ * cs-parser.jay (delegate_declaration): Implement.
+
+2001-09-01 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * class.cs (Event::Define): Implement.
+ (Event.EventBuilder): New member.
+
+ * class.cs (TypeContainer::Populate): Update to define all enums and events
+ we have.
+ (Events): New property for the events arraylist we hold. Shouldn't we move to using
+ readonly fields for all these cases ?
+
+2001-08-31 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * class.cs (Property): Revamp to use the convention of making fields readonly.
+ Accordingly modify code elsewhere.
+
+ * class.cs : Apply patch from Mr. Mandar <go_mono@hotmail.com> for implementing
+ the Define method of the Property class.
+
+ * class.cs : Clean up applied patch and update references to variables etc. Fix
+ trivial bug.
+ (TypeContainer::Populate): Update to define all the properties we have. Also
+ define all enumerations.
+
+ * enum.cs (Define): Implement.
+
+2001-08-31 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * cs-parser.jay (overloadable_operator): The semantic value is an
+ enum of the Operator class.
+ (operator_declarator): Implement actions.
+ (operator_declaration): Implement.
+
+ * class.cs (Operator::CheckUnaryOperator): New static method to help in checking
+ validity of definitions.
+ (Operator::CheckBinaryOperator): Static method to check for binary operators
+ (TypeContainer::AddOperator): New method to add an operator to a type.
+
+ * cs-parser.jay (indexer_declaration): Added line to actually call the
+ AddIndexer method so it gets added ;-)
+
+ * ../errors/errors.txt : Update to include new error numbers. Are these numbers
+ already taken care of by the MS compiler ?
+
+2001-08-29 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * class.cs (Operator): New class for operator declarations.
+ (Operator::OpType): Enum for the various operators.
+
+2001-08-29 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * class.cs (TypeContainer::AddIndexer): Remove FIXME comment. We
+ ostensibly handle this in semantic analysis.
+
+ * cs-parser.jay (general_catch_clause): Comment out
+ (specific_catch_clauses, specific_catch_clause): Ditto.
+ (opt_general_catch_clause, opt_specific_catch_clauses): Ditto
+ (catch_args, opt_catch_args): New productions.
+ (catch_clause): Rewrite to use the new productions above
+ (catch_clauses): Modify accordingly.
+ (opt_catch_clauses): New production to use in try_statement
+ (try_statement): Revamp. Basically, we get rid of one unnecessary rule
+ and re-write the code in the actions to extract the specific and
+ general catch clauses by being a little smart ;-)
+
+ * ../tests/try.cs : Fix. It's not 'finalize' my friend, it's 'finally' !
+ Hooray, try and catch statements parse fine !
+
+2001-08-28 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * statement.cs (Block::GetVariableType): Fix logic to extract the type
+ string from the hashtable of variables.
+
+ * cs-parser.jay (event_accessor_declarations): Trivial fix. Man, how did
+ I end up making that mistake ;-)
+ (catch_clauses): Fixed gross error which made Key and Value of the
+ DictionaryEntry the same : $1 !!
+
+2001-08-28 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * cs-tokenizer.cs (initTokens): Add keywords 'add' and 'remove'
+
+ * cs-parser.jay (event_declaration): Correct to remove the semicolon
+ when the add and remove accessors are specified.
+
+2001-08-28 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * cs-parser.jay (IndexerDeclaration): New helper class to hold
+ information about indexer_declarator.
+ (indexer_declarator): Implement actions.
+ (parsing_indexer): New local boolean used to keep track of whether
+ we are parsing indexers or properties. This is necessary because
+ implicit_parameters come into picture even for the get accessor in the
+ case of an indexer.
+ (get_accessor_declaration, set_accessor_declaration): Correspondingly modified.
+
+ * class.cs (Indexer): New class for indexer declarations.
+ (TypeContainer::AddIndexer): New method to add an indexer to a type.
+ (TypeContainer::indexers): New member to hold list of indexers for the
+ type.
+
+2001-08-27 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * cs-parser.jay (add_accessor_declaration): Implement action.
+ (remove_accessor_declaration): Implement action.
+ (event_accessors_declaration): Implement
+ (variable_declarators): swap statements for first rule - trivial.
+
+ * class.cs (Event): New class to hold information about event
+ declarations.
+ (TypeContainer::AddEvent): New method to add an event to a type
+ (TypeContainer::events): New member to hold list of events.
+
+ * cs-parser.jay (event_declaration): Implement actions.
+
+2001-08-27 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * cs-parser.jay (dim_separators): Implement. Make it a string
+ concatenating all the commas together, just as they appear.
+ (opt_dim_separators): Modify accordingly
+ (rank_specifiers): Update accordingly. Basically do the same
+ thing - instead, collect the brackets here.
+ (opt_rank_sepcifiers): Modify accordingly.
+ (array_type): Modify to actually return the complete type string
+ instead of ignoring the rank_specifiers.
+ (expression_list): Implement to collect the expressions
+ (variable_initializer): Implement. We make it a list of expressions
+ essentially so that we can handle the array_initializer case neatly too.
+ (variable_initializer_list): Implement.
+ (array_initializer): Make it a list of variable_initializers
+ (opt_array_initializer): Modify accordingly.
+
+ * expression.cs (New::NType): Add enumeration to help us
+ keep track of whether we have an object/delegate creation
+ or an array creation.
+ (New:NewType, New::Rank, New::Indices, New::Initializers): New
+ members to hold data about array creation.
+ (New:New): Modify to update NewType
+ (New:New): New Overloaded contructor for the array creation
+ case.
+
+ * cs-parser.jay (array_creation_expression): Implement to call
+ the overloaded New constructor.
+
+2001-08-26 Ravi Pratap <ravi@che.iitm.ac.in>
+
+ * class.cs (TypeContainer::Constructors): Return member
+ constructors instead of returning null.
+
+2001-08-26 Miguel de Icaza <miguel@ximian.com>
+
+ * typemanager.cs (InitCoreTypes): Initialize the various core
+ types after we have populated the type manager with the user
+ defined types (this distinction will be important later while
+ compiling corlib.dll)
+
+ * expression.cs, literal.cs, assign.cs, constant.cs: Started work
+ on Expression Classification. Now all expressions have a method
+ `Resolve' and a method `Emit'.
+
+ * codegen.cs, cs-parser.jay: Fixed the bug that stopped code
+ generation from working. Also add some temporary debugging
+ code.
+
+2001-08-24 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs: Lots of code generation pieces. This is only the
+ beginning, will continue tomorrow with more touches of polish. We
+ handle the fundamentals of if, while, do, for, return. Others are
+ trickier and I need to start working on invocations soon.
+
+ * gen-treedump.cs: Bug fix, use s.Increment here instead of
+ s.InitStatement.
+
+ * codegen.cs (EmitContext): New struct, used during code
+ emission to keep a context. Most of the code generation will be
+ here.
+
+ * cs-parser.jay: Add embedded blocks to the list of statements of
+ this block. So code generation proceeds in a top down fashion.
+
+2001-08-23 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs: Add support for multiple child blocks.
+
+2001-08-22 Miguel de Icaza <miguel@ximian.com>
+
+ * codegen.cs (EmitCode): New function, will emit the code for a
+ Block of code given a TypeContainer and its ILGenerator.
+
+ * statement.cs (Block): Standard public readonly optimization.
+ (Block::Block constructors): Link children.
+ (Block::Child): Child Linker.
+ (Block::EmitVariables): Emits IL variable declarations.
+
+ * class.cs: Drop support for MethodGroups here, delay until
+ Semantic Analysis.
+ (Method::): Applied the same simplification that I did before, and
+ move from Properties to public readonly fields.
+ (Method::ParameterTypes): Returns the parameter types for the
+ function, and implements a cache that will be useful later when I
+ do error checking and the semantic analysis on the methods is
+ performed.
+ (Constructor::GetCallingConvention): Renamed from CallingConvetion
+ and made a method, optional argument tells whether this is a class
+ or a structure to apply the `has-this' bit.
+ (Method::GetCallingConvention): Implement, returns the calling
+ convention.
+ (Method::Define): Defines the type, a second pass is performed
+ later to populate the methods.
+
+ (Constructor::ParameterTypes): implement a cache similar to the
+ one on Method::ParameterTypes, useful later when we do semantic
+ analysis.
+
+ (TypeContainer::EmitMethod): New method. Emits methods.
+
+ * expression.cs: Removed MethodGroup class from here.
+
+ * parameter.cs (Parameters::GetCallingConvention): new method.
+
+2001-08-21 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer::Populate): Drop RootContext from the
+ argument.
+
+ (Constructor::CallingConvention): Returns the calling convention.
+ (Constructor::ParameterTypes): Returns the constructor parameter
+ types.
+
+ (TypeContainer::AddConstructor): Keep track of default constructor
+ and the default static constructor.
+
+ (Constructor::) Another class that starts using `public readonly'
+ instead of properties.
+
+ (Constructor::IsDefault): Whether this is a default constructor.
+
+ (Field::) use readonly public fields instead of properties also.
+
+ (TypeContainer::TypeAttr, TypeContainer::AddConstructor): Keep
+ track of static constructors; If none is used, turn on
+ BeforeFieldInit in the TypeAttributes.
+
+ * cs-parser.jay (opt_argument_list): now the return can be null
+ for the cases where there are no arguments.
+
+ (constructor_declarator): If there is no implicit `base' or
+ `this', then invoke the default parent constructor.
+
+ * modifiers.cs (MethodAttr): New static function maps a set of
+ modifiers flags into a MethodAttributes enum
+ (FieldAttr): renamed from `Map'. So now we have FieldAttr,
+ MethodAttr, TypeAttr to represent the various mappings where the
+ modifiers are used.
+ (FieldAttr): Map also `readonly' to `FieldAttributes.InitOnly'
+
+2001-08-19 Miguel de Icaza <miguel@ximian.com>
+
+ * parameter.cs (GetParameterInfo): Fix bug where there would be no
+ method arguments.
+
+ * interface.cs (PopulateIndexer): Implemented the code generator
+ for interface indexers.
+
+2001-08-17 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs (InterfaceMemberBase): Now we track the new status
+ here.
+
+ (PopulateProperty): Implement property population. Woohoo! Got
+ Methods and Properties going today.
+
+ Removed all the properties for interfaces, and replaced them with
+ `public readonly' fields.
+
+2001-08-16 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs (AddEvent, AddMethod, AddIndexer, AddProperty):
+ initialize their hashtables/arraylists only when they are needed
+ instead of doing this always.
+
+ * parameter.cs: Handle refs and out parameters.
+
+ * cs-parser.jay: Use an ArrayList to construct the arguments
+ instead of the ParameterCollection, and then cast that to a
+ Parameter[] array.
+
+ * parameter.cs: Drop the use of ParameterCollection and use
+ instead arrays of Parameters.
+
+ (GetParameterInfo): Use the Type, not the Name when resolving
+ types.
+
+2001-08-13 Miguel de Icaza <miguel@ximian.com>
+
+ * parameter.cs: Eliminate the properties Name, Type and ModFlags,
+ and instead use public readonly fields.
+
+ * class.cs: Put back walking code for type containers.
+
+2001-08-11 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (MakeConstant): Code to define constants.
+
+ * rootcontext.cs (LookupType): New function. Used to locate types
+
+
+2001-08-08 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs: OH MY! My trick works! It is amazing how nice
+ this System.Reflection code is. Kudos to Microsoft
+
+ * typemanager.cs: Implement a type cache and avoid loading all
+ types at boot time. Wrap in LookupType the internals. This made
+ the compiler so much faster. Wow. I rule!
+
+ * driver.cs: Make sure we always load mscorlib first (for
+ debugging purposes, nothing really important).
+
+ * Renamespaced things that were on `CSC' to `CIR'. Maybe I should
+ have moved to `CSC' rather than `CIR'. Oh man! The confussion!
+
+ * rootcontext.cs: Lookup types on their namespace; Lookup types
+ on namespaces that have been imported using the `using' keyword.
+
+ * class.cs (TypeContainer::TypeAttr): Virtualize.
+ (Class::TypeAttr): Return attributes suitable for this bad boy.
+ (Struct::TypeAttr): ditto.
+ Handle nested classes.
+ (TypeContainer::) Remove all the type visiting code, it is now
+ replaced with the rootcontext.cs code
+
+ * rootcontext.cs (GetClassBases): Added support for structs.
+
+2001-08-06 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs, statement.cs, class.cs, parameter.cs,
+ rootcontext.cs, gen-treedump.cs, enum.cs, cs-parse.jay:
+ Drop use of TypeRefs, and use strings instead.
+
+2001-08-04 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs:
+
+ * class.cs (Struct::Struct): set the SEALED flags after
+ checking the modifiers.
+ (TypeContainer::TypeAttr): new property, returns the
+ TypeAttributes for a class.
+
+ * cs-parser.jay (type_list): Oops, list production was creating a
+ new list of base types.
+
+ * rootcontext.cs (StdLib): New property.
+ (GetInterfaceTypeByName): returns an interface by type name, and
+ encapsulates error handling here.
+ (GetInterfaces): simplified.
+ (ResolveTree): Encapsulated all the tree resolution here.
+ (CreateClass, GetClassBases, GetInterfaceOrClass): Create class
+ types.
+
+ * driver.cs: Add support for --nostdlib, to avoid loading the
+ default assemblies.
+ (Main): Do not put tree resolution here.
+
+ * rootcontext.cs: Beginning of the class resolution.
+
+2001-08-03 Miguel de Icaza <miguel@ximian.com>
+
+ * rootcontext.cs: Provide better error reporting.
+
+ * cs-parser.jay (interface_base): set our $$ to be interfaces.
+
+ * rootcontext.cs (CreateInterface): Handle the case where there
+ are no parent interfaces.
+
+ (CloseTypes): Routine to flush types at the end.
+ (CreateInterface): Track types.
+ (GetInterfaces): Returns an array of Types from the list of
+ defined interfaces.
+
+ * typemanager.c (AddUserType): Mechanism to track user types (puts
+ the type on the global type hash, and allows us to close it at the
+ end).
+
+2001-08-02 Miguel de Icaza <miguel@ximian.com>
+
+ * tree.cs: Removed RecordType, added RecordClass, RecordStruct and
+ RecordInterface instead.
+
+ * cs-parser.jay: Updated to reflect changes above.
+
+ * decl.cs (Definition): Keep track of the TypeBuilder type that
+ represents this type here. Not sure we will use it in the long
+ run, but wont hurt for now.
+
+ * driver.cs: Smaller changes to accomodate the new code.
+
+ Call ResolveInterfaceBases, Call ResolveClassBases, Save assembly
+ when done.
+
+ * rootcontext.cs (CreateInterface): New method, used to create
+ the System.TypeBuilder type for interfaces.
+ (ResolveInterfaces): new entry point to resolve the interface
+ hierarchy.
+ (CodeGen): Property, used to keep track of the code generator.
+
+2001-07-26 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Add a second production for delegate_declaration
+ with `VOID'.
+
+ (enum_body): Put an opt_comma here instead of putting it on
+ enum_body or enum_member_declarations so we can handle trailing
+ commas on enumeration members. Gets rid of a shift/reduce.
+
+ (type_list): Need a COMMA in the middle.
+
+ (indexer_declaration): Tell tokenizer to recognize get/set
+
+ * Remove old targets.
+
+ * Re-add the parser target.
+
+2001-07-13 Simon Cozens <simon@simon-cozens.org>
+
+ * cs-parser.jay: Add precendence rules for a number of operators
+ ot reduce the number of shift/reduce conflicts in the grammar.
+
+2001-07-17 Miguel de Icaza <miguel@ximian.com>
+
+ * tree.cs: moved IGenerator interface and renamed it to ITreeDump
+ and put it here.
+
+ Get rid of old crufty code.
+
+ * rootcontext.cs: Use this to keep track of the parsed
+ representation and the defined types available to the program.
+
+ * gen-treedump.cs: adjust for new convention.
+
+ * type.cs: Split out the type manager, and the assembly builder
+ from here.
+
+ * typemanager.cs: the type manager will live here now.
+
+ * cil-codegen.cs: And the code generator here.
+
+2001-07-14 Sean MacIsaac <macisaac@ximian.com>
+
+ * makefile: Fixed up for easy making.
+
+2001-07-13 Simon Cozens <simon@simon-cozens.org>
+
+ * cs-parser.jay (rank_specifier): Remove a conflict by reordering
+ the
+
+ (unary_expression): Expand pre_increment_expression and
+ post_decrement_expression to reduce a shift/reduce.
+
+2001-07-11 Simon Cozens
+
+ * cs-tokenizer.cs: Hex numbers should begin with a 0.
+
+ Improve allow_keyword_as_indent name.
+
+2001-06-19 Miguel de Icaza <miguel@ximian.com>
+
+ * Adjustments for Beta2.
+
+2001-06-13 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs: Added `Define' abstract method.
+ (InTransit): new property, used to catch recursive definitions.
+
+ * interface.cs: Implement `Define'.
+
+ * modifiers.cs: Map Modifiers.constants to
+ System.Reflection.TypeAttribute flags.
+
+ * class.cs: Keep track of types and user-defined types.
+ (BuilderInit): New method for creating an assembly
+ (ResolveType): New function to launch the resolution process, only
+ used by interfaces for now.
+
+ * cs-parser.jay: Keep track of Classes, Structs and Interfaces
+ that are inserted into the name space.
+
+2001-06-08 Miguel de Icaza <miguel@ximian.com>
+
+ * ARGH. I have screwed up my tree so many times due to the use of
+ rsync rather than using CVS. Going to fix this at once.
+
+ * driver.cs: Objetify driver. Load assemblies, use assemblies to
+ load types.
+
+2001-06-07 Miguel de Icaza <miguel@ximian.com>
+
+ * Experiment successful: Use System.Type rather that our own
+ version of Type.
+
+2001-05-25 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Removed nsAliases from here.
+
+ Use new namespaces, handle `using XXX;'
+
+ * namespace.cs: Reimplemented namespace handling, use a recursive
+ definition of the class. Now we can keep track of using clauses
+ and catch invalid using clauses.
+
+2001-05-24 Miguel de Icaza <miguel@ximian.com>
+
+ * gen-treedump.cs: Adapted for all the renaming.
+
+ * expression.cs (Expression): this class now has a Type property
+ which returns an expression Type.
+
+ (Probe::, New::, TypeOf::, SizeOf::, Constant::): renamed from
+ `Type', as this has a different meaning now in the base
+
+2001-05-22 Miguel de Icaza <miguel@ximian.com>
+
+ * interface.cs, class.cs: Removed from all the sources the
+ references to signature computation, as we can not do method
+ signature computation during the parsing time, as we are not
+ trying to solve at that point distinguishing:
+
+ class X {
+ void a (Blah x) {}
+ void a (NS.Blah x) {}
+ }
+
+ Which depending on the context might be valid or not, as we do not
+ know if Blah is the same thing as NS.Blah at that point.
+
+ * Redid everything so the code uses TypeRefs now instead of
+ Types. TypeRefs are just temporary type placeholders, that need
+ to be resolved. They initially have a pointer to a string and the
+ current scope in which they are used. This is used later by the
+ compiler to resolve the reference to an actual Type.
+
+ * DeclSpace is no longer a CIR.Type, and neither are
+ TypeContainers (Class and Struct) nor Interfaces nor Enums. They
+ are all DeclSpaces, but no Types.
+
+ * type.cs (TypeRefManager): This implements the TypeRef manager,
+ which keeps track of all the types that need to be resolved after
+ the parsing has finished.
+
+2001-05-13 Miguel de Icaza <miguel@ximian.com>
+
+ * ARGH. We are going to have to store `foreach' as a class rather
+ than resolving it, as we need to verify error 1579 after name
+ resolution. *OR* we could keep a flag that says `This request to
+ IEnumerator comes from a foreach statement' which we can then use
+ to generate the error.
+
+2001-05-10 Miguel de Icaza <miguel@ximian.com>
+
+ * class.cs (TypeContainer.AddMethod): we now add methods to the
+ MethodGroup instead of the method hashtable.
+
+ * expression.cs: Add MethodGroup abstraction, which gets us one
+ step closer to the specification in the way we handle method
+ declarations.
+
+ * cs-parser.jay (primary_expression): qualified_identifier now
+ tried to match up an identifier to a local variable reference or
+ to a parameter reference.
+
+ current_local_parameters is now a parser global variable that
+ points to the current parameters for the block, used during name
+ lookup.
+
+ (property_declaration): Now creates an implicit `value' argument to
+ the set accessor.
+
+2001-05-09 Miguel de Icaza <miguel@ximian.com>
+
+ * parameter.cs: Do not use `param' arguments as part of the
+ signature, per the spec.
+
+2001-05-08 Miguel de Icaza <miguel@ximian.com>
+
+ * decl.cs: Base class for classes, structs and interfaces. This
+ is the "Declaration Space"
+
+ * cs-parser.jay: Use CheckDef for checking declaration errors
+ instead of having one on each function.
+
+ * class.cs: Factor out some code for handling error handling in
+ accordance to the "Declarations" section in the "Basic Concepts"
+ chapter in the ECMA C# spec.
+
+ * interface.cs: Make all interface member classes derive from
+ InterfaceMemberBase.
+
+2001-05-07 Miguel de Icaza <miguel@ximian.com>
+
+ * Many things: all interfaces are parsed and generated in
+ gen-treedump. Support for member variables, constructors,
+ destructors, properties, constants is there.
+
+ Beginning of the IL backend, but very little done, just there for
+ testing purposes.
+
+2001-04-29 Miguel de Icaza <miguel@ximian.com>
+
+ * cs-parser.jay: Fix labeled statement.
+
+ * cs-tokenizer.cs (escape): Escape " and ' always.
+ ref_line, ref_name: keep track of the line/filename as instructed
+ by #line by the compiler.
+ Parse #line.
+
+2001-04-27 Miguel de Icaza <miguel@ximian.com>
+
+ * System.CodeDOM/CodeBinaryOperatorExpression.cs: Rearrange enum
+ to match the values in System.CodeDOM.
+
+ Divid renamed to Divide.
+
+ * System.CodeDOM/CodeForLoopStatement.cs: Always have valid
+ statements.
+ (Statements.set): remove.
+
+ * System.CodeDOM/CodeCatchClause.cs: always have a valid
+ statements.
+
+ * System.CodeDOM/CodeIfStatement.cs: trueStatements and
+ falseStatements always have valid values.
+
+ * cs-parser.jay: Use System.CodeDOM now.
+
--- /dev/null
+thisdir := mcs
+SUBDIRS :=
+include ../build/rules.make
+
+COMPILER_SOURCES = \
+ AssemblyInfo.cs \
+ anonymous.cs \
+ assign.cs \
+ attribute.cs \
+ driver.cs \
+ cs-tokenizer.cs \
+ cfold.cs \
+ class.cs \
+ codegen.cs \
+ const.cs \
+ constant.cs \
+ convert.cs \
+ decl.cs \
+ delegate.cs \
+ enum.cs \
+ ecore.cs \
+ expression.cs \
+ genericparser.cs \
+ interface.cs \
+ iterators.cs \
+ literal.cs \
+ location.cs \
+ modifiers.cs \
+ namespace.cs \
+ parameter.cs \
+ pending.cs \
+ report.cs \
+ rootcontext.cs \
+ statement.cs \
+ support.cs \
+ typemanager.cs \
+ symbolwriter.cs \
+ tree.cs
+
+all_sources = $(COMPILER_SOURCES) cs-parser.cs
+
+DISTFILES = \
+ $(COMPILER_SOURCES) \
+ compiler.csproj \
+ compiler.csproj.user \
+ compiler.doc \
+ compiler.sln \
+ cs-parser.jay \
+ mcs.exe.config \
+ NOTES \
+ TODO
+
+all-local: mcs.exe
+
+install-local: mcs.exe
+ $(MKINSTALLDIRS) $(DESTDIR)$(prefix)/bin
+ $(INSTALL_BIN) mcs.exe $(DESTDIR)$(prefix)/bin
+
+test-local run-test-local:
+
+clean-local:
+ rm -f *.exe *.pdb cs-parser.cs y.output
+
+dist-local: dist-default
+
+mcs.exe: $(all_sources)
+ $(BOOT_COMPILE) /target:exe /out:$@ $^
+
+cs-parser.cs: cs-parser.jay $(topdir)/jay/skeleton.cs
+ $(topdir)/jay/jay -ctv < $(topdir)/jay/skeleton.cs $< >$@
+
+# Testing targets
+
+TIME = time
+
+# This used to be called test, but that conflicts with the global
+# recursive target.
+
+btest: mcs2.exe mcs3.exe
+ ls -l mcs2.exe mcs3.exe
+
+mcs2.exe: mcs.exe
+ $(TIME) $(RUNTIME) ./mcs.exe $(USE_MCS_FLAGS) /target:exe /out:$@ $(all_sources)
+
+mcs3.exe: mcs2.exe
+ $(TIME) $(RUNTIME) ./mcs2.exe $(USE_MCS_FLAGS) /target:exe /out:$@ $(all_sources)
--- /dev/null
+//
+// anonymous.cs: Support for anonymous methods
+//
+// Author:
+// Miguel de Icaza (miguel@ximain.com)
+//
+// (C) 2003 Ximian, Inc.
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ public class AnonymousMethod : Expression {
+ // An array list of AnonymousMethodParameter or null
+ Parameters parameters;
+ Block block;
+
+ public AnonymousMethod (Parameters parameters, Block block, Location l)
+ {
+ this.parameters = parameters;
+ this.block = block;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // Set class type, set type
+ //
+
+ eclass = ExprClass.Value;
+
+ //
+ // This hack means `The type is not accessible
+ // anywhere', we depend on special conversion
+ // rules.
+ //
+ type = typeof (AnonymousMethod);
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ // nothing, as we only exist to not do anything.
+ }
+ }
+}
+
--- /dev/null
+//
+// assign.cs: Assignments.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Martin Baulig (martin@gnome.org)
+//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+//
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// This interface is implemented by expressions that can be assigned to.
+ /// </summary>
+ /// <remarks>
+ /// This interface is implemented by Expressions whose values can not
+ /// store the result on the top of the stack.
+ ///
+ /// Expressions implementing this (Properties, Indexers and Arrays) would
+ /// perform an assignment of the Expression "source" into its final
+ /// location.
+ ///
+ /// No values on the top of the stack are expected to be left by
+ /// invoking this method.
+ /// </remarks>
+ public interface IAssignMethod {
+ //
+ // This method will emit the code for the actual assignment
+ //
+ void EmitAssign (EmitContext ec, Expression source);
+
+ //
+ // This method is invoked before any code generation takes
+ // place, and it is a mechanism to inform that the expression
+ // will be invoked more than once, and that the method should
+ // use temporary values to avoid having side effects
+ //
+ // Example: a [ g () ] ++
+ //
+ void CacheTemporaries (EmitContext ec);
+ }
+
+ /// <summary>
+ /// An Expression to hold a temporary value.
+ /// </summary>
+ /// <remarks>
+ /// The LocalTemporary class is used to hold temporary values of a given
+ /// type to "simulate" the expression semantics on property and indexer
+ /// access whose return values are void.
+ ///
+ /// The local temporary is used to alter the normal flow of code generation
+ /// basically it creates a local variable, and its emit instruction generates
+ /// code to access this value, return its address or save its value.
+ /// </remarks>
+ public class LocalTemporary : Expression, IMemoryLocation {
+ LocalBuilder builder;
+
+ public LocalTemporary (EmitContext ec, Type t)
+ {
+ type = t;
+ eclass = ExprClass.Value;
+ loc = Location.Null;
+ builder = ec.GetTemporaryStorage (t);
+ }
+
+ public void Release (EmitContext ec)
+ {
+ ec.FreeTemporaryStorage (builder);
+ builder = null;
+ }
+
+ public LocalTemporary (LocalBuilder b, Type t)
+ {
+ type = t;
+ eclass = ExprClass.Value;
+ loc = Location.Null;
+ builder = b;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloc, builder);
+ }
+
+ public void Store (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Stloc, builder);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ec.ig.Emit (OpCodes.Ldloca, builder);
+ }
+ }
+
+ /// <summary>
+ /// The Assign node takes care of assigning the value of source into
+ /// the expression represented by target.
+ /// </summary>
+ public class Assign : ExpressionStatement {
+ protected Expression target, source, real_source;
+ protected LocalTemporary temp = null, real_temp = null;
+ protected Assign embedded = null;
+ protected bool is_embedded = false;
+ protected bool must_free_temp = false;
+
+ public Assign (Expression target, Expression source, Location l)
+ {
+ this.target = target;
+ this.source = this.real_source = source;
+ this.loc = l;
+ }
+
+ protected Assign (Assign embedded, Location l)
+ : this (embedded.target, embedded.source, l)
+ {
+ this.is_embedded = true;
+ }
+
+ protected virtual Assign GetEmbeddedAssign (Location loc)
+ {
+ return new Assign (this, loc);
+ }
+
+ public Expression Target {
+ get {
+ return target;
+ }
+
+ set {
+ target = value;
+ }
+ }
+
+ public Expression Source {
+ get {
+ return source;
+ }
+
+ set {
+ source = value;
+ }
+ }
+
+ public static void error70 (EventInfo ei, Location l)
+ {
+ Report.Error (70, l, "The event '" + ei.Name +
+ "' can only appear on the left-side of a += or -= (except when" +
+ " used from within the type '" + ei.DeclaringType + "')");
+ }
+
+ //
+ // Will return either `this' or an instance of `New'.
+ //
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // Create an embedded assignment if our source is an assignment.
+ if (source is Assign)
+ source = embedded = ((Assign) source).GetEmbeddedAssign (loc);
+
+ real_source = source = source.Resolve (ec);
+ if (source == null)
+ return null;
+
+ //
+ // This is used in an embedded assignment.
+ // As an example, consider the statement "A = X = Y = Z".
+ //
+ if (is_embedded && !(source is Constant)) {
+ // If this is the innermost assignment (the "Y = Z" in our example),
+ // create a new temporary local, otherwise inherit that variable
+ // from our child (the "X = (Y = Z)" inherits the local from the
+ // "Y = Z" assignment).
+
+ if (embedded == null) {
+ if (this is CompoundAssign)
+ real_temp = temp = new LocalTemporary (ec, target.Type);
+ else
+ real_temp = temp = new LocalTemporary (ec, source.Type);
+ } else
+ temp = embedded.temp;
+
+ // Set the source to the new temporary variable.
+ // This means that the following target.ResolveLValue () will tell
+ // the target to read it's source value from that variable.
+ source = temp;
+ }
+
+ // If we have an embedded assignment, use the embedded assignment's temporary
+ // local variable as source.
+ if (embedded != null)
+ source = (embedded.temp != null) ? embedded.temp : embedded.source;
+
+ target = target.ResolveLValue (ec, source);
+
+ if (target == null)
+ return null;
+
+ Type target_type = target.Type;
+ Type source_type = real_source.Type;
+
+ // If we're an embedded assignment, our parent will reuse our source as its
+ // source, it won't read from our target.
+ if (is_embedded)
+ type = source_type;
+ else
+ type = target_type;
+ eclass = ExprClass.Value;
+
+ //
+ // If we are doing a property assignment, then
+ // set the `value' field on the property, and Resolve
+ // it.
+ //
+ if (target is PropertyExpr){
+ PropertyExpr property_assign = (PropertyExpr) target;
+
+ if (source_type != target_type){
+ source = Convert.ImplicitConversionRequired (ec, source, target_type, loc);
+ if (source == null)
+ return null;
+ }
+
+ //
+ // FIXME: Maybe handle this in the LValueResolve
+ //
+ if (!property_assign.VerifyAssignable ())
+ return null;
+
+ return this;
+ }
+
+ if (target is IndexerAccess) {
+ return this;
+ }
+
+ if (target is EventExpr) {
+ EventInfo ei = ((EventExpr) target).EventInfo;
+
+ Expression ml = MemberLookup (
+ ec, 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
+ // is allowed to only appear on the left hand of
+ // the += and -= operators
+ //
+ // 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.
+ //
+
+ if (!(source is Binary)) {
+ error70 (ei, loc);
+ return null;
+ } else {
+ Binary tmp = ((Binary) source);
+ if (tmp.Oper != Binary.Operator.Addition &&
+ tmp.Oper != Binary.Operator.Subtraction) {
+ error70 (ei, loc);
+ return null;
+ }
+ }
+ }
+ }
+
+ if (source is New && target_type.IsValueType){
+ New n = (New) source;
+
+ if (n.SetValueTypeVariable (target))
+ return n;
+ else
+ return null;
+ }
+
+ if (target.eclass != ExprClass.Variable && target.eclass != ExprClass.EventAccess){
+ Report.Error (131, loc,
+ "Left hand of an assignment must be a variable, " +
+ "a property or an indexer");
+ return null;
+ }
+
+ if ((source.eclass == ExprClass.Type) && (source is TypeExpr)) {
+ source.Error_UnexpectedKind ("variable or value");
+ return null;
+ } else if (source is MethodGroupExpr){
+ ((MethodGroupExpr) source).ReportUsageError ();
+ return null;
+ }
+
+ if (target_type == source_type)
+ return this;
+
+ //
+ // If this assignemnt/operator was part of a compound binary
+ // operator, then we allow an explicit conversion, as detailed
+ // in the spec.
+ //
+
+ if (this is CompoundAssign){
+ CompoundAssign a = (CompoundAssign) this;
+
+ Binary b = source as Binary;
+ if (b != null && b.IsBuiltinOperator){
+ //
+ // 1. if the source is explicitly convertible to the
+ // target_type
+ //
+
+ source = Convert.ExplicitConversion (ec, source, target_type, loc);
+ if (source == null){
+ Convert.Error_CannotImplicitConversion (loc, source_type, target_type);
+ return null;
+ }
+
+ //
+ // 2. and the original right side is implicitly convertible to
+ // the type of target_type.
+ //
+ if (Convert.ImplicitStandardConversionExists (a.original_source, target_type))
+ return this;
+
+ Convert.Error_CannotImplicitConversion (loc, a.original_source.Type, target_type);
+ return null;
+ }
+ }
+
+ source = Convert.ImplicitConversionRequired (ec, source, target_type, loc);
+ if (source == null)
+ return null;
+
+ // If we're an embedded assignment, we need to create a new temporary variable
+ // for the converted value. Our parent will use this new variable as its source.
+ // The same applies when we have an embedded assignment - in this case, we need
+ // to convert our embedded assignment's temporary local variable to the correct
+ // type and store it in a new temporary local.
+ if (is_embedded || embedded != null) {
+ type = target_type;
+ temp = new LocalTemporary (ec, type);
+ must_free_temp = true;
+ }
+
+ return this;
+ }
+
+ Expression EmitEmbedded (EmitContext ec)
+ {
+ // Emit an embedded assignment.
+
+ if (real_temp != null) {
+ // If we're the innermost assignment, `real_source' is the right-hand
+ // expression which gets assigned to all the variables left of it.
+ // Emit this expression and store its result in real_temp.
+ real_source.Emit (ec);
+ real_temp.Store (ec);
+ }
+
+ if (embedded != null)
+ embedded.EmitEmbedded (ec);
+
+ // This happens when we've done a type conversion, in this case source will be
+ // the expression which does the type conversion from real_temp.
+ // So emit it and store the result in temp; this is the var which will be read
+ // by our parent.
+ if (temp != real_temp) {
+ source.Emit (ec);
+ temp.Store (ec);
+ }
+
+ Expression temp_source = (temp != null) ? temp : source;
+ ((IAssignMethod) target).EmitAssign (ec, temp_source);
+ return temp_source;
+ }
+
+ void ReleaseEmbedded (EmitContext ec)
+ {
+ if (embedded != null)
+ embedded.ReleaseEmbedded (ec);
+
+ if (real_temp != null)
+ real_temp.Release (ec);
+
+ if (must_free_temp)
+ temp.Release (ec);
+ }
+
+ void Emit (EmitContext ec, bool is_statement)
+ {
+ if (target is EventExpr) {
+ ((EventExpr) target).EmitAddOrRemove (ec, source);
+ return;
+ }
+
+ bool use_temporaries = false;
+
+ //
+ // FIXME! We need a way to "probe" if the process can
+ // just use `dup' to propagate the result
+ //
+ IAssignMethod am = (IAssignMethod) target;
+
+ if (this is CompoundAssign){
+ am.CacheTemporaries (ec);
+ use_temporaries = true;
+ }
+
+ if (!is_statement)
+ use_temporaries = true;
+
+ Expression temp_source;
+ if (embedded != null) {
+ temp_source = embedded.EmitEmbedded (ec);
+
+ if (temp != null) {
+ source.Emit (ec);
+ temp.Store (ec);
+ temp_source = temp;
+ }
+ } else
+ temp_source = source;
+
+ if (use_temporaries){
+ //
+ // Doing this for every path is too expensive
+ // I wonder if we can work around this and have a less
+ // expensive path
+ //
+ LocalTemporary tempo;
+
+ tempo = new LocalTemporary (ec, source.Type);
+
+ temp_source.Emit (ec);
+ tempo.Store (ec);
+ am.EmitAssign (ec, tempo);
+ if (!is_statement)
+ tempo.Emit (ec);
+
+ tempo.Release (ec);
+ } else {
+ am.EmitAssign (ec, temp_source);
+ }
+
+ if (embedded != null) {
+ if (temp != null)
+ temp.Release (ec);
+ embedded.ReleaseEmbedded (ec);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec, true);
+ }
+ }
+
+
+ //
+ // This class is used for compound assignments.
+ //
+ class CompoundAssign : Assign {
+ Binary.Operator op;
+ public Expression original_source;
+
+ public CompoundAssign (Binary.Operator op, Expression target, Expression source, Location l)
+ : base (target, source, l)
+ {
+ original_source = source;
+ this.op = op;
+ }
+
+ protected CompoundAssign (CompoundAssign embedded, Location l)
+ : this (embedded.op, embedded.target, embedded.source, l)
+ {
+ this.is_embedded = true;
+ }
+
+ protected override Assign GetEmbeddedAssign (Location loc)
+ {
+ return new CompoundAssign (this, loc);
+ }
+
+ public Expression ResolveSource (EmitContext ec)
+ {
+ return original_source.Resolve (ec);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ original_source = original_source.Resolve (ec);
+ if (original_source == null)
+ return null;
+
+ target = target.Resolve (ec);
+ if (target == null)
+ return null;
+
+ //
+ // Only now we can decouple the original source/target
+ // into a tree, to guarantee that we do not have side
+ // effects.
+ //
+ source = new Binary (op, target, original_source, loc);
+ return base.DoResolve (ec);
+ }
+ }
+}
+
+
+
+
--- /dev/null
+//\r
+// attribute.cs: Attribute Handler\r
+//\r
+// Author: Ravi Pratap (ravi@ximian.com)\r
+//\r
+// Licensed under the terms of the GNU GPL\r
+//\r
+// (C) 2001 Ximian, Inc (http://www.ximian.com)\r
+//\r
+//\r
+\r
+using System;\r
+using System.Diagnostics;\r
+using System.Collections;\r
+using System.Reflection;\r
+using System.Reflection.Emit;\r
+using System.Runtime.InteropServices;\r
+using System.Runtime.CompilerServices;\r
+using System.Text;\r
+\r
+namespace Mono.CSharp {\r
+\r
+ public class Attribute {\r
+ public readonly string Name;\r
+ public readonly ArrayList Arguments;\r
+\r
+ Location Location;\r
+\r
+ public Type Type;\r
+ \r
+ //\r
+ // The following are only meaningful when the attribute\r
+ // being emitted is one of the builtin ones\r
+ //\r
+ AttributeTargets Targets;\r
+ bool AllowMultiple;\r
+ bool Inherited;\r
+\r
+ bool UsageAttr = false;\r
+ \r
+ MethodImplOptions ImplOptions;\r
+ UnmanagedType UnmanagedType;\r
+ CustomAttributeBuilder cb;\r
+ \r
+ /* non-null if named args present after Resolve () is called */\r
+ PropertyInfo [] prop_info_arr;\r
+ FieldInfo [] field_info_arr;\r
+ object [] field_values_arr;\r
+ object [] prop_values_arr;\r
+ \r
+ public Attribute (string name, ArrayList args, Location loc)\r
+ {\r
+ Name = name;\r
+ Arguments = args;\r
+ Location = loc;\r
+ }\r
+\r
+ void Error_InvalidNamedArgument (string name)\r
+ {\r
+ Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +\r
+ "argument. Named attribute arguments must be fields which are not " +\r
+ "readonly, static or const, or properties with a set accessor which "+\r
+ "are not static.");\r
+ }\r
+\r
+ static void Error_AttributeArgumentNotValid (Location loc)\r
+ {\r
+ Report.Error (182, loc,\r
+ "An attribute argument must be a constant expression, typeof " +\r
+ "expression or array creation expression");\r
+ }\r
+\r
+ static void Error_AttributeConstructorMismatch (Location loc)\r
+ {\r
+ Report.Error (-6, loc,\r
+ "Could not find a constructor for this argument list.");\r
+ }\r
+ \r
+ private Type CheckAttributeType (EmitContext ec) {\r
+ Type t;\r
+ bool isattributeclass = true;\r
+ \r
+ t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);\r
+ if (t != null) {\r
+ isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);\r
+ if (isattributeclass)\r
+ return t;\r
+ }\r
+ t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);\r
+ if (t != null) {\r
+ if (t.IsSubclassOf (TypeManager.attribute_type))\r
+ return t;\r
+ }\r
+ if (!isattributeclass) {\r
+ Report.Error (616, Location, "'" + Name + "': is not an attribute class");\r
+ return null;\r
+ }\r
+ if (t != null) {\r
+ Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");\r
+ return null;\r
+ }\r
+ Report.Error (\r
+ 246, Location, "Could not find attribute '" + Name + "' (are you" +\r
+ " missing a using directive or an assembly reference ?)");\r
+ return null;\r
+ }\r
+\r
+ public Type ResolveType (EmitContext ec)\r
+ {\r
+ Type = CheckAttributeType (ec);\r
+ return Type;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Validates the guid string\r
+ /// </summary>\r
+ bool ValidateGuid (string guid)\r
+ {\r
+ try {\r
+ new Guid (guid);\r
+ return true;\r
+ } catch {\r
+ Report.Error (647, Location, "Format of GUID is invalid: " + guid);\r
+ return false;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Given an expression, if the expression is a valid attribute-argument-expression\r
+ // returns an object that can be used to encode it, or null on failure.\r
+ //\r
+ public static bool GetAttributeArgumentExpression (Expression e, Location loc, out object result)\r
+ {\r
+ if (e is Constant) {\r
+ result = ((Constant) e).GetValue ();\r
+ return true;\r
+ } else if (e is TypeOf) {\r
+ result = ((TypeOf) e).TypeArg;\r
+ return true;\r
+ } else if (e is ArrayCreation){\r
+ result = ((ArrayCreation) e).EncodeAsAttribute ();\r
+ if (result != null)\r
+ return true;\r
+ }\r
+\r
+ result = null;\r
+ Error_AttributeArgumentNotValid (loc);\r
+ return false;\r
+ }\r
+ \r
+ public CustomAttributeBuilder Resolve (EmitContext ec)\r
+ {\r
+ if (Type == null)\r
+ Type = CheckAttributeType (ec);\r
+ if (Type == null)\r
+ return null;\r
+\r
+ bool MethodImplAttr = false;\r
+ bool MarshalAsAttr = false;\r
+ bool GuidAttr = false;\r
+ UsageAttr = false;\r
+\r
+ bool DoCompares = true;\r
+ if (Type == TypeManager.attribute_usage_type)\r
+ UsageAttr = true;\r
+ else if (Type == TypeManager.methodimpl_attr_type)\r
+ MethodImplAttr = true;\r
+ else if (Type == TypeManager.marshal_as_attr_type)\r
+ MarshalAsAttr = true;\r
+ else if (Type == TypeManager.guid_attr_type)\r
+ GuidAttr = true;\r
+ else\r
+ DoCompares = false;\r
+\r
+ // Now we extract the positional and named arguments\r
+ \r
+ ArrayList pos_args = new ArrayList ();\r
+ ArrayList named_args = new ArrayList ();\r
+ int pos_arg_count = 0;\r
+ \r
+ if (Arguments != null) {\r
+ pos_args = (ArrayList) Arguments [0];\r
+ if (pos_args != null)\r
+ pos_arg_count = pos_args.Count;\r
+ if (Arguments.Count > 1)\r
+ named_args = (ArrayList) Arguments [1];\r
+ }\r
+\r
+ object [] pos_values = new object [pos_arg_count];\r
+\r
+ //\r
+ // First process positional arguments \r
+ //\r
+\r
+ int i;\r
+ for (i = 0; i < pos_arg_count; i++) {\r
+ Argument a = (Argument) pos_args [i];\r
+ Expression e;\r
+\r
+ if (!a.Resolve (ec, Location))\r
+ return null;\r
+\r
+ e = a.Expr;\r
+\r
+ object val;\r
+ if (!GetAttributeArgumentExpression (e, Location, out val))\r
+ return null;\r
+ \r
+ pos_values [i] = val;\r
+ if (DoCompares){\r
+ if (UsageAttr)\r
+ this.Targets = (AttributeTargets) pos_values [0];\r
+ else if (MethodImplAttr)\r
+ this.ImplOptions = (MethodImplOptions) pos_values [0];\r
+ else if (GuidAttr){\r
+ //\r
+ // we will later check the validity of the type\r
+ //\r
+ if (pos_values [0] is string){\r
+ if (!ValidateGuid ((string) pos_values [0]))\r
+ return null;\r
+ }\r
+ \r
+ } else if (MarshalAsAttr)\r
+ this.UnmanagedType =\r
+ (System.Runtime.InteropServices.UnmanagedType) pos_values [0];\r
+ }\r
+ }\r
+\r
+ //\r
+ // Now process named arguments\r
+ //\r
+\r
+ ArrayList field_infos = null;\r
+ ArrayList prop_infos = null;\r
+ ArrayList field_values = null;\r
+ ArrayList prop_values = null;\r
+\r
+ if (named_args.Count > 0) {\r
+ field_infos = new ArrayList ();\r
+ prop_infos = new ArrayList ();\r
+ field_values = new ArrayList ();\r
+ prop_values = new ArrayList ();\r
+ }\r
+ \r
+ for (i = 0; i < named_args.Count; i++) {\r
+ DictionaryEntry de = (DictionaryEntry) named_args [i];\r
+ string member_name = (string) de.Key;\r
+ Argument a = (Argument) de.Value;\r
+ Expression e;\r
+ \r
+ if (!a.Resolve (ec, Location))\r
+ return null;\r
+\r
+ Expression member = Expression.MemberLookup (\r
+ ec, Type, member_name,\r
+ MemberTypes.Field | MemberTypes.Property,\r
+ BindingFlags.Public | BindingFlags.Instance,\r
+ Location);\r
+\r
+ if (member == null || !(member is PropertyExpr || member is FieldExpr)) {\r
+ Error_InvalidNamedArgument (member_name);\r
+ return null;\r
+ }\r
+\r
+ e = a.Expr;\r
+ if (member is PropertyExpr) {\r
+ PropertyExpr pe = (PropertyExpr) member;\r
+ PropertyInfo pi = pe.PropertyInfo;\r
+\r
+ if (!pi.CanWrite) {\r
+ Error_InvalidNamedArgument (member_name);\r
+ return null;\r
+ }\r
+\r
+ if (e is Constant) {\r
+ object o = ((Constant) e).GetValue ();\r
+ prop_values.Add (o);\r
+ \r
+ if (UsageAttr) {\r
+ if (member_name == "AllowMultiple")\r
+ this.AllowMultiple = (bool) o;\r
+ if (member_name == "Inherited")\r
+ this.Inherited = (bool) o;\r
+ }\r
+ \r
+ } else if (e is TypeOf) {\r
+ prop_values.Add (((TypeOf) e).TypeArg);\r
+ } else {\r
+ Error_AttributeArgumentNotValid (Location);\r
+ return null;\r
+ }\r
+ \r
+ prop_infos.Add (pi);\r
+ \r
+ } else if (member is FieldExpr) {\r
+ FieldExpr fe = (FieldExpr) member;\r
+ FieldInfo fi = fe.FieldInfo;\r
+\r
+ if (fi.IsInitOnly) {\r
+ Error_InvalidNamedArgument (member_name);\r
+ return null;\r
+ }\r
+\r
+ //\r
+ // Handle charset here, and set the TypeAttributes\r
+ \r
+ if (e is Constant){\r
+ object value = ((Constant) e).GetValue ();\r
+ \r
+ field_values.Add (value);\r
+ } else if (e is TypeOf) {\r
+ field_values.Add (((TypeOf) e).TypeArg);\r
+ } else {\r
+ Error_AttributeArgumentNotValid (Location);\r
+ return null;\r
+ }\r
+ \r
+ field_infos.Add (fi);\r
+ }\r
+ }\r
+\r
+ Expression mg = Expression.MemberLookup (\r
+ ec, Type, ".ctor", MemberTypes.Constructor,\r
+ BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,\r
+ Location);\r
+\r
+ if (mg == null) {\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ MethodBase constructor = Invocation.OverloadResolve (\r
+ ec, (MethodGroupExpr) mg, pos_args, Location);\r
+\r
+ if (constructor == null) {\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ //\r
+ // Now we perform some checks on the positional args as they\r
+ // cannot be null for a constructor which expects a parameter\r
+ // of type object\r
+ //\r
+\r
+ ParameterData pd = Invocation.GetParameterData (constructor);\r
+\r
+ int group_in_params_array = Int32.MaxValue;\r
+ int pc = pd.Count;\r
+ if (pc > 0 && pd.ParameterModifier (pc-1) == Parameter.Modifier.PARAMS)\r
+ group_in_params_array = pc-1;\r
+ \r
+ for (int j = 0; j < pos_arg_count; ++j) {\r
+ Argument a = (Argument) pos_args [j];\r
+ \r
+ if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {\r
+ Error_AttributeArgumentNotValid (Location);\r
+ return null;\r
+ }\r
+\r
+ if (j < group_in_params_array)\r
+ continue;\r
+ \r
+ if (j == group_in_params_array){\r
+ object v = pos_values [j];\r
+ int count = pos_arg_count - j;\r
+\r
+ object [] array = new object [count];\r
+ pos_values [j] = array;\r
+ array [0] = v;\r
+ } else {\r
+ object [] array = (object []) pos_values [group_in_params_array];\r
+\r
+ array [j - group_in_params_array] = pos_values [j];\r
+ }\r
+ }\r
+\r
+ //\r
+ // Adjust the size of the pos_values if it had params\r
+ //\r
+ if (group_in_params_array != Int32.MaxValue){\r
+ int argc = group_in_params_array+1;\r
+ object [] new_pos_values = new object [argc];\r
+\r
+ for (int p = 0; p < argc; p++)\r
+ new_pos_values [p] = pos_values [p];\r
+ pos_values = new_pos_values;\r
+ }\r
+\r
+ try {\r
+ if (named_args.Count > 0) {\r
+ prop_info_arr = new PropertyInfo [prop_infos.Count];\r
+ field_info_arr = new FieldInfo [field_infos.Count];\r
+ field_values_arr = new object [field_values.Count];\r
+ prop_values_arr = new object [prop_values.Count];\r
+\r
+ field_infos.CopyTo (field_info_arr, 0);\r
+ field_values.CopyTo (field_values_arr, 0);\r
+\r
+ prop_values.CopyTo (prop_values_arr, 0);\r
+ prop_infos.CopyTo (prop_info_arr, 0);\r
+\r
+ cb = new CustomAttributeBuilder (\r
+ (ConstructorInfo) constructor, pos_values,\r
+ prop_info_arr, prop_values_arr,\r
+ field_info_arr, field_values_arr);\r
+ }\r
+ else\r
+ cb = new CustomAttributeBuilder (\r
+ (ConstructorInfo) constructor, pos_values);\r
+ } catch (NullReferenceException) {\r
+ // \r
+ // Don't know what to do here\r
+ //\r
+ Report.Warning (\r
+ -100, Location, "NullReferenceException while trying to create attribute. Something's wrong!");\r
+ } catch (Exception e) {\r
+ //\r
+ // Sample:\r
+ // using System.ComponentModel;\r
+ // [DefaultValue (CollectionChangeAction.Add)]\r
+ // class X { static void Main () {} }\r
+ //\r
+ Report.Warning (\r
+ -23, Location,\r
+ "The compiler can not encode this attribute in .NET due to\n" +\r
+ "\ta bug in the .NET runtime. Try the Mono runtime.\nThe error was: " + e.Message);\r
+ }\r
+ \r
+ return cb;\r
+ }\r
+\r
+ static string GetValidPlaces (Attribute attr)\r
+ {\r
+ StringBuilder sb = new StringBuilder ();\r
+ AttributeTargets targets = 0;\r
+ \r
+ TypeContainer a = TypeManager.LookupAttr (attr.Type);\r
+\r
+ if (a == null) {\r
+ \r
+ System.Attribute [] attrs = null;\r
+ \r
+ try {\r
+ attrs = System.Attribute.GetCustomAttributes (attr.Type);\r
+ \r
+ } catch {\r
+ Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +\r
+ " (maybe you forgot to set the usage using the" +\r
+ " AttributeUsage attribute ?).");\r
+ return null;\r
+ }\r
+ \r
+ foreach (System.Attribute tmp in attrs)\r
+ if (tmp is AttributeUsageAttribute) {\r
+ targets = ((AttributeUsageAttribute) tmp).ValidOn;\r
+ break;\r
+ }\r
+ } else\r
+ targets = a.Targets;\r
+\r
+ \r
+ if ((targets & AttributeTargets.Assembly) != 0)\r
+ sb.Append ("'assembly' ");\r
+\r
+ if ((targets & AttributeTargets.Class) != 0)\r
+ sb.Append ("'class' ");\r
+\r
+ if ((targets & AttributeTargets.Constructor) != 0)\r
+ sb.Append ("'constructor' ");\r
+\r
+ if ((targets & AttributeTargets.Delegate) != 0)\r
+ sb.Append ("'delegate' ");\r
+\r
+ if ((targets & AttributeTargets.Enum) != 0)\r
+ sb.Append ("'enum' ");\r
+\r
+ if ((targets & AttributeTargets.Event) != 0)\r
+ sb.Append ("'event' ");\r
+\r
+ if ((targets & AttributeTargets.Field) != 0)\r
+ sb.Append ("'field' ");\r
+\r
+ if ((targets & AttributeTargets.Interface) != 0)\r
+ sb.Append ("'interface' ");\r
+\r
+ if ((targets & AttributeTargets.Method) != 0)\r
+ sb.Append ("'method' ");\r
+\r
+ if ((targets & AttributeTargets.Module) != 0)\r
+ sb.Append ("'module' ");\r
+\r
+ if ((targets & AttributeTargets.Parameter) != 0)\r
+ sb.Append ("'parameter' ");\r
+\r
+ if ((targets & AttributeTargets.Property) != 0)\r
+ sb.Append ("'property' ");\r
+\r
+ if ((targets & AttributeTargets.ReturnValue) != 0)\r
+ sb.Append ("'return value' ");\r
+\r
+ if ((targets & AttributeTargets.Struct) != 0)\r
+ sb.Append ("'struct' ");\r
+\r
+ return sb.ToString ();\r
+\r
+ }\r
+\r
+ public static void Error_AttributeNotValidForElement (Attribute a, Location loc)\r
+ {\r
+ Report.Error (\r
+ 592, loc, "Attribute '" + a.Name +\r
+ "' is not valid on this declaration type. " +\r
+ "It is valid on " + GetValidPlaces (a) + "declarations only.");\r
+ }\r
+\r
+ public static bool CheckAttribute (Attribute a, object element)\r
+ {\r
+ TypeContainer attr = TypeManager.LookupAttr (a.Type);\r
+ AttributeTargets targets = 0;\r
+\r
+ \r
+ if (attr == null) {\r
+ System.Attribute [] attrs = null;\r
+ \r
+ try {\r
+ attrs = System.Attribute.GetCustomAttributes (a.Type);\r
+\r
+ } catch {\r
+ Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +\r
+ " (maybe you forgot to set the usage using the" +\r
+ " AttributeUsage attribute ?).");\r
+ return false;\r
+ }\r
+ \r
+ foreach (System.Attribute tmp in attrs)\r
+ if (tmp is AttributeUsageAttribute) \r
+ targets = ((AttributeUsageAttribute) tmp).ValidOn;\r
+ } else\r
+ targets = attr.Targets;\r
+\r
+ if (element is Class) {\r
+ if ((targets & AttributeTargets.Class) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ \r
+ } else if (element is Struct) {\r
+ if ((targets & AttributeTargets.Struct) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Constructor) {\r
+ if ((targets & AttributeTargets.Constructor) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Delegate) {\r
+ if ((targets & AttributeTargets.Delegate) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Enum) {\r
+ if ((targets & AttributeTargets.Enum) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Event || element is InterfaceEvent) {\r
+ if ((targets & AttributeTargets.Event) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Field || element is FieldBuilder) {\r
+ if ((targets & AttributeTargets.Field) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Interface) {\r
+ if ((targets & AttributeTargets.Interface) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Method || element is Operator || element is InterfaceMethod || element is Accessor) {\r
+ if ((targets & AttributeTargets.Method) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is ParameterBuilder) {\r
+ if ((targets & AttributeTargets.Parameter) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is Property || element is Indexer ||\r
+ element is InterfaceProperty || element is InterfaceIndexer) {\r
+ if ((targets & AttributeTargets.Property) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ } else if (element is AssemblyBuilder){\r
+ if ((targets & AttributeTargets.Assembly) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ //\r
+ // This method should be invoked to pull the IndexerName attribute from an\r
+ // Indexer if it exists.\r
+ //\r
+ public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)\r
+ {\r
+ if (opt_attrs == null)\r
+ return null;\r
+ if (opt_attrs.AttributeSections == null)\r
+ return null;\r
+\r
+ foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
+ if (asec.Attributes == null)\r
+ continue;\r
+\r
+ foreach (Attribute a in asec.Attributes){\r
+ if (a.ResolveType (ec) == null)\r
+ return null;\r
+ \r
+ if (a.Type != TypeManager.indexer_name_type)\r
+ continue;\r
+\r
+ //\r
+ // So we have found an IndexerName, pull the data out.\r
+ //\r
+ if (a.Arguments == null || a.Arguments [0] == null){\r
+ Error_AttributeConstructorMismatch (a.Location);\r
+ return null;\r
+ }\r
+ ArrayList pos_args = (ArrayList) a.Arguments [0];\r
+ if (pos_args.Count == 0){\r
+ Error_AttributeConstructorMismatch (a.Location);\r
+ return null;\r
+ }\r
+ \r
+ Argument arg = (Argument) pos_args [0];\r
+ if (!arg.Resolve (ec, a.Location))\r
+ return null;\r
+ \r
+ Expression e = arg.Expr;\r
+ if (!(e is StringConstant)){\r
+ Error_AttributeConstructorMismatch (a.Location);\r
+ return null;\r
+ }\r
+\r
+ //\r
+ // Remove the attribute from the list\r
+ //\r
+ asec.Attributes.Remove (a);\r
+\r
+ return (((StringConstant) e).Value);\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ //\r
+ // This pulls the condition name out of a Conditional attribute\r
+ //\r
+ public string Conditional_GetConditionName ()\r
+ {\r
+ //\r
+ // So we have a Conditional, pull the data out.\r
+ //\r
+ if (Arguments == null || Arguments [0] == null){\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ ArrayList pos_args = (ArrayList) Arguments [0];\r
+ if (pos_args.Count != 1){\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ Argument arg = (Argument) pos_args [0]; \r
+ if (!(arg.Expr is StringConstant)){\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ return ((StringConstant) arg.Expr).Value;\r
+ }\r
+\r
+ //\r
+ // This pulls the obsolete message and error flag out of an Obsolete attribute\r
+ //\r
+ public string Obsolete_GetObsoleteMessage (out bool is_error)\r
+ {\r
+ is_error = false;\r
+ //\r
+ // So we have an Obsolete, pull the data out.\r
+ //\r
+ if (Arguments == null || Arguments [0] == null)\r
+ return "";\r
+\r
+ ArrayList pos_args = (ArrayList) Arguments [0];\r
+ if (pos_args.Count == 0)\r
+ return "";\r
+ else if (pos_args.Count > 2){\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ Argument arg = (Argument) pos_args [0]; \r
+ if (!(arg.Expr is StringConstant)){\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+\r
+ if (pos_args.Count == 2){\r
+ Argument arg2 = (Argument) pos_args [1];\r
+ if (!(arg2.Expr is BoolConstant)){\r
+ Error_AttributeConstructorMismatch (Location);\r
+ return null;\r
+ }\r
+ is_error = ((BoolConstant) arg2.Expr).Value;\r
+ }\r
+\r
+ return ((StringConstant) arg.Expr).Value;\r
+ }\r
+\r
+ static object GetFieldValue (Attribute a, string name) {\r
+ int i;\r
+ if (a.field_info_arr == null)\r
+ return null;\r
+ i = 0;\r
+ foreach (FieldInfo fi in a.field_info_arr) {\r
+ if (fi.Name == name)\r
+ return a.field_values_arr [i];\r
+ i++;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ static UnmanagedMarshal GetMarshal (Attribute a) {\r
+ UnmanagedMarshal marshal;\r
+\r
+ if (a.UnmanagedType == UnmanagedType.CustomMarshaler) {\r
+ MethodInfo define_custom = typeof (UnmanagedMarshal).GetMethod ("DefineCustom", BindingFlags.Static | BindingFlags.Public);\r
+ if (define_custom == null) {\r
+ return null;\r
+ }\r
+ object[] args = new object [4];\r
+ args [0] = GetFieldValue (a, "MarshalTypeRef");\r
+ args [1] = GetFieldValue (a, "MarshalCookie");\r
+ args [2] = GetFieldValue (a, "MarshalType");\r
+ args [3] = Guid.Empty;\r
+ marshal = (UnmanagedMarshal) define_custom.Invoke (null, args);\r
+ /*\r
+ * need to special case other special marshal types\r
+ */\r
+ } else {\r
+ marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);\r
+ }\r
+ return marshal;\r
+ }\r
+\r
+ //\r
+ // Applies the attributes to the `builder'.\r
+ //\r
+ public static void ApplyAttributes (EmitContext ec, object builder, object kind,\r
+ Attributes opt_attrs)\r
+ {\r
+ Type attr_type = null;\r
+ \r
+ if (opt_attrs == null)\r
+ return;\r
+ if (opt_attrs.AttributeSections == null)\r
+ return;\r
+\r
+ ArrayList emitted_attrs = new ArrayList ();\r
+ ArrayList emitted_targets = new ArrayList ();\r
+\r
+ foreach (AttributeSection asec in opt_attrs.AttributeSections) {\r
+ string attr_target = asec.Target;\r
+ \r
+ if (asec.Attributes == null)\r
+ continue;\r
+\r
+ if (attr_target == "assembly" && !(builder is AssemblyBuilder))\r
+ continue;\r
+\r
+ if (attr_target == "return" && !(builder is ParameterBuilder))\r
+ continue;\r
+ \r
+ foreach (Attribute a in asec.Attributes) {\r
+ Location loc = a.Location;\r
+ CustomAttributeBuilder cb = a.Resolve (ec);\r
+ attr_type = a.Type;\r
+\r
+ if (cb == null) \r
+ continue;\r
+ \r
+ if (!(kind is TypeContainer))\r
+ if (!CheckAttribute (a, kind)) {\r
+ Error_AttributeNotValidForElement (a, loc);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Perform the check for duplicate attributes\r
+ //\r
+ if (emitted_attrs.Contains (attr_type) &&\r
+ emitted_targets.Contains (attr_target) &&\r
+ !TypeManager.AreMultipleAllowed (attr_type)) {\r
+ Report.Error (579, loc, "Duplicate '" + a.Name + "' attribute");\r
+ return;\r
+ }\r
+\r
+ if (kind is Method || kind is Operator || kind is InterfaceMethod ||\r
+ kind is Accessor) {\r
+ if (attr_type == TypeManager.methodimpl_attr_type) {\r
+ if (a.ImplOptions == MethodImplOptions.InternalCall)\r
+ ((MethodBuilder) builder).\r
+ SetImplementationFlags (\r
+ MethodImplAttributes.InternalCall |\r
+ MethodImplAttributes.Runtime);\r
+ else\r
+ ((MethodBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (attr_type != TypeManager.dllimport_type){\r
+ ((MethodBuilder) builder).SetCustomAttribute (cb);\r
+ }\r
+ } else if (kind is Constructor) {\r
+ ((ConstructorBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is Field) {\r
+ ((FieldBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is Property || kind is Indexer ||\r
+ kind is InterfaceProperty || kind is InterfaceIndexer) {\r
+ ((PropertyBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is Event || kind is InterfaceEvent) {\r
+ ((MyEventBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is ParameterBuilder) {\r
+\r
+ if (attr_type == TypeManager.marshal_as_attr_type) {\r
+ UnmanagedMarshal marshal = GetMarshal (a);\r
+ if (marshal == null) {\r
+ Report.Warning (-24, loc,\r
+ "The Microsoft Runtime cannot set this marshal info. " +\r
+ "Please use the Mono runtime instead.");\r
+ } else {\r
+ ((ParameterBuilder) builder).SetMarshal (marshal);\r
+ }\r
+ } else { \r
+\r
+ try {\r
+ ((ParameterBuilder) builder).SetCustomAttribute (cb);\r
+ } catch (System.ArgumentException) {\r
+ Report.Warning (-24, loc,\r
+ "The Microsoft Runtime cannot set attributes \n" +\r
+ "on the return type of a method. Please use the \n" +\r
+ "Mono runtime instead.");\r
+ }\r
+\r
+ }\r
+ } else if (kind is Enum) {\r
+ ((TypeBuilder) builder).SetCustomAttribute (cb); \r
+\r
+ } else if (kind is TypeContainer) {\r
+ TypeContainer tc = (TypeContainer) kind;\r
+ \r
+ if (a.UsageAttr) {\r
+ tc.Targets = a.Targets;\r
+ tc.AllowMultiple = a.AllowMultiple;\r
+ tc.Inherited = a.Inherited;\r
+\r
+ TypeManager.RegisterAttributeAllowMultiple (tc.TypeBuilder,\r
+ tc.AllowMultiple);\r
+ \r
+ } else if (attr_type == TypeManager.default_member_type) {\r
+ if (tc.Indexers != null) {\r
+ Report.Error (646, loc,\r
+ "Cannot specify the DefaultMember attribute on" +\r
+ " a type containing an indexer");\r
+ return;\r
+ }\r
+\r
+ } else {\r
+ if (!CheckAttribute (a, kind)) {\r
+ Error_AttributeNotValidForElement (a, loc);\r
+ return;\r
+ }\r
+ }\r
+\r
+ try {\r
+ ((TypeBuilder) builder).SetCustomAttribute (cb);\r
+ } catch (System.ArgumentException) {\r
+ Report.Warning (\r
+ -21, loc,\r
+ "The CharSet named property on StructLayout\n"+\r
+ "\tdoes not work correctly on Microsoft.NET\n"+\r
+ "\tYou might want to remove the CharSet declaration\n"+\r
+ "\tor compile using the Mono runtime instead of the\n"+\r
+ "\tMicrosoft .NET runtime");\r
+ }\r
+ \r
+ } else if (kind is Interface) {\r
+ Interface iface = (Interface) kind;\r
+\r
+ if ((attr_type == TypeManager.default_member_type) &&\r
+ (iface.InterfaceIndexers != null)) {\r
+ Report.Error (\r
+ 646, loc,\r
+ "Cannot specify the DefaultMember attribute on" +\r
+ " a type containing an indexer");\r
+ return;\r
+ }\r
+\r
+ if (!CheckAttribute (a, kind)) {\r
+ Error_AttributeNotValidForElement (a, loc);\r
+ return;\r
+ }\r
+\r
+ ((TypeBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is AssemblyBuilder){\r
+ ((AssemblyBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is ModuleBuilder) {\r
+ ((ModuleBuilder) builder).SetCustomAttribute (cb);\r
+ } else if (kind is FieldBuilder) {\r
+ if (attr_type == TypeManager.marshal_as_attr_type) {\r
+ UnmanagedMarshal marshal = GetMarshal (a);\r
+ if (marshal == null) {\r
+ Report.Warning (-24, loc,\r
+ "The Microsoft Runtime cannot set this marshal info. " +\r
+ "Please use the Mono runtime instead.");\r
+ } else {\r
+ ((ParameterBuilder) builder).SetMarshal (marshal);\r
+ }\r
+ } else { \r
+ ((FieldBuilder) builder).SetCustomAttribute (cb);\r
+ }\r
+ } else\r
+ throw new Exception ("Unknown kind: " + kind);\r
+\r
+ //\r
+ // Once an attribute type has been emitted once we\r
+ // keep track of the info to prevent multiple occurences\r
+ // for attributes which do not explicitly allow it\r
+ //\r
+ if (!emitted_attrs.Contains (attr_type))\r
+ emitted_attrs.Add (attr_type);\r
+\r
+ //\r
+ // We keep of this target-wise and so emitted targets\r
+ // are tracked too\r
+ //\r
+ if (!emitted_targets.Contains (attr_target))\r
+ emitted_targets.Add (attr_target);\r
+ }\r
+ \r
+ \r
+ }\r
+ }\r
+\r
+ public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,\r
+ MethodAttributes flags, Type ret_type, Type [] param_types)\r
+ {\r
+ //\r
+ // We extract from the attribute the information we need \r
+ //\r
+\r
+ if (Arguments == null) {\r
+ Console.WriteLine ("Internal error : this is not supposed to happen !");\r
+ return null;\r
+ }\r
+\r
+ Type = CheckAttributeType (ec);\r
+ if (Type == null)\r
+ return null;\r
+ \r
+ ArrayList named_args = new ArrayList ();\r
+ \r
+ ArrayList pos_args = (ArrayList) Arguments [0];\r
+ if (Arguments.Count > 1)\r
+ named_args = (ArrayList) Arguments [1];\r
+ \r
+\r
+ string dll_name = null;\r
+ \r
+ Argument tmp = (Argument) pos_args [0];\r
+\r
+ if (!tmp.Resolve (ec, Location))\r
+ return null;\r
+ \r
+ if (tmp.Expr is Constant)\r
+ dll_name = (string) ((Constant) tmp.Expr).GetValue ();\r
+ else { \r
+ Error_AttributeArgumentNotValid (Location);\r
+ return null;\r
+ }\r
+\r
+ // Now we process the named arguments\r
+ CallingConvention cc = CallingConvention.Winapi;\r
+ CharSet charset = CharSet.Ansi;\r
+ bool preserve_sig = true;\r
+ bool exact_spelling = false;\r
+ bool set_last_err = false;\r
+ string entry_point = null;\r
+\r
+ for (int i = 0; i < named_args.Count; i++) {\r
+\r
+ DictionaryEntry de = (DictionaryEntry) named_args [i];\r
+\r
+ string member_name = (string) de.Key;\r
+ Argument a = (Argument) de.Value;\r
+\r
+ if (!a.Resolve (ec, Location))\r
+ return null;\r
+\r
+ Expression member = Expression.MemberLookup (\r
+ ec, Type, member_name, \r
+ MemberTypes.Field | MemberTypes.Property,\r
+ BindingFlags.Public | BindingFlags.Instance,\r
+ Location);\r
+\r
+ if (member == null || !(member is FieldExpr)) {\r
+ Error_InvalidNamedArgument (member_name);\r
+ return null;\r
+ }\r
+\r
+ if (member is FieldExpr) {\r
+ FieldExpr fe = (FieldExpr) member;\r
+ FieldInfo fi = fe.FieldInfo;\r
+\r
+ if (fi.IsInitOnly) {\r
+ Error_InvalidNamedArgument (member_name);\r
+ return null;\r
+ }\r
+\r
+ if (a.Expr is Constant) {\r
+ Constant c = (Constant) a.Expr;\r
+ \r
+ if (member_name == "CallingConvention")\r
+ cc = (CallingConvention) c.GetValue ();\r
+ else if (member_name == "CharSet")\r
+ charset = (CharSet) c.GetValue ();\r
+ else if (member_name == "EntryPoint")\r
+ entry_point = (string) c.GetValue ();\r
+ else if (member_name == "SetLastError")\r
+ set_last_err = (bool) c.GetValue ();\r
+ else if (member_name == "ExactSpelling")\r
+ exact_spelling = (bool) c.GetValue ();\r
+ else if (member_name == "PreserveSig")\r
+ preserve_sig = (bool) c.GetValue ();\r
+ } else { \r
+ Error_AttributeArgumentNotValid (Location);\r
+ return null;\r
+ }\r
+ \r
+ }\r
+ }\r
+\r
+ if (entry_point == null)\r
+ entry_point = name;\r
+ \r
+ MethodBuilder mb = builder.DefinePInvokeMethod (\r
+ name, dll_name, entry_point, flags | MethodAttributes.HideBySig,\r
+ CallingConventions.Standard,\r
+ ret_type,\r
+ param_types,\r
+ cc,\r
+ charset);\r
+\r
+ if (preserve_sig)\r
+ mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);\r
+ \r
+ return mb;\r
+ }\r
+ \r
+ }\r
+ \r
+ public class AttributeSection {\r
+ public readonly string Target;\r
+ public readonly ArrayList Attributes;\r
+ \r
+ public AttributeSection (string target, ArrayList attrs)\r
+ {\r
+ Target = target;\r
+ Attributes = attrs;\r
+ }\r
+ \r
+ }\r
+\r
+ public class Attributes {\r
+ public ArrayList AttributeSections;\r
+\r
+ public Attributes (AttributeSection a)\r
+ {\r
+ AttributeSections = new ArrayList ();\r
+ AttributeSections.Add (a);\r
+\r
+ }\r
+\r
+ public void AddAttributeSection (AttributeSection a)\r
+ {\r
+ if (a != null && !AttributeSections.Contains (a))\r
+ AttributeSections.Add (a);\r
+ }\r
+\r
+ public bool Contains (Type t)\r
+ {\r
+ foreach (AttributeSection attr_section in AttributeSections){\r
+ foreach (Attribute a in attr_section.Attributes){\r
+ if (a.Type == t)\r
+ return true;\r
+ }\r
+ }\r
+ \r
+ return false;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+//
+// cfold.cs: Constant Folding
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2002, 2003 Ximian, Inc.
+//
+
+using System;
+
+namespace Mono.CSharp {
+
+ public class ConstantFold {
+
+ //
+ // Performs the numeric promotions on the left and right expresions
+ // and desposits the results on `lc' and `rc'.
+ //
+ // On success, the types of `lc' and `rc' on output will always match,
+ // and the pair will be one of:
+ //
+ // (double, double)
+ // (float, float)
+ // (ulong, ulong)
+ // (long, long)
+ // (uint, uint)
+ // (int, int)
+ // (short, short) (Happens with enumerations with underlying short type)
+ // (ushort, ushort) (Happens with enumerations with underlying short type)
+ //
+ static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
+ ref Constant left, ref Constant right,
+ Location loc)
+ {
+ if (left is DoubleConstant || right is DoubleConstant){
+ //
+ // If either side is a double, convert the other to a double
+ //
+ if (!(left is DoubleConstant))
+ left = left.ToDouble (loc);
+
+ if (!(right is DoubleConstant))
+ right = right.ToDouble (loc);
+ return;
+ } else if (left is FloatConstant || right is FloatConstant) {
+ //
+ // If either side is a float, convert the other to a float
+ //
+ if (!(left is FloatConstant))
+ left = left.ToFloat (loc);
+
+ if (!(right is FloatConstant))
+ right = right.ToFloat (loc);
+; return;
+ } else if (left is ULongConstant || right is ULongConstant){
+ //
+ // If either operand is of type ulong, the other operand is
+ // converted to type ulong. or an error ocurrs if the other
+ // operand is of type sbyte, short, int or long
+ //
+ Constant match, other;
+
+ if (left is ULongConstant){
+ other = right;
+ match = left;
+ if (!(right is ULongConstant))
+ right = right.ToULong (loc);
+ } else {
+ other = left;
+ match = right;
+ left = left.ToULong (loc);
+ }
+
+#if WRONG
+ if (other is SByteConstant || other is ShortConstant ||
+ other is IntConstant || other is LongConstant){
+ Binary.Error_OperatorAmbiguous
+ (loc, oper, other.Type, match.Type);
+ left = null;
+ right = null;
+ }
+#endif
+ return;
+ } else if (left is LongConstant || right is LongConstant){
+ //
+ // If either operand is of type long, the other operand is converted
+ // to type long.
+ //
+ if (!(left is LongConstant))
+ left = left.ToLong (loc);
+ else if (!(right is LongConstant))
+ right = right.ToLong (loc);
+ return;
+ } else if (left is UIntConstant || right is UIntConstant){
+ //
+ // If either operand is of type uint, and the other
+ // operand is of type sbyte, short or int, the operands are
+ // converted to type long.
+ //
+ Constant match, other;
+ if (left is UIntConstant){
+ other = right;
+ match = left;
+ } else {
+ other = left;
+ match = right;
+ }
+
+ // Nothing to do.
+ if (other is UIntConstant)
+ return;
+
+ if (other is SByteConstant || other is ShortConstant ||
+ other is IntConstant){
+ left = left.ToLong (loc);
+ right = right.ToLong (loc);
+ }
+
+ return;
+ } else if (left is EnumConstant || right is EnumConstant){
+ //
+ // If either operand is an enum constant, the other one must
+ // be implicitly convertable to that enum's underlying type.
+ //
+ EnumConstant match;
+ Constant other;
+ if (left is EnumConstant){
+ other = right;
+ match = (EnumConstant) left;
+ } else {
+ other = left;
+ match = (EnumConstant) right;
+ }
+
+ bool need_check = (other is EnumConstant) ||
+ ((oper != Binary.Operator.Addition) &&
+ (oper != Binary.Operator.Subtraction));
+
+ if (need_check &&
+ !Convert.ImplicitConversionExists (ec, match, other.Type)) {
+ Convert.Error_CannotImplicitConversion (loc, match.Type, other.Type);
+ left = null;
+ right = null;
+ return;
+ }
+
+ if (left is EnumConstant)
+ left = ((EnumConstant) left).Child;
+ if (right is EnumConstant)
+ right = ((EnumConstant) right).Child;
+ return;
+
+ } else {
+ //
+ // Force conversions to int32
+ //
+ if (!(left is IntConstant))
+ left = left.ToInt (loc);
+ if (!(right is IntConstant))
+ right = right.ToInt (loc);
+ }
+ return;
+ }
+
+ static void Error_CompileTimeOverflow (Location loc)
+ {
+ Report.Error (220, loc, "The operation overflows at compile time in checked mode");
+ }
+
+ /// <summary>
+ /// Constant expression folder for binary operations.
+ ///
+ /// Returns null if the expression can not be folded.
+ /// </summary>
+ static public Expression BinaryFold (EmitContext ec, Binary.Operator oper,
+ Constant left, Constant right, Location loc)
+ {
+ Type lt = left.Type;
+ Type rt = right.Type;
+ Type result_type = null;
+ bool bool_res;
+
+ //
+ // Enumerator folding
+ //
+ if (rt == lt && left is EnumConstant)
+ result_type = lt;
+
+ //
+ // During an enum evaluation, we need to unwrap enumerations
+ //
+ if (ec.InEnumContext){
+ if (left is EnumConstant)
+ left = ((EnumConstant) left).Child;
+
+ if (right is EnumConstant)
+ right = ((EnumConstant) right).Child;
+ }
+
+ Type wrap_as;
+ Constant result = null;
+ switch (oper){
+ case Binary.Operator.BitwiseOr:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ if (left is IntConstant){
+ IntConstant v;
+ int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
+
+ v = new IntConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is UIntConstant){
+ UIntConstant v;
+ uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
+
+ v = new UIntConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is LongConstant){
+ LongConstant v;
+ long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
+
+ v = new LongConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is ULongConstant){
+ ULongConstant v;
+ ulong res = ((ULongConstant)left).Value |
+ ((ULongConstant)right).Value;
+
+ v = new ULongConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is UShortConstant){
+ UShortConstant v;
+ ushort res = (ushort) (((UShortConstant)left).Value |
+ ((UShortConstant)right).Value);
+
+ v = new UShortConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is ShortConstant){
+ ShortConstant v;
+ short res = (short) (((ShortConstant)left).Value |
+ ((ShortConstant)right).Value);
+
+ v = new ShortConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ }
+ break;
+
+ case Binary.Operator.BitwiseAnd:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ if (left is IntConstant){
+ IntConstant v;
+ int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
+
+ v = new IntConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is UIntConstant){
+ UIntConstant v;
+ uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
+
+ v = new UIntConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is LongConstant){
+ LongConstant v;
+ long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
+
+ v = new LongConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is ULongConstant){
+ ULongConstant v;
+ ulong res = ((ULongConstant)left).Value &
+ ((ULongConstant)right).Value;
+
+ v = new ULongConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is UShortConstant){
+ UShortConstant v;
+ ushort res = (ushort) (((UShortConstant)left).Value &
+ ((UShortConstant)right).Value);
+
+ v = new UShortConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is ShortConstant){
+ ShortConstant v;
+ short res = (short) (((ShortConstant)left).Value &
+ ((ShortConstant)right).Value);
+
+ v = new ShortConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ }
+ break;
+
+ case Binary.Operator.ExclusiveOr:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ if (left is IntConstant){
+ IntConstant v;
+ int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
+
+ v = new IntConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is UIntConstant){
+ UIntConstant v;
+ uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
+
+ v = new UIntConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is LongConstant){
+ LongConstant v;
+ long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
+
+ v = new LongConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is ULongConstant){
+ ULongConstant v;
+ ulong res = ((ULongConstant)left).Value ^
+ ((ULongConstant)right).Value;
+
+ v = new ULongConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is UShortConstant){
+ UShortConstant v;
+ ushort res = (ushort) (((UShortConstant)left).Value ^
+ ((UShortConstant)right).Value);
+
+ v = new UShortConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ } else if (left is ShortConstant){
+ ShortConstant v;
+ short res = (short)(((ShortConstant)left).Value ^
+ ((ShortConstant)right).Value);
+
+ v = new ShortConstant (res);
+ if (result_type == null)
+ return v;
+ else
+ return new EnumConstant (v, result_type);
+ }
+ break;
+
+ case Binary.Operator.Addition:
+ bool left_is_string = left is StringConstant;
+ bool right_is_string = right is StringConstant;
+
+ //
+ // If both sides are strings, then concatenate, if
+ // one is a string, and the other is not, then defer
+ // to runtime concatenation
+ //
+ wrap_as = null;
+ if (left_is_string || right_is_string){
+ if (left_is_string && right_is_string)
+ return new StringConstant (
+ ((StringConstant) left).Value +
+ ((StringConstant) right).Value);
+
+ return null;
+ }
+
+ //
+ // handle "E operator + (E x, U y)"
+ // handle "E operator + (Y y, E x)"
+ //
+ // note that E operator + (E x, E y) is invalid
+ //
+ if (left is EnumConstant){
+ if (right is EnumConstant){
+ return null;
+ }
+ if (((EnumConstant) left).Child.Type != right.Type)
+ return null;
+
+ wrap_as = left.Type;
+ } else if (right is EnumConstant){
+ if (((EnumConstant) right).Child.Type != left.Type)
+ return null;
+ wrap_as = right.Type;
+ }
+
+ result = null;
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ try {
+ if (left is DoubleConstant){
+ double res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((DoubleConstant) left).Value +
+ ((DoubleConstant) right).Value);
+ else
+ res = unchecked (((DoubleConstant) left).Value +
+ ((DoubleConstant) right).Value);
+
+ result = new DoubleConstant (res);
+ } else if (left is FloatConstant){
+ float res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((FloatConstant) left).Value +
+ ((FloatConstant) right).Value);
+ else
+ res = unchecked (((FloatConstant) left).Value +
+ ((FloatConstant) right).Value);
+
+ result = new FloatConstant (res);
+ } else if (left is ULongConstant){
+ ulong res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((ULongConstant) left).Value +
+ ((ULongConstant) right).Value);
+ else
+ res = unchecked (((ULongConstant) left).Value +
+ ((ULongConstant) right).Value);
+
+ result = new ULongConstant (res);
+ } else if (left is LongConstant){
+ long res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((LongConstant) left).Value +
+ ((LongConstant) right).Value);
+ else
+ res = unchecked (((LongConstant) left).Value +
+ ((LongConstant) right).Value);
+
+ result = new LongConstant (res);
+ } else if (left is UIntConstant){
+ uint res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((UIntConstant) left).Value +
+ ((UIntConstant) right).Value);
+ else
+ res = unchecked (((UIntConstant) left).Value +
+ ((UIntConstant) right).Value);
+
+ result = new UIntConstant (res);
+ } else if (left is IntConstant){
+ int res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((IntConstant) left).Value +
+ ((IntConstant) right).Value);
+ else
+ res = unchecked (((IntConstant) left).Value +
+ ((IntConstant) right).Value);
+
+ result = new IntConstant (res);
+ } else {
+ throw new Exception ( "Unexepected input: " + left);
+ }
+ } catch (OverflowException){
+ Error_CompileTimeOverflow (loc);
+ }
+
+ if (wrap_as != null)
+ return new EnumConstant (result, wrap_as);
+ else
+ return result;
+
+ case Binary.Operator.Subtraction:
+ //
+ // handle "E operator - (E x, U y)"
+ // handle "E operator - (Y y, E x)"
+ // handle "U operator - (E x, E y)"
+ //
+ wrap_as = null;
+ if (left is EnumConstant){
+ if (right is EnumConstant){
+ if (left.Type == right.Type)
+ wrap_as = TypeManager.EnumToUnderlying (left.Type);
+ else
+ return null;
+ }
+ if (((EnumConstant) left).Child.Type != right.Type)
+ return null;
+
+ wrap_as = left.Type;
+ } else if (right is EnumConstant){
+ if (((EnumConstant) right).Child.Type != left.Type)
+ return null;
+ wrap_as = right.Type;
+ }
+
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ try {
+ if (left is DoubleConstant){
+ double res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((DoubleConstant) left).Value -
+ ((DoubleConstant) right).Value);
+ else
+ res = unchecked (((DoubleConstant) left).Value -
+ ((DoubleConstant) right).Value);
+
+ result = new DoubleConstant (res);
+ } else if (left is FloatConstant){
+ float res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((FloatConstant) left).Value -
+ ((FloatConstant) right).Value);
+ else
+ res = unchecked (((FloatConstant) left).Value -
+ ((FloatConstant) right).Value);
+
+ result = new FloatConstant (res);
+ } else if (left is ULongConstant){
+ ulong res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((ULongConstant) left).Value -
+ ((ULongConstant) right).Value);
+ else
+ res = unchecked (((ULongConstant) left).Value -
+ ((ULongConstant) right).Value);
+
+ result = new ULongConstant (res);
+ } else if (left is LongConstant){
+ long res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((LongConstant) left).Value -
+ ((LongConstant) right).Value);
+ else
+ res = unchecked (((LongConstant) left).Value -
+ ((LongConstant) right).Value);
+
+ result = new LongConstant (res);
+ } else if (left is UIntConstant){
+ uint res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((UIntConstant) left).Value -
+ ((UIntConstant) right).Value);
+ else
+ res = unchecked (((UIntConstant) left).Value -
+ ((UIntConstant) right).Value);
+
+ result = new UIntConstant (res);
+ } else if (left is IntConstant){
+ int res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((IntConstant) left).Value -
+ ((IntConstant) right).Value);
+ else
+ res = unchecked (((IntConstant) left).Value -
+ ((IntConstant) right).Value);
+
+ result = new IntConstant (res);
+ } else {
+ throw new Exception ( "Unexepected input: " + left);
+ }
+ } catch (OverflowException){
+ Error_CompileTimeOverflow (loc);
+ }
+ if (wrap_as != null)
+ return new EnumConstant (result, wrap_as);
+ else
+ return result;
+
+ case Binary.Operator.Multiply:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ try {
+ if (left is DoubleConstant){
+ double res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((DoubleConstant) left).Value *
+ ((DoubleConstant) right).Value);
+ else
+ res = unchecked (((DoubleConstant) left).Value *
+ ((DoubleConstant) right).Value);
+
+ return new DoubleConstant (res);
+ } else if (left is FloatConstant){
+ float res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((FloatConstant) left).Value *
+ ((FloatConstant) right).Value);
+ else
+ res = unchecked (((FloatConstant) left).Value *
+ ((FloatConstant) right).Value);
+
+ return new FloatConstant (res);
+ } else if (left is ULongConstant){
+ ulong res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((ULongConstant) left).Value *
+ ((ULongConstant) right).Value);
+ else
+ res = unchecked (((ULongConstant) left).Value *
+ ((ULongConstant) right).Value);
+
+ return new ULongConstant (res);
+ } else if (left is LongConstant){
+ long res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((LongConstant) left).Value *
+ ((LongConstant) right).Value);
+ else
+ res = unchecked (((LongConstant) left).Value *
+ ((LongConstant) right).Value);
+
+ return new LongConstant (res);
+ } else if (left is UIntConstant){
+ uint res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((UIntConstant) left).Value *
+ ((UIntConstant) right).Value);
+ else
+ res = unchecked (((UIntConstant) left).Value *
+ ((UIntConstant) right).Value);
+
+ return new UIntConstant (res);
+ } else if (left is IntConstant){
+ int res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((IntConstant) left).Value *
+ ((IntConstant) right).Value);
+ else
+ res = unchecked (((IntConstant) left).Value *
+ ((IntConstant) right).Value);
+
+ return new IntConstant (res);
+ } else {
+ throw new Exception ( "Unexepected input: " + left);
+ }
+ } catch (OverflowException){
+ Error_CompileTimeOverflow (loc);
+ }
+ break;
+
+ case Binary.Operator.Division:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ try {
+ if (left is DoubleConstant){
+ double res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((DoubleConstant) left).Value /
+ ((DoubleConstant) right).Value);
+ else
+ res = unchecked (((DoubleConstant) left).Value /
+ ((DoubleConstant) right).Value);
+
+ return new DoubleConstant (res);
+ } else if (left is FloatConstant){
+ float res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((FloatConstant) left).Value /
+ ((FloatConstant) right).Value);
+ else
+ res = unchecked (((FloatConstant) left).Value /
+ ((FloatConstant) right).Value);
+
+ return new FloatConstant (res);
+ } else if (left is ULongConstant){
+ ulong res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((ULongConstant) left).Value /
+ ((ULongConstant) right).Value);
+ else
+ res = unchecked (((ULongConstant) left).Value /
+ ((ULongConstant) right).Value);
+
+ return new ULongConstant (res);
+ } else if (left is LongConstant){
+ long res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((LongConstant) left).Value /
+ ((LongConstant) right).Value);
+ else
+ res = unchecked (((LongConstant) left).Value /
+ ((LongConstant) right).Value);
+
+ return new LongConstant (res);
+ } else if (left is UIntConstant){
+ uint res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((UIntConstant) left).Value /
+ ((UIntConstant) right).Value);
+ else
+ res = unchecked (((UIntConstant) left).Value /
+ ((UIntConstant) right).Value);
+
+ return new UIntConstant (res);
+ } else if (left is IntConstant){
+ int res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((IntConstant) left).Value /
+ ((IntConstant) right).Value);
+ else
+ res = unchecked (((IntConstant) left).Value /
+ ((IntConstant) right).Value);
+
+ return new IntConstant (res);
+ } else {
+ throw new Exception ( "Unexepected input: " + left);
+ }
+ } catch (OverflowException){
+ Error_CompileTimeOverflow (loc);
+
+ } catch (DivideByZeroException) {
+ Report.Error (020, loc, "Division by constant zero");
+ }
+
+ break;
+
+ case Binary.Operator.Modulus:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ try {
+ if (left is DoubleConstant){
+ double res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((DoubleConstant) left).Value %
+ ((DoubleConstant) right).Value);
+ else
+ res = unchecked (((DoubleConstant) left).Value %
+ ((DoubleConstant) right).Value);
+
+ return new DoubleConstant (res);
+ } else if (left is FloatConstant){
+ float res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((FloatConstant) left).Value %
+ ((FloatConstant) right).Value);
+ else
+ res = unchecked (((FloatConstant) left).Value %
+ ((FloatConstant) right).Value);
+
+ return new FloatConstant (res);
+ } else if (left is ULongConstant){
+ ulong res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((ULongConstant) left).Value %
+ ((ULongConstant) right).Value);
+ else
+ res = unchecked (((ULongConstant) left).Value %
+ ((ULongConstant) right).Value);
+
+ return new ULongConstant (res);
+ } else if (left is LongConstant){
+ long res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((LongConstant) left).Value %
+ ((LongConstant) right).Value);
+ else
+ res = unchecked (((LongConstant) left).Value %
+ ((LongConstant) right).Value);
+
+ return new LongConstant (res);
+ } else if (left is UIntConstant){
+ uint res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((UIntConstant) left).Value %
+ ((UIntConstant) right).Value);
+ else
+ res = unchecked (((UIntConstant) left).Value %
+ ((UIntConstant) right).Value);
+
+ return new UIntConstant (res);
+ } else if (left is IntConstant){
+ int res;
+
+ if (ec.ConstantCheckState)
+ res = checked (((IntConstant) left).Value %
+ ((IntConstant) right).Value);
+ else
+ res = unchecked (((IntConstant) left).Value %
+ ((IntConstant) right).Value);
+
+ return new IntConstant (res);
+ } else {
+ throw new Exception ( "Unexepected input: " + left);
+ }
+ } catch (DivideByZeroException){
+ Report.Error (020, loc, "Division by constant zero");
+ } catch (OverflowException){
+ Error_CompileTimeOverflow (loc);
+ }
+ break;
+
+ //
+ // There is no overflow checking on left shift
+ //
+ case Binary.Operator.LeftShift:
+ IntConstant ic = right.ToInt (loc);
+ if (ic == null){
+ Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+ return null;
+ }
+ int lshift_val = ic.Value;
+
+ IntConstant lic;
+ if ((lic = left.ConvertToInt ()) != null)
+ return new IntConstant (lic.Value << lshift_val);
+
+ UIntConstant luic;
+ if ((luic = left.ConvertToUInt ()) != null)
+ return new UIntConstant (luic.Value << lshift_val);
+
+ LongConstant llc;
+ if ((llc = left.ConvertToLong ()) != null)
+ return new LongConstant (llc.Value << lshift_val);
+
+ ULongConstant lulc;
+ if ((lulc = left.ConvertToULong ()) != null)
+ return new ULongConstant (lulc.Value << lshift_val);
+
+ Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+ break;
+
+ //
+ // There is no overflow checking on right shift
+ //
+ case Binary.Operator.RightShift:
+ IntConstant sic = right.ToInt (loc);
+ if (sic == null){
+ Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+ return null;
+ }
+ int rshift_val = sic.Value;
+
+ IntConstant ric;
+ if ((ric = left.ConvertToInt ()) != null)
+ return new IntConstant (ric.Value >> rshift_val);
+
+ UIntConstant ruic;
+ if ((ruic = left.ConvertToUInt ()) != null)
+ return new UIntConstant (ruic.Value >> rshift_val);
+
+ LongConstant rlc;
+ if ((rlc = left.ConvertToLong ()) != null)
+ return new LongConstant (rlc.Value >> rshift_val);
+
+ ULongConstant rulc;
+ if ((rulc = left.ConvertToULong ()) != null)
+ return new ULongConstant (rulc.Value >> rshift_val);
+
+ Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+ break;
+
+ case Binary.Operator.LogicalAnd:
+ if (left is BoolConstant && right is BoolConstant){
+ return new BoolConstant (
+ ((BoolConstant) left).Value &&
+ ((BoolConstant) right).Value);
+ }
+ break;
+
+ case Binary.Operator.LogicalOr:
+ if (left is BoolConstant && right is BoolConstant){
+ return new BoolConstant (
+ ((BoolConstant) left).Value ||
+ ((BoolConstant) right).Value);
+ }
+ break;
+
+ case Binary.Operator.Equality:
+ if (left is BoolConstant && right is BoolConstant){
+ return new BoolConstant (
+ ((BoolConstant) left).Value ==
+ ((BoolConstant) right).Value);
+
+ }
+ if (left is StringConstant && right is StringConstant){
+ return new BoolConstant (
+ ((StringConstant) left).Value ==
+ ((StringConstant) right).Value);
+
+ }
+
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ bool_res = false;
+ if (left is DoubleConstant)
+ bool_res = ((DoubleConstant) left).Value ==
+ ((DoubleConstant) right).Value;
+ else if (left is FloatConstant)
+ bool_res = ((FloatConstant) left).Value ==
+ ((FloatConstant) right).Value;
+ else if (left is ULongConstant)
+ bool_res = ((ULongConstant) left).Value ==
+ ((ULongConstant) right).Value;
+ else if (left is LongConstant)
+ bool_res = ((LongConstant) left).Value ==
+ ((LongConstant) right).Value;
+ else if (left is UIntConstant)
+ bool_res = ((UIntConstant) left).Value ==
+ ((UIntConstant) right).Value;
+ else if (left is IntConstant)
+ bool_res = ((IntConstant) left).Value ==
+ ((IntConstant) right).Value;
+ else
+ return null;
+
+ return new BoolConstant (bool_res);
+
+ case Binary.Operator.Inequality:
+ if (left is BoolConstant && right is BoolConstant){
+ return new BoolConstant (
+ ((BoolConstant) left).Value !=
+ ((BoolConstant) right).Value);
+ }
+ if (left is StringConstant && right is StringConstant){
+ return new BoolConstant (
+ ((StringConstant) left).Value !=
+ ((StringConstant) right).Value);
+
+ }
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ bool_res = false;
+ if (left is DoubleConstant)
+ bool_res = ((DoubleConstant) left).Value !=
+ ((DoubleConstant) right).Value;
+ else if (left is FloatConstant)
+ bool_res = ((FloatConstant) left).Value !=
+ ((FloatConstant) right).Value;
+ else if (left is ULongConstant)
+ bool_res = ((ULongConstant) left).Value !=
+ ((ULongConstant) right).Value;
+ else if (left is LongConstant)
+ bool_res = ((LongConstant) left).Value !=
+ ((LongConstant) right).Value;
+ else if (left is UIntConstant)
+ bool_res = ((UIntConstant) left).Value !=
+ ((UIntConstant) right).Value;
+ else if (left is IntConstant)
+ bool_res = ((IntConstant) left).Value !=
+ ((IntConstant) right).Value;
+ else
+ return null;
+
+ return new BoolConstant (bool_res);
+
+ case Binary.Operator.LessThan:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ bool_res = false;
+ if (left is DoubleConstant)
+ bool_res = ((DoubleConstant) left).Value <
+ ((DoubleConstant) right).Value;
+ else if (left is FloatConstant)
+ bool_res = ((FloatConstant) left).Value <
+ ((FloatConstant) right).Value;
+ else if (left is ULongConstant)
+ bool_res = ((ULongConstant) left).Value <
+ ((ULongConstant) right).Value;
+ else if (left is LongConstant)
+ bool_res = ((LongConstant) left).Value <
+ ((LongConstant) right).Value;
+ else if (left is UIntConstant)
+ bool_res = ((UIntConstant) left).Value <
+ ((UIntConstant) right).Value;
+ else if (left is IntConstant)
+ bool_res = ((IntConstant) left).Value <
+ ((IntConstant) right).Value;
+ else
+ return null;
+
+ return new BoolConstant (bool_res);
+
+ case Binary.Operator.GreaterThan:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ bool_res = false;
+ if (left is DoubleConstant)
+ bool_res = ((DoubleConstant) left).Value >
+ ((DoubleConstant) right).Value;
+ else if (left is FloatConstant)
+ bool_res = ((FloatConstant) left).Value >
+ ((FloatConstant) right).Value;
+ else if (left is ULongConstant)
+ bool_res = ((ULongConstant) left).Value >
+ ((ULongConstant) right).Value;
+ else if (left is LongConstant)
+ bool_res = ((LongConstant) left).Value >
+ ((LongConstant) right).Value;
+ else if (left is UIntConstant)
+ bool_res = ((UIntConstant) left).Value >
+ ((UIntConstant) right).Value;
+ else if (left is IntConstant)
+ bool_res = ((IntConstant) left).Value >
+ ((IntConstant) right).Value;
+ else
+ return null;
+
+ return new BoolConstant (bool_res);
+
+ case Binary.Operator.GreaterThanOrEqual:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ bool_res = false;
+ if (left is DoubleConstant)
+ bool_res = ((DoubleConstant) left).Value >=
+ ((DoubleConstant) right).Value;
+ else if (left is FloatConstant)
+ bool_res = ((FloatConstant) left).Value >=
+ ((FloatConstant) right).Value;
+ else if (left is ULongConstant)
+ bool_res = ((ULongConstant) left).Value >=
+ ((ULongConstant) right).Value;
+ else if (left is LongConstant)
+ bool_res = ((LongConstant) left).Value >=
+ ((LongConstant) right).Value;
+ else if (left is UIntConstant)
+ bool_res = ((UIntConstant) left).Value >=
+ ((UIntConstant) right).Value;
+ else if (left is IntConstant)
+ bool_res = ((IntConstant) left).Value >=
+ ((IntConstant) right).Value;
+ else
+ return null;
+
+ return new BoolConstant (bool_res);
+
+ case Binary.Operator.LessThanOrEqual:
+ DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
+ if (left == null || right == null)
+ return null;
+
+ bool_res = false;
+ if (left is DoubleConstant)
+ bool_res = ((DoubleConstant) left).Value <=
+ ((DoubleConstant) right).Value;
+ else if (left is FloatConstant)
+ bool_res = ((FloatConstant) left).Value <=
+ ((FloatConstant) right).Value;
+ else if (left is ULongConstant)
+ bool_res = ((ULongConstant) left).Value <=
+ ((ULongConstant) right).Value;
+ else if (left is LongConstant)
+ bool_res = ((LongConstant) left).Value <=
+ ((LongConstant) right).Value;
+ else if (left is UIntConstant)
+ bool_res = ((UIntConstant) left).Value <=
+ ((UIntConstant) right).Value;
+ else if (left is IntConstant)
+ bool_res = ((IntConstant) left).Value <=
+ ((IntConstant) right).Value;
+ else
+ return null;
+
+ return new BoolConstant (bool_res);
+ }
+
+ return null;
+ }
+ }
+}
--- /dev/null
+//
+// class.cs: Class and Struct handlers
+//
+// Authors: Miguel de Icaza (miguel@gnu.org)
+// Martin Baulig (martin@gnome.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+//
+//
+// 2002-10-11 Miguel de Icaza <miguel@ximian.com>
+//
+// * class.cs: Following the comment from 2002-09-26 to AddMethod, I
+// have fixed a remaining problem: not every AddXXXX was adding a
+// fully qualified name.
+//
+// Now everyone registers a fully qualified name in the DeclSpace as
+// being defined instead of the partial name.
+//
+// Downsides: we are slower than we need to be due to the excess
+// copies and the names being registered this way.
+//
+// The reason for this is that we currently depend (on the corlib
+// bootstrap for instance) that types are fully qualified, because
+// we dump all the types in the namespace, and we should really have
+// types inserted into the proper namespace, so we can only store the
+// basenames in the defined_names array.
+//
+//
+#define CACHE
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// This is the base class for structs and classes.
+ /// </summary>
+ public class TypeContainer : DeclSpace, IMemberContainer {
+ // Holds a list of classes and structures
+ ArrayList types;
+
+ // Holds the list of properties
+ ArrayList properties;
+
+ // Holds the list of enumerations
+ ArrayList enums;
+
+ // Holds the list of delegates
+ ArrayList delegates;
+
+ // Holds the list of constructors
+ ArrayList instance_constructors;
+
+ // Holds the list of fields
+ ArrayList fields;
+
+ // Holds a list of fields that have initializers
+ ArrayList initialized_fields;
+
+ // Holds a list of static fields that have initializers
+ ArrayList initialized_static_fields;
+
+ // Holds the list of constants
+ ArrayList constants;
+
+ // Holds the list of
+ ArrayList interfaces;
+
+ // Holds order in which interfaces must be closed
+ ArrayList interface_order;
+
+ // Holds the methods.
+ ArrayList methods;
+
+ // Holds the events
+ ArrayList events;
+
+ // Holds the indexers
+ ArrayList indexers;
+
+ // Holds the operators
+ ArrayList operators;
+
+ // The emit context for toplevel objects.
+ EmitContext ec;
+
+ //
+ // Pointers to the default constructor and the default static constructor
+ //
+ Constructor default_constructor;
+ Constructor default_static_constructor;
+
+ //
+ // Whether we have seen a static constructor for this class or not
+ //
+ bool have_static_constructor = false;
+
+ //
+ // Whether we have at least one non-static field
+ //
+ bool have_nonstatic_fields = false;
+
+ //
+ // This one is computed after we can distinguish interfaces
+ // from classes from the arraylist `type_bases'
+ //
+ string base_class_name;
+
+ ArrayList type_bases;
+
+ // Attributes for this type
+ protected Attributes attributes;
+
+ // Information in the case we are an attribute type
+
+ public AttributeTargets Targets = AttributeTargets.All;
+ public bool AllowMultiple = false;
+ public bool Inherited;
+
+ // The interfaces we implement.
+ Type [] ifaces;
+
+ // The parent member container and our member cache
+ IMemberContainer parent_container;
+ MemberCache member_cache;
+
+ //
+ // The indexer name for this class
+ //
+ public string IndexerName;
+
+ public TypeContainer (TypeContainer parent, string name, Location l)
+ : base (parent, name, l)
+ {
+ string n;
+ types = new ArrayList ();
+
+ if (parent == null)
+ n = "";
+ else
+ n = parent.Name;
+
+ base_class_name = null;
+
+ //Console.WriteLine ("New class " + name + " inside " + n);
+ }
+
+ public AdditionResult AddConstant (Const constant)
+ {
+ AdditionResult res;
+ string basename = constant.Name;
+ string fullname = Name + "." + basename;
+
+ if ((res = IsValid (basename, fullname)) != AdditionResult.Success)
+ return res;
+
+ if (constants == null)
+ constants = new ArrayList ();
+
+ constants.Add (constant);
+ DefineName (fullname, constant);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddEnum (Mono.CSharp.Enum e)
+ {
+ AdditionResult res;
+
+ if ((res = IsValid (e.Basename, e.Name)) != AdditionResult.Success)
+ return res;
+
+ if (enums == null)
+ enums = new ArrayList ();
+
+ enums.Add (e);
+ DefineName (e.Name, e);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddClass (Class c)
+ {
+ AdditionResult res;
+ string name = c.Basename;
+
+ if ((res = IsValid (name, c.Name)) != AdditionResult.Success)
+ return res;
+
+ DefineName (c.Name, c);
+ types.Add (c);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddStruct (Struct s)
+ {
+ AdditionResult res;
+ string name = s.Basename;
+
+ if ((res = IsValid (name, s.Name)) != AdditionResult.Success)
+ return res;
+
+ DefineName (s.Name, s);
+ types.Add (s);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddDelegate (Delegate d)
+ {
+ AdditionResult res;
+ string name = d.Basename;
+
+ if ((res = IsValid (name, d.Name)) != AdditionResult.Success)
+ return res;
+
+ if (delegates == null)
+ delegates = new ArrayList ();
+
+ DefineName (d.Name, d);
+ delegates.Add (d);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddMethod (Method method)
+ {
+ string basename = method.Name;
+ string fullname = Name + "." + basename;
+
+ Object value = defined_names [fullname];
+
+ if (value != null && (!(value is Method)))
+ return AdditionResult.NameExists;
+
+ if (basename == Basename)
+ return AdditionResult.EnclosingClash;
+
+ if (methods == null)
+ methods = new ArrayList ();
+
+ if (method.Name.IndexOf (".") != -1)
+ methods.Insert (0, method);
+ else
+ methods.Add (method);
+
+ if (value == null)
+ DefineName (fullname, method);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddConstructor (Constructor c)
+ {
+ if (c.Name != Basename)
+ return AdditionResult.NotAConstructor;
+
+ bool is_static = (c.ModFlags & Modifiers.STATIC) != 0;
+
+ if (is_static){
+ have_static_constructor = true;
+ if (default_static_constructor != null){
+ Console.WriteLine ("I have a static constructor already");
+ Console.WriteLine (" " + default_static_constructor);
+ return AdditionResult.MethodExists;
+ }
+
+ default_static_constructor = c;
+ } else {
+ if (c.IsDefault ()){
+ if (default_constructor != null)
+ return AdditionResult.MethodExists;
+ default_constructor = c;
+ }
+
+ if (instance_constructors == null)
+ instance_constructors = new ArrayList ();
+
+ instance_constructors.Add (c);
+ }
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddInterface (Interface iface)
+ {
+ AdditionResult res;
+ string name = iface.Basename;
+
+ if ((res = IsValid (name, iface.Name)) != AdditionResult.Success)
+ return res;
+
+ if (interfaces == null)
+ interfaces = new ArrayList ();
+ interfaces.Add (iface);
+ DefineName (iface.Name, iface);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddField (Field field)
+ {
+ AdditionResult res;
+ string basename = field.Name;
+ string fullname = Name + "." + basename;
+
+ if ((res = IsValid (basename, fullname)) != AdditionResult.Success)
+ return res;
+
+ if (fields == null)
+ fields = new ArrayList ();
+
+ fields.Add (field);
+
+ if (field.HasInitializer){
+ if ((field.ModFlags & Modifiers.STATIC) != 0){
+ if (initialized_static_fields == null)
+ initialized_static_fields = new ArrayList ();
+
+ initialized_static_fields.Add (field);
+
+ //
+ // We have not seen a static constructor,
+ // but we will provide static initialization of fields
+ //
+ have_static_constructor = true;
+ } else {
+ if (initialized_fields == null)
+ initialized_fields = new ArrayList ();
+
+ initialized_fields.Add (field);
+ }
+ }
+
+ if ((field.ModFlags & Modifiers.STATIC) == 0)
+ have_nonstatic_fields = true;
+
+ DefineName (fullname, field);
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddProperty (Property prop)
+ {
+ AdditionResult res;
+ string basename = prop.Name;
+ string fullname = Name + "." + basename;
+
+ if ((res = IsValid (basename, fullname)) != AdditionResult.Success)
+ return res;
+
+ if (properties == null)
+ properties = new ArrayList ();
+
+ if (prop.Name.IndexOf (".") != -1)
+ properties.Insert (0, prop);
+ else
+ properties.Add (prop);
+ DefineName (fullname, prop);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddEvent (Event e)
+ {
+ AdditionResult res;
+ string basename = e.Name;
+ string fullname = Name + "." + basename;
+
+ if ((res = IsValid (basename, fullname)) != AdditionResult.Success)
+ return res;
+
+ if (events == null)
+ events = new ArrayList ();
+
+ events.Add (e);
+ DefineName (fullname, e);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddIndexer (Indexer i)
+ {
+ if (indexers == null)
+ indexers = new ArrayList ();
+
+ if (i.InterfaceType != null)
+ indexers.Insert (0, i);
+ else
+ indexers.Add (i);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddOperator (Operator op)
+ {
+ if (operators == null)
+ operators = new ArrayList ();
+
+ operators.Add (op);
+
+ return AdditionResult.Success;
+ }
+
+ public void RegisterOrder (Interface iface)
+ {
+ if (interface_order == null)
+ interface_order = new ArrayList ();
+
+ interface_order.Add (iface);
+ }
+
+ public ArrayList Types {
+ get {
+ return types;
+ }
+ }
+
+ public ArrayList Methods {
+ get {
+ return methods;
+ }
+ }
+
+ public ArrayList Constants {
+ get {
+ return constants;
+ }
+ }
+
+ public ArrayList Interfaces {
+ get {
+ return interfaces;
+ }
+ }
+
+ public string Base {
+ get {
+ return base_class_name;
+ }
+ }
+
+ public ArrayList Bases {
+ get {
+ return type_bases;
+ }
+
+ set {
+ type_bases = value;
+ }
+ }
+
+ public ArrayList Fields {
+ get {
+ return fields;
+ }
+
+ set {
+ fields = value;
+ }
+ }
+
+ public ArrayList InstanceConstructors {
+ get {
+ return instance_constructors;
+ }
+ }
+
+ public ArrayList Properties {
+ get {
+ return properties;
+ }
+ }
+
+ public ArrayList Events {
+ get {
+ return events;
+ }
+ }
+
+ public ArrayList Enums {
+ get {
+ return enums;
+ }
+ }
+
+ public ArrayList Indexers {
+ get {
+ return indexers;
+ }
+ }
+
+ public ArrayList Operators {
+ get {
+ return operators;
+ }
+ }
+
+ public ArrayList Delegates {
+ get {
+ return delegates;
+ }
+ }
+
+ public Attributes OptAttributes {
+ get {
+ return attributes;
+ }
+ }
+
+ public bool HaveStaticConstructor {
+ get {
+ return have_static_constructor;
+ }
+ }
+
+ public virtual TypeAttributes TypeAttr {
+ get {
+ return Modifiers.TypeAttr (ModFlags, this);
+ }
+ }
+
+ //
+ // Emits the instance field initializers
+ //
+ public bool EmitFieldInitializers (EmitContext ec)
+ {
+ ArrayList fields;
+ ILGenerator ig = ec.ig;
+ Expression instance_expr;
+
+ if (ec.IsStatic){
+ fields = initialized_static_fields;
+ instance_expr = null;
+ } else {
+ fields = initialized_fields;
+ instance_expr = new This (Location.Null).Resolve (ec);
+ }
+
+ if (fields == null)
+ return true;
+
+ foreach (Field f in fields){
+ Expression e = f.GetInitializerExpression (ec);
+ if (e == null)
+ return false;
+
+ Location l = f.Location;
+ FieldExpr fe = new FieldExpr (f.FieldBuilder, l);
+ fe.InstanceExpression = instance_expr;
+ ExpressionStatement a = new Assign (fe, e, l);
+
+ a = a.ResolveStatement (ec);
+ if (a == null)
+ return false;
+
+ a.EmitStatement (ec);
+ }
+
+ return true;
+ }
+
+ //
+ // Defines the default constructors
+ //
+ void DefineDefaultConstructor (bool is_static)
+ {
+ Constructor c;
+ int mods = 0;
+
+ c = new Constructor (Basename, Parameters.EmptyReadOnlyParameters,
+ new ConstructorBaseInitializer (
+ null, Parameters.EmptyReadOnlyParameters,
+ Location),
+ Location);
+
+ if (is_static)
+ mods = Modifiers.STATIC;
+
+ c.ModFlags = mods;
+
+ AddConstructor (c);
+
+ c.Block = new Block (null);
+
+ }
+
+ public void ReportStructInitializedInstanceError ()
+ {
+ string n = TypeBuilder.FullName;
+
+ foreach (Field f in initialized_fields){
+ Report.Error (
+ 573, Location,
+ "`" + n + "." + f.Name + "': can not have " +
+ "instance field initializers in structs");
+ }
+ }
+
+ /// <remarks>
+ /// The pending methods that need to be implemented (interfaces or abstract methods)
+ /// </remarks>
+ public PendingImplementation Pending;
+
+ /// <summary>
+ /// This function computes the Base class and also the
+ /// list of interfaces that the class or struct @c implements.
+ ///
+ /// The return value is an array (might be null) of
+ /// interfaces implemented (as Types).
+ ///
+ /// The @parent argument is set to the parent object or null
+ /// if this is `System.Object'.
+ /// </summary>
+ Type [] GetClassBases (bool is_class, out Type parent, out bool error)
+ {
+ ArrayList bases = Bases;
+ int count;
+ int start, j, i;
+
+ error = false;
+
+ if (is_class)
+ parent = null;
+ else
+ parent = TypeManager.value_type;
+
+ if (bases == null){
+ if (is_class){
+ if (RootContext.StdLib)
+ parent = TypeManager.object_type;
+ else if (Name != "System.Object")
+ parent = TypeManager.object_type;
+ } else {
+ //
+ // If we are compiling our runtime,
+ // and we are defining ValueType, then our
+ // parent is `System.Object'.
+ //
+ if (!RootContext.StdLib && Name == "System.ValueType")
+ parent = TypeManager.object_type;
+ }
+
+ return null;
+ }
+
+ //
+ // Bases should be null if there are no bases at all
+ //
+ count = bases.Count;
+
+ if (is_class){
+ Expression name = (Expression) bases [0];
+ name = ResolveTypeExpr (name, false, Location);
+
+ if (name == null){
+ error = true;
+ return null;
+ }
+
+ Type first = name.Type;
+
+ if (first.IsClass){
+ parent = first;
+ start = 1;
+ } else {
+ parent = TypeManager.object_type;
+ start = 0;
+ }
+ if (first.IsSealed){
+ string detail = "";
+
+ if (first.IsValueType)
+ detail = " (a class can not inherit from a struct/enum)";
+
+ Report.Error (509, "class `"+ Name +
+ "': Cannot inherit from sealed class `"+
+ first + "'" + detail);
+ error = true;
+ return null;
+ }
+
+ if (!AsAccessible (parent, ModFlags))
+ Report.Error (60, Location,
+ "Inconsistent accessibility: base class `" +
+ TypeManager.CSharpName (parent) + "' is less " +
+ "accessible than class `" +
+ Name + "'");
+
+ } else {
+ start = 0;
+ }
+
+ if (parent != null)
+ base_class_name = parent.Name;
+
+ Type [] ifaces = new Type [count-start];
+
+ for (i = start, j = 0; i < count; i++, j++){
+ Expression name = (Expression) bases [i];
+ Expression resolved = ResolveTypeExpr (name, false, Location);
+ if (resolved == null)
+ return null;
+
+ bases [i] = resolved;
+ Type t = resolved.Type;
+
+ if (t == null){
+ error = true;
+ return null;
+ }
+
+ if (is_class == false && !t.IsInterface){
+ Report.Error (527, "In Struct `" + Name + "', type `"+
+ name +"' is not an interface");
+ error = true;
+ return null;
+ }
+
+ if (t.IsClass) {
+ if (parent != null){
+ Report.Error (527, "In Class `" + Name + "', type `"+
+ name+"' is not an interface");
+ error = true;
+ return null;
+ }
+ }
+
+ for (int x = 0; x < j; x++) {
+ if (t == ifaces [x]) {
+ Report.Error (528, "`" + name + "' is already listed in interface list");
+ error = true;
+ return null;
+ }
+ }
+
+ ifaces [j] = t;
+ }
+
+ return TypeManager.ExpandInterfaces (ifaces);
+ }
+
+ //
+ // Defines the type in the appropriate ModuleBuilder or TypeBuilder.
+ //
+ public override TypeBuilder DefineType ()
+ {
+ Type parent;
+ bool error;
+ bool is_class;
+
+ if (TypeBuilder != null)
+ return TypeBuilder;
+
+ if (InTransit)
+ return null;
+
+ InTransit = true;
+
+ if (this is Class)
+ is_class = true;
+ else
+ is_class = false;
+
+ ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
+
+ ifaces = GetClassBases (is_class, out parent, out error);
+
+ if (error)
+ return null;
+
+ if (is_class && parent != null){
+ if (parent == TypeManager.enum_type ||
+ (parent == TypeManager.value_type && RootContext.StdLib) ||
+ parent == TypeManager.delegate_type ||
+ parent == TypeManager.array_type){
+ Report.Error (
+ 644, Location, "`" + Name + "' cannot inherit from " +
+ "special class `" + TypeManager.CSharpName (parent) + "'");
+ return null;
+ }
+ }
+
+ if (!is_class && TypeManager.value_type == null)
+ throw new Exception ();
+
+ TypeAttributes type_attributes = TypeAttr;
+
+ // if (parent_builder is ModuleBuilder) {
+ if (IsTopLevel){
+ if (TypeManager.NamespaceClash (Name, Location))
+ return null;
+
+ ModuleBuilder builder = CodeGen.ModuleBuilder;
+ TypeBuilder = builder.DefineType (
+ Name, type_attributes, parent, ifaces);
+
+ } else {
+ TypeBuilder builder = Parent.TypeBuilder;
+ TypeBuilder = builder.DefineNestedType (
+ Basename, type_attributes, parent, ifaces);
+ }
+
+ //
+ // Structs with no fields need to have at least one byte.
+ // The right thing would be to set the PackingSize in a DefineType
+ // but there are no functions that allow interfaces *and* the size to
+ // be specified.
+ //
+
+ if (!is_class && !have_nonstatic_fields){
+ TypeBuilder.DefineField ("$PRIVATE$", TypeManager.byte_type,
+ FieldAttributes.Private);
+ // add interfaces that were not added at type creation
+ if (ifaces != null) {
+ foreach (Type i in ifaces)
+ TypeBuilder.AddInterfaceImplementation (i);
+ }
+ }
+
+ //
+ // Finish the setup for the EmitContext
+ //
+ ec.ContainerType = TypeBuilder;
+
+ TypeManager.AddUserType (Name, TypeBuilder, this, ifaces);
+
+ if ((parent != null) &&
+ (parent == TypeManager.attribute_type ||
+ parent.IsSubclassOf (TypeManager.attribute_type))) {
+ RootContext.RegisterAttribute (this);
+ TypeManager.RegisterAttrType (TypeBuilder, this);
+ } else
+ RootContext.RegisterOrder (this);
+
+ if (Interfaces != null) {
+ foreach (Interface iface in Interfaces)
+ iface.DefineType ();
+ }
+
+ if (Types != null) {
+ foreach (TypeContainer tc in Types)
+ tc.DefineType ();
+ }
+
+ if (Delegates != null) {
+ foreach (Delegate d in Delegates)
+ d.DefineType ();
+ }
+
+ if (Enums != null) {
+ foreach (Enum en in Enums)
+ en.DefineType ();
+ }
+
+ InTransit = false;
+ return TypeBuilder;
+ }
+
+
+ /// <summary>
+ /// Defines the MemberCore objects that are in the `list' Arraylist
+ ///
+ /// The `defined_names' array contains a list of members defined in
+ /// a base class
+ /// </summary>
+ static ArrayList remove_list = new ArrayList ();
+ void DefineMembers (ArrayList list, MemberInfo [] defined_names)
+ {
+ int idx;
+
+ remove_list.Clear ();
+
+ foreach (MemberCore mc in list){
+ if (!mc.Define (this)){
+ remove_list.Add (mc);
+ continue;
+ }
+
+ if (defined_names == null)
+ continue;
+
+ idx = Array.BinarySearch (defined_names, mc.Name, mif_compare);
+ if (idx < 0){
+ if (RootContext.WarningLevel >= 4){
+ if ((mc.ModFlags & Modifiers.NEW) != 0)
+ Warning_KewywordNewNotRequired (mc.Location, mc);
+ }
+ continue;
+ }
+
+ MemberInfo match = defined_names [idx];
+
+ if (match is PropertyInfo && ((mc.ModFlags & Modifiers.OVERRIDE) != 0))
+ continue;
+
+ //
+ // If we are both methods, let the method resolution emit warnings
+ //
+ if (match is MethodBase && mc is MethodCore)
+ continue;
+
+ if ((mc.ModFlags & Modifiers.NEW) == 0) {
+ if (mc is Event) {
+ if (!(match is EventInfo)) {
+ Error_EventCanOnlyOverrideEvent (mc.Location, defined_names [idx]);
+ return;
+ }
+
+ if ((mc.ModFlags & Modifiers.OVERRIDE) != 0)
+ continue;
+ }
+
+ Warning_KeywordNewRequired (mc.Location, defined_names [idx]);
+ }
+ }
+
+ foreach (object o in remove_list)
+ list.Remove (o);
+
+ remove_list.Clear ();
+ }
+
+ //
+ // Defines the indexers, and also verifies that the IndexerNameAttribute in the
+ // class is consisten. Either it is `Item' or it is the name defined by all the
+ // indexers with the `IndexerName' attribute.
+ //
+ // Turns out that the IndexerNameAttribute is applied to each indexer,
+ // but it is never emitted, instead a DefaultName attribute is attached
+ // to the class.
+ //
+ void DefineIndexers ()
+ {
+ string class_indexer_name = null;
+
+ //
+ // If there's both an explicit and an implicit interface implementation, the
+ // explicit one actually implements the interface while the other one is just
+ // a normal indexer. See bug #37714.
+ //
+ ArrayList list = new ArrayList ();
+ foreach (Indexer i in Indexers){
+ if (i.ExplicitInterfaceName != null)
+ list.Add (i);
+ }
+ foreach (Indexer i in Indexers){
+ if (i.ExplicitInterfaceName == null)
+ list.Add (i);
+ }
+
+ foreach (Indexer i in list){
+ string name;
+
+ i.Define (this);
+
+ name = i.IndexerName;
+
+ if (i.InterfaceType != null)
+ continue;
+
+ if (class_indexer_name == null){
+ class_indexer_name = name;
+ continue;
+ }
+
+ if (name == class_indexer_name)
+ continue;
+
+ Report.Error (
+ 668, "Two indexers have different names, " +
+ " you should use the same name for all your indexers");
+ }
+ if (class_indexer_name == null)
+ class_indexer_name = "Item";
+ IndexerName = class_indexer_name;
+ }
+
+ static void Error_KeywordNotAllowed (Location loc)
+ {
+ Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
+ }
+
+ /// <summary>
+ /// Populates our TypeBuilder with fields and methods
+ /// </summary>
+ public override bool DefineMembers (TypeContainer container)
+ {
+ MemberInfo [] defined_names = null;
+
+ if (interface_order != null){
+ foreach (Interface iface in interface_order)
+ if ((iface.ModFlags & Modifiers.NEW) == 0)
+ iface.DefineMembers (this);
+ else
+ Error_KeywordNotAllowed (iface.Location);
+ }
+
+ if (RootContext.WarningLevel > 1){
+ Type ptype;
+
+ //
+ // This code throws an exception in the comparer
+ // I guess the string is not an object?
+ //
+ ptype = TypeBuilder.BaseType;
+ if (ptype != null){
+ defined_names = (MemberInfo []) FindMembers (
+ ptype, MemberTypes.All & ~MemberTypes.Constructor,
+ BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.Static, null, null);
+
+ Array.Sort (defined_names, mif_compare);
+ }
+ }
+
+ Class pclass = Parent as Class;
+ if (pclass != null) {
+ string pname = null;
+ Type ptype = null;
+ Type t = pclass.TypeBuilder.BaseType;
+ while ((t != null) && (ptype == null)) {
+ pname = MakeFQN (t.Name, Basename);
+ ptype = RootContext.LookupType (this, pname, true, Location.Null);
+ t = t.BaseType;
+ }
+
+ if ((ModFlags & Modifiers.NEW) != 0) {
+ if (ptype == null)
+ Report.Warning (109, Location, "The member '" + Name + "' does not hide an " +
+ "inherited member. The keyword new is not required.");
+ } else if (ptype != null) {
+ Report.Warning (108, Location, "The keyword new is required on `" +
+ Name + "' because it hides inherited member '" +
+ pname + "'.");
+ }
+ } else if ((ModFlags & Modifiers.NEW) != 0)
+ Error_KeywordNotAllowed (Location);
+
+ if (constants != null)
+ DefineMembers (constants, defined_names);
+
+ if (fields != null)
+ DefineMembers (fields, defined_names);
+
+ if (this is Class){
+ if (instance_constructors == null){
+ if (default_constructor == null)
+ DefineDefaultConstructor (false);
+ }
+
+ if (initialized_static_fields != null &&
+ default_static_constructor == null)
+ DefineDefaultConstructor (true);
+ }
+
+ if (this is Struct){
+ //
+ // Structs can not have initialized instance
+ // fields
+ //
+ if (initialized_static_fields != null &&
+ default_static_constructor == null)
+ DefineDefaultConstructor (true);
+
+ if (initialized_fields != null)
+ ReportStructInitializedInstanceError ();
+ }
+
+ Pending = PendingImplementation.GetPendingImplementations (this);
+
+ //
+ // Constructors are not in the defined_names array
+ //
+ if (instance_constructors != null)
+ DefineMembers (instance_constructors, null);
+
+ if (default_static_constructor != null)
+ default_static_constructor.Define (this);
+
+ if (methods != null)
+ DefineMembers (methods, defined_names);
+
+ if (properties != null)
+ DefineMembers (properties, defined_names);
+
+ if (events != null)
+ DefineMembers (events, defined_names);
+
+ if (indexers != null) {
+ DefineIndexers ();
+ } else
+ IndexerName = "Item";
+
+ if (operators != null){
+ DefineMembers (operators, null);
+
+ CheckPairedOperators ();
+ }
+
+ if (enums != null)
+ DefineMembers (enums, defined_names);
+
+ if (delegates != null)
+ DefineMembers (delegates, defined_names);
+
+#if CACHE
+ if (TypeBuilder.BaseType != null)
+ parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
+
+ member_cache = new MemberCache (this);
+#endif
+
+
+ return true;
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ if (interface_order != null){
+ foreach (Interface iface in interface_order)
+ if ((iface.ModFlags & Modifiers.NEW) == 0)
+ iface.Define (this);
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// This function is based by a delegate to the FindMembers routine
+ /// </summary>
+ static bool AlwaysAccept (MemberInfo m, object filterCriteria)
+ {
+ return true;
+ }
+
+ /// <summary>
+ /// This filter is used by FindMembers, and we just keep
+ /// a global for the filter to `AlwaysAccept'
+ /// </summary>
+ static MemberFilter accepting_filter;
+
+
+ /// <summary>
+ /// A member comparission method based on name only
+ /// </summary>
+ static IComparer mif_compare;
+
+ static TypeContainer ()
+ {
+ accepting_filter = new MemberFilter (AlwaysAccept);
+ mif_compare = new MemberInfoCompare ();
+ }
+
+ /// <summary>
+ /// This method returns the members of this type just like Type.FindMembers would
+ /// Only, we need to use this for types which are _being_ defined because MS'
+ /// implementation can't take care of that.
+ /// </summary>
+ //
+ // FIXME: return an empty static array instead of null, that cleans up
+ // some code and is consistent with some coding conventions I just found
+ // out existed ;-)
+ //
+ //
+ // Notice that in various cases we check if our field is non-null,
+ // something that would normally mean that there was a bug elsewhere.
+ //
+ // The problem happens while we are defining p-invoke methods, as those
+ // will trigger a FindMembers, but this happens before things are defined
+ //
+ // Since the whole process is a no-op, it is fine to check for null here.
+ //
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList ();
+
+ int modflags = 0;
+ if ((bf & BindingFlags.Public) != 0)
+ modflags |= Modifiers.PUBLIC | Modifiers.PROTECTED |
+ Modifiers.INTERNAL;
+ if ((bf & BindingFlags.NonPublic) != 0)
+ modflags |= Modifiers.PRIVATE;
+
+ int static_mask = 0, static_flags = 0;
+ switch (bf & (BindingFlags.Static | BindingFlags.Instance)) {
+ case BindingFlags.Static:
+ static_mask = static_flags = Modifiers.STATIC;
+ break;
+
+ case BindingFlags.Instance:
+ static_mask = Modifiers.STATIC;
+ static_flags = 0;
+ break;
+
+ default:
+ static_mask = static_flags = 0;
+ break;
+ }
+
+ Timer.StartTimer (TimerType.TcFindMembers);
+
+ if (filter == null)
+ filter = accepting_filter;
+
+ if ((mt & MemberTypes.Field) != 0) {
+ if (fields != null) {
+ foreach (Field f in fields) {
+ if ((f.ModFlags & modflags) == 0)
+ continue;
+ if ((f.ModFlags & static_mask) != static_flags)
+ continue;
+
+ FieldBuilder fb = f.FieldBuilder;
+ if (fb != null && filter (fb, criteria) == true)
+ members.Add (fb);
+ }
+ }
+
+ if (constants != null) {
+ foreach (Const con in constants) {
+ if ((con.ModFlags & modflags) == 0)
+ continue;
+ if ((con.ModFlags & static_mask) != static_flags)
+ continue;
+
+ FieldBuilder fb = con.FieldBuilder;
+ if (fb != null && filter (fb, criteria) == true)
+ members.Add (fb);
+ }
+ }
+ }
+
+ if ((mt & MemberTypes.Method) != 0) {
+ if (methods != null) {
+ foreach (Method m in methods) {
+ if ((m.ModFlags & modflags) == 0)
+ continue;
+ if ((m.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MethodBuilder mb = m.MethodBuilder;
+
+ if (mb != null && filter (mb, criteria) == true)
+ members.Add (mb);
+ }
+ }
+
+ if (operators != null){
+ foreach (Operator o in operators) {
+ if ((o.ModFlags & modflags) == 0)
+ continue;
+ if ((o.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MethodBuilder ob = o.OperatorMethodBuilder;
+ if (ob != null && filter (ob, criteria) == true)
+ members.Add (ob);
+ }
+ }
+
+ if (properties != null){
+ foreach (Property p in properties){
+ if ((p.ModFlags & modflags) == 0)
+ continue;
+ if ((p.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MethodBuilder b;
+
+ b = p.GetBuilder;
+ if (b != null && filter (b, criteria) == true)
+ members.Add (b);
+
+ b = p.SetBuilder;
+ if (b != null && filter (b, criteria) == true)
+ members.Add (b);
+ }
+ }
+
+ if (indexers != null){
+ foreach (Indexer ix in indexers){
+ if ((ix.ModFlags & modflags) == 0)
+ continue;
+ if ((ix.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MethodBuilder b;
+
+ b = ix.GetBuilder;
+ if (b != null && filter (b, criteria) == true)
+ members.Add (b);
+
+ b = ix.SetBuilder;
+ if (b != null && filter (b, criteria) == true)
+ members.Add (b);
+ }
+ }
+ }
+
+ if ((mt & MemberTypes.Event) != 0) {
+ if (events != null)
+ foreach (Event e in events) {
+ if ((e.ModFlags & modflags) == 0)
+ continue;
+ if ((e.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MemberInfo eb = e.EventBuilder;
+ if (eb != null && filter (eb, criteria) == true)
+ members.Add (e.EventBuilder);
+ }
+ }
+
+ if ((mt & MemberTypes.Property) != 0){
+ if (properties != null)
+ foreach (Property p in properties) {
+ if ((p.ModFlags & modflags) == 0)
+ continue;
+ if ((p.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MemberInfo pb = p.PropertyBuilder;
+ if (pb != null && filter (pb, criteria) == true) {
+ members.Add (p.PropertyBuilder);
+ }
+ }
+
+ if (indexers != null)
+ foreach (Indexer ix in indexers) {
+ if ((ix.ModFlags & modflags) == 0)
+ continue;
+ if ((ix.ModFlags & static_mask) != static_flags)
+ continue;
+
+ MemberInfo ib = ix.PropertyBuilder;
+ if (ib != null && filter (ib, criteria) == true) {
+ members.Add (ix.PropertyBuilder);
+ }
+ }
+ }
+
+ if ((mt & MemberTypes.NestedType) != 0) {
+ if (types != null){
+ foreach (TypeContainer t in types) {
+ if ((t.ModFlags & modflags) == 0)
+ continue;
+
+ TypeBuilder tb = t.TypeBuilder;
+ if (tb != null && (filter (tb, criteria) == true))
+ members.Add (tb);
+ }
+ }
+
+ if (enums != null){
+ foreach (Enum en in enums){
+ if ((en.ModFlags & modflags) == 0)
+ continue;
+
+ TypeBuilder tb = en.TypeBuilder;
+ if (tb != null && (filter (tb, criteria) == true))
+ members.Add (tb);
+ }
+ }
+
+ if (delegates != null){
+ foreach (Delegate d in delegates){
+ if ((d.ModFlags & modflags) == 0)
+ continue;
+
+ TypeBuilder tb = d.TypeBuilder;
+ if (tb != null && (filter (tb, criteria) == true))
+ members.Add (tb);
+ }
+ }
+
+ if (interfaces != null){
+ foreach (Interface iface in interfaces){
+ if ((iface.ModFlags & modflags) == 0)
+ continue;
+
+ TypeBuilder tb = iface.TypeBuilder;
+ if (tb != null && (filter (tb, criteria) == true))
+ members.Add (tb);
+ }
+ }
+ }
+
+ if ((mt & MemberTypes.Constructor) != 0){
+ if (((bf & BindingFlags.Instance) != 0) && (instance_constructors != null)){
+ foreach (Constructor c in instance_constructors){
+ ConstructorBuilder cb = c.ConstructorBuilder;
+ if (cb != null)
+ if (filter (cb, criteria) == true)
+ members.Add (cb);
+ }
+ }
+
+ if (((bf & BindingFlags.Static) != 0) && (default_static_constructor != null)){
+ ConstructorBuilder cb =
+ default_static_constructor.ConstructorBuilder;
+
+ if (cb != null)
+ if (filter (cb, criteria) == true)
+ members.Add (cb);
+ }
+ }
+
+ //
+ // Lookup members in parent if requested.
+ //
+ if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
+ MemberList list = FindMembers (TypeBuilder.BaseType, mt, bf, filter, criteria);
+ members.AddRange (list);
+ }
+
+ Timer.StopTimer (TimerType.TcFindMembers);
+
+ return new MemberList (members);
+ }
+
+ public override MemberCache MemberCache {
+ get {
+ return member_cache;
+ }
+ }
+
+ public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ DeclSpace ds = TypeManager.LookupDeclSpace (t);
+
+ if (ds != null)
+ return ds.FindMembers (mt, bf, filter, criteria);
+ else
+ return new MemberList (t.FindMembers (mt, bf, filter, criteria));
+ }
+
+ //
+ // FindMethods will look for methods not only in the type `t', but in
+ // any interfaces implemented by the type.
+ //
+ public static MethodInfo [] FindMethods (Type t, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ return null;
+ }
+
+ /// <summary>
+ /// Emits the values for the constants
+ /// </summary>
+ public void EmitConstants ()
+ {
+ if (constants != null)
+ foreach (Const con in constants)
+ con.EmitConstant (this);
+ return;
+ }
+
+ /// <summary>
+ /// Emits the code, this step is performed after all
+ /// the types, enumerations, constructors
+ /// </summary>
+ public void Emit ()
+ {
+ if (instance_constructors != null)
+ foreach (Constructor c in instance_constructors)
+ c.Emit (this);
+
+ if (default_static_constructor != null)
+ default_static_constructor.Emit (this);
+
+ if (methods != null)
+ foreach (Method m in methods)
+ m.Emit (this);
+
+ if (operators != null)
+ foreach (Operator o in operators)
+ o.Emit (this);
+
+ if (properties != null)
+ foreach (Property p in properties)
+ p.Emit (this);
+
+ if (indexers != null){
+ foreach (Indexer ix in indexers)
+ ix.Emit (this);
+
+ CustomAttributeBuilder cb = Interface.EmitDefaultMemberAttr (
+ this, IndexerName, ModFlags, Location);
+ TypeBuilder.SetCustomAttribute (cb);
+ }
+
+ if (fields != null)
+ foreach (Field f in fields)
+ f.Emit (this);
+
+ if (events != null){
+ foreach (Event e in Events)
+ e.Emit (this);
+ }
+
+ if (Pending != null)
+ if (Pending.VerifyPendingMethods ())
+ return;
+
+ Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
+
+ //
+ // Check for internal or private fields that were never assigned
+ //
+ if (RootContext.WarningLevel >= 3) {
+ if (fields != null){
+ foreach (Field f in fields) {
+ if ((f.ModFlags & Modifiers.PUBLIC) != 0)
+ continue;
+
+ if (f.status == 0){
+ Report.Warning (
+ 169, f.Location, "Private field " +
+ MakeName (f.Name) + " is never used");
+ continue;
+ }
+
+ //
+ // Only report 649 on level 4
+ //
+ if (RootContext.WarningLevel < 4)
+ continue;
+
+ if ((f.status & Field.Status.ASSIGNED) != 0)
+ continue;
+
+ Report.Warning (
+ 649, f.Location,
+ "Field " + MakeName (f.Name) + " is never assigned " +
+ " to and will always have its default value");
+ }
+ }
+
+ if (events != null){
+ foreach (Event e in events){
+ if (e.status == 0)
+ Report.Warning (67, "The event " + MakeName (e.Name) + " is never used");
+ }
+ }
+ }
+
+// if (types != null)
+// foreach (TypeContainer tc in types)
+// tc.Emit ();
+ }
+
+ public override void CloseType ()
+ {
+ try {
+ if (!Created){
+ Created = true;
+ TypeBuilder.CreateType ();
+ }
+ } catch (TypeLoadException){
+ //
+ // This is fine, the code still created the type
+ //
+// Report.Warning (-20, "Exception while creating class: " + TypeBuilder.Name);
+// Console.WriteLine (e.Message);
+ } catch {
+ Console.WriteLine ("In type: " + Name);
+ throw;
+ }
+
+ if (Enums != null)
+ foreach (Enum en in Enums)
+ en.CloseType ();
+
+ if (interface_order != null){
+ foreach (Interface iface in interface_order)
+ iface.CloseType ();
+ }
+
+ if (Types != null){
+ foreach (TypeContainer tc in Types)
+ if (tc is Struct)
+ tc.CloseType ();
+
+ foreach (TypeContainer tc in Types)
+ if (!(tc is Struct))
+ tc.CloseType ();
+ }
+
+ if (Delegates != null)
+ foreach (Delegate d in Delegates)
+ d.CloseType ();
+ }
+
+ public string MakeName (string n)
+ {
+ return "`" + Name + "." + n + "'";
+ }
+
+ public void Warning_KeywordNewRequired (Location l, MemberInfo mi)
+ {
+ Report.Warning (
+ 108, l, "The keyword new is required on " +
+ MakeName (mi.Name) + " because it hides `" +
+ mi.ReflectedType.Name + "." + mi.Name + "'");
+ }
+
+ public void Warning_KewywordNewNotRequired (Location l, MemberCore mc)
+ {
+ Report.Warning (
+ 109, l, "The member " + MakeName (mc.Name) + " does not hide an " +
+ "inherited member, the keyword new is not required");
+ }
+
+ public void Error_EventCanOnlyOverrideEvent (Location l, MemberInfo mi)
+ {
+ Report.Error (
+ 72, l, MakeName (mi.Name) + " : cannot override; `" +
+ mi.ReflectedType.Name + "." + mi.Name + "' is not an event");
+ }
+
+ public static int CheckMember (string name, MemberInfo mi, int ModFlags)
+ {
+ return 0;
+ }
+
+ //
+ // Performs the validation on a Method's modifiers (properties have
+ // the same properties).
+ //
+ public bool MethodModifiersValid (int flags, string n, Location loc)
+ {
+ const int vao = (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE);
+ const int va = (Modifiers.VIRTUAL | Modifiers.ABSTRACT);
+ const int nv = (Modifiers.NEW | Modifiers.VIRTUAL);
+ bool ok = true;
+
+ //
+ // At most one of static, virtual or override
+ //
+ if ((flags & Modifiers.STATIC) != 0){
+ if ((flags & vao) != 0){
+ Report.Error (
+ 112, loc, "static method " + MakeName (n) + "can not be marked " +
+ "as virtual, abstract or override");
+ ok = false;
+ }
+ }
+
+ if (this is Struct){
+ if ((flags & va) != 0){
+ Modifiers.Error_InvalidModifier (loc, "virtual or abstract");
+ ok = false;
+ }
+ }
+
+ if ((flags & Modifiers.OVERRIDE) != 0 && (flags & nv) != 0){
+ Report.Error (
+ 113, loc, MakeName (n) +
+ " marked as override cannot be marked as new or virtual");
+ ok = false;
+ }
+
+ //
+ // If the declaration includes the abstract modifier, then the
+ // declaration does not include static, virtual or extern
+ //
+ if ((flags & Modifiers.ABSTRACT) != 0){
+ if ((flags & Modifiers.EXTERN) != 0){
+ Report.Error (
+ 180, loc, MakeName (n) + " can not be both abstract and extern");
+ ok = false;
+ }
+
+ if ((flags & Modifiers.VIRTUAL) != 0){
+ Report.Error (
+ 503, loc, MakeName (n) + " can not be both abstract and virtual");
+ ok = false;
+ }
+
+ if ((ModFlags & Modifiers.ABSTRACT) == 0){
+ Report.Error (
+ 513, loc, MakeName (n) +
+ " is abstract but its container class is not");
+ ok = false;
+
+ }
+ }
+
+ if ((flags & Modifiers.PRIVATE) != 0){
+ if ((flags & vao) != 0){
+ Report.Error (
+ 621, loc, MakeName (n) +
+ " virtual or abstract members can not be private");
+ ok = false;
+ }
+ }
+
+ if ((flags & Modifiers.SEALED) != 0){
+ if ((flags & Modifiers.OVERRIDE) == 0){
+ Report.Error (
+ 238, loc, MakeName (n) +
+ " cannot be sealed because it is not an override");
+ ok = false;
+ }
+ }
+
+ return ok;
+ }
+
+ // Access level of a type.
+ enum AccessLevel {
+ Public = 0,
+ ProtectedInternal = 1,
+ Internal = 2,
+ Protected = 3,
+ Private = 4
+ }
+
+ // Check whether `flags' denotes a more restricted access than `level'
+ // and return the new level.
+ static AccessLevel CheckAccessLevel (AccessLevel level, int flags)
+ {
+ AccessLevel old_level = level;
+
+ if ((flags & Modifiers.INTERNAL) != 0) {
+ if ((flags & Modifiers.PROTECTED) != 0) {
+ if ((int) level < (int) AccessLevel.ProtectedInternal)
+ level = AccessLevel.ProtectedInternal;
+ } else {
+ if ((int) level < (int) AccessLevel.Internal)
+ level = AccessLevel.Internal;
+ }
+ } else if ((flags & Modifiers.PROTECTED) != 0) {
+ if ((int) level < (int) AccessLevel.Protected)
+ level = AccessLevel.Protected;
+ } else if ((flags & Modifiers.PRIVATE) != 0)
+ level = AccessLevel.Private;
+
+ return level;
+ }
+
+ // Return the access level for a new member which is defined in the current
+ // TypeContainer with access modifiers `flags'.
+ AccessLevel GetAccessLevel (int flags)
+ {
+ if ((flags & Modifiers.PRIVATE) != 0)
+ return AccessLevel.Private;
+
+ AccessLevel level;
+ if (!IsTopLevel && (Parent != null))
+ level = Parent.GetAccessLevel (flags);
+ else
+ level = AccessLevel.Public;
+
+ return CheckAccessLevel (CheckAccessLevel (level, flags), ModFlags);
+ }
+
+ // Return the access level for type `t', but don't give more access than `flags'.
+ static AccessLevel GetAccessLevel (Type t, int flags)
+ {
+ if (((flags & Modifiers.PRIVATE) != 0) || t.IsNestedPrivate)
+ return AccessLevel.Private;
+
+ AccessLevel level;
+ if (TypeManager.IsBuiltinType (t))
+ return AccessLevel.Public;
+ else if ((t.DeclaringType != null) && (t != t.DeclaringType))
+ level = GetAccessLevel (t.DeclaringType, flags);
+ else {
+ level = CheckAccessLevel (AccessLevel.Public, flags);
+ }
+
+ if (t.IsNestedPublic)
+ return level;
+
+ if (t.IsNestedAssembly || t.IsNotPublic) {
+ if ((int) level < (int) AccessLevel.Internal)
+ level = AccessLevel.Internal;
+ }
+
+ if (t.IsNestedFamily) {
+ if ((int) level < (int) AccessLevel.Protected)
+ level = AccessLevel.Protected;
+ }
+
+ if (t.IsNestedFamORAssem) {
+ if ((int) level < (int) AccessLevel.ProtectedInternal)
+ level = AccessLevel.ProtectedInternal;
+ }
+
+ return level;
+ }
+
+ //
+ // Returns true if `parent' is as accessible as the flags `flags'
+ // given for this member.
+ //
+ public bool AsAccessible (Type parent, int flags)
+ {
+ while (parent.IsArray || parent.IsPointer || parent.IsByRef)
+ parent = TypeManager.GetElementType (parent);
+
+ AccessLevel level = GetAccessLevel (flags);
+ AccessLevel level2 = GetAccessLevel (parent, flags);
+
+ return (int) level >= (int) level2;
+ }
+
+ Hashtable builder_and_args;
+
+ public bool RegisterMethod (MethodBuilder mb, InternalParameters ip, Type [] args)
+ {
+ if (builder_and_args == null)
+ builder_and_args = new Hashtable ();
+ return true;
+ }
+
+ /// <summary>
+ /// Performs checks for an explicit interface implementation. First it
+ /// checks whether the `interface_type' is a base inteface implementation.
+ /// Then it checks whether `name' exists in the interface type.
+ /// </summary>
+ public bool VerifyImplements (Type interface_type, string full, string name, Location loc)
+ {
+ bool found = false;
+
+ if (ifaces != null){
+ foreach (Type t in ifaces){
+ if (t == interface_type){
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found){
+ Report.Error (540, "`" + full + "': containing class does not implement interface `" + interface_type.FullName + "'");
+ return false;
+ }
+
+ return true;
+ }
+
+ public static void Error_ExplicitInterfaceNotMemberInterface (Location loc, string name)
+ {
+ Report.Error (539, loc, "Explicit implementation: `" + name + "' is not a member of the interface");
+ }
+
+ //
+ // IMemberContainer
+ //
+
+ string IMemberContainer.Name {
+ get {
+ return Name;
+ }
+ }
+
+ Type IMemberContainer.Type {
+ get {
+ return TypeBuilder;
+ }
+ }
+
+ IMemberContainer IMemberContainer.Parent {
+ get {
+ return parent_container;
+ }
+ }
+
+ MemberCache IMemberContainer.MemberCache {
+ get {
+ return member_cache;
+ }
+ }
+
+ bool IMemberContainer.IsInterface {
+ get {
+ return false;
+ }
+ }
+
+ MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
+ {
+ return FindMembers (mt, bf | BindingFlags.DeclaredOnly, null, null);
+ }
+
+ //
+ // Operator pair checking
+ //
+
+ class OperatorEntry {
+ public int flags;
+ public Type ret_type;
+ public Type type1, type2;
+ public Operator op;
+ public Operator.OpType ot;
+
+ public OperatorEntry (int f, Operator o)
+ {
+ flags = f;
+
+ ret_type = o.OperatorMethod.GetReturnType ();
+ Type [] pt = o.OperatorMethod.ParameterTypes;
+ type1 = pt [0];
+ type2 = pt [1];
+ op = o;
+ ot = o.OperatorType;
+ }
+
+ public override int GetHashCode ()
+ {
+ return ret_type.GetHashCode ();
+ }
+
+ public override bool Equals (object o)
+ {
+ OperatorEntry other = (OperatorEntry) o;
+
+ if (other.ret_type != ret_type)
+ return false;
+ if (other.type1 != type1)
+ return false;
+ if (other.type2 != type2)
+ return false;
+ return true;
+ }
+ }
+
+ //
+ // Checks that some operators come in pairs:
+ // == and !=
+ // > and <
+ // >= and <=
+ // true and false
+ //
+ // They are matched based on the return type and the argument types
+ //
+ void CheckPairedOperators ()
+ {
+ Hashtable pairs = new Hashtable (null, null);
+ Operator true_op = null;
+ Operator false_op = null;
+ bool has_equality_or_inequality = false;
+
+ // Register all the operators we care about.
+ foreach (Operator op in operators){
+ int reg = 0;
+
+ switch (op.OperatorType){
+ case Operator.OpType.Equality:
+ reg = 1;
+ has_equality_or_inequality = true;
+ break;
+ case Operator.OpType.Inequality:
+ reg = 2;
+ has_equality_or_inequality = true;
+ break;
+
+ case Operator.OpType.True:
+ true_op = op;
+ break;
+ case Operator.OpType.False:
+ false_op = op;
+ break;
+
+ case Operator.OpType.GreaterThan:
+ reg = 1; break;
+ case Operator.OpType.LessThan:
+ reg = 2; break;
+
+ case Operator.OpType.GreaterThanOrEqual:
+ reg = 1; break;
+ case Operator.OpType.LessThanOrEqual:
+ reg = 2; break;
+ }
+ if (reg == 0)
+ continue;
+
+ OperatorEntry oe = new OperatorEntry (reg, op);
+
+ object o = pairs [oe];
+ if (o == null)
+ pairs [oe] = oe;
+ else {
+ oe = (OperatorEntry) o;
+ oe.flags |= reg;
+ }
+ }
+
+ if (true_op != null){
+ if (false_op == null)
+ Report.Error (216, true_op.Location, "operator true requires a matching operator false");
+ } else if (false_op != null)
+ Report.Error (216, false_op.Location, "operator false requires a matching operator true");
+
+ //
+ // Look for the mistakes.
+ //
+ foreach (DictionaryEntry de in pairs){
+ OperatorEntry oe = (OperatorEntry) de.Key;
+
+ if (oe.flags == 3)
+ continue;
+
+ string s = "";
+ switch (oe.ot){
+ case Operator.OpType.Equality:
+ s = "!=";
+ break;
+ case Operator.OpType.Inequality:
+ s = "==";
+ break;
+ case Operator.OpType.GreaterThan:
+ s = "<";
+ break;
+ case Operator.OpType.LessThan:
+ s = ">";
+ break;
+ case Operator.OpType.GreaterThanOrEqual:
+ s = "<=";
+ break;
+ case Operator.OpType.LessThanOrEqual:
+ s = ">=";
+ break;
+ }
+ Report.Error (216, oe.op.Location,
+ "The operator `" + oe.op + "' requires a matching operator `" + s + "' to also be defined");
+ }
+
+ if ((has_equality_or_inequality) && (RootContext.WarningLevel >= 2)) {
+ MethodSignature equals_ms = new MethodSignature (
+ "Equals", TypeManager.bool_type, new Type [] { TypeManager.object_type });
+ MethodSignature hash_ms = new MethodSignature (
+ "GetHashCode", TypeManager.int32_type, new Type [0]);
+
+ MemberList equals_ml = FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly, MethodSignature.method_signature_filter,
+ equals_ms);
+ MemberList hash_ml = FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly, MethodSignature.method_signature_filter,
+ hash_ms);
+
+ bool equals_ok = false;
+ if ((equals_ml != null) && (equals_ml.Count == 1))
+ equals_ok = equals_ml [0].DeclaringType == TypeBuilder;
+ bool hash_ok = false;
+ if ((hash_ml != null) && (hash_ml.Count == 1))
+ hash_ok = hash_ml [0].DeclaringType == TypeBuilder;
+
+ if (!equals_ok)
+ Report.Warning (660, Location, "`" + Name + "' defines operator == or operator != but does " +
+ "not override Object.Equals (object o)");
+ if (!hash_ok)
+ Report.Warning (661, Location, "`" + Name + "' defines operator == or operator != but does " +
+ "not override Object.GetHashCode ()");
+ }
+ }
+
+
+ }
+
+ public class Class : TypeContainer {
+ // <summary>
+ // Modifiers allowed in a class declaration
+ // </summary>
+ public const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE |
+ Modifiers.ABSTRACT |
+ Modifiers.SEALED |
+ Modifiers.UNSAFE;
+
+ public Class (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
+ : base (parent, name, l)
+ {
+ int accmods;
+
+ if (parent.Parent == null)
+ accmods = Modifiers.INTERNAL;
+ else
+ accmods = Modifiers.PRIVATE;
+
+ this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l);
+ this.attributes = attrs;
+ }
+
+ //
+ // FIXME: How do we deal with the user specifying a different
+ // layout?
+ //
+ public override TypeAttributes TypeAttr {
+ get {
+ return base.TypeAttr | TypeAttributes.AutoLayout | TypeAttributes.Class;
+ }
+ }
+ }
+
+ public class Struct : TypeContainer {
+ // <summary>
+ // Modifiers allowed in a struct declaration
+ // </summary>
+ public const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.UNSAFE |
+ Modifiers.PRIVATE;
+
+ public Struct (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
+ : base (parent, name, l)
+ {
+ int accmods;
+
+ if (parent.Parent == null)
+ accmods = Modifiers.INTERNAL;
+ else
+ accmods = Modifiers.PRIVATE;
+
+ this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l);
+
+ this.ModFlags |= Modifiers.SEALED;
+ this.attributes = attrs;
+
+ }
+
+ //
+ // FIXME: Allow the user to specify a different set of attributes
+ // in some cases (Sealed for example is mandatory for a class,
+ // but what SequentialLayout can be changed
+ //
+ public override TypeAttributes TypeAttr {
+ get {
+ return base.TypeAttr |
+ TypeAttributes.SequentialLayout |
+ TypeAttributes.Sealed |
+ TypeAttributes.BeforeFieldInit;
+ }
+ }
+ }
+
+ public abstract class MethodCore : MemberBase {
+ public readonly Parameters Parameters;
+ protected Block block;
+
+ //
+ // Parameters, cached for semantic analysis.
+ //
+ protected InternalParameters parameter_info;
+ protected Type [] parameter_types;
+
+ public MethodCore (Expression type, int mod, int allowed_mod, string name,
+ Attributes attrs, Parameters parameters, Location loc)
+ : base (type, mod, allowed_mod, name, attrs, loc)
+ {
+ Parameters = parameters;
+ }
+
+ //
+ // Returns the System.Type array for the parameters of this method
+ //
+ public Type [] ParameterTypes {
+ get {
+ return parameter_types;
+ }
+ }
+
+ public InternalParameters ParameterInfo
+ {
+ get {
+ return parameter_info;
+ }
+ }
+
+ public Block Block {
+ get {
+ return block;
+ }
+
+ set {
+ block = value;
+ }
+ }
+
+ protected virtual bool DoDefineParameters (TypeContainer container)
+ {
+ // Check if arguments were correct
+ parameter_types = Parameters.GetParameterInfo (container);
+ if ((parameter_types == null) || !CheckParameters (container, parameter_types))
+ return false;
+
+ parameter_info = new InternalParameters (container, Parameters);
+
+ Parameter array_param = Parameters.ArrayParameter;
+ if ((array_param != null) &&
+ (!array_param.ParameterType.IsArray ||
+ (array_param.ParameterType.GetArrayRank () != 1))) {
+ Report.Error (225, Location, "params parameter has to be a single dimensional array");
+ return false;
+ }
+
+ return true;
+ }
+
+ public CallingConventions GetCallingConvention (bool is_class)
+ {
+ CallingConventions cc = 0;
+
+ cc = Parameters.GetCallingConvention ();
+
+ if (is_class)
+ if ((ModFlags & Modifiers.STATIC) == 0)
+ cc |= CallingConventions.HasThis;
+
+ // FIXME: How is `ExplicitThis' used in C#?
+
+ return cc;
+ }
+
+ //
+ // The method's attributes are passed in because we need to extract
+ // the "return:" attribute from there to apply on the return type
+ //
+ public void LabelParameters (EmitContext ec, MethodBase builder, Attributes method_attrs)
+ {
+ //
+ // Define each type attribute (in/out/ref) and
+ // the argument names.
+ //
+ Parameter [] p = Parameters.FixedParameters;
+ int i = 0;
+
+ MethodBuilder mb = null;
+ ConstructorBuilder cb = null;
+
+ if (builder is MethodBuilder)
+ mb = (MethodBuilder) builder;
+ else
+ cb = (ConstructorBuilder) builder;
+
+ if (p != null){
+ for (i = 0; i < p.Length; i++) {
+ ParameterBuilder pb;
+ ParameterAttributes par_attr = p [i].Attributes;
+
+ if (mb == null)
+ pb = cb.DefineParameter (
+ i + 1, par_attr, p [i].Name);
+ else
+ pb = mb.DefineParameter (
+ i + 1, par_attr, p [i].Name);
+
+ Attributes attr = p [i].OptAttributes;
+ if (attr != null){
+ Attribute.ApplyAttributes (ec, pb, pb, attr);
+
+ if (par_attr == ParameterAttributes.Out){
+ if (attr.Contains (TypeManager.in_attribute_type))
+ Report.Error (36, Location, "Can not use [In] attribute on out parameter");
+ }
+ }
+ }
+ }
+
+ if (Parameters.ArrayParameter != null){
+ ParameterBuilder pb;
+ Parameter array_param = Parameters.ArrayParameter;
+
+ if (mb == null)
+ pb = cb.DefineParameter (
+ i + 1, array_param.Attributes,
+ array_param.Name);
+ else
+ pb = mb.DefineParameter (
+ i + 1, array_param.Attributes,
+ array_param.Name);
+
+ CustomAttributeBuilder a = new CustomAttributeBuilder (
+ TypeManager.cons_param_array_attribute, new object [0]);
+
+ pb.SetCustomAttribute (a);
+ }
+
+ //
+ // And now for the return type attribute decoration
+ //
+ ParameterBuilder ret_pb;
+ Attributes ret_attrs = null;
+
+ if (mb == null || method_attrs == null)
+ return;
+
+ foreach (AttributeSection asec in method_attrs.AttributeSections) {
+
+ if (asec.Target != "return")
+ continue;
+
+ if (ret_attrs == null)
+ ret_attrs = new Attributes (asec);
+ else
+ ret_attrs.AddAttributeSection (asec);
+ }
+
+ if (ret_attrs != null) {
+ try {
+ ret_pb = mb.DefineParameter (0, ParameterAttributes.None, "");
+ Attribute.ApplyAttributes (ec, ret_pb, ret_pb, ret_attrs);
+ } catch (ArgumentOutOfRangeException) {
+ Report.Warning (
+ -24, Location,
+ ".NET SDK 1.0 does not permit to set custom attributes to the return type of a method");
+ }
+ }
+ }
+ }
+
+ public class Method : MethodCore, IIteratorContainer {
+ public MethodBuilder MethodBuilder;
+ public MethodData MethodData;
+
+ /// <summary>
+ /// Modifiers allowed in a class declaration
+ /// </summary>
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE |
+ Modifiers.STATIC |
+ Modifiers.VIRTUAL |
+ Modifiers.SEALED |
+ Modifiers.OVERRIDE |
+ Modifiers.ABSTRACT |
+ Modifiers.UNSAFE |
+ Modifiers.EXTERN;
+
+ //
+ // return_type can be "null" for VOID values.
+ //
+ public Method (Expression return_type, int mod, string name, Parameters parameters,
+ Attributes attrs, Location l)
+ : base (return_type, mod, AllowedModifiers, name, attrs, parameters, l)
+ { }
+
+ //
+ // Returns the `System.Type' for the ReturnType of this
+ // function. Provides a nice cache. (used between semantic analysis
+ // and actual code generation
+ //
+ public Type GetReturnType ()
+ {
+ return MemberType;
+ }
+
+ // Whether this is an operator method.
+ public bool IsOperator;
+
+ void DuplicateEntryPoint (MethodInfo b, Location location)
+ {
+ Report.Error (
+ 17, location,
+ "Program `" + CodeGen.FileName +
+ "' has more than one entry point defined: `" +
+ TypeManager.CSharpSignature(b) + "'");
+ }
+
+ void Report28 (MethodInfo b)
+ {
+ Report.Warning (
+ 28, Location,
+ "`" + TypeManager.CSharpSignature(b) +
+ "' has the wrong signature to be an entry point");
+ }
+
+ public bool IsEntryPoint (MethodBuilder b, InternalParameters pinfo)
+ {
+ if (b.ReturnType != TypeManager.void_type &&
+ b.ReturnType != TypeManager.int32_type)
+ return false;
+
+ if (pinfo.Count == 0)
+ return true;
+
+ if (pinfo.Count > 1)
+ return false;
+
+ Type t = pinfo.ParameterType(0);
+ if (t.IsArray &&
+ (t.GetArrayRank() == 1) &&
+ (TypeManager.GetElementType(t) == TypeManager.string_type) &&
+ (pinfo.ParameterModifier(0) == Parameter.Modifier.NONE))
+ return true;
+ else
+ return false;
+ }
+
+ //
+ // Checks our base implementation if any
+ //
+ protected override bool CheckBase (TypeContainer container)
+ {
+ base.CheckBase (container);
+
+ // Check whether arguments were correct.
+ if (!DoDefineParameters (container))
+ return false;
+
+ MethodSignature ms = new MethodSignature (Name, null, ParameterTypes);
+ if (IsOperator) {
+ flags |= MethodAttributes.SpecialName | MethodAttributes.HideBySig;
+ } else {
+ MemberList mi_this;
+
+ mi_this = TypeContainer.FindMembers (
+ container.TypeBuilder, MemberTypes.Method,
+ BindingFlags.NonPublic | BindingFlags.Public |
+ BindingFlags.Static | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly,
+ MethodSignature.method_signature_filter, ms);
+
+ if (mi_this.Count > 0) {
+ Report.Error (111, Location, "Class `" + container.Name + "' " +
+ "already defines a member called `" + Name + "' " +
+ "with the same parameter types");
+ return false;
+ }
+ }
+
+ //
+ // Verify if the parent has a type with the same name, and then
+ // check whether we have to create a new slot for it or not.
+ //
+ Type ptype = container.TypeBuilder.BaseType;
+
+ // ptype is only null for System.Object while compiling corlib.
+ if (ptype != null){
+ MemberList mi, mi_static, mi_instance;
+
+ mi_instance = TypeContainer.FindMembers (
+ ptype, MemberTypes.Method,
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
+ MethodSignature.inheritable_method_signature_filter,
+ ms);
+
+ if (mi_instance.Count > 0){
+ mi = mi_instance;
+ } else {
+ mi_static = TypeContainer.FindMembers (
+ ptype, MemberTypes.Method,
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static,
+ MethodSignature.inheritable_method_signature_filter, ms);
+
+ if (mi_static.Count > 0)
+ mi = mi_static;
+ else
+ mi = null;
+ }
+
+ if (mi != null && mi.Count > 0){
+ parent_method = (MethodInfo) mi [0];
+ string name = parent_method.DeclaringType.Name + "." +
+ parent_method.Name;
+
+ if (!CheckMethodAgainstBase (container, flags, parent_method, name))
+ return false;
+
+ if ((ModFlags & Modifiers.NEW) == 0) {
+ Type parent_ret = TypeManager.TypeToCoreType (
+ parent_method.ReturnType);
+
+ if (parent_ret != MemberType) {
+ Report.Error (
+ 508, Location, container.MakeName (Name) + ": cannot " +
+ "change return type when overriding " +
+ "inherited member " + name);
+ return false;
+ }
+ }
+ } else {
+ if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (container);
+
+ if ((ModFlags & Modifiers.OVERRIDE) != 0){
+ Report.Error (115, Location,
+ container.MakeName (Name) +
+ " no suitable methods found to override");
+ }
+ }
+ } else if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (container);
+
+ return true;
+ }
+
+ //
+ // Creates the type
+ //
+ public override bool Define (TypeContainer container)
+ {
+ if (!DoDefine (container))
+ return false;
+
+ if (!CheckBase (container))
+ return false;
+
+ CallingConventions cc = GetCallingConvention (container is Class);
+
+ MethodData = new MethodData (this, null, MemberType, ParameterTypes,
+ ParameterInfo, cc, OptAttributes,
+ ModFlags, flags, true);
+
+ if (!MethodData.Define (container))
+ return false;
+
+ //
+ // Setup iterator if we are one
+ //
+ if ((ModFlags & Modifiers.METHOD_YIELDS) != 0){
+ IteratorHandler ih = new IteratorHandler (
+ Name, container, MemberType,
+ ParameterTypes, ParameterInfo,
+ ModFlags, Location);
+
+ Block new_block = ih.Setup (block);
+ if (new_block == null)
+ return false;
+ block = new_block;
+ }
+
+ MethodBuilder = MethodData.MethodBuilder;
+
+ //
+ // This is used to track the Entry Point,
+ //
+ if (Name == "Main" &&
+ ((ModFlags & Modifiers.STATIC) != 0) &&
+ (RootContext.MainClass == null ||
+ RootContext.MainClass == container.TypeBuilder.FullName)){
+ if (IsEntryPoint (MethodBuilder, ParameterInfo)) {
+ if (RootContext.EntryPoint == null) {
+ RootContext.EntryPoint = MethodBuilder;
+ RootContext.EntryPointLocation = Location;
+ } else {
+ DuplicateEntryPoint (RootContext.EntryPoint, RootContext.EntryPointLocation);
+ DuplicateEntryPoint (MethodBuilder, Location);
+ }
+ } else
+ Report28(MethodBuilder);
+ }
+
+ return true;
+ }
+
+ //
+ // Emits the code
+ //
+ public void Emit (TypeContainer container)
+ {
+ MethodData.Emit (container, Block, this);
+ Block = null;
+ }
+
+ void IIteratorContainer.SetYields ()
+ {
+ ModFlags |= Modifiers.METHOD_YIELDS;
+ }
+ }
+
+ public abstract class ConstructorInitializer {
+ ArrayList argument_list;
+ ConstructorInfo parent_constructor;
+ Parameters parameters;
+ Location loc;
+
+ public ConstructorInitializer (ArrayList argument_list, Parameters parameters,
+ Location loc)
+ {
+ this.argument_list = argument_list;
+ this.parameters = parameters;
+ this.loc = loc;
+ }
+
+ public ArrayList Arguments {
+ get {
+ return argument_list;
+ }
+ }
+
+ public bool Resolve (EmitContext ec)
+ {
+ Expression parent_constructor_group;
+ Type t;
+
+ ec.CurrentBlock = new Block (null, Block.Flags.Implicit, parameters);
+
+ if (argument_list != null){
+ foreach (Argument a in argument_list){
+ if (!a.Resolve (ec, loc))
+ return false;
+ }
+ }
+ ec.CurrentBlock = null;
+
+ if (this is ConstructorBaseInitializer) {
+ if (ec.ContainerType.BaseType == null)
+ return true;
+
+ t = ec.ContainerType.BaseType;
+ if (ec.ContainerType.IsValueType) {
+ Report.Error (522, loc,
+ "structs cannot call base class constructors");
+ return false;
+ }
+ } else
+ t = ec.ContainerType;
+
+ parent_constructor_group = Expression.MemberLookup (
+ ec, t, null, t, ".ctor",
+ MemberTypes.Constructor,
+ BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
+ loc);
+
+ if (parent_constructor_group == null){
+ Report.Error (1501, loc,
+ "Can not find a constructor for this argument list");
+ return false;
+ }
+
+ parent_constructor = (ConstructorInfo) Invocation.OverloadResolve (ec,
+ (MethodGroupExpr) parent_constructor_group, argument_list, loc);
+
+ if (parent_constructor == null){
+ Report.Error (1501, loc,
+ "Can not find a constructor for this argument list");
+ return false;
+ }
+
+ return true;
+ }
+
+ public void Emit (EmitContext ec)
+ {
+ if (parent_constructor != null){
+ ec.Mark (loc, false);
+ if (ec.IsStatic)
+ Invocation.EmitCall (ec, true, true, null, parent_constructor, argument_list, loc);
+ else
+ Invocation.EmitCall (ec, true, false, ec.GetThis (loc), parent_constructor, argument_list, loc);
+ }
+ }
+ }
+
+ public class ConstructorBaseInitializer : ConstructorInitializer {
+ public ConstructorBaseInitializer (ArrayList argument_list, Parameters pars, Location l) :
+ base (argument_list, pars, l)
+ {
+ }
+ }
+
+ public class ConstructorThisInitializer : ConstructorInitializer {
+ public ConstructorThisInitializer (ArrayList argument_list, Parameters pars, Location l) :
+ base (argument_list, pars, l)
+ {
+ }
+ }
+
+ public class Constructor : MethodCore {
+ public ConstructorBuilder ConstructorBuilder;
+ public ConstructorInitializer Initializer;
+ new public Attributes OptAttributes;
+
+ // <summary>
+ // Modifiers allowed for a constructor.
+ // </summary>
+ public const int AllowedModifiers =
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.STATIC |
+ Modifiers.UNSAFE |
+ Modifiers.EXTERN |
+ Modifiers.PRIVATE;
+
+ //
+ // The spec claims that static is not permitted, but
+ // my very own code has static constructors.
+ //
+ public Constructor (string name, Parameters args, ConstructorInitializer init, Location l)
+ : base (null, 0, AllowedModifiers, name, null, args, l)
+ {
+ Initializer = init;
+ }
+
+ //
+ // Returns true if this is a default constructor
+ //
+ public bool IsDefault ()
+ {
+ if ((ModFlags & Modifiers.STATIC) != 0)
+ return (Parameters.FixedParameters == null ? true : Parameters.Empty) &&
+ (Parameters.ArrayParameter == null ? true : Parameters.Empty);
+
+ else
+ return (Parameters.FixedParameters == null ? true : Parameters.Empty) &&
+ (Parameters.ArrayParameter == null ? true : Parameters.Empty) &&
+ (Initializer is ConstructorBaseInitializer) &&
+ (Initializer.Arguments == null);
+ }
+
+ //
+ // Creates the ConstructorBuilder
+ //
+ public override bool Define (TypeContainer container)
+ {
+ MethodAttributes ca = (MethodAttributes.RTSpecialName |
+ MethodAttributes.SpecialName);
+
+ // Check if arguments were correct.
+ if (!DoDefineParameters (container))
+ return false;
+
+ if ((ModFlags & Modifiers.STATIC) != 0){
+ ca |= MethodAttributes.Static | MethodAttributes.Private;
+ } else {
+ if (container is Struct && ParameterTypes.Length == 0){
+ Report.Error (
+ 568, Location,
+ "Structs can not contain explicit parameterless " +
+ "constructors");
+ return false;
+ }
+ ca |= MethodAttributes.HideBySig;
+
+ if ((ModFlags & Modifiers.PUBLIC) != 0)
+ ca |= MethodAttributes.Public;
+ else if ((ModFlags & Modifiers.PROTECTED) != 0){
+ if ((ModFlags & Modifiers.INTERNAL) != 0)
+ ca |= MethodAttributes.FamORAssem;
+ else
+ ca |= MethodAttributes.Family;
+ } else if ((ModFlags & Modifiers.INTERNAL) != 0)
+ ca |= MethodAttributes.Assembly;
+ else if (IsDefault ())
+ ca |= MethodAttributes.Public;
+ else
+ ca |= MethodAttributes.Private;
+ }
+
+ ConstructorBuilder = container.TypeBuilder.DefineConstructor (
+ ca, GetCallingConvention (container is Class), ParameterTypes);
+
+ if ((ModFlags & Modifiers.UNSAFE) != 0)
+ ConstructorBuilder.InitLocals = false;
+
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ if (!TypeManager.RegisterMethod (ConstructorBuilder, ParameterInfo, ParameterTypes)) {
+ Report.Error (
+ 111, Location,
+ "Class `" +container.Name+ "' already contains a definition with the " +
+ "same return value and parameter types for constructor `" + Name
+ + "'");
+ return false;
+ }
+
+ return true;
+ }
+
+ //
+ // Emits the code
+ //
+ public void Emit (TypeContainer container)
+ {
+ ILGenerator ig = ConstructorBuilder.GetILGenerator ();
+ EmitContext ec = new EmitContext (container, Location, ig, null, ModFlags, true);
+
+ //
+ // extern methods have no bodies
+ //
+ if ((ModFlags & Modifiers.EXTERN) != 0) {
+ if ((block != null) && ((ModFlags & Modifiers.EXTERN) != 0)) {
+ Report.Error (
+ 179, Location, "External constructor `" +
+ TypeManager.CSharpSignature (ConstructorBuilder) +
+ "' can not have a body");
+ return;
+ }
+ } else if (block == null) {
+ Report.Error (
+ 501, Location, "Constructor `" +
+ TypeManager.CSharpSignature (ConstructorBuilder) +
+ "' must declare a body since it is not marked extern");
+ return;
+ }
+
+ if ((ModFlags & Modifiers.STATIC) == 0){
+ if (container is Class && Initializer == null)
+ Initializer = new ConstructorBaseInitializer (
+ null, Parameters.EmptyReadOnlyParameters, Location);
+
+
+ //
+ // Spec mandates that Initializers will not have
+ // `this' access
+ //
+ ec.IsStatic = true;
+ if (Initializer != null && !Initializer.Resolve (ec))
+ return;
+ ec.IsStatic = false;
+ }
+
+ LabelParameters (ec, ConstructorBuilder, OptAttributes);
+
+ SymbolWriter sw = CodeGen.SymbolWriter;
+ bool generate_debugging = false;
+
+ if ((sw != null) && (block != null) &&
+ !Location.IsNull (Location) &&
+ !Location.IsNull (block.EndLocation)) {
+
+ sw.OpenMethod (container, ConstructorBuilder, Location, block.EndLocation);
+
+ generate_debugging = true;
+ }
+
+ //
+ // Classes can have base initializers and instance field initializers.
+ //
+ if (container is Class){
+ if ((ModFlags & Modifiers.STATIC) == 0){
+
+ //
+ // If we use a "this (...)" constructor initializer, then
+ // do not emit field initializers, they are initialized in the other constructor
+ //
+ if (!(Initializer != null && Initializer is ConstructorThisInitializer))
+ container.EmitFieldInitializers (ec);
+ }
+ }
+ if (Initializer != null)
+ Initializer.Emit (ec);
+
+ if ((ModFlags & Modifiers.STATIC) != 0)
+ container.EmitFieldInitializers (ec);
+
+ Attribute.ApplyAttributes (ec, ConstructorBuilder, this, OptAttributes);
+
+ // If this is a non-static `struct' constructor and doesn't have any
+ // initializer, it must initialize all of the struct's fields.
+ if ((container is Struct) && ((ModFlags & Modifiers.STATIC) == 0) && (Initializer == null))
+ Block.AddThisVariable (container, Location);
+
+ ec.EmitTopBlock (block, ParameterInfo, Location);
+
+ if (generate_debugging)
+ sw.CloseMethod ();
+
+ block = null;
+ }
+ }
+
+ //
+ // Encapsulates most of the Method's state
+ //
+ public class MethodData {
+ //
+ // The return type of this method
+ //
+ public readonly Type ReturnType;
+ public readonly Type[] ParameterTypes;
+ public readonly InternalParameters ParameterInfo;
+ public readonly CallingConventions CallingConventions;
+ public readonly Attributes OptAttributes;
+ public readonly Location Location;
+
+ //
+ // Are we implementing an interface ?
+ //
+ public bool IsImplementing = false;
+
+ //
+ // Protected data.
+ //
+ protected MemberBase member;
+ protected int modifiers;
+ protected MethodAttributes flags;
+ protected bool is_method;
+ protected string accessor_name;
+
+ //
+ // It can either hold a string with the condition, or an arraylist of conditions.
+ object conditionals;
+
+ MethodBuilder builder = null;
+ public MethodBuilder MethodBuilder {
+ get {
+ return builder;
+ }
+ }
+
+ public MethodData (MemberBase member, string name, Type return_type,
+ Type [] parameter_types, InternalParameters parameters,
+ CallingConventions cc, Attributes opt_attrs,
+ int modifiers, MethodAttributes flags, bool is_method)
+ {
+ this.member = member;
+ this.accessor_name = name;
+ this.ReturnType = return_type;
+ this.ParameterTypes = parameter_types;
+ this.ParameterInfo = parameters;
+ this.CallingConventions = cc;
+ this.OptAttributes = opt_attrs;
+ this.modifiers = modifiers;
+ this.flags = flags;
+ this.is_method = is_method;
+ this.Location = member.Location;
+ this.conditionals = null;
+ }
+
+ //
+ // Attributes.
+ //
+ Attribute dllimport_attribute = null;
+ string obsolete = null;
+ bool obsolete_error = false;
+
+ public virtual bool ApplyAttributes (Attributes opt_attrs, bool is_method)
+ {
+ if ((opt_attrs == null) || (opt_attrs.AttributeSections == null))
+ return true;
+
+ foreach (AttributeSection asec in opt_attrs.AttributeSections) {
+ if (asec.Attributes == null)
+ continue;
+
+ foreach (Attribute a in asec.Attributes) {
+ if (a.Name == "Conditional") {
+ if (!ApplyConditionalAttribute (a))
+ return false;
+ } else if (a.Name == "Obsolete") {
+ if (!ApplyObsoleteAttribute (a))
+ return false;
+ } else if (a.Name.IndexOf ("DllImport") != -1) {
+ if (!is_method) {
+ a.Type = TypeManager.dllimport_type;
+ Attribute.Error_AttributeNotValidForElement (a, Location);
+ return false;
+ }
+ if (!ApplyDllImportAttribute (a))
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ //
+ // Applies the `DllImport' attribute to the method.
+ //
+ protected virtual bool ApplyDllImportAttribute (Attribute a)
+ {
+ const int extern_static = Modifiers.EXTERN | Modifiers.STATIC;
+ if ((modifiers & extern_static) != extern_static) {
+ Report.Error (601, Location,
+ "The DllImport attribute must be specified on a method " +
+ "marked `static' and `extern'.");
+ return false;
+ }
+
+ flags |= MethodAttributes.PinvokeImpl;
+ dllimport_attribute = a;
+ return true;
+ }
+
+ //
+ // Applies the `Obsolete' attribute to the method.
+ //
+ protected virtual bool ApplyObsoleteAttribute (Attribute a)
+ {
+ if (obsolete != null) {
+ Report.Error (579, Location, "Duplicate `Obsolete' attribute");
+ return false;
+ }
+
+ obsolete = a.Obsolete_GetObsoleteMessage (out obsolete_error);
+ return obsolete != null;
+ }
+
+ //
+ // Applies the `Conditional' attribute to the method.
+ //
+ protected virtual bool ApplyConditionalAttribute (Attribute a)
+ {
+ // The Conditional attribute is only valid on methods.
+ if (!is_method) {
+ Attribute.Error_AttributeNotValidForElement (a, Location);
+ return false;
+ }
+
+ string condition = a.Conditional_GetConditionName ();
+
+ if (condition == null)
+ return false;
+
+ if (ReturnType != TypeManager.void_type) {
+ Report.Error (578, Location,
+ "Conditional not valid on `" + member.Name + "' " +
+ "because its return type is not void");
+ return false;
+ }
+
+ if ((modifiers & Modifiers.OVERRIDE) != 0) {
+ Report.Error (243, Location,
+ "Conditional not valid on `" + member.Name + "' " +
+ "because it is an override method");
+ return false;
+ }
+
+ if (member.IsExplicitImpl) {
+ Report.Error (577, Location,
+ "Conditional not valid on `" + member.Name + "' " +
+ "because it is an explicit interface implementation");
+ return false;
+ }
+
+ if (IsImplementing) {
+ Report.Error (623, Location,
+ "Conditional not valid on `" + member.Name + "' " +
+ "because it is an interface method");
+ return false;
+ }
+
+ //
+ // The likelyhood that the conditional will be more than 1 is very slim
+ //
+ if (conditionals == null)
+ conditionals = condition;
+ else if (conditionals is string){
+ string s = (string) conditionals;
+ conditionals = new ArrayList ();
+ ((ArrayList)conditionals).Add (s);
+ } else
+ ((ArrayList)conditionals).Add (condition);
+
+ return true;
+ }
+
+ //
+ // Checks whether this method should be ignored due to its Conditional attributes.
+ //
+ bool ShouldIgnore (Location loc)
+ {
+ // When we're overriding a virtual method, we implicitly inherit the
+ // Conditional attributes from our parent.
+ if (member.ParentMethod != null) {
+ TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (
+ member.ParentMethod, loc);
+
+ if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
+ return true;
+ }
+
+ if (conditionals != null){
+ if (conditionals is string){
+ if (RootContext.AllDefines [conditionals] == null)
+ return true;
+ } else {
+ foreach (string condition in (ArrayList) conditionals)
+ if (RootContext.AllDefines [condition] == null)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //
+ // Returns the TypeManager.MethodFlags for this method.
+ // This emits an error 619 / warning 618 if the method is obsolete.
+ // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
+ //
+ public virtual TypeManager.MethodFlags GetMethodFlags (Location loc)
+ {
+ TypeManager.MethodFlags flags = 0;
+
+ if (obsolete != null) {
+ if (obsolete_error) {
+ Report.Error (619, loc, "Method `" + member.Name +
+ "' is obsolete: `" + obsolete + "'");
+ return TypeManager.MethodFlags.IsObsoleteError;
+ } else
+ Report.Warning (618, loc, "Method `" + member.Name +
+ "' is obsolete: `" + obsolete + "'");
+
+ flags |= TypeManager.MethodFlags.IsObsolete;
+ }
+
+ if (ShouldIgnore (loc))
+ flags |= TypeManager.MethodFlags.ShouldIgnore;
+
+ return flags;
+ }
+
+ public virtual bool Define (TypeContainer container)
+ {
+ MethodInfo implementing = null;
+ string method_name, name, prefix;
+
+ if (OptAttributes != null)
+ if (!ApplyAttributes (OptAttributes, is_method))
+ return false;
+
+ if (member.IsExplicitImpl)
+ prefix = member.InterfaceType.FullName + ".";
+ else
+ prefix = "";
+
+ if (accessor_name != null)
+ name = accessor_name + "_" + member.ShortName;
+ else
+ name = member.ShortName;
+ method_name = prefix + name;
+
+ if (container.Pending != null){
+ if (member is Indexer)
+ implementing = container.Pending.IsInterfaceIndexer (
+ member.InterfaceType, ReturnType, ParameterTypes);
+ else
+ implementing = container.Pending.IsInterfaceMethod (
+ member.InterfaceType, name, ReturnType, ParameterTypes);
+
+ if (member.InterfaceType != null && implementing == null){
+ TypeContainer.Error_ExplicitInterfaceNotMemberInterface (
+ Location, name);
+ return false;
+ }
+ }
+
+ //
+ // For implicit implementations, make sure we are public, for
+ // explicit implementations, make sure we are private.
+ //
+ if (implementing != null){
+ //
+ // Setting null inside this block will trigger a more
+ // verbose error reporting for missing interface implementations
+ //
+ // The "candidate" function has been flagged already
+ // but it wont get cleared
+ //
+ if (member.IsExplicitImpl){
+ if ((modifiers & (Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0){
+ Modifiers.Error_InvalidModifier (Location, "public, virtual or abstract");
+ implementing = null;
+ }
+ } else {
+ //
+ // If this is an interface method implementation,
+ // check for public accessibility
+ //
+ if ((flags & MethodAttributes.MemberAccessMask) != MethodAttributes.Public){
+ if (TypeManager.IsInterfaceType (implementing.DeclaringType))
+ implementing = null;
+ }
+ }
+
+ //
+ // Static is not allowed
+ //
+ if ((modifiers & Modifiers.STATIC) != 0){
+ implementing = null;
+ Modifiers.Error_InvalidModifier (Location, "static");
+ }
+ }
+
+ //
+ // If implementing is still valid, set flags
+ //
+ if (implementing != null){
+ //
+ // When implementing interface methods, set NewSlot
+ // unless, we are overwriting a method.
+ //
+ if (implementing.DeclaringType.IsInterface){
+ if ((modifiers & Modifiers.OVERRIDE) == 0)
+ flags |= MethodAttributes.NewSlot;
+ }
+ flags |=
+ MethodAttributes.Virtual |
+ MethodAttributes.HideBySig;
+
+ // Set Final unless we're virtual, abstract or already overriding a method.
+ if ((modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) == 0)
+ flags |= MethodAttributes.Final;
+
+ // Get the method name from the explicit interface.
+ if (member.InterfaceType != null) {
+ name = implementing.Name;
+ method_name = prefix + name;
+ }
+
+ IsImplementing = true;
+ }
+
+ //
+ // Create the MethodBuilder for the method
+ //
+ if ((flags & MethodAttributes.PinvokeImpl) != 0) {
+ if ((modifiers & Modifiers.STATIC) == 0) {
+ Report.Error (601, Location,
+ "The DllImport attribute must be specified on " +
+ "a method marked 'static' and 'extern'.");
+ return false;
+ }
+
+ EmitContext ec = new EmitContext (
+ container, Location, null, ReturnType, modifiers);
+
+ builder = dllimport_attribute.DefinePInvokeMethod (
+ ec, container.TypeBuilder, method_name, flags,
+ ReturnType, ParameterTypes);
+ } else
+ builder = container.TypeBuilder.DefineMethod (
+ method_name, flags, CallingConventions,
+ ReturnType, ParameterTypes);
+
+ if (builder == null)
+ return false;
+
+ if ((modifiers & Modifiers.UNSAFE) != 0)
+ builder.InitLocals = false;
+
+ if (IsImplementing){
+ //
+ // clear the pending implemntation flag
+ //
+ if (member is Indexer) {
+ container.Pending.ImplementIndexer (
+ member.InterfaceType, builder, ReturnType,
+ ParameterTypes, true);
+ } else
+ container.Pending.ImplementMethod (
+ member.InterfaceType, name, ReturnType,
+ ParameterTypes, member.IsExplicitImpl);
+
+ if (member.IsExplicitImpl)
+ container.TypeBuilder.DefineMethodOverride (
+ builder, implementing);
+
+ }
+
+ if (!TypeManager.RegisterMethod (builder, ParameterInfo, ParameterTypes)) {
+ Report.Error (111, Location,
+ "Class `" + container.Name +
+ "' already contains a definition with the " +
+ "same return value and parameter types as the " +
+ "'get' method of property `" + member.Name + "'");
+ return false;
+ }
+
+ TypeManager.AddMethod (builder, this);
+
+ return true;
+ }
+
+ //
+ // Emits the code
+ //
+ public virtual void Emit (TypeContainer container, Block block, object kind)
+ {
+ ILGenerator ig;
+ EmitContext ec;
+
+ if ((flags & MethodAttributes.PinvokeImpl) == 0)
+ ig = builder.GetILGenerator ();
+ else
+ ig = null;
+
+ ec = new EmitContext (container, Location, ig, ReturnType, modifiers);
+
+ if (OptAttributes != null)
+ Attribute.ApplyAttributes (ec, builder, kind, OptAttributes);
+
+ if (member is MethodCore)
+ ((MethodCore) member).LabelParameters (ec, MethodBuilder, OptAttributes);
+
+ //
+ // abstract or extern methods have no bodies
+ //
+ if ((modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0){
+ if (block == null) {
+ SymbolWriter sw = CodeGen.SymbolWriter;
+
+ if ((sw != null) && ((modifiers & Modifiers.EXTERN) != 0)) {
+ sw.OpenMethod (container, MethodBuilder, Location, Location);
+ sw.CloseMethod ();
+ }
+
+ return;
+ }
+
+ //
+ // abstract or extern methods have no bodies.
+ //
+ if ((modifiers & Modifiers.ABSTRACT) != 0)
+ Report.Error (
+ 500, Location, "Abstract method `" +
+ TypeManager.CSharpSignature (builder) +
+ "' can not have a body");
+
+ if ((modifiers & Modifiers.EXTERN) != 0)
+ Report.Error (
+ 179, Location, "External method `" +
+ TypeManager.CSharpSignature (builder) +
+ "' can not have a body");
+
+ return;
+ }
+
+ //
+ // Methods must have a body unless they're extern or abstract
+ //
+ if (block == null) {
+ Report.Error (
+ 501, Location, "Method `" +
+ TypeManager.CSharpSignature (builder) +
+ "' must declare a body since it is not marked " +
+ "abstract or extern");
+ return;
+ }
+
+ //
+ // Handle destructors specially
+ //
+ // FIXME: This code generates buggy code
+ //
+ if (member.Name == "Finalize" && ReturnType == TypeManager.void_type)
+ EmitDestructor (ec, block);
+ else {
+ SymbolWriter sw = CodeGen.SymbolWriter;
+
+ if ((sw != null) && !Location.IsNull (Location) &&
+ !Location.IsNull (block.EndLocation)) {
+ sw.OpenMethod (container, MethodBuilder, Location, block.EndLocation);
+
+ ec.EmitTopBlock (block, ParameterInfo, Location);
+
+ sw.CloseMethod ();
+ } else
+ ec.EmitTopBlock (block, ParameterInfo, Location);
+ }
+ }
+
+ void EmitDestructor (EmitContext ec, Block block)
+ {
+ ILGenerator ig = ec.ig;
+
+ Label finish = ig.DefineLabel ();
+ bool old_in_try = ec.InTry;
+
+ ig.BeginExceptionBlock ();
+ ec.InTry = true;
+ ec.ReturnLabel = finish;
+ ec.HasReturnLabel = true;
+ ec.EmitTopBlock (block, null, Location);
+ ec.InTry = old_in_try;
+
+ // ig.MarkLabel (finish);
+ bool old_in_finally = ec.InFinally;
+ ec.InFinally = true;
+ ig.BeginFinallyBlock ();
+
+ if (ec.ContainerType.BaseType != null) {
+ Expression member_lookup = Expression.MemberLookup (
+ ec, ec.ContainerType.BaseType, null, ec.ContainerType.BaseType,
+ "Finalize", MemberTypes.Method, Expression.AllBindingFlags, Location);
+
+ if (member_lookup != null){
+ MethodGroupExpr parent_destructor = ((MethodGroupExpr) member_lookup);
+
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Call, (MethodInfo) parent_destructor.Methods [0]);
+ }
+ }
+ ec.InFinally = old_in_finally;
+
+ ig.EndExceptionBlock ();
+ //ig.MarkLabel (ec.ReturnLabel);
+ ig.Emit (OpCodes.Ret);
+ }
+ }
+
+ abstract public class MemberBase : MemberCore {
+ public Expression Type;
+ public readonly Attributes OptAttributes;
+
+ protected MethodAttributes flags;
+
+ //
+ // The "short" name of this property / indexer / event. This is the
+ // name without the explicit interface.
+ //
+ public string ShortName;
+
+ //
+ // The type of this property / indexer / event
+ //
+ public Type MemberType;
+
+ //
+ // If true, this is an explicit interface implementation
+ //
+ public bool IsExplicitImpl = false;
+
+ //
+ // The name of the interface we are explicitly implementing
+ //
+ public string ExplicitInterfaceName = null;
+
+ //
+ // If true, the interface type we are explicitly implementing
+ //
+ public Type InterfaceType = null;
+
+ //
+ // The method we're overriding if this is an override method.
+ //
+ protected MethodInfo parent_method = null;
+ public MethodInfo ParentMethod {
+ get {
+ return parent_method;
+ }
+ }
+
+ //
+ // The constructor is only exposed to our children
+ //
+ protected MemberBase (Expression type, int mod, int allowed_mod, string name,
+ Attributes attrs, Location loc)
+ : base (name, loc)
+ {
+ Type = type;
+ ModFlags = Modifiers.Check (allowed_mod, mod, Modifiers.PRIVATE, loc);
+ OptAttributes = attrs;
+ }
+
+ protected virtual bool CheckBase (TypeContainer container)
+ {
+ if ((container is Struct) || (RootContext.WarningLevel > 3)){
+ if ((ModFlags & Modifiers.PROTECTED) != 0 && (container.ModFlags & Modifiers.SEALED) != 0){
+ if (container is Struct){
+ Report.Error (666, Location, "Protected member in struct declaration");
+ return false;
+ } else
+ Report.Warning (628, Location, "Member " + container.MakeName (Name) + " protected in sealed class");
+ }
+ }
+ return true;
+ }
+
+ protected virtual bool CheckParameters (TypeContainer container, Type [] parameters)
+ {
+ bool error = false;
+
+ foreach (Type partype in parameters){
+ if (partype.IsPointer){
+ if (!UnsafeOK (container))
+ error = true;
+ if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (partype), Location))
+ error = true;
+ }
+
+ if (container.AsAccessible (partype, ModFlags))
+ continue;
+
+ if (this is Indexer)
+ Report.Error (55, Location,
+ "Inconsistent accessibility: parameter type `" +
+ TypeManager.CSharpName (partype) + "' is less " +
+ "accessible than indexer `" + Name + "'");
+ else if ((this is Method) && ((Method) this).IsOperator)
+ Report.Error (57, Location,
+ "Inconsistent accessibility: parameter type `" +
+ TypeManager.CSharpName (partype) + "' is less " +
+ "accessible than operator `" + Name + "'");
+ else
+ Report.Error (51, Location,
+ "Inconsistent accessibility: parameter type `" +
+ TypeManager.CSharpName (partype) + "' is less " +
+ "accessible than method `" + Name + "'");
+ error = true;
+ }
+
+ return !error;
+ }
+
+ protected virtual bool DoDefine (TypeContainer container)
+ {
+ if (Name == null)
+ Name = "this";
+
+ if (!container.MethodModifiersValid (ModFlags, Name, Location))
+ return false;
+
+ flags = Modifiers.MethodAttr (ModFlags);
+
+ // Lookup Type, verify validity
+ MemberType = container.ResolveType (Type, false, Location);
+ if (MemberType == null)
+ return false;
+
+ if ((container.ModFlags & Modifiers.SEALED) != 0){
+ if ((ModFlags & (Modifiers.VIRTUAL|Modifiers.ABSTRACT)) != 0){
+ Report.Error (549, Location, "Virtual method can not be contained in sealed class");
+ return false;
+ }
+ }
+
+ // verify accessibility
+ if (!container.AsAccessible (MemberType, ModFlags)) {
+ if (this is Property)
+ Report.Error (53, Location,
+ "Inconsistent accessibility: property type `" +
+ TypeManager.CSharpName (MemberType) + "' is less " +
+ "accessible than property `" + Name + "'");
+ else if (this is Indexer)
+ Report.Error (54, Location,
+ "Inconsistent accessibility: indexer return type `" +
+ TypeManager.CSharpName (MemberType) + "' is less " +
+ "accessible than indexer `" + Name + "'");
+ else if (this is Method) {
+ if (((Method) this).IsOperator)
+ Report.Error (56, Location,
+ "Inconsistent accessibility: return type `" +
+ TypeManager.CSharpName (MemberType) + "' is less " +
+ "accessible than operator `" + Name + "'");
+ else
+ Report.Error (50, Location,
+ "Inconsistent accessibility: return type `" +
+ TypeManager.CSharpName (MemberType) + "' is less " +
+ "accessible than method `" + Name + "'");
+ } else
+ Report.Error (52, Location,
+ "Inconsistent accessibility: field type `" +
+ TypeManager.CSharpName (MemberType) + "' is less " +
+ "accessible than field `" + Name + "'");
+ return false;
+ }
+
+ if (MemberType.IsPointer && !UnsafeOK (container))
+ return false;
+
+ //
+ // Check for explicit interface implementation
+ //
+ if ((ExplicitInterfaceName == null) && (Name.IndexOf (".") != -1)){
+ int pos = Name.LastIndexOf (".");
+
+ ExplicitInterfaceName = Name.Substring (0, pos);
+ ShortName = Name.Substring (pos + 1);
+ } else
+ ShortName = Name;
+
+ if (ExplicitInterfaceName != null) {
+ InterfaceType = RootContext.LookupType (
+ container, ExplicitInterfaceName, false, Location);
+ if (InterfaceType == null)
+ return false;
+
+ // Compute the full name that we need to export.
+ Name = InterfaceType.FullName + "." + ShortName;
+
+ if (!container.VerifyImplements (InterfaceType, ShortName, Name, Location))
+ return false;
+
+ IsExplicitImpl = true;
+ } else
+ IsExplicitImpl = false;
+
+ return true;
+ }
+ }
+
+ //
+ // Fields and Events both generate FieldBuilders, we use this to share
+ // their common bits. This is also used to flag usage of the field
+ //
+ abstract public class FieldBase : MemberBase {
+ public FieldBuilder FieldBuilder;
+ public Status status;
+
+ [Flags]
+ public enum Status : byte { ASSIGNED = 1, USED = 2 }
+
+ //
+ // The constructor is only exposed to our children
+ //
+ protected FieldBase (Expression type, int mod, int allowed_mod, string name,
+ object init, Attributes attrs, Location loc)
+ : base (type, mod, allowed_mod, name, attrs, loc)
+ {
+ this.init = init;
+ }
+
+ //
+ // Whether this field has an initializer.
+ //
+ public bool HasInitializer {
+ get {
+ return init != null;
+ }
+ }
+
+ protected readonly Object init;
+ // Private.
+ Expression init_expr;
+ bool init_expr_initialized = false;
+
+ //
+ // Resolves and returns the field initializer.
+ //
+ public Expression GetInitializerExpression (EmitContext ec)
+ {
+ if (init_expr_initialized)
+ return init_expr;
+
+ Expression e;
+ if (init is Expression)
+ e = (Expression) init;
+ else
+ e = new ArrayCreation (Type, "", (ArrayList)init, Location);
+
+ ec.IsFieldInitializer = true;
+ e = e.DoResolve (ec);
+ ec.IsFieldInitializer = false;
+
+ init_expr = e;
+ init_expr_initialized = true;
+
+ return init_expr;
+ }
+ }
+
+ //
+ // The Field class is used to represents class/struct fields during parsing.
+ //
+ public class Field : FieldBase {
+ // <summary>
+ // Modifiers allowed in a class declaration
+ // </summary>
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE |
+ Modifiers.STATIC |
+ Modifiers.VOLATILE |
+ Modifiers.UNSAFE |
+ Modifiers.READONLY;
+
+ public Field (Expression type, int mod, string name, Object expr_or_array_init,
+ Attributes attrs, Location loc)
+ : base (type, mod, AllowedModifiers, name, expr_or_array_init, attrs, loc)
+ {
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ Type t = container.ResolveType (Type, false, Location);
+
+ if (t == null)
+ return false;
+
+ CheckBase (container);
+
+ if (!container.AsAccessible (t, ModFlags)) {
+ Report.Error (52, Location,
+ "Inconsistent accessibility: field type `" +
+ TypeManager.CSharpName (t) + "' is less " +
+ "accessible than field `" + Name + "'");
+ return false;
+ }
+
+ if (t.IsPointer && !UnsafeOK (container))
+ return false;
+
+ if (RootContext.WarningLevel > 1){
+ Type ptype = container.TypeBuilder.BaseType;
+
+ // ptype is only null for System.Object while compiling corlib.
+ if (ptype != null){
+ TypeContainer.FindMembers (
+ ptype, MemberTypes.Method,
+ BindingFlags.Public |
+ BindingFlags.Static | BindingFlags.Instance,
+ System.Type.FilterName, Name);
+ }
+ }
+
+ if ((ModFlags & Modifiers.VOLATILE) != 0){
+ if (!t.IsClass){
+ Type vt = t;
+
+ if (TypeManager.IsEnumType (vt))
+ vt = TypeManager.EnumToUnderlying (t);
+
+ if (!((vt == TypeManager.bool_type) ||
+ (vt == TypeManager.sbyte_type) ||
+ (vt == TypeManager.byte_type) ||
+ (vt == TypeManager.short_type) ||
+ (vt == TypeManager.ushort_type) ||
+ (vt == TypeManager.int32_type) ||
+ (vt == TypeManager.uint32_type) ||
+ (vt == TypeManager.char_type) ||
+ (vt == TypeManager.float_type))){
+ Report.Error (
+ 677, Location, container.MakeName (Name) +
+ " A volatile field can not be of type `" +
+ TypeManager.CSharpName (vt) + "'");
+ return false;
+ }
+ }
+
+ if ((ModFlags & Modifiers.READONLY) != 0){
+ Report.Error (
+ 678, Location,
+ "A field can not be both volatile and readonly");
+ return false;
+ }
+ }
+
+ FieldAttributes fa = Modifiers.FieldAttr (ModFlags);
+
+ if (container is Struct &&
+ ((fa & FieldAttributes.Static) == 0) &&
+ t == container.TypeBuilder &&
+ !TypeManager.IsBuiltinType (t)){
+ Report.Error (523, Location, "Struct member `" + container.Name + "." + Name +
+ "' causes a cycle in the structure layout");
+ return false;
+ }
+
+ FieldBuilder = container.TypeBuilder.DefineField (
+ Name, t, Modifiers.FieldAttr (ModFlags));
+
+ TypeManager.RegisterFieldBase (FieldBuilder, this);
+ return true;
+ }
+
+ public void Emit (TypeContainer tc)
+ {
+ EmitContext ec = new EmitContext (tc, Location, null,
+ FieldBuilder.FieldType, ModFlags);
+
+ Attribute.ApplyAttributes (ec, FieldBuilder, this, OptAttributes);
+ }
+ }
+
+ //
+ // `set' and `get' accessors are represented with an Accessor.
+ //
+ public class Accessor {
+ //
+ // Null if the accessor is empty, or a Block if not
+ //
+ public Block Block;
+ public Attributes OptAttributes;
+
+ public Accessor (Block b, Attributes attrs)
+ {
+ Block = b;
+ OptAttributes = attrs;
+ }
+ }
+
+ //
+ // Properties and Indexers both generate PropertyBuilders, we use this to share
+ // their common bits.
+ //
+ abstract public class PropertyBase : MethodCore {
+ public Accessor Get, Set;
+ public PropertyBuilder PropertyBuilder;
+ public MethodBuilder GetBuilder, SetBuilder;
+ public MethodData GetData, SetData;
+
+ protected EmitContext ec;
+
+ public PropertyBase (Expression type, string name, int mod_flags, int allowed_mod,
+ Parameters parameters, Accessor get_block, Accessor set_block,
+ Attributes attrs, Location loc)
+ : base (type, mod_flags, allowed_mod, name, attrs, parameters, loc)
+ {
+ Get = get_block;
+ Set = set_block;
+ }
+
+ protected override bool DoDefine (TypeContainer container)
+ {
+ if (!base.DoDefine (container))
+ return false;
+
+ ec = new EmitContext (container, Location, null, MemberType, ModFlags);
+
+ return true;
+ }
+
+ //
+ // Checks our base implementation if any
+ //
+ protected override bool CheckBase (TypeContainer container)
+ {
+ base.CheckBase (container);
+
+ // Check whether arguments were correct.
+ if (!DoDefineParameters (container))
+ return false;
+
+ if (IsExplicitImpl)
+ return true;
+
+ string report_name;
+ MethodSignature ms, base_ms;
+ if (this is Indexer) {
+ string name, base_name;
+
+ report_name = "this";
+ name = TypeManager.IndexerPropertyName (container.TypeBuilder);
+ ms = new MethodSignature (name, null, ParameterTypes);
+ base_name = TypeManager.IndexerPropertyName (container.TypeBuilder.BaseType);
+ base_ms = new MethodSignature (base_name, null, ParameterTypes);
+ } else {
+ report_name = Name;
+ ms = base_ms = new MethodSignature (Name, null, ParameterTypes);
+ }
+
+ //
+ // Verify if the parent has a type with the same name, and then
+ // check whether we have to create a new slot for it or not.
+ //
+ Type ptype = container.TypeBuilder.BaseType;
+
+ // ptype is only null for System.Object while compiling corlib.
+ if (ptype == null) {
+ if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (container);
+
+ return true;
+ }
+
+ MemberList props_this;
+
+ props_this = TypeContainer.FindMembers (
+ container.TypeBuilder, MemberTypes.Property,
+ BindingFlags.NonPublic | BindingFlags.Public |
+ BindingFlags.Static | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly,
+ MethodSignature.method_signature_filter, ms);
+
+ if (props_this.Count > 0) {
+ Report.Error (111, Location, "Class `" + container.Name + "' " +
+ "already defines a member called `" + report_name + "' " +
+ "with the same parameter types");
+ return false;
+ }
+
+ MemberList mi_props;
+
+ mi_props = TypeContainer.FindMembers (
+ ptype, MemberTypes.Property,
+ BindingFlags.NonPublic | BindingFlags.Public |
+ BindingFlags.Instance | BindingFlags.Static,
+ MethodSignature.inheritable_method_signature_filter, base_ms);
+
+ if (mi_props.Count > 0){
+ PropertyInfo parent_property = (PropertyInfo) mi_props [0];
+ string name = parent_property.DeclaringType.Name + "." +
+ parent_property.Name;
+
+ MethodInfo get, set, parent_method;
+ get = parent_property.GetGetMethod (true);
+ set = parent_property.GetSetMethod (true);
+
+ if (get != null)
+ parent_method = get;
+ else if (set != null)
+ parent_method = set;
+ else
+ throw new Exception ("Internal error!");
+
+ if (!CheckMethodAgainstBase (container, flags, parent_method, name))
+ return false;
+
+ if ((ModFlags & Modifiers.NEW) == 0) {
+ Type parent_type = TypeManager.TypeToCoreType (
+ parent_property.PropertyType);
+
+ if (parent_type != MemberType) {
+ Report.Error (
+ 508, Location, container.MakeName (Name) + ": cannot " +
+ "change return type when overriding " +
+ "inherited member " + name);
+ return false;
+ }
+ }
+ } else {
+ if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (container);
+
+ if ((ModFlags & Modifiers.OVERRIDE) != 0){
+ if (this is Indexer)
+ Report.Error (115, Location,
+ container.MakeName (Name) +
+ " no suitable indexers found to override");
+ else
+ Report.Error (115, Location,
+ container.MakeName (Name) +
+ " no suitable properties found to override");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void Emit (TypeContainer tc)
+ {
+ //
+ // The PropertyBuilder can be null for explicit implementations, in that
+ // case, we do not actually emit the ".property", so there is nowhere to
+ // put the attribute
+ //
+ if (PropertyBuilder != null)
+ Attribute.ApplyAttributes (ec, PropertyBuilder, this, OptAttributes);
+
+ if (GetData != null) {
+ GetData.Emit (tc, Get.Block, Get);
+ Get.Block = null;
+ }
+
+ if (SetData != null) {
+ SetData.Emit (tc, Set.Block, Set);
+ Set.Block = null;
+ }
+ }
+ }
+
+ public class Property : PropertyBase {
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE |
+ Modifiers.STATIC |
+ Modifiers.SEALED |
+ Modifiers.OVERRIDE |
+ Modifiers.ABSTRACT |
+ Modifiers.UNSAFE |
+ Modifiers.EXTERN |
+ Modifiers.VIRTUAL;
+
+ public Property (Expression type, string name, int mod_flags,
+ Accessor get_block, Accessor set_block,
+ Attributes attrs, Location loc)
+ : base (type, name, mod_flags, AllowedModifiers,
+ Parameters.EmptyReadOnlyParameters,
+ get_block, set_block, attrs, loc)
+ {
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ if (!DoDefine (container))
+ return false;
+
+ if (!CheckBase (container))
+ return false;
+
+ flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
+
+ if (Get != null) {
+ Type [] parameters = TypeManager.NoTypes;
+
+ InternalParameters ip = new InternalParameters (
+ container, Parameters.EmptyReadOnlyParameters);
+
+ GetData = new MethodData (this, "get", MemberType,
+ parameters, ip, CallingConventions.Standard,
+ Get.OptAttributes, ModFlags, flags, false);
+
+ if (!GetData.Define (container))
+ return false;
+
+ GetBuilder = GetData.MethodBuilder;
+ }
+
+ if (Set != null) {
+ Type [] parameters = new Type [1];
+ parameters [0] = MemberType;
+
+ Parameter [] parms = new Parameter [1];
+ parms [0] = new Parameter (Type, "value", Parameter.Modifier.NONE, null);
+ InternalParameters ip = new InternalParameters (
+ container, new Parameters (parms, null, Location));
+
+ SetData = new MethodData (this, "set", TypeManager.void_type,
+ parameters, ip, CallingConventions.Standard,
+ Set.OptAttributes, ModFlags, flags, false);
+
+ if (!SetData.Define (container))
+ return false;
+
+ SetBuilder = SetData.MethodBuilder;
+ SetBuilder.DefineParameter (1, ParameterAttributes.None, "value");
+ }
+
+ // FIXME - PropertyAttributes.HasDefault ?
+
+ PropertyAttributes prop_attr =
+ PropertyAttributes.RTSpecialName |
+ PropertyAttributes.SpecialName;
+
+ if (!IsExplicitImpl){
+ PropertyBuilder = container.TypeBuilder.DefineProperty (
+ Name, prop_attr, MemberType, null);
+
+ if (Get != null)
+ PropertyBuilder.SetGetMethod (GetBuilder);
+
+ if (Set != null)
+ PropertyBuilder.SetSetMethod (SetBuilder);
+
+ //
+ // HACK for the reasons exposed above
+ //
+ if (!TypeManager.RegisterProperty (PropertyBuilder, GetBuilder, SetBuilder)) {
+ Report.Error (
+ 111, Location,
+ "Class `" + container.Name +
+ "' already contains a definition for the property `" +
+ Name + "'");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /// </summary>
+ /// Gigantic workaround for lameness in SRE follows :
+ /// This class derives from EventInfo and attempts to basically
+ /// wrap around the EventBuilder so that FindMembers can quickly
+ /// return this in it search for members
+ /// </summary>
+ public class MyEventBuilder : EventInfo {
+
+ //
+ // We use this to "point" to our Builder which is
+ // not really a MemberInfo
+ //
+ EventBuilder MyBuilder;
+
+ //
+ // We "catch" and wrap these methods
+ //
+ MethodInfo raise, remove, add;
+
+ EventAttributes attributes;
+ Type declaring_type, reflected_type, event_type;
+ string name;
+
+ Event my_event;
+
+ public MyEventBuilder (Event ev, TypeBuilder type_builder, string name, EventAttributes event_attr, Type event_type)
+ {
+ MyBuilder = type_builder.DefineEvent (name, event_attr, event_type);
+
+ // And now store the values in our own fields.
+
+ declaring_type = type_builder;
+
+ reflected_type = type_builder;
+
+ attributes = event_attr;
+ this.name = name;
+ my_event = ev;
+ this.event_type = event_type;
+ }
+
+ //
+ // Methods that you have to override. Note that you only need
+ // to "implement" the variants that take the argument (those are
+ // the "abstract" methods, the others (GetAddMethod()) are
+ // regular.
+ //
+ public override MethodInfo GetAddMethod (bool nonPublic)
+ {
+ return add;
+ }
+
+ public override MethodInfo GetRemoveMethod (bool nonPublic)
+ {
+ return remove;
+ }
+
+ public override MethodInfo GetRaiseMethod (bool nonPublic)
+ {
+ return raise;
+ }
+
+ //
+ // These methods make "MyEventInfo" look like a Builder
+ //
+ public void SetRaiseMethod (MethodBuilder raiseMethod)
+ {
+ raise = raiseMethod;
+ MyBuilder.SetRaiseMethod (raiseMethod);
+ }
+
+ public void SetRemoveOnMethod (MethodBuilder removeMethod)
+ {
+ remove = removeMethod;
+ MyBuilder.SetRemoveOnMethod (removeMethod);
+ }
+
+ public void SetAddOnMethod (MethodBuilder addMethod)
+ {
+ add = addMethod;
+ MyBuilder.SetAddOnMethod (addMethod);
+ }
+
+ public void SetCustomAttribute (CustomAttributeBuilder cb)
+ {
+ MyBuilder.SetCustomAttribute (cb);
+ }
+
+ public override object [] GetCustomAttributes (bool inherit)
+ {
+ // FIXME : There's nothing which can be seemingly done here because
+ // we have no way of getting at the custom attribute objects of the
+ // EventBuilder !
+ return null;
+ }
+
+ public override object [] GetCustomAttributes (Type t, bool inherit)
+ {
+ // FIXME : Same here !
+ return null;
+ }
+
+ public override bool IsDefined (Type t, bool b)
+ {
+ return true;
+ }
+
+ public override EventAttributes Attributes {
+ get {
+ return attributes;
+ }
+ }
+
+ public override string Name {
+ get {
+ return name;
+ }
+ }
+
+ public override Type DeclaringType {
+ get {
+ return declaring_type;
+ }
+ }
+
+ public override Type ReflectedType {
+ get {
+ return reflected_type;
+ }
+ }
+
+ public Type EventType {
+ get {
+ return event_type;
+ }
+ }
+
+ public void SetUsed ()
+ {
+ if (my_event != null)
+ my_event.status = (FieldBase.Status.ASSIGNED | FieldBase.Status.USED);
+ }
+ }
+
+ public class Event : FieldBase {
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE |
+ Modifiers.STATIC |
+ Modifiers.VIRTUAL |
+ Modifiers.SEALED |
+ Modifiers.OVERRIDE |
+ Modifiers.UNSAFE |
+ Modifiers.ABSTRACT;
+
+ public readonly Accessor Add;
+ public readonly Accessor Remove;
+ public MyEventBuilder EventBuilder;
+
+ MethodBuilder AddBuilder, RemoveBuilder;
+ MethodData AddData, RemoveData;
+
+ public Event (Expression type, string name, Object init, int mod, Accessor add,
+ Accessor remove, Attributes attrs, Location loc)
+ : base (type, mod, AllowedModifiers, name, init, attrs, loc)
+ {
+ Add = add;
+ Remove = remove;
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ EventAttributes e_attr = EventAttributes.RTSpecialName | EventAttributes.SpecialName;
+ MethodAttributes m_attr = MethodAttributes.HideBySig | MethodAttributes.SpecialName
+;
+ if (!DoDefine (container))
+ return false;
+
+ if (init != null && ((ModFlags & Modifiers.ABSTRACT) != 0)){
+ Report.Error (74, Location, "'" + container.Name + "." + Name +
+ "': abstract event can not have an initializer");
+ return false;
+ }
+
+ if (!MemberType.IsSubclassOf (TypeManager.delegate_type)) {
+ Report.Error (66, Location, "'" + container.Name + "." + Name +
+ "' : event must be of a delegate type");
+ return false;
+ }
+
+ Type [] parameter_types = new Type [1];
+ parameter_types [0] = MemberType;
+
+ Parameter [] parms = new Parameter [1];
+ parms [0] = new Parameter (Type, "value", Parameter.Modifier.NONE, null);
+ InternalParameters ip = new InternalParameters (
+ container, new Parameters (parms, null, Location));
+
+ if (!CheckBase (container))
+ return false;
+
+ //
+ // Now define the accessors
+ //
+ AddData = new MethodData (this, "add", TypeManager.void_type,
+ parameter_types, ip, CallingConventions.Standard,
+ (Add != null) ? Add.OptAttributes : null,
+ ModFlags, flags | m_attr, false);
+
+ if (!AddData.Define (container))
+ return false;
+
+ AddBuilder = AddData.MethodBuilder;
+ AddBuilder.DefineParameter (1, ParameterAttributes.None, "value");
+
+ RemoveData = new MethodData (this, "remove", TypeManager.void_type,
+ parameter_types, ip, CallingConventions.Standard,
+ (Remove != null) ? Remove.OptAttributes : null,
+ ModFlags, flags | m_attr, false);
+
+ if (!RemoveData.Define (container))
+ return false;
+
+ RemoveBuilder = RemoveData.MethodBuilder;
+ RemoveBuilder.DefineParameter (1, ParameterAttributes.None, "value");
+
+ if (!IsExplicitImpl){
+ EventBuilder = new MyEventBuilder (this,
+ container.TypeBuilder, Name, e_attr, MemberType);
+
+ if (Add == null && Remove == null) {
+ FieldBuilder = container.TypeBuilder.DefineField (
+ Name, MemberType,
+ FieldAttributes.Private | ((ModFlags & Modifiers.STATIC) != 0 ? FieldAttributes.Static : 0));
+ TypeManager.RegisterPrivateFieldOfEvent (
+ (EventInfo) EventBuilder, FieldBuilder);
+ TypeManager.RegisterFieldBase (FieldBuilder, this);
+ }
+
+ EventBuilder.SetAddOnMethod (AddBuilder);
+ EventBuilder.SetRemoveOnMethod (RemoveBuilder);
+
+ if (!TypeManager.RegisterEvent (EventBuilder, AddBuilder, RemoveBuilder)) {
+ Report.Error (111, Location,
+ "Class `" + container.Name +
+ "' already contains a definition for the event `" +
+ Name + "'");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void EmitDefaultMethod (EmitContext ec, bool is_add)
+ {
+ ILGenerator ig = ec.ig;
+ MethodInfo method = null;
+
+ if (is_add)
+ method = TypeManager.delegate_combine_delegate_delegate;
+ else
+ method = TypeManager.delegate_remove_delegate_delegate;
+
+ if ((ModFlags & Modifiers.STATIC) != 0) {
+ ig.Emit (OpCodes.Ldsfld, (FieldInfo) FieldBuilder);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Call, method);
+ ig.Emit (OpCodes.Castclass, MemberType);
+ ig.Emit (OpCodes.Stsfld, (FieldInfo) FieldBuilder);
+ } else {
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, (FieldInfo) FieldBuilder);
+ ig.Emit (OpCodes.Ldarg_1);
+ ig.Emit (OpCodes.Call, method);
+ ig.Emit (OpCodes.Castclass, MemberType);
+ ig.Emit (OpCodes.Stfld, (FieldInfo) FieldBuilder);
+ }
+ ig.Emit (OpCodes.Ret);
+ }
+
+ public void Emit (TypeContainer tc)
+ {
+ EmitContext ec;
+
+ ec = new EmitContext (tc, Location, null, MemberType, ModFlags);
+ Attribute.ApplyAttributes (ec, EventBuilder, this, OptAttributes);
+
+ if (Add != null) {
+ AddData.Emit (tc, Add.Block, Add);
+ Add.Block = null;
+ } else {
+ ILGenerator ig = AddData.MethodBuilder.GetILGenerator ();
+ ec = new EmitContext (tc, Location, ig, TypeManager.void_type, ModFlags);
+ EmitDefaultMethod (ec, true);
+ }
+
+ if (Remove != null) {
+ RemoveData.Emit (tc, Remove.Block, Remove);
+ Remove.Block = null;
+ } else {
+ ILGenerator ig = RemoveData.MethodBuilder.GetILGenerator ();
+ ec = new EmitContext (tc, Location, ig, TypeManager.void_type, ModFlags);
+ EmitDefaultMethod (ec, false);
+ }
+ }
+
+ }
+
+ //
+ // FIXME: This does not handle:
+ //
+ // int INTERFACENAME [ args ]
+ // Does not
+ //
+ // Only:
+ //
+ // int this [ args ]
+
+ public class Indexer : PropertyBase {
+
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE |
+ Modifiers.VIRTUAL |
+ Modifiers.SEALED |
+ Modifiers.OVERRIDE |
+ Modifiers.UNSAFE |
+ Modifiers.EXTERN |
+ Modifiers.ABSTRACT;
+
+ public string IndexerName;
+ public string InterfaceIndexerName;
+
+ //
+ // Are we implementing an interface ?
+ //
+ bool IsImplementing = false;
+
+ public Indexer (Expression type, string int_type, int flags, Parameters parameters,
+ Accessor get_block, Accessor set_block, Attributes attrs, Location loc)
+ : base (type, "", flags, AllowedModifiers, parameters, get_block, set_block,
+ attrs, loc)
+ {
+ ExplicitInterfaceName = int_type;
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ PropertyAttributes prop_attr =
+ PropertyAttributes.RTSpecialName |
+ PropertyAttributes.SpecialName;
+
+ if (!DoDefine (container))
+ return false;
+
+ IndexerName = Attribute.ScanForIndexerName (ec, OptAttributes);
+ if (IndexerName == null)
+ IndexerName = "Item";
+ else if (IsExplicitImpl)
+ Report.Error (592, Location,
+ "Attribute 'IndexerName' is not valid on this declaration " +
+ "type. It is valid on `property' declarations only.");
+
+ ShortName = IndexerName;
+ if (IsExplicitImpl) {
+ InterfaceIndexerName = TypeManager.IndexerPropertyName (InterfaceType);
+ Name = InterfaceType.FullName + "." + IndexerName;
+ } else {
+ InterfaceIndexerName = IndexerName;
+ Name = ShortName;
+ }
+
+ if (!CheckBase (container))
+ return false;
+
+ flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
+ if (Get != null){
+ InternalParameters ip = new InternalParameters (container, Parameters);
+
+ GetData = new MethodData (this, "get", MemberType,
+ ParameterTypes, ip, CallingConventions.Standard,
+ Get.OptAttributes, ModFlags, flags, false);
+
+ if (!GetData.Define (container))
+ return false;
+
+ GetBuilder = GetData.MethodBuilder;
+ }
+
+ if (Set != null){
+ int top = ParameterTypes.Length;
+ Type [] set_pars = new Type [top + 1];
+ ParameterTypes.CopyTo (set_pars, 0);
+ set_pars [top] = MemberType;
+
+ Parameter [] fixed_parms = Parameters.FixedParameters;
+
+ if (fixed_parms == null){
+ throw new Exception ("We currently do not support only array arguments in an indexer at: " + Location);
+ // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG
+ // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG
+ //
+ // Here is the problem: the `value' parameter has
+ // to come *after* the array parameter in the declaration
+ // like this:
+ // X (object [] x, Type value)
+ // .param [0]
+ //
+ // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG
+ // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG
+
+ }
+
+ Parameter [] tmp = new Parameter [fixed_parms.Length + 1];
+
+
+ fixed_parms.CopyTo (tmp, 0);
+ tmp [fixed_parms.Length] = new Parameter (
+ Type, "value", Parameter.Modifier.NONE, null);
+
+ Parameters set_formal_params = new Parameters (tmp, null, Location);
+
+ InternalParameters ip = new InternalParameters (container, set_formal_params);
+
+ SetData = new MethodData (this, "set", TypeManager.void_type,
+ set_pars, ip, CallingConventions.Standard,
+ Set.OptAttributes, ModFlags, flags, false);
+
+ if (!SetData.Define (container))
+ return false;
+
+ SetBuilder = SetData.MethodBuilder;
+ }
+
+ //
+ // Now name the parameters
+ //
+ Parameter [] p = Parameters.FixedParameters;
+ if (p != null) {
+ int i;
+
+ for (i = 0; i < p.Length; ++i) {
+ if (Get != null)
+ GetBuilder.DefineParameter (
+ i + 1, p [i].Attributes, p [i].Name);
+
+ if (Set != null)
+ SetBuilder.DefineParameter (
+ i + 1, p [i].Attributes, p [i].Name);
+ }
+
+ if (Set != null)
+ SetBuilder.DefineParameter (
+ i + 1, ParameterAttributes.None, "value");
+
+ if (i != ParameterTypes.Length) {
+ Parameter array_param = Parameters.ArrayParameter;
+
+ SetBuilder.DefineParameter (
+ i + 1, array_param.Attributes, array_param.Name);
+ }
+ }
+
+ if (GetData != null)
+ IsImplementing = GetData.IsImplementing;
+ else if (SetData != null)
+ IsImplementing = SetData.IsImplementing;
+
+ //
+ // Define the PropertyBuilder if one of the following conditions are met:
+ // a) we're not implementing an interface indexer.
+ // b) the indexer has a different IndexerName and this is no
+ // explicit interface implementation.
+ //
+ if (!IsExplicitImpl) {
+ PropertyBuilder = container.TypeBuilder.DefineProperty (
+ IndexerName, prop_attr, MemberType, ParameterTypes);
+
+ if (GetData != null)
+ PropertyBuilder.SetGetMethod (GetBuilder);
+
+ if (SetData != null)
+ PropertyBuilder.SetSetMethod (SetBuilder);
+
+ TypeManager.RegisterIndexer (PropertyBuilder, GetBuilder, SetBuilder,
+ ParameterTypes);
+ }
+
+ return true;
+ }
+ }
+
+ public class Operator : MemberCore {
+
+ const int AllowedModifiers =
+ Modifiers.PUBLIC |
+ Modifiers.UNSAFE |
+ Modifiers.EXTERN |
+ Modifiers.STATIC;
+
+ const int RequiredModifiers =
+ Modifiers.PUBLIC |
+ Modifiers.STATIC;
+
+ public enum OpType : byte {
+
+ // Unary operators
+ LogicalNot,
+ OnesComplement,
+ Increment,
+ Decrement,
+ True,
+ False,
+
+ // Unary and Binary operators
+ Addition,
+ Subtraction,
+
+ UnaryPlus,
+ UnaryNegation,
+
+ // Binary operators
+ Multiply,
+ Division,
+ Modulus,
+ BitwiseAnd,
+ BitwiseOr,
+ ExclusiveOr,
+ LeftShift,
+ RightShift,
+ Equality,
+ Inequality,
+ GreaterThan,
+ LessThan,
+ GreaterThanOrEqual,
+ LessThanOrEqual,
+
+ // Implicit and Explicit
+ Implicit,
+ Explicit
+ };
+
+ public readonly OpType OperatorType;
+ public readonly Expression ReturnType;
+ public readonly Expression FirstArgType, SecondArgType;
+ public readonly string FirstArgName, SecondArgName;
+ public Block Block;
+ public Attributes OptAttributes;
+ public MethodBuilder OperatorMethodBuilder;
+
+ public string MethodName;
+ public Method OperatorMethod;
+
+ public Operator (OpType type, Expression ret_type, int flags,
+ Expression arg1type, string arg1name,
+ Expression arg2type, string arg2name,
+ Block block, Attributes attrs, Location loc)
+ : base ("", loc)
+ {
+ OperatorType = type;
+ ReturnType = ret_type;
+ ModFlags = Modifiers.Check (AllowedModifiers, flags, Modifiers.PUBLIC, loc);
+ FirstArgType = arg1type;
+ FirstArgName = arg1name;
+ SecondArgType = arg2type;
+ SecondArgName = arg2name;
+ Block = block;
+ OptAttributes = attrs;
+ }
+
+ string Prototype (TypeContainer container)
+ {
+ return container.Name + ".operator " + OperatorType + " (" + FirstArgType + "," +
+ SecondArgType + ")";
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ int length = 1;
+ MethodName = "op_" + OperatorType;
+
+ if (SecondArgType != null)
+ length = 2;
+
+ Parameter [] param_list = new Parameter [length];
+
+ if ((ModFlags & RequiredModifiers) != RequiredModifiers){
+ Report.Error (
+ 558, Location,
+ "User defined operators `" +
+ Prototype (container) +
+ "' must be declared static and public");
+ return false;
+ }
+
+ param_list[0] = new Parameter (FirstArgType, FirstArgName,
+ Parameter.Modifier.NONE, null);
+ if (SecondArgType != null)
+ param_list[1] = new Parameter (SecondArgType, SecondArgName,
+ Parameter.Modifier.NONE, null);
+
+ OperatorMethod = new Method (ReturnType, ModFlags, MethodName,
+ new Parameters (param_list, null, Location),
+ OptAttributes, Location);
+
+ OperatorMethod.IsOperator = true;
+ OperatorMethod.Define (container);
+
+ if (OperatorMethod.MethodBuilder == null)
+ return false;
+
+ OperatorMethodBuilder = OperatorMethod.MethodBuilder;
+
+ Type [] param_types = OperatorMethod.ParameterTypes;
+ Type declaring_type = OperatorMethodBuilder.DeclaringType;
+ Type return_type = OperatorMethod.GetReturnType ();
+ Type first_arg_type = param_types [0];
+
+ // Rules for conversion operators
+
+ if (OperatorType == OpType.Implicit || OperatorType == OpType.Explicit) {
+ if (first_arg_type == return_type && first_arg_type == declaring_type){
+ Report.Error (
+ 555, Location,
+ "User-defined conversion cannot take an object of the " +
+ "enclosing type and convert to an object of the enclosing" +
+ " type");
+ return false;
+ }
+
+ if (first_arg_type != declaring_type && return_type != declaring_type){
+ Report.Error (
+ 556, Location,
+ "User-defined conversion must convert to or from the " +
+ "enclosing type");
+ return false;
+ }
+
+ if (first_arg_type == TypeManager.object_type ||
+ return_type == TypeManager.object_type){
+ Report.Error (
+ -8, Location,
+ "User-defined conversion cannot convert to or from " +
+ "object type");
+ return false;
+ }
+
+ if (first_arg_type.IsInterface || return_type.IsInterface){
+ Report.Error (
+ 552, Location,
+ "User-defined conversion cannot convert to or from an " +
+ "interface type");
+ return false;
+ }
+
+ if (first_arg_type.IsSubclassOf (return_type) ||
+ return_type.IsSubclassOf (first_arg_type)){
+ Report.Error (
+ -10, Location,
+ "User-defined conversion cannot convert between types " +
+ "that derive from each other");
+ return false;
+ }
+ } else if (SecondArgType == null) {
+ // Checks for Unary operators
+
+ if (first_arg_type != declaring_type){
+ Report.Error (
+ 562, Location,
+ "The parameter of a unary operator must be the " +
+ "containing type");
+ return false;
+ }
+
+ if (OperatorType == OpType.Increment || OperatorType == OpType.Decrement) {
+ if (return_type != declaring_type){
+ Report.Error (
+ 559, Location,
+ "The parameter and return type for ++ and -- " +
+ "must be the containing type");
+ return false;
+ }
+
+ }
+
+ if (OperatorType == OpType.True || OperatorType == OpType.False) {
+ if (return_type != TypeManager.bool_type){
+ Report.Error (
+ 215, Location,
+ "The return type of operator True or False " +
+ "must be bool");
+ return false;
+ }
+ }
+
+ } else {
+ // Checks for Binary operators
+
+ if (first_arg_type != declaring_type &&
+ param_types [1] != declaring_type){
+ Report.Error (
+ 563, Location,
+ "One of the parameters of a binary operator must " +
+ "be the containing type");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void Emit (TypeContainer container)
+ {
+ //
+ // abstract or extern methods have no bodies
+ //
+ if ((ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
+ return;
+
+ OperatorMethod.Block = Block;
+ OperatorMethod.Emit (container);
+ Block = null;
+ }
+
+ public static string GetName (OpType ot)
+ {
+ switch (ot){
+ case OpType.LogicalNot:
+ return "!";
+ case OpType.OnesComplement:
+ return "~";
+ case OpType.Increment:
+ return "++";
+ case OpType.Decrement:
+ return "--";
+ case OpType.True:
+ return "true";
+ case OpType.False:
+ return "false";
+ case OpType.Addition:
+ return "+";
+ case OpType.Subtraction:
+ return "-";
+ case OpType.UnaryPlus:
+ return "+";
+ case OpType.UnaryNegation:
+ return "-";
+ case OpType.Multiply:
+ return "*";
+ case OpType.Division:
+ return "/";
+ case OpType.Modulus:
+ return "%";
+ case OpType.BitwiseAnd:
+ return "&";
+ case OpType.BitwiseOr:
+ return "|";
+ case OpType.ExclusiveOr:
+ return "^";
+ case OpType.LeftShift:
+ return "<<";
+ case OpType.RightShift:
+ return ">>";
+ case OpType.Equality:
+ return "==";
+ case OpType.Inequality:
+ return "!=";
+ case OpType.GreaterThan:
+ return ">";
+ case OpType.LessThan:
+ return "<";
+ case OpType.GreaterThanOrEqual:
+ return ">=";
+ case OpType.LessThanOrEqual:
+ return "<=";
+ case OpType.Implicit:
+ return "implicit";
+ case OpType.Explicit:
+ return "explicit";
+ default: return "";
+ }
+ }
+
+ public override string ToString ()
+ {
+ Type return_type = OperatorMethod.GetReturnType();
+ Type [] param_types = OperatorMethod.ParameterTypes;
+
+ if (SecondArgType == null)
+ return String.Format (
+ "{0} operator {1}({2})",
+ TypeManager.CSharpName (return_type),
+ GetName (OperatorType),
+ param_types [0]);
+ else
+ return String.Format (
+ "{0} operator {1}({2}, {3})",
+ TypeManager.CSharpName (return_type),
+ GetName (OperatorType),
+ param_types [0], param_types [1]);
+ }
+ }
+
+ //
+ // This is used to compare method signatures
+ //
+ struct MethodSignature {
+ public string Name;
+ public Type RetType;
+ public Type [] Parameters;
+
+ /// <summary>
+ /// This delegate is used to extract methods which have the
+ /// same signature as the argument
+ /// </summary>
+ public static MemberFilter method_signature_filter;
+
+ /// <summary>
+ /// This delegate is used to extract inheritable methods which
+ /// have the same signature as the argument. By inheritable,
+ /// this means that we have permissions to override the method
+ /// from the current assembly and class
+ /// </summary>
+ public static MemberFilter inheritable_method_signature_filter;
+
+ static MethodSignature ()
+ {
+ method_signature_filter = new MemberFilter (MemberSignatureCompare);
+ inheritable_method_signature_filter = new MemberFilter (
+ InheritableMemberSignatureCompare);
+ }
+
+ public MethodSignature (string name, Type ret_type, Type [] parameters)
+ {
+ Name = name;
+ RetType = ret_type;
+
+ if (parameters == null)
+ Parameters = TypeManager.NoTypes;
+ else
+ Parameters = parameters;
+ }
+
+ public override string ToString ()
+ {
+ string pars = "";
+ if (Parameters.Length != 0){
+ System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+ for (int i = 0; i < Parameters.Length; i++){
+ sb.Append (Parameters [i]);
+ if (i+1 < Parameters.Length)
+ sb.Append (", ");
+ }
+ pars = sb.ToString ();
+ }
+
+ return String.Format ("{0} {1} ({2})", RetType, Name, pars);
+ }
+
+ public override int GetHashCode ()
+ {
+ return Name.GetHashCode ();
+ }
+
+ public override bool Equals (Object o)
+ {
+ MethodSignature other = (MethodSignature) o;
+
+ if (other.Name != Name)
+ return false;
+
+ if (other.RetType != RetType)
+ return false;
+
+ if (Parameters == null){
+ if (other.Parameters == null)
+ return true;
+ return false;
+ }
+
+ if (other.Parameters == null)
+ return false;
+
+ int c = Parameters.Length;
+ if (other.Parameters.Length != c)
+ return false;
+
+ for (int i = 0; i < c; i++)
+ if (other.Parameters [i] != Parameters [i])
+ return false;
+
+ return true;
+ }
+
+ static bool MemberSignatureCompare (MemberInfo m, object filter_criteria)
+ {
+ MethodSignature sig = (MethodSignature) filter_criteria;
+
+ if (m.Name != sig.Name)
+ return false;
+
+ Type ReturnType;
+ MethodInfo mi = m as MethodInfo;
+ PropertyInfo pi = m as PropertyInfo;
+
+ if (mi != null)
+ ReturnType = mi.ReturnType;
+ else if (pi != null)
+ ReturnType = pi.PropertyType;
+ else
+ return false;
+
+ //
+ // we use sig.RetType == null to mean `do not check the
+ // method return value.
+ //
+ if (sig.RetType != null)
+ if (ReturnType != sig.RetType)
+ return false;
+
+ Type [] args;
+ if (mi != null)
+ args = TypeManager.GetArgumentTypes (mi);
+ else
+ args = TypeManager.GetArgumentTypes (pi);
+ Type [] sigp = sig.Parameters;
+
+ if (args.Length != sigp.Length)
+ return false;
+
+ for (int i = args.Length; i > 0; ){
+ i--;
+ if (args [i] != sigp [i])
+ return false;
+ }
+ return true;
+ }
+
+ //
+ // This filter should be used when we are requesting methods that
+ // we want to override.
+ //
+ // This makes a number of assumptions, for example
+ // that the methods being extracted are of a parent
+ // class (this means we know implicitly that we are
+ // being called to find out about members by a derived
+ // class).
+ //
+ static bool InheritableMemberSignatureCompare (MemberInfo m, object filter_criteria)
+ {
+ MethodInfo mi;
+ PropertyInfo pi = m as PropertyInfo;
+
+ if (pi != null) {
+ mi = pi.GetGetMethod (true);
+ if (mi == null)
+ mi = pi.GetSetMethod (true);
+ } else
+ mi = m as MethodInfo;
+
+ if (mi == null){
+ Console.WriteLine ("Nothing found");
+ }
+
+ MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ // If only accessible to the current class.
+ if (prot == MethodAttributes.Private)
+ return false;
+
+ if (!MemberSignatureCompare (m, filter_criteria))
+ return false;
+
+ // If only accessible to the defining assembly or
+ if (prot == MethodAttributes.FamANDAssem ||
+ prot == MethodAttributes.Assembly){
+ if (m.DeclaringType.Assembly == CodeGen.AssemblyBuilder)
+ return true;
+ else
+ return false;
+ }
+
+ // Anything else (FamOrAssembly and Public) is fine
+ return true;
+ }
+ }
+}
--- /dev/null
+//
+// codegen.cs: The code generator
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Code generator class.
+ /// </summary>
+ public class CodeGen {
+ static AppDomain current_domain;
+ public static AssemblyBuilder AssemblyBuilder;
+ public static ModuleBuilder ModuleBuilder;
+
+ static public SymbolWriter SymbolWriter;
+
+ public static string Basename (string name)
+ {
+ int pos = name.LastIndexOf ("/");
+
+ if (pos != -1)
+ return name.Substring (pos + 1);
+
+ pos = name.LastIndexOf ("\\");
+ if (pos != -1)
+ return name.Substring (pos + 1);
+
+ return name;
+ }
+
+ public static string Dirname (string name)
+ {
+ int pos = name.LastIndexOf ("/");
+
+ if (pos != -1)
+ return name.Substring (0, pos);
+
+ pos = name.LastIndexOf ("\\");
+ if (pos != -1)
+ return name.Substring (0, pos);
+
+ return ".";
+ }
+
+ static string TrimExt (string name)
+ {
+ int pos = name.LastIndexOf (".");
+
+ return name.Substring (0, pos);
+ }
+
+ static public string FileName;
+
+ //
+ // Initializes the symbol writer
+ //
+ static void InitializeSymbolWriter ()
+ {
+ SymbolWriter = SymbolWriter.GetSymbolWriter (ModuleBuilder);
+
+ //
+ // If we got an ISymbolWriter instance, initialize it.
+ //
+ if (SymbolWriter == null) {
+ Report.Warning (
+ -18, "Could not find the symbol writer assembly (Mono.CSharp.Debugger.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CSharp.Debugger directory.");
+ return;
+ }
+ }
+
+ //
+ // Initializes the code generator variables
+ //
+ static public void Init (string name, string output, bool want_debugging_support)
+ {
+ AssemblyName an;
+
+ FileName = output;
+ an = new AssemblyName ();
+ an.Name = Path.GetFileNameWithoutExtension (name);
+
+ current_domain = AppDomain.CurrentDomain;
+ AssemblyBuilder = current_domain.DefineDynamicAssembly (
+ an, AssemblyBuilderAccess.RunAndSave, Dirname (name));
+
+ //
+ // Pass a path-less name to DefineDynamicModule. Wonder how
+ // this copes with output in different directories then.
+ // FIXME: figure out how this copes with --output /tmp/blah
+ //
+ // If the third argument is true, the ModuleBuilder will dynamically
+ // load the default symbol writer.
+ //
+ ModuleBuilder = AssemblyBuilder.DefineDynamicModule (
+ Basename (name), Basename (output), want_debugging_support);
+
+ if (want_debugging_support)
+ InitializeSymbolWriter ();
+ }
+
+ static public void Save (string name)
+ {
+ try {
+ AssemblyBuilder.Save (Basename (name));
+ } catch (System.IO.IOException io){
+ Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
+ }
+ }
+ }
+
+ /// <summary>
+ /// An Emit Context is created for each body of code (from methods,
+ /// properties bodies, indexer bodies or constructor bodies)
+ /// </summary>
+ public class EmitContext {
+ public DeclSpace DeclSpace;
+ public DeclSpace TypeContainer;
+ public ILGenerator ig;
+
+ /// <summary>
+ /// This variable tracks the `checked' state of the compilation,
+ /// it controls whether we should generate code that does overflow
+ /// checking, or if we generate code that ignores overflows.
+ ///
+ /// The default setting comes from the command line option to generate
+ /// checked or unchecked code plus any source code changes using the
+ /// checked/unchecked statements or expressions. Contrast this with
+ /// the ConstantCheckState flag.
+ /// </summary>
+
+ public bool CheckState;
+
+ /// <summary>
+ /// The constant check state is always set to `true' and cant be changed
+ /// from the command line. The source code can change this setting with
+ /// the `checked' and `unchecked' statements and expressions.
+ /// </summary>
+ public bool ConstantCheckState;
+
+ /// <summary>
+ /// Whether we are emitting code inside a static or instance method
+ /// </summary>
+ public bool IsStatic;
+
+ /// <summary>
+ /// Whether we are emitting a field initializer
+ /// </summary>
+ public bool IsFieldInitializer;
+
+ /// <summary>
+ /// The value that is allowed to be returned or NULL if there is no
+ /// return type.
+ /// </summary>
+ public Type ReturnType;
+
+ /// <summary>
+ /// Points to the Type (extracted from the TypeContainer) that
+ /// declares this body of code
+ /// </summary>
+ public Type ContainerType;
+
+ /// <summary>
+ /// Whether this is generating code for a constructor
+ /// </summary>
+ public bool IsConstructor;
+
+ /// <summary>
+ /// Whether we're control flow analysis enabled
+ /// </summary>
+ public bool DoFlowAnalysis;
+
+ /// <summary>
+ /// Keeps track of the Type to LocalBuilder temporary storage created
+ /// to store structures (used to compute the address of the structure
+ /// value on structure method invocations)
+ /// </summary>
+ public Hashtable temporary_storage;
+
+ public Block CurrentBlock;
+
+ public int CurrentFile;
+
+ /// <summary>
+ /// The location where we store the return value.
+ /// </summary>
+ LocalBuilder return_value;
+
+ /// <summary>
+ /// The location where return has to jump to return the
+ /// value
+ /// </summary>
+ public Label ReturnLabel;
+
+ /// <summary>
+ /// If we already defined the ReturnLabel
+ /// </summary>
+ public bool HasReturnLabel;
+
+ /// <summary>
+ /// Whether we are in a Finally block
+ /// </summary>
+ public bool InFinally;
+
+ /// <summary>
+ /// Whether we are in a Try block
+ /// </summary>
+ public bool InTry;
+
+ /// <summary>
+ /// Whether we are inside an iterator block.
+ /// </summary>
+ public bool InIterator;
+
+ /// <summary>
+ /// Whether we need an explicit return statement at the end of the method.
+ /// </summary>
+ public bool NeedExplicitReturn;
+
+ /// <summary>
+ /// Whether remapping of locals, parameters and fields is turned on.
+ /// Used by iterators and anonymous methods.
+ /// </summary>
+ public bool RemapToProxy;
+
+ /// <summary>
+ /// Whether we are in a Catch block
+ /// </summary>
+ public bool InCatch;
+
+ /// <summary>
+ /// Whether we are inside an unsafe block
+ /// </summary>
+ public bool InUnsafe;
+
+ /// <summary>
+ /// Whether we are in a `fixed' initialization
+ /// </summary>
+ public bool InFixedInitializer;
+
+ /// <summary>
+ /// Whether we are inside an anonymous method.
+ /// </summary>
+ public bool InAnonymousMethod;
+
+ /// <summary>
+ /// Location for this EmitContext
+ /// </summary>
+ public Location loc;
+
+ /// <summary>
+ /// Used to flag that it is ok to define types recursively, as the
+ /// expressions are being evaluated as part of the type lookup
+ /// during the type resolution process
+ /// </summary>
+ public bool ResolvingTypeTree;
+
+ /// <summary>
+ /// Inside an enum definition, we do not resolve enumeration values
+ /// to their enumerations, but rather to the underlying type/value
+ /// This is so EnumVal + EnumValB can be evaluated.
+ ///
+ /// There is no "E operator + (E x, E y)", so during an enum evaluation
+ /// we relax the rules
+ /// </summary>
+ public bool InEnumContext;
+
+ protected Stack FlowStack;
+
+ public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
+ Type return_type, int code_flags, bool is_constructor)
+ {
+ this.ig = ig;
+
+ TypeContainer = parent;
+ DeclSpace = ds;
+ CheckState = RootContext.Checked;
+ ConstantCheckState = true;
+
+ IsStatic = (code_flags & Modifiers.STATIC) != 0;
+ InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
+ RemapToProxy = InIterator;
+ ReturnType = return_type;
+ IsConstructor = is_constructor;
+ CurrentBlock = null;
+ CurrentFile = 0;
+
+ if (parent != null){
+ // Can only be null for the ResolveType contexts.
+ ContainerType = parent.TypeBuilder;
+ if (parent.UnsafeContext)
+ InUnsafe = true;
+ else
+ InUnsafe = (code_flags & Modifiers.UNSAFE) != 0;
+ }
+ loc = l;
+
+ FlowStack = new Stack ();
+
+ if (ReturnType == TypeManager.void_type)
+ ReturnType = null;
+ }
+
+ public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
+ Type return_type, int code_flags, bool is_constructor)
+ : this (tc, tc, l, ig, return_type, code_flags, is_constructor)
+ {
+ }
+
+ public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
+ Type return_type, int code_flags)
+ : this (tc, tc, l, ig, return_type, code_flags, false)
+ {
+ }
+
+ public FlowBranching CurrentBranching {
+ get {
+ return (FlowBranching) FlowStack.Peek ();
+ }
+ }
+
+ // <summary>
+ // Starts a new code branching. This inherits the state of all local
+ // variables and parameters from the current branching.
+ // </summary>
+ public FlowBranching StartFlowBranching (FlowBranchingType type, Location loc)
+ {
+ FlowBranching cfb = new FlowBranching (CurrentBranching, type, null, loc);
+
+ FlowStack.Push (cfb);
+
+ return cfb;
+ }
+
+ // <summary>
+ // Starts a new code branching for block `block'.
+ // </summary>
+ public FlowBranching StartFlowBranching (Block block)
+ {
+ FlowBranching cfb;
+ FlowBranchingType type;
+
+ if (CurrentBranching.Type == FlowBranchingType.SWITCH)
+ type = FlowBranchingType.SWITCH_SECTION;
+ else
+ type = FlowBranchingType.BLOCK;
+
+ cfb = new FlowBranching (CurrentBranching, type, block, block.StartLocation);
+
+ FlowStack.Push (cfb);
+
+ return cfb;
+ }
+
+ // <summary>
+ // Ends a code branching. Merges the state of locals and parameters
+ // from all the children of the ending branching.
+ // </summary>
+ public FlowReturns EndFlowBranching ()
+ {
+ FlowBranching cfb = (FlowBranching) FlowStack.Pop ();
+
+ return CurrentBranching.MergeChild (cfb);
+ }
+
+ // <summary>
+ // Kills the current code branching. This throws away any changed state
+ // information and should only be used in case of an error.
+ // </summary>
+ public void KillFlowBranching ()
+ {
+ FlowBranching cfb = (FlowBranching) FlowStack.Pop ();
+ }
+
+ public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
+ {
+ bool has_ret = false;
+
+ if (!Location.IsNull (loc))
+ CurrentFile = loc.File;
+
+ if (block != null){
+ try {
+ int errors = Report.Errors;
+
+ block.EmitMeta (this, ip, block);
+
+ if (Report.Errors == errors){
+ bool old_do_flow_analysis = DoFlowAnalysis;
+ DoFlowAnalysis = true;
+
+ FlowBranching cfb = new FlowBranching (block, loc);
+ FlowStack.Push (cfb);
+
+ if (!block.Resolve (this)) {
+ FlowStack.Pop ();
+ DoFlowAnalysis = old_do_flow_analysis;
+ return;
+ }
+
+ cfb = (FlowBranching) FlowStack.Pop ();
+ FlowReturns returns = cfb.MergeTopBlock ();
+
+ DoFlowAnalysis = old_do_flow_analysis;
+
+ has_ret = block.Emit (this);
+
+ if ((returns == FlowReturns.ALWAYS) ||
+ (returns == FlowReturns.EXCEPTION) ||
+ (returns == FlowReturns.UNREACHABLE))
+ has_ret = true;
+
+ if (Report.Errors == errors){
+ if (RootContext.WarningLevel >= 3)
+ block.UsageWarning ();
+ }
+ }
+ } catch {
+ Console.WriteLine ("Exception caught by the compiler while compiling:");
+ Console.WriteLine (" Block that caused the problem begin at: " + loc);
+
+ if (CurrentBlock != null){
+ Console.WriteLine (" Block being compiled: [{0},{1}]",
+ CurrentBlock.StartLocation, CurrentBlock.EndLocation);
+ }
+ throw;
+ }
+ }
+
+ if (ReturnType != null && !has_ret){
+ //
+ // FIXME: we need full flow analysis to implement this
+ // correctly and emit an error instead of a warning.
+ //
+ //
+ if (!InIterator){
+ Report.Error (161, loc, "Not all code paths return a value");
+ return;
+ }
+ }
+
+ if (HasReturnLabel)
+ ig.MarkLabel (ReturnLabel);
+ if (return_value != null){
+ ig.Emit (OpCodes.Ldloc, return_value);
+ ig.Emit (OpCodes.Ret);
+ } else {
+ if (!InTry){
+ if (InIterator)
+ has_ret = true;
+
+ if (!has_ret || HasReturnLabel) {
+ ig.Emit (OpCodes.Ret);
+ NeedExplicitReturn = false;
+ }
+ }
+
+ // Unfortunately, System.Reflection.Emit automatically emits a leave
+ // to the end of a finally block. This is a problem if no code is
+ // following the try/finally block since we may jump to a point after
+ // the end of the method. As a workaround, emit an explicit ret here.
+
+ if (NeedExplicitReturn) {
+ if (ReturnType != null)
+ ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
+ ig.Emit (OpCodes.Ret);
+ }
+ }
+ }
+
+ /// <summary>
+ /// This is called immediately before emitting an IL opcode to tell the symbol
+ /// writer to which source line this opcode belongs.
+ /// </summary>
+ public void Mark (Location loc, bool check_file)
+ {
+ if ((CodeGen.SymbolWriter == null) || Location.IsNull (loc))
+ return;
+
+ if (check_file && (CurrentFile != loc.File))
+ return;
+
+ ig.MarkSequencePoint (null, loc.Row, 0, 0, 0);
+ }
+
+ /// <summary>
+ /// Returns a temporary storage for a variable of type t as
+ /// a local variable in the current body.
+ /// </summary>
+ public LocalBuilder GetTemporaryStorage (Type t)
+ {
+ LocalBuilder location;
+
+ if (temporary_storage != null){
+ location = (LocalBuilder) temporary_storage [t];
+ if (location != null)
+ return location;
+ }
+
+ location = ig.DeclareLocal (t);
+
+ return location;
+ }
+
+ public void FreeTemporaryStorage (LocalBuilder b)
+ {
+ // Empty for now.
+ }
+
+ /// <summary>
+ /// Current loop begin and end labels.
+ /// </summary>
+ public Label LoopBegin, LoopEnd;
+
+ /// <summary>
+ /// Whether we are inside a loop and break/continue are possible.
+ /// </summary>
+ public bool InLoop;
+
+ /// <summary>
+ /// This is incremented each time we enter a try/catch block and
+ /// decremented if we leave it.
+ /// </summary>
+ public int TryCatchLevel;
+
+ /// <summary>
+ /// The TryCatchLevel at the begin of the current loop.
+ /// </summary>
+ public int LoopBeginTryCatchLevel;
+
+ /// <summary>
+ /// Default target in a switch statement. Only valid if
+ /// InSwitch is true
+ /// </summary>
+ public Label DefaultTarget;
+
+ /// <summary>
+ /// If this is non-null, points to the current switch statement
+ /// </summary>
+ public Switch Switch;
+
+ /// <summary>
+ /// ReturnValue creates on demand the LocalBuilder for the
+ /// return value from the function. By default this is not
+ /// used. This is only required when returns are found inside
+ /// Try or Catch statements.
+ /// </summary>
+ public LocalBuilder TemporaryReturn ()
+ {
+ if (return_value == null){
+ return_value = ig.DeclareLocal (ReturnType);
+ ReturnLabel = ig.DefineLabel ();
+ HasReturnLabel = true;
+ }
+
+ return return_value;
+ }
+
+ //
+ // Creates a field `name' with the type `t' on the proxy class
+ //
+ public FieldBuilder MapVariable (string name, Type t)
+ {
+ if (InIterator){
+ return IteratorHandler.Current.MapVariable (name, t);
+ }
+
+ throw new Exception ("MapVariable for an unknown state");
+ }
+
+ //
+ // Emits the proper object to address fields on a remapped
+ // variable/parameter to field in anonymous-method/iterator proxy classes.
+ //
+ public void EmitThis ()
+ {
+ ig.Emit (OpCodes.Ldarg_0);
+
+ if (!IsStatic){
+ if (InIterator)
+ ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.this_field);
+ else
+ throw new Exception ("EmitThis for an unknown state");
+ }
+ }
+
+ public void EmitArgument (int idx)
+ {
+ if (InIterator)
+ ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.parameter_fields [idx]);
+ else
+ throw new Exception ("EmitStoreArgument for an unknown state");
+ }
+
+ public void EmitStoreArgument (int idx)
+ {
+ if (InIterator)
+ ig.Emit (OpCodes.Stfld, IteratorHandler.Current.parameter_fields [idx]);
+ else
+ throw new Exception ("EmitStoreArgument for an unknown state");
+ }
+
+ public Expression GetThis (Location loc)
+ {
+ This my_this;
+ if (CurrentBlock != null)
+ my_this = new This (CurrentBlock, loc);
+ else
+ my_this = new This (loc);
+
+ if (!my_this.ResolveBase (this))
+ my_this = null;
+
+ return my_this;
+ }
+ }
+}
--- /dev/null
+//
+// const.cs: Constant declarations.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+//
+
+//
+// This is needed because the following situation arises:
+//
+// The FieldBuilder is declared with the real type for an enumeration
+//
+// When we attempt to set the value for the constant, the FieldBuilder.SetConstant
+// function aborts because it requires its argument to be of the same type
+//
+
+namespace Mono.CSharp {
+
+ using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Collections;
+
+ public class Const : MemberCore {
+ public Expression ConstantType;
+ public Expression Expr;
+ public Attributes OptAttributes;
+ public FieldBuilder FieldBuilder;
+ EmitContext const_ec;
+
+ object ConstantValue = null;
+ Type type;
+
+ bool in_transit = false;
+
+ public const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE;
+
+ public Const (Expression constant_type, string name, Expression expr, int mod_flags,
+ Attributes attrs, Location loc)
+ : base (name, loc)
+ {
+ ConstantType = constant_type;
+ Name = name;
+ Expr = expr;
+ ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE, loc);
+ OptAttributes = attrs;
+ }
+
+ public FieldAttributes FieldAttr {
+ get {
+ return FieldAttributes.Literal | FieldAttributes.Static |
+ Modifiers.FieldAttr (ModFlags) ;
+ }
+ }
+
+#if DEBUG
+ void dump_tree (Type t)
+ {
+ Console.WriteLine ("Dumping hierarchy");
+ while (t != null){
+ Console.WriteLine (" " + t.FullName + " " +
+ (t.GetType ().IsEnum ? "yes" : "no"));
+ t = t.BaseType;
+ }
+ }
+#endif
+
+ /// <summary>
+ /// Defines the constant in the @parent
+ /// </summary>
+ public override bool Define (TypeContainer parent)
+ {
+ type = parent.ResolveType (ConstantType, false, Location);
+
+ if (type == null)
+ return false;
+
+ const_ec = new EmitContext (parent, Location, null, type, ModFlags);
+
+ if (!TypeManager.IsBuiltinType (type) &&
+ (!type.IsSubclassOf (TypeManager.enum_type))) {
+ Report.Error (
+ -3, Location,
+ "Constant type is not valid (only system types are allowed)");
+ return false;
+ }
+
+ Type ptype = parent.TypeBuilder.BaseType;
+
+ if (ptype != null) {
+ MemberList list = TypeContainer.FindMembers (
+ ptype, MemberTypes.Field, BindingFlags.Public,
+ Type.FilterName, Name);
+
+ if (list.Count == 0)
+ if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (parent);
+
+ } else if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (parent);
+
+ FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
+
+ TypeManager.RegisterConstant (FieldBuilder, this);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Looks up the value of a constant field. Defines it if it hasn't
+ /// already been. Similar to LookupEnumValue in spirit.
+ /// </summary>
+ public object LookupConstantValue ()
+ {
+ if (ConstantValue != null)
+ return ConstantValue;
+
+ if (in_transit) {
+ Report.Error (110, Location,
+ "The evaluation of the constant value for `" +
+ Name + "' involves a circular definition.");
+ return null;
+ }
+
+ in_transit = true;
+ int errors = Report.Errors;
+
+ Expr = Expr.Resolve (const_ec);
+
+ in_transit = false;
+
+ if (Expr == null) {
+ if (errors == Report.Errors)
+ Report.Error (150, Location, "A constant value is expected");
+ return null;
+ }
+
+ if (!(Expr is Constant)) {
+ UnCheckedExpr un_expr = Expr as UnCheckedExpr;
+ CheckedExpr ch_expr = Expr as CheckedExpr;
+
+ if ((un_expr != null) && (un_expr.Expr is Constant))
+ Expr = un_expr.Expr;
+ else if ((ch_expr != null) && (ch_expr.Expr is Constant))
+ Expr = ch_expr.Expr;
+ else {
+ if (errors == Report.Errors)
+ Report.Error (150, Location, "A constant value is expected");
+ return null;
+ }
+ }
+
+ ConstantValue = ((Constant) Expr).GetValue ();
+
+ if (type != Expr.Type) {
+ bool fail;
+
+ // from the null type to any reference-type.
+ if (Expr is NullLiteral && !type.IsValueType &&
+ !TypeManager.IsEnumType (type)){
+ return NullLiteral.Null;
+ }
+
+ ConstantValue = TypeManager.ChangeType (ConstantValue, type, out fail);
+ if (fail){
+ Convert.Error_CannotImplicitConversion (Location, Expr.Type, type);
+ return null;
+ }
+
+ if (type == TypeManager.int32_type)
+ Expr = new IntConstant ((int) ConstantValue);
+ else if (type == TypeManager.uint32_type)
+ Expr = new UIntConstant ((uint) ConstantValue);
+ else if (type == TypeManager.int64_type)
+ Expr = new LongConstant ((long) ConstantValue);
+ else if (type == TypeManager.uint64_type)
+ Expr = new ULongConstant ((ulong) ConstantValue);
+ else if (type == TypeManager.float_type)
+ Expr = new FloatConstant ((float) ConstantValue);
+ else if (type == TypeManager.double_type)
+ Expr = new DoubleConstant ((double) ConstantValue);
+ else if (type == TypeManager.string_type)
+ Expr = new StringConstant ((string) ConstantValue);
+ else if (type == TypeManager.short_type)
+ Expr = new ShortConstant ((short) ConstantValue);
+ else if (type == TypeManager.ushort_type)
+ Expr = new UShortConstant ((ushort) ConstantValue);
+ else if (type == TypeManager.sbyte_type)
+ Expr = new SByteConstant ((sbyte) ConstantValue);
+ else if (type == TypeManager.byte_type)
+ Expr = new ByteConstant ((byte) ConstantValue);
+ else if (type == TypeManager.char_type)
+ Expr = new CharConstant ((char) ConstantValue);
+ else if (type == TypeManager.bool_type)
+ Expr = new BoolConstant ((bool) ConstantValue);
+ }
+
+ if (type.IsEnum){
+ //
+ // This sadly does not work for our user-defined enumerations types ;-(
+ //
+ try {
+ ConstantValue = System.Enum.ToObject (
+ type, ConstantValue);
+ } catch (ArgumentException){
+ Report.Error (
+ -16, Location,
+ ".NET SDK 1.0 does not permit to create the constant "+
+ " field from a user-defined enumeration");
+ }
+ }
+
+ FieldBuilder.SetConstant (ConstantValue);
+
+ if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
+ return null;
+
+ return ConstantValue;
+ }
+
+
+ /// <summary>
+ /// Emits the field value by evaluating the expression
+ /// </summary>
+ public void EmitConstant (TypeContainer parent)
+ {
+ LookupConstantValue ();
+
+ return;
+ }
+ }
+}
+
+
--- /dev/null
+//
+// constant.cs: Constants.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+//
+
+namespace Mono.CSharp {
+
+ using System;
+ using System.Reflection.Emit;
+
+ /// <summary>
+ /// Base class for constants and literals.
+ /// </summary>
+ public abstract class Constant : Expression {
+ /// <remarks>
+ /// This is different from ToString in that ToString
+ /// is supposed to be there for debugging purposes,
+ /// and is not guaranteed to be useful for anything else,
+ /// AsString() will provide something that can be used
+ /// for round-tripping C# code. Maybe it can be used
+ /// for IL assembly as well.
+ /// </remarks>
+ public abstract string AsString ();
+
+ override public string ToString ()
+ {
+ return this.GetType ().Name + " (" + AsString () + ")";
+ }
+
+ /// <summary>
+ /// This is used to obtain the actual value of the literal
+ /// cast into an object.
+ /// </summary>
+ public abstract object GetValue ();
+
+ /// <summary>
+ /// Constants are always born in a fully resolved state
+ /// </summary>
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ //
+ // The various ToXXXX conversion functions are used by the constant
+ // folding evaluator. A null value is returned if the conversion is
+ // not possible.
+ //
+ // Note: not all the patterns for catching `implicit_conv' are the same.
+ // some implicit conversions can never be performed between two types
+ // even if the conversion would be lossless (for example short to uint),
+ // but some conversions are explicitly permitted by the standard provided
+ // that there will be no loss of information (for example, int to uint).
+ //
+ public DoubleConstant ToDouble (Location loc)
+ {
+ DoubleConstant c = ConvertToDouble ();
+
+ if (c == null)
+ Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.double_type);
+
+ return c;
+ }
+
+ public FloatConstant ToFloat (Location loc)
+ {
+ FloatConstant c = ConvertToFloat ();
+
+ if (c == null)
+ Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.float_type);
+
+ return c;
+ }
+
+ public ULongConstant ToULong (Location loc)
+ {
+ ULongConstant c = ConvertToULong ();
+
+ if (c == null)
+ Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint64_type);
+
+ return c;
+ }
+
+ public LongConstant ToLong (Location loc)
+ {
+ LongConstant c = ConvertToLong ();
+
+ if (c == null)
+ Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int64_type);
+
+ return c;
+ }
+
+ public UIntConstant ToUInt (Location loc)
+ {
+ UIntConstant c = ConvertToUInt ();
+
+ if (c == null)
+ Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint32_type);
+
+ return c;
+ }
+
+ public IntConstant ToInt (Location loc)
+ {
+ IntConstant c = ConvertToInt ();
+
+ if (c == null)
+ Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int32_type);
+
+ return c;
+ }
+
+ public virtual DoubleConstant ConvertToDouble ()
+ {
+ return null;
+ }
+
+ public virtual FloatConstant ConvertToFloat ()
+ {
+ return null;
+ }
+
+ public virtual ULongConstant ConvertToULong ()
+ {
+ return null;
+ }
+
+ public virtual LongConstant ConvertToLong ()
+ {
+ return null;
+ }
+
+ public virtual UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public virtual IntConstant ConvertToInt ()
+ {
+ return null;
+ }
+ }
+
+ public class BoolConstant : Constant {
+ public readonly bool Value;
+
+ public BoolConstant (bool val)
+ {
+ type = TypeManager.bool_type;
+ eclass = ExprClass.Value;
+
+ Value = val;
+ }
+
+ override public string AsString ()
+ {
+ return Value ? "true" : "false";
+ }
+
+ public override object GetValue ()
+ {
+ return (object) Value;
+ }
+
+
+ public override void Emit (EmitContext ec)
+ {
+ if (Value)
+ ec.ig.Emit (OpCodes.Ldc_I4_1);
+ else
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ }
+ }
+
+ public class ByteConstant : Constant {
+ public readonly byte Value;
+
+ public ByteConstant (byte v)
+ {
+ type = TypeManager.byte_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ IntLiteral.EmitInt (ec.ig, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return new ULongConstant (Value);
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return new UIntConstant (Value);
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return new IntConstant (Value);
+ }
+ }
+
+ public class CharConstant : Constant {
+ public readonly char Value;
+
+ public CharConstant (char v)
+ {
+ type = TypeManager.char_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ IntLiteral.EmitInt (ec.ig, Value);
+ }
+
+ static public string descape (char c)
+ {
+ switch (c){
+ case '\a':
+ return "\\a";
+ case '\b':
+ return "\\b";
+ case '\n':
+ return "\\n";
+ case '\t':
+ return "\\t";
+ case '\v':
+ return "\\v";
+ case '\r':
+ return "\\r";
+ case '\\':
+ return "\\\\";
+ case '\f':
+ return "\\f";
+ case '\0':
+ return "\\0";
+ case '"':
+ return "\\\"";
+ case '\'':
+ return "\\\'";
+ }
+ return c.ToString ();
+ }
+
+ public override string AsString ()
+ {
+ return "\"" + descape (Value) + "\"";
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return new ULongConstant (Value);
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return new UIntConstant (Value);
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return new IntConstant (Value);
+ }
+ }
+
+ public class SByteConstant : Constant {
+ public readonly sbyte Value;
+
+ public SByteConstant (sbyte v)
+ {
+ type = TypeManager.sbyte_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ IntLiteral.EmitInt (ec.ig, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ if (Value >= 0)
+ return new ULongConstant ((ulong) Value);
+
+ return null;
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return new IntConstant (Value);
+ }
+ }
+
+ public class ShortConstant : Constant {
+ public readonly short Value;
+
+ public ShortConstant (short v)
+ {
+ type = TypeManager.short_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ IntLiteral.EmitInt (ec.ig, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return null;
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return new IntConstant (Value);
+ }
+ }
+
+ public class UShortConstant : Constant {
+ public readonly ushort Value;
+
+ public UShortConstant (ushort v)
+ {
+ type = TypeManager.ushort_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ IntLiteral.EmitInt (ec.ig, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return new ULongConstant (Value);
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return new UIntConstant (Value);
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return new IntConstant (Value);
+ }
+ }
+
+ public class IntConstant : Constant {
+ public readonly int Value;
+
+ public IntConstant (int v)
+ {
+ type = TypeManager.int32_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ static public void EmitInt (ILGenerator ig, int i)
+ {
+ switch (i){
+ case -1:
+ ig.Emit (OpCodes.Ldc_I4_M1);
+ break;
+
+ case 0:
+ ig.Emit (OpCodes.Ldc_I4_0);
+ break;
+
+ case 1:
+ ig.Emit (OpCodes.Ldc_I4_1);
+ break;
+
+ case 2:
+ ig.Emit (OpCodes.Ldc_I4_2);
+ break;
+
+ case 3:
+ ig.Emit (OpCodes.Ldc_I4_3);
+ break;
+
+ case 4:
+ ig.Emit (OpCodes.Ldc_I4_4);
+ break;
+
+ case 5:
+ ig.Emit (OpCodes.Ldc_I4_5);
+ break;
+
+ case 6:
+ ig.Emit (OpCodes.Ldc_I4_6);
+ break;
+
+ case 7:
+ ig.Emit (OpCodes.Ldc_I4_7);
+ break;
+
+ case 8:
+ ig.Emit (OpCodes.Ldc_I4_8);
+ break;
+
+ default:
+ if (i >= -128 && i <= 127){
+ ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
+ } else
+ ig.Emit (OpCodes.Ldc_I4, i);
+ break;
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ EmitInt (ec.ig, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ if (Value < 0)
+ return null;
+
+ return new ULongConstant ((ulong) Value);
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ if (Value < 0)
+ return null;
+
+ return new UIntConstant ((uint) Value);
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return this;
+ }
+ }
+
+ public class UIntConstant : Constant {
+ public readonly uint Value;
+
+ public UIntConstant (uint v)
+ {
+ type = TypeManager.uint32_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ IntLiteral.EmitInt (ec.ig, unchecked ((int) Value));
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return new ULongConstant (Value);
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return new LongConstant (Value);
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return this;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return null;
+ }
+ }
+
+ public class LongConstant : Constant {
+ public readonly long Value;
+
+ public LongConstant (long v)
+ {
+ type = TypeManager.int64_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ EmitLong (ig, Value);
+ }
+
+ static public void EmitLong (ILGenerator ig, long l)
+ {
+ if ((l >> 32) == 0){
+ IntLiteral.EmitInt (ig, unchecked ((int) l));
+ ig.Emit (OpCodes.Conv_U8);
+ } else {
+ ig.Emit (OpCodes.Ldc_I8, l);
+ }
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ if (Value < 0)
+ return null;
+
+ return new ULongConstant ((ulong) Value);
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return this;
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return null;
+ }
+ }
+
+ public class ULongConstant : Constant {
+ public readonly ulong Value;
+
+ public ULongConstant (ulong v)
+ {
+ type = TypeManager.uint64_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ LongLiteral.EmitLong (ig, unchecked ((long) Value));
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return new FloatConstant (Value);
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return this;
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return null;
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return null;
+ }
+ }
+
+ public class FloatConstant : Constant {
+ public readonly float Value;
+
+ public FloatConstant (float v)
+ {
+ type = TypeManager.float_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldc_R4, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return new DoubleConstant (Value);
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return this;
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return null;
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return null;
+ }
+ }
+
+ public class DoubleConstant : Constant {
+ public readonly double Value;
+
+ public DoubleConstant (double v)
+ {
+ type = TypeManager.double_type;
+ eclass = ExprClass.Value;
+ Value = v;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldc_R8, Value);
+ }
+
+ public override string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override DoubleConstant ConvertToDouble ()
+ {
+ return this;
+ }
+
+ public override FloatConstant ConvertToFloat ()
+ {
+ return null;
+ }
+
+ public override ULongConstant ConvertToULong ()
+ {
+ return null;
+ }
+
+ public override LongConstant ConvertToLong ()
+ {
+ return null;
+ }
+
+ public override UIntConstant ConvertToUInt ()
+ {
+ return null;
+ }
+
+ public override IntConstant ConvertToInt ()
+ {
+ return null;
+ }
+ }
+
+ public class DecimalConstant : Constant {
+ public readonly decimal Value;
+
+ public DecimalConstant (decimal d)
+ {
+ type = TypeManager.decimal_type;
+ eclass = ExprClass.Value;
+ Value = d;
+ }
+
+ override public string AsString ()
+ {
+ return Value.ToString ();
+ }
+
+ public override object GetValue ()
+ {
+ return (object) Value;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int [] words = Decimal.GetBits (Value);
+
+ //
+ // FIXME: we could optimize this, and call a better
+ // constructor
+ //
+
+ ILGenerator ig = ec.ig;
+
+ IntConstant.EmitInt (ig, words [0]);
+ IntConstant.EmitInt (ig, words [1]);
+ IntConstant.EmitInt (ig, words [2]);
+
+ // sign
+ IntConstant.EmitInt (ig, words [3] >> 31);
+
+ // power
+ IntConstant.EmitInt (ig, (words [3] >> 16) & 0xff);
+
+ ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args);
+ }
+ }
+
+ public class StringConstant : Constant {
+ public readonly string Value;
+
+ public StringConstant (string s)
+ {
+ type = TypeManager.string_type;
+ eclass = ExprClass.Value;
+ Value = s;
+ }
+
+ // FIXME: Escape the string.
+ override public string AsString ()
+ {
+ return "\"" + Value + "\"";
+ }
+
+ public override object GetValue ()
+ {
+ return Value;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldstr, Value);
+ }
+ }
+
+}
+
+
--- /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 {
+ static public void Error_CannotConvertType (Location loc, Type source, Type target)
+ {
+ Report.Error (30, loc, "Cannot convert type '" +
+ TypeManager.CSharpName (source) + "' to '" +
+ TypeManager.CSharpName (target) + "'");
+ }
+
+ 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);
+ }
+
+ //
+ // 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 (expr_type.IsValueType)
+ return new BoxedCast (expr);
+ if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type)
+ return new EmptyCast (expr, target_type);
+ } else if (target_type == TypeManager.value_type) {
+ if (expr_type.IsValueType)
+ return new BoxedCast (expr);
+ if (expr is NullLiteral)
+ return new BoxedCast (expr);
+ } else if (expr_type.IsSubclassOf (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)
+ return new BoxedCast (expr);
+
+ return new EmptyCast (expr, target_type);
+ } else {
+
+ // 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 is NullLiteral){
+ if (target_type.IsPointer)
+ return NullPointer.Null;
+
+ if (!target_type.IsValueType)
+ return new NullCast (expr, target_type);
+ }
+
+ // from any class-type S to any interface-type T.
+ if (target_type.IsInterface) {
+ if (TypeManager.ImplementsInterface (expr_type, target_type)){
+ if (expr_type.IsClass)
+ return new EmptyCast (expr, target_type);
+ else if (expr_type.IsValueType)
+ return new BoxedCast (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 any delegate type to System.Delegate
+ if ((expr_type == TypeManager.delegate_type ||
+ expr_type.IsSubclassOf (TypeManager.delegate_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 ||
+ expr_type.IsSubclassOf (TypeManager.delegate_type))
+ if (target_type == TypeManager.icloneable_type)
+ return new EmptyCast (expr, target_type);
+
+ return null;
+
+ }
+
+ return null;
+ }
+
+ //
+ // Tests whether an implicit reference conversion exists between expr_type
+ // and target_type
+ //
+ public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ //
+ // This is the boxed case.
+ //
+ if (target_type == TypeManager.object_type) {
+ if (expr_type.IsClass || expr_type.IsValueType ||
+ expr_type.IsInterface || expr_type == TypeManager.enum_type)
+ return true;
+ } else if (expr_type.IsSubclassOf (target_type)) {
+ return true;
+ } else {
+ // 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 (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 any delegate type to System.Delegate
+ if ((expr_type == TypeManager.delegate_type ||
+ expr_type.IsSubclassOf (TypeManager.delegate_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 ||
+ expr_type.IsSubclassOf (TypeManager.delegate_type))
+ if (target_type == TypeManager.icloneable_type)
+ return true;
+
+ // from the null type to any reference-type.
+ if (expr is NullLiteral && !target_type.IsValueType &&
+ !TypeManager.IsEnumType (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 (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ 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);
+ }
+ }
+
+ Type real_target_type = target_type;
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to short, int, long, float, double.
+ //
+ 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);
+ } else if (expr_type == TypeManager.byte_type){
+ //
+ // From byte to short, ushort, int, uint, long, ulong, float, double
+ //
+ 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);
+ } else if (expr_type == TypeManager.short_type){
+ //
+ // From short to int, long, float, double
+ //
+ 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);
+ } else if (expr_type == TypeManager.ushort_type){
+ //
+ // From ushort to int, uint, long, ulong, float, double
+ //
+ 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);
+ } else if (expr_type == TypeManager.int32_type){
+ //
+ // From int to long, float, double
+ //
+ 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);
+ } else if (expr_type == TypeManager.uint32_type){
+ //
+ // From uint to long, ulong, float, double
+ //
+ 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);
+ } 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);
+ } 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);
+ } else if (expr_type == TypeManager.char_type){
+ //
+ // From char to ushort, int, uint, long, ulong, float, double
+ //
+ 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);
+ } 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 (ImplicitStandardConversionExists (expr, target_type))
+ return true;
+
+ Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
+
+ if (dummy != null)
+ return true;
+
+ return false;
+ }
+
+ public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
+ {
+ Expression dummy = ImplicitUserConversion (
+ ec, new EmptyExpression (source), target, Location.Null);
+ return dummy != null;
+ }
+
+ /// <summary>
+ /// Determines if a standard implicit conversion exists from
+ /// expr_type to target_type
+ /// </summary>
+ public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ 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 == target_type)
+ return true;
+
+ //Console.WriteLine ("No !!");
+
+ // First numeric conversions
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to short, int, long, float, double.
+ //
+ 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
+ //
+ 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, float, double
+ //
+ 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, float, double
+ //
+ 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, float, double
+ //
+ 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, float, double
+ //
+ 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 float, double
+ //
+ 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, long, ulong, float, double
+ //
+ 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 (ImplicitReferenceConversionExists (expr, target_type))
+ return true;
+
+ 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 (Byte.MinValue >= 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 (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
+ return true;
+
+ return false;
+ }
+
+ //
+ // Used internally by FindMostEncompassedType, this is used
+ // to avoid creating lots of objects in the tight loop inside
+ // FindMostEncompassedType
+ //
+ static EmptyExpression priv_fmet_param;
+
+ /// <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 (priv_fmet_param == null)
+ priv_fmet_param = new EmptyExpression ();
+
+ foreach (Type t in types){
+ priv_fmet_param.SetType (t);
+
+ if (best == null) {
+ best = t;
+ continue;
+ }
+
+ if (ImplicitStandardConversionExists (priv_fmet_param, best))
+ best = t;
+ }
+
+ return best;
+ }
+
+ //
+ // Used internally by FindMostEncompassingType, this is used
+ // to avoid creating lots of objects in the tight loop inside
+ // FindMostEncompassingType
+ //
+ static EmptyExpression priv_fmee_ret;
+
+ /// <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 (priv_fmee_ret == null)
+ priv_fmee_ret = new EmptyExpression ();
+
+ foreach (Type t in types){
+ priv_fmee_ret.SetType (best);
+
+ if (best == null) {
+ best = t;
+ continue;
+ }
+
+ if (ImplicitStandardConversionExists (priv_fmee_ret, t))
+ best = t;
+ }
+
+ return best;
+ }
+
+ //
+ // Used to avoid creating too many objects
+ //
+ static EmptyExpression priv_fms_expr;
+
+ /// <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 (MethodGroupExpr me, Expression source,
+ bool apply_explicit_conv_rules,
+ Location loc)
+ {
+ ArrayList src_types_set = new ArrayList ();
+
+ if (priv_fms_expr == null)
+ priv_fms_expr = new EmptyExpression ();
+
+ //
+ // If any operator converts from S then Sx = S
+ //
+ Type source_type = source.Type;
+ foreach (MethodBase mb in me.Methods){
+ ParameterData pd = Invocation.GetParameterData (mb);
+ Type param_type = pd.ParameterType (0);
+
+ if (param_type == source_type)
+ return param_type;
+
+ if (apply_explicit_conv_rules) {
+ //
+ // From the spec :
+ // Find the set of applicable user-defined conversion operators, U. This set
+ // consists of the
+ // user-defined implicit or explicit conversion operators declared by
+ // the classes or structs in D that convert from a type encompassing
+ // or encompassed by S to a type encompassing or encompassed by T
+ //
+ priv_fms_expr.SetType (param_type);
+ if (ImplicitStandardConversionExists (priv_fms_expr, source_type))
+ src_types_set.Add (param_type);
+ else {
+ if (ImplicitStandardConversionExists (source, param_type))
+ src_types_set.Add (param_type);
+ }
+ } else {
+ //
+ // Only if S is encompassed by param_type
+ //
+ if (ImplicitStandardConversionExists (source, 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);
+ }
+
+ //
+ // Useful in avoiding proliferation of objects
+ //
+ static EmptyExpression priv_fmt_expr;
+
+ /// <summary>
+ /// Finds the most specific target Tx according to section 13.4.4
+ /// </summary>
+ static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
+ bool apply_explicit_conv_rules,
+ Location loc)
+ {
+ ArrayList tgt_types_set = new ArrayList ();
+
+ if (priv_fmt_expr == null)
+ priv_fmt_expr = new EmptyExpression ();
+
+ //
+ // If any operator converts to T then Tx = T
+ //
+ foreach (MethodInfo mi in me.Methods){
+ Type ret_type = mi.ReturnType;
+
+ if (ret_type == target)
+ return ret_type;
+
+ if (apply_explicit_conv_rules) {
+ //
+ // From the spec :
+ // Find the set of applicable user-defined conversion operators, U.
+ //
+ // This set consists of the
+ // user-defined implicit or explicit conversion operators declared by
+ // the classes or structs in D that convert from a type encompassing
+ // or encompassed by S to a type encompassing or encompassed by T
+ //
+ priv_fms_expr.SetType (ret_type);
+ if (ImplicitStandardConversionExists (priv_fms_expr, target))
+ tgt_types_set.Add (ret_type);
+ else {
+ priv_fms_expr.SetType (target);
+ if (ImplicitStandardConversionExists (priv_fms_expr, ret_type))
+ tgt_types_set.Add (ret_type);
+ }
+ } else {
+ //
+ // Only if T is encompassed by param_type
+ //
+ priv_fms_expr.SetType (ret_type);
+ if (ImplicitStandardConversionExists (priv_fms_expr, target))
+ tgt_types_set.Add (ret_type);
+ }
+ }
+
+ //
+ // Explicit conv rules
+ //
+ if (apply_explicit_conv_rules) {
+ ArrayList candidate_set = new ArrayList ();
+
+ foreach (Type ret_type in tgt_types_set){
+ priv_fmt_expr.SetType (ret_type);
+
+ if (ImplicitStandardConversionExists (priv_fmt_expr, target))
+ candidate_set.Add (ret_type);
+ }
+
+ 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);
+ }
+
+ /// <summary>
+ /// Computes the MethodGroup for the user-defined conversion
+ /// operators from source_type to target_type. `look_for_explicit'
+ /// controls whether we should also include the list of explicit
+ /// operators
+ /// </summary>
+ static MethodGroupExpr GetConversionOperators (EmitContext ec,
+ Type source_type, Type target_type,
+ Location loc, bool look_for_explicit)
+ {
+ Expression mg1 = null, mg2 = null;
+ Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
+ string op_name;
+
+ op_name = "op_Implicit";
+
+ MethodGroupExpr union3;
+
+ mg1 = Expression.MethodLookup (ec, source_type, op_name, loc);
+ if (source_type.BaseType != null)
+ mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
+
+ if (mg1 == null)
+ union3 = (MethodGroupExpr) mg2;
+ else if (mg2 == null)
+ union3 = (MethodGroupExpr) mg1;
+ else
+ union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
+
+ mg1 = Expression.MethodLookup (ec, target_type, op_name, loc);
+ if (mg1 != null){
+ if (union3 != null)
+ union3 = Invocation.MakeUnionSet (union3, mg1, loc);
+ else
+ union3 = (MethodGroupExpr) mg1;
+ }
+
+ if (target_type.BaseType != null)
+ mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
+
+ if (mg1 != null){
+ if (union3 != null)
+ union3 = Invocation.MakeUnionSet (union3, mg1, loc);
+ else
+ union3 = (MethodGroupExpr) mg1;
+ }
+
+ MethodGroupExpr union4 = null;
+
+ if (look_for_explicit) {
+ op_name = "op_Explicit";
+
+ mg5 = Expression.MemberLookup (ec, source_type, op_name, loc);
+ if (source_type.BaseType != null)
+ mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
+
+ mg7 = Expression.MemberLookup (ec, target_type, op_name, loc);
+ if (target_type.BaseType != null)
+ mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
+
+ MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
+ MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
+
+ union4 = Invocation.MakeUnionSet (union5, union6, loc);
+ }
+
+ return Invocation.MakeUnionSet (union3, union4, loc);
+ }
+
+ /// <summary>
+ /// User-defined conversions
+ /// </summary>
+ static public Expression UserDefinedConversion (EmitContext ec, Expression source,
+ Type target, Location loc,
+ bool look_for_explicit)
+ {
+ MethodGroupExpr union;
+ Type source_type = source.Type;
+ MethodBase method = null;
+
+ union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
+ if (union == null)
+ return null;
+
+ Type most_specific_source, most_specific_target;
+#if BLAH
+ foreach (MethodBase m in union.Methods){
+ Console.WriteLine ("Name: " + m.Name);
+ Console.WriteLine (" : " + ((MethodInfo)m).ReturnType);
+ }
+#endif
+
+ most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
+ if (most_specific_source == null)
+ return null;
+
+ most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
+ if (most_specific_target == null)
+ return null;
+
+ int count = 0;
+
+
+ foreach (MethodBase mb in union.Methods){
+ ParameterData pd = Invocation.GetParameterData (mb);
+ MethodInfo mi = (MethodInfo) mb;
+
+ if (pd.ParameterType (0) == most_specific_source &&
+ mi.ReturnType == most_specific_target) {
+ method = mb;
+ count++;
+ }
+ }
+
+ if (method == null || count > 1)
+ return null;
+
+
+ //
+ // 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 ((MethodInfo) 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)
+ {
+ Type expr_type = expr.Type;
+ 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 (expr_type == target_type && !(expr is NullLiteral))
+ return expr;
+
+ e = ImplicitNumericConversion (ec, expr, target_type, loc);
+ if (e != null)
+ return e;
+
+ e = ImplicitReferenceConversion (expr, target_type);
+ if (e != null)
+ return e;
+
+ if ((target_type == TypeManager.enum_type ||
+ target_type.IsSubclassOf (TypeManager.enum_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;
+ }
+ }
+
+ if (target_type.IsPointer) {
+ if (expr is NullLiteral)
+ return new EmptyCast (expr, target_type);
+
+ if (expr_type == TypeManager.void_ptr_type)
+ return new EmptyCast (expr, target_type);
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Attemps to perform an implict 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);
+ } else if (target_type == TypeManager.byte_type){
+ if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
+ return new ByteConstant ((byte) value);
+ } else if (target_type == TypeManager.short_type){
+ if (value >= Int16.MinValue && value <= Int16.MaxValue)
+ return new ShortConstant ((short) value);
+ } else if (target_type == TypeManager.ushort_type){
+ if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
+ return new UShortConstant ((ushort) value);
+ } else if (target_type == TypeManager.uint32_type){
+ if (value >= 0)
+ return new UIntConstant ((uint) value);
+ } 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);
+ } else if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) value);
+ else if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) value);
+
+ 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
+ //n
+ if (underlying == TypeManager.int64_type)
+ e = new LongLiteral (0);
+ else if (underlying == TypeManager.uint64_type)
+ e = new ULongLiteral (0);
+
+ return new EnumConstant (e, target_type);
+ }
+ return null;
+ }
+
+ static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
+ {
+ string msg = "Cannot convert implicitly from `"+
+ TypeManager.CSharpName (source) + "' to `" +
+ TypeManager.CSharpName (target) + "'";
+
+ Report.Error (29, loc, msg);
+ }
+
+ /// <summary>
+ /// Attemptes to implicityly convert `target' into `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;
+
+ e = ImplicitConversion (ec, source, target_type, loc);
+ if (e != null)
+ return e;
+
+ if (source is DoubleLiteral && target_type == TypeManager.float_type){
+ Report.Error (664, loc,
+ "Double literal cannot be implicitly converted to " +
+ "float type, use F suffix to create a float literal");
+ }
+
+ Error_CannotImplicitConversion (loc, source.Type, target_type);
+
+ return null;
+ }
+
+ /// <summary>
+ /// Performs the explicit numeric conversions
+ /// </summary>
+ static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+
+ //
+ // If we have an enumeration, extract the underlying type,
+ // use this during the comparison, but wrap around the original
+ // target_type
+ //
+ Type real_target_type = target_type;
+
+ if (TypeManager.IsEnumType (real_target_type))
+ real_target_type = TypeManager.EnumToUnderlying (real_target_type);
+
+ if (ImplicitStandardConversionExists (expr, real_target_type)){
+ Expression ce = ImplicitConversionStandard (ec, expr, real_target_type, loc);
+
+ if (real_target_type != target_type)
+ return new EmptyCast (ce, target_type);
+ return ce;
+ }
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to byte, ushort, uint, ulong, char
+ //
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
+ } else if (expr_type == TypeManager.byte_type){
+ //
+ // From byte to sbyte and char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
+ } else if (expr_type == TypeManager.short_type){
+ //
+ // From short to sbyte, byte, ushort, uint, ulong, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
+ } else if (expr_type == TypeManager.ushort_type){
+ //
+ // From ushort to sbyte, byte, short, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
+ } else if (expr_type == TypeManager.int32_type){
+ //
+ // From int to sbyte, byte, short, ushort, uint, ulong, char
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
+ } 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 (ec, expr, target_type, ConvCast.Mode.U4_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, 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 (ec, expr, target_type, ConvCast.Mode.I8_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, 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 (ec, expr, target_type, ConvCast.Mode.U8_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
+ if (real_target_type == TypeManager.int64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
+ } else if (expr_type == TypeManager.char_type){
+ //
+ // From char to sbyte, byte, short
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, 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 (ec, expr, target_type, ConvCast.Mode.R4_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4);
+ if (real_target_type == TypeManager.int64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I8);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH);
+ } else if (expr_type == TypeManager.double_type){
+ //
+ // From double to byte, byte, short,
+ // ushort, int, uint, long, ulong,
+ // char, float or decimal
+ //
+ if (real_target_type == TypeManager.sbyte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1);
+ if (real_target_type == TypeManager.byte_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
+ if (real_target_type == TypeManager.short_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
+ if (real_target_type == TypeManager.ushort_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2);
+ if (real_target_type == TypeManager.int32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
+ if (real_target_type == TypeManager.uint32_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4);
+ if (real_target_type == TypeManager.int64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
+ if (real_target_type == TypeManager.uint64_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8);
+ if (real_target_type == TypeManager.char_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH);
+ if (real_target_type == TypeManager.float_type)
+ return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
+ }
+
+ // decimal is taken care of by the op_Explicit methods.
+
+ 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_value_type = target_type.IsValueType;
+
+ if (source_type == target_type)
+ 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 (target_type.IsSubclassOf (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 (!target_type.IsSubclassOf (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 (!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 &&
+ target_type.IsSubclassOf (TypeManager.delegate_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_value_type = target_type.IsValueType;
+
+ //
+ // From object to any reference type
+ //
+ if (source_type == TypeManager.object_type && !target_is_value_type)
+ return new ClassCast (source, target_type);
+
+
+ //
+ // From any class S to any class-type T, provided S is a base class of T
+ //
+ if (target_type.IsSubclassOf (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))
+ return new ClassCast (source, target_type);
+ else
+ 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 &&
+ target_type.IsSubclassOf (TypeManager.delegate_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 ExplicitConversion (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+ Type original_expr_type = expr_type;
+
+ if (expr_type.IsSubclassOf (TypeManager.enum_type)){
+ if (target_type == TypeManager.enum_type ||
+ target_type == TypeManager.object_type) {
+ if (expr is EnumConstant)
+ expr = ((EnumConstant) expr).Child;
+ // We really need all these casts here .... :-(
+ expr = new BoxedCast (new EmptyCast (expr, expr_type));
+ return new EmptyCast (expr, target_type);
+ } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
+ target_type.IsSubclassOf (TypeManager.enum_type))
+ return new UnboxCast (expr, target_type);
+
+ //
+ // Notice that we have kept the expr_type unmodified, which is only
+ // used later on to
+ if (expr is EnumConstant)
+ expr = ((EnumConstant) expr).Child;
+ else
+ expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
+ expr_type = expr.Type;
+ }
+
+ Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
+
+ if (ne != null)
+ return ne;
+
+ ne = ExplicitNumericConversion (ec, expr, target_type, loc);
+ if (ne != null)
+ return ne;
+
+ //
+ // Unboxing conversion.
+ //
+ if (expr_type == TypeManager.object_type && target_type.IsValueType){
+ if (expr is NullLiteral){
+ Report.Error (37, "Cannot convert null to value type `" +
+ TypeManager.CSharpName (expr_type) + "'");
+ return null;
+ }
+ return new UnboxCast (expr, target_type);
+ }
+
+
+ ne = ExplicitReferenceConversion (expr, target_type);
+ if (ne != null)
+ return ne;
+
+ if (ec.InUnsafe){
+ if (target_type.IsPointer){
+ if (expr_type.IsPointer)
+ return new EmptyCast (expr, target_type);
+
+ if (expr_type == TypeManager.sbyte_type ||
+ expr_type == TypeManager.byte_type ||
+ expr_type == TypeManager.short_type ||
+ expr_type == TypeManager.ushort_type ||
+ expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.uint32_type ||
+ expr_type == TypeManager.uint64_type ||
+ expr_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
+ }
+ if (expr_type.IsPointer){
+ Expression e = null;
+
+ if (target_type == TypeManager.sbyte_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
+ else if (target_type == TypeManager.byte_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
+ else if (target_type == TypeManager.short_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
+ else if (target_type == TypeManager.ushort_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
+ else if (target_type == TypeManager.int32_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
+ else if (target_type == TypeManager.uint32_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
+ else if (target_type == TypeManager.uint64_type)
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ else if (target_type == TypeManager.int64_type){
+ e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ }
+
+ if (e != null){
+ Expression ci, ce;
+
+ ci = ImplicitConversionStandard (ec, e, target_type, loc);
+
+ if (ci != null)
+ return ci;
+
+ ce = ExplicitNumericConversion (ec, e, target_type, loc);
+ if (ce != null)
+ return ce;
+ //
+ // We should always be able to go from an uint32
+ // implicitly or explicitly to the other integral
+ // types
+ //
+ throw new Exception ("Internal compiler error");
+ }
+ }
+ }
+
+ ne = ExplicitUserConversion (ec, expr, target_type, loc);
+ if (ne != null)
+ return ne;
+
+ Error_CannotConvertType (loc, original_expr_type, target_type);
+ 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)
+ {
+ Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
+
+ if (ne != null)
+ return ne;
+
+ ne = ExplicitNumericConversion (ec, expr, target_type, l);
+ if (ne != null)
+ return ne;
+
+ ne = ExplicitReferenceConversion (expr, target_type);
+ if (ne != null)
+ return ne;
+
+ Error_CannotConvertType (l, expr.Type, target_type);
+ 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)
+//
+// 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;
+ using Mono.Languages;
+
+ /// <summary>
+ /// The C# Parser
+ /// </summary>
+ public class CSharpParser : GenericParser {
+ NamespaceEntry current_namespace;
+ TypeContainer current_container;
+
+ IIteratorContainer iterator_container;
+
+ // <summary>
+ // Current block is used to add statements as we find
+ // them.
+ // </summary>
+
+ Block current_block;
+
+ // <summary>
+ // Current interface is used by the various declaration
+ // productions in the interface declaration to "add"
+ // the interfaces as we find them.
+ // </summary>
+ Interface current_interface;
+
+ // <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>
+ // Used to determine if we are parsing the get/set pair
+ // of an indexer or a property
+ // </summmary>
+ bool parsing_indexer;
+
+ //
+ // An out-of-band stack.
+ //
+ Stack oob_stack;
+
+ //
+ // Switch stack.
+ //
+ Stack switch_stack;
+
+ //
+ // The current file.
+ //
+ SourceFile file;
+%}
+
+%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 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
+
+/* v2 tokens */
+%token YIELD
+
+/* C# keywords which are not really keywords */
+%token GET "get"
+%token SET "set"
+
+/* 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 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
+
+/* 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 attribute_sections opt_EOF
+ | attribute_sections opt_EOF
+ | opt_EOF /* allow empty files */
+ ;
+
+opt_EOF
+ : /* empty */
+ | EOF
+ ;
+
+outer_declarations
+ : outer_declaration
+ | outer_declarations outer_declaration
+ ;
+
+outer_declaration
+ : using_directive
+ | namespace_member_declaration
+ ;
+
+using_directives
+ : using_directive
+ | using_directives using_directive
+ ;
+
+using_directive
+ : using_alias_directive
+ | using_namespace_directive
+ ;
+
+using_alias_directive
+ : USING IDENTIFIER ASSIGN
+ namespace_or_type_name SEMICOLON
+ {
+ current_namespace.UsingAlias ((string) $2, (string) $4, lexer.Location);
+ }
+ ;
+
+using_namespace_directive
+ : USING namespace_name SEMICOLON
+ {
+ current_namespace.Using ((string) $2, lexer.Location);
+ }
+ ;
+
+//
+// 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 qualified_identifier
+ {
+ Attributes attrs = (Attributes) $1;
+
+ if (attrs != null) {
+ foreach (AttributeSection asec in attrs.AttributeSections)
+ if (asec.Target == "assembly")
+ RootContext.AddGlobalAttributeSection (current_container, asec);
+ else
+ Report.Error(1518, Lexer.Location,
+ "Attributes cannot be applied to namespaces."
+ + " Expected class, delegate, enum, interface, or struct");
+ }
+
+ current_namespace = RootContext.Tree.RecordNamespace (current_namespace, file, (string) $3);
+ }
+ namespace_body opt_semicolon
+ {
+ current_namespace = current_namespace.Parent;
+ }
+ ;
+
+opt_semicolon
+ : /* empty */
+ | SEMICOLON
+ ;
+
+opt_comma
+ : /* empty */
+ | COMMA
+ ;
+
+qualified_identifier
+ : IDENTIFIER
+ | qualified_identifier DOT IDENTIFIER {
+ $$ = (($1).ToString ()) + "." + ($3.ToString ()); }
+ ;
+
+
+namespace_name
+ : namespace_or_type_name
+ ;
+
+namespace_body
+ : OPEN_BRACE
+ opt_using_directives
+ opt_namespace_member_declarations
+ CLOSE_BRACE
+ {
+ }
+ ;
+
+opt_using_directives
+ : /* empty */
+ | using_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
+ {
+ string name = "";
+ int mod_flags;
+
+ if ($1 is Class){
+ Class c = (Class) $1;
+ mod_flags = c.ModFlags;
+ name = c.Name;
+ } else if ($1 is Struct){
+ Struct s = (Struct) $1;
+ mod_flags = s.ModFlags;
+ name = s.Name;
+ } else
+ break;
+
+ if ((mod_flags & (Modifiers.PRIVATE|Modifiers.PROTECTED)) != 0){
+ Report.Error (
+ 1527, lexer.Location,
+ "Namespace elements cant be explicitly " +
+ "declared private or protected in `" + name + "'");
+ }
+ current_namespace.DeclarationFound = true;
+ }
+ | namespace_declaration {
+ current_namespace.DeclarationFound = true;
+ }
+ ;
+
+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 {
+// Report.Error (1518, lexer.Location, "Expected class, struct, interface, enum or delegate");
+// }
+ ;
+
+//
+// Attributes 17.2
+//
+
+opt_attributes
+ : /* empty */
+ | attribute_sections { $$ = $1; }
+ ;
+
+attribute_sections
+ : attribute_section
+ {
+ AttributeSection sect = (AttributeSection) $1;
+
+ if (sect.Target == "assembly")
+ RootContext.AddGlobalAttributeSection (current_container, sect);
+
+
+ $$ = new Attributes ((AttributeSection) $1);
+ }
+ | attribute_sections attribute_section
+ {
+ Attributes attrs = null;
+ AttributeSection sect = (AttributeSection) $2;
+
+ if (sect.Target == "assembly")
+ RootContext.AddGlobalAttributeSection (current_container, sect);
+
+ if ($1 != null) {
+ attrs = (Attributes) $1;
+ attrs.AddAttributeSection (sect);
+ }
+
+ $$ = attrs;
+ }
+ ;
+
+attribute_section
+ : OPEN_BRACKET attribute_target_specifier attribute_list opt_comma CLOSE_BRACKET
+ {
+ string target = null;
+
+ if ($2 != null)
+ target = (string) $2;
+
+ $$ = new AttributeSection (target, (ArrayList) $3);
+ }
+ | OPEN_BRACKET attribute_list opt_comma CLOSE_BRACKET
+ {
+ $$ = new AttributeSection (null, (ArrayList) $2);
+ }
+ ;
+
+attribute_target_specifier
+ : attribute_target COLON
+ {
+ $$ = $1;
+ }
+ ;
+
+attribute_target
+ : IDENTIFIER
+ {
+ CheckAttributeTarget ((string) $1);
+ $$ = $1;
+ }
+ | 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
+ {
+ $$ = lexer.Location;
+ }
+ opt_attribute_arguments
+ {
+ $$ = new Attribute ((string) $1, (ArrayList) $3, (Location) $2);
+ }
+ ;
+
+attribute_name
+ : 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 {
+ ArrayList args = new ArrayList (4);
+ args.Add ($1);
+
+ $$ = args;
+ }
+ }
+ | positional_argument_list COMMA named_argument_list
+ {
+ ArrayList args = new ArrayList (4);
+ args.Add ($1);
+ args.Add ($3);
+
+ $$ = args;
+ }
+ | named_argument_list
+ {
+ ArrayList args = new ArrayList (4);
+ args.Add (null);
+ args.Add ($1);
+
+ $$ = args;
+ }
+ ;
+
+
+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
+ : IDENTIFIER ASSIGN expression
+ {
+ $$ = new DictionaryEntry (
+ (string) $1,
+ 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
+ STRUCT IDENTIFIER
+ {
+ Struct new_struct;
+ string full_struct_name = MakeName ((string) $4);
+
+ new_struct = new Struct (current_container, full_struct_name, (int) $2,
+ (Attributes) $1, lexer.Location);
+ current_container = new_struct;
+ current_container.Namespace = current_namespace;
+ RootContext.Tree.RecordDecl (full_struct_name, new_struct);
+ }
+ opt_class_base
+ struct_body
+ opt_semicolon
+ {
+ Struct new_struct = (Struct) current_container;
+
+ if ($6 != null)
+ new_struct.Bases = (ArrayList) $6;
+
+ current_container = current_container.Parent;
+ CheckDef (current_container.AddStruct (new_struct), new_struct.Name, new_struct.Location);
+ $$ = new_struct;
+ }
+ ;
+
+struct_body
+ : OPEN_BRACE 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
+ {
+ foreach (VariableDeclaration constant in (ArrayList) $5){
+ Location l = constant.Location;
+
+ Const c = new Const (
+ (Expression) $4, (string) constant.identifier,
+ (Expression) constant.expression_or_array_initializer, (int) $2,
+ (Attributes) $1, l);
+
+ CheckDef (current_container.AddConstant (c), c.Name, l);
+ }
+ }
+ ;
+
+constant_declarators
+ : constant_declarator
+ {
+ ArrayList constants = new ArrayList (4);
+ constants.Add ($1);
+ $$ = constants;
+ }
+ | constant_declarators COMMA constant_declarator
+ {
+ ArrayList constants = (ArrayList) $1;
+
+ constants.Add ($3);
+ }
+ ;
+
+constant_declarator
+ : IDENTIFIER ASSIGN constant_expression
+ {
+ $$ = new VariableDeclaration ((string) $1, $3, lexer.Location);
+ }
+ ;
+
+field_declaration
+ : opt_attributes
+ opt_modifiers
+ type
+ variable_declarators
+ SEMICOLON
+ {
+ Expression type = (Expression) $3;
+ int mod = (int) $2;
+
+ foreach (VariableDeclaration var in (ArrayList) $4){
+ Location l = var.Location;
+
+ Field field = new Field (type, mod, var.identifier,
+ var.expression_or_array_initializer,
+ (Attributes) $1, l);
+
+ CheckDef (current_container.AddField (field), field.Name, l);
+ }
+ }
+ | opt_attributes
+ opt_modifiers
+ VOID
+ variable_declarators
+ SEMICOLON {
+ Report.Error (670, lexer.Location, "void type is not allowed for fields");
+ }
+ ;
+
+variable_declarators
+ : variable_declarator
+ {
+ ArrayList decl = new ArrayList (4);
+ 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 ((string) $1, $3, lexer.Location);
+ }
+ | IDENTIFIER
+ {
+ $$ = new VariableDeclaration ((string) $1, null, lexer.Location);
+ }
+ ;
+
+variable_initializer
+ : expression
+ {
+ $$ = $1;
+ }
+ | array_initializer
+ {
+ $$ = $1;
+ }
+ | STACKALLOC type OPEN_BRACKET expression CLOSE_BRACKET
+ {
+ $$ = new StackAlloc ((Expression) $2, (Expression) $4, lexer.Location);
+ }
+ ;
+
+method_declaration
+ : method_header {
+ iterator_container = (IIteratorContainer) $1;
+ }
+ method_body
+ {
+ Method method = (Method) $1;
+ Block b = (Block) $3;
+ const int extern_abstract = (Modifiers.EXTERN | Modifiers.ABSTRACT);
+
+ if (b == null){
+ if ((method.ModFlags & extern_abstract) == 0){
+ Report.Error (
+ 501, lexer.Location, current_container.MakeName (method.Name) +
+ "must declare a body because it is not marked abstract or extern");
+ }
+ } else {
+ if ((method.ModFlags & Modifiers.EXTERN) != 0){
+ Report.Error (
+ 179, lexer.Location, current_container.MakeName (method.Name) +
+ " is declared extern, but has a body");
+ }
+ }
+
+ method.Block = (Block) $3;
+ CheckDef (current_container.AddMethod (method), method.Name, method.Location);
+
+ current_local_parameters = null;
+ iterator_container = null;
+ }
+ ;
+
+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 `" +
+ Modifiers.Name (i) + "' must precede member type and name");
+ }
+ m &= ~i;
+ i = i << 1;
+ }
+ }
+ ;
+
+method_header
+ : opt_attributes
+ opt_modifiers
+ type
+ member_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ Method method = new Method ((Expression) $3, (int) $2, (string) $4,
+ (Parameters) $6, (Attributes) $1, lexer.Location);
+
+ current_local_parameters = (Parameters) $6;
+
+ $$ = method;
+ }
+ | opt_attributes
+ opt_modifiers
+ VOID
+ member_name
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ Method method = new Method (TypeManager.system_void_expr, (int) $2, (string) $4,
+ (Parameters) $6, (Attributes) $1, lexer.Location);
+
+ current_local_parameters = (Parameters) $6;
+ $$ = method;
+ }
+ ;
+
+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, null, lexer.Location);
+ }
+ | fixed_parameters COMMA parameter_array
+ {
+ ArrayList pars_list = (ArrayList) $1;
+
+ Parameter [] pars = new Parameter [pars_list.Count];
+ pars_list.CopyTo (pars);
+
+ $$ = new Parameters (pars, (Parameter) $3, lexer.Location);
+ }
+ | parameter_array
+ {
+ $$ = new Parameters (null, (Parameter) $1, lexer.Location);
+ }
+ ;
+
+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
+ {
+ $$ = new Parameter ((Expression) $3, (string) $4, (Parameter.Modifier) $2, (Attributes) $1);
+ }
+ ;
+
+opt_parameter_modifier
+ : /* empty */ { $$ = Parameter.Modifier.NONE; }
+ | parameter_modifier
+ ;
+
+parameter_modifier
+ : REF { $$ = Parameter.Modifier.REF | Parameter.Modifier.ISBYREF; }
+ | OUT { $$ = Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF; }
+ ;
+
+parameter_array
+ : opt_attributes PARAMS type IDENTIFIER
+ {
+ $$ = new Parameter ((Expression) $3, (string) $4, Parameter.Modifier.PARAMS, (Attributes) $1);
+ note ("type must be a single-dimension array type");
+ }
+ ;
+
+member_name
+ : qualified_identifier
+ ;
+
+property_declaration
+ : opt_attributes
+ opt_modifiers
+ type member_name
+ OPEN_BRACE
+ {
+ implicit_value_parameter_type = (Expression) $3;
+
+ lexer.PropertyParsing = true;
+
+ $$ = lexer.Location;
+ }
+ accessor_declarations
+ {
+ lexer.PropertyParsing = false;
+ }
+ CLOSE_BRACE
+ {
+ Property prop;
+ Pair pair = (Pair) $7;
+ Accessor get_block = (Accessor) pair.First;
+ Accessor set_block = (Accessor) pair.Second;
+
+ Location loc = (Location) $6;
+ prop = new Property ((Expression) $3, (string) $4, (int) $2, get_block, set_block,
+ (Attributes) $1, loc);
+
+ CheckDef (current_container.AddProperty (prop), prop.Name, loc);
+ implicit_value_parameter_type = null;
+ }
+ ;
+
+accessor_declarations
+ : get_accessor_declaration opt_set_accessor_declaration
+ {
+ $$ = new Pair ($1, $2);
+ }
+ | set_accessor_declaration opt_get_accessor_declaration
+ {
+ $$ = new Pair ($2, $1);
+ }
+ ;
+
+opt_get_accessor_declaration
+ : /* empty */ { $$ = null; }
+ | get_accessor_declaration
+ ;
+
+opt_set_accessor_declaration
+ : /* empty */ { $$ = null; }
+ | set_accessor_declaration
+ ;
+
+get_accessor_declaration
+ : opt_attributes 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;
+ }
+ accessor_body
+ {
+ $$ = new Accessor ((Block) $4, (Attributes) $1);
+ current_local_parameters = null;
+ lexer.PropertyParsing = true;
+ }
+ ;
+
+set_accessor_declaration
+ : opt_attributes SET
+ {
+ Parameter [] args;
+ Parameter implicit_value_parameter = new Parameter (
+ implicit_value_parameter_type, "value",
+ Parameter.Modifier.NONE, null);
+
+ if (parsing_indexer == false) {
+ args = new Parameter [1];
+ args [0] = implicit_value_parameter;
+ current_local_parameters = new Parameters (args, null, lexer.Location);
+ } 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, indexer_parameters.ArrayParameter, lexer.Location);
+ }
+
+ lexer.PropertyParsing = false;
+ }
+ accessor_body
+ {
+ $$ = new Accessor ((Block) $4, (Attributes) $1);
+ current_local_parameters = null;
+ lexer.PropertyParsing = true;
+ }
+ ;
+
+accessor_body
+ : block
+ | SEMICOLON { $$ = null; }
+ ;
+
+interface_declaration
+ : opt_attributes
+ opt_modifiers
+ INTERFACE IDENTIFIER
+ {
+ Interface new_interface;
+ string full_interface_name = MakeName ((string) $4);
+
+ new_interface = new Interface (current_container, full_interface_name, (int) $2,
+ (Attributes) $1, lexer.Location);
+ if (current_interface != null) {
+ Location l = lexer.Location;
+ Report.Error (-2, l, "Internal compiler error: interface inside interface");
+ }
+ current_interface = new_interface;
+ new_interface.Namespace = current_namespace;
+ RootContext.Tree.RecordDecl (full_interface_name, new_interface);
+ }
+ opt_interface_base
+ interface_body opt_semicolon
+ {
+ Interface new_interface = (Interface) current_interface;
+
+ if ($6 != null)
+ new_interface.Bases = (ArrayList) $6;
+
+ current_interface = null;
+ CheckDef (current_container.AddInterface (new_interface),
+ new_interface.Name, new_interface.Location);
+ }
+ ;
+
+opt_interface_base
+ : /* empty */ { $$ = null; }
+ | interface_base
+ ;
+
+interface_base
+ : COLON interface_type_list { $$ = $2; }
+ ;
+
+interface_type_list
+ : interface_type
+ {
+ ArrayList interfaces = new ArrayList (4);
+
+ interfaces.Add ($1);
+ $$ = interfaces;
+ }
+ | interface_type_list COMMA interface_type
+ {
+ ArrayList interfaces = (ArrayList) $1;
+ interfaces.Add ($3);
+ $$ = interfaces;
+ }
+ ;
+
+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
+ {
+ InterfaceMethod m = (InterfaceMethod) $1;
+
+ CheckDef (current_interface.AddMethod (m), m.Name, m.Location);
+ }
+ | interface_property_declaration
+ {
+ InterfaceProperty p = (InterfaceProperty) $1;
+
+ CheckDef (current_interface.AddProperty (p), p.Name, p.Location);
+ }
+ | interface_event_declaration
+ {
+ InterfaceEvent e = (InterfaceEvent) $1;
+
+ CheckDef (current_interface.AddEvent (e), e.Name, lexer.Location);
+ }
+ | interface_indexer_declaration
+ {
+ InterfaceIndexer i = (InterfaceIndexer) $1;
+
+ CheckDef (current_interface.AddIndexer (i), "indexer", i.Location);
+ }
+ ;
+
+opt_new
+ : /* empty */ { $$ = false; }
+ | NEW { $$ = true; }
+ ;
+
+interface_method_declaration
+ : opt_attributes opt_new type IDENTIFIER
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ SEMICOLON
+ {
+ $$ = new InterfaceMethod ((Expression) $3, (string) $4, (bool) $2,
+ (Parameters) $6, (Attributes) $1, lexer.Location);
+ }
+ | opt_attributes opt_new VOID IDENTIFIER
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ SEMICOLON
+ {
+ $$ = new InterfaceMethod (
+ TypeManager.system_void_expr, (string) $4, (bool) $2, (Parameters) $6,
+ (Attributes) $1, lexer.Location);
+ }
+ ;
+
+interface_property_declaration
+ : opt_attributes
+ opt_new
+ type IDENTIFIER
+ OPEN_BRACE
+ { lexer.PropertyParsing = true; }
+ interface_accesors
+ { lexer.PropertyParsing = false; }
+ CLOSE_BRACE
+ {
+ int gs = (int) $7;
+
+ $$ = new InterfaceProperty ((Expression) $3, (string) $4, (bool) $2,
+ (gs & 1) == 1, (gs & 2) == 2, (Attributes) $1,
+ lexer.Location);
+ }
+ ;
+
+interface_accesors
+ : opt_attributes GET SEMICOLON { $$ = 1; }
+ | opt_attributes SET SEMICOLON { $$ = 2; }
+ | opt_attributes GET SEMICOLON opt_attributes SET SEMICOLON
+ { $$ = 3; }
+ | opt_attributes SET SEMICOLON opt_attributes GET SEMICOLON
+ { $$ = 3; }
+ ;
+
+interface_event_declaration
+ : opt_attributes opt_new EVENT type IDENTIFIER SEMICOLON
+ {
+ $$ = new InterfaceEvent ((Expression) $4, (string) $5, (bool) $2, (Attributes) $1,
+ lexer.Location);
+ }
+ ;
+
+interface_indexer_declaration
+ : opt_attributes opt_new type THIS
+ OPEN_BRACKET formal_parameter_list CLOSE_BRACKET
+ OPEN_BRACE
+ { lexer.PropertyParsing = true; }
+ interface_accesors
+ { lexer.PropertyParsing = false; }
+ CLOSE_BRACE
+ {
+ int a_flags = (int) $10;
+
+ bool do_get = (a_flags & 1) == 1;
+ bool do_set = (a_flags & 2) == 2;
+
+ $$ = new InterfaceIndexer ((Expression) $3, (Parameters) $6, do_get, do_set,
+ (bool) $2, (Attributes) $1, lexer.Location);
+ }
+ ;
+
+operator_declaration
+ : opt_attributes opt_modifiers operator_declarator operator_body
+ {
+ OperatorDeclaration decl = (OperatorDeclaration) $3;
+
+ Operator op = new Operator (decl.optype, decl.ret_type, (int) $2, decl.arg1type, decl.arg1name,
+ decl.arg2type, decl.arg2name, (Block) $4, (Attributes) $1, decl.location);
+
+ // 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
+ {
+ Operator.OpType op = (Operator.OpType) $3;
+ CheckUnaryOperator (op);
+
+ if (op == Operator.OpType.Addition)
+ op = Operator.OpType.UnaryPlus;
+
+ if (op == Operator.OpType.Subtraction)
+ op = Operator.OpType.UnaryNegation;
+
+ Parameter [] pars = new Parameter [1];
+
+ pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
+
+ current_local_parameters = new Parameters (pars, null, lexer.Location);
+
+ $$ = new OperatorDeclaration (op, (Expression) $1, (Expression) $5, (string) $6,
+ null, null, lexer.Location);
+ }
+ | type OPERATOR overloadable_operator
+ OPEN_PARENS
+ type IDENTIFIER COMMA
+ type IDENTIFIER
+ CLOSE_PARENS
+ {
+ CheckBinaryOperator ((Operator.OpType) $3);
+
+ Parameter [] pars = new Parameter [2];
+
+ pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
+ pars [1] = new Parameter ((Expression) $8, (string) $9, Parameter.Modifier.NONE, null);
+
+ current_local_parameters = new Parameters (pars, null, lexer.Location);
+
+ $$ = new OperatorDeclaration ((Operator.OpType) $3, (Expression) $1,
+ (Expression) $5, (string) $6,
+ (Expression) $8, (string) $9, lexer.Location);
+ }
+ | conversion_operator_declarator
+ ;
+
+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
+ {
+ Parameter [] pars = new Parameter [1];
+
+ pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
+
+ current_local_parameters = new Parameters (pars, null, lexer.Location);
+
+ $$ = new OperatorDeclaration (Operator.OpType.Implicit, (Expression) $3, (Expression) $5, (string) $6,
+ null, null, lexer.Location);
+ }
+ | EXPLICIT OPERATOR type OPEN_PARENS type IDENTIFIER CLOSE_PARENS
+ {
+ Parameter [] pars = new Parameter [1];
+
+ pars [0] = new Parameter ((Expression) $5, (string) $6, Parameter.Modifier.NONE, null);
+
+ current_local_parameters = new Parameters (pars, null, lexer.Location);
+
+ $$ = new OperatorDeclaration (Operator.OpType.Explicit, (Expression) $3, (Expression) $5, (string) $6,
+ null, null, lexer.Location);
+ }
+ | IMPLICIT error
+ {
+ syntax_error (lexer.Location, "'operator' expected");
+ }
+ | EXPLICIT error
+ {
+ syntax_error (lexer.Location, "'operator' expected");
+ }
+ ;
+
+constructor_declaration
+ : opt_attributes
+ opt_modifiers
+ constructor_declarator
+ constructor_body
+ {
+ Constructor c = (Constructor) $3;
+ c.Block = (Block) $4;
+ c.OptAttributes = (Attributes) $1;
+ c.ModFlags = (int) $2;
+
+ if (c.Name == current_container.Basename){
+ if ((c.ModFlags & Modifiers.STATIC) != 0){
+ if ((c.ModFlags & Modifiers.Accessibility) != 0){
+ Report.Error (
+ 515, c.Location, String.Format (
+ "`{0}.{1}': static constructor can not have access modifiers",
+ c.Name, current_container.Name));
+ }
+
+ c.ModFlags = Modifiers.Check (Constructor.AllowedModifiers, (int) $2, Modifiers.PRIVATE, c.Location);
+
+ if (c.Initializer != null){
+ Report.Error (
+ 514, c.Location,
+ "Static constructors can not have an explicit this or base " +
+ "constructor invocations");
+ }
+
+ if (!c.Parameters.Empty){
+ Report.Error (
+ 132, c.Location, "Static constructors should not have parameters");
+ }
+ } 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);
+ }
+
+ CheckDef (current_container.AddConstructor (c), c.Name, c.Location);
+
+ current_local_parameters = null;
+ }
+ ;
+
+constructor_declarator
+ : IDENTIFIER
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ oob_stack.Push (lexer.Location);
+
+ current_local_parameters = (Parameters) $3;
+ }
+ opt_constructor_initializer
+ {
+ Location l = (Location) oob_stack.Pop ();
+ $$ = new Constructor ((string) $1, (Parameters) $3, (ConstructorInitializer) $6, l);
+ }
+ ;
+
+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, current_local_parameters, lexer.Location);
+ }
+ | COLON THIS OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ $$ = new ConstructorThisInitializer ((ArrayList) $4, current_local_parameters, lexer.Location);
+ }
+ | COLON error {
+ Report.Error (1018, lexer.Location, "Keyword this or base expected");
+ $$ = null;
+ }
+ ;
+
+opt_finalizer
+ : /* EMPTY */ { $$ = 0; }
+ | UNSAFE { $$ = Modifiers.UNSAFE; }
+ | EXTERN { $$ = Modifiers.EXTERN; }
+ ;
+
+destructor_declaration
+ : opt_attributes opt_finalizer TILDE IDENTIFIER OPEN_PARENS CLOSE_PARENS block
+ {
+ if ((string) $4 != current_container.Basename){
+ Report.Error (574, lexer.Location, "Name of destructor must match name of class");
+ } else if (!(current_container is Class)){
+ Report.Error (575, lexer.Location, "Destructors are only allowed in class types");
+ } else {
+ Location l = lexer.Location;
+
+ int m = (int) $2;
+ if (!RootContext.StdLib && current_container.Name == "System.Object")
+ m |= Modifiers.PROTECTED | Modifiers.VIRTUAL;
+ else
+ m |= Modifiers.PROTECTED | Modifiers.OVERRIDE;
+
+ if ((m & Modifiers.UNSAFE) != 0){
+ if (!RootContext.Unsafe){
+ Report.Error (227, l,
+ "Unsafe code requires the --unsafe command " +
+ "line option to be specified");
+ }
+ }
+
+ Method d = new Method (
+ TypeManager.system_void_expr, m, "Finalize",
+ new Parameters (null, null, l), (Attributes) $1, l);
+
+ d.Block = (Block) $7;
+ CheckDef (current_container.AddMethod (d), d.Name, d.Location);
+ }
+ }
+ ;
+
+event_declaration
+ : opt_attributes
+ opt_modifiers
+ EVENT type variable_declarators SEMICOLON
+ {
+ foreach (VariableDeclaration var in (ArrayList) $5) {
+
+ Event e = new Event ((Expression) $4, var.identifier,
+ var.expression_or_array_initializer,
+ (int) $2, null, null, (Attributes) $1, lexer.Location);
+
+ CheckDef (current_container.AddEvent (e), e.Name, e.Location);
+
+ }
+ }
+ | opt_attributes
+ opt_modifiers
+ EVENT type member_name
+ OPEN_BRACE
+ {
+ implicit_value_parameter_type = (Expression) $4;
+ lexer.EventParsing = true;
+ oob_stack.Push (lexer.Location);
+ }
+ event_accessor_declarations
+ {
+ lexer.EventParsing = false;
+ }
+ CLOSE_BRACE
+ {
+ Location loc = (Location) oob_stack.Pop ();
+
+ Pair pair = (Pair) $8;
+ Accessor add_accessor = null;
+ Accessor rem_accessor = null;
+
+ if (pair.First != null)
+ add_accessor = (Accessor) pair.First;
+ if (pair.Second != null)
+ rem_accessor = (Accessor) pair.Second;
+
+ Event e = new Event ((Expression) $4, (string) $5, null, (int) $2, add_accessor, rem_accessor,
+ (Attributes) $1, loc);
+
+ CheckDef (current_container.AddEvent (e), e.Name, loc);
+ implicit_value_parameter_type = null;
+ }
+ ;
+
+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
+ : opt_attributes ADD
+ {
+ Parameter [] args = new Parameter [1];
+ Parameter implicit_value_parameter = new Parameter (
+ implicit_value_parameter_type, "value",
+ Parameter.Modifier.NONE, null);
+
+ args [0] = implicit_value_parameter;
+
+ current_local_parameters = new Parameters (args, null, lexer.Location);
+ lexer.EventParsing = false;
+ }
+ block
+ {
+ $$ = new Accessor ((Block) $4, (Attributes) $1);
+ lexer.EventParsing = true;
+ }
+ | opt_attributes ADD error {
+ Report.Error (73, lexer.Location, "Add or remove accessor must have a body");
+ $$ = 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);
+
+ args [0] = implicit_value_parameter;
+
+ current_local_parameters = new Parameters (args, null, lexer.Location);
+ lexer.EventParsing = false;
+ }
+ block
+ {
+ $$ = new Accessor ((Block) $4, (Attributes) $1);
+ lexer.EventParsing = true;
+ }
+ | opt_attributes REMOVE error {
+ Report.Error (73, lexer.Location, "Add or remove accessor must have a body");
+ $$ = 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;
+ oob_stack.Push (lexer.Location);
+ }
+ accessor_declarations
+ {
+ lexer.PropertyParsing = false;
+ parsing_indexer = false;
+ }
+ CLOSE_BRACE
+ {
+ // The signature is computed from the signature of the indexer. Look
+ // at section 3.6 on the spec
+ Location loc = (Location) oob_stack.Pop ();
+ Indexer indexer;
+ IndexerDeclaration decl = (IndexerDeclaration) $3;
+ Pair pair = (Pair) $6;
+ Accessor get_block = (Accessor) pair.First;
+ Accessor set_block = (Accessor) pair.Second;
+
+ indexer = new Indexer (decl.type, decl.interface_type, (int) $2, decl.param_list,
+ get_block, set_block, (Attributes) $1, loc);
+
+ // Note that there is no equivalent of CheckDef for this case
+ // We shall handle this in semantic analysis
+
+ 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.FixedParameters == null && pars.ArrayParameter == null){
+ Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
+ }
+
+ $$ = new IndexerDeclaration ((Expression) $1, null, pars);
+ }
+ | type qualified_identifier DOT THIS OPEN_BRACKET opt_formal_parameter_list CLOSE_BRACKET
+ {
+ Parameters pars = (Parameters) $6;
+
+ if (pars.FixedParameters == null && pars.ArrayParameter == null){
+ Report.Error (1551, lexer.Location, "Indexers must have at least one parameter");
+ }
+ $$ = new IndexerDeclaration ((Expression) $1, (string) $2, pars);
+ }
+ ;
+
+enum_declaration
+ : opt_attributes
+ opt_modifiers
+ ENUM IDENTIFIER
+ opt_enum_base
+ enum_body
+ opt_semicolon
+ {
+ Location enum_location = lexer.Location;
+
+ string full_name = MakeName ((string) $4);
+ Enum e = new Enum (current_container, (Expression) $5, (int) $2, full_name,
+ (Attributes) $1, enum_location);
+
+ foreach (VariableDeclaration ev in (ArrayList) $6) {
+ Location loc = (Location) ev.Location;
+
+ CheckDef (e.AddEnumMember (ev.identifier,
+ (Expression) ev.expression_or_array_initializer,
+ loc, ev.OptAttributes),
+ ev.identifier, loc);
+ }
+
+ e.Namespace = current_namespace;
+
+ CheckDef (current_container.AddEnum (e), full_name, enum_location);
+ RootContext.Tree.RecordDecl (full_name, e);
+
+ }
+ ;
+
+opt_enum_base
+ : /* empty */ { $$ = TypeManager.system_int32_expr; }
+ | COLON type { $$ = $2; }
+ ;
+
+enum_body
+ : OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE
+ {
+ $$ = $2;
+ }
+ ;
+
+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
+ {
+ $$ = new VariableDeclaration ((string) $2, null, lexer.Location, (Attributes) $1);
+ }
+ | opt_attributes IDENTIFIER
+ {
+ $$ = lexer.Location;
+ }
+ ASSIGN expression
+ {
+ $$ = new VariableDeclaration ((string) $2, $5, lexer.Location, (Attributes) $1);
+ }
+ ;
+
+delegate_declaration
+ : opt_attributes
+ opt_modifiers
+ DELEGATE type
+ IDENTIFIER OPEN_PARENS
+ opt_formal_parameter_list
+ CLOSE_PARENS
+ SEMICOLON
+ {
+ Location l = lexer.Location;
+ Delegate del = new Delegate (current_container, (Expression) $4, (int) $2,
+ MakeName ((string) $5), (Parameters) $7,
+ (Attributes) $1, l);
+
+ del.Namespace = current_namespace;
+ CheckDef (current_container.AddDelegate (del), del.Name, l);
+ }
+ | opt_attributes
+ opt_modifiers
+ DELEGATE VOID
+ IDENTIFIER OPEN_PARENS
+ opt_formal_parameter_list
+ CLOSE_PARENS
+ SEMICOLON
+ {
+ Location l = lexer.Location;
+ Delegate del = new Delegate (
+ current_container,
+ TypeManager.system_void_expr, (int) $2, MakeName ((string) $5),
+ (Parameters) $7, (Attributes) $1, l);
+
+ del.Namespace = current_namespace;
+ CheckDef (current_container.AddDelegate (del), del.Name, l);
+ }
+ ;
+
+type_name
+ : namespace_or_type_name
+ ;
+
+namespace_or_type_name
+ : qualified_identifier
+ ;
+
+/*
+ * 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
+ : type_name { /* class_type */
+ /*
+ This does interfaces, delegates, struct_types, class_types,
+ parent classes, and more! 4.2
+ */
+ $$ = DecomposeQI ((string) $1, lexer.Location);
+ }
+ | 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, "*", lexer.Location);
+ }
+ ;
+
+non_expression_type
+ : builtin_types
+ | non_expression_type rank_specifier
+ {
+ $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
+ }
+ | non_expression_type STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
+ }
+ | expression rank_specifiers
+ {
+ $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
+ }
+ | expression STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
+ }
+
+ //
+ // We need this because the parser will happily go and reduce IDENTIFIER STAR
+ // through this different path
+ //
+ | multiplicative_expression STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
+ }
+ ;
+
+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; }
+ ;
+
+interface_type
+ : type_name
+ ;
+
+array_type
+ : type rank_specifiers
+ {
+ $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
+ }
+ ;
+
+//
+// Expressions, section 7.5
+//
+primary_expression
+ : literal
+ {
+ // 7.5.1: Literals
+ }
+
+ | qualified_identifier
+ {
+ string name = (string) $1;
+
+ $$ = null;
+ $$ = DecomposeQI (name, lexer.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); }
+ | LITERAL_STRING { $$ = new StringLiteral ((string) lexer.Value); }
+ | NULL { $$ = NullLiteral.Null; }
+ ;
+
+real_literal
+ : LITERAL_FLOAT { $$ = new FloatLiteral ((float) lexer.Value); }
+ | LITERAL_DOUBLE { $$ = new DoubleLiteral ((double) lexer.Value); }
+ | LITERAL_DECIMAL { $$ = new DecimalLiteral ((decimal) lexer.Value); }
+ ;
+
+integer_literal
+ : LITERAL_INTEGER {
+ object v = lexer.Value;
+
+ if (v is int)
+ $$ = new IntLiteral ((Int32) v);
+ else if (v is uint)
+ $$ = new UIntLiteral ((UInt32) v);
+ else if (v is long)
+ $$ = new LongLiteral ((Int64) v);
+ else if (v is ulong)
+ $$ = new ULongLiteral ((UInt64) v);
+ else
+ Console.WriteLine ("OOPS. Unexpected result from scanner");
+ }
+ ;
+
+boolean_literal
+ : TRUE { $$ = new BoolLiteral (true); }
+ | FALSE { $$ = new BoolLiteral (false); }
+ ;
+
+parenthesized_expression
+ : OPEN_PARENS expression CLOSE_PARENS
+ { $$ = $2; }
+ ;
+
+member_access
+ : primary_expression DOT IDENTIFIER
+ {
+ $$ = new MemberAccess ((Expression) $1, (string) $3, lexer.Location);
+ }
+ | predefined_type DOT IDENTIFIER
+ {
+ $$ = new MemberAccess ((Expression) $1, (string) $3, lexer.Location);
+ }
+ ;
+
+predefined_type
+ : builtin_types
+ ;
+
+invocation_expression
+ : primary_expression OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ if ($1 == null) {
+ Location l = lexer.Location;
+ Report.Error (1, l, "Parse error");
+ }
+ $$ = new Invocation ((Expression) $1, (ArrayList) $3, lexer.Location);
+ }
+ | OPEN_PARENS expression CLOSE_PARENS unary_expression
+ {
+ $$ = new InvocationOrCast ((Expression) $2, (Expression) $4, lexer.Location);
+ }
+ ;
+
+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
+ : expression
+ {
+ $$ = new Argument ((Expression) $1, Argument.AType.Expression);
+ }
+ | REF variable_reference
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Ref);
+ }
+ | OUT variable_reference
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Out);
+ }
+ ;
+
+variable_reference
+ : expression { note ("section 5.4"); $$ = $1; }
+ ;
+
+element_access
+ : primary_expression OPEN_BRACKET expression_list CLOSE_BRACKET
+ {
+ $$ = new ElementAccess ((Expression) $1, (ArrayList) $3, lexer.Location);
+ }
+ | 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, lexer.Location);
+ } else if (!(expr is SimpleName || expr is MemberAccess)){
+ Error_ExpectingTypeName (lexer.Location, expr);
+ $$ = TypeManager.system_object_expr;
+ } else {
+ //
+ // So we extract the string corresponding to the SimpleName
+ // or MemberAccess
+ //
+ $$ = new ComposedCast (expr, (string) $2, lexer.Location);
+ }
+ }
+ ;
+
+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, lexer.Location);
+ }
+ ;
+
+base_access
+ : BASE DOT IDENTIFIER
+ {
+ $$ = new BaseAccess ((string) $3, lexer.Location);
+ }
+ | BASE OPEN_BRACKET expression_list CLOSE_BRACKET
+ {
+ $$ = new BaseIndexerAccess ((ArrayList) $3, lexer.Location);
+ }
+ ;
+
+post_increment_expression
+ : primary_expression OP_INC
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PostIncrement,
+ (Expression) $1, lexer.Location);
+ }
+ ;
+
+post_decrement_expression
+ : primary_expression OP_DEC
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PostDecrement,
+ (Expression) $1, lexer.Location);
+ }
+ ;
+
+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, lexer.Location);
+ }
+ ;
+
+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, lexer.Location);
+ }
+ | NEW type rank_specifiers array_initializer
+ {
+ $$ = new ArrayCreation ((Expression) $2, (string) $3, (ArrayList) $4, lexer.Location);
+ }
+ | NEW type error
+ {
+ Report.Error (1526, lexer.Location, "new expression requires () or [] after type");
+ }
+ ;
+
+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 OPEN_PARENS VOID CLOSE_PARENS
+ {
+ $$ = new TypeOfVoid (lexer.Location);
+ }
+ | TYPEOF OPEN_PARENS type CLOSE_PARENS
+ {
+ $$ = new TypeOf ((Expression) $3, lexer.Location);
+ }
+ ;
+
+sizeof_expression
+ : SIZEOF OPEN_PARENS type CLOSE_PARENS {
+ $$ = new SizeOf ((Expression) $3, lexer.Location);
+ }
+ ;
+
+checked_expression
+ : CHECKED OPEN_PARENS expression CLOSE_PARENS
+ {
+ $$ = new CheckedExpr ((Expression) $3, lexer.Location);
+ }
+ ;
+
+unchecked_expression
+ : UNCHECKED OPEN_PARENS expression CLOSE_PARENS
+ {
+ $$ = new UnCheckedExpr ((Expression) $3, lexer.Location);
+ }
+ ;
+
+pointer_member_access
+ : primary_expression OP_PTR IDENTIFIER
+ {
+ Expression deref;
+
+ deref = new Unary (Unary.Operator.Indirection, (Expression) $1, lexer.Location);
+ $$ = new MemberAccess (deref, (string) $3, lexer.Location);
+ }
+ ;
+
+anonymous_method_expression
+ : DELEGATE opt_anonymous_method_signature {
+ oob_stack.Push (current_local_parameters);
+ current_local_parameters = (Parameters)$2;
+ } block {
+ if (!RootContext.V2){
+ Report.Error (-213, lexer.Location, "Anonymous methods are only supported in V2");
+ $$ = null;
+ } else
+ $$ = new AnonymousMethod ((Parameters) $2, (Block) $3, lexer.Location);
+ current_local_parameters = (Parameters) oob_stack.Pop ();
+ }
+ ;
+
+opt_anonymous_method_signature
+ : /* empty */ { $$ = Parameters.EmptyReadOnlyParameters; }
+ | 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, null, lexer.Location);
+ }
+ }
+ ;
+
+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 {
+ $$ = new Parameter ((Expression) $2, (string) $2, (Parameter.Modifier) $1, null);
+ }
+ ;
+
+unary_expression
+ : primary_expression
+ | BANG prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.LogicalNot, (Expression) $2, lexer.Location);
+ }
+ | TILDE prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.OnesComplement, (Expression) $2, lexer.Location);
+ }
+ | cast_expression
+ ;
+
+cast_expression
+ : OPEN_PARENS non_expression_type CLOSE_PARENS prefixed_unary_expression
+ {
+ $$ = 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, lexer.Location);
+ }
+ | MINUS prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.UnaryNegation, (Expression) $2, lexer.Location);
+ }
+ | OP_INC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement,
+ (Expression) $2, lexer.Location);
+ }
+ | OP_DEC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement,
+ (Expression) $2, lexer.Location);
+ }
+ | STAR prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.Indirection, (Expression) $2, lexer.Location);
+ }
+ | BITWISE_AND prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.AddressOf, (Expression) $2, lexer.Location);
+ }
+ ;
+
+pre_increment_expression
+ : OP_INC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreIncrement,
+ (Expression) $2, lexer.Location);
+ }
+ ;
+
+pre_decrement_expression
+ : OP_DEC prefixed_unary_expression
+ {
+ $$ = new UnaryMutator (UnaryMutator.Mode.PreDecrement,
+ (Expression) $2, lexer.Location);
+ }
+ ;
+
+multiplicative_expression
+ : prefixed_unary_expression
+ | multiplicative_expression STAR prefixed_unary_expression
+ {
+ $$ = new Binary (Binary.Operator.Multiply,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | multiplicative_expression DIV prefixed_unary_expression
+ {
+ $$ = new Binary (Binary.Operator.Division,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | multiplicative_expression PERCENT prefixed_unary_expression
+ {
+ $$ = new Binary (Binary.Operator.Modulus,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression
+ | additive_expression PLUS multiplicative_expression
+ {
+ $$ = new Binary (Binary.Operator.Addition,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | additive_expression MINUS multiplicative_expression
+ {
+ $$ = new Binary (Binary.Operator.Subtraction,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+shift_expression
+ : additive_expression
+ | shift_expression OP_SHIFT_LEFT additive_expression
+ {
+ $$ = new Binary (Binary.Operator.LeftShift,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | shift_expression OP_SHIFT_RIGHT additive_expression
+ {
+ $$ = new Binary (Binary.Operator.RightShift,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+relational_expression
+ : shift_expression
+ | relational_expression OP_LT shift_expression
+ {
+ $$ = new Binary (Binary.Operator.LessThan,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression OP_GT shift_expression
+ {
+ $$ = new Binary (Binary.Operator.GreaterThan,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression OP_LE shift_expression
+ {
+ $$ = new Binary (Binary.Operator.LessThanOrEqual,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression OP_GE shift_expression
+ {
+ $$ = new Binary (Binary.Operator.GreaterThanOrEqual,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression IS type
+ {
+ $$ = new Is ((Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression AS type
+ {
+ $$ = new As ((Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+equality_expression
+ : relational_expression
+ | equality_expression OP_EQ relational_expression
+ {
+ $$ = new Binary (Binary.Operator.Equality,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | equality_expression OP_NE relational_expression
+ {
+ $$ = new Binary (Binary.Operator.Inequality,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+and_expression
+ : equality_expression
+ | and_expression BITWISE_AND equality_expression
+ {
+ $$ = new Binary (Binary.Operator.BitwiseAnd,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression CARRET and_expression
+ {
+ $$ = new Binary (Binary.Operator.ExclusiveOr,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression
+ | inclusive_or_expression BITWISE_OR exclusive_or_expression
+ {
+ $$ = new Binary (Binary.Operator.BitwiseOr,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+conditional_and_expression
+ : inclusive_or_expression
+ | conditional_and_expression OP_AND inclusive_or_expression
+ {
+ $$ = new Binary (Binary.Operator.LogicalAnd,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+conditional_or_expression
+ : conditional_and_expression
+ | conditional_or_expression OP_OR conditional_and_expression
+ {
+ $$ = new Binary (Binary.Operator.LogicalOr,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+conditional_expression
+ : conditional_or_expression
+ | conditional_or_expression INTERR expression COLON expression
+ {
+ $$ = new Conditional ((Expression) $1, (Expression) $3, (Expression) $5, lexer.Location);
+ }
+ ;
+
+assignment_expression
+ : prefixed_unary_expression ASSIGN expression
+ {
+ $$ = new Assign ((Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | prefixed_unary_expression OP_MULT_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.Multiply, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_DIV_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.Division, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_MOD_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.Modulus, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_ADD_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.Addition, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_SUB_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.Subtraction, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.LeftShift, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.RightShift, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_AND_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.BitwiseAnd, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_OR_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.BitwiseOr, (Expression) $1, (Expression) $3, l);
+ }
+ | prefixed_unary_expression OP_XOR_ASSIGN expression
+ {
+ Location l = lexer.Location;
+
+ $$ = new CompoundAssign (
+ Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3, l);
+ }
+ ;
+
+expression
+ : conditional_expression
+ | assignment_expression
+ ;
+
+constant_expression
+ : expression
+ ;
+
+boolean_expression
+ : expression
+ ;
+
+//
+// 10 classes
+//
+class_declaration
+ : opt_attributes
+ opt_modifiers
+ CLASS IDENTIFIER
+ {
+ Class new_class;
+ string name;
+
+ name = MakeName ((string) $4);
+
+ new_class = new Class (current_container, name, (int) $2,
+ (Attributes) $1, lexer.Location);
+ current_container = new_class;
+ current_container.Namespace = current_namespace;
+ RootContext.Tree.RecordDecl (name, new_class);
+ }
+ opt_class_base
+ class_body
+ opt_semicolon
+ {
+ Class new_class = (Class) current_container;
+
+ if ($6 != null)
+ new_class.Bases = (ArrayList) $6;
+
+ current_container = current_container.Parent;
+ CheckDef (current_container.AddClass (new_class), new_class.Name, new_class.Location);
+
+ $$ = new_class;
+ }
+ ;
+
+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 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
+ {
+ current_block = new Block (current_block, current_local_parameters,
+ lexer.Location, Location.Null);
+ }
+ opt_statement_list CLOSE_BRACE
+ {
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block.SetEndLocation (lexer.Location);
+ current_block = current_block.Parent;
+ }
+ ;
+
+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;
+ }
+ }
+ | embedded_statement
+ {
+ Statement s = (Statement) $1;
+
+
+ current_block.AddStatement ((Statement) $1);
+ }
+ | labeled_statement
+ ;
+
+embedded_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
+ ;
+
+empty_statement
+ : SEMICOLON
+ {
+ $$ = new EmptyStatement ();
+ }
+ ;
+
+labeled_statement
+ : IDENTIFIER COLON
+ {
+ LabeledStatement labeled = new LabeledStatement ((string) $1, lexer.Location);
+
+ if (!current_block.AddLabel ((string) $1, labeled)){
+ Location l = lexer.Location;
+ Report.Error (140, l, "The label '" + ((string) $1) + "' is a duplicate");
+ }
+ current_block.AddStatement (labeled);
+ }
+ statement
+ ;
+
+declaration_statement
+ : local_variable_declaration SEMICOLON
+ {
+ if ($1 != null){
+ DictionaryEntry de = (DictionaryEntry) $1;
+
+ $$ = declare_local_variables ((Expression) de.Key, (ArrayList) de.Value, lexer.Location);
+ }
+ }
+
+ | local_constant_declaration SEMICOLON
+ {
+ if ($1 != null){
+ DictionaryEntry de = (DictionaryEntry) $1;
+
+ $$ = declare_local_constant ((Expression) de.Key, (VariableDeclaration) 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 qualified_identifier (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)) {
+ Error_ExpectingTypeName (lexer.Location, 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, lexer.Location);
+ }
+ }
+ | builtin_types opt_rank_specifier
+ {
+ if ((string) $2 == "")
+ $$ = $1;
+ else
+ $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
+ }
+ ;
+
+local_variable_pointer_type
+ : primary_expression STAR
+ {
+ Expression expr = (Expression) $1;
+ Location l = lexer.Location;
+
+ if (!(expr is SimpleName || expr is MemberAccess || expr is ComposedCast)) {
+ Error_ExpectingTypeName (l, expr);
+
+ $$ = null;
+ } else
+ $$ = new ComposedCast ((Expression) $1, "*", l);
+ }
+ | builtin_types STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);;
+ }
+ | VOID STAR
+ {
+ $$ = new ComposedCast (TypeManager.system_void_expr, "*", lexer.Location);;
+ }
+ | local_variable_pointer_type STAR
+ {
+ $$ = new ComposedCast ((Expression) $1, "*", lexer.Location);
+ }
+ ;
+
+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, lexer.Location);
+ $$ = new DictionaryEntry (t, $3);
+ } else
+ $$ = null;
+ }
+ ;
+
+local_constant_declaration
+ : CONST local_variable_type constant_declarator
+ {
+ 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
+ : invocation_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | object_creation_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | assignment_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | post_increment_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | post_decrement_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | pre_increment_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | pre_decrement_expression { $$ = new StatementExpression ((ExpressionStatement) $1, lexer.Location); }
+ | error {
+ Report.Error (1002, lexer.Location, "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_statement_open if_statement_rest
+ {
+ $$ = $2;
+ }
+ ;
+
+if_statement_open
+ : IF OPEN_PARENS
+ {
+ oob_stack.Push (lexer.Location);
+ }
+ ;
+
+if_statement_rest
+ : boolean_expression CLOSE_PARENS
+ embedded_statement
+ {
+ Location l = (Location) oob_stack.Pop ();
+
+ $$ = new If ((Expression) $1, (Statement) $3, l);
+
+ if (RootContext.WarningLevel >= 3){
+ if ($3 is EmptyStatement)
+ Report.Warning (642, lexer.Location, "Possibly mistaken empty statement");
+ }
+
+ }
+ | boolean_expression CLOSE_PARENS
+ embedded_statement ELSE embedded_statement
+ {
+ Location l = (Location) oob_stack.Pop ();
+
+ $$ = new If ((Expression) $1, (Statement) $3, (Statement) $5, l);
+ }
+ ;
+
+switch_statement
+ : SWITCH OPEN_PARENS
+ {
+ oob_stack.Push (lexer.Location);
+ switch_stack.Push (current_block);
+ }
+ expression CLOSE_PARENS
+ switch_block
+ {
+ $$ = new Switch ((Expression) $4, (ArrayList) $6, (Location) oob_stack.Pop ());
+ current_block = (Block) switch_stack.Pop ();
+ }
+ ;
+
+switch_block
+ : OPEN_BRACE
+ opt_switch_sections
+ CLOSE_BRACE
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_switch_sections
+ : /* empty */
+ {
+ Report.Error (1522, lexer.Location, "Empty switch block");
+ }
+ | 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, lexer.Location); }
+ | DEFAULT COLON { $$ = new SwitchLabel (null, lexer.Location); }
+ | error {
+ Report.Error (
+ 1523, lexer.Location,
+ "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
+ {
+ oob_stack.Push (lexer.Location);
+ }
+ boolean_expression CLOSE_PARENS embedded_statement
+ {
+ Location l = (Location) oob_stack.Pop ();
+ $$ = new While ((Expression) $4, (Statement) $6, l);
+
+ if (RootContext.WarningLevel >= 3){
+ if ($6 is EmptyStatement)
+ Report.Warning (642, lexer.Location, "Possibly mistaken empty statement");
+ }
+ }
+ ;
+
+do_statement
+ : DO embedded_statement
+ WHILE OPEN_PARENS {
+ oob_stack.Push (lexer.Location);
+ }
+ boolean_expression CLOSE_PARENS SEMICOLON
+ {
+ Location l = (Location) oob_stack.Pop ();
+
+ $$ = new Do ((Statement) $2, (Expression) $6, 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, current_local_parameters, decl.Location);
+ if (vi == null)
+ continue;
+
+ Location l = lexer.Location;
+ Expression expr;
+ if (decl.expression_or_array_initializer is Expression){
+ expr = (Expression) decl.expression_or_array_initializer;
+ } else if (decl.expression_or_array_initializer == null) {
+ expr = null;
+ } else {
+ ArrayList init = (ArrayList) decl.expression_or_array_initializer;
+ expr = new ArrayCreation (type, "", init, decl.Location);
+ }
+
+ 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, lexer.Location));
+ }
+ }
+
+ $3 = null;
+ }
+ oob_stack.Push (lexer.Location);
+ }
+ opt_for_condition SEMICOLON
+ opt_for_iterator CLOSE_PARENS
+ embedded_statement
+ {
+ Location l = (Location) oob_stack.Pop ();
+
+ For f = new For ((Statement) $3, (Expression) $6, (Statement) $8, (Statement) $10, l);
+
+ if (RootContext.WarningLevel >= 3){
+ if ($10 is EmptyStatement)
+ Report.Warning (642, lexer.Location, "Possibly mistaken empty statement");
+ }
+
+ current_block.AddStatement (f);
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+ $$ = current_block;
+ current_block = current_block.Parent;
+ }
+ ;
+
+opt_for_initializer
+ : /* empty */ { $$ = new EmptyStatement (); }
+ | for_initializer
+ ;
+
+for_initializer
+ : local_variable_declaration
+ | statement_expression_list
+ ;
+
+opt_for_condition
+ : /* empty */ { $$ = null; }
+ | boolean_expression
+ ;
+
+opt_for_iterator
+ : /* empty */ { $$ = new EmptyStatement (); }
+ | for_iterator
+ ;
+
+for_iterator
+ : statement_expression_list
+ ;
+
+statement_expression_list
+ : statement_expression
+ {
+ // CHANGE: was `null'
+ Block b = new Block (current_block, Block.Flags.Implicit);
+
+ b.AddStatement ((Statement) $1);
+ $$ = b;
+ }
+ | statement_expression_list COMMA statement_expression
+ {
+ Block b = (Block) $1;
+
+ b.AddStatement ((Statement) $3);
+ $$ = $1;
+ }
+ ;
+
+foreach_statement
+ : FOREACH OPEN_PARENS type IDENTIFIER IN
+ {
+ oob_stack.Push (lexer.Location);
+ }
+ expression CLOSE_PARENS
+ {
+ oob_stack.Push (current_block);
+
+ Block foreach_block = new Block (current_block, Block.Flags.Implicit);
+ LocalVariableReference v = null;
+ Location l = lexer.Location;
+ LocalInfo vi;
+
+ vi = foreach_block.AddVariable ((Expression) $3, (string) $4, current_local_parameters, l);
+ if (vi != null) {
+ vi.ReadOnly = true;
+
+ // Get a writable reference to this read-only variable.
+ v = new LocalVariableReference (foreach_block, (string) $4, l, vi, false);
+ }
+ current_block = foreach_block;
+
+ oob_stack.Push (v);
+ oob_stack.Push (current_block);
+ }
+ embedded_statement
+ {
+ Block foreach_block = (Block) oob_stack.Pop ();
+ LocalVariableReference v = (LocalVariableReference) oob_stack.Pop ();
+ Block prev_block = (Block) oob_stack.Pop ();
+ Location l = (Location) oob_stack.Pop ();
+
+ current_block = prev_block;
+
+ if (v != null) {
+ Foreach f = new Foreach ((Expression) $3, v, (Expression) $7, (Statement) $10, l);
+ foreach_block.AddStatement (f);
+ }
+
+ $$ = foreach_block;
+ }
+ ;
+
+jump_statement
+ : break_statement
+ | continue_statement
+ | goto_statement
+ | return_statement
+ | throw_statement
+ | yield_statement
+ ;
+
+break_statement
+ : BREAK SEMICOLON
+ {
+ $$ = new Break (lexer.Location);
+ }
+ ;
+
+continue_statement
+ : CONTINUE SEMICOLON
+ {
+ $$ = new Continue (lexer.Location);
+ }
+ ;
+
+goto_statement
+ : GOTO IDENTIFIER SEMICOLON
+ {
+ $$ = new Goto (current_block, (string) $2, lexer.Location);
+ }
+ | GOTO CASE constant_expression SEMICOLON
+ {
+ $$ = new GotoCase ((Expression) $3, lexer.Location);
+ }
+ | GOTO DEFAULT SEMICOLON
+ {
+ $$ = new GotoDefault (lexer.Location);
+ }
+ ;
+
+return_statement
+ : RETURN opt_expression SEMICOLON
+ {
+ $$ = new Return ((Expression) $2, lexer.Location);
+ }
+ ;
+
+throw_statement
+ : THROW opt_expression SEMICOLON
+ {
+ $$ = new Throw ((Expression) $2, lexer.Location);
+ }
+ ;
+
+yield_statement
+ : YIELD expression SEMICOLON
+ {
+ if (iterator_container == null){
+ Report.Error (204, lexer.Location, "yield statement can only be used within a method, operator or property");
+ $$ = null;
+ } else {
+ iterator_container.SetYields ();
+ $$ = new Yield ((Expression) $2, lexer.Location);
+ }
+ }
+ | YIELD BREAK SEMICOLON
+ {
+ if (iterator_container == null){
+ Report.Error (204, lexer.Location, "yield statement can only be used within a method, operator or property");
+ $$ = null;
+ } else {
+ iterator_container.SetYields ();
+ $$ = new YieldBreak (lexer.Location);
+ }
+ }
+ ;
+
+opt_expression
+ : /* empty */
+ | expression
+ ;
+
+try_statement
+ : TRY block catch_clauses
+ {
+ Catch g = null;
+ ArrayList s = new ArrayList (4);
+
+ foreach (Catch cc in (ArrayList) $3) {
+ if (cc.IsGeneral)
+ g = cc;
+ else
+ s.Add (cc);
+ }
+
+ // Now s contains the list of specific catch clauses
+ // and g contains the general one.
+
+ $$ = new Try ((Block) $2, s, g, null, lexer.Location);
+ }
+ | 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, lexer.Location);
+ }
+ | TRY block error
+ {
+ Report.Error (1524, lexer.Location, "Expected catch or finally");
+ }
+ ;
+
+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;
+ string id = null;
+
+ if ($2 != null) {
+ DictionaryEntry cc = (DictionaryEntry) $2;
+ type = (Expression) cc.Key;
+ id = (string) cc.Value;
+
+ if (id != null){
+ ArrayList one = new ArrayList (4);
+ Location loc = lexer.Location;
+
+ one.Add (new VariableDeclaration (id, null, loc));
+
+ $1 = current_block;
+ current_block = new Block (current_block);
+ Block b = declare_local_variables (type, one, loc);
+ current_block = b;
+ }
+ }
+ } block {
+ Expression type = null;
+ string id = null;
+
+ if ($2 != null){
+ DictionaryEntry cc = (DictionaryEntry) $2;
+ type = (Expression) cc.Key;
+ id = (string) cc.Value;
+
+ if ($1 != null){
+ //
+ // FIXME: I can change this for an assignment.
+ //
+ while (current_block != (Block) $1)
+ current_block = current_block.Parent;
+ }
+ }
+
+
+ $$ = new Catch (type, id , (Block) $4, lexer.Location);
+ }
+ ;
+
+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
+ {
+ if (!RootContext.Unsafe){
+ Report.Error (227, lexer.Location,
+ "Unsafe code can only be used if --unsafe is used");
+ }
+ } block {
+ $$ = new Unsafe ((Block) $3);
+ }
+ ;
+
+fixed_statement
+ : FIXED OPEN_PARENS
+ type fixed_pointer_declarators
+ CLOSE_PARENS
+ {
+ Block assign_block = new Block (current_block, Block.Flags.Implicit);
+ ArrayList list = (ArrayList) $4;
+ Expression type = (Expression) $3;
+ Location l = lexer.Location;
+ int top = list.Count;
+
+ for (int i = 0; i < top; i++){
+ Pair p = (Pair) list [i];
+ LocalInfo v;
+
+ v = current_block.AddVariable (type, (string) p.First,current_local_parameters, l);
+ if (v == null)
+ continue;
+ v.ReadOnly = true;
+ p.First = v;
+ list [i] = p;
+ }
+ current_block.AddStatement (assign_block);
+ current_block = assign_block;
+ oob_stack.Push (assign_block);
+ oob_stack.Push (l);
+ }
+ embedded_statement
+ {
+ Location l = (Location) oob_stack.Pop ();
+ Block assign_block = (Block) oob_stack.Pop ();
+
+ ArrayList list = (ArrayList) $4;
+ int top = list.Count;
+
+ $$ = new Fixed ((Expression) $3, (ArrayList) $4, (Statement) $7, l);
+ }
+ ;
+
+fixed_pointer_declarators
+ : fixed_pointer_declarator {
+ ArrayList declarators = new ArrayList (4);
+ declarators.Add ($1);
+ $$ = declarators;
+ }
+ | fixed_pointer_declarators COMMA fixed_pointer_declarator
+ {
+ ArrayList declarators = (ArrayList) $1;
+ declarators.Add ($3);
+ $$ = declarators;
+ }
+ ;
+
+fixed_pointer_declarator
+ : IDENTIFIER ASSIGN expression
+ {
+ $$ = new Pair ($1, $3);
+ }
+ ;
+
+lock_statement
+ : LOCK OPEN_PARENS expression CLOSE_PARENS
+ {
+ //
+ }
+ embedded_statement
+ {
+ $$ = new Lock ((Expression) $3, (Statement) $6, lexer.Location);
+ }
+ ;
+
+using_statement
+ : USING OPEN_PARENS resource_acquisition CLOSE_PARENS
+ {
+ Block assign_block = new Block (current_block);
+ current_block = assign_block;
+
+ oob_stack.Push (lexer.Location);
+
+ if ($3 is DictionaryEntry){
+ DictionaryEntry de = (DictionaryEntry) $3;
+ Location l = lexer.Location;
+
+ 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,
+ current_local_parameters, decl.Location);
+ if (vi == null)
+ continue;
+ vi.ReadOnly = true;
+
+ Expression expr;
+ if (decl.expression_or_array_initializer is Expression){
+ expr = (Expression) decl.expression_or_array_initializer;
+ } else {
+ ArrayList init = (ArrayList) decl.expression_or_array_initializer;
+
+ expr = new ArrayCreation (type, "", init, decl.Location);
+ }
+
+ 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, lexer.Location));
+ }
+ $3 = new DictionaryEntry (type, vars);
+ }
+ }
+ embedded_statement
+ {
+ Using u = new Using ($3, (Statement) $6, (Location) oob_stack.Pop ());
+ 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 object expression_or_array_initializer;
+ public Location Location;
+ public Attributes OptAttributes;
+
+ public VariableDeclaration (string id, object eoai, Location l, Attributes opt_attrs)
+ {
+ this.identifier = id;
+ this.expression_or_array_initializer = eoai;
+ this.Location = l;
+ this.OptAttributes = opt_attrs;
+ }
+
+ public VariableDeclaration (string id, object eoai, Location l) : this (id, eoai, l, null)
+ {
+ }
+}
+
+// <summary>
+// A class used to hold info about an indexer declarator
+// </summary>
+
+public class IndexerDeclaration {
+ public Expression type;
+ public string interface_type;
+ public Parameters param_list;
+
+ public IndexerDeclaration (Expression type, string interface_type, Parameters param_list)
+ {
+ this.type = type;
+ this.interface_type = interface_type;
+ this.param_list = param_list;
+ }
+}
+
+// <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 (Location l, Expression expr)
+{
+ if (expr is Invocation){
+ Report.Error (1002, l, "; expected");
+ } else {
+ Report.Error (-1, l, "Invalid Type definition");
+ }
+}
+
+// <summary>
+// Given the @class_name name, it creates a fully qualified name
+// based on the containing declaration space
+// </summary>
+string
+MakeName (string class_name)
+{
+ string ns = current_namespace.Name;
+ string container_name = current_container.Name;
+
+ if (container_name == ""){
+ if (ns != "")
+ return ns + "." + class_name;
+ else
+ return class_name;
+ } else
+ return container_name + "." + class_name;
+}
+
+// <summary>
+// Used to report back to the user the result of a declaration
+// in the current declaration space
+// </summary>
+void
+CheckDef (AdditionResult result, string name, Location l)
+{
+ if (result == AdditionResult.Success)
+ return;
+
+ switch (result){
+ case AdditionResult.NameExists:
+ Report.Error (102, l, "The container `" + current_container.Name +
+ "' already contains a definition for `"+
+ name + "'");
+ break;
+
+
+ //
+ // This is handled only for static Constructors, because
+ // in reality we handle these by the semantic analysis later
+ //
+ case AdditionResult.MethodExists:
+ Report.Error (
+ 111, l, "Class `"+current_container.Name+
+ "' already defines a member called '" +
+ name + "' with the same parameter types (more than one default constructor)");
+ break;
+
+ case AdditionResult.EnclosingClash:
+ Report.Error (542, l, "Member names cannot be the same as their enclosing type");
+ break;
+
+ case AdditionResult.NotAConstructor:
+ Report.Error (1520, l, "Class, struct, or interface method must have a return type");
+ break;
+
+ case AdditionResult.Error:
+ // Error has already been reported.
+ break;
+ }
+}
+
+void
+CheckDef (bool result, string name, Location l)
+{
+ if (result)
+ return;
+ CheckDef (AdditionResult.NameExists, name, l);
+}
+
+Expression DecomposeQI (string name, Location loc)
+{
+ Expression o;
+
+ if (name.IndexOf ('.') == -1){
+ return new SimpleName (name, loc);
+ } else {
+ int pos = name.LastIndexOf (".");
+ string left = name.Substring (0, pos);
+ string right = name.Substring (pos + 1);
+
+ o = DecomposeQI (left, loc);
+
+ return new MemberAccess (o, right, loc);
+ }
+}
+
+// <summary>
+// This method is used to get at the complete string representation of
+// a fully-qualified type name, hiding inside a MemberAccess ;-)
+// This is necessary because local_variable_type admits primary_expression
+// as the type of the variable. So we do some extra checking
+// </summary>
+#if false
+string GetQualifiedIdentifier (Expression expr)
+{
+ if (expr is SimpleName)
+ return ((SimpleName)expr).Name;
+ else if (expr is MemberAccess)
+ return GetQualifiedIdentifier (((MemberAccess)expr).Expr) + "." + ((MemberAccess) expr).Identifier;
+ else
+ throw new Exception ("Expr has to be either SimpleName or MemberAccess! (" + expr + ")");
+
+}
+#endif
+
+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);
+ implicit_block.AddChildVariableNames (current_block);
+ } else
+ implicit_block = current_block;
+
+ foreach (VariableDeclaration decl in variable_declarators){
+
+ if (implicit_block.AddVariable (type, decl.identifier, current_local_parameters, 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;
+
+ if (decl.expression_or_array_initializer is Expression){
+ expr = (Expression) decl.expression_or_array_initializer;
+
+ } else {
+ ArrayList init = (ArrayList) decl.expression_or_array_initializer;
+
+ expr = new ArrayCreation (type, "", init, decl.Location);
+ }
+
+ LocalVariableReference var;
+ var = new LocalVariableReference (implicit_block, decl.identifier, loc);
+
+ assign = new Assign (var, expr, decl.Location);
+
+ implicit_block.AddStatement (new StatementExpression (assign, lexer.Location));
+ }
+
+ return implicit_block;
+}
+
+Block declare_local_constant (Expression type, VariableDeclaration decl)
+{
+ Block implicit_block;
+
+ if (current_block.Used)
+ implicit_block = new Block (current_block, Block.Flags.Implicit);
+ else
+ implicit_block = current_block;
+
+ if (!(implicit_block.AddConstant (type, decl.identifier, (Expression) decl.expression_or_array_initializer,
+ current_local_parameters, decl.Location))){
+ }
+
+ return implicit_block;
+}
+
+void CheckAttributeTarget (string a)
+{
+ switch (a) {
+
+ case "assembly" : case "field" : case "method" : case "param" : case "property" : case "type" :
+ return;
+
+ default :
+ Location l = lexer.Location;
+ Report.Error (658, l, "`" + a + "' is an invalid attribute target");
+ break;
+ }
+
+}
+
+void CheckUnaryOperator (Operator.OpType op)
+{
+ 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 :
+ Location l = lexer.Location;
+ Report.Error (1019, l, "Overloadable unary operator expected");
+ break;
+
+ }
+}
+
+void CheckBinaryOperator (Operator.OpType op)
+{
+ 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 :
+ Location l = lexer.Location;
+ Report.Error (1020, l, "Overloadable binary operator expected");
+ break;
+ }
+
+}
+
+void syntax_error (Location l, string msg)
+{
+ Report.Error (1003, l, "Syntax error, " + msg);
+}
+
+void output (string s)
+{
+ Console.WriteLine (s);
+}
+
+void note (string s)
+{
+ // Used to put annotations
+}
+
+Tokenizer lexer;
+
+public Tokenizer Lexer {
+ get {
+ return lexer;
+ }
+}
+
+public CSharpParser (StreamReader reader, SourceFile file, ArrayList defines)
+{
+ current_namespace = new NamespaceEntry (null, file, null);
+ this.name = file.Name;
+ this.file = file;
+ current_container = RootContext.Tree.Types;
+ current_container.Namespace = current_namespace;
+ oob_stack = new Stack ();
+ switch_stack = new Stack ();
+
+ lexer = new Tokenizer (reader, file, defines);
+}
+
+public override void parse ()
+{
+ try {
+ if (yacc_verbose_flag)
+ yyparse (lexer, new yydebug.yyDebugSimple ());
+ else
+ yyparse (lexer);
+ Tokenizer tokenizer = lexer as Tokenizer;
+ tokenizer.cleanup ();
+ } catch (Exception e){
+ // Please do not remove this, it is used during debugging
+ // of the grammar
+ //
+ Report.Error (-25, lexer.Location, ": Parsing error ");
+ Console.WriteLine (e);
+ }
+}
+
+/* end end end */
+}
--- /dev/null
+//\r
+// cs-tokenizer.cs: The Tokenizer for the C# compiler\r
+// This also implements the preprocessor\r
+//\r
+// Author: Miguel de Icaza (miguel@gnu.org)\r
+//\r
+// Licensed under the terms of the GNU GPL\r
+//\r
+// (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)\r
+//\r
+\r
+/*\r
+ * TODO:\r
+ * Make sure we accept the proper Unicode ranges, per the spec.\r
+ * Report error 1032\r
+*/\r
+\r
+using System;\r
+using System.Text;\r
+using System.Collections;\r
+using System.IO;\r
+using System.Globalization;\r
+using System.Reflection;\r
+\r
+namespace Mono.CSharp\r
+{\r
+ /// <summary>\r
+ /// Tokenizer for C# source code. \r
+ /// </summary>\r
+\r
+ public class Tokenizer : yyParser.yyInput\r
+ {\r
+ StreamReader reader;\r
+ public SourceFile ref_name;\r
+ public SourceFile file_name;\r
+ public int ref_line = 1;\r
+ public int line = 1;\r
+ public int col = 1;\r
+ public int current_token;\r
+ bool handle_get_set = false;\r
+ bool handle_remove_add = false;\r
+ bool handle_assembly = false;\r
+\r
+ //\r
+ // Whether tokens have been seen on this line\r
+ //\r
+ bool tokens_seen = false;\r
+\r
+ //\r
+ // Whether a token has been seen on the file\r
+ // This is needed because `define' is not allowed to be used\r
+ // after a token has been seen.\r
+ //\r
+ bool any_token_seen = false;\r
+ static Hashtable tokenValues;\r
+ \r
+ private static Hashtable TokenValueName\r
+ {\r
+ get {\r
+ if (tokenValues == null)\r
+ tokenValues = GetTokenValueNameHash ();\r
+\r
+ return tokenValues;\r
+ }\r
+ }\r
+\r
+ private static Hashtable GetTokenValueNameHash ()\r
+ {\r
+ Type t = typeof (Token);\r
+ FieldInfo [] fields = t.GetFields ();\r
+ Hashtable hash = new Hashtable ();\r
+ foreach (FieldInfo field in fields) {\r
+ if (field.IsLiteral && field.IsStatic && field.FieldType == typeof (int))\r
+ hash.Add (field.GetValue (null), field.Name);\r
+ }\r
+ return hash;\r
+ }\r
+ \r
+ //\r
+ // Returns a verbose representation of the current location\r
+ //\r
+ public string location {\r
+ get {\r
+ string det;\r
+\r
+ if (current_token == Token.ERROR)\r
+ det = "detail: " + error_details;\r
+ else\r
+ det = "";\r
+ \r
+ // return "Line: "+line+" Col: "+col + "\n" +\r
+ // "VirtLine: "+ref_line +\r
+ // " Token: "+current_token + " " + det;\r
+ string current_token_name = TokenValueName [current_token] as string;\r
+ if (current_token_name == null)\r
+ current_token_name = current_token.ToString ();\r
+\r
+ return String.Format ("{0} ({1},{2}), Token: {3} {4}", ref_name.Name,\r
+ ref_line,\r
+ col,\r
+ current_token_name,\r
+ det);\r
+ }\r
+ }\r
+\r
+ public bool PropertyParsing {\r
+ get {\r
+ return handle_get_set;\r
+ }\r
+\r
+ set {\r
+ handle_get_set = value;\r
+ }\r
+ }\r
+\r
+ public bool AssemblyTargetParsing {\r
+ get {\r
+ return handle_assembly;\r
+ }\r
+\r
+ set {\r
+ handle_assembly = value;\r
+ }\r
+ }\r
+\r
+ public bool EventParsing {\r
+ get {\r
+ return handle_remove_add;\r
+ }\r
+\r
+ set {\r
+ handle_remove_add = value;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Class variables\r
+ // \r
+ static Hashtable keywords;\r
+ static NumberStyles styles;\r
+ static NumberFormatInfo csharp_format_info;\r
+ \r
+ //\r
+ // Values for the associated token returned\r
+ //\r
+ int putback_char;\r
+ Object val;\r
+\r
+ //\r
+ // Pre-processor\r
+ //\r
+ Hashtable defines;\r
+\r
+ const int TAKING = 1;\r
+ const int TAKEN_BEFORE = 2;\r
+ const int ELSE_SEEN = 4;\r
+ const int PARENT_TAKING = 8;\r
+ const int REGION = 16; \r
+\r
+ //\r
+ // pre-processor if stack state:\r
+ //\r
+ Stack ifstack;\r
+\r
+ static System.Text.StringBuilder string_builder;\r
+\r
+ const int max_id_size = 512;\r
+ static char [] id_builder = new char [max_id_size];\r
+\r
+ const int max_number_size = 128;\r
+ static char [] number_builder = new char [max_number_size];\r
+ static int number_pos;\r
+ \r
+ //\r
+ // Details about the error encoutered by the tokenizer\r
+ //\r
+ string error_details;\r
+ \r
+ public string error {\r
+ get {\r
+ return error_details;\r
+ }\r
+ }\r
+ \r
+ public int Line {\r
+ get {\r
+ return ref_line;\r
+ }\r
+ }\r
+\r
+ public int Col {\r
+ get {\r
+ return col;\r
+ }\r
+ }\r
+\r
+ static void InitTokens ()\r
+ {\r
+ keywords = new Hashtable ();\r
+\r
+ keywords.Add ("abstract", Token.ABSTRACT);\r
+ keywords.Add ("as", Token.AS);\r
+ keywords.Add ("add", Token.ADD);\r
+ keywords.Add ("assembly", Token.ASSEMBLY);\r
+ keywords.Add ("base", Token.BASE);\r
+ keywords.Add ("bool", Token.BOOL);\r
+ keywords.Add ("break", Token.BREAK);\r
+ keywords.Add ("byte", Token.BYTE);\r
+ keywords.Add ("case", Token.CASE);\r
+ keywords.Add ("catch", Token.CATCH);\r
+ keywords.Add ("char", Token.CHAR);\r
+ keywords.Add ("checked", Token.CHECKED);\r
+ keywords.Add ("class", Token.CLASS);\r
+ keywords.Add ("const", Token.CONST);\r
+ keywords.Add ("continue", Token.CONTINUE);\r
+ keywords.Add ("decimal", Token.DECIMAL);\r
+ keywords.Add ("default", Token.DEFAULT);\r
+ keywords.Add ("delegate", Token.DELEGATE);\r
+ keywords.Add ("do", Token.DO);\r
+ keywords.Add ("double", Token.DOUBLE);\r
+ keywords.Add ("else", Token.ELSE);\r
+ keywords.Add ("enum", Token.ENUM);\r
+ keywords.Add ("event", Token.EVENT);\r
+ keywords.Add ("explicit", Token.EXPLICIT);\r
+ keywords.Add ("extern", Token.EXTERN);\r
+ keywords.Add ("false", Token.FALSE);\r
+ keywords.Add ("finally", Token.FINALLY);\r
+ keywords.Add ("fixed", Token.FIXED);\r
+ keywords.Add ("float", Token.FLOAT);\r
+ keywords.Add ("for", Token.FOR);\r
+ keywords.Add ("foreach", Token.FOREACH);\r
+ keywords.Add ("goto", Token.GOTO);\r
+ keywords.Add ("get", Token.GET);\r
+ keywords.Add ("if", Token.IF);\r
+ keywords.Add ("implicit", Token.IMPLICIT);\r
+ keywords.Add ("in", Token.IN);\r
+ keywords.Add ("int", Token.INT);\r
+ keywords.Add ("interface", Token.INTERFACE);\r
+ keywords.Add ("internal", Token.INTERNAL);\r
+ keywords.Add ("is", Token.IS);\r
+ keywords.Add ("lock", Token.LOCK);\r
+ keywords.Add ("long", Token.LONG);\r
+ keywords.Add ("namespace", Token.NAMESPACE);\r
+ keywords.Add ("new", Token.NEW);\r
+ keywords.Add ("null", Token.NULL);\r
+ keywords.Add ("object", Token.OBJECT);\r
+ keywords.Add ("operator", Token.OPERATOR);\r
+ keywords.Add ("out", Token.OUT);\r
+ keywords.Add ("override", Token.OVERRIDE);\r
+ keywords.Add ("params", Token.PARAMS);\r
+ keywords.Add ("private", Token.PRIVATE);\r
+ keywords.Add ("protected", Token.PROTECTED);\r
+ keywords.Add ("public", Token.PUBLIC);\r
+ keywords.Add ("readonly", Token.READONLY);\r
+ keywords.Add ("ref", Token.REF);\r
+ keywords.Add ("remove", Token.REMOVE);\r
+ keywords.Add ("return", Token.RETURN);\r
+ keywords.Add ("sbyte", Token.SBYTE);\r
+ keywords.Add ("sealed", Token.SEALED);\r
+ keywords.Add ("set", Token.SET);\r
+ keywords.Add ("short", Token.SHORT);\r
+ keywords.Add ("sizeof", Token.SIZEOF);\r
+ keywords.Add ("stackalloc", Token.STACKALLOC);\r
+ keywords.Add ("static", Token.STATIC);\r
+ keywords.Add ("string", Token.STRING);\r
+ keywords.Add ("struct", Token.STRUCT);\r
+ keywords.Add ("switch", Token.SWITCH);\r
+ keywords.Add ("this", Token.THIS);\r
+ keywords.Add ("throw", Token.THROW);\r
+ keywords.Add ("true", Token.TRUE);\r
+ keywords.Add ("try", Token.TRY);\r
+ keywords.Add ("typeof", Token.TYPEOF);\r
+ keywords.Add ("uint", Token.UINT);\r
+ keywords.Add ("ulong", Token.ULONG);\r
+ keywords.Add ("unchecked", Token.UNCHECKED);\r
+ keywords.Add ("unsafe", Token.UNSAFE);\r
+ keywords.Add ("ushort", Token.USHORT);\r
+ keywords.Add ("using", Token.USING);\r
+ keywords.Add ("virtual", Token.VIRTUAL);\r
+ keywords.Add ("void", Token.VOID);\r
+ keywords.Add ("volatile", Token.VOLATILE);\r
+ keywords.Add ("while", Token.WHILE);\r
+\r
+ if (RootContext.V2){\r
+ keywords.Add ("__yield", Token.YIELD);\r
+ keywords.Add ("yield", Token.YIELD);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Class initializer\r
+ // \r
+ static Tokenizer ()\r
+ {\r
+ InitTokens ();\r
+ csharp_format_info = NumberFormatInfo.InvariantInfo;\r
+ styles = NumberStyles.Float;\r
+ \r
+ string_builder = new System.Text.StringBuilder ();\r
+ }\r
+\r
+ int GetKeyword (string name)\r
+ {\r
+ object o = keywords [name];\r
+\r
+ if (o == null)\r
+ return -1;\r
+ \r
+ int res = (int) o;\r
+\r
+ if (handle_get_set == false && (res == Token.GET || res == Token.SET))\r
+ return -1;\r
+ if (handle_remove_add == false && (res == Token.REMOVE || res == Token.ADD))\r
+ return -1;\r
+ if (handle_assembly == false && res == Token.ASSEMBLY)\r
+ return -1;\r
+ return res;\r
+ \r
+ }\r
+\r
+ public Location Location {\r
+ get {\r
+ return new Location (ref_line);\r
+ }\r
+ }\r
+\r
+ void define (string def)\r
+ {\r
+ if (!RootContext.AllDefines.Contains (def)){\r
+ RootContext.AllDefines [def] = true;\r
+ }\r
+ if (defines.Contains (def))\r
+ return;\r
+ defines [def] = true;\r
+ }\r
+ \r
+ public Tokenizer (StreamReader input, SourceFile file, ArrayList defs)\r
+ {\r
+ this.ref_name = file;\r
+ this.file_name = file;\r
+ reader = input;\r
+ \r
+ putback_char = -1;\r
+\r
+ if (defs != null){\r
+ defines = new Hashtable ();\r
+ foreach (string def in defs)\r
+ define (def);\r
+ }\r
+\r
+ //\r
+ // FIXME: This could be `Location.Push' but we have to\r
+ // find out why the MS compiler allows this\r
+ //\r
+ Mono.CSharp.Location.Push (file);\r
+ }\r
+\r
+ bool is_identifier_start_character (char c)\r
+ {\r
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || Char.IsLetter (c);\r
+ }\r
+\r
+ bool is_identifier_part_character (char c)\r
+ {\r
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9') || Char.IsLetter (c);\r
+ }\r
+\r
+ int is_punct (char c, ref bool doread)\r
+ {\r
+ int d;\r
+ int t;\r
+\r
+ doread = false;\r
+\r
+ switch (c){\r
+ case '{':\r
+ return Token.OPEN_BRACE;\r
+ case '}':\r
+ return Token.CLOSE_BRACE;\r
+ case '[':\r
+ return Token.OPEN_BRACKET;\r
+ case ']':\r
+ return Token.CLOSE_BRACKET;\r
+ case '(':\r
+ return Token.OPEN_PARENS;\r
+ case ')':\r
+ return Token.CLOSE_PARENS;\r
+ case ',':\r
+ return Token.COMMA;\r
+ case ':':\r
+ return Token.COLON;\r
+ case ';':\r
+ return Token.SEMICOLON;\r
+ case '~':\r
+ return Token.TILDE;\r
+ case '?':\r
+ return Token.INTERR;\r
+ }\r
+\r
+ d = peekChar ();\r
+ if (c == '+'){\r
+ \r
+ if (d == '+')\r
+ t = Token.OP_INC;\r
+ else if (d == '=')\r
+ t = Token.OP_ADD_ASSIGN;\r
+ else\r
+ return Token.PLUS;\r
+ doread = true;\r
+ return t;\r
+ }\r
+ if (c == '-'){\r
+ if (d == '-')\r
+ t = Token.OP_DEC;\r
+ else if (d == '=')\r
+ t = Token.OP_SUB_ASSIGN;\r
+ else if (d == '>')\r
+ t = Token.OP_PTR;\r
+ else\r
+ return Token.MINUS;\r
+ doread = true;\r
+ return t;\r
+ }\r
+\r
+ if (c == '!'){\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_NE;\r
+ }\r
+ return Token.BANG;\r
+ }\r
+\r
+ if (c == '='){\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_EQ;\r
+ }\r
+ return Token.ASSIGN;\r
+ }\r
+\r
+ if (c == '&'){\r
+ if (d == '&'){\r
+ doread = true;\r
+ return Token.OP_AND;\r
+ } else if (d == '='){\r
+ doread = true;\r
+ return Token.OP_AND_ASSIGN;\r
+ }\r
+ return Token.BITWISE_AND;\r
+ }\r
+\r
+ if (c == '|'){\r
+ if (d == '|'){\r
+ doread = true;\r
+ return Token.OP_OR;\r
+ } else if (d == '='){\r
+ doread = true;\r
+ return Token.OP_OR_ASSIGN;\r
+ }\r
+ return Token.BITWISE_OR;\r
+ }\r
+\r
+ if (c == '*'){\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_MULT_ASSIGN;\r
+ }\r
+ return Token.STAR;\r
+ }\r
+\r
+ if (c == '/'){\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_DIV_ASSIGN;\r
+ }\r
+ return Token.DIV;\r
+ }\r
+\r
+ if (c == '%'){\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_MOD_ASSIGN;\r
+ }\r
+ return Token.PERCENT;\r
+ }\r
+\r
+ if (c == '^'){\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_XOR_ASSIGN;\r
+ }\r
+ return Token.CARRET;\r
+ }\r
+\r
+ if (c == '<'){\r
+ if (d == '<'){\r
+ getChar ();\r
+ d = peekChar ();\r
+\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_SHIFT_LEFT_ASSIGN;\r
+ }\r
+ return Token.OP_SHIFT_LEFT;\r
+ } else if (d == '='){\r
+ doread = true;\r
+ return Token.OP_LE;\r
+ }\r
+ return Token.OP_LT;\r
+ }\r
+\r
+ if (c == '>'){\r
+ if (d == '>'){\r
+ getChar ();\r
+ d = peekChar ();\r
+\r
+ if (d == '='){\r
+ doread = true;\r
+ return Token.OP_SHIFT_RIGHT_ASSIGN;\r
+ }\r
+ return Token.OP_SHIFT_RIGHT;\r
+ } else if (d == '='){\r
+ doread = true;\r
+ return Token.OP_GE;\r
+ }\r
+ return Token.OP_GT;\r
+ }\r
+ return Token.ERROR;\r
+ }\r
+\r
+ void Error_NumericConstantTooLong ()\r
+ {\r
+ Report.Error (1021, Location, "Numeric constant too long"); \r
+ }\r
+ \r
+ bool decimal_digits (int c)\r
+ {\r
+ int d;\r
+ bool seen_digits = false;\r
+ \r
+ if (c != -1){\r
+ if (number_pos == max_number_size)\r
+ Error_NumericConstantTooLong ();\r
+ number_builder [number_pos++] = (char) c;\r
+ }\r
+ \r
+ //\r
+ // We use peekChar2, because decimal_digits needs to do a \r
+ // 2-character look-ahead (5.ToString for example).\r
+ //\r
+ while ((d = peekChar2 ()) != -1){\r
+ if (d >= '0' && d <= '9'){\r
+ if (number_pos == max_number_size)\r
+ Error_NumericConstantTooLong ();\r
+ number_builder [number_pos++] = (char) d;\r
+ getChar ();\r
+ seen_digits = true;\r
+ } else\r
+ break;\r
+ }\r
+ \r
+ return seen_digits;\r
+ }\r
+\r
+ bool is_hex (int e)\r
+ {\r
+ return (e >= '0' && e <= '9') || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');\r
+ }\r
+ \r
+ void hex_digits (int c)\r
+ {\r
+ if (c != -1)\r
+ number_builder [number_pos++] = (char) c;\r
+ \r
+ }\r
+ \r
+ int real_type_suffix (int c)\r
+ {\r
+ int t;\r
+\r
+ switch (c){\r
+ case 'F': case 'f':\r
+ t = Token.LITERAL_FLOAT;\r
+ break;\r
+ case 'D': case 'd':\r
+ t = Token.LITERAL_DOUBLE;\r
+ break;\r
+ case 'M': case 'm':\r
+ t= Token.LITERAL_DECIMAL;\r
+ break;\r
+ default:\r
+ return Token.NONE;\r
+ }\r
+ return t;\r
+ }\r
+\r
+ int integer_type_suffix (ulong ul, int c)\r
+ {\r
+ bool is_unsigned = false;\r
+ bool is_long = false;\r
+\r
+ if (c != -1){\r
+ bool scanning = true;\r
+ do {\r
+ switch (c){\r
+ case 'U': case 'u':\r
+ if (is_unsigned)\r
+ scanning = false;\r
+ is_unsigned = true;\r
+ getChar ();\r
+ break;\r
+\r
+ case 'l':\r
+ if (!is_unsigned){\r
+ //\r
+ // if we have not seen anything in between\r
+ // report this error\r
+ //\r
+ Report.Warning (\r
+ 78, Location,\r
+ "the 'l' suffix is easily confused with digit `1'," +\r
+ " use 'L' for clarity");\r
+ }\r
+ goto case 'L';\r
+ \r
+ case 'L': \r
+ if (is_long)\r
+ scanning = false;\r
+ is_long = true;\r
+ getChar ();\r
+ break;\r
+ \r
+ default:\r
+ scanning = false;\r
+ break;\r
+ }\r
+ c = peekChar ();\r
+ } while (scanning);\r
+ }\r
+\r
+ if (is_long && is_unsigned){\r
+ val = ul;\r
+ return Token.LITERAL_INTEGER;\r
+ } else if (is_unsigned){\r
+ // uint if possible, or ulong else.\r
+\r
+ if ((ul & 0xffffffff00000000) == 0)\r
+ val = (uint) ul;\r
+ else\r
+ val = ul;\r
+ } else if (is_long){\r
+ // long if possible, ulong otherwise\r
+ if ((ul & 0x8000000000000000) != 0)\r
+ val = ul;\r
+ else\r
+ val = (long) ul;\r
+ } else {\r
+ // int, uint, long or ulong in that order\r
+ if ((ul & 0xffffffff00000000) == 0){\r
+ uint ui = (uint) ul;\r
+ \r
+ if ((ui & 0x80000000) != 0)\r
+ val = ui;\r
+ else\r
+ val = (int) ui;\r
+ } else {\r
+ if ((ul & 0x8000000000000000) != 0)\r
+ val = ul;\r
+ else\r
+ val = (long) ul;\r
+ }\r
+ }\r
+ return Token.LITERAL_INTEGER;\r
+ }\r
+ \r
+ //\r
+ // given `c' as the next char in the input decide whether\r
+ // we need to convert to a special type, and then choose\r
+ // the best representation for the integer\r
+ //\r
+ int adjust_int (int c)\r
+ {\r
+ try {\r
+ if (number_pos > 9){\r
+ ulong ul = (uint) (number_builder [0] - '0');\r
+\r
+ for (int i = 1; i < number_pos; i++){\r
+ ul = checked ((ul * 10) + ((uint)(number_builder [i] - '0')));\r
+ }\r
+ return integer_type_suffix (ul, c);\r
+ } else {\r
+ uint ui = (uint) (number_builder [0] - '0');\r
+\r
+ for (int i = 1; i < number_pos; i++){\r
+ ui = checked ((ui * 10) + ((uint)(number_builder [i] - '0')));\r
+ }\r
+ return integer_type_suffix (ui, c);\r
+ }\r
+ } catch (OverflowException) {\r
+ error_details = "Integral constant is too large";\r
+ Report.Error (1021, Location, error_details);\r
+ val = 0ul;\r
+ return Token.LITERAL_INTEGER;\r
+ }\r
+ }\r
+ \r
+ int adjust_real (int t)\r
+ {\r
+ string s = new String (number_builder, 0, number_pos);\r
+\r
+ switch (t){\r
+ case Token.LITERAL_DECIMAL:\r
+ try {\r
+ val = System.Decimal.Parse (s, styles, csharp_format_info);\r
+ } catch (OverflowException) {\r
+ val = 0m; \r
+ error_details = "Floating-point constant is outside the range of the type 'decimal'";\r
+ Report.Error (594, Location, error_details);\r
+ }\r
+ break;\r
+ case Token.LITERAL_FLOAT:\r
+ try {\r
+ val = (float) System.Double.Parse (s, styles, csharp_format_info);\r
+ } catch (OverflowException) {\r
+ val = 0.0f; \r
+ error_details = "Floating-point constant is outside the range of the type 'float'";\r
+ Report.Error (594, Location, error_details);\r
+ }\r
+ break;\r
+ \r
+ case Token.LITERAL_DOUBLE:\r
+ case Token.NONE:\r
+ t = Token.LITERAL_DOUBLE;\r
+ try {\r
+ val = System.Double.Parse (s, styles, csharp_format_info);\r
+ } catch (OverflowException) {\r
+ val = 0.0; \r
+ error_details = "Floating-point constant is outside the range of the type 'double'";\r
+ Report.Error (594, Location, error_details);\r
+ }\r
+ break;\r
+ }\r
+ return t;\r
+ }\r
+\r
+ int handle_hex ()\r
+ {\r
+ int d;\r
+ ulong ul;\r
+ \r
+ getChar ();\r
+ while ((d = peekChar ()) != -1){\r
+ if (is_hex (d)){\r
+ if (number_pos == 16){\r
+ Report.Error (1021, Location, "Integral constant too large");\r
+ return Token.ERROR;\r
+ }\r
+ number_builder [number_pos++] = (char) d;\r
+ getChar ();\r
+ } else\r
+ break;\r
+ }\r
+ \r
+ string s = new String (number_builder, 0, number_pos);\r
+ if (number_pos <= 8)\r
+ ul = System.UInt32.Parse (s, NumberStyles.HexNumber);\r
+ else\r
+ ul = System.UInt64.Parse (s, NumberStyles.HexNumber);\r
+ return integer_type_suffix (ul, peekChar ());\r
+ }\r
+\r
+ //\r
+ // Invoked if we know we have .digits or digits\r
+ //\r
+ int is_number (int c)\r
+ {\r
+ bool is_real = false;\r
+ int type;\r
+\r
+ number_pos = 0;\r
+\r
+ if (c >= '0' && c <= '9'){\r
+ if (c == '0'){\r
+ int peek = peekChar ();\r
+\r
+ if (peek == 'x' || peek == 'X')\r
+ return handle_hex ();\r
+ }\r
+ decimal_digits (c);\r
+ c = getChar ();\r
+ }\r
+\r
+ //\r
+ // We need to handle the case of\r
+ // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER)\r
+ //\r
+ if (c == '.'){\r
+ if (decimal_digits ('.')){\r
+ is_real = true;\r
+ c = getChar ();\r
+ } else {\r
+ putback ('.');\r
+ number_pos--;\r
+ return adjust_int (-1);\r
+ }\r
+ }\r
+ \r
+ if (c == 'e' || c == 'E'){\r
+ is_real = true;\r
+ if (number_pos == max_number_size)\r
+ Error_NumericConstantTooLong ();\r
+ number_builder [number_pos++] = 'e';\r
+ c = getChar ();\r
+ \r
+ if (c == '+'){\r
+ if (number_pos == max_number_size)\r
+ Error_NumericConstantTooLong ();\r
+ number_builder [number_pos++] = '+';\r
+ c = -1;\r
+ } else if (c == '-') {\r
+ if (number_pos == max_number_size)\r
+ Error_NumericConstantTooLong ();\r
+ number_builder [number_pos++] = '-';\r
+ c = -1;\r
+ } else {\r
+ if (number_pos == max_number_size)\r
+ Error_NumericConstantTooLong ();\r
+ number_builder [number_pos++] = '+';\r
+ }\r
+ \r
+ decimal_digits (c);\r
+ c = getChar ();\r
+ }\r
+\r
+ type = real_type_suffix (c);\r
+ if (type == Token.NONE && !is_real){\r
+ putback (c);\r
+ return adjust_int (c);\r
+ } else \r
+ is_real = true;\r
+\r
+ if (type == Token.NONE){\r
+ putback (c);\r
+ }\r
+ \r
+ if (is_real)\r
+ return adjust_real (type);\r
+\r
+ Console.WriteLine ("This should not be reached");\r
+ throw new Exception ("Is Number should never reach this point");\r
+ }\r
+\r
+ //\r
+ // Accepts exactly count (4 or 8) hex, no more no less\r
+ //\r
+ int getHex (int count, out bool error)\r
+ {\r
+ int [] buffer = new int [8];\r
+ int i;\r
+ int total = 0;\r
+ int c;\r
+ int top = count != -1 ? count : 4;\r
+ \r
+ getChar ();\r
+ error = false;\r
+ for (i = 0; i < top; i++){\r
+ c = getChar ();\r
+ \r
+ if (c >= '0' && c <= '9')\r
+ c = (int) c - (int) '0';\r
+ else if (c >= 'A' && c <= 'F')\r
+ c = (int) c - (int) 'A' + 10;\r
+ else if (c >= 'a' && c <= 'f')\r
+ c = (int) c - (int) 'a' + 10;\r
+ else {\r
+ error = true;\r
+ return 0;\r
+ }\r
+ \r
+ total = (total * 16) + c;\r
+ if (count == -1){\r
+ int p = peekChar ();\r
+ if (p == -1)\r
+ break;\r
+ if (!is_hex ((char)p))\r
+ break;\r
+ }\r
+ }\r
+ return total;\r
+ }\r
+\r
+ int escape (int c)\r
+ {\r
+ bool error;\r
+ int d;\r
+ int v;\r
+\r
+ d = peekChar ();\r
+ if (c != '\\')\r
+ return c;\r
+ \r
+ switch (d){\r
+ case 'a':\r
+ v = '\a'; break;\r
+ case 'b':\r
+ v = '\b'; break;\r
+ case 'n':\r
+ v = '\n'; break;\r
+ case 't':\r
+ v = '\t'; break;\r
+ case 'v':\r
+ v = '\v'; break;\r
+ case 'r':\r
+ v = '\r'; break;\r
+ case '\\':\r
+ v = '\\'; break;\r
+ case 'f':\r
+ v = '\f'; break;\r
+ case '0':\r
+ v = 0; break;\r
+ case '"':\r
+ v = '"'; break;\r
+ case '\'':\r
+ v = '\''; break;\r
+ case 'x':\r
+ v = getHex (-1, out error);\r
+ if (error)\r
+ goto default;\r
+ return v;\r
+ case 'u':\r
+ v = getHex (4, out error);\r
+ if (error)\r
+ goto default;\r
+ return v;\r
+ case 'U':\r
+ v = getHex (8, out error);\r
+ if (error)\r
+ goto default;\r
+ return v;\r
+ default:\r
+ Report.Error (1009, Location, "Unrecognized escape sequence in " + (char)d);\r
+ return d;\r
+ }\r
+ getChar ();\r
+ return v;\r
+ }\r
+\r
+ int getChar ()\r
+ {\r
+ if (putback_char != -1){\r
+ int x = putback_char;\r
+ putback_char = -1;\r
+\r
+ return x;\r
+ }\r
+ return reader.Read ();\r
+ }\r
+\r
+ int peekChar ()\r
+ {\r
+ if (putback_char != -1)\r
+ return putback_char;\r
+ putback_char = reader.Read ();\r
+ return putback_char;\r
+ }\r
+\r
+ int peekChar2 ()\r
+ {\r
+ if (putback_char != -1)\r
+ return putback_char;\r
+ return reader.Peek ();\r
+ }\r
+ \r
+ void putback (int c)\r
+ {\r
+ if (putback_char != -1){\r
+ Console.WriteLine ("Col: " + col);\r
+ Console.WriteLine ("Row: " + line);\r
+ Console.WriteLine ("Name: " + ref_name.Name);\r
+ Console.WriteLine ("Current [{0}] putting back [{1}] ", putback_char, c);\r
+ throw new Exception ("This should not happen putback on putback");\r
+ }\r
+ putback_char = c;\r
+ }\r
+\r
+ public bool advance ()\r
+ {\r
+ return peekChar () != -1;\r
+ }\r
+\r
+ public Object Value {\r
+ get {\r
+ return val;\r
+ }\r
+ }\r
+\r
+ public Object value ()\r
+ {\r
+ return val;\r
+ }\r
+ \r
+ public int token ()\r
+ {\r
+ current_token = xtoken ();\r
+ return current_token;\r
+ }\r
+\r
+ static StringBuilder static_cmd_arg = new System.Text.StringBuilder ();\r
+ \r
+ void get_cmd_arg (out string cmd, out string arg)\r
+ {\r
+ int c;\r
+ \r
+ tokens_seen = false;\r
+ arg = "";\r
+ static_cmd_arg.Length = 0;\r
+ \r
+ while ((c = getChar ()) != -1 && (c != '\n') && (c != ' ') && (c != '\t') && (c != '\r')){\r
+ static_cmd_arg.Append ((char) c);\r
+ }\r
+\r
+ cmd = static_cmd_arg.ToString ();\r
+\r
+ if (c == '\n'){\r
+ line++;\r
+ ref_line++;\r
+ return;\r
+ } else if (c == '\r')\r
+ col = 0;\r
+\r
+ // skip over white space\r
+ while ((c = getChar ()) != -1 && (c != '\n') && ((c == '\r') || (c == ' ') || (c == '\t')))\r
+ ;\r
+\r
+ if (c == '\n'){\r
+ line++;\r
+ ref_line++;\r
+ return;\r
+ } else if (c == '\r'){\r
+ col = 0;\r
+ return;\r
+ }\r
+ \r
+ static_cmd_arg.Length = 0;\r
+ static_cmd_arg.Append ((char) c);\r
+ \r
+ while ((c = getChar ()) != -1 && (c != '\n') && (c != '\r')){\r
+ static_cmd_arg.Append ((char) c);\r
+ }\r
+\r
+ if (c == '\n'){\r
+ line++;\r
+ ref_line++;\r
+ } else if (c == '\r')\r
+ col = 0;\r
+ arg = static_cmd_arg.ToString ().Trim ();\r
+ }\r
+\r
+ //\r
+ // Handles the #line directive\r
+ //\r
+ bool PreProcessLine (string arg)\r
+ {\r
+ if (arg == "")\r
+ return false;\r
+\r
+ if (arg == "default"){\r
+ ref_line = line;\r
+ ref_name = file_name;\r
+ Location.Push (ref_name);\r
+ return true;\r
+ }\r
+ \r
+ try {\r
+ int pos;\r
+\r
+ if ((pos = arg.IndexOf (' ')) != -1 && pos != 0){\r
+ ref_line = System.Int32.Parse (arg.Substring (0, pos));\r
+ pos++;\r
+ \r
+ char [] quotes = { '\"' };\r
+ \r
+ string name = arg.Substring (pos). Trim (quotes);\r
+ ref_name = Location.LookupFile (name);\r
+ Location.Push (ref_name);\r
+ } else {\r
+ ref_line = System.Int32.Parse (arg);\r
+ }\r
+ } catch {\r
+ return false;\r
+ }\r
+ \r
+ return true;\r
+ }\r
+\r
+ //\r
+ // Handles #define and #undef\r
+ //\r
+ void PreProcessDefinition (bool is_define, string arg)\r
+ {\r
+ if (arg == "" || arg == "true" || arg == "false"){\r
+ Report.Error (1001, Location, "Missing identifer to pre-processor directive");\r
+ return;\r
+ }\r
+\r
+ char[] whitespace = { ' ', '\t' };\r
+ if (arg.IndexOfAny (whitespace) != -1){\r
+ Report.Error (1025, Location, "Single-line comment or end-of-line expected");\r
+ return;\r
+ }\r
+\r
+ foreach (char c in arg){\r
+ if (!Char.IsLetter (c) && (c != '_')){\r
+ Report.Error (1001, Location, "Identifier expected");\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (is_define){\r
+ if (defines == null)\r
+ defines = new Hashtable ();\r
+ define (arg);\r
+ } else {\r
+ if (defines == null)\r
+ return;\r
+ if (defines.Contains (arg))\r
+ defines.Remove (arg);\r
+ }\r
+ }\r
+\r
+ bool eval_val (string s)\r
+ {\r
+ if (s == "true")\r
+ return true;\r
+ if (s == "false")\r
+ return false;\r
+ \r
+ if (defines == null)\r
+ return false;\r
+ if (defines.Contains (s))\r
+ return true;\r
+\r
+ return false;\r
+ }\r
+\r
+ bool pp_primary (ref string s)\r
+ {\r
+ s = s.Trim ();\r
+ int len = s.Length;\r
+\r
+ if (len > 0){\r
+ char c = s [0];\r
+ \r
+ if (c == '('){\r
+ s = s.Substring (1);\r
+ bool val = pp_expr (ref s);\r
+ if (s.Length > 0 && s [0] == ')'){\r
+ s = s.Substring (1);\r
+ return val;\r
+ }\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ \r
+ if (is_identifier_start_character (c)){\r
+ int j = 1;\r
+\r
+ while (j < len){\r
+ c = s [j];\r
+ \r
+ if (is_identifier_part_character (c)){\r
+ j++;\r
+ continue;\r
+ }\r
+ bool v = eval_val (s.Substring (0, j));\r
+ s = s.Substring (j);\r
+ return v;\r
+ }\r
+ bool vv = eval_val (s);\r
+ s = "";\r
+ return vv;\r
+ }\r
+ }\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ \r
+ bool pp_unary (ref string s)\r
+ {\r
+ s = s.Trim ();\r
+ int len = s.Length;\r
+\r
+ if (len > 0){\r
+ if (s [0] == '!'){\r
+ if (len > 1 && s [1] == '='){\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ s = s.Substring (1);\r
+ return ! pp_primary (ref s);\r
+ } else\r
+ return pp_primary (ref s);\r
+ } else {\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ bool pp_eq (ref string s)\r
+ {\r
+ bool va = pp_unary (ref s);\r
+\r
+ s = s.Trim ();\r
+ int len = s.Length;\r
+ if (len > 0){\r
+ if (s [0] == '='){\r
+ if (len > 2 && s [1] == '='){\r
+ s = s.Substring (2);\r
+ return va == pp_unary (ref s);\r
+ } else {\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ } else if (s [0] == '!' && len > 1 && s [1] == '='){\r
+ s = s.Substring (2);\r
+\r
+ return va != pp_unary (ref s);\r
+\r
+ } \r
+ }\r
+\r
+ return va;\r
+ \r
+ }\r
+ \r
+ bool pp_and (ref string s)\r
+ {\r
+ bool va = pp_eq (ref s);\r
+\r
+ s = s.Trim ();\r
+ int len = s.Length;\r
+ if (len > 0){\r
+ if (s [0] == '&'){\r
+ if (len > 2 && s [1] == '&'){\r
+ s = s.Substring (2);\r
+ return (va & pp_eq (ref s));\r
+ } else {\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ } \r
+ }\r
+ return va;\r
+ }\r
+ \r
+ //\r
+ // Evaluates an expression for `#if' or `#elif'\r
+ //\r
+ bool pp_expr (ref string s)\r
+ {\r
+ bool va = pp_and (ref s);\r
+ s = s.Trim ();\r
+ int len = s.Length;\r
+ if (len > 0){\r
+ char c = s [0];\r
+ \r
+ if (c == '|'){\r
+ if (len > 2 && s [1] == '|'){\r
+ s = s.Substring (2);\r
+ return va | pp_expr (ref s);\r
+ } else {\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+ } \r
+ }\r
+ \r
+ return va;\r
+ }\r
+\r
+ bool eval (string s)\r
+ {\r
+ bool v = pp_expr (ref s);\r
+ s = s.Trim ();\r
+ if (s.Length != 0){\r
+ Error_InvalidDirective ();\r
+ return false;\r
+ }\r
+\r
+ return v;\r
+ }\r
+ \r
+ void Error_InvalidDirective ()\r
+ {\r
+ Report.Error (1517, Location, "Invalid pre-processor directive");\r
+ }\r
+\r
+ void Error_UnexpectedDirective (string extra)\r
+ {\r
+ Report.Error (\r
+ 1028, Location,\r
+ "Unexpected processor directive (" + extra + ")");\r
+ }\r
+\r
+ void Error_TokensSeen ()\r
+ {\r
+ Report.Error (\r
+ 1032, Location,\r
+ "Cannot define or undefine pre-processor symbols after a token in the file");\r
+ }\r
+ \r
+ //\r
+ // if true, then the code continues processing the code\r
+ // if false, the code stays in a loop until another directive is\r
+ // reached.\r
+ //\r
+ bool handle_preprocessing_directive (bool caller_is_taking)\r
+ {\r
+ char [] blank = { ' ', '\t' };\r
+ string cmd, arg;\r
+ bool region_directive = false;\r
+\r
+ get_cmd_arg (out cmd, out arg);\r
+\r
+ // Eat any trailing whitespaces and single-line comments\r
+ if (arg.IndexOf ("//") != -1)\r
+ arg = arg.Substring (0, arg.IndexOf ("//"));\r
+ arg = arg.TrimEnd (' ', '\t');\r
+\r
+ //\r
+ // The first group of pre-processing instructions is always processed\r
+ //\r
+ switch (cmd){\r
+ case "line":\r
+ if (!PreProcessLine (arg))\r
+ Report.Error (\r
+ 1576, Location,\r
+ "Argument to #line directive is missing or invalid");\r
+ return true;\r
+\r
+ case "region":\r
+ region_directive = true;\r
+ arg = "true";\r
+ goto case "if";\r
+\r
+ case "endregion":\r
+ region_directive = true;\r
+ goto case "endif";\r
+ \r
+ case "if":\r
+ if (arg == ""){\r
+ Error_InvalidDirective ();\r
+ return true;\r
+ }\r
+ bool taking = false;\r
+ if (ifstack == null)\r
+ ifstack = new Stack ();\r
+\r
+ if (ifstack.Count == 0){\r
+ taking = true;\r
+ } else {\r
+ int state = (int) ifstack.Peek ();\r
+ if ((state & TAKING) != 0)\r
+ taking = true;\r
+ }\r
+\r
+ if (eval (arg) && taking){\r
+ int push = TAKING | TAKEN_BEFORE | PARENT_TAKING;\r
+ if (region_directive)\r
+ push |= REGION;\r
+ ifstack.Push (push);\r
+ return true;\r
+ } else {\r
+ int push = (taking ? PARENT_TAKING : 0);\r
+ if (region_directive)\r
+ push |= REGION;\r
+ ifstack.Push (push);\r
+ return false;\r
+ }\r
+ \r
+ case "endif":\r
+ if (ifstack == null || ifstack.Count == 0){\r
+ Error_UnexpectedDirective ("no #if for this #endif");\r
+ return true;\r
+ } else {\r
+ int pop = (int) ifstack.Pop ();\r
+ \r
+ if (region_directive && ((pop & REGION) == 0))\r
+ Report.Error (1027, Location, "#endif directive expected");\r
+ else if (!region_directive && ((pop & REGION) != 0))\r
+ Report.Error (1038, Location, "#endregion directive expected");\r
+ \r
+ if (ifstack.Count == 0)\r
+ return true;\r
+ else {\r
+ int state = (int) ifstack.Peek ();\r
+\r
+ if ((state & TAKING) != 0)\r
+ return true;\r
+ else\r
+ return false;\r
+ }\r
+ }\r
+\r
+ case "elif":\r
+ if (ifstack == null || ifstack.Count == 0){\r
+ Error_UnexpectedDirective ("no #if for this #elif");\r
+ return true;\r
+ } else {\r
+ int state = (int) ifstack.Peek ();\r
+\r
+ if ((state & REGION) != 0) {\r
+ Report.Error (1038, Location, "#endregion directive expected");\r
+ return true;\r
+ }\r
+\r
+ if ((state & ELSE_SEEN) != 0){\r
+ Error_UnexpectedDirective ("#elif not valid after #else");\r
+ return true;\r
+ }\r
+\r
+ if ((state & (TAKEN_BEFORE | TAKING)) != 0)\r
+ return false;\r
+\r
+ if (eval (arg) && ((state & PARENT_TAKING) != 0)){\r
+ state = (int) ifstack.Pop ();\r
+ ifstack.Push (state | TAKING | TAKEN_BEFORE);\r
+ return true;\r
+ } else \r
+ return false;\r
+ }\r
+\r
+ case "else":\r
+ if (ifstack == null || ifstack.Count == 0){\r
+ Report.Error (\r
+ 1028, Location,\r
+ "Unexpected processor directive (no #if for this #else)");\r
+ return true;\r
+ } else {\r
+ int state = (int) ifstack.Peek ();\r
+\r
+ if ((state & REGION) != 0) {\r
+ Report.Error (1038, Location, "#endregion directive expected");\r
+ return true;\r
+ }\r
+\r
+ if ((state & ELSE_SEEN) != 0){\r
+ Error_UnexpectedDirective ("#else within #else");\r
+ return true;\r
+ }\r
+\r
+ ifstack.Pop ();\r
+\r
+ bool ret;\r
+ if ((state & TAKEN_BEFORE) == 0){\r
+ ret = ((state & PARENT_TAKING) != 0);\r
+ } else\r
+ ret = false;\r
+ \r
+ if (ret)\r
+ state |= TAKING;\r
+ else\r
+ state &= ~TAKING;\r
+ \r
+ ifstack.Push (state | ELSE_SEEN);\r
+ \r
+ return ret;\r
+ }\r
+ }\r
+\r
+ //\r
+ // These are only processed if we are in a `taking' block\r
+ //\r
+ if (!caller_is_taking)\r
+ return false;\r
+ \r
+ switch (cmd){\r
+ case "define":\r
+ if (any_token_seen){\r
+ Error_TokensSeen ();\r
+ return true;\r
+ }\r
+ PreProcessDefinition (true, arg);\r
+ return true;\r
+\r
+ case "undef":\r
+ if (any_token_seen){\r
+ Error_TokensSeen ();\r
+ return true;\r
+ }\r
+ PreProcessDefinition (false, arg);\r
+ return true;\r
+\r
+ case "error":\r
+ Report.Error (1029, Location, "#error: '" + arg + "'");\r
+ return true;\r
+\r
+ case "warning":\r
+ Report.Warning (1030, Location, "#warning: '" + arg + "'");\r
+ return true;\r
+ }\r
+\r
+ Report.Error (1024, Location, "Preprocessor directive expected (got: " + cmd + ")");\r
+ return true;\r
+\r
+ }\r
+\r
+ private int consume_string (bool quoted) \r
+ {\r
+ int c;\r
+ string_builder.Length = 0;\r
+ \r
+ while ((c = getChar ()) != -1){\r
+ if (c == '"'){\r
+ if (quoted && peekChar () == '"'){\r
+ string_builder.Append ((char) c);\r
+ getChar ();\r
+ continue;\r
+ } else {\r
+ val = string_builder.ToString ();\r
+ return Token.LITERAL_STRING;\r
+ }\r
+ }\r
+\r
+ if (c == '\n'){\r
+ if (!quoted)\r
+ Report.Error (1010, Location, "Newline in constant");\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ } else\r
+ col++;\r
+\r
+ if (!quoted){\r
+ c = escape (c);\r
+ if (c == -1)\r
+ return Token.ERROR;\r
+ }\r
+ string_builder.Append ((char) c);\r
+ }\r
+\r
+ Report.Error (1039, Location, "Unterminated string literal");\r
+ return Token.EOF;\r
+ }\r
+\r
+ private int consume_identifier (int s, bool quoted) \r
+ {\r
+ int pos = 1;\r
+ int c;\r
+ \r
+ id_builder [0] = (char) s;\r
+ \r
+ while ((c = reader.Read ()) != -1) {\r
+ if (is_identifier_part_character ((char) c)){\r
+ if (pos == max_id_size){\r
+ Report.Error (645, Location, "Identifier too long (limit is 512 chars)");\r
+ return Token.ERROR;\r
+ }\r
+ \r
+ id_builder [pos++] = (char) c;\r
+ putback_char = -1;\r
+ col++;\r
+ } else {\r
+ putback_char = c;\r
+ break;\r
+ }\r
+ }\r
+\r
+ string ids = new String (id_builder, 0, pos);\r
+\r
+ //\r
+ // Optimization: avoids doing the keyword lookup\r
+ // on uppercase letters and _\r
+ //\r
+ if (s >= 'a'){\r
+ int keyword = GetKeyword (ids);\r
+ if (keyword == -1 || quoted){\r
+ val = ids;\r
+ return Token.IDENTIFIER;\r
+ }\r
+ return keyword;\r
+ }\r
+ val = ids;\r
+ return Token.IDENTIFIER;\r
+ }\r
+ \r
+ public int xtoken ()\r
+ {\r
+ int t;\r
+ bool doread = false;\r
+ int c;\r
+\r
+ val = null;\r
+ // optimization: eliminate col and implement #directive semantic correctly.\r
+ for (;(c = getChar ()) != -1; col++) {\r
+ if (c == ' ' || c == '\t' || c == '\f' || c == '\v' || c == '\r' || c == 0xa0){\r
+ \r
+ if (c == '\t')\r
+ col = (((col + 8) / 8) * 8) - 1;\r
+ continue;\r
+ }\r
+\r
+ // Handle double-slash comments.\r
+ if (c == '/'){\r
+ int d = peekChar ();\r
+ \r
+ if (d == '/'){\r
+ getChar ();\r
+ while ((d = getChar ()) != -1 && (d != '\n') && d != '\r')\r
+ col++;\r
+ if (d == '\n'){\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ }\r
+ any_token_seen |= tokens_seen;\r
+ tokens_seen = false;\r
+ continue;\r
+ } else if (d == '*'){\r
+ getChar ();\r
+\r
+ while ((d = getChar ()) != -1){\r
+ if (d == '*' && peekChar () == '/'){\r
+ getChar ();\r
+ col++;\r
+ break;\r
+ }\r
+ if (d == '\n'){\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ any_token_seen |= tokens_seen;\r
+ tokens_seen = false;\r
+ }\r
+ }\r
+ continue;\r
+ }\r
+ goto is_punct_label;\r
+ }\r
+\r
+ \r
+ if (is_identifier_start_character ((char)c)){\r
+ tokens_seen = true;\r
+ return consume_identifier (c, false);\r
+ }\r
+\r
+ is_punct_label:\r
+ if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){\r
+ tokens_seen = true;\r
+ if (doread){\r
+ getChar ();\r
+ col++;\r
+ }\r
+ return t;\r
+ }\r
+\r
+ // white space\r
+ if (c == '\n'){\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ any_token_seen |= tokens_seen;\r
+ tokens_seen = false;\r
+ continue;\r
+ }\r
+\r
+ if (c >= '0' && c <= '9'){\r
+ tokens_seen = true;\r
+ return is_number (c);\r
+ }\r
+\r
+ if (c == '.'){\r
+ tokens_seen = true;\r
+ int peek = peekChar ();\r
+ if (peek >= '0' && peek <= '9')\r
+ return is_number (c);\r
+ return Token.DOT;\r
+ }\r
+ \r
+ /* For now, ignore pre-processor commands */\r
+ // FIXME: In C# the '#' is not limited to appear\r
+ // on the first column.\r
+ if (c == '#' && !tokens_seen){\r
+ bool cont = true;\r
+ \r
+ start_again:\r
+ \r
+ cont = handle_preprocessing_directive (cont);\r
+\r
+ if (cont){\r
+ col = 0;\r
+ continue;\r
+ }\r
+ col = 1;\r
+\r
+ bool skipping = false;\r
+ for (;(c = getChar ()) != -1; col++){\r
+ if (c == '\n'){\r
+ col = 0;\r
+ line++;\r
+ ref_line++;\r
+ skipping = false;\r
+ } else if (c == ' ' || c == '\t' || c == '\v' || c == '\r' || c == 0xa0)\r
+ continue;\r
+ else if (c != '#')\r
+ skipping = true;\r
+ if (c == '#' && !skipping)\r
+ goto start_again;\r
+ }\r
+ any_token_seen |= tokens_seen;\r
+ tokens_seen = false;\r
+ if (c == -1)\r
+ Report.Error (1027, Location, "#endif/#endregion expected");\r
+ continue;\r
+ }\r
+ \r
+ if (c == '"') \r
+ return consume_string (false);\r
+\r
+ if (c == '\''){\r
+ c = getChar ();\r
+ tokens_seen = true;\r
+ if (c == '\''){\r
+ error_details = "Empty character literal";\r
+ Report.Error (1011, Location, error_details);\r
+ return Token.ERROR;\r
+ }\r
+ c = escape (c);\r
+ if (c == -1)\r
+ return Token.ERROR;\r
+ val = new System.Char ();\r
+ val = (char) c;\r
+ c = getChar ();\r
+\r
+ if (c != '\''){\r
+ error_details = "Too many characters in character literal";\r
+ Report.Error (1012, Location, error_details);\r
+\r
+ // Try to recover, read until newline or next "'"\r
+ while ((c = getChar ()) != -1){\r
+ if (c == '\n' || c == '\''){\r
+ line++;\r
+ ref_line++;\r
+ col = 0;\r
+ break;\r
+ } else\r
+ col++;\r
+ \r
+ }\r
+ return Token.ERROR;\r
+ }\r
+ return Token.LITERAL_CHARACTER;\r
+ }\r
+ \r
+ if (c == '@') {\r
+ c = getChar ();\r
+ if (c == '"') {\r
+ tokens_seen = true;\r
+ return consume_string (true);\r
+ } else if (is_identifier_start_character ((char) c)){\r
+ return consume_identifier (c, true);\r
+ } else {\r
+ Report.Error (1033, Location, "'@' must be followed by string constant or identifier");\r
+ }\r
+ }\r
+\r
+ error_details = ((char)c).ToString ();\r
+ \r
+ return Token.ERROR;\r
+ }\r
+\r
+ return Token.EOF;\r
+ }\r
+\r
+ public void cleanup ()\r
+ {\r
+ if (ifstack != null && ifstack.Count >= 1) {\r
+ int state = (int) ifstack.Pop ();\r
+ if ((state & REGION) != 0)\r
+ Report.Error (1038, "#endregion directive expected");\r
+ else \r
+ Report.Error (1027, "#endif directive expected");\r
+ }\r
+ \r
+ }\r
+\r
+ }\r
+}\r
+\r
--- /dev/null
+//
+// decl.cs: Declaration base class for structs, classes, enums and interfaces.
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+//
+// TODO: Move the method verification stuff from the class.cs and interface.cs here
+//
+
+using System;
+using System.Collections;
+using System.Reflection.Emit;
+using System.Reflection;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Base representation for members. This is only used to keep track
+ /// of Name, Location and Modifier flags.
+ /// </summary>
+ public abstract class MemberCore {
+ /// <summary>
+ /// Public name
+ /// </summary>
+ public string Name;
+
+ /// <summary>
+ /// Modifier flags that the user specified in the source code
+ /// </summary>
+ public int ModFlags;
+
+ /// <summary>
+ /// Location where this declaration happens
+ /// </summary>
+ public readonly Location Location;
+
+ public MemberCore (string name, Location loc)
+ {
+ Name = name;
+ Location = loc;
+ }
+
+ protected void WarningNotHiding (TypeContainer parent)
+ {
+ Report.Warning (
+ 109, Location,
+ "The member " + parent.MakeName (Name) + " does not hide an " +
+ "inherited member. The keyword new is not required");
+
+ }
+
+ void Error_CannotChangeAccessModifiers (TypeContainer parent, MethodInfo parent_method,
+ string name)
+ {
+ //
+ // FIXME: report the old/new permissions?
+ //
+ Report.Error (
+ 507, Location, parent.MakeName (Name) +
+ ": can't change the access modifiers when overriding inherited " +
+ "member `" + name + "'");
+ }
+
+ //
+ // Performs various checks on the MethodInfo `mb' regarding the modifier flags
+ // that have been defined.
+ //
+ // `name' is the user visible name for reporting errors (this is used to
+ // provide the right name regarding method names and properties)
+ //
+ protected bool CheckMethodAgainstBase (TypeContainer parent, MethodAttributes my_attrs,
+ MethodInfo mb, string name)
+ {
+ bool ok = true;
+
+ if ((ModFlags & Modifiers.OVERRIDE) != 0){
+ if (!(mb.IsAbstract || mb.IsVirtual)){
+ Report.Error (
+ 506, Location, parent.MakeName (Name) +
+ ": cannot override inherited member `" +
+ name + "' because it is not " +
+ "virtual, abstract or override");
+ ok = false;
+ }
+
+ // Now we check that the overriden method is not final
+
+ if (mb.IsFinal) {
+ // This happens when implementing interface methods.
+ if (mb.IsHideBySig && mb.IsVirtual) {
+ Report.Error (
+ 506, Location, parent.MakeName (Name) +
+ ": cannot override inherited member `" +
+ name + "' because it is not " +
+ "virtual, abstract or override");
+ } else
+ Report.Error (239, Location, parent.MakeName (Name) + " : cannot " +
+ "override inherited member `" + name +
+ "' because it is sealed.");
+ ok = false;
+ }
+ //
+ // Check that the permissions are not being changed
+ //
+ MethodAttributes thisp = my_attrs & MethodAttributes.MemberAccessMask;
+ MethodAttributes parentp = mb.Attributes & MethodAttributes.MemberAccessMask;
+
+ //
+ // special case for "protected internal"
+ //
+
+ if ((parentp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){
+ //
+ // when overriding protected internal, the method can be declared
+ // protected internal only within the same assembly
+ //
+
+ if ((thisp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){
+ if (parent.TypeBuilder.Assembly != mb.DeclaringType.Assembly){
+ //
+ // assemblies differ - report an error
+ //
+
+ Error_CannotChangeAccessModifiers (parent, mb, name);
+ ok = false;
+ } else if (thisp != parentp) {
+ //
+ // same assembly, but other attributes differ - report an error
+ //
+
+ Error_CannotChangeAccessModifiers (parent, mb, name);
+ ok = false;
+ };
+ } else if ((thisp & MethodAttributes.Family) != MethodAttributes.Family) {
+ //
+ // if it's not "protected internal", it must be "protected"
+ //
+
+ Error_CannotChangeAccessModifiers (parent, mb, name);
+ ok = false;
+ } else if (parent.TypeBuilder.Assembly == mb.DeclaringType.Assembly) {
+ //
+ // protected within the same assembly - an error
+ //
+ Error_CannotChangeAccessModifiers (parent, mb, name);
+ ok = false;
+ } else if ((thisp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem)) !=
+ (parentp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem))) {
+ //
+ // protected ok, but other attributes differ - report an error
+ //
+ Error_CannotChangeAccessModifiers (parent, mb, name);
+ ok = false;
+ }
+ } else {
+ if (thisp != parentp){
+ Error_CannotChangeAccessModifiers (parent, mb, name);
+ ok = false;
+ }
+ }
+ }
+
+ if (mb.IsVirtual || mb.IsAbstract){
+ if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
+ if (Name != "Finalize"){
+ Report.Warning (
+ 114, 2, Location, parent.MakeName (Name) +
+ " hides inherited member `" + name +
+ "'. To make the current member override that " +
+ "implementation, add the override keyword, " +
+ "otherwise use the new keyword");
+ ModFlags |= Modifiers.NEW;
+ }
+ }
+ } else {
+ if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){
+ if (Name != "Finalize"){
+ Report.Warning (
+ 108, 1, Location, "The keyword new is required on " +
+ parent.MakeName (Name) + " because it hides " +
+ "inherited member `" + name + "'");
+ ModFlags |= Modifiers.NEW;
+ }
+ }
+ }
+
+ return ok;
+ }
+
+ public abstract bool Define (TypeContainer parent);
+
+ //
+ // Whehter is it ok to use an unsafe pointer in this type container
+ //
+ public bool UnsafeOK (DeclSpace parent)
+ {
+ //
+ // First check if this MemberCore modifier flags has unsafe set
+ //
+ if ((ModFlags & Modifiers.UNSAFE) != 0)
+ return true;
+
+ if (parent.UnsafeContext)
+ return true;
+
+ Expression.UnsafeError (Location);
+ return false;
+ }
+ }
+
+ //
+ // FIXME: This is temporary outside DeclSpace, because I have to fix a bug
+ // in MCS that makes it fail the lookup for the enum
+ //
+
+ /// <summary>
+ /// The result value from adding an declaration into
+ /// a struct or a class
+ /// </summary>
+ public enum AdditionResult {
+ /// <summary>
+ /// The declaration has been successfully
+ /// added to the declation space.
+ /// </summary>
+ Success,
+
+ /// <summary>
+ /// The symbol has already been defined.
+ /// </summary>
+ NameExists,
+
+ /// <summary>
+ /// Returned if the declation being added to the
+ /// name space clashes with its container name.
+ ///
+ /// The only exceptions for this are constructors
+ /// and static constructors
+ /// </summary>
+ EnclosingClash,
+
+ /// <summary>
+ /// Returned if a constructor was created (because syntactically
+ /// it looked like a constructor) but was not (because the name
+ /// of the method is not the same as the container class
+ /// </summary>
+ NotAConstructor,
+
+ /// <summary>
+ /// This is only used by static constructors to emit the
+ /// error 111, but this error for other things really
+ /// happens at another level for other functions.
+ /// </summary>
+ MethodExists,
+
+ /// <summary>
+ /// Some other error.
+ /// </summary>
+ Error
+ }
+
+ /// <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>
+ /// This variable tracks whether we have Closed the type
+ /// </summary>
+ public bool Created = false;
+
+ //
+ // This is the namespace in which this typecontainer
+ // was declared. We use this to resolve names.
+ //
+ public NamespaceEntry Namespace;
+
+ public Hashtable Cache = new Hashtable ();
+
+ public string Basename;
+
+ /// <summary>
+ /// defined_names is used for toplevel objects
+ /// </summary>
+ protected Hashtable defined_names;
+
+ TypeContainer parent;
+
+ public DeclSpace (TypeContainer parent, string name, Location l)
+ : base (name, l)
+ {
+ Basename = name.Substring (1 + name.LastIndexOf ('.'));
+ defined_names = new Hashtable ();
+ this.parent = parent;
+ }
+
+ /// <summary>
+ /// Returns a status code based purely on the name
+ /// of the member being added
+ /// </summary>
+ protected AdditionResult IsValid (string basename, string name)
+ {
+ if (basename == Basename)
+ return AdditionResult.EnclosingClash;
+
+ if (defined_names.Contains (name))
+ return AdditionResult.NameExists;
+
+ return AdditionResult.Success;
+ }
+
+ public static int length;
+ public static int small;
+
+ /// <summary>
+ /// Introduce @name into this declaration space and
+ /// associates it with the object @o. Note that for
+ /// methods this will just point to the first method. o
+ /// </summary>
+ protected void DefineName (string name, object o)
+ {
+ defined_names.Add (name, o);
+
+#if DEBUGME
+ int p = name.LastIndexOf (".");
+ int l = name.Length;
+ length += l;
+ small += l -p;
+#endif
+ }
+
+ /// <summary>
+ /// Returns the object associated with a given name in the declaration
+ /// space. This is the inverse operation of `DefineName'
+ /// </summary>
+ public object GetDefinition (string name)
+ {
+ return defined_names [name];
+ }
+
+ bool in_transit = false;
+
+ /// <summary>
+ /// This function is used to catch recursive definitions
+ /// in declarations.
+ /// </summary>
+ public bool InTransit {
+ get {
+ return in_transit;
+ }
+
+ set {
+ in_transit = value;
+ }
+ }
+
+ public TypeContainer Parent {
+ get {
+ return parent;
+ }
+ }
+
+ /// <summary>
+ /// Looks up the alias for the name
+ /// </summary>
+ public string LookupAlias (string name)
+ {
+ if (Namespace != null)
+ return Namespace.LookupAlias (name);
+ else
+ return null;
+ }
+
+ //
+ // 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 {
+ if (parent != null){
+ if (parent.parent == null)
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public virtual void CloseType ()
+ {
+ if (!Created){
+ 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
+ }
+ Created = true;
+ }
+ }
+
+ /// <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 abstract bool DefineMembers (TypeContainer parent);
+
+ //
+ // Whether this is an `unsafe context'
+ //
+ public bool UnsafeContext {
+ get {
+ if ((ModFlags & Modifiers.UNSAFE) != 0)
+ return true;
+ if (parent != null)
+ return parent.UnsafeContext;
+ return false;
+ }
+ }
+
+ public static string MakeFQN (string nsn, string name)
+ {
+ if (nsn == "")
+ return name;
+ return String.Concat (nsn, ".", name);
+ }
+
+ EmitContext type_resolve_ec;
+ EmitContext GetTypeResolveEmitContext (TypeContainer parent, Location loc)
+ {
+ type_resolve_ec = new EmitContext (parent, this, loc, null, null, ModFlags, false);
+ type_resolve_ec.ResolvingTypeTree = true;
+
+ return type_resolve_ec;
+ }
+
+ // <summary>
+ // Looks up the type, as parsed into the expression `e'
+ // </summary>
+ public Type ResolveType (Expression e, bool silent, Location loc)
+ {
+ if (type_resolve_ec == null)
+ type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
+ type_resolve_ec.loc = loc;
+ type_resolve_ec.ContainerType = TypeBuilder;
+
+ int errors = Report.Errors;
+ Expression d = e.ResolveAsTypeTerminal (type_resolve_ec);
+
+ if (d == null || d.eclass != ExprClass.Type){
+ if (!silent && errors == Report.Errors){
+ Report.Error (246, loc, "Cannot find type `"+ e.ToString () +"'");
+ }
+ return null;
+ }
+
+ if (!CheckAccessLevel (d.Type)) {
+ Report. Error (122, loc, "`" + d.Type + "' " +
+ "is inaccessible because of its protection level");
+ return null;
+ }
+
+ return d.Type;
+ }
+
+ // <summary>
+ // Resolves the expression `e' for a type, and will recursively define
+ // types.
+ // </summary>
+ public Expression ResolveTypeExpr (Expression e, bool silent, Location loc)
+ {
+ if (type_resolve_ec == null)
+ type_resolve_ec = GetTypeResolveEmitContext (parent, loc);
+ type_resolve_ec.loc = loc;
+ type_resolve_ec.ContainerType = TypeBuilder;
+
+ Expression d = e.ResolveAsTypeTerminal (type_resolve_ec);
+
+ if (d == null || d.eclass != ExprClass.Type){
+ if (!silent){
+ Report.Error (246, loc, "Cannot find type `"+ e +"'");
+ }
+ return null;
+ }
+
+ return d;
+ }
+
+ public bool CheckAccessLevel (Type check_type)
+ {
+ if (check_type == TypeBuilder)
+ return true;
+
+ 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:
+ //
+ // This test should probably use the declaringtype.
+ //
+ if (check_type.Assembly == TypeBuilder.Assembly){
+ return true;
+ }
+ return false;
+
+ case TypeAttributes.NestedPublic:
+ return true;
+
+ case TypeAttributes.NestedPrivate:
+ string check_type_name = check_type.FullName;
+ string type_name = TypeBuilder.FullName;
+
+ int cio = check_type_name.LastIndexOf ("+");
+ string container = check_type_name.Substring (0, cio);
+
+ //
+ // Check if the check_type is a nested class of the current type
+ //
+ if (check_type_name.StartsWith (type_name + "+")){
+ return true;
+ }
+
+ if (type_name.StartsWith (container)){
+ return true;
+ }
+
+ return false;
+
+ case TypeAttributes.NestedFamily:
+ //
+ // Only accessible to methods in current type or any subtypes
+ //
+ return FamilyAccessible (check_type);
+
+ case TypeAttributes.NestedFamANDAssem:
+ return (check_type.Assembly == TypeBuilder.Assembly) &&
+ FamilyAccessible (check_type);
+
+ case TypeAttributes.NestedFamORAssem:
+ return (check_type.Assembly == TypeBuilder.Assembly) ||
+ FamilyAccessible (check_type);
+
+ case TypeAttributes.NestedAssembly:
+ return check_type.Assembly == TypeBuilder.Assembly;
+ }
+
+ Console.WriteLine ("HERE: " + check_attr);
+ return false;
+
+ }
+
+ protected bool FamilyAccessible (Type check_type)
+ {
+ Type declaring = check_type.DeclaringType;
+ if (TypeBuilder.IsSubclassOf (declaring))
+ return true;
+
+ string check_type_name = check_type.FullName;
+ string type_name = TypeBuilder.FullName;
+
+ int cio = check_type_name.LastIndexOf ("+");
+ string container = check_type_name.Substring (0, cio);
+
+ //
+ // Check if the check_type is a nested class of the current type
+ //
+ if (check_type_name.StartsWith (container + "+"))
+ return true;
+
+ return false;
+ }
+
+
+ Type LookupInterfaceOrClass (string ns, string name, out bool error)
+ {
+ DeclSpace parent;
+ Type t;
+
+ error = false;
+
+ name = MakeFQN (ns, name);
+
+ t = TypeManager.LookupType (name);
+ if (t != null)
+ return t;
+
+ parent = (DeclSpace) RootContext.Tree.Decls [name];
+ if (parent == null)
+ return null;
+
+ t = parent.DefineType ();
+ if (t == null){
+ Report.Error (146, Location, "Class definition is circular: `"+name+"'");
+ error = true;
+ return null;
+ }
+ return t;
+ }
+
+ public static void Error_AmbiguousTypeReference (Location loc, string name, Type t1, Type t2)
+ {
+ Report.Error (104, loc,
+ String.Format ("`{0}' is an ambiguous reference ({1} or {2}) ", name,
+ t1.FullName, t2.FullName));
+ }
+
+ /// <summary>
+ /// GetType is used to resolve type names at the DeclSpace level.
+ /// Use this to lookup class/struct bases, interface bases or
+ /// delegate type references
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Contrast this to LookupType which is used inside method bodies to
+ /// lookup types that have already been defined. GetType is used
+ /// during the tree resolution process and potentially define
+ /// recursively the type
+ /// </remarks>
+ public Type FindType (Location loc, string name)
+ {
+ Type t;
+ bool error;
+
+ //
+ // For the case the type we are looking for is nested within this one
+ // or is in any base class
+ //
+ DeclSpace containing_ds = this;
+
+ while (containing_ds != null){
+ Type container_type = containing_ds.TypeBuilder;
+ Type current_type = container_type;
+
+ while (current_type != null) {
+ string pre = current_type.FullName;
+
+ t = LookupInterfaceOrClass (pre, name, out error);
+ if (error)
+ return null;
+
+ if ((t != null) && containing_ds.CheckAccessLevel (t))
+ return t;
+
+ current_type = current_type.BaseType;
+ }
+ containing_ds = containing_ds.Parent;
+ }
+
+ //
+ // Attempt to lookup the class on our namespace and all it's implicit parents
+ //
+ for (NamespaceEntry ns = Namespace; ns != null; ns = ns.ImplicitParent) {
+ t = LookupInterfaceOrClass (ns.Name, name, out error);
+ if (error)
+ return null;
+
+ if (t != null)
+ return t;
+ }
+
+ //
+ // Attempt to do a direct unqualified lookup
+ //
+ t = LookupInterfaceOrClass ("", name, out error);
+ if (error)
+ return null;
+
+ if (t != null)
+ return t;
+
+ //
+ // Attempt to lookup the class on any of the `using'
+ // namespaces
+ //
+
+ for (NamespaceEntry ns = Namespace; ns != null; ns = ns.Parent){
+
+ t = LookupInterfaceOrClass (ns.Name, name, out error);
+ if (error)
+ return null;
+
+ if (t != null)
+ return t;
+
+ //
+ // Now check the using clause list
+ //
+ Type match = null;
+ foreach (Namespace using_ns in ns.GetUsingTable ()) {
+ match = LookupInterfaceOrClass (using_ns.Name, name, out error);
+ if (error)
+ return null;
+
+ if (match != null){
+ if (t != null){
+ if (CheckAccessLevel (match)) {
+ Error_AmbiguousTypeReference (loc, name, t, match);
+ return null;
+ }
+ continue;
+ }
+
+ t = match;
+ }
+ }
+ if (t != null)
+ return t;
+ }
+
+ //Report.Error (246, Location, "Can not find type `"+name+"'");
+ return null;
+ }
+
+ /// <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;
+ }
+ }
+
+ /// <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 parent 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 parent class.
+ /// </summary>
+ IMemberContainer Parent {
+ 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;
+ protected Hashtable interface_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);
+
+ interface_hash = new Hashtable ();
+
+ // If we have a parent class (we have a parent class unless we're
+ // TypeManager.object_type), we deep-copy its MemberCache here.
+ if (Container.Parent != null) {
+ member_hash = SetupCache (Container.Parent.MemberCache);
+ } else if (Container.IsInterface)
+ member_hash = SetupCacheForInterface ();
+ 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) {
+ method_hash = new Hashtable ();
+ AddMethods (type);
+ }
+
+ // Add all members from the current class.
+ AddMembers (Container);
+
+ Timer.StopTimer (TimerType.CacheInit);
+ }
+
+ /// <summary>
+ /// Bootstrap this member cache by doing a deep-copy of our parent.
+ /// </summary>
+ Hashtable SetupCache (MemberCache parent)
+ {
+ Hashtable hash = new Hashtable ();
+
+ IDictionaryEnumerator it = parent.member_hash.GetEnumerator ();
+ while (it.MoveNext ()) {
+ hash [it.Key] = ((ArrayList) it.Value).Clone ();
+ }
+
+ return hash;
+ }
+
+ void AddInterfaces (MemberCache parent)
+ {
+ foreach (Type iface in parent.interface_hash.Keys) {
+ if (!interface_hash.Contains (iface))
+ interface_hash.Add (iface, true);
+ }
+ }
+
+ /// <summary>
+ /// Add the contents of `new_hash' to `hash'.
+ /// </summary>
+ void AddHashtable (Hashtable hash, Hashtable new_hash)
+ {
+ IDictionaryEnumerator it = new_hash.GetEnumerator ();
+ while (it.MoveNext ()) {
+ ArrayList list = (ArrayList) hash [it.Key];
+ if (list != null)
+ list.AddRange ((ArrayList) it.Value);
+ else
+ hash [it.Key] = ((ArrayList) it.Value).Clone ();
+ }
+ }
+
+ /// <summary>
+ /// Bootstrap the member cache for an interface type.
+ /// Type.GetMembers() won't return any inherited members for interface types,
+ /// so we need to do this manually. Interfaces also inherit from System.Object.
+ /// </summary>
+ Hashtable SetupCacheForInterface ()
+ {
+ Hashtable hash = SetupCache (TypeHandle.ObjectType.MemberCache);
+ Type [] ifaces = TypeManager.GetInterfaces (Container.Type);
+
+ foreach (Type iface in ifaces) {
+ if (interface_hash.Contains (iface))
+ continue;
+ interface_hash.Add (iface, true);
+
+ IMemberContainer iface_container =
+ TypeManager.LookupMemberContainer (iface);
+
+ MemberCache iface_cache = iface_container.MemberCache;
+ AddHashtable (hash, iface_cache.member_hash);
+ AddInterfaces (iface_cache);
+ }
+
+ return hash;
+ }
+
+ /// <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.
+ 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);
+ BindingFlags new_bf = (container == Container) ?
+ bf | BindingFlags.DeclaredOnly : bf;
+
+ foreach (MemberInfo member in members) {
+ string name = member.Name;
+
+ // 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 parent 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);
+ }
+
+ void AddMethods (BindingFlags bf, Type type)
+ {
+ MemberInfo [] members = type.GetMethods (bf);
+
+ foreach (MethodBase member in members) {
+ string name = member.Name;
+
+ // Varargs methods aren't allowed in C# code.
+ if ((member.CallingConvention & CallingConventions.VarArgs) != 0)
+ continue;
+
+ // 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);
+ }
+
+ // 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 struct 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);
+ }
+ }
+
+ /// <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>
+ public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
+ MemberFilter filter, object criteria)
+ {
+ 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 MemberList.Empty;
+
+ //
+ // 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?
+ //
+ ArrayList list = new ArrayList ();
+
+ Timer.StartTimer (TimerType.CachedLookup);
+
+ EntryType type = GetEntryType (mt, bf);
+
+ IMemberContainer current = Container;
+
+ // `applicable' is a list of all members with the given member name `name'
+ // in the current class and all its parent 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 parent).
+
+ 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 || DoneSearching (list))
+ 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;
+ list.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 && (list.Count > 0)){
+ return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
+ }
+
+ return new MemberList (list);
+ }
+ }
+}
--- /dev/null
+//\r
+// delegate.cs: Delegate Handler\r
+//\r
+// Authors:\r
+// Ravi Pratap (ravi@ximian.com)\r
+// Miguel de Icaza (miguel@ximian.com)\r
+//\r
+// Licensed under the terms of the GNU GPL\r
+//\r
+// (C) 2001 Ximian, Inc (http://www.ximian.com)\r
+//\r
+//\r
+\r
+using System;\r
+using System.Collections;\r
+using System.Reflection;\r
+using System.Reflection.Emit;\r
+using System.Text;\r
+\r
+namespace Mono.CSharp {\r
+\r
+ /// <summary>\r
+ /// Holds Delegates\r
+ /// </summary>\r
+ public class Delegate : DeclSpace {\r
+ public Expression ReturnType;\r
+ public Parameters Parameters;\r
+ public Attributes OptAttributes;\r
+\r
+ public ConstructorBuilder ConstructorBuilder;\r
+ public MethodBuilder InvokeBuilder;\r
+ public MethodBuilder BeginInvokeBuilder;\r
+ public MethodBuilder EndInvokeBuilder;\r
+ \r
+ Type [] param_types;\r
+ Type ret_type;\r
+ \r
+ Expression instance_expr;\r
+ MethodBase delegate_method;\r
+ \r
+ const int AllowedModifiers =\r
+ Modifiers.NEW |\r
+ Modifiers.PUBLIC |\r
+ Modifiers.PROTECTED |\r
+ Modifiers.INTERNAL |\r
+ Modifiers.UNSAFE |\r
+ Modifiers.PRIVATE;\r
+\r
+ public Delegate (TypeContainer parent, Expression type, int mod_flags,\r
+ string name, Parameters param_list,\r
+ Attributes attrs, Location l)\r
+ : base (parent, name, l)\r
+ {\r
+ this.ReturnType = type;\r
+ ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,\r
+ IsTopLevel ? Modifiers.INTERNAL :\r
+ Modifiers.PRIVATE, l);\r
+ Parameters = param_list;\r
+ OptAttributes = attrs;\r
+ }\r
+\r
+ public override TypeBuilder DefineType ()\r
+ {\r
+ if (TypeBuilder != null)\r
+ return TypeBuilder;\r
+\r
+ TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel) |\r
+ TypeAttributes.Class | TypeAttributes.Sealed;\r
+\r
+ if (IsTopLevel) {\r
+ if (TypeManager.NamespaceClash (Name, Location))\r
+ return null;\r
+ \r
+ ModuleBuilder builder = CodeGen.ModuleBuilder;\r
+\r
+ TypeBuilder = builder.DefineType (\r
+ Name, attr, TypeManager.multicast_delegate_type);\r
+ } else {\r
+ TypeBuilder builder = Parent.TypeBuilder;\r
+\r
+ string name = Name.Substring (1 + Name.LastIndexOf ('.'));\r
+ TypeBuilder = builder.DefineNestedType (\r
+ name, attr, TypeManager.multicast_delegate_type);\r
+ }\r
+\r
+ TypeManager.AddDelegateType (Name, TypeBuilder, this);\r
+\r
+ return TypeBuilder;\r
+ }\r
+\r
+ public override bool DefineMembers (TypeContainer container)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ public override bool Define (TypeContainer container)\r
+ {\r
+ MethodAttributes mattr;\r
+ int i;\r
+ ParameterBuilder pb;\r
+ Attributes cattr;\r
+ EmitContext ec = new EmitContext (this, this, Location, null,\r
+ null, ModFlags, false);\r
+\r
+ // FIXME: POSSIBLY make this static, as it is always constant\r
+ //\r
+ Type [] const_arg_types = new Type [2];\r
+ const_arg_types [0] = TypeManager.object_type;\r
+ const_arg_types [1] = TypeManager.intptr_type;\r
+\r
+ mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |\r
+ MethodAttributes.HideBySig | MethodAttributes.Public;\r
+\r
+ ConstructorBuilder = TypeBuilder.DefineConstructor (mattr,\r
+ CallingConventions.Standard,\r
+ const_arg_types);\r
+\r
+ ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");\r
+ ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");\r
+ //\r
+ // HACK because System.Reflection.Emit is lame\r
+ //\r
+ //\r
+ // FIXME: POSSIBLY make these static, as they are always the same\r
+ Parameter [] fixed_pars = new Parameter [2];\r
+ fixed_pars [0] = new Parameter (null, null, Parameter.Modifier.NONE, null);\r
+ fixed_pars [1] = new Parameter (null, null, Parameter.Modifier.NONE, null);\r
+ Parameters const_parameters = new Parameters (fixed_pars, null, Location);\r
+ \r
+ TypeManager.RegisterMethod (\r
+ ConstructorBuilder,\r
+ new InternalParameters (const_arg_types, const_parameters),\r
+ const_arg_types);\r
+ \r
+ \r
+ ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
+\r
+ //\r
+ // Here the various methods like Invoke, BeginInvoke etc are defined\r
+ //\r
+ // First, call the `out of band' special method for\r
+ // defining recursively any types we need:\r
+ \r
+ if (!Parameters.ComputeAndDefineParameterTypes (this))\r
+ return false;\r
+ \r
+ param_types = Parameters.GetParameterInfo (this);\r
+ if (param_types == null)\r
+ return false;\r
+\r
+ //\r
+ // Invoke method\r
+ //\r
+\r
+ // Check accessibility\r
+ foreach (Type partype in param_types){\r
+ if (!container.AsAccessible (partype, ModFlags)) {\r
+ Report.Error (59, Location,\r
+ "Inconsistent accessibility: parameter type `" +\r
+ TypeManager.CSharpName (partype) + "` is less " +\r
+ "accessible than delegate `" + Name + "'");\r
+ return false;\r
+ }\r
+ if (partype.IsPointer && !UnsafeOK (container))\r
+ return false;\r
+ }\r
+ \r
+ ReturnType = ResolveTypeExpr (ReturnType, false, Location);\r
+ ret_type = ReturnType.Type;\r
+ if (ret_type == null)\r
+ return false;\r
+\r
+ if (!container.AsAccessible (ret_type, ModFlags)) {\r
+ Report.Error (58, Location,\r
+ "Inconsistent accessibility: return type `" +\r
+ TypeManager.CSharpName (ret_type) + "` is less " +\r
+ "accessible than delegate `" + Name + "'");\r
+ return false;\r
+ }\r
+\r
+ if (ret_type.IsPointer && !UnsafeOK (container))\r
+ return false;\r
+\r
+ //\r
+ // We don't have to check any others because they are all\r
+ // guaranteed to be accessible - they are standard types.\r
+ //\r
+ \r
+ CallingConventions cc = Parameters.GetCallingConvention ();\r
+\r
+ mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;\r
+\r
+ InvokeBuilder = TypeBuilder.DefineMethod ("Invoke", \r
+ mattr, \r
+ cc,\r
+ ret_type, \r
+ param_types);\r
+\r
+ //\r
+ // Define parameters, and count out/ref parameters\r
+ //\r
+ int out_params = 0;\r
+ i = 0;\r
+ if (Parameters.FixedParameters != null){\r
+ int top = Parameters.FixedParameters.Length;\r
+ Parameter p;\r
+ \r
+ for (; i < top; i++) {\r
+ p = Parameters.FixedParameters [i];\r
+ pb = InvokeBuilder.DefineParameter (i+1, p.Attributes, p.Name);\r
+ cattr = p.OptAttributes;\r
+ if (cattr != null)\r
+ Attribute.ApplyAttributes (ec, pb, pb, cattr);\r
+\r
+ if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0)\r
+ out_params++;\r
+ }\r
+ }\r
+ if (Parameters.ArrayParameter != null){\r
+ Parameter p = Parameters.ArrayParameter;\r
+ \r
+ pb = InvokeBuilder.DefineParameter (\r
+ i+1, p.Attributes, p.Name);\r
+ cattr = p.OptAttributes;\r
+ if (cattr != null)\r
+ Attribute.ApplyAttributes (ec, pb, pb, cattr);\r
+ }\r
+ \r
+ InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
+\r
+ TypeManager.RegisterMethod (InvokeBuilder,\r
+ new InternalParameters (container, Parameters),\r
+ param_types);\r
+\r
+ //\r
+ // BeginInvoke\r
+ //\r
+ int params_num = param_types.Length;\r
+ Type [] async_param_types = new Type [params_num + 2];\r
+\r
+ param_types.CopyTo (async_param_types, 0);\r
+\r
+ async_param_types [params_num] = TypeManager.asynccallback_type;\r
+ async_param_types [params_num + 1] = TypeManager.object_type;\r
+\r
+ mattr = MethodAttributes.Public | MethodAttributes.HideBySig |\r
+ MethodAttributes.Virtual | MethodAttributes.NewSlot;\r
+ \r
+ BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",\r
+ mattr,\r
+ cc,\r
+ TypeManager.iasyncresult_type,\r
+ async_param_types);\r
+\r
+ i = 0;\r
+ if (Parameters.FixedParameters != null){\r
+ int top = Parameters.FixedParameters.Length;\r
+ Parameter p;\r
+ \r
+ for (i = 0 ; i < top; i++) {\r
+ p = Parameters.FixedParameters [i];\r
+\r
+ pb = BeginInvokeBuilder.DefineParameter (i+1, p.Attributes, p.Name);\r
+ cattr = p.OptAttributes;\r
+ if (cattr != null)\r
+ Attribute.ApplyAttributes (ec, pb, pb, cattr);\r
+ }\r
+ }\r
+ if (Parameters.ArrayParameter != null){\r
+ Parameter p = Parameters.ArrayParameter;\r
+ \r
+ pb = BeginInvokeBuilder.DefineParameter (i+1, p.Attributes, p.Name);\r
+ cattr = p.OptAttributes;\r
+ if (cattr != null)\r
+ Attribute.ApplyAttributes (ec, pb, pb, cattr);\r
+ i++;\r
+ }\r
+\r
+ BeginInvokeBuilder.DefineParameter (i + 1, ParameterAttributes.None, "callback");\r
+ BeginInvokeBuilder.DefineParameter (i + 2, ParameterAttributes.None, "object");\r
+ \r
+ BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
+\r
+ Parameter [] async_params = new Parameter [params_num + 2];\r
+ int n = 0;\r
+ if (Parameters.FixedParameters != null){\r
+ Parameters.FixedParameters.CopyTo (async_params, 0);\r
+ n = Parameters.FixedParameters.Length;\r
+ }\r
+ if (Parameters.ArrayParameter != null)\r
+ async_params [n] = Parameters.ArrayParameter;\r
+ \r
+ async_params [params_num] = new Parameter (\r
+ TypeManager.system_asynccallback_expr, "callback",\r
+ Parameter.Modifier.NONE, null);\r
+ async_params [params_num + 1] = new Parameter (\r
+ TypeManager.system_object_expr, "object",\r
+ Parameter.Modifier.NONE, null);\r
+\r
+ Parameters async_parameters = new Parameters (async_params, null, Location);\r
+ async_parameters.ComputeAndDefineParameterTypes (this);\r
+ \r
+ async_parameters.ComputeAndDefineParameterTypes (this);\r
+ TypeManager.RegisterMethod (BeginInvokeBuilder,\r
+ new InternalParameters (container, async_parameters),\r
+ async_param_types);\r
+\r
+ //\r
+ // EndInvoke is a bit more interesting, all the parameters labeled as\r
+ // out or ref have to be duplicated here.\r
+ //\r
+ \r
+ Type [] end_param_types = new Type [out_params + 1];\r
+ Parameter [] end_params = new Parameter [out_params + 1];\r
+ int param = 0; \r
+ if (out_params > 0){\r
+ int top = Parameters.FixedParameters.Length;\r
+ for (i = 0; i < top; i++){\r
+ Parameter p = Parameters.FixedParameters [i];\r
+ if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0)\r
+ continue;\r
+\r
+ end_param_types [param] = param_types [i];\r
+ end_params [param] = p;\r
+ param++;\r
+ }\r
+ }\r
+ end_param_types [out_params] = TypeManager.iasyncresult_type;\r
+ end_params [out_params] = new Parameter (TypeManager.system_iasyncresult_expr, "result", Parameter.Modifier.NONE, null);\r
+\r
+ //\r
+ // Create method, define parameters, register parameters with type system\r
+ //\r
+ EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_param_types);\r
+ EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
+\r
+ //\r
+ // EndInvoke: Label the parameters\r
+ //\r
+ EndInvokeBuilder.DefineParameter (out_params + 1, ParameterAttributes.None, "result");\r
+ for (i = 0; i < end_params.Length-1; i++){\r
+ EndInvokeBuilder.DefineParameter (i + 1, end_params [i].Attributes, end_params [i].Name);\r
+ }\r
+\r
+ Parameters end_parameters = new Parameters (end_params, null, Location);\r
+ end_parameters.ComputeAndDefineParameterTypes (this);\r
+\r
+ TypeManager.RegisterMethod (\r
+ EndInvokeBuilder,\r
+ new InternalParameters (container, end_parameters),\r
+ end_param_types);\r
+\r
+ return true;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Verifies whether the method in question is compatible with the delegate\r
+ /// Returns the method itself if okay and null if not.\r
+ /// </summary>\r
+ public static MethodBase VerifyMethod (EmitContext ec, Type delegate_type, MethodBase mb,\r
+ Location loc)\r
+ {\r
+ ParameterData pd = Invocation.GetParameterData (mb);\r
+\r
+ int pd_count = pd.Count;\r
+\r
+ Expression ml = Expression.MemberLookup (\r
+ ec, delegate_type, "Invoke", loc);\r
+\r
+ if (!(ml is MethodGroupExpr)) {\r
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");\r
+ return null;\r
+ }\r
+\r
+ MethodBase invoke_mb = ((MethodGroupExpr) ml).Methods [0];\r
+\r
+ ParameterData invoke_pd = Invocation.GetParameterData (invoke_mb);\r
+\r
+ if (invoke_pd.Count != pd_count)\r
+ return null;\r
+\r
+ for (int i = pd_count; i > 0; ) {\r
+ i--;\r
+\r
+ if (invoke_pd.ParameterType (i) == pd.ParameterType (i) &&\r
+ invoke_pd.ParameterModifier (i) == pd.ParameterModifier (i))\r
+ continue;\r
+ else {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ if (((MethodInfo) invoke_mb).ReturnType == ((MethodInfo) mb).ReturnType)\r
+ return mb;\r
+ else\r
+ return null;\r
+ }\r
+\r
+ // <summary>\r
+ // Verifies whether the invocation arguments are compatible with the\r
+ // delegate's target method\r
+ // </summary>\r
+ public static bool VerifyApplicability (EmitContext ec,\r
+ Type delegate_type,\r
+ ArrayList args,\r
+ Location loc)\r
+ {\r
+ int arg_count;\r
+\r
+ if (args == null)\r
+ arg_count = 0;\r
+ else\r
+ arg_count = args.Count;\r
+\r
+ Expression ml = Expression.MemberLookup (\r
+ ec, delegate_type, "Invoke", loc);\r
+\r
+ if (!(ml is MethodGroupExpr)) {\r
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!" + delegate_type);\r
+ return false;\r
+ }\r
+ \r
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];\r
+ ParameterData pd = Invocation.GetParameterData (mb);\r
+\r
+ int pd_count = pd.Count;\r
+\r
+ bool not_params_method = (pd_count == 0) ||\r
+ (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS);\r
+\r
+ if (not_params_method && pd_count != arg_count) {\r
+ Report.Error (1593, loc,\r
+ "Delegate '" + delegate_type.ToString ()\r
+ + "' does not take '" + arg_count + "' arguments");\r
+ return false;\r
+ }\r
+\r
+ return Invocation.VerifyArgumentsCompat (ec, args, arg_count, mb, !not_params_method,\r
+ delegate_type, loc);\r
+ }\r
+ \r
+ /// <summary>\r
+ /// Verifies whether the delegate in question is compatible with this one in\r
+ /// order to determine if instantiation from the same is possible.\r
+ /// </summary>\r
+ public static bool VerifyDelegate (EmitContext ec, Type delegate_type, Type probe_type, Location loc)\r
+ {\r
+ Expression ml = Expression.MemberLookup (\r
+ ec, delegate_type, "Invoke", loc);\r
+ \r
+ if (!(ml is MethodGroupExpr)) {\r
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");\r
+ return false;\r
+ }\r
+ \r
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];\r
+ ParameterData pd = Invocation.GetParameterData (mb);\r
+\r
+ Expression probe_ml = Expression.MemberLookup (\r
+ ec, delegate_type, "Invoke", loc);\r
+ \r
+ if (!(probe_ml is MethodGroupExpr)) {\r
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");\r
+ return false;\r
+ }\r
+ \r
+ MethodBase probe_mb = ((MethodGroupExpr) probe_ml).Methods [0];\r
+ ParameterData probe_pd = Invocation.GetParameterData (probe_mb);\r
+ \r
+ if (((MethodInfo) mb).ReturnType != ((MethodInfo) probe_mb).ReturnType)\r
+ return false;\r
+\r
+ if (pd.Count != probe_pd.Count)\r
+ return false;\r
+\r
+ for (int i = pd.Count; i > 0; ) {\r
+ i--;\r
+\r
+ if (pd.ParameterType (i) != probe_pd.ParameterType (i) ||\r
+ pd.ParameterModifier (i) != probe_pd.ParameterModifier (i))\r
+ return false;\r
+ }\r
+ \r
+ return true;\r
+ }\r
+ \r
+ public static string FullDelegateDesc (Type del_type, MethodBase mb, ParameterData pd)\r
+ {\r
+ StringBuilder sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));\r
+ \r
+ sb.Append (" " + del_type.ToString ());\r
+ sb.Append (" (");\r
+\r
+ int length = pd.Count;\r
+ \r
+ for (int i = length; i > 0; ) {\r
+ i--;\r
+\r
+ sb.Append (pd.ParameterDesc (length - i - 1));\r
+ if (i != 0)\r
+ sb.Append (", ");\r
+ }\r
+ \r
+ sb.Append (")");\r
+ return sb.ToString ();\r
+ \r
+ }\r
+ \r
+ // Hack around System.Reflection as found everywhere else\r
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,\r
+ MemberFilter filter, object criteria)\r
+ {\r
+ ArrayList members = new ArrayList ();\r
+\r
+ if ((mt & MemberTypes.Method) != 0) {\r
+ if (ConstructorBuilder != null)\r
+ if (filter (ConstructorBuilder, criteria))\r
+ members.Add (ConstructorBuilder);\r
+\r
+ if (InvokeBuilder != null)\r
+ if (filter (InvokeBuilder, criteria))\r
+ members.Add (InvokeBuilder);\r
+\r
+ if (BeginInvokeBuilder != null)\r
+ if (filter (BeginInvokeBuilder, criteria))\r
+ members.Add (BeginInvokeBuilder);\r
+\r
+ if (EndInvokeBuilder != null)\r
+ if (filter (EndInvokeBuilder, criteria))\r
+ members.Add (EndInvokeBuilder);\r
+ }\r
+\r
+ return new MemberList (members);\r
+ }\r
+\r
+ public override MemberCache MemberCache {\r
+ get {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ public Expression InstanceExpression {\r
+ get {\r
+ return instance_expr;\r
+ }\r
+ set {\r
+ instance_expr = value;\r
+ }\r
+ }\r
+\r
+ public MethodBase TargetMethod {\r
+ get {\r
+ return delegate_method;\r
+ }\r
+ set {\r
+ delegate_method = value;\r
+ }\r
+ }\r
+\r
+ public Type TargetReturnType {\r
+ get {\r
+ return ret_type;\r
+ }\r
+ }\r
+\r
+ public Type [] ParameterTypes {\r
+ get {\r
+ return param_types;\r
+ }\r
+ }\r
+ \r
+ }\r
+\r
+ public class NewDelegate : Expression {\r
+\r
+ public ArrayList Arguments;\r
+\r
+ MethodBase constructor_method;\r
+ MethodBase delegate_method;\r
+ Expression delegate_instance_expr;\r
+\r
+ public NewDelegate (Type type, ArrayList Arguments, Location loc)\r
+ {\r
+ this.type = type;\r
+ this.Arguments = Arguments;\r
+ this.loc = loc; \r
+ }\r
+\r
+ public override Expression DoResolve (EmitContext ec)\r
+ {\r
+ if (Arguments == null || Arguments.Count != 1) {\r
+ Report.Error (149, loc,\r
+ "Method name expected");\r
+ return null;\r
+ }\r
+\r
+ Expression ml = Expression.MemberLookup (\r
+ ec, type, ".ctor", loc);\r
+\r
+ if (!(ml is MethodGroupExpr)) {\r
+ Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");\r
+ return null;\r
+ }\r
+\r
+ constructor_method = ((MethodGroupExpr) ml).Methods [0];\r
+ Argument a = (Argument) Arguments [0];\r
+ \r
+ if (!a.ResolveMethodGroup (ec, Location))\r
+ return null;\r
+ \r
+ Expression e = a.Expr;\r
+\r
+ Expression invoke_method = Expression.MemberLookup (\r
+ ec, type, "Invoke", MemberTypes.Method,\r
+ Expression.AllBindingFlags, loc);\r
+\r
+ if (invoke_method == null) {\r
+ Report.Error (-200, loc, "Internal error ! Could not find Invoke method!");\r
+ return null;\r
+ }\r
+\r
+ if (e is MethodGroupExpr) {\r
+ MethodGroupExpr mg = (MethodGroupExpr) e;\r
+\r
+ foreach (MethodInfo mi in mg.Methods){\r
+ delegate_method = Delegate.VerifyMethod (ec, type, mi, loc);\r
+\r
+ if (delegate_method != null)\r
+ break;\r
+ }\r
+ \r
+ if (delegate_method == null) {\r
+ string method_desc;\r
+ if (mg.Methods.Length > 1)\r
+ method_desc = mg.Methods [0].Name;\r
+ else\r
+ method_desc = Invocation.FullMethodDesc (mg.Methods [0]);\r
+\r
+ MethodBase dm = ((MethodGroupExpr) invoke_method).Methods [0];\r
+ ParameterData param = Invocation.GetParameterData (dm);\r
+ string delegate_desc = Delegate.FullDelegateDesc (type, dm, param);\r
+\r
+ Report.Error (123, loc, "Method '" + method_desc + "' does not " +\r
+ "match delegate '" + delegate_desc + "'");\r
+\r
+ return null;\r
+ }\r
+\r
+ //\r
+ // Check safe/unsafe of the delegate\r
+ //\r
+ if (!ec.InUnsafe){\r
+ ParameterData param = Invocation.GetParameterData (delegate_method);\r
+ int count = param.Count;\r
+ \r
+ for (int i = 0; i < count; i++){\r
+ if (param.ParameterType (i).IsPointer){\r
+ Expression.UnsafeError (loc);\r
+ return null;\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (mg.InstanceExpression != null)\r
+ delegate_instance_expr = mg.InstanceExpression.Resolve (ec);\r
+ else {\r
+ if (ec.IsStatic){\r
+ if (!delegate_method.IsStatic){\r
+ Report.Error (120, loc,\r
+ "An object reference is required for the non-static method " +\r
+ delegate_method.Name);\r
+ return null;\r
+ }\r
+ delegate_instance_expr = null;\r
+ } else\r
+ delegate_instance_expr = ec.GetThis (loc);\r
+ }\r
+\r
+ if (delegate_instance_expr != null)\r
+ if (delegate_instance_expr.Type.IsValueType)\r
+ delegate_instance_expr = new BoxedCast (delegate_instance_expr);\r
+ \r
+ eclass = ExprClass.Value;\r
+ return this;\r
+ }\r
+\r
+ Type e_type = e.Type;\r
+\r
+ if (!TypeManager.IsDelegateType (e_type)) {\r
+ e.Error_UnexpectedKind ("method");\r
+ return null;\r
+ }\r
+\r
+ // This is what MS' compiler reports. We could always choose\r
+ // to be more verbose and actually give delegate-level specifics\r
+ \r
+ if (!Delegate.VerifyDelegate (ec, type, e_type, loc)) {\r
+ Report.Error (29, loc, "Cannot implicitly convert type '" + e_type + "' " +\r
+ "to type '" + type + "'");\r
+ return null;\r
+ }\r
+ \r
+ delegate_instance_expr = e;\r
+ delegate_method = ((MethodGroupExpr) invoke_method).Methods [0];\r
+ \r
+ eclass = ExprClass.Value;\r
+ return this;\r
+ }\r
+ \r
+ public override void Emit (EmitContext ec)\r
+ {\r
+ if (delegate_instance_expr == null ||\r
+ delegate_method.IsStatic)\r
+ ec.ig.Emit (OpCodes.Ldnull);\r
+ else\r
+ delegate_instance_expr.Emit (ec);\r
+ \r
+ if (delegate_method.IsVirtual) {\r
+ ec.ig.Emit (OpCodes.Dup);\r
+ ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);\r
+ } else\r
+ ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);\r
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);\r
+ }\r
+ }\r
+\r
+ public class DelegateInvocation : ExpressionStatement {\r
+\r
+ public Expression InstanceExpr;\r
+ public ArrayList Arguments;\r
+\r
+ MethodBase method;\r
+ \r
+ public DelegateInvocation (Expression instance_expr, ArrayList args, Location loc)\r
+ {\r
+ this.InstanceExpr = instance_expr;\r
+ this.Arguments = args;\r
+ this.loc = loc;\r
+ }\r
+\r
+ public override Expression DoResolve (EmitContext ec)\r
+ {\r
+ if (InstanceExpr is EventExpr) {\r
+ \r
+ EventInfo ei = ((EventExpr) InstanceExpr).EventInfo;\r
+ \r
+ Expression ml = MemberLookup (\r
+ ec, ec.ContainerType, ei.Name,\r
+ MemberTypes.Event, AllBindingFlags | BindingFlags.DeclaredOnly, loc);\r
+\r
+ if (ml == null) {\r
+ //\r
+ // If this is the case, then the Event does not belong \r
+ // to this Type and so, according to the spec\r
+ // cannot be accessed directly\r
+ //\r
+ // Note that target will not appear as an EventExpr\r
+ // in the case it is being referenced within the same type container;\r
+ // it will appear as a FieldExpr in that case.\r
+ //\r
+ \r
+ Assign.error70 (ei, loc);\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ \r
+ Type del_type = InstanceExpr.Type;\r
+ if (del_type == null)\r
+ return null;\r
+ \r
+ if (Arguments != null){\r
+ foreach (Argument a in Arguments){\r
+ if (!a.Resolve (ec, loc))\r
+ return null;\r
+ }\r
+ }\r
+ \r
+ if (!Delegate.VerifyApplicability (ec, del_type, Arguments, loc))\r
+ return null;\r
+\r
+ Expression lookup = Expression.MemberLookup (ec, del_type, "Invoke", loc);\r
+ if (!(lookup is MethodGroupExpr)) {\r
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");\r
+ return null;\r
+ }\r
+ \r
+ method = ((MethodGroupExpr) lookup).Methods [0];\r
+ type = ((MethodInfo) method).ReturnType;\r
+ eclass = ExprClass.Value;\r
+ \r
+ return this;\r
+ }\r
+\r
+ public override void Emit (EmitContext ec)\r
+ {\r
+ Delegate del = TypeManager.LookupDelegate (InstanceExpr.Type);\r
+\r
+ //\r
+ // Invocation on delegates call the virtual Invoke member\r
+ // so we are always `instance' calls\r
+ //\r
+ Invocation.EmitCall (ec, false, false, InstanceExpr, method, Arguments, loc);\r
+ }\r
+\r
+ public override void EmitStatement (EmitContext ec)\r
+ {\r
+ Emit (ec);\r
+ // \r
+ // Pop the return value if there is one\r
+ //\r
+ if (method is MethodInfo){\r
+ if (((MethodInfo) method).ReturnType != TypeManager.void_type)\r
+ ec.ig.Emit (OpCodes.Pop);\r
+ }\r
+ }\r
+\r
+ }\r
+}\r
--- /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)
+//
+
+namespace Mono.CSharp
+{
+ using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Collections;
+ using System.IO;
+ using System.Text;
+ using System.Globalization;
+ using Mono.Languages;
+
+ 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;
+
+ // Lookup paths
+ static ArrayList link_paths;
+
+ // Whether we want Yacc to output its progress
+ static bool yacc_verbose = false;
+
+ // Whether we want to only run the tokenizer
+ static bool tokenize = false;
+
+ static string first_source;
+
+ static Target target = Target.Exe;
+ static string target_ext = ".exe";
+
+ 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;
+
+ static Hashtable response_file_list;
+
+ //
+ // A list of resource files
+ //
+ static ArrayList resources;
+ static ArrayList embedded_resources;
+
+ //
+ // 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: ISO-Latin1 is 28591
+ //
+ static Encoding encoding;
+
+ //
+ // Whether the user has specified a different encoder manually
+ //
+ static bool using_default_encoder = true;
+
+ 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);
+
+ if (pause)
+ Console.ReadLine ();
+ }
+
+ 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 opened");
+ return;
+ }
+
+ using (input){
+ StreamReader reader = new StreamReader (input, encoding, using_default_encoder);
+ Tokenizer lexer = new Tokenizer (reader, file, defines);
+ int token, tokens = 0, errors = 0;
+
+ while ((token = lexer.token ()) != Token.EOF){
+ Location l = lexer.Location;
+ 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 opened");
+ return;
+ }
+
+ StreamReader reader = new StreamReader (input, encoding, using_default_encoder);
+
+ parser = new CSharpParser (reader, file, defines);
+ parser.yacc_verbose = yacc_verbose;
+ try {
+ parser.parse ();
+ } catch (Exception ex) {
+ Report.Error(666, "Compilation aborted: " + ex);
+ } finally {
+ input.Close ();
+ }
+ }
+
+ static void Usage ()
+ {
+ Console.WriteLine (
+ "Mono C# compiler, (C) 2001 - 2003 Ximian, Inc.\n" +
+ "mcs [options] source-files\n" +
+ " --about About the Mono C# compiler\n" +
+ " -checked[+|-] Set default context to checked\n" +
+ " -codepage:ID Sets code page to the one in ID\n" +
+ " (number, `utf8' or `reset')\n" +
+ " -define:S1[;S2] Defines one or more symbols (short: /d:)\n" +
+ " -debug[+-] Generate debugging information\n" +
+ " -doc:FILE XML Documentation file to generate\n" +
+ " -g Generate debugging information\n" +
+ " --fatal Makes errors fatal\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" +
+ " -out:FNAME Specifies output file\n" +
+ " --parse Only parses the source file\n" +
+ " --expect-error X Expect that error X will be encountered\n" +
+ " -recurse:SPEC Recursively compiles the files in SPEC ([dir]/file)\n" +
+ " -reference:ASS References the specified assembly (-r:ASS)\n" +
+ " --stacktrace Shows stack trace at error location\n" +
+ " -target:KIND Specifies the target (KIND is one of: exe, winexe,\n" +
+ " library, module), (short: /t:)\n" +
+ " --timestamp Displays time stamps of various compiler events\n" +
+ " -unsafe[+|-] Allows unsafe code\n" +
+ " -warnaserror[+|-] Treat warnings as errors\n" +
+ " -warn:LEVEL Sets warning level (the highest is 4, the default)\n" +
+ " -v Verbose parsing (for debugging the parser)\n" +
+ "\n" +
+ "Resources:\n" +
+ " -linkresource:FILE[,ID] Links FILE as a resource\n" +
+ " -resource:FILE[,ID] Embed FILE as a resource\n" +
+ " --mcs-debug X Sets MCS debugging level to X\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, "Valid options for -target: are exe, winexe, library or module");
+ }
+
+ static void About ()
+ {
+ Console.WriteLine (
+ "The Mono C# compiler is (C) 2001, 2002, 2003 Ximian, 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 and Martin Baulig");
+ Environment.Exit (0);
+ }
+
+ public static int counter1, counter2;
+
+ public static int Main (string[] args)
+ {
+ bool ok = MainDriver (args);
+
+ if (ok && Report.Errors == 0) {
+ Console.Write("Compilation succeeded");
+ if (Report.Warnings > 0) {
+ Console.Write(" - {0} warning(s)", Report.Warnings);
+ }
+ Console.WriteLine();
+ if (show_counters){
+ Console.WriteLine ("Counter1: " + counter1);
+ Console.WriteLine ("Counter2: " + counter2);
+ }
+ 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)
+ {
+ Assembly a;
+ string total_log = "";
+
+ try {
+ char[] path_chars = { '/', '\\', '.' };
+
+ if (assembly.IndexOfAny (path_chars) != -1) {
+ a = Assembly.LoadFrom (assembly);
+ } else {
+ a = Assembly.Load (assembly);
+ }
+ TypeManager.AddAssembly (a);
+
+ } catch (FileNotFoundException){
+ foreach (string dir in link_paths){
+ string full_path = Path.Combine (dir, assembly);
+ if (!assembly.EndsWith (".dll"))
+ full_path += ".dll";
+
+ try {
+ a = Assembly.LoadFrom (full_path);
+ TypeManager.AddAssembly (a);
+ return;
+ } catch (FileNotFoundException ff) {
+ total_log += ff.FusionLog;
+ continue;
+ }
+ }
+ if (!soft) {
+ Report.Error (6, "Cannot find assembly `" + assembly + "'" );
+ Console.WriteLine ("Log: \n" + total_log);
+ }
+ } catch (BadImageFormatException f) {
+ Report.Error(6, "Cannot load assembly (bad file format)" + f.FusionLog);
+ } catch (FileLoadException f){
+ Report.Error(6, "Cannot load assembly " + f.FusionLog);
+ } catch (ArgumentNullException){
+ Report.Error(6, "Cannot load assembly (null argument)");
+ }
+ }
+
+ /// <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);
+
+ 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 ()
+ {
+ Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
+
+ foreach (Assembly a in assemblies){
+ string codebase = a.Location;
+ if (codebase.EndsWith ("corlib.dll")){
+ return codebase.Substring (0, codebase.LastIndexOf (System.IO.Path.DirectorySeparatorChar));
+ }
+ }
+
+ Report.Error (-15, "Can not compute my system path");
+ return "";
+ }
+
+ //
+ // 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);
+ }
+
+ static void SetOutputFile (string name)
+ {
+ output_file = name;
+ }
+
+ static void SetWarningLevel (string s)
+ {
+ int level = 0;
+
+ try {
+ level = Int32.Parse (s);
+ } catch {
+ Report.Error (
+ 1900,
+ "--wlevel requires an value from 0 to 4");
+ Environment.Exit (1);
+ }
+ if (level < 0 || level > 4){
+ Report.Error (1900, "Warning level must be 0 to 4");
+ Environment.Exit (1);
+ } else
+ RootContext.WarningLevel = level;
+ }
+
+ static void SetupV2 ()
+ {
+ RootContext.V2 = true;
+ 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":
+ yacc_verbose = true;
+ return true;
+
+ case "--version":
+ Version ();
+ return true;
+
+ case "--parse":
+ parse_only = true;
+ return true;
+
+ case "--main": case "-m":
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ RootContext.MainClass = args [++i];
+ return true;
+
+ case "--unsafe":
+ RootContext.Unsafe = true;
+ return true;
+
+ case "/?": case "/h": case "/help":
+ case "--help":
+ Usage ();
+ Environment.Exit (0);
+ return true;
+
+ case "--define":
+ 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":
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ SetOutputFile (args [++i]);
+ return true;
+
+ case "--checked":
+ RootContext.Checked = true;
+ return true;
+
+ case "--stacktrace":
+ Report.Stacktrace = true;
+ return true;
+
+ case "--linkresource":
+ case "--linkres":
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Report.Error (5, "Missing argument to --linkres");
+ Environment.Exit (1);
+ }
+ if (resources == null)
+ resources = new ArrayList ();
+
+ resources.Add (args [++i]);
+ return true;
+
+ case "--resource":
+ case "--res":
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Report.Error (5, "Missing argument to --resource");
+ Environment.Exit (1);
+ }
+ if (embedded_resources == null)
+ embedded_resources = new ArrayList ();
+
+ embedded_resources.Add (args [++i]);
+ return true;
+
+ case "--target":
+ if ((i + 1) >= args.Length){
+ Environment.Exit (1);
+ return true;
+ }
+
+ string type = args [++i];
+ switch (type){
+ case "library":
+ target = Target.Library;
+ target_ext = ".dll";
+ break;
+
+ case "exe":
+ target = Target.Exe;
+ break;
+
+ case "winexe":
+ target = Target.WinExe;
+ break;
+
+ case "module":
+ target = Target.Module;
+ target_ext = ".dll";
+ break;
+ default:
+ TargetUsage ();
+ Environment.Exit (1);
+ break;
+ }
+ return true;
+
+ case "-r":
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+
+ references.Add (args [++i]);
+ return true;
+
+ case "-L":
+ if ((i + 1) >= args.Length){
+ Usage ();
+ Environment.Exit (1);
+ }
+ link_paths.Add (args [++i]);
+ return true;
+
+ case "--nostdlib":
+ RootContext.StdLib = false;
+ return true;
+
+ case "--fatal":
+ Report.Fatal = true;
+ return true;
+
+ case "--werror":
+ Report.WarningsAreErrors = true;
+ return true;
+
+ case "--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":
+ if ((i + 1) >= args.Length){
+ Report.Error (
+ 1900,
+ "--wlevel requires an 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":
+ 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":
+ want_debugging_support = true;
+ return true;
+
+ case "--noconfig":
+ load_default_config = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ //
+ // Currently it is very basic option parsing, but eventually, this will
+ // be the complete option parser
+ //
+ 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":
+ target = Target.Exe;
+ break;
+
+ case "winexe":
+ target = Target.WinExe;
+ break;
+
+ case "library":
+ target = Target.Library;
+ target_ext = ".dll";
+ break;
+
+ case "module":
+ target = Target.Module;
+ target_ext = ".netmodule";
+ break;
+
+ default:
+ TargetUsage ();
+ Environment.Exit (1);
+ break;
+ }
+ return true;
+
+ case "/out":
+ if (value == ""){
+ Usage ();
+ Environment.Exit (1);
+ }
+ SetOutputFile (value);
+ return true;
+
+ case "/optimize":
+ case "/optimize+":
+ case "/optimize-":
+ case "/incremental":
+ case "/incremental+":
+ case "/incremental-":
+ // nothing.
+ return true;
+
+ case "/d":
+ case "/define": {
+ string [] defs;
+
+ if (value == ""){
+ Usage ();
+ Environment.Exit (1);
+ }
+
+ defs = value.Split (new Char [] {';', ','});
+ foreach (string d in defs){
+ defines.Add (d);
+ }
+ return true;
+ }
+
+ case "/linkres":
+ case "/linkresource":
+ if (value == ""){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ if (resources == null)
+ resources = new ArrayList ();
+
+ resources.Add (value);
+ return true;
+
+ case "/res":
+ case "/resource":
+ if (value == ""){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ if (embedded_resources == null)
+ embedded_resources = new ArrayList ();
+
+ embedded_resources.Add (value);
+ return true;
+
+ case "/recurse":
+ if (value == ""){
+ Report.Error (5, "/recurse requires an argument");
+ Environment.Exit (1);
+ }
+ CompileFiles (value, true);
+ return true;
+
+ case "/r":
+ case "/reference": {
+ if (value == ""){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+
+ string [] refs = value.Split (new char [] { ';', ',' });
+ foreach (string r in refs){
+ references.Add (r);
+ }
+ return true;
+ }
+ case "/doc": {
+ if (value == ""){
+ Report.Error (5, arg + " requires an argument");
+ Environment.Exit (1);
+ }
+ // TODO handle the /doc argument to generate xml doc
+ return true;
+ }
+ case "/lib": {
+ string [] libdirs;
+
+ if (value == ""){
+ 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":
+ 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 "/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 == ""){
+ Report.Error (5, "/nowarn requires an argument");
+ Environment.Exit (1);
+ }
+
+ warns = value.Split (new Char [] {','});
+ foreach (string wc in warns){
+ int warn = 0;
+
+ try {
+ warn = Int32.Parse (wc);
+ } catch {
+ Usage ();
+ Environment.Exit (1);
+ }
+ Report.SetIgnoreWarning (warn);
+ }
+ return true;
+ }
+
+ case "/noconfig-":
+ load_default_config = true;
+ return true;
+
+ case "/noconfig":
+ case "/noconfig+":
+ load_default_config = false;
+ return true;
+
+ case "/help":
+ case "/?":
+ Usage ();
+ Environment.Exit (0);
+ return true;
+
+ case "/main":
+ case "/m":
+ if (value == ""){
+ 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 "/win32icon":
+ Report.Error (5, "/win32icon is currently not supported");
+ return true;
+
+ case "/v2":
+ SetupV2 ();
+ return true;
+
+ case "/codepage":
+ int cp = -1;
+
+ if (value == "utf8"){
+ encoding = new UTF8Encoding();
+ using_default_encoder = false;
+ return true;
+ }
+ if (value == "reset"){
+ //
+ // 28591 is the code page for ISO-8859-1 encoding.
+ //
+ cp = 28591;
+ using_default_encoder = true;
+ }
+
+ try {
+ cp = Int32.Parse (value);
+ } catch { }
+
+ if (cp == -1){
+ Console.WriteLine ("Invalid code-page requested");
+ Usage ();
+ }
+
+ try {
+ encoding = Encoding.GetEncoding (cp);
+ using_default_encoder = false;
+ } catch {
+ Console.WriteLine ("Code page: {0} not supported", cp);
+ }
+ return true;
+
+ }
+ return false;
+ }
+
+ /// <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")]
+ static bool MainDriver (string [] args)
+ {
+ int i;
+ bool parsing_options = true;
+
+ try {
+ encoding = Encoding.GetEncoding (28591);
+ } catch {
+ Console.WriteLine ("Error: could not load encoding 28591, trying 1252");
+ encoding = Encoding.GetEncoding (1252);
+ }
+
+ references = new ArrayList ();
+ soft_references = new ArrayList ();
+ link_paths = new ArrayList ();
+
+ SetupDefaultDefines ();
+
+ //
+ // Setup defaults
+ //
+ // This is not required because Assembly.Load knows about this
+ // path.
+ //
+
+ int argc = args.Length;
+ for (i = 0; i < argc; i++){
+ string arg = args [i];
+
+ if (arg.StartsWith ("@")){
+ string [] new_args, 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;
+ }
+
+ new_args = new string [extra_args.Length + argc];
+ args.CopyTo (new_args, 0);
+ extra_args.CopyTo (new_args, argc);
+ args = new_args;
+ argc = new_args.Length;
+ 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;
+ } else {
+ if (arg.StartsWith ("/")){
+ if (CSCParseOption (arg, ref args, ref i))
+ continue;
+ }
+ }
+ }
+
+ CompileFiles (arg, false);
+ }
+
+ ProcessFiles ();
+
+ if (tokenize)
+ return true;
+
+ if (first_source == 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 ());
+ LoadReferences ();
+
+ if (timestamps)
+ ShowTime (" References loaded");
+
+ if (Report.Errors > 0){
+ return false;
+ }
+
+ //
+ // Quick hack
+ //
+ if (output_file == null){
+ int pos = first_source.LastIndexOf (".");
+
+ if (pos > 0)
+ output_file = first_source.Substring (0, pos) + target_ext;
+ else
+ output_file = first_source + target_ext;
+ }
+
+ CodeGen.Init (output_file, output_file, want_debugging_support);
+
+ TypeManager.AddModule (CodeGen.ModuleBuilder);
+
+ DateTime start = DateTime.Now;
+ TypeManager.ComputeNamespaces ();
+ DateTime end = DateTime.Now;
+
+ //
+ // 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");
+
+ //
+ // The second pass of the compiler
+ //
+ if (timestamps)
+ ShowTime ("Resolving tree");
+ RootContext.ResolveTree ();
+ if (timestamps)
+ ShowTime ("Populate tree");
+ if (!RootContext.StdLib)
+ RootContext.BootCorlib_PopulateCoreTypes ();
+ RootContext.PopulateTypes ();
+ RootContext.DefineTypes ();
+
+ TypeManager.InitCodeHelpers ();
+
+ //
+ // Verify using aliases now
+ //
+ Namespace.VerifyUsing ();
+
+ 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;
+
+ if (target == Target.Library || target == Target.Module){
+ k = PEFileKinds.Dll;
+
+ if (RootContext.MainClass != null)
+ Report.Error (2017, "Can not specify -main: when building module or library");
+ } else if (target == Target.Exe)
+ k = PEFileKinds.ConsoleApplication;
+ else if (target == Target.WinExe)
+ k = PEFileKinds.WindowApplication;
+
+ if (target == Target.Exe || target == Target.WinExe){
+ MethodInfo ep = RootContext.EntryPoint;
+
+ if (ep == null){
+ if (Report.Errors == 0)
+ Report.Error (5001, "Program " + output_file +
+ " does not have an entry point defined");
+ return false;
+ }
+
+ CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
+ }
+
+ //
+ // Add the resources
+ //
+ if (resources != null){
+ foreach (string spec in resources){
+ string file, res;
+ int cp;
+
+ cp = spec.IndexOf (',');
+ if (cp != -1){
+ file = spec.Substring (0, cp);
+ res = spec.Substring (cp + 1);
+ } else
+ file = res = spec;
+
+ CodeGen.AssemblyBuilder.AddResourceFile (res, file);
+ }
+ }
+
+ if (embedded_resources != null){
+ object[] margs = new object [2];
+ Type[] argst = new Type [2];
+ argst [0] = argst [1] = typeof (string);
+ MethodInfo embed_res = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", argst);
+ if (embed_res == null) {
+ Report.Warning (0, new Location (-1), "Cannot embed resources on this runtime: try the Mono runtime instead.");
+ } else {
+ foreach (string spec in embedded_resources) {
+ int cp;
+
+ cp = spec.IndexOf (',');
+ if (cp != -1){
+ margs [0] = spec.Substring (cp + 1);
+ margs [1] = spec.Substring (0, cp);
+ } else
+ margs [0] = margs [1] = spec;
+
+ if (File.Exists ((string) margs [1]))
+ embed_res.Invoke (CodeGen.AssemblyBuilder, margs);
+ else {
+ Report.Error (1566, "Can not find the resource " + margs [1]);
+ }
+ }
+ }
+ }
+
+ if (Report.Errors > 0)
+ return false;
+
+ CodeGen.Save (output_file);
+ if (timestamps) {
+ ShowTime ("Saved output");
+ ShowTotalTime ("Total");
+ }
+
+ Timer.ShowTimers ();
+
+ if (Report.ExpectedError != 0){
+ Console.WriteLine("Failed to report expected error " + Report.ExpectedError);
+ 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);
+ }
+
+ }
+}
--- /dev/null
+//
+// ecore.cs: Core of the Expression representation for the intermediate tree.
+//
+// Author:
+// Miguel de Icaza (miguel@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;
+ 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,
+
+ // Allows SimpleNames to be returned.
+ // This is used by MemberAccess to construct long names that can not be
+ // partially resolved (namespace-qualified names for example).
+ SimpleName = 8,
+
+ // Mask of all the expression class flags.
+ MaskExprClass = 15,
+
+ // Disable control flow analysis while resolving the expression.
+ // This is used when resolving the instance expression of a field expression.
+ DisableFlowAnalysis = 16
+ }
+
+ //
+ // 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 (bool is_expression);
+ }
+
+ /// <summary>
+ /// This interface denotes an expression which evaluates to a member
+ /// of a struct or a class.
+ /// </summary>
+ public interface IMemberExpr
+ {
+ /// <summary>
+ /// The name of this member.
+ /// </summary>
+ string Name {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is an instance member.
+ /// </summary>
+ bool IsInstance {
+ get;
+ }
+
+ /// <summary>
+ /// Whether this is a static member.
+ /// </summary>
+ bool IsStatic {
+ get;
+ }
+
+ /// <summary>
+ /// The type which declares this member.
+ /// </summary>
+ Type DeclaringType {
+ get;
+ }
+
+ /// <summary>
+ /// The instance expression associated with this member, if it's a
+ /// non-static member.
+ /// </summary>
+ Expression InstanceExpression {
+ get; set;
+ }
+ }
+
+ /// <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 Location Location {
+ get {
+ return loc;
+ }
+ }
+
+ /// <summary>
+ /// Utility wrapper routine for Error, just to beautify the code
+ /// </summary>
+ public void Error (int error, string s)
+ {
+ if (!Location.IsNull (loc))
+ Report.Error (error, loc, s);
+ else
+ Report.Error (error, s);
+ }
+
+ /// <summary>
+ /// Utility wrapper routine for Warning, just to beautify the code
+ /// </summary>
+ public void Warning (int warning, string s)
+ {
+ if (!Location.IsNull (loc))
+ Report.Warning (warning, loc, s);
+ else
+ Report.Warning (warning, s);
+ }
+
+ /// <summary>
+ /// Utility wrapper routine for Warning, only prints the warning if
+ /// warnings of level `level' are enabled.
+ /// </summary>
+ public void Warning (int warning, int level, string s)
+ {
+ if (level <= RootContext.WarningLevel)
+ Warning (warning, s);
+ }
+
+ /// <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 DoResolve (ec);
+ }
+
+ //
+ // This is used if the expression should be resolved as a type.
+ // the default implementation fails. Use this method in
+ // those participants in the SimpleName chain system.
+ //
+ public virtual Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ 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 Expression ResolveAsTypeTerminal (EmitContext ec)
+ {
+ Expression e = ResolveAsTypeStep (ec);
+
+ if (e == null)
+ return null;
+ if (e is SimpleName)
+ return null;
+ return e;
+ }
+
+ /// <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);
+
+ bool old_do_flow_analysis = ec.DoFlowAnalysis;
+ if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
+ ec.DoFlowAnalysis = false;
+
+ Expression e;
+ if (this is SimpleName)
+ e = ((SimpleName) this).DoResolveAllowStatic (ec);
+ else
+ e = DoResolve (ec);
+
+ ec.DoFlowAnalysis = old_do_flow_analysis;
+
+ if (e == null)
+ return null;
+
+ if (e is SimpleName){
+ SimpleName s = (SimpleName) e;
+
+ if ((flags & ResolveFlags.SimpleName) == 0) {
+ MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
+ ec.DeclSpace.Name, loc);
+ return null;
+ }
+
+ return s;
+ }
+
+ if ((e is TypeExpr) || (e is ComposedCast)) {
+ if ((flags & ResolveFlags.Type) == 0) {
+ e.Error_UnexpectedKind (flags);
+ return null;
+ }
+
+ return e;
+ }
+
+ switch (e.eclass) {
+ case ExprClass.Type:
+ if ((flags & ResolveFlags.VariableOrValue) == 0) {
+ e.Error_UnexpectedKind (flags);
+ return null;
+ }
+ break;
+
+ case ExprClass.MethodGroup:
+ if ((flags & ResolveFlags.MethodGroup) == 0) {
+ ((MethodGroupExpr) e).ReportUsageError ();
+ return null;
+ }
+ break;
+
+ case ExprClass.Value:
+ case ExprClass.Variable:
+ case ExprClass.PropertyAccess:
+ case ExprClass.EventAccess:
+ case ExprClass.IndexerAccess:
+ if ((flags & ResolveFlags.VariableOrValue) == 0) {
+ Console.WriteLine ("I got: {0} and {1}", e.GetType (), e);
+ Console.WriteLine ("I am {0} and {1}", this.GetType (), this);
+ FieldInfo fi = ((FieldExpr) e).FieldInfo;
+
+ Console.WriteLine ("{0} and {1}", fi.DeclaringType, fi.Name);
+ e.Error_UnexpectedKind (flags);
+ return null;
+ }
+ break;
+
+ default:
+ throw new Exception ("Expression " + e.GetType () +
+ " ExprClass is Invalid after resolve");
+ }
+
+ if (e.type == null)
+ 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)
+ {
+ return Resolve (ec, ResolveFlags.VariableOrValue);
+ }
+
+ /// <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)
+ {
+ Expression e = DoResolveLValue (ec, right_side);
+
+ if (e != null){
+ if (e is SimpleName){
+ SimpleName s = (SimpleName) e;
+ MemberLookupFailed (ec, null, ec.ContainerType, s.Name,
+ ec.DeclSpace.Name, 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)
+ 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);
+
+ /// <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);
+ else if (t == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ else if (t == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ else if (t == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ else if (t == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ else if (t == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ else if (t == TypeManager.string_type)
+ return new StringConstant ((string) v);
+ else if (t == TypeManager.short_type)
+ return new ShortConstant ((short)v);
+ else if (t == TypeManager.ushort_type)
+ return new UShortConstant ((ushort)v);
+ else if (t == TypeManager.sbyte_type)
+ return new SByteConstant (((sbyte)v));
+ else if (t == TypeManager.byte_type)
+ return new ByteConstant ((byte)v);
+ else if (t == TypeManager.char_type)
+ return new CharConstant ((char)v);
+ else if (t == TypeManager.bool_type)
+ return new BoolConstant ((bool) v);
+ else if (TypeManager.IsEnumType (t)){
+ Constant e = Constantify (v, TypeManager.TypeToCoreType (v.GetType ()));
+
+ return new EnumConstant (e, t);
+ } 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 (EmitContext ec, 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 (ec, (PropertyInfo) mi, loc);
+ else if (mi is Type){
+ return new TypeExpr ((System.Type) mi, loc);
+ }
+
+ return null;
+ }
+
+ //
+ // 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 (EmitContext ec, Type queried_type, string name,
+ MemberTypes mt, BindingFlags bf, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, 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 (EmitContext ec, Type container_type,
+ Type qualifier_type, Type queried_type,
+ string name, MemberTypes mt,
+ BindingFlags bf, Location loc)
+ {
+ MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
+ queried_type, mt, bf, name);
+
+ if (mi == null)
+ return null;
+
+ int count = mi.Length;
+
+ if (mi [0] is MethodBase)
+ return new MethodGroupExpr (mi, loc);
+
+ if (count > 1)
+ return null;
+
+ return ExprClassFromMemberInfo (ec, 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 (EmitContext ec, Type queried_type,
+ string name, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
+ AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MemberLookup (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
+ name, AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MethodLookup (EmitContext ec, Type queried_type,
+ string name, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, 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, ec.ContainerType, qualifier_type, queried_type,
+ name, mt, bf, loc);
+
+ if (e != null)
+ return e;
+
+ // Error has already been reported.
+ if (errors < Report.Errors)
+ return null;
+
+ MemberLookupFailed (ec, qualifier_type, queried_type, name, null, loc);
+ return null;
+ }
+
+ public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
+ Type queried_type, string name,
+ string class_name, Location loc)
+ {
+ object lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
+ AllMemberTypes, AllBindingFlags |
+ BindingFlags.NonPublic, name);
+
+ if (lookup == null) {
+ if (class_name != null)
+ Report.Error (103, loc, "The name `" + name + "' could not be " +
+ "found in `" + class_name + "'");
+ else
+ Report.Error (
+ 117, loc, "`" + queried_type + "' does not contain a " +
+ "definition for `" + name + "'");
+ return;
+ }
+
+ if ((qualifier_type != null) && (qualifier_type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (qualifier_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 parent of the
+ // ec.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
+
+ lookup = TypeManager.MemberLookup (
+ ec.ContainerType, ec.ContainerType, ec.ContainerType,
+ AllMemberTypes, AllBindingFlags, name);
+
+ if (lookup != null) {
+ Report.Error (
+ 1540, loc, "Cannot access protected member `" +
+ TypeManager.CSharpName (qualifier_type) + "." +
+ name + "' " + "via a qualifier of type `" +
+ TypeManager.CSharpName (qualifier_type) + "'; the " +
+ "qualifier must be of type `" +
+ TypeManager.CSharpName (ec.ContainerType) + "' " +
+ "(or derived from it)");
+ return;
+ }
+ }
+
+ if (qualifier_type != null)
+ Report.Error (
+ 122, loc, "`" + TypeManager.CSharpName (qualifier_type) + "." +
+ name + "' is inaccessible due to its protection level");
+ else
+ Report.Error (
+ 122, loc, "`" + name + "' is inaccessible due to its " +
+ "protection level");
+ }
+
+ static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
+ {
+ EventInfo ei = event_expr.EventInfo;
+
+ return TypeManager.GetPrivateFieldOfEvent (ei);
+ }
+
+ /// <summary>
+ /// Returns an expression that can be used to invoke operator true
+ /// on the expression if it exists.
+ /// </summary>
+ static public StaticCallExpr 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 StaticCallExpr GetOperatorFalse (EmitContext ec, Expression e, Location loc)
+ {
+ return GetOperatorTrueOrFalse (ec, e, false, loc);
+ }
+
+ static StaticCallExpr GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
+ {
+ MethodBase method;
+ Expression operator_group;
+
+ operator_group = MethodLookup (ec, 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, 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;
+
+ Expression converted = e;
+ if (e.Type != TypeManager.bool_type)
+ converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, new Location (-1));
+
+ //
+ // If no implicit conversion to bool exists, try using `operator true'
+ //
+ if (converted == null){
+ Expression operator_true = Expression.GetOperatorTrue (ec, e, loc);
+ if (operator_true == null){
+ Report.Error (
+ 31, loc, "Can not convert the expression to a boolean");
+ return null;
+ }
+ e = operator_true;
+ } else
+ e = converted;
+
+ return e;
+ }
+
+ static string ExprClassName (ExprClass c)
+ {
+ switch (c){
+ 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 (string expected)
+ {
+ string kind = "Unknown";
+
+ kind = ExprClassName (eclass);
+
+ Error (118, "Expression denotes a `" + kind +
+ "' where a `" + expected + "' was expected");
+ }
+
+ public void Error_UnexpectedKind (ResolveFlags flags)
+ {
+ ArrayList valid = new ArrayList (10);
+
+ if ((flags & ResolveFlags.VariableOrValue) != 0) {
+ valid.Add ("variable");
+ valid.Add ("value");
+ }
+
+ if ((flags & ResolveFlags.Type) != 0)
+ valid.Add ("type");
+
+ if ((flags & ResolveFlags.MethodGroup) != 0)
+ valid.Add ("method group");
+
+ if ((flags & ResolveFlags.SimpleName) != 0)
+ valid.Add ("simple name");
+
+ if (valid.Count == 0)
+ valid.Add ("unknown");
+
+ StringBuilder sb = new StringBuilder ();
+ for (int i = 0; i < valid.Count; i++) {
+ if (i > 0)
+ sb.Append (", ");
+ else if (i == valid.Count)
+ sb.Append (" or ");
+ sb.Append (valid [i]);
+ }
+
+ string kind = ExprClassName (eclass);
+
+ Error (119, "Expression denotes a `" + kind + "' where " +
+ "a `" + sb.ToString () + "' was expected");
+ }
+
+ static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t)
+ {
+ Report.Error (31, l, "Constant value `" + val + "' cannot be converted to " +
+ TypeManager.CSharpName (t));
+ }
+
+ public static void UnsafeError (Location loc)
+ {
+ Report.Error (214, loc, "Pointers may only be used in an unsafe context");
+ }
+
+ /// <summary>
+ /// Converts the IntConstant, UIntConstant, LongConstant or
+ /// ULongConstant into the integral target_type. Notice
+ /// that we do not return an `Expression' we do return
+ /// a boxed integral type.
+ ///
+ /// FIXME: Since I added the new constants, we need to
+ /// also support conversions from CharConstant, ByteConstant,
+ /// SByteConstant, UShortConstant, ShortConstant
+ ///
+ /// This is used by the switch statement, so the domain
+ /// of work is restricted to the literals above, and the
+ /// targets are int32, uint32, char, byte, sbyte, ushort,
+ /// short, uint64 and int64
+ /// </summary>
+ public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
+ {
+ if (!Convert.ImplicitStandardConversionExists (c, target_type)){
+ Convert.Error_CannotImplicitConversion (loc, c.Type, target_type);
+ return null;
+ }
+
+ string s = "";
+
+ if (c.Type == target_type)
+ return ((Constant) c).GetValue ();
+
+ //
+ // Make into one of the literals we handle, we dont really care
+ // about this value as we will just return a few limited types
+ //
+ if (c is EnumConstant)
+ c = ((EnumConstant)c).WidenToCompilerConstant ();
+
+ if (c is IntConstant){
+ int v = ((IntConstant) c).Value;
+
+ if (target_type == TypeManager.uint32_type){
+ if (v >= 0)
+ return (uint) v;
+ } else if (target_type == TypeManager.char_type){
+ if (v >= Char.MinValue && v <= Char.MaxValue)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v >= Byte.MinValue && v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v >= SByte.MinValue && v <= SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.short_type){
+ if (v >= Int16.MinValue && v <= UInt16.MaxValue)
+ return (short) v;
+ } else if (target_type == TypeManager.ushort_type){
+ if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
+ return (ushort) v;
+ } else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type){
+ if (v > 0)
+ return (ulong) v;
+ }
+
+ s = v.ToString ();
+ } else if (c is UIntConstant){
+ uint v = ((UIntConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type){
+ if (v <= Int32.MaxValue)
+ return (int) v;
+ } else if (target_type == TypeManager.char_type){
+ if (v >= Char.MinValue && v <= Char.MaxValue)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v <= SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.short_type){
+ if (v <= UInt16.MaxValue)
+ return (short) v;
+ } else if (target_type == TypeManager.ushort_type){
+ if (v <= UInt16.MaxValue)
+ return (ushort) v;
+ } else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type)
+ return (ulong) v;
+ s = v.ToString ();
+ } else if (c is LongConstant){
+ long v = ((LongConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type){
+ if (v >= UInt32.MinValue && v <= UInt32.MaxValue)
+ return (int) v;
+ } else if (target_type == TypeManager.uint32_type){
+ if (v >= 0 && v <= UInt32.MaxValue)
+ return (uint) v;
+ } else if (target_type == TypeManager.char_type){
+ if (v >= Char.MinValue && v <= Char.MaxValue)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v >= Byte.MinValue && v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v >= SByte.MinValue && v <= SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.short_type){
+ if (v >= Int16.MinValue && v <= UInt16.MaxValue)
+ return (short) v;
+ } else if (target_type == TypeManager.ushort_type){
+ if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
+ return (ushort) v;
+ } else if (target_type == TypeManager.uint64_type){
+ if (v > 0)
+ return (ulong) v;
+ }
+ s = v.ToString ();
+ } else if (c is ULongConstant){
+ ulong v = ((ULongConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type){
+ if (v <= Int32.MaxValue)
+ return (int) v;
+ } else if (target_type == TypeManager.uint32_type){
+ if (v <= UInt32.MaxValue)
+ return (uint) v;
+ } else if (target_type == TypeManager.char_type){
+ if (v >= Char.MinValue && v <= Char.MaxValue)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v >= Byte.MinValue && v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v <= (int) SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.short_type){
+ if (v <= UInt16.MaxValue)
+ return (short) v;
+ } else if (target_type == TypeManager.ushort_type){
+ if (v <= UInt16.MaxValue)
+ return (ushort) v;
+ } else if (target_type == TypeManager.int64_type){
+ if (v <= Int64.MaxValue)
+ return (long) v;
+ }
+ s = v.ToString ();
+ } else if (c is ByteConstant){
+ byte v = ((ByteConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type)
+ return (int) v;
+ else if (target_type == TypeManager.uint32_type)
+ return (uint) v;
+ else if (target_type == TypeManager.char_type)
+ return (char) v;
+ else if (target_type == TypeManager.sbyte_type){
+ if (v <= SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.short_type)
+ return (short) v;
+ else if (target_type == TypeManager.ushort_type)
+ return (ushort) v;
+ else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type)
+ return (ulong) v;
+ s = v.ToString ();
+ } else if (c is SByteConstant){
+ sbyte v = ((SByteConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type)
+ return (int) v;
+ else if (target_type == TypeManager.uint32_type){
+ if (v >= 0)
+ return (uint) v;
+ } else if (target_type == TypeManager.char_type){
+ if (v >= 0)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v >= 0)
+ return (byte) v;
+ } else if (target_type == TypeManager.short_type)
+ return (short) v;
+ else if (target_type == TypeManager.ushort_type){
+ if (v >= 0)
+ return (ushort) v;
+ } else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type){
+ if (v >= 0)
+ return (ulong) v;
+ }
+ s = v.ToString ();
+ } else if (c is ShortConstant){
+ short v = ((ShortConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type){
+ return (int) v;
+ } else if (target_type == TypeManager.uint32_type){
+ if (v >= 0)
+ return (uint) v;
+ } else if (target_type == TypeManager.char_type){
+ if (v >= 0)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v >= Byte.MinValue && v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v >= SByte.MinValue && v <= SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.ushort_type){
+ if (v >= 0)
+ return (ushort) v;
+ } else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type)
+ return (ulong) v;
+
+ s = v.ToString ();
+ } else if (c is UShortConstant){
+ ushort v = ((UShortConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type)
+ return (int) v;
+ else if (target_type == TypeManager.uint32_type)
+ return (uint) v;
+ else if (target_type == TypeManager.char_type){
+ if (v >= Char.MinValue && v <= Char.MaxValue)
+ return (char) v;
+ } else if (target_type == TypeManager.byte_type){
+ if (v >= Byte.MinValue && v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v <= SByte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.short_type){
+ if (v <= Int16.MaxValue)
+ return (short) v;
+ } else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type)
+ return (ulong) v;
+
+ s = v.ToString ();
+ } else if (c is CharConstant){
+ char v = ((CharConstant) c).Value;
+
+ if (target_type == TypeManager.int32_type)
+ return (int) v;
+ else if (target_type == TypeManager.uint32_type)
+ return (uint) v;
+ else if (target_type == TypeManager.byte_type){
+ if (v >= Byte.MinValue && v <= Byte.MaxValue)
+ return (byte) v;
+ } else if (target_type == TypeManager.sbyte_type){
+ if (v <= SByte.MaxValue)
+ return (sbyte) v;
+ } else if (target_type == TypeManager.short_type){
+ if (v <= Int16.MaxValue)
+ return (short) v;
+ } else if (target_type == TypeManager.ushort_type)
+ return (short) v;
+ else if (target_type == TypeManager.int64_type)
+ return (long) v;
+ else if (target_type == TypeManager.uint64_type)
+ return (ulong) v;
+
+ s = v.ToString ();
+ }
+ Error_ConstantValueCannotBeConverted (loc, s, target_type);
+ return null;
+ }
+
+ //
+ // 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)
+ 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)
+ 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;
+ }
+
+ //
+ // Default implementation of IAssignMethod.CacheTemporaries
+ //
+ public void CacheTemporaries (EmitContext ec)
+ {
+ }
+
+ static void Error_NegativeArrayIndex (Location loc)
+ {
+ Report.Error (284, loc, "Can not create array with a negative size");
+ }
+
+ //
+ // Converts `source' to an int, uint, long or ulong.
+ //
+ public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
+ {
+ Expression target;
+
+ bool old_checked = ec.CheckState;
+ ec.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)
+ Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
+ }
+ }
+ }
+ ec.CheckState = old_checked;
+
+ //
+ // 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 Expression child;
+
+ public EmptyCast (Expression child, Type return_type)
+ {
+ eclass = child.eclass;
+ 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);
+ }
+ }
+
+ //
+ // We need to special case this since an empty cast of
+ // a NullLiteral is still a Constant
+ //
+ public class NullCast : Constant {
+ protected Expression child;
+
+ public NullCast (Expression child, Type return_type)
+ {
+ eclass = child.eclass;
+ type = return_type;
+ this.child = child;
+ }
+
+ override public string AsString ()
+ {
+ return "null";
+ }
+
+ public override object GetValue ()
+ {
+ return null;
+ }
+
+ 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);
+ }
+ }
+
+
+ /// <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)
+ {
+ 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 object GetValue ()
+ {
+ return Child.GetValue ();
+ }
+
+ //
+ // Converts from one of the valid underlying types for an enumeration
+ // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
+ // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
+ //
+ public Constant WidenToCompilerConstant ()
+ {
+ Type t = TypeManager.EnumToUnderlying (Child.Type);
+ object v = ((Constant) Child).GetValue ();;
+
+ if (t == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (t == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (t == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (t == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (t == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (t == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (t == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (t == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+
+ throw new Exception ("Invalid enumeration underlying type: " + t);
+ }
+
+ //
+ // Extracts the value in the enumeration on its native representation
+ //
+ public object GetPlainValue ()
+ {
+ Type t = TypeManager.EnumToUnderlying (Child.Type);
+ object v = ((Constant) Child).GetValue ();;
+
+ if (t == TypeManager.int32_type)
+ return (int) v;
+ if (t == TypeManager.uint32_type)
+ return (uint) v;
+ if (t == TypeManager.int64_type)
+ return (long) v;
+ if (t == TypeManager.uint64_type)
+ return (ulong) v;
+ if (t == TypeManager.short_type)
+ return (short) v;
+ if (t == TypeManager.ushort_type)
+ return (ushort) v;
+ if (t == TypeManager.byte_type)
+ return (byte) v;
+ if (t == TypeManager.sbyte_type)
+ return (sbyte) v;
+
+ return null;
+ }
+
+ 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 ();
+ }
+ }
+
+ /// <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)
+ : base (expr, TypeManager.object_type)
+ {
+ }
+
+ public BoxedCast (Expression expr, Type target_type)
+ : base (expr, target_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);
+
+ 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 void Emit (EmitContext ec)
+ {
+ Type t = type;
+ ILGenerator ig = ec.ig;
+
+ base.Emit (ec);
+ 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;
+ bool checked_state;
+
+ public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m)
+ : base (child, return_type)
+ {
+ checked_state = ec.CheckState;
+ 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 (checked_state){
+ 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);
+
+ ec.ig.Emit (OpCodes.Castclass, type);
+ }
+
+ }
+
+ /// <summary>
+ /// SimpleName expressions are initially formed of a single
+ /// word and it only happens at the beginning of the expression.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// The expression will try to be bound to a Field, a Method
+ /// group or a Property. If those fail we pass the name to our
+ /// caller and the SimpleName is compounded to perform a type
+ /// lookup. The idea behind this process is that we want to avoid
+ /// creating a namespace map from the assemblies, as that requires
+ /// the GetExportedTypes function to be called and a hashtable to
+ /// be constructed which reduces startup time. If later we find
+ /// that this is slower, we should create a `NamespaceExpr' expression
+ /// that fully participates in the resolution process.
+ ///
+ /// For example `System.Console.WriteLine' is decomposed into
+ /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
+ ///
+ /// The first SimpleName wont produce a match on its own, so it will
+ /// be turned into:
+ /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
+ ///
+ /// System.Console will produce a TypeExpr match.
+ ///
+ /// The downside of this is that we might be hitting `LookupType' too many
+ /// times with this scheme.
+ /// </remarks>
+ public class SimpleName : Expression {
+ public string Name;
+
+ //
+ // If true, then we are a simple name, not composed with a ".
+ //
+ bool is_base;
+
+ public SimpleName (string a, string b, Location l)
+ {
+ Name = String.Concat (a, ".", b);
+ loc = l;
+ is_base = false;
+ }
+
+ public SimpleName (string name, Location l)
+ {
+ Name = name;
+ loc = l;
+ is_base = true;
+ }
+
+ public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
+ {
+ if (ec.IsFieldInitializer)
+ Report.Error (
+ 236, l,
+ "A field initializer cannot reference the non-static field, " +
+ "method or property `"+name+"'");
+ else
+ Report.Error (
+ 120, l,
+ "An object reference is required " +
+ "for the non-static field `"+name+"'");
+ }
+
+ //
+ // Checks whether we are trying to access an instance
+ // property, method or field from a static body.
+ //
+ Expression MemberStaticCheck (EmitContext ec, Expression e)
+ {
+ if (e is IMemberExpr){
+ IMemberExpr member = (IMemberExpr) e;
+
+ if (!member.IsStatic){
+ Error_ObjectRefRequired (ec, loc, Name);
+ return null;
+ }
+ }
+
+ return e;
+ }
+
+ 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 DoResolveAllowStatic (EmitContext ec)
+ {
+ return SimpleNameResolve (ec, null, true);
+ }
+
+ public override Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ DeclSpace ds = ec.DeclSpace;
+ NamespaceEntry ns = ds.Namespace;
+ Type t;
+ string alias_value;
+
+ //
+ // Since we are cheating: we only do the Alias lookup for
+ // namespaces if the name does not include any dots in it
+ //
+ if (ns != null && is_base)
+ alias_value = ns.LookupAlias (Name);
+ else
+ alias_value = null;
+
+ if (ec.ResolvingTypeTree){
+ if (alias_value != null){
+ if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
+ return new TypeExpr (t, loc);
+ }
+
+ int errors = Report.Errors;
+ Type dt = ec.DeclSpace.FindType (loc, Name);
+
+ if (Report.Errors != errors)
+ return null;
+
+ if (dt != null)
+ return new TypeExpr (dt, loc);
+ }
+
+ //
+ // First, the using aliases
+ //
+ if (alias_value != null){
+ if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
+ return new TypeExpr (t, loc);
+
+ // we have alias value, but it isn't Type, so try if it's namespace
+ return new SimpleName (alias_value, loc);
+ }
+
+ //
+ // Stage 2: Lookup up if we are an alias to a type
+ // or a namespace.
+ //
+
+ if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
+ return new TypeExpr (t, loc);
+
+ // No match, maybe our parent can compose us
+ // into something meaningful.
+ return this;
+ }
+
+ /// <remarks>
+ /// 7.5.2: Simple Names.
+ ///
+ /// Local Variables and Parameters are handled at
+ /// parse time, so they never occur as SimpleNames.
+ ///
+ /// The `allow_static' 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 SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
+ {
+ Expression e = null;
+
+ //
+ // Since we are cheating (is_base is our hint
+ // that we are the beginning of the name): we
+ // only do the Alias lookup for namespaces if
+ // the name does not include any dots in it
+ //
+ NamespaceEntry ns = ec.DeclSpace.Namespace;
+ if (is_base && ns != null){
+ string alias_value = ns.LookupAlias (Name);
+ if (alias_value != null){
+ Name = alias_value;
+ Type t;
+
+ if ((t = TypeManager.LookupType (Name)) != null)
+ return new TypeExpr (t, loc);
+
+ // No match, maybe our parent can compose us
+ // into something meaningful.
+ return this;
+ }
+ }
+
+
+ //
+ // 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){
+ Expression var;
+
+ var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
+
+ if (right_side != null)
+ return var.ResolveLValue (ec, right_side);
+ else
+ return var.Resolve (ec);
+ }
+
+ int idx = -1;
+ Parameter par = null;
+ Parameters pars = current_block.Parameters;
+ if (pars != null)
+ par = pars.GetParameterByName (Name, out idx);
+
+ if (par != null) {
+ ParameterReference param;
+
+ param = new ParameterReference (pars, current_block, idx, Name, loc);
+
+ if (right_side != null)
+ return param.ResolveLValue (ec, right_side);
+ else
+ return param.Resolve (ec);
+ }
+ }
+
+ //
+ // Stage 2: Lookup members
+ //
+
+ DeclSpace lookup_ds = ec.DeclSpace;
+ do {
+ if (lookup_ds.TypeBuilder == null)
+ break;
+
+ e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
+ if (e != null)
+ break;
+
+ lookup_ds =lookup_ds.Parent;
+ } while (lookup_ds != null);
+
+ if (e == null && ec.ContainerType != null)
+ e = MemberLookup (ec, ec.ContainerType, Name, loc);
+
+ if (e == null)
+ return ResolveAsTypeStep (ec);
+
+ if (e is TypeExpr)
+ return e;
+
+ if (e is IMemberExpr) {
+ e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this);
+ if (e == null)
+ return null;
+
+ IMemberExpr me = e as IMemberExpr;
+ if (me == null)
+ return e;
+
+ // This fails if ResolveMemberAccess() was unable to decide whether
+ // it's a field or a type of the same name.
+ if (!me.IsStatic && (me.InstanceExpression == null))
+ return e;
+
+ if (!me.IsStatic &&
+ TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType) &&
+ !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType)) {
+ Error (38, "Cannot access nonstatic member `" + me.Name + "' of " +
+ "outer type `" + me.DeclaringType + "' via nested type `" +
+ me.InstanceExpression.Type + "'");
+ return null;
+ }
+
+ if (right_side != null)
+ e = e.DoResolveLValue (ec, right_side);
+ else
+ e = e.DoResolve (ec);
+
+ return e;
+ }
+
+ if (ec.IsStatic || ec.IsFieldInitializer){
+ if (allow_static)
+ return e;
+
+ return MemberStaticCheck (ec, e);
+ } else
+ 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.DeclSpace.Name + "'");
+ }
+
+ public override string ToString ()
+ {
+ return Name;
+ }
+ }
+
+ /// <summary>
+ /// Fully resolved expression that evaluates to a type
+ /// </summary>
+ public class TypeExpr : Expression {
+ public TypeExpr (Type t, Location l)
+ {
+ Type = t;
+ eclass = ExprClass.Type;
+ loc = l;
+ }
+
+ public override Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ return this;
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be called");
+ }
+
+ public override string ToString ()
+ {
+ return Type.ToString ();
+ }
+ }
+
+ /// <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 class TypeLookupExpression : TypeExpr {
+ string name;
+
+ public TypeLookupExpression (string name) : base (null, Location.Null)
+ {
+ this.name = name;
+ }
+
+ public override Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ if (type == null)
+ type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return ResolveAsTypeStep (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be called");
+ }
+
+ public override string ToString ()
+ {
+ return name;
+ }
+ }
+
+ /// <summary>
+ /// MethodGroup Expression.
+ ///
+ /// This is a fully resolved expression that evaluates to a type
+ /// </summary>
+ public class MethodGroupExpr : Expression, IMemberExpr {
+ public MethodBase [] Methods;
+ Expression instance_expression = null;
+ bool is_explicit_impl = false;
+
+ 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 Type DeclaringType {
+ get {
+ //
+ // We assume that the top-level type is in the end
+ //
+ return Methods [Methods.Length - 1].DeclaringType;
+ //return Methods [0].DeclaringType;
+ }
+ }
+
+ //
+ // `A method group may have associated an instance expression'
+ //
+ public Expression InstanceExpression {
+ get {
+ return instance_expression;
+ }
+
+ set {
+ instance_expression = value;
+ }
+ }
+
+ public bool IsExplicitImpl {
+ get {
+ return is_explicit_impl;
+ }
+
+ set {
+ is_explicit_impl = value;
+ }
+ }
+
+ public string Name {
+ get {
+ //return Methods [0].Name;
+ return Methods [Methods.Length - 1].Name;
+ }
+ }
+
+ public bool IsInstance {
+ get {
+ foreach (MethodBase mb in Methods)
+ if (!mb.IsStatic)
+ return true;
+
+ return false;
+ }
+ }
+
+ public bool IsStatic {
+ get {
+ foreach (MethodBase mb in Methods)
+ if (mb.IsStatic)
+ return true;
+
+ return false;
+ }
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (!IsInstance)
+ instance_expression = null;
+
+ if (instance_expression != null) {
+ instance_expression = instance_expression.DoResolve (ec);
+ if (instance_expression == 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);
+ }
+ }
+
+ /// <summary>
+ /// Fully resolved expression that evaluates to a Field
+ /// </summary>
+ public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr, IVariable {
+ public readonly FieldInfo FieldInfo;
+ Expression instance_expr;
+ VariableInfo variable_info;
+
+ public FieldExpr (FieldInfo fi, Location l)
+ {
+ FieldInfo = fi;
+ eclass = ExprClass.Variable;
+ type = fi.FieldType;
+ loc = l;
+ }
+
+ public string Name {
+ get {
+ return FieldInfo.Name;
+ }
+ }
+
+ public bool IsInstance {
+ get {
+ return !FieldInfo.IsStatic;
+ }
+ }
+
+ public bool IsStatic {
+ get {
+ return FieldInfo.IsStatic;
+ }
+ }
+
+ public Type DeclaringType {
+ get {
+ return FieldInfo.DeclaringType;
+ }
+ }
+
+ public Expression InstanceExpression {
+ get {
+ return instance_expr;
+ }
+
+ set {
+ instance_expr = value;
+ }
+ }
+
+ public VariableInfo VariableInfo {
+ get {
+ return variable_info;
+ }
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (!FieldInfo.IsStatic){
+ if (instance_expr == null){
+ //
+ // This can happen when referencing an instance field using
+ // a fully qualified type expression: TypeName.InstanceField = xxx
+ //
+ SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
+ 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.
+ instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue |
+ ResolveFlags.DisableFlowAnalysis);
+ if (instance_expr == null)
+ return null;
+ }
+
+ // If the instance expression is a local variable or parameter.
+ IVariable var = instance_expr 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;
+ }
+
+ void Report_AssignToReadonly (bool is_instance)
+ {
+ string msg;
+
+ if (is_instance)
+ msg = "Readonly field can not be assigned outside " +
+ "of constructor or variable initializer";
+ else
+ msg = "A static readonly field can only be assigned in " +
+ "a static constructor";
+
+ Report.Error (is_instance ? 191 : 198, loc, msg);
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ IVariable var = instance_expr as IVariable;
+ if ((var != null) && (var.VariableInfo != null))
+ var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
+
+ Expression e = DoResolve (ec);
+
+ if (e == null)
+ return null;
+
+ if (!FieldInfo.IsStatic && (instance_expr.Type.IsValueType && !(instance_expr is IMemoryLocation))) {
+ // FIXME: Provide better error reporting.
+ Error (1612, "Cannot modify expression because it is not a variable.");
+ return null;
+ }
+
+ if (!FieldInfo.IsInitOnly)
+ return this;
+
+ //
+ // InitOnly fields can only be assigned in constructors
+ //
+
+ if (ec.IsConstructor){
+ if (ec.ContainerType == FieldInfo.DeclaringType)
+ return this;
+ }
+
+ Report_AssignToReadonly (true);
+
+ return null;
+ }
+
+ public bool VerifyFixed (bool is_expression)
+ {
+ IVariable variable = instance_expr as IVariable;
+ if ((variable == null) || !variable.VerifyFixed (true))
+ return false;
+
+ return true;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ bool is_volatile = false;
+
+ if (FieldInfo is FieldBuilder){
+ FieldBase f = TypeManager.GetField (FieldInfo);
+
+ if ((f.ModFlags & Modifiers.VOLATILE) != 0)
+ is_volatile = true;
+
+ f.status |= Field.Status.USED;
+ }
+
+ if (FieldInfo.IsStatic){
+ if (is_volatile)
+ ig.Emit (OpCodes.Volatile);
+
+ ig.Emit (OpCodes.Ldsfld, FieldInfo);
+ return;
+ }
+
+ if (instance_expr.Type.IsValueType){
+ IMemoryLocation ml;
+ LocalTemporary tempo = null;
+
+ if (!(instance_expr is IMemoryLocation)){
+ tempo = new LocalTemporary (ec, instance_expr.Type);
+
+ if (ec.RemapToProxy)
+ ec.EmitThis ();
+
+ InstanceExpression.Emit (ec);
+ tempo.Store (ec);
+ ml = tempo;
+ } else
+ ml = (IMemoryLocation) instance_expr;
+
+ ml.AddressOf (ec, AddressOp.Load);
+ } else {
+ if (ec.RemapToProxy)
+ ec.EmitThis ();
+ else
+ instance_expr.Emit (ec);
+ }
+ if (is_volatile)
+ ig.Emit (OpCodes.Volatile);
+
+ ig.Emit (OpCodes.Ldfld, FieldInfo);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ FieldAttributes fa = FieldInfo.Attributes;
+ bool is_static = (fa & FieldAttributes.Static) != 0;
+ bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
+ ILGenerator ig = ec.ig;
+
+ if (is_readonly && !ec.IsConstructor){
+ Report_AssignToReadonly (!is_static);
+ return;
+ }
+
+ if (!is_static){
+ Expression instance = instance_expr;
+
+ if (instance.Type.IsValueType){
+ IMemoryLocation ml = (IMemoryLocation) instance;
+
+ ml.AddressOf (ec, AddressOp.Store);
+ } else {
+ if (ec.RemapToProxy)
+ ec.EmitThis ();
+ else
+ instance.Emit (ec);
+ }
+ }
+
+ source.Emit (ec);
+
+ if (FieldInfo is FieldBuilder){
+ FieldBase f = TypeManager.GetField (FieldInfo);
+
+ if ((f.ModFlags & Modifiers.VOLATILE) != 0)
+ ig.Emit (OpCodes.Volatile);
+
+ f.status |= Field.Status.ASSIGNED;
+ }
+
+ if (is_static)
+ ig.Emit (OpCodes.Stsfld, FieldInfo);
+ else
+ ig.Emit (OpCodes.Stfld, FieldInfo);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (FieldInfo is FieldBuilder){
+ FieldBase f = TypeManager.GetField (FieldInfo);
+ if ((f.ModFlags & Modifiers.VOLATILE) != 0){
+ Error (676, "volatile variable: can not take its address, or pass as ref/out parameter");
+ return;
+ }
+
+ if ((mode & AddressOp.Store) != 0)
+ f.status |= Field.Status.ASSIGNED;
+ if ((mode & AddressOp.Load) != 0)
+ f.status |= Field.Status.USED;
+ }
+
+ //
+ // Handle initonly fields specially: make a copy and then
+ // get the address of the copy.
+ //
+ if (FieldInfo.IsInitOnly && !ec.IsConstructor){
+ 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 {
+ //
+ // In the case of `This', we call the AddressOf method, which will
+ // only load the pointer, and not perform an Ldobj immediately after
+ // the value has been loaded into the stack.
+ //
+ if (instance_expr is This)
+ ((This)instance_expr).AddressOf (ec, AddressOp.LoadStore);
+ else if (instance_expr.Type.IsValueType && instance_expr is IMemoryLocation){
+ IMemoryLocation ml = (IMemoryLocation) instance_expr;
+
+ ml.AddressOf (ec, AddressOp.LoadStore);
+ } else
+ instance_expr.Emit (ec);
+ ig.Emit (OpCodes.Ldflda, FieldInfo);
+ }
+ }
+ }
+
+ /// <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 : ExpressionStatement, IAssignMethod, IMemberExpr {
+ public readonly PropertyInfo PropertyInfo;
+
+ //
+ // This is set externally by the `BaseAccess' class
+ //
+ public bool IsBase;
+ MethodInfo getter, setter;
+ bool is_static;
+ bool must_do_cs1540_check;
+
+ Expression instance_expr;
+
+ public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
+ {
+ PropertyInfo = pi;
+ eclass = ExprClass.PropertyAccess;
+ is_static = false;
+ loc = l;
+
+ type = TypeManager.TypeToCoreType (pi.PropertyType);
+
+ ResolveAccessors (ec);
+ }
+
+ public string Name {
+ get {
+ return PropertyInfo.Name;
+ }
+ }
+
+ public bool IsInstance {
+ get {
+ return !is_static;
+ }
+ }
+
+ public bool IsStatic {
+ get {
+ return is_static;
+ }
+ }
+
+ public Type DeclaringType {
+ get {
+ return PropertyInfo.DeclaringType;
+ }
+ }
+
+ //
+ // The instance expression associated with this expression
+ //
+ public Expression InstanceExpression {
+ set {
+ instance_expr = value;
+ }
+
+ get {
+ return instance_expr;
+ }
+ }
+
+ public bool VerifyAssignable ()
+ {
+ if (setter == null) {
+ Report.Error (200, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be assigned to, as it has not set accessor");
+ return false;
+ }
+
+ return true;
+ }
+
+ MethodInfo GetAccessor (Type invocation_type, string accessor_name)
+ {
+ BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance;
+ MemberInfo[] group;
+
+ group = TypeManager.MemberLookup (
+ invocation_type, invocation_type, PropertyInfo.DeclaringType,
+ MemberTypes.Method, flags, accessor_name + "_" + PropertyInfo.Name);
+
+ //
+ // The first method is the closest to us
+ //
+ if (group == null)
+ return null;
+
+ foreach (MethodInfo mi in group) {
+ MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ //
+ // If only accessible to the current class or children
+ //
+ if (ma == MethodAttributes.Private) {
+ Type declaring_type = mi.DeclaringType;
+
+ if (invocation_type != declaring_type){
+ if (TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType))
+ return mi;
+ else
+ continue;
+ } else
+ return mi;
+ }
+ //
+ // FamAndAssem requires that we not only derivate, but we are on the
+ // same assembly.
+ //
+ if (ma == MethodAttributes.FamANDAssem){
+ if (mi.DeclaringType.Assembly != invocation_type.Assembly)
+ continue;
+ else
+ return mi;
+ }
+
+ // Assembly and FamORAssem succeed if we're in the same assembly.
+ if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
+ if (mi.DeclaringType.Assembly != invocation_type.Assembly)
+ continue;
+ else
+ return mi;
+ }
+
+ // We already know that we aren't in the same assembly.
+ if (ma == MethodAttributes.Assembly)
+ continue;
+
+ // Family and FamANDAssem require that we derive.
+ if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
+ if (!TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType))
+ continue;
+ else {
+ must_do_cs1540_check = true;
+
+ return mi;
+ }
+ }
+
+ return mi;
+ }
+
+ return null;
+ }
+
+ //
+ // We also perform the permission checking here, as the PropertyInfo does not
+ // hold the information for the accessibility of its setter/getter
+ //
+ void ResolveAccessors (EmitContext ec)
+ {
+ getter = GetAccessor (ec.ContainerType, "get");
+ if ((getter != null) && getter.IsStatic)
+ is_static = true;
+
+ setter = GetAccessor (ec.ContainerType, "set");
+ if ((setter != null) && setter.IsStatic)
+ is_static = true;
+
+ if (setter == null && getter == null){
+ Error (122, "`" + PropertyInfo.Name + "' " +
+ "is inaccessible because of its protection level");
+
+ }
+ }
+
+ bool InstanceResolve (EmitContext ec)
+ {
+ if ((instance_expr == null) && ec.IsStatic && !is_static) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
+ return false;
+ }
+
+ if (instance_expr != null) {
+ instance_expr = instance_expr.DoResolve (ec);
+ if (instance_expr == null)
+ return false;
+ }
+
+ if (must_do_cs1540_check && (instance_expr != null)) {
+ if ((instance_expr.Type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (instance_expr.Type)) {
+ Report.Error (1540, loc, "Cannot access protected member `" +
+ PropertyInfo.DeclaringType + "." + PropertyInfo.Name +
+ "' via a qualifier of type `" +
+ TypeManager.CSharpName (instance_expr.Type) +
+ "'; the qualifier must be of type `" +
+ TypeManager.CSharpName (ec.ContainerType) +
+ "' (or derived from it)");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ 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;
+
+ Report.Error (154, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be used in " +
+ "this context because it lacks a get accessor");
+ return null;
+ }
+
+ if (!InstanceResolve (ec))
+ return null;
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (IsBase && getter.IsAbstract){
+ Report.Error (205, loc, "Cannot call an abstract base property: " +
+ PropertyInfo.DeclaringType + "." +PropertyInfo.Name);
+ return null;
+ }
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ 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 (154, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be used in " +
+ "this context because it lacks a set accessor");
+ return null;
+ }
+
+ if (!InstanceResolve (ec))
+ return null;
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (IsBase && setter.IsAbstract){
+ Report.Error (205, loc, "Cannot call an abstract base property: " +
+ PropertyInfo.DeclaringType + "." +PropertyInfo.Name);
+ return null;
+ }
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ //
+ // 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 = instance_expr.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)){
+ instance_expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Ldlen);
+ return;
+ }
+ }
+
+ Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, loc);
+
+ }
+
+ //
+ // Implements the IAssignMethod interface for assignments
+ //
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ Argument arg = new Argument (source, Argument.AType.Expression);
+ ArrayList args = new ArrayList ();
+
+ args.Add (arg);
+ Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, loc);
+ }
+
+ override public void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ /// <summary>
+ /// Fully resolved expression that evaluates to an Event
+ /// </summary>
+ public class EventExpr : Expression, IMemberExpr {
+ public readonly EventInfo EventInfo;
+ public Expression instance_expr;
+
+ bool is_static;
+ MethodInfo add_accessor, remove_accessor;
+
+ 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.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 string Name {
+ get {
+ return EventInfo.Name;
+ }
+ }
+
+ public bool IsInstance {
+ get {
+ return !is_static;
+ }
+ }
+
+ public bool IsStatic {
+ get {
+ return is_static;
+ }
+ }
+
+ public Type DeclaringType {
+ get {
+ return EventInfo.DeclaringType;
+ }
+ }
+
+ public Expression InstanceExpression {
+ get {
+ return instance_expr;
+ }
+
+ set {
+ instance_expr = value;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (instance_expr != null) {
+ instance_expr = instance_expr.DoResolve (ec);
+ if (instance_expr == null)
+ return null;
+ }
+
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Report.Error (70, loc, "The event `" + Name + "' can only appear on the left hand side of += or -= (except on the defining type)");
+ }
+
+ public void EmitAddOrRemove (EmitContext ec, Expression source)
+ {
+ Expression handler = ((Binary) source).Right;
+
+ Argument arg = new Argument (handler, Argument.AType.Expression);
+ ArrayList args = new ArrayList ();
+
+ args.Add (arg);
+
+ if (((Binary) source).Oper == Binary.Operator.Addition)
+ Invocation.EmitCall (
+ ec, false, IsStatic, instance_expr, add_accessor, args, loc);
+ else
+ Invocation.EmitCall (
+ ec, false, IsStatic, instance_expr, remove_accessor, args, loc);
+ }
+ }
+}
--- /dev/null
+//
+// enum.cs: Enum handling.
+//
+// Author: 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)
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Enumeration container
+ /// </summary>
+ public class Enum : DeclSpace {
+ ArrayList ordered_enums;
+
+ public Expression BaseType;
+ public Attributes OptAttributes;
+
+ public Type UnderlyingType;
+
+ Hashtable member_to_location;
+ Hashtable member_to_attributes;
+
+ //
+ // This is for members that have been defined
+ //
+ Hashtable member_to_value;
+
+ //
+ // This is used to mark members we're currently defining
+ //
+ Hashtable in_transit;
+
+ ArrayList field_builders;
+
+ public const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.PRIVATE;
+
+ public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l)
+ : base (parent, name, l)
+ {
+ this.BaseType = type;
+ ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
+ IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l);
+ OptAttributes = attrs;
+
+ ordered_enums = new ArrayList ();
+ member_to_location = new Hashtable ();
+ member_to_value = new Hashtable ();
+ in_transit = new Hashtable ();
+ field_builders = new ArrayList ();
+ }
+
+ /// <summary>
+ /// Adds @name to the enumeration space, with @expr
+ /// being its definition.
+ /// </summary>
+ public AdditionResult AddEnumMember (string name, Expression expr, Location loc,
+ Attributes opt_attrs)
+ {
+ if (defined_names.Contains (name))
+ return AdditionResult.NameExists;
+
+ if (name == "value__") {
+ Report.Error (76, loc, "An item in an enumeration can't have an identifier `value__'");
+ return AdditionResult.Error;
+ }
+
+ DefineName (name, expr);
+
+ ordered_enums.Add (name);
+ member_to_location.Add (name, loc);
+
+ if (member_to_attributes == null)
+ member_to_attributes = new Hashtable ();
+
+ member_to_attributes.Add (name, opt_attrs);
+
+ return AdditionResult.Success;
+ }
+
+ //
+ // This is used by corlib compilation: we map from our
+ // type to a type that is consumable by the DefineField
+ //
+ Type MapToInternalType (Type t)
+ {
+ if (t == TypeManager.int32_type)
+ return typeof (int);
+ if (t == TypeManager.int64_type)
+ return typeof (long);
+ if (t == TypeManager.uint32_type)
+ return typeof (uint);
+ if (t == TypeManager.uint64_type)
+ return typeof (ulong);
+ if (t == TypeManager.float_type)
+ return typeof (float);
+ if (t == TypeManager.double_type)
+ return typeof (double);
+ if (t == TypeManager.byte_type)
+ return typeof (byte);
+ if (t == TypeManager.sbyte_type)
+ return typeof (sbyte);
+ if (t == TypeManager.char_type)
+ return typeof (char);
+ if (t == TypeManager.short_type)
+ return typeof (short);
+ if (t == TypeManager.ushort_type)
+ return typeof (ushort);
+
+ throw new Exception ();
+ }
+
+ public override TypeBuilder DefineType ()
+ {
+ if (TypeBuilder != null)
+ return TypeBuilder;
+
+ TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
+
+ attr |= TypeAttributes.Class | TypeAttributes.Sealed;
+
+ UnderlyingType = ResolveType (BaseType, false, Location);
+
+ if (UnderlyingType != TypeManager.int32_type &&
+ UnderlyingType != TypeManager.uint32_type &&
+ UnderlyingType != TypeManager.int64_type &&
+ UnderlyingType != TypeManager.uint64_type &&
+ UnderlyingType != TypeManager.short_type &&
+ UnderlyingType != TypeManager.ushort_type &&
+ UnderlyingType != TypeManager.byte_type &&
+ UnderlyingType != TypeManager.char_type &&
+ UnderlyingType != TypeManager.sbyte_type) {
+ Report.Error (1008, Location,
+ "Type byte, sbyte, short, char, ushort, int, uint, " +
+ "long, or ulong expected (got: " +
+ TypeManager.CSharpName (UnderlyingType) + ")");
+ return null;
+ }
+
+ if (IsTopLevel) {
+ if (TypeManager.NamespaceClash (Name, Location))
+ return null;
+
+ ModuleBuilder builder = CodeGen.ModuleBuilder;
+
+ TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type);
+ } else {
+ TypeBuilder builder = Parent.TypeBuilder;
+
+ TypeBuilder = builder.DefineNestedType (
+ Basename, attr, TypeManager.enum_type);
+ }
+
+ //
+ // Call MapToInternalType for corlib
+ //
+ TypeBuilder.DefineField ("value__", UnderlyingType,
+ FieldAttributes.Public | FieldAttributes.SpecialName
+ | FieldAttributes.RTSpecialName);
+
+ TypeManager.AddEnumType (Name, TypeBuilder, this);
+
+ return TypeBuilder;
+ }
+
+ bool IsValidEnumConstant (Expression e)
+ {
+ if (!(e is Constant))
+ return false;
+
+ if (e is IntConstant || e is UIntConstant || e is LongConstant ||
+ e is ByteConstant || e is SByteConstant || e is ShortConstant ||
+ e is UShortConstant || e is ULongConstant || e is EnumConstant ||
+ e is CharConstant)
+ return true;
+ else
+ return false;
+ }
+
+ object GetNextDefaultValue (object default_value)
+ {
+ if (UnderlyingType == TypeManager.int32_type) {
+ int i = (int) default_value;
+
+ if (i < System.Int32.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.uint32_type) {
+ uint i = (uint) default_value;
+
+ if (i < System.UInt32.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.int64_type) {
+ long i = (long) default_value;
+
+ if (i < System.Int64.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.uint64_type) {
+ ulong i = (ulong) default_value;
+
+ if (i < System.UInt64.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.short_type) {
+ short i = (short) default_value;
+
+ if (i < System.Int16.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.ushort_type) {
+ ushort i = (ushort) default_value;
+
+ if (i < System.UInt16.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.byte_type) {
+ byte i = (byte) default_value;
+
+ if (i < System.Byte.MaxValue)
+ return ++i;
+ else
+ return null;
+ } else if (UnderlyingType == TypeManager.sbyte_type) {
+ sbyte i = (sbyte) default_value;
+
+ if (i < System.SByte.MaxValue)
+ return ++i;
+ else
+ return null;
+ }
+
+ return null;
+ }
+
+ void Error_ConstantValueCannotBeConverted (object val, Location loc)
+ {
+ if (val is Constant)
+ Report.Error (31, loc, "Constant value '" + ((Constant) val).AsString () +
+ "' cannot be converted" +
+ " to a " + TypeManager.CSharpName (UnderlyingType));
+ else
+ Report.Error (31, loc, "Constant value '" + val +
+ "' cannot be converted" +
+ " to a " + TypeManager.CSharpName (UnderlyingType));
+ return;
+ }
+
+ /// <summary>
+ /// Determines if a standard implicit conversion exists from
+ /// expr_type to target_type
+ /// </summary>
+ public static bool ImplicitConversionExists (Type expr_type, Type target_type)
+ {
+ expr_type = TypeManager.TypeToCoreType (expr_type);
+
+ if (expr_type == TypeManager.void_type)
+ return false;
+
+ if (expr_type == target_type)
+ return true;
+
+ // First numeric conversions
+
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to short, int, long, float, double.
+ //
+ 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
+ //
+ 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, float, double
+ //
+ 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, float, double
+ //
+ 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, float, double
+ //
+ 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, float, double
+ //
+ 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 float, double
+ //
+ 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, long, ulong, float, double
+ //
+ 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;
+ }
+
+ return false;
+ }
+
+ //
+ // Horrible, horrible. But there is no other way we can pass the EmitContext
+ // to the recursive definition triggered by the evaluation of a forward
+ // expression
+ //
+ static EmitContext current_ec = null;
+
+ /// <summary>
+ /// This is used to lookup the value of an enum member. If the member is undefined,
+ /// it attempts to define it and return its value
+ /// </summary>
+ public object LookupEnumValue (EmitContext ec, string name, Location loc)
+ {
+
+ object default_value = null;
+ Constant c = null;
+
+ default_value = member_to_value [name];
+
+ if (default_value != null)
+ return default_value;
+
+ //
+ // This may happen if we're calling a method in System.Enum, for instance
+ // Enum.IsDefined().
+ //
+ if (!defined_names.Contains (name))
+ return null;
+
+ if (in_transit.Contains (name)) {
+ Report.Error (110, loc, "The evaluation of the constant value for `" +
+ Name + "." + name + "' involves a circular definition.");
+ return null;
+ }
+
+ //
+ // So if the above doesn't happen, we have a member that is undefined
+ // We now proceed to define it
+ //
+ Expression val = this [name];
+
+ if (val == null) {
+
+ int idx = ordered_enums.IndexOf (name);
+
+ if (idx == 0)
+ default_value = 0;
+ else {
+ for (int i = 0; i < idx; ++i) {
+ string n = (string) ordered_enums [i];
+ Location m_loc = (Mono.CSharp.Location)
+ member_to_location [n];
+ in_transit.Add (name, true);
+
+ EmitContext old_ec = current_ec;
+ current_ec = ec;
+
+ default_value = LookupEnumValue (ec, n, m_loc);
+
+ current_ec = old_ec;
+
+ in_transit.Remove (name);
+ if (default_value == null)
+ return null;
+ }
+
+ default_value = GetNextDefaultValue (default_value);
+ }
+
+ } else {
+ bool old = ec.InEnumContext;
+ ec.InEnumContext = true;
+ in_transit.Add (name, true);
+
+ EmitContext old_ec = current_ec;
+ current_ec = ec;
+ val = val.Resolve (ec);
+ current_ec = old_ec;
+
+ in_transit.Remove (name);
+ ec.InEnumContext = old;
+
+ if (val == null)
+ return null;
+
+ if (!IsValidEnumConstant (val)) {
+ Report.Error (
+ 1008, loc,
+ "Type byte, sbyte, short, ushort, int, uint, long, or " +
+ "ulong expected (have: " + val + ")");
+ return null;
+ }
+
+ c = (Constant) val;
+ default_value = c.GetValue ();
+
+ if (default_value == null) {
+ Error_ConstantValueCannotBeConverted (c, loc);
+ return null;
+ }
+
+ if (val is EnumConstant){
+ Type etype = TypeManager.EnumToUnderlying (c.Type);
+
+ if (!ImplicitConversionExists (etype, UnderlyingType)){
+ Convert.Error_CannotImplicitConversion (
+ loc, c.Type, UnderlyingType);
+ return null;
+ }
+ }
+ }
+
+ FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
+ | FieldAttributes.Literal;
+
+ FieldBuilder fb = TypeBuilder.DefineField (name, TypeBuilder, attr);
+
+ bool fail;
+ default_value = TypeManager.ChangeType (default_value, UnderlyingType, out fail);
+ if (fail){
+ Error_ConstantValueCannotBeConverted (c, loc);
+ return null;
+ }
+
+ fb.SetConstant (default_value);
+ field_builders.Add (fb);
+ member_to_value [name] = default_value;
+
+ if (!TypeManager.RegisterFieldValue (fb, default_value))
+ return null;
+
+ //
+ // Now apply attributes
+ //
+ Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name]);
+
+ return default_value;
+ }
+
+ public override bool DefineMembers (TypeContainer parent)
+ {
+ return true;
+ }
+
+ public override bool Define (TypeContainer parent)
+ {
+ //
+ // If there was an error during DefineEnum, return
+ //
+ if (TypeBuilder == null)
+ return false;
+
+ EmitContext ec = new EmitContext (this, this, Location, null,
+ UnderlyingType, ModFlags, false);
+
+
+ object default_value = 0;
+
+ FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
+ | FieldAttributes.Literal;
+
+
+ foreach (string name in ordered_enums) {
+ //
+ // Have we already been defined, thanks to some cross-referencing ?
+ //
+ if (member_to_value.Contains (name))
+ continue;
+
+ Location loc = (Mono.CSharp.Location) member_to_location [name];
+
+ if (this [name] != null) {
+ default_value = LookupEnumValue (ec, name, loc);
+
+ if (default_value == null)
+ return true;
+ } else {
+ if (name == "value__"){
+ Report.Error (76, loc, "The name `value__' is reserved for enumerations");
+ return false;
+ }
+
+ FieldBuilder fb = TypeBuilder.DefineField (
+ name, TypeBuilder, attr);
+
+ if (default_value == null) {
+ Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
+ "fit in its type");
+ return false;
+ }
+
+ bool fail;
+ default_value = TypeManager.ChangeType (default_value, UnderlyingType, out fail);
+ if (fail){
+ Error_ConstantValueCannotBeConverted (default_value, loc);
+ return false;
+ }
+
+ fb.SetConstant (default_value);
+ field_builders.Add (fb);
+ member_to_value [name] = default_value;
+
+ if (!TypeManager.RegisterFieldValue (fb, default_value))
+ return false;
+
+ //
+ // Apply attributes on the enum member
+ //
+ Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name]);
+ }
+
+ default_value = GetNextDefaultValue (default_value);
+ }
+
+ Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
+
+ return true;
+ }
+
+ //
+ // IMemberFinder
+ //
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList ();
+
+ if ((mt & MemberTypes.Field) != 0) {
+ if (criteria is string){
+ if (member_to_value [criteria] == null && current_ec != null){
+ LookupEnumValue (current_ec, (string) criteria, Location.Null);
+ }
+ }
+
+ foreach (FieldBuilder fb in field_builders)
+ if (filter (fb, criteria) == true)
+ members.Add (fb);
+ }
+
+ return new MemberList (members);
+ }
+
+ public override MemberCache MemberCache {
+ get {
+ return null;
+ }
+ }
+
+ public ArrayList ValueNames {
+ get {
+ return ordered_enums;
+ }
+ }
+
+ // indexer
+ public Expression this [string name] {
+ get {
+ return (Expression) defined_names [name];
+ }
+ }
+ }
+}
--- /dev/null
+//
+// expression.cs: Expression representation for the IL tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+//
+#define USE_OLD
+
+namespace Mono.CSharp {
+ using System;
+ using System.Collections;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Text;
+
+ /// <summary>
+ /// This is just a helper class, it is generated by Unary, UnaryMutator
+ /// when an overloaded method has been found. It just emits the code for a
+ /// static call.
+ /// </summary>
+ public class StaticCallExpr : ExpressionStatement {
+ ArrayList args;
+ MethodInfo mi;
+
+ public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
+ {
+ mi = m;
+ args = a;
+
+ type = m.ReturnType;
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (args != null)
+ Invocation.EmitArguments (ec, mi, args);
+
+ ec.ig.Emit (OpCodes.Call, mi);
+ return;
+ }
+
+ static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
+ Expression e, Location loc)
+ {
+ ArrayList args;
+ MethodBase method;
+
+ args = new ArrayList (1);
+ Argument a = new Argument (e, Argument.AType.Expression);
+
+ // We need to resolve the arguments before sending them in !
+ if (!a.Resolve (ec, loc))
+ return null;
+
+ args.Add (a);
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
+
+ if (method == null)
+ return null;
+
+ return new StaticCallExpr ((MethodInfo) method, args, loc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ /// <summary>
+ /// Unary expressions.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Unary implements unary expressions. It derives from
+ /// ExpressionStatement becuase the pre/post increment/decrement
+ /// operators can be used in a statement context.
+ /// </remarks>
+ public class Unary : Expression {
+ public enum Operator : byte {
+ UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
+ Indirection, AddressOf, TOP
+ }
+
+ public Operator Oper;
+ public Expression Expr;
+
+ public Unary (Operator op, Expression expr, Location loc)
+ {
+ this.Oper = op;
+ this.Expr = expr;
+ this.loc = loc;
+ }
+
+ /// <summary>
+ /// Returns a stringified representation of the Operator
+ /// </summary>
+ static public string OperName (Operator oper)
+ {
+ switch (oper){
+ case Operator.UnaryPlus:
+ return "+";
+ case Operator.UnaryNegation:
+ return "-";
+ case Operator.LogicalNot:
+ return "!";
+ case Operator.OnesComplement:
+ return "~";
+ case Operator.AddressOf:
+ return "&";
+ case Operator.Indirection:
+ return "*";
+ }
+
+ return oper.ToString ();
+ }
+
+ public static readonly string [] oper_names;
+
+ static Unary ()
+ {
+ oper_names = new string [(int)Operator.TOP];
+
+ oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
+ oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
+ oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
+ oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
+ oper_names [(int) Operator.Indirection] = "op_Indirection";
+ oper_names [(int) Operator.AddressOf] = "op_AddressOf";
+ }
+
+ void Error23 (Type t)
+ {
+ Error (
+ 23, "Operator " + OperName (Oper) +
+ " cannot be applied to operand of type `" +
+ TypeManager.CSharpName (t) + "'");
+ }
+
+ /// <remarks>
+ /// The result has been already resolved:
+ ///
+ /// FIXME: a minus constant -128 sbyte cant be turned into a
+ /// constant byte.
+ /// </remarks>
+ static Expression TryReduceNegative (Constant expr)
+ {
+ Expression e = null;
+
+ if (expr is IntConstant)
+ e = new IntConstant (-((IntConstant) expr).Value);
+ else if (expr is UIntConstant){
+ uint value = ((UIntConstant) expr).Value;
+
+ if (value < 2147483649)
+ return new IntConstant (-(int)value);
+ else
+ e = new LongConstant (-value);
+ }
+ else if (expr is LongConstant)
+ e = new LongConstant (-((LongConstant) expr).Value);
+ else if (expr is ULongConstant){
+ ulong value = ((ULongConstant) expr).Value;
+
+ if (value < 9223372036854775809)
+ return new LongConstant(-(long)value);
+ }
+ else if (expr is FloatConstant)
+ e = new FloatConstant (-((FloatConstant) expr).Value);
+ else if (expr is DoubleConstant)
+ e = new DoubleConstant (-((DoubleConstant) expr).Value);
+ else if (expr is DecimalConstant)
+ e = new DecimalConstant (-((DecimalConstant) expr).Value);
+ else if (expr is ShortConstant)
+ e = new IntConstant (-((ShortConstant) expr).Value);
+ else if (expr is UShortConstant)
+ e = new IntConstant (-((UShortConstant) expr).Value);
+ return e;
+ }
+
+ // <summary>
+ // This routine will attempt to simplify the unary expression when the
+ // argument is a constant. The result is returned in `result' and the
+ // function returns true or false depending on whether a reduction
+ // was performed or not
+ // </summary>
+ bool Reduce (EmitContext ec, Constant e, out Expression result)
+ {
+ Type expr_type = e.Type;
+
+ switch (Oper){
+ case Operator.UnaryPlus:
+ result = e;
+ return true;
+
+ case Operator.UnaryNegation:
+ result = TryReduceNegative (e);
+ return true;
+
+ case Operator.LogicalNot:
+ if (expr_type != TypeManager.bool_type) {
+ result = null;
+ Error23 (expr_type);
+ return false;
+ }
+
+ BoolConstant b = (BoolConstant) e;
+ result = new BoolConstant (!(b.Value));
+ return true;
+
+ case Operator.OnesComplement:
+ if (!((expr_type == TypeManager.int32_type) ||
+ (expr_type == TypeManager.uint32_type) ||
+ (expr_type == TypeManager.int64_type) ||
+ (expr_type == TypeManager.uint64_type) ||
+ (expr_type.IsSubclassOf (TypeManager.enum_type)))){
+
+ result = null;
+ if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
+ result = new Cast (new TypeExpr (TypeManager.int32_type, loc), e, loc);
+ result = result.Resolve (ec);
+ } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
+ result = new Cast (new TypeExpr (TypeManager.uint32_type, loc), e, loc);
+ result = result.Resolve (ec);
+ } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
+ result = new Cast (new TypeExpr (TypeManager.int64_type, loc), e, loc);
+ result = result.Resolve (ec);
+ } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
+ result = new Cast (new TypeExpr (TypeManager.uint64_type, loc), e, loc);
+ result = result.Resolve (ec);
+ }
+
+ if (result == null || !(result is Constant)){
+ result = null;
+ Error23 (expr_type);
+ return false;
+ }
+
+ expr_type = result.Type;
+ e = (Constant) result;
+ }
+
+ if (e is EnumConstant){
+ EnumConstant enum_constant = (EnumConstant) e;
+ Expression reduced;
+
+ if (Reduce (ec, enum_constant.Child, out reduced)){
+ result = new EnumConstant ((Constant) reduced, enum_constant.Type);
+ return true;
+ } else {
+ result = null;
+ return false;
+ }
+ }
+
+ if (expr_type == TypeManager.int32_type){
+ result = new IntConstant (~ ((IntConstant) e).Value);
+ } else if (expr_type == TypeManager.uint32_type){
+ result = new UIntConstant (~ ((UIntConstant) e).Value);
+ } else if (expr_type == TypeManager.int64_type){
+ result = new LongConstant (~ ((LongConstant) e).Value);
+ } else if (expr_type == TypeManager.uint64_type){
+ result = new ULongConstant (~ ((ULongConstant) e).Value);
+ } else {
+ result = null;
+ Error23 (expr_type);
+ return false;
+ }
+ return true;
+
+ case Operator.AddressOf:
+ result = this;
+ return false;
+
+ case Operator.Indirection:
+ result = this;
+ return false;
+ }
+ throw new Exception ("Can not constant fold: " + Oper.ToString());
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type expr_type = Expr.Type;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression mg;
+ string op_name;
+
+ op_name = oper_names [(int) Oper];
+
+ mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+
+ if (mg != null) {
+ Expression e = StaticCallExpr.MakeSimpleCall (
+ ec, (MethodGroupExpr) mg, Expr, loc);
+
+ if (e == null){
+ Error23 (expr_type);
+ return null;
+ }
+
+ return e;
+ }
+
+ // Only perform numeric promotions on:
+ // +, -
+
+ if (expr_type == null)
+ return null;
+
+ //
+ // Step 2: Default operations on CLI native types.
+ //
+
+ // Attempt to use a constant folding operation.
+ if (Expr is Constant){
+ Expression result;
+
+ if (Reduce (ec, (Constant) Expr, out result))
+ return result;
+ }
+
+ switch (Oper){
+ case Operator.LogicalNot:
+ if (expr_type != TypeManager.bool_type) {
+ Expr = ResolveBoolean (ec, Expr, loc);
+ if (Expr == null){
+ Error23 (expr_type);
+ return null;
+ }
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+
+ case Operator.OnesComplement:
+ if (!((expr_type == TypeManager.int32_type) ||
+ (expr_type == TypeManager.uint32_type) ||
+ (expr_type == TypeManager.int64_type) ||
+ (expr_type == TypeManager.uint64_type) ||
+ (expr_type.IsSubclassOf (TypeManager.enum_type)))){
+ Expression e;
+
+ e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
+ if (e != null){
+ type = TypeManager.int32_type;
+ return this;
+ }
+ e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
+ if (e != null){
+ type = TypeManager.uint32_type;
+ return this;
+ }
+ e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
+ if (e != null){
+ type = TypeManager.int64_type;
+ return this;
+ }
+ e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
+ if (e != null){
+ type = TypeManager.uint64_type;
+ return this;
+ }
+ Error23 (expr_type);
+ return null;
+ }
+ type = expr_type;
+ return this;
+
+ case Operator.AddressOf:
+ if (Expr.eclass != ExprClass.Variable){
+ Error (211, "Cannot take the address of non-variables");
+ return null;
+ }
+
+ if (!ec.InUnsafe) {
+ UnsafeError (loc);
+ return null;
+ }
+
+ if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
+ return null;
+ }
+
+ IVariable variable = Expr as IVariable;
+ if (!ec.InFixedInitializer && ((variable == null) || !variable.VerifyFixed (false))) {
+ Error (212, "You can only take the address of an unfixed expression inside " +
+ "of a fixed statement initializer");
+ return null;
+ }
+
+ // According to the specs, a variable is considered definitely assigned if you take
+ // its address.
+ if ((variable != null) && (variable.VariableInfo != null))
+ variable.VariableInfo.SetAssigned (ec);
+
+ type = TypeManager.GetPointerType (Expr.Type);
+ return this;
+
+ case Operator.Indirection:
+ if (!ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+
+ if (!expr_type.IsPointer){
+ Error (193, "The * or -> operator can only be applied to pointers");
+ return null;
+ }
+
+ //
+ // We create an Indirection expression, because
+ // it can implement the IMemoryLocation.
+ //
+ return new Indirection (Expr, loc);
+
+ case Operator.UnaryPlus:
+ //
+ // A plus in front of something is just a no-op, so return the child.
+ //
+ return Expr;
+
+ case Operator.UnaryNegation:
+ //
+ // Deals with -literals
+ // int operator- (int x)
+ // long operator- (long x)
+ // float operator- (float f)
+ // double operator- (double d)
+ // decimal operator- (decimal d)
+ //
+ Expression expr = null;
+
+ //
+ // transform - - expr into expr
+ //
+ if (Expr is Unary){
+ Unary unary = (Unary) Expr;
+
+ if (unary.Oper == Operator.UnaryNegation)
+ return unary.Expr;
+ }
+
+ //
+ // perform numeric promotions to int,
+ // long, double.
+ //
+ //
+ // The following is inneficient, because we call
+ // ImplicitConversion too many times.
+ //
+ // It is also not clear if we should convert to Float
+ // or Double initially.
+ //
+ if (expr_type == TypeManager.uint32_type){
+ //
+ // FIXME: handle exception to this rule that
+ // permits the int value -2147483648 (-2^31) to
+ // bt wrote as a decimal interger literal
+ //
+ type = TypeManager.int64_type;
+ Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
+ return this;
+ }
+
+ if (expr_type == TypeManager.uint64_type){
+ //
+ // FIXME: Handle exception of `long value'
+ // -92233720368547758087 (-2^63) to be wrote as
+ // decimal integer literal.
+ //
+ Error23 (expr_type);
+ return null;
+ }
+
+ if (expr_type == TypeManager.float_type){
+ type = expr_type;
+ return this;
+ }
+
+ expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ Error23 (expr_type);
+ return null;
+ }
+
+ Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
+ TypeManager.CSharpName (expr_type) + "'");
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (Oper == Operator.AddressOf)
+ Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
+ else
+ Expr = Expr.Resolve (ec);
+
+ if (Expr == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ return ResolveOperator (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Type expr_type = Expr.Type;
+
+ switch (Oper) {
+ case Operator.UnaryPlus:
+ throw new Exception ("This should be caught by Resolve");
+
+ case Operator.UnaryNegation:
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Neg);
+ break;
+
+ case Operator.LogicalNot:
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ceq);
+ break;
+
+ case Operator.OnesComplement:
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Not);
+ break;
+
+ case Operator.AddressOf:
+ ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
+ break;
+
+ default:
+ throw new Exception ("This should not happen: Operator = "
+ + Oper.ToString ());
+ }
+ }
+
+ /// <summary>
+ /// This will emit the child expression for `ec' avoiding the logical
+ /// not. The parent will take care of changing brfalse/brtrue
+ /// </summary>
+ public void EmitLogicalNot (EmitContext ec)
+ {
+ if (Oper != Operator.LogicalNot)
+ throw new Exception ("EmitLogicalNot can only be called with !expr");
+
+ Expr.Emit (ec);
+ }
+
+ public override string ToString ()
+ {
+ return "Unary (" + Oper + ", " + Expr + ")";
+ }
+
+ }
+
+ //
+ // Unary operators are turned into Indirection expressions
+ // after semantic analysis (this is so we can take the address
+ // of an indirection).
+ //
+ public class Indirection : Expression, IMemoryLocation, IAssignMethod {
+ Expression expr;
+ LocalTemporary temporary;
+ bool have_temporary;
+
+ public Indirection (Expression expr, Location l)
+ {
+ this.expr = expr;
+ this.type = TypeManager.GetElementType (expr.Type);
+ eclass = ExprClass.Variable;
+ loc = l;
+ }
+
+ void LoadExprValue (EmitContext ec)
+ {
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (temporary != null){
+ if (have_temporary){
+ temporary.Emit (ec);
+ return;
+ }
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Dup);
+ temporary.Store (ec);
+ have_temporary = true;
+ } else
+ expr.Emit (ec);
+
+ LoadFromPtr (ig, Type);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ if (temporary != null){
+ if (have_temporary)
+ temporary.Emit (ec);
+ else {
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Dup);
+ temporary.Store (ec);
+ have_temporary = true;
+ }
+ } else
+ expr.Emit (ec);
+
+ source.Emit (ec);
+ StoreFromPtr (ec.ig, type);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp Mode)
+ {
+ if (temporary != null){
+ if (have_temporary){
+ temporary.Emit (ec);
+ return;
+ }
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Dup);
+ temporary.Store (ec);
+ have_temporary = true;
+ } else
+ expr.Emit (ec);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // Born fully resolved
+ //
+ return this;
+ }
+
+ public new void CacheTemporaries (EmitContext ec)
+ {
+ temporary = new LocalTemporary (ec, type);
+ }
+
+ public override string ToString ()
+ {
+ return "*(" + expr + ")";
+ }
+ }
+
+ /// <summary>
+ /// Unary Mutator expressions (pre and post ++ and --)
+ /// </summary>
+ ///
+ /// <remarks>
+ /// UnaryMutator implements ++ and -- expressions. It derives from
+ /// ExpressionStatement becuase the pre/post increment/decrement
+ /// operators can be used in a statement context.
+ ///
+ /// FIXME: Idea, we could split this up in two classes, one simpler
+ /// for the common case, and one with the extra fields for more complex
+ /// classes (indexers require temporary access; overloaded require method)
+ ///
+ /// </remarks>
+ public class UnaryMutator : ExpressionStatement {
+ [Flags]
+ public enum Mode : byte {
+ IsIncrement = 0,
+ IsDecrement = 1,
+ IsPre = 0,
+ IsPost = 2,
+
+ PreIncrement = 0,
+ PreDecrement = IsDecrement,
+ PostIncrement = IsPost,
+ PostDecrement = IsPost | IsDecrement
+ }
+
+ Mode mode;
+ Expression expr;
+ LocalTemporary temp_storage;
+
+ //
+ // This is expensive for the simplest case.
+ //
+ Expression method;
+
+ public UnaryMutator (Mode m, Expression e, Location l)
+ {
+ mode = m;
+ loc = l;
+ expr = e;
+ }
+
+ static string OperName (Mode mode)
+ {
+ return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
+ "++" : "--";
+ }
+
+ void Error23 (Type t)
+ {
+ Error (
+ 23, "Operator " + OperName (mode) +
+ " cannot be applied to operand of type `" +
+ TypeManager.CSharpName (t) + "'");
+ }
+
+ /// <summary>
+ /// Returns whether an object of type `t' can be incremented
+ /// or decremented with add/sub (ie, basically whether we can
+ /// use pre-post incr-decr operations on it, but it is not a
+ /// System.Decimal, which we require operator overloading to catch)
+ /// </summary>
+ static bool IsIncrementableNumber (Type t)
+ {
+ return (t == TypeManager.sbyte_type) ||
+ (t == TypeManager.byte_type) ||
+ (t == TypeManager.short_type) ||
+ (t == TypeManager.ushort_type) ||
+ (t == TypeManager.int32_type) ||
+ (t == TypeManager.uint32_type) ||
+ (t == TypeManager.int64_type) ||
+ (t == TypeManager.uint64_type) ||
+ (t == TypeManager.char_type) ||
+ (t.IsSubclassOf (TypeManager.enum_type)) ||
+ (t == TypeManager.float_type) ||
+ (t == TypeManager.double_type) ||
+ (t.IsPointer && t != TypeManager.void_ptr_type);
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type expr_type = expr.Type;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression mg;
+ string op_name;
+
+ if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
+ op_name = "op_Increment";
+ else
+ op_name = "op_Decrement";
+
+ mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+
+ if (mg == null && expr_type.BaseType != null)
+ mg = MemberLookup (ec, expr_type.BaseType, op_name,
+ MemberTypes.Method, AllBindingFlags, loc);
+
+ if (mg != null) {
+ method = StaticCallExpr.MakeSimpleCall (
+ ec, (MethodGroupExpr) mg, expr, loc);
+
+ type = method.Type;
+ return this;
+ }
+
+ //
+ // The operand of the prefix/postfix increment decrement operators
+ // should be an expression that is classified as a variable,
+ // a property access or an indexer access
+ //
+ type = expr_type;
+ if (expr.eclass == ExprClass.Variable){
+ if (IsIncrementableNumber (expr_type) ||
+ expr_type == TypeManager.decimal_type){
+ return this;
+ }
+ } else if (expr.eclass == ExprClass.IndexerAccess){
+ IndexerAccess ia = (IndexerAccess) expr;
+
+ temp_storage = new LocalTemporary (ec, expr.Type);
+
+ expr = ia.ResolveLValue (ec, temp_storage);
+ if (expr == null)
+ return null;
+
+ return this;
+ } else if (expr.eclass == ExprClass.PropertyAccess){
+ PropertyExpr pe = (PropertyExpr) expr;
+
+ if (pe.VerifyAssignable ())
+ return this;
+
+ return null;
+ } else {
+ expr.Error_UnexpectedKind ("variable, indexer or property access");
+ return null;
+ }
+
+ Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
+ TypeManager.CSharpName (expr_type) + "'");
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+
+ if (expr == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ return ResolveOperator (ec);
+ }
+
+ static int PtrTypeSize (Type t)
+ {
+ return GetTypeSize (TypeManager.GetElementType (t));
+ }
+
+ //
+ // Loads the proper "1" into the stack based on the type, then it emits the
+ // opcode for the operation requested
+ //
+ void LoadOneAndEmitOp (EmitContext ec, Type t)
+ {
+ //
+ // Measure if getting the typecode and using that is more/less efficient
+ // that comparing types. t.GetTypeCode() is an internal call.
+ //
+ ILGenerator ig = ec.ig;
+
+ if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
+ LongConstant.EmitLong (ig, 1);
+ else if (t == TypeManager.double_type)
+ ig.Emit (OpCodes.Ldc_R8, 1.0);
+ else if (t == TypeManager.float_type)
+ ig.Emit (OpCodes.Ldc_R4, 1.0F);
+ else if (t.IsPointer){
+ int n = PtrTypeSize (t);
+
+ if (n == 0)
+ ig.Emit (OpCodes.Sizeof, t);
+ else
+ IntConstant.EmitInt (ig, n);
+ } else
+ ig.Emit (OpCodes.Ldc_I4_1);
+
+ //
+ // Now emit the operation
+ //
+ if (ec.CheckState){
+ if (t == TypeManager.int32_type ||
+ t == TypeManager.int64_type){
+ if ((mode & Mode.IsDecrement) != 0)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ } else if (t == TypeManager.uint32_type ||
+ t == TypeManager.uint64_type){
+ if ((mode & Mode.IsDecrement) != 0)
+ ig.Emit (OpCodes.Sub_Ovf_Un);
+ else
+ ig.Emit (OpCodes.Add_Ovf_Un);
+ } else {
+ if ((mode & Mode.IsDecrement) != 0)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ }
+ } else {
+ if ((mode & Mode.IsDecrement) != 0)
+ ig.Emit (OpCodes.Sub);
+ else
+ ig.Emit (OpCodes.Add);
+ }
+
+ if (t == TypeManager.sbyte_type){
+ if (ec.CheckState)
+ ig.Emit (OpCodes.Conv_Ovf_I1);
+ else
+ ig.Emit (OpCodes.Conv_I1);
+ } else if (t == TypeManager.byte_type){
+ if (ec.CheckState)
+ ig.Emit (OpCodes.Conv_Ovf_U1);
+ else
+ ig.Emit (OpCodes.Conv_U1);
+ } else if (t == TypeManager.short_type){
+ if (ec.CheckState)
+ ig.Emit (OpCodes.Conv_Ovf_I2);
+ else
+ ig.Emit (OpCodes.Conv_I2);
+ } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
+ if (ec.CheckState)
+ ig.Emit (OpCodes.Conv_Ovf_U2);
+ else
+ ig.Emit (OpCodes.Conv_U2);
+ }
+
+ }
+
+ static EmptyExpression empty_expr;
+
+ void EmitCode (EmitContext ec, bool is_expr)
+ {
+ ILGenerator ig = ec.ig;
+ IAssignMethod ia = (IAssignMethod) expr;
+ Type expr_type = expr.Type;
+
+ ia.CacheTemporaries (ec);
+
+ if (temp_storage == null){
+ //
+ // Temporary improvement: if we are dealing with something that does
+ // not require complicated instance setup, avoid using a temporary
+ //
+ // For now: only localvariables when not remapped
+ //
+
+ if (method == null &&
+ (expr is LocalVariableReference && ec.RemapToProxy == false) ||
+ (expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic)){
+ if (empty_expr == null)
+ empty_expr = new EmptyExpression ();
+
+ switch (mode){
+ case Mode.PreIncrement:
+ case Mode.PreDecrement:
+ expr.Emit (ec);
+
+ LoadOneAndEmitOp (ec, expr_type);
+ if (is_expr)
+ ig.Emit (OpCodes.Dup);
+ ia.EmitAssign (ec, empty_expr);
+ break;
+
+ case Mode.PostIncrement:
+ case Mode.PostDecrement:
+ expr.Emit (ec);
+ if (is_expr)
+ ig.Emit (OpCodes.Dup);
+
+ LoadOneAndEmitOp (ec, expr_type);
+ ia.EmitAssign (ec, empty_expr);
+ break;
+ }
+ return;
+ }
+ temp_storage = new LocalTemporary (ec, expr_type);
+ }
+
+ switch (mode){
+ case Mode.PreIncrement:
+ case Mode.PreDecrement:
+ if (method == null){
+ expr.Emit (ec);
+
+ LoadOneAndEmitOp (ec, expr_type);
+ } else
+ method.Emit (ec);
+
+ temp_storage.Store (ec);
+ ia.EmitAssign (ec, temp_storage);
+ if (is_expr)
+ temp_storage.Emit (ec);
+ break;
+
+ case Mode.PostIncrement:
+ case Mode.PostDecrement:
+ if (is_expr)
+ expr.Emit (ec);
+
+ if (method == null){
+ if (!is_expr)
+ expr.Emit (ec);
+ else
+ ig.Emit (OpCodes.Dup);
+
+ LoadOneAndEmitOp (ec, expr_type);
+ } else {
+ method.Emit (ec);
+ }
+
+ temp_storage.Store (ec);
+ ia.EmitAssign (ec, temp_storage);
+ break;
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ EmitCode (ec, true);
+
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ EmitCode (ec, false);
+ }
+
+ }
+
+ /// <summary>
+ /// Base class for the `Is' and `As' classes.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// FIXME: Split this in two, and we get to save the `Operator' Oper
+ /// size.
+ /// </remarks>
+ public abstract class Probe : Expression {
+ public readonly Expression ProbeType;
+ protected Expression expr;
+ protected Type probe_type;
+
+ public Probe (Expression expr, Expression probe_type, Location l)
+ {
+ ProbeType = probe_type;
+ loc = l;
+ this.expr = expr;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
+
+ if (probe_type == null)
+ return null;
+
+ expr = expr.Resolve (ec);
+
+ return this;
+ }
+ }
+
+ /// <summary>
+ /// Implementation of the `is' operator.
+ /// </summary>
+ public class Is : Probe {
+ public Is (Expression expr, Expression probe_type, Location l)
+ : base (expr, probe_type, l)
+ {
+ }
+
+ enum Action {
+ AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
+ }
+
+ Action action;
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ expr.Emit (ec);
+
+ switch (action){
+ case Action.AlwaysFalse:
+ ig.Emit (OpCodes.Pop);
+ IntConstant.EmitInt (ig, 0);
+ return;
+ case Action.AlwaysTrue:
+ ig.Emit (OpCodes.Pop);
+ IntConstant.EmitInt (ig, 1);
+ return;
+ case Action.LeaveOnStack:
+ // the `e != null' rule.
+ ig.Emit (OpCodes.Ldnull);
+ ig.Emit (OpCodes.Ceq);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ceq);
+ return;
+ case Action.Probe:
+ ig.Emit (OpCodes.Isinst, probe_type);
+ ig.Emit (OpCodes.Ldnull);
+ ig.Emit (OpCodes.Cgt_Un);
+ return;
+ }
+ throw new Exception ("never reached");
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expression e = base.DoResolve (ec);
+
+ if ((e == null) || (expr == null))
+ return null;
+
+ Type etype = expr.Type;
+ bool warning_always_matches = false;
+ bool warning_never_matches = false;
+
+ type = TypeManager.bool_type;
+ eclass = ExprClass.Value;
+
+ //
+ // First case, if at compile time, there is an implicit conversion
+ // then e != null (objects) or true (value types)
+ //
+ e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
+ if (e != null){
+ expr = e;
+ if (etype.IsValueType)
+ action = Action.AlwaysTrue;
+ else
+ action = Action.LeaveOnStack;
+
+ warning_always_matches = true;
+ } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
+ //
+ // Second case: explicit reference convresion
+ //
+ if (expr is NullLiteral)
+ action = Action.AlwaysFalse;
+ else
+ action = Action.Probe;
+ } else {
+ action = Action.AlwaysFalse;
+ warning_never_matches = true;
+ }
+
+ if (RootContext.WarningLevel >= 1){
+ if (warning_always_matches)
+ Warning (183, "The expression is always of type `" +
+ TypeManager.CSharpName (probe_type) + "'");
+ else if (warning_never_matches){
+ if (!(probe_type.IsInterface || expr.Type.IsInterface))
+ Warning (184,
+ "The expression is never of type `" +
+ TypeManager.CSharpName (probe_type) + "'");
+ }
+ }
+
+ return this;
+ }
+ }
+
+ /// <summary>
+ /// Implementation of the `as' operator.
+ /// </summary>
+ public class As : Probe {
+ public As (Expression expr, Expression probe_type, Location l)
+ : base (expr, probe_type, l)
+ {
+ }
+
+ bool do_isinst = false;
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ expr.Emit (ec);
+
+ if (do_isinst)
+ ig.Emit (OpCodes.Isinst, probe_type);
+ }
+
+ static void Error_CannotConvertType (Type source, Type target, Location loc)
+ {
+ Report.Error (
+ 39, loc, "as operator can not convert from `" +
+ TypeManager.CSharpName (source) + "' to `" +
+ TypeManager.CSharpName (target) + "'");
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expression e = base.DoResolve (ec);
+
+ if (e == null)
+ return null;
+
+ type = probe_type;
+ eclass = ExprClass.Value;
+ Type etype = expr.Type;
+
+ if (TypeManager.IsValueType (probe_type)){
+ Report.Error (77, loc, "The as operator should be used with a reference type only (" +
+ TypeManager.CSharpName (probe_type) + " is a value type");
+ return null;
+
+ }
+
+ e = Convert.ImplicitConversion (ec, expr, probe_type, loc);
+ if (e != null){
+ expr = e;
+ do_isinst = false;
+ return this;
+ }
+
+ if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
+ do_isinst = true;
+ return this;
+ }
+
+ Error_CannotConvertType (etype, probe_type, loc);
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// This represents a typecast in the source language.
+ ///
+ /// FIXME: Cast expressions have an unusual set of parsing
+ /// rules, we need to figure those out.
+ /// </summary>
+ public class Cast : Expression {
+ Expression target_type;
+ Expression expr;
+
+ public Cast (Expression cast_type, Expression expr, Location loc)
+ {
+ this.target_type = cast_type;
+ this.expr = expr;
+ this.loc = loc;
+ }
+
+ public Expression TargetType {
+ get {
+ return target_type;
+ }
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ set {
+ expr = value;
+ }
+ }
+
+ bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
+ {
+ if (!ec.ConstantCheckState)
+ return true;
+
+ if ((value < min) || (value > max)) {
+ Error (221, "Constant value `" + value + "' cannot be converted " +
+ "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
+ "syntax to override)");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
+ {
+ if (!ec.ConstantCheckState)
+ return true;
+
+ if (value > max) {
+ Error (221, "Constant value `" + value + "' cannot be converted " +
+ "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
+ "syntax to override)");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckUnsigned (EmitContext ec, long value, Type type)
+ {
+ if (!ec.ConstantCheckState)
+ return true;
+
+ if (value < 0) {
+ Error (221, "Constant value `" + value + "' cannot be converted " +
+ "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
+ "syntax to override)");
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Attempts to do a compile-time folding of a constant cast.
+ /// </summary>
+ Expression TryReduce (EmitContext ec, Type target_type)
+ {
+ Expression real_expr = expr;
+ if (real_expr is EnumConstant)
+ real_expr = ((EnumConstant) real_expr).Child;
+
+ if (real_expr is ByteConstant){
+ byte v = ((ByteConstant) real_expr).Value;
+
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is SByteConstant){
+ sbyte v = ((SByteConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new UShortConstant ((ushort) v);
+ } if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new UIntConstant ((uint) v);
+ } if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new ULongConstant ((ulong) v);
+ }
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is ShortConstant){
+ short v = ((ShortConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.ushort_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new UShortConstant ((ushort) v);
+ }
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new UIntConstant ((uint) v);
+ }
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new ULongConstant ((ulong) v);
+ }
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is UShortConstant){
+ ushort v = ((UShortConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type) {
+ if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
+ return null;
+ return new ShortConstant ((short) v);
+ }
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is IntConstant){
+ int v = ((IntConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type) {
+ if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
+ return null;
+ return new ShortConstant ((short) v);
+ }
+ if (target_type == TypeManager.ushort_type) {
+ if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
+ return null;
+ return new UShortConstant ((ushort) v);
+ }
+ if (target_type == TypeManager.uint32_type) {
+ if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
+ return null;
+ return new UIntConstant ((uint) v);
+ }
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new ULongConstant ((ulong) v);
+ }
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is UIntConstant){
+ uint v = ((UIntConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type) {
+ if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
+ return null;
+ return new ShortConstant ((short) v);
+ }
+ if (target_type == TypeManager.ushort_type) {
+ if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
+ return null;
+ return new UShortConstant ((ushort) v);
+ }
+ if (target_type == TypeManager.int32_type) {
+ if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
+ return null;
+ return new IntConstant ((int) v);
+ }
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is LongConstant){
+ long v = ((LongConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type) {
+ if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
+ return null;
+ return new ShortConstant ((short) v);
+ }
+ if (target_type == TypeManager.ushort_type) {
+ if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
+ return null;
+ return new UShortConstant ((ushort) v);
+ }
+ if (target_type == TypeManager.int32_type) {
+ if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
+ return null;
+ return new IntConstant ((int) v);
+ }
+ if (target_type == TypeManager.uint32_type) {
+ if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
+ return null;
+ return new UIntConstant ((uint) v);
+ }
+ if (target_type == TypeManager.uint64_type) {
+ if (!CheckUnsigned (ec, v, target_type))
+ return null;
+ return new ULongConstant ((ulong) v);
+ }
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is ULongConstant){
+ ulong v = ((ULongConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Byte.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type) {
+ if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
+ return null;
+ return new ShortConstant ((short) v);
+ }
+ if (target_type == TypeManager.ushort_type) {
+ if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
+ return null;
+ return new UShortConstant ((ushort) v);
+ }
+ if (target_type == TypeManager.int32_type) {
+ if (!CheckRange (ec, v, target_type, Int32.MaxValue))
+ return null;
+ return new IntConstant ((int) v);
+ }
+ if (target_type == TypeManager.uint32_type) {
+ if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
+ return null;
+ return new UIntConstant ((uint) v);
+ }
+ if (target_type == TypeManager.int64_type) {
+ if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
+ return null;
+ return new LongConstant ((long) v);
+ }
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is FloatConstant){
+ float v = ((FloatConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (real_expr is DoubleConstant){
+ double v = ((DoubleConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+
+ if (real_expr is CharConstant){
+ char v = ((CharConstant) real_expr).Value;
+
+ if (target_type == TypeManager.byte_type) {
+ if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
+ return null;
+ return new ByteConstant ((byte) v);
+ }
+ if (target_type == TypeManager.sbyte_type) {
+ if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
+ return null;
+ return new SByteConstant ((sbyte) v);
+ }
+ if (target_type == TypeManager.short_type) {
+ if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
+ return null;
+ return new ShortConstant ((short) v);
+ }
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type) {
+ if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
+ return null;
+ return new CharConstant ((char) v);
+ }
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
+
+ int errors = Report.Errors;
+
+ type = ec.DeclSpace.ResolveType (target_type, false, Location);
+
+ if (type == null)
+ return null;
+
+ eclass = ExprClass.Value;
+
+ if (expr is Constant){
+ Expression e = TryReduce (ec, type);
+
+ if (e != null)
+ return e;
+ }
+
+ expr = Convert.ExplicitConversion (ec, expr, type, loc);
+ return expr;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // This one will never happen
+ //
+ throw new Exception ("Should not happen");
+ }
+ }
+
+ /// <summary>
+ /// Binary operators
+ /// </summary>
+ public class Binary : Expression {
+ public enum Operator : byte {
+ Multiply, Division, Modulus,
+ Addition, Subtraction,
+ LeftShift, RightShift,
+ LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
+ Equality, Inequality,
+ BitwiseAnd,
+ ExclusiveOr,
+ BitwiseOr,
+ LogicalAnd,
+ LogicalOr,
+ TOP
+ }
+
+ Operator oper;
+ Expression left, right;
+
+ //
+ // After resolution, method might contain the operator overload
+ // method.
+ //
+ protected MethodBase method;
+ ArrayList Arguments;
+
+ bool DelegateOperation;
+
+ // This must be kept in sync with Operator!!!
+ public static readonly string [] oper_names;
+
+ static Binary ()
+ {
+ oper_names = new string [(int) Operator.TOP];
+
+ oper_names [(int) Operator.Multiply] = "op_Multiply";
+ oper_names [(int) Operator.Division] = "op_Division";
+ oper_names [(int) Operator.Modulus] = "op_Modulus";
+ oper_names [(int) Operator.Addition] = "op_Addition";
+ oper_names [(int) Operator.Subtraction] = "op_Subtraction";
+ oper_names [(int) Operator.LeftShift] = "op_LeftShift";
+ oper_names [(int) Operator.RightShift] = "op_RightShift";
+ oper_names [(int) Operator.LessThan] = "op_LessThan";
+ oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
+ oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
+ oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
+ oper_names [(int) Operator.Equality] = "op_Equality";
+ oper_names [(int) Operator.Inequality] = "op_Inequality";
+ oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
+ oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
+ oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
+ oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
+ oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
+ }
+
+ public Binary (Operator oper, Expression left, Expression right, Location loc)
+ {
+ this.oper = oper;
+ this.left = left;
+ this.right = right;
+ this.loc = loc;
+ }
+
+ public Operator Oper {
+ get {
+ return oper;
+ }
+ set {
+ oper = value;
+ }
+ }
+
+ public Expression Left {
+ get {
+ return left;
+ }
+ set {
+ left = value;
+ }
+ }
+
+ public Expression Right {
+ get {
+ return right;
+ }
+ set {
+ right = value;
+ }
+ }
+
+
+ /// <summary>
+ /// Returns a stringified representation of the Operator
+ /// </summary>
+ static string OperName (Operator oper)
+ {
+ switch (oper){
+ case Operator.Multiply:
+ return "*";
+ case Operator.Division:
+ return "/";
+ case Operator.Modulus:
+ return "%";
+ case Operator.Addition:
+ return "+";
+ case Operator.Subtraction:
+ return "-";
+ case Operator.LeftShift:
+ return "<<";
+ case Operator.RightShift:
+ return ">>";
+ case Operator.LessThan:
+ return "<";
+ case Operator.GreaterThan:
+ return ">";
+ case Operator.LessThanOrEqual:
+ return "<=";
+ case Operator.GreaterThanOrEqual:
+ return ">=";
+ case Operator.Equality:
+ return "==";
+ case Operator.Inequality:
+ return "!=";
+ case Operator.BitwiseAnd:
+ return "&";
+ case Operator.BitwiseOr:
+ return "|";
+ case Operator.ExclusiveOr:
+ return "^";
+ case Operator.LogicalOr:
+ return "||";
+ case Operator.LogicalAnd:
+ return "&&";
+ }
+
+ return oper.ToString ();
+ }
+
+ public override string ToString ()
+ {
+ return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
+ right.ToString () + ")";
+ }
+
+ Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
+ {
+ if (expr.Type == target_type)
+ return expr;
+
+ return Convert.ImplicitConversion (ec, expr, target_type, loc);
+ }
+
+ public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
+ {
+ Report.Error (
+ 34, loc, "Operator `" + OperName (oper)
+ + "' is ambiguous on operands of type `"
+ + TypeManager.CSharpName (l) + "' "
+ + "and `" + TypeManager.CSharpName (r)
+ + "'");
+ }
+
+ bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
+ {
+ if ((l == t) || (r == t))
+ return true;
+
+ if (!check_user_conversions)
+ return false;
+
+ if (Convert.ImplicitUserConversionExists (ec, l, t))
+ return true;
+ else if (Convert.ImplicitUserConversionExists (ec, r, t))
+ return true;
+ else
+ return false;
+ }
+
+ //
+ // Note that handling the case l == Decimal || r == Decimal
+ // is taken care of by the Step 1 Operator Overload resolution.
+ //
+ // If `check_user_conv' is true, we also check whether a user-defined conversion
+ // exists. Note that we only need to do this if both arguments are of a user-defined
+ // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
+ // so we don't explicitly check for performance reasons.
+ //
+ bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
+ {
+ if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
+ //
+ // If either operand is of type double, the other operand is
+ // conveted to type double.
+ //
+ if (r != TypeManager.double_type)
+ right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
+ if (l != TypeManager.double_type)
+ left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
+
+ type = TypeManager.double_type;
+ } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
+ //
+ // if either operand is of type float, the other operand is
+ // converted to type float.
+ //
+ if (r != TypeManager.double_type)
+ right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
+ if (l != TypeManager.double_type)
+ left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
+ type = TypeManager.float_type;
+ } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
+ Expression e;
+ Type other;
+ //
+ // If either operand is of type ulong, the other operand is
+ // converted to type ulong. or an error ocurrs if the other
+ // operand is of type sbyte, short, int or long
+ //
+ if (l == TypeManager.uint64_type){
+ if (r != TypeManager.uint64_type){
+ if (right is IntConstant){
+ IntConstant ic = (IntConstant) right;
+
+ e = Convert.TryImplicitIntConversion (l, ic);
+ if (e != null)
+ right = e;
+ } else if (right is LongConstant){
+ long ll = ((LongConstant) right).Value;
+
+ if (ll > 0)
+ right = new ULongConstant ((ulong) ll);
+ } else {
+ e = Convert.ImplicitNumericConversion (ec, right, l, loc);
+ if (e != null)
+ right = e;
+ }
+ }
+ other = right.Type;
+ } else {
+ if (left is IntConstant){
+ e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
+ if (e != null)
+ left = e;
+ } else if (left is LongConstant){
+ long ll = ((LongConstant) left).Value;
+
+ if (ll > 0)
+ left = new ULongConstant ((ulong) ll);
+ } else {
+ e = Convert.ImplicitNumericConversion (ec, left, r, loc);
+ if (e != null)
+ left = e;
+ }
+ other = left.Type;
+ }
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type) ||
+ (other == TypeManager.int64_type))
+ Error_OperatorAmbiguous (loc, oper, l, r);
+ type = TypeManager.uint64_type;
+ } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
+ //
+ // If either operand is of type long, the other operand is converted
+ // to type long.
+ //
+ if (l != TypeManager.int64_type)
+ left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
+ if (r != TypeManager.int64_type)
+ right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
+
+ type = TypeManager.int64_type;
+ } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
+ //
+ // If either operand is of type uint, and the other
+ // operand is of type sbyte, short or int, othe operands are
+ // converted to type long.
+ //
+ Type other = null;
+
+ if (l == TypeManager.uint32_type){
+ if (right is IntConstant){
+ IntConstant ic = (IntConstant) right;
+ int val = ic.Value;
+
+ if (val >= 0){
+ right = new UIntConstant ((uint) val);
+ type = l;
+
+ return true;
+ }
+ }
+ other = r;
+ } else if (r == TypeManager.uint32_type){
+ if (left is IntConstant){
+ IntConstant ic = (IntConstant) left;
+ int val = ic.Value;
+
+ if (val >= 0){
+ left = new UIntConstant ((uint) val);
+ type = r;
+ return true;
+ }
+ }
+
+ other = l;
+ }
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type)){
+ left = ForceConversion (ec, left, TypeManager.int64_type);
+ right = ForceConversion (ec, right, TypeManager.int64_type);
+ type = TypeManager.int64_type;
+ } else {
+ //
+ // if either operand is of type uint, the other
+ // operand is converd to type uint
+ //
+ left = ForceConversion (ec, left, TypeManager.uint32_type);
+ right = ForceConversion (ec, right, TypeManager.uint32_type);
+ type = TypeManager.uint32_type;
+ }
+ } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
+ if (l != TypeManager.decimal_type)
+ left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
+
+ if (r != TypeManager.decimal_type)
+ right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
+ type = TypeManager.decimal_type;
+ } else {
+ left = ForceConversion (ec, left, TypeManager.int32_type);
+ right = ForceConversion (ec, right, TypeManager.int32_type);
+
+ type = TypeManager.int32_type;
+ }
+
+ return (left != null) && (right != null);
+ }
+
+ static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
+ {
+ Report.Error (19, loc,
+ "Operator " + name + " cannot be applied to operands of type `" +
+ TypeManager.CSharpName (l) + "' and `" +
+ TypeManager.CSharpName (r) + "'");
+ }
+
+ void Error_OperatorCannotBeApplied ()
+ {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
+ }
+
+ static bool is_32_or_64 (Type t)
+ {
+ return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
+ t == TypeManager.int64_type || t == TypeManager.uint64_type);
+ }
+
+ static bool is_unsigned (Type t)
+ {
+ return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+ t == TypeManager.short_type || t == TypeManager.byte_type);
+ }
+
+ static bool is_user_defined (Type t)
+ {
+ if (t.IsSubclassOf (TypeManager.value_type) &&
+ (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
+ return true;
+ else
+ return false;
+ }
+
+ Expression CheckShiftArguments (EmitContext ec)
+ {
+ Expression e;
+ Type l = left.Type;
+ Type r = right.Type;
+
+ e = ForceConversion (ec, right, TypeManager.int32_type);
+ if (e == null){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ right = e;
+
+ if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
+ ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
+ ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
+ ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
+ left = e;
+ type = e.Type;
+
+ return this;
+ }
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type l = left.Type;
+ Type r = right.Type;
+
+ bool overload_failed = false;
+
+ //
+ // Special cases: string comapred to null
+ //
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ if ((l == TypeManager.string_type && (right is NullLiteral)) ||
+ (r == TypeManager.string_type && (left is NullLiteral))){
+ Type = TypeManager.bool_type;
+
+ return this;
+ }
+ }
+
+ //
+ // Do not perform operator overload resolution when both sides are
+ // built-in types
+ //
+ if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression left_expr, right_expr;
+
+ string op = oper_names [(int) oper];
+
+ MethodGroupExpr union;
+ left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
+ if (r != l){
+ right_expr = MemberLookup (
+ ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
+ union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
+ } else
+ union = (MethodGroupExpr) left_expr;
+
+ if (union != null) {
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
+ if (method != null) {
+ MethodInfo mi = (MethodInfo) method;
+
+ type = mi.ReturnType;
+ return this;
+ } else {
+ overload_failed = true;
+ }
+ }
+ }
+
+ //
+ // Step 2: Default operations on CLI native types.
+ //
+
+ //
+ // Step 0: String concatenation (because overloading will get this wrong)
+ //
+ if (oper == Operator.Addition){
+ //
+ // If any of the arguments is a string, cast to string
+ //
+
+ if (l == TypeManager.string_type){
+
+ if (r == TypeManager.void_type) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ if (r == TypeManager.string_type){
+ if (left is Constant && right is Constant){
+ StringConstant ls = (StringConstant) left;
+ StringConstant rs = (StringConstant) right;
+
+ return new StringConstant (
+ ls.Value + rs.Value);
+ }
+
+ if (left is Binary){
+ Binary b = (Binary) left;
+
+ //
+ // Call String.Concat (string, string, string) or
+ // String.Concat (string, string, string, string)
+ // if possible.
+ //
+ if (b.oper == Operator.Addition &&
+ (b.method == TypeManager.string_concat_string_string ||
+ b.method == TypeManager.string_concat_string_string_string)){
+ ArrayList bargs = b.Arguments;
+ int count = bargs.Count;
+
+ if (count == 2){
+ Arguments = bargs;
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+ type = TypeManager.string_type;
+ method = TypeManager.string_concat_string_string_string;
+
+ return this;
+ } else if (count == 3){
+ Arguments = bargs;
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+ type = TypeManager.string_type;
+ method = TypeManager.string_concat_string_string_string_string;
+ return this;
+ }
+ }
+ }
+
+ // string + string
+ method = TypeManager.string_concat_string_string;
+ } else {
+ // string + object
+ method = TypeManager.string_concat_object_object;
+ right = Convert.ImplicitConversion (
+ ec, right, TypeManager.object_type, loc);
+ if (right == null){
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ }
+ type = TypeManager.string_type;
+
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ return this;
+
+ } else if (r == TypeManager.string_type){
+ // object + string
+
+ if (l == TypeManager.void_type) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ method = TypeManager.string_concat_object_object;
+ left = Convert.ImplicitConversion (ec, left, TypeManager.object_type, loc);
+ if (left == null){
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ type = TypeManager.string_type;
+
+ return this;
+ }
+
+ //
+ // Transform a + ( - b) into a - b
+ //
+ if (right is Unary){
+ Unary right_unary = (Unary) right;
+
+ if (right_unary.Oper == Unary.Operator.UnaryNegation){
+ oper = Operator.Subtraction;
+ right = right_unary.Expr;
+ r = right.Type;
+ }
+ }
+ }
+
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ if (l == TypeManager.bool_type || r == TypeManager.bool_type){
+ if (r != TypeManager.bool_type || l != TypeManager.bool_type){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ //
+ // operator != (object a, object b)
+ // operator == (object a, object b)
+ //
+ // For this to be used, both arguments have to be reference-types.
+ // Read the rationale on the spec (14.9.6)
+ //
+ // Also, if at compile time we know that the classes do not inherit
+ // one from the other, then we catch the error there.
+ //
+ if (!(l.IsValueType || r.IsValueType)){
+ type = TypeManager.bool_type;
+
+ if (l == r)
+ return this;
+
+ if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
+ return this;
+
+ //
+ // Also, a standard conversion must exist from either one
+ //
+ if (!(Convert.ImplicitStandardConversionExists (left, r) ||
+ Convert.ImplicitStandardConversionExists (right, l))){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ //
+ // We are going to have to convert to an object to compare
+ //
+ if (l != TypeManager.object_type)
+ left = new EmptyCast (left, TypeManager.object_type);
+ if (r != TypeManager.object_type)
+ right = new EmptyCast (right, TypeManager.object_type);
+
+ //
+ // FIXME: CSC here catches errors cs254 and cs252
+ //
+ return this;
+ }
+
+ //
+ // One of them is a valuetype, but the other one is not.
+ //
+ if (!l.IsValueType || !r.IsValueType) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ }
+
+ // Only perform numeric promotions on:
+ // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
+ //
+ if (oper == Operator.Addition || oper == Operator.Subtraction) {
+ if (l.IsSubclassOf (TypeManager.delegate_type) &&
+ r.IsSubclassOf (TypeManager.delegate_type)) {
+
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ if (oper == Operator.Addition)
+ method = TypeManager.delegate_combine_delegate_delegate;
+ else
+ method = TypeManager.delegate_remove_delegate_delegate;
+
+ if (l != r) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ DelegateOperation = true;
+ type = l;
+ return this;
+ }
+
+ //
+ // Pointer arithmetic:
+ //
+ // T* operator + (T* x, int y);
+ // T* operator + (T* x, uint y);
+ // T* operator + (T* x, long y);
+ // T* operator + (T* x, ulong y);
+ //
+ // T* operator + (int y, T* x);
+ // T* operator + (uint y, T *x);
+ // T* operator + (long y, T *x);
+ // T* operator + (ulong y, T *x);
+ //
+ // T* operator - (T* x, int y);
+ // T* operator - (T* x, uint y);
+ // T* operator - (T* x, long y);
+ // T* operator - (T* x, ulong y);
+ //
+ // long operator - (T* x, T *y)
+ //
+ if (l.IsPointer){
+ if (r.IsPointer && oper == Operator.Subtraction){
+ if (r == l)
+ return new PointerArithmetic (
+ false, left, right, TypeManager.int64_type,
+ loc);
+ } else if (is_32_or_64 (r))
+ return new PointerArithmetic (
+ oper == Operator.Addition, left, right, l, loc);
+ } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
+ return new PointerArithmetic (
+ true, right, left, r, loc);
+ }
+
+ //
+ // Enumeration operators
+ //
+ bool lie = TypeManager.IsEnumType (l);
+ bool rie = TypeManager.IsEnumType (r);
+ if (lie || rie){
+ Expression temp;
+
+ // U operator - (E e, E f)
+ if (lie && rie && oper == Operator.Subtraction){
+ if (l == r){
+ type = TypeManager.EnumToUnderlying (l);
+ return this;
+ }
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ //
+ // operator + (E e, U x)
+ // operator - (E e, U x)
+ //
+ if (oper == Operator.Addition || oper == Operator.Subtraction){
+ Type enum_type = lie ? l : r;
+ Type other_type = lie ? r : l;
+ Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
+;
+
+ if (underlying_type != other_type){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ type = enum_type;
+ return this;
+ }
+
+ if (!rie){
+ temp = Convert.ImplicitConversion (ec, right, l, loc);
+ if (temp != null)
+ right = temp;
+ else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ } if (!lie){
+ temp = Convert.ImplicitConversion (ec, left, r, loc);
+ if (temp != null){
+ left = temp;
+ l = r;
+ } else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ }
+
+ if (oper == Operator.Equality || oper == Operator.Inequality ||
+ oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
+ oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
+ if (left.Type != right.Type){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ type = l;
+ return this;
+ }
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ if (oper == Operator.LeftShift || oper == Operator.RightShift)
+ return CheckShiftArguments (ec);
+
+ if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
+ if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ if (l != r) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ Expression e = new ConditionalLogicalOperator (
+ oper == Operator.LogicalAnd, left, right, l, loc);
+ return e.Resolve (ec);
+ }
+
+ //
+ // operator & (bool x, bool y)
+ // operator | (bool x, bool y)
+ // operator ^ (bool x, bool y)
+ //
+ if (l == TypeManager.bool_type && r == TypeManager.bool_type){
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ type = l;
+ return this;
+ }
+ }
+
+ //
+ // Pointer comparison
+ //
+ if (l.IsPointer && r.IsPointer){
+ if (oper == Operator.Equality || oper == Operator.Inequality ||
+ oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
+ type = TypeManager.bool_type;
+ return this;
+ }
+ }
+
+ //
+ // We are dealing with numbers
+ //
+ if (overload_failed){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ //
+ // This will leave left or right set to null if there is an error
+ //
+ bool check_user_conv = is_user_defined (l) && is_user_defined (r);
+ DoNumericPromotions (ec, l, r, check_user_conv);
+ if (left == null || right == null){
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+
+ //
+ // reload our cached types if required
+ //
+ l = left.Type;
+ r = right.Type;
+
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ if (l == r){
+ if (!((l == TypeManager.int32_type) ||
+ (l == TypeManager.uint32_type) ||
+ (l == TypeManager.short_type) ||
+ (l == TypeManager.ushort_type) ||
+ (l == TypeManager.int64_type) ||
+ (l == TypeManager.uint64_type)))
+ type = l;
+ } else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ }
+
+ if (oper == Operator.Equality ||
+ oper == Operator.Inequality ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.LessThan ||
+ oper == Operator.GreaterThanOrEqual ||
+ oper == Operator.GreaterThan){
+ type = TypeManager.bool_type;
+ }
+
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ left = left.Resolve (ec);
+ right = right.Resolve (ec);
+
+ if (left == null || right == null)
+ return null;
+
+ eclass = ExprClass.Value;
+
+ Constant rc = right as Constant;
+ Constant lc = left as Constant;
+
+ if (rc != null & lc != null){
+ Expression e = ConstantFold.BinaryFold (
+ ec, oper, lc, rc, loc);
+ if (e != null)
+ return e;
+ }
+
+ return ResolveOperator (ec);
+ }
+
+ /// <remarks>
+ /// EmitBranchable is called from Statement.EmitBoolExpression in the
+ /// context of a conditional bool expression. This function will return
+ /// false if it is was possible to use EmitBranchable, or true if it was.
+ ///
+ /// The expression's code is generated, and we will generate a branch to `target'
+ /// if the resulting expression value is equal to isTrue
+ /// </remarks>
+ public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ if (method != null)
+ return false;
+
+ ILGenerator ig = ec.ig;
+
+ //
+ // This is more complicated than it looks, but its just to avoid
+ // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
+ // but on top of that we want for == and != to use a special path
+ // if we are comparing against null
+ //
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
+
+ if (left is NullLiteral){
+ right.Emit (ec);
+ if (my_on_true)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ } else if (right is NullLiteral){
+ left.Emit (ec);
+ if (my_on_true)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ } else if (left is BoolConstant){
+ right.Emit (ec);
+ if (my_on_true != ((BoolConstant) left).Value)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ } else if (right is BoolConstant){
+ left.Emit (ec);
+ if (my_on_true != ((BoolConstant) right).Value)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ }
+
+ } else if (oper == Operator.LogicalAnd){
+ if (left is Binary){
+ Binary left_binary = (Binary) left;
+
+ if (onTrue){
+ Label tests_end = ig.DefineLabel ();
+
+ if (left_binary.EmitBranchable (ec, tests_end, false)){
+ if (right is Binary){
+ Binary right_binary = (Binary) right;
+
+ if (right_binary.EmitBranchable (ec, target, true)){
+ ig.MarkLabel (tests_end);
+ return true;
+ }
+ }
+ right.Emit (ec);
+ ig.Emit (OpCodes.Brtrue, target);
+ ig.MarkLabel (tests_end);
+ return true;
+ }
+ } else {
+ if (left_binary.EmitBranchable (ec, target, false)){
+ if (right is Binary){
+ Binary right_binary = (Binary) right;
+
+ if (right_binary.EmitBranchable (ec, target, false))
+ return true;
+ }
+ right.Emit (ec);
+ if (onTrue)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ }
+ }
+ //
+ // Give up, and let the regular Emit work, but we could
+ // also optimize the left-non-Branchable, but-right-Branchable
+ //
+ }
+ return false;
+ } else if (oper == Operator.LogicalOr){
+ if (left is Binary){
+ Binary left_binary = (Binary) left;
+
+ if (onTrue){
+ if (left_binary.EmitBranchable (ec, target, true)){
+ if (right is Binary){
+ Binary right_binary = (Binary) right;
+
+ if (right_binary.EmitBranchable (ec, target, true))
+ return true;
+ }
+ right.Emit (ec);
+ ig.Emit (OpCodes.Brtrue, target);
+ return true;
+ }
+
+ //
+ // Give up, and let the regular Emit work, but we could
+ // also optimize the left-non-Branchable, but-right-Branchable
+ //
+ } else {
+ Label tests_end = ig.DefineLabel ();
+
+ if (left_binary.EmitBranchable (ec, tests_end, true)){
+ if (right is Binary){
+ Binary right_binary = (Binary) right;
+
+ if (right_binary.EmitBranchable (ec, target, false)){
+ ig.MarkLabel (tests_end);
+ return true;
+ }
+ }
+ right.Emit (ec);
+ ig.Emit (OpCodes.Brfalse, target);
+ ig.MarkLabel (tests_end);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ } else if (!(oper == Operator.LessThan ||
+ oper == Operator.GreaterThan ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThanOrEqual))
+ return false;
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ Type t = left.Type;
+ bool isUnsigned = is_unsigned (t);
+
+ switch (oper){
+ case Operator.Equality:
+ if (onTrue)
+ ig.Emit (OpCodes.Beq, target);
+ else
+ ig.Emit (OpCodes.Bne_Un, target);
+ break;
+
+ case Operator.Inequality:
+ if (onTrue)
+ ig.Emit (OpCodes.Bne_Un, target);
+ else
+ ig.Emit (OpCodes.Beq, target);
+ break;
+
+ case Operator.LessThan:
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Blt_Un, target);
+ else
+ ig.Emit (OpCodes.Blt, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bge_Un, target);
+ else
+ ig.Emit (OpCodes.Bge, target);
+ break;
+
+ case Operator.GreaterThan:
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bgt_Un, target);
+ else
+ ig.Emit (OpCodes.Bgt, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Ble_Un, target);
+ else
+ ig.Emit (OpCodes.Ble, target);
+ break;
+
+ case Operator.LessThanOrEqual:
+ if (t == TypeManager.double_type || t == TypeManager.float_type)
+ isUnsigned = true;
+
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Ble_Un, target);
+ else
+ ig.Emit (OpCodes.Ble, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bgt_Un, target);
+ else
+ ig.Emit (OpCodes.Bgt, target);
+ break;
+
+
+ case Operator.GreaterThanOrEqual:
+ if (t == TypeManager.double_type || t == TypeManager.float_type)
+ isUnsigned = true;
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bge_Un, target);
+ else
+ ig.Emit (OpCodes.Bge, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Blt_Un, target);
+ else
+ ig.Emit (OpCodes.Blt, target);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Type l = left.Type;
+ Type r = right.Type;
+ OpCode opcode;
+
+ if (method != null) {
+
+ // Note that operators are static anyway
+
+ if (Arguments != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+ if (DelegateOperation)
+ ig.Emit (OpCodes.Castclass, type);
+
+ return;
+ }
+
+ //
+ // Handle short-circuit operators differently
+ // than the rest
+ //
+ if (oper == Operator.LogicalAnd){
+ Label load_zero = ig.DefineLabel ();
+ Label end = ig.DefineLabel ();
+ bool process = true;
+
+ if (left is Binary){
+ Binary left_binary = (Binary) left;
+
+ if (left_binary.EmitBranchable (ec, load_zero, false)){
+ right.Emit (ec);
+ ig.Emit (OpCodes.Br, end);
+ process = false;
+ }
+ }
+
+ if (process){
+ left.Emit (ec);
+ ig.Emit (OpCodes.Brfalse, load_zero);
+ right.Emit (ec);
+ ig.Emit (OpCodes.Br, end);
+ }
+ ig.MarkLabel (load_zero);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.MarkLabel (end);
+ return;
+ } else if (oper == Operator.LogicalOr){
+ Label load_one = ig.DefineLabel ();
+ Label end = ig.DefineLabel ();
+ bool process = true;
+
+ if (left is Binary){
+ Binary left_binary = (Binary) left;
+
+ if (left_binary.EmitBranchable (ec, load_one, true)){
+ right.Emit (ec);
+ ig.Emit (OpCodes.Br, end);
+ process = false;
+ }
+ }
+
+ if (process){
+ left.Emit (ec);
+ ig.Emit (OpCodes.Brtrue, load_one);
+ right.Emit (ec);
+ ig.Emit (OpCodes.Br, end);
+ }
+ ig.MarkLabel (load_one);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.MarkLabel (end);
+ return;
+ }
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ bool isUnsigned = is_unsigned (left.Type);
+
+ switch (oper){
+ case Operator.Multiply:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Mul_Ovf;
+ else if (isUnsigned)
+ opcode = OpCodes.Mul_Ovf_Un;
+ else
+ opcode = OpCodes.Mul;
+ } else
+ opcode = OpCodes.Mul;
+
+ break;
+
+ case Operator.Division:
+ if (isUnsigned)
+ opcode = OpCodes.Div_Un;
+ else
+ opcode = OpCodes.Div;
+ break;
+
+ case Operator.Modulus:
+ if (isUnsigned)
+ opcode = OpCodes.Rem_Un;
+ else
+ opcode = OpCodes.Rem;
+ break;
+
+ case Operator.Addition:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Add_Ovf;
+ else if (isUnsigned)
+ opcode = OpCodes.Add_Ovf_Un;
+ else
+ opcode = OpCodes.Add;
+ } else
+ opcode = OpCodes.Add;
+ break;
+
+ case Operator.Subtraction:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Sub_Ovf;
+ else if (isUnsigned)
+ opcode = OpCodes.Sub_Ovf_Un;
+ else
+ opcode = OpCodes.Sub;
+ } else
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.RightShift:
+ if (isUnsigned)
+ opcode = OpCodes.Shr_Un;
+ else
+ opcode = OpCodes.Shr;
+ break;
+
+ case Operator.LeftShift:
+ opcode = OpCodes.Shl;
+ break;
+
+ case Operator.Equality:
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.Inequality:
+ ig.Emit (OpCodes.Ceq);
+ ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.LessThan:
+ if (isUnsigned)
+ opcode = OpCodes.Clt_Un;
+ else
+ opcode = OpCodes.Clt;
+ break;
+
+ case Operator.GreaterThan:
+ if (isUnsigned)
+ opcode = OpCodes.Cgt_Un;
+ else
+ opcode = OpCodes.Cgt;
+ break;
+
+ case Operator.LessThanOrEqual:
+ Type lt = left.Type;
+
+ if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
+ ig.Emit (OpCodes.Cgt_Un);
+ else
+ ig.Emit (OpCodes.Cgt);
+ ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.GreaterThanOrEqual:
+ Type le = left.Type;
+
+ if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
+ ig.Emit (OpCodes.Clt_Un);
+ else
+ ig.Emit (OpCodes.Clt);
+
+ ig.Emit (OpCodes.Ldc_I4_1);
+
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.BitwiseOr:
+ opcode = OpCodes.Or;
+ break;
+
+ case Operator.BitwiseAnd:
+ opcode = OpCodes.And;
+ break;
+
+ case Operator.ExclusiveOr:
+ opcode = OpCodes.Xor;
+ break;
+
+ default:
+ throw new Exception ("This should not happen: Operator = "
+ + oper.ToString ());
+ }
+
+ ig.Emit (opcode);
+ }
+
+ public bool IsBuiltinOperator {
+ get {
+ return method == null;
+ }
+ }
+ }
+
+ //
+ // User-defined conditional logical operator
+ public class ConditionalLogicalOperator : Expression {
+ Expression left, right;
+ bool is_and;
+
+ public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
+ {
+ type = t;
+ eclass = ExprClass.Value;
+ this.loc = loc;
+ this.left = left;
+ this.right = right;
+ this.is_and = is_and;
+ }
+
+ protected void Error19 ()
+ {
+ Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
+ }
+
+ protected void Error218 ()
+ {
+ Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
+ "declarations of operator true and operator false");
+ }
+
+ Expression op_true, op_false, op;
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ MethodInfo method;
+ Expression operator_group;
+
+ operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
+ if (operator_group == null) {
+ Error19 ();
+ return null;
+ }
+
+ ArrayList arguments = new ArrayList ();
+ arguments.Add (new Argument (left, Argument.AType.Expression));
+ arguments.Add (new Argument (right, Argument.AType.Expression));
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) operator_group, arguments, loc) as MethodInfo;
+ if ((method == null) || (method.ReturnType != type)) {
+ Error19 ();
+ return null;
+ }
+
+ op = new StaticCallExpr (method, arguments, loc);
+
+ op_true = GetOperatorTrue (ec, left, loc);
+ op_false = GetOperatorFalse (ec, left, loc);
+ if ((op_true == null) || (op_false == null)) {
+ Error218 ();
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label false_target = ig.DefineLabel ();
+ Label end_target = ig.DefineLabel ();
+
+ ig.Emit (OpCodes.Nop);
+
+ Statement.EmitBoolExpression (ec, is_and ? op_false : op_true, false_target, false);
+ left.Emit (ec);
+ ig.Emit (OpCodes.Br, end_target);
+ ig.MarkLabel (false_target);
+ op.Emit (ec);
+ ig.MarkLabel (end_target);
+
+ ig.Emit (OpCodes.Nop);
+ }
+ }
+
+ public class PointerArithmetic : Expression {
+ Expression left, right;
+ bool is_add;
+
+ //
+ // We assume that `l' is always a pointer
+ //
+ public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
+ {
+ type = t;
+ eclass = ExprClass.Variable;
+ this.loc = loc;
+ left = l;
+ right = r;
+ is_add = is_addition;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Type op_type = left.Type;
+ ILGenerator ig = ec.ig;
+ int size = GetTypeSize (TypeManager.GetElementType (op_type));
+ Type rtype = right.Type;
+
+ if (rtype.IsPointer){
+ //
+ // handle (pointer - pointer)
+ //
+ left.Emit (ec);
+ right.Emit (ec);
+ ig.Emit (OpCodes.Sub);
+
+ if (size != 1){
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, op_type);
+ else
+ IntLiteral.EmitInt (ig, size);
+ ig.Emit (OpCodes.Div);
+ }
+ ig.Emit (OpCodes.Conv_I8);
+ } else {
+ //
+ // handle + and - on (pointer op int)
+ //
+ left.Emit (ec);
+ ig.Emit (OpCodes.Conv_I);
+ right.Emit (ec);
+ if (size != 1){
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, op_type);
+ else
+ IntLiteral.EmitInt (ig, size);
+ if (rtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_I8);
+ else if (rtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_U8);
+ ig.Emit (OpCodes.Mul);
+ ig.Emit (OpCodes.Conv_I);
+ }
+ if (is_add)
+ ig.Emit (OpCodes.Add);
+ else
+ ig.Emit (OpCodes.Sub);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Implements the ternary conditional operator (?:)
+ /// </summary>
+ public class Conditional : Expression {
+ Expression expr, trueExpr, falseExpr;
+
+ public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
+ {
+ this.expr = expr;
+ this.trueExpr = trueExpr;
+ this.falseExpr = falseExpr;
+ this.loc = l;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ public Expression TrueExpr {
+ get {
+ return trueExpr;
+ }
+ }
+
+ public Expression FalseExpr {
+ get {
+ return falseExpr;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+
+ if (expr == null)
+ return null;
+
+ if (expr.Type != TypeManager.bool_type){
+ expr = Expression.ResolveBoolean (
+ ec, expr, loc);
+
+ if (expr == null)
+ return null;
+ }
+
+ trueExpr = trueExpr.Resolve (ec);
+ falseExpr = falseExpr.Resolve (ec);
+
+ if (trueExpr == null || falseExpr == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ if (trueExpr.Type == falseExpr.Type)
+ type = trueExpr.Type;
+ else {
+ Expression conv;
+ Type true_type = trueExpr.Type;
+ Type false_type = falseExpr.Type;
+
+ if (trueExpr is NullLiteral){
+ type = false_type;
+ return this;
+ } else if (falseExpr is NullLiteral){
+ type = true_type;
+ return this;
+ }
+
+ //
+ // First, if an implicit conversion exists from trueExpr
+ // to falseExpr, then the result type is of type falseExpr.Type
+ //
+ conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
+ if (conv != null){
+ //
+ // Check if both can convert implicitl to each other's type
+ //
+ if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
+ Error (172,
+ "Can not compute type of conditional expression " +
+ "as `" + TypeManager.CSharpName (trueExpr.Type) +
+ "' and `" + TypeManager.CSharpName (falseExpr.Type) +
+ "' convert implicitly to each other");
+ return null;
+ }
+ type = false_type;
+ trueExpr = conv;
+ } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
+ type = true_type;
+ falseExpr = conv;
+ } else {
+ Error (173, "The type of the conditional expression can " +
+ "not be computed because there is no implicit conversion" +
+ " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
+ " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
+ return null;
+ }
+ }
+
+ if (expr is BoolConstant){
+ BoolConstant bc = (BoolConstant) expr;
+
+ if (bc.Value)
+ return trueExpr;
+ else
+ return falseExpr;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label false_target = ig.DefineLabel ();
+ Label end_target = ig.DefineLabel ();
+
+ Statement.EmitBoolExpression (ec, expr, false_target, false);
+ trueExpr.Emit (ec);
+ ig.Emit (OpCodes.Br, end_target);
+ ig.MarkLabel (false_target);
+ falseExpr.Emit (ec);
+ ig.MarkLabel (end_target);
+ }
+
+ }
+
+ /// <summary>
+ /// Local variables
+ /// </summary>
+ public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public readonly string Name;
+ public readonly Block Block;
+ LocalInfo local_info;
+ VariableInfo variable_info;
+ bool is_readonly;
+
+ public LocalVariableReference (Block block, string name, Location l)
+ {
+ Block = block;
+ Name = name;
+ loc = l;
+ eclass = ExprClass.Variable;
+ }
+
+ // Setting `is_readonly' to false will allow you to create a writable
+ // reference to a read-only variable. This is used by foreach and using.
+ public LocalVariableReference (Block block, string name, Location l,
+ LocalInfo local_info, bool is_readonly)
+ : this (block, name, l)
+ {
+ this.local_info = local_info;
+ this.is_readonly = is_readonly;
+ }
+
+ public VariableInfo VariableInfo {
+ get { return variable_info; }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return is_readonly;
+ }
+ }
+
+ protected void DoResolveBase (EmitContext ec)
+ {
+ if (local_info == null) {
+ local_info = Block.GetLocalInfo (Name);
+ is_readonly = local_info.ReadOnly;
+ }
+
+ variable_info = Block.GetVariableInfo (local_info);
+ type = local_info.VariableType;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ DoResolveBase (ec);
+
+ Expression e = Block.GetConstantExpression (Name);
+ if (e != null) {
+ local_info.Used = true;
+ eclass = ExprClass.Value;
+ return e;
+ }
+
+ if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
+ return null;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ DoResolveBase (ec);
+
+ if (variable_info != null)
+ variable_info.SetAssigned (ec);
+
+ Expression e = DoResolve (ec);
+
+ if (e == null)
+ return null;
+
+ if (is_readonly){
+ Error (1604, "cannot assign to `" + Name + "' because it is readonly");
+ return null;
+ }
+
+ return this;
+ }
+
+ public bool VerifyFixed (bool is_expression)
+ {
+ return !is_expression || local_info.IsFixed;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (local_info.LocalBuilder == null){
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
+ } else
+ ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
+
+ local_info.Used = true;
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+
+ local_info.Assigned = true;
+
+ if (local_info.LocalBuilder == null){
+ ig.Emit (OpCodes.Ldarg_0);
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
+ } else {
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (local_info.LocalBuilder == null){
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
+ } else
+ ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
+ }
+ }
+
+ /// <summary>
+ /// This represents a reference to a parameter in the intermediate
+ /// representation.
+ /// </summary>
+ public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ Parameters pars;
+ String name;
+ int idx;
+ Block block;
+ VariableInfo vi;
+ public Parameter.Modifier mod;
+ public bool is_ref, is_out;
+
+ public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
+ {
+ this.pars = pars;
+ this.block = block;
+ this.idx = idx;
+ this.name = name;
+ this.loc = loc;
+ eclass = ExprClass.Variable;
+ }
+
+ public VariableInfo VariableInfo {
+ get { return vi; }
+ }
+
+ public bool VerifyFixed (bool is_expression)
+ {
+ return !is_expression;
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (!ec.DoFlowAnalysis || !is_out ||
+ ec.CurrentBranching.IsAssigned (vi))
+ return true;
+
+ Report.Error (165, loc,
+ "Use of unassigned parameter `" + name + "'");
+ return false;
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+ {
+ if (!ec.DoFlowAnalysis || !is_out ||
+ ec.CurrentBranching.IsFieldAssigned (vi, field_name))
+ return true;
+
+ Report.Error (170, loc,
+ "Use of possibly unassigned field `" + field_name + "'");
+ return false;
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (is_out && ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetAssigned (vi);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string field_name)
+ {
+ if (is_out && ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetFieldAssigned (vi, field_name);
+ }
+
+ protected void DoResolveBase (EmitContext ec)
+ {
+ type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
+ is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
+ is_out = (mod & Parameter.Modifier.OUT) != 0;
+ eclass = ExprClass.Variable;
+
+ if (is_out)
+ vi = block.ParameterMap [idx];
+ }
+
+ //
+ // Notice that for ref/out parameters, the type exposed is not the
+ // same type exposed externally.
+ //
+ // for "ref int a":
+ // externally we expose "int&"
+ // here we expose "int".
+ //
+ // We record this in "is_ref". This means that the type system can treat
+ // the type as it is expected, but when we generate the code, we generate
+ // the alternate kind of code.
+ //
+ public override Expression DoResolve (EmitContext ec)
+ {
+ DoResolveBase (ec);
+
+ if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
+ return null;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ DoResolveBase (ec);
+
+ SetAssigned (ec);
+
+ return this;
+ }
+
+ static public void EmitLdArg (ILGenerator ig, int x)
+ {
+ if (x <= 255){
+ switch (x){
+ case 0: ig.Emit (OpCodes.Ldarg_0); break;
+ case 1: ig.Emit (OpCodes.Ldarg_1); break;
+ case 2: ig.Emit (OpCodes.Ldarg_2); break;
+ case 3: ig.Emit (OpCodes.Ldarg_3); break;
+ default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
+ }
+ } else
+ ig.Emit (OpCodes.Ldarg, x);
+ }
+
+ //
+ // This method is used by parameters that are references, that are
+ // being passed as references: we only want to pass the pointer (that
+ // is already stored in the parameter, not the address of the pointer,
+ // and not the value of the variable).
+ //
+ public void EmitLoad (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ EmitLdArg (ig, arg_idx);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (ec.RemapToProxy){
+ ig.Emit (OpCodes.Ldarg_0);
+ ec.EmitArgument (idx);
+ return;
+ }
+
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ EmitLdArg (ig, arg_idx);
+
+ if (!is_ref)
+ return;
+
+ //
+ // If we are a reference, we loaded on the stack a pointer
+ // Now lets load the real value
+ //
+ LoadFromPtr (ig, type);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (ec.RemapToProxy){
+ ig.Emit (OpCodes.Ldarg_0);
+ source.Emit (ec);
+ ec.EmitStoreArgument (idx);
+ return;
+ }
+
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ if (is_ref)
+ EmitLdArg (ig, arg_idx);
+
+ source.Emit (ec);
+
+ if (is_ref)
+ StoreFromPtr (ig, type);
+ else {
+ if (arg_idx <= 255)
+ ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
+ else
+ ig.Emit (OpCodes.Starg, arg_idx);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ if (ec.RemapToProxy){
+ Report.Error (-1, "Report this: Taking the address of a remapped parameter not supported");
+ return;
+ }
+
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ if (is_ref){
+ if (arg_idx <= 255)
+ ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
+ else
+ ec.ig.Emit (OpCodes.Ldarg, arg_idx);
+ } else {
+ if (arg_idx <= 255)
+ ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
+ else
+ ec.ig.Emit (OpCodes.Ldarga, arg_idx);
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Used for arguments to New(), Invocation()
+ /// </summary>
+ public class Argument {
+ public enum AType : byte {
+ Expression,
+ Ref,
+ Out
+ };
+
+ public readonly AType ArgType;
+ public Expression Expr;
+
+ public Argument (Expression expr, AType type)
+ {
+ this.Expr = expr;
+ this.ArgType = type;
+ }
+
+ public Type Type {
+ get {
+ if (ArgType == AType.Ref || ArgType == AType.Out)
+ return TypeManager.GetReferenceType (Expr.Type);
+ else
+ return Expr.Type;
+ }
+ }
+
+ public Parameter.Modifier GetParameterModifier ()
+ {
+ switch (ArgType) {
+ case AType.Out:
+ return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
+
+ case AType.Ref:
+ return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
+
+ default:
+ return Parameter.Modifier.NONE;
+ }
+ }
+
+ public static string FullDesc (Argument a)
+ {
+ return (a.ArgType == AType.Ref ? "ref " :
+ (a.ArgType == AType.Out ? "out " : "")) +
+ TypeManager.CSharpName (a.Expr.Type);
+ }
+
+ public bool ResolveMethodGroup (EmitContext ec, Location loc)
+ {
+ // FIXME: csc doesn't report any error if you try to use `ref' or
+ // `out' in a delegate creation expression.
+ Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+ if (Expr == null)
+ return false;
+
+ return true;
+ }
+
+ public bool Resolve (EmitContext ec, Location loc)
+ {
+ if (ArgType == AType.Ref) {
+ Expr = Expr.Resolve (ec);
+ if (Expr == null)
+ return false;
+
+ Expr = Expr.ResolveLValue (ec, Expr);
+ } else if (ArgType == AType.Out)
+ Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
+ else
+ Expr = Expr.Resolve (ec);
+
+ if (Expr == null)
+ return false;
+
+ if (ArgType == AType.Expression)
+ return true;
+
+ if (Expr.eclass != ExprClass.Variable){
+ //
+ // We just probe to match the CSC output
+ //
+ if (Expr.eclass == ExprClass.PropertyAccess ||
+ Expr.eclass == ExprClass.IndexerAccess){
+ Report.Error (
+ 206, loc,
+ "A property or indexer can not be passed as an out or ref " +
+ "parameter");
+ } else {
+ Report.Error (
+ 1510, loc,
+ "An lvalue is required as an argument to out or ref");
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ public void Emit (EmitContext ec)
+ {
+ //
+ // Ref and Out parameters need to have their addresses taken.
+ //
+ // ParameterReferences might already be references, so we want
+ // to pass just the value
+ //
+ if (ArgType == AType.Ref || ArgType == AType.Out){
+ AddressOp mode = AddressOp.Store;
+
+ if (ArgType == AType.Ref)
+ mode |= AddressOp.Load;
+
+ if (Expr is ParameterReference){
+ ParameterReference pr = (ParameterReference) Expr;
+
+ if (pr.is_ref)
+ pr.EmitLoad (ec);
+ else {
+
+ pr.AddressOf (ec, mode);
+ }
+ } else
+ ((IMemoryLocation)Expr).AddressOf (ec, mode);
+ } else
+ Expr.Emit (ec);
+ }
+ }
+
+ /// <summary>
+ /// Invocation of methods or delegates.
+ /// </summary>
+ public class Invocation : ExpressionStatement {
+ public readonly ArrayList Arguments;
+
+ Expression expr;
+ MethodBase method = null;
+ bool is_base;
+
+ static Hashtable method_parameter_cache;
+
+ static Invocation ()
+ {
+ method_parameter_cache = new PtrHashtable ();
+ }
+
+ //
+ // arguments is an ArrayList, but we do not want to typecast,
+ // as it might be null.
+ //
+ // FIXME: only allow expr to be a method invocation or a
+ // delegate invocation (7.5.5)
+ //
+ public Invocation (Expression expr, ArrayList arguments, Location l)
+ {
+ this.expr = expr;
+ Arguments = arguments;
+ loc = l;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ /// <summary>
+ /// Returns the Parameters (a ParameterData interface) for the
+ /// Method `mb'
+ /// </summary>
+ public static ParameterData GetParameterData (MethodBase mb)
+ {
+ object pd = method_parameter_cache [mb];
+ object ip;
+
+ if (pd != null)
+ return (ParameterData) pd;
+
+
+ ip = TypeManager.LookupParametersByBuilder (mb);
+ if (ip != null){
+ method_parameter_cache [mb] = ip;
+
+ return (ParameterData) ip;
+ } else {
+ ParameterInfo [] pi = mb.GetParameters ();
+ ReflectionParameters rp = new ReflectionParameters (pi);
+ method_parameter_cache [mb] = rp;
+
+ return (ParameterData) rp;
+ }
+ }
+
+ /// <summary>
+ /// Determines "better conversion" as specified in 7.4.2.3
+ /// Returns : 1 if a->p is better
+ /// 0 if a->q or neither is better
+ /// </summary>
+ static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
+ {
+ Type argument_type = a.Type;
+ Expression argument_expr = a.Expr;
+
+ if (argument_type == null)
+ throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
+
+ //
+ // This is a special case since csc behaves this way. I can't find
+ // it anywhere in the spec but oh well ...
+ //
+ if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
+ return 1;
+ else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
+ return 0;
+
+ if (p == q)
+ return 0;
+
+ if (argument_type == p)
+ return 1;
+
+ if (argument_type == q)
+ return 0;
+
+ //
+ // Now probe whether an implicit constant expression conversion
+ // can be used.
+ //
+ // An implicit constant expression conversion permits the following
+ // conversions:
+ //
+ // * A constant-expression of type `int' can be converted to type
+ // sbyte, byute, short, ushort, uint, ulong provided the value of
+ // of the expression is withing the range of the destination type.
+ //
+ // * A constant-expression of type long can be converted to type
+ // ulong, provided the value of the constant expression is not negative
+ //
+ // FIXME: Note that this assumes that constant folding has
+ // taken place. We dont do constant folding yet.
+ //
+
+ if (argument_expr is IntConstant){
+ IntConstant ei = (IntConstant) argument_expr;
+ int value = ei.Value;
+
+ if (p == TypeManager.sbyte_type){
+ if (value >= SByte.MinValue && value <= SByte.MaxValue)
+ return 1;
+ } else if (p == TypeManager.byte_type){
+ if (q == TypeManager.sbyte_type &&
+ value >= SByte.MinValue && value <= SByte.MaxValue)
+ return 0;
+ else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
+ return 1;
+ } else if (p == TypeManager.short_type){
+ if (value >= Int16.MinValue && value <= Int16.MaxValue)
+ return 1;
+ } else if (p == TypeManager.ushort_type){
+ if (q == TypeManager.short_type &&
+ value >= Int16.MinValue && value <= Int16.MaxValue)
+ return 0;
+ else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
+ return 1;
+ } else if (p == TypeManager.int32_type){
+ if (value >= Int32.MinValue && value <= Int32.MaxValue)
+ return 1;
+ } else if (p == TypeManager.uint32_type){
+ //
+ // we can optimize this case: a positive int32
+ // always fits on a uint32
+ //
+ if (value >= 0)
+ return 1;
+ } else if (p == TypeManager.uint64_type){
+ //
+ // we can optimize this case: a positive int32
+ // always fits on a uint64
+ //
+ if (q == TypeManager.int64_type)
+ return 0;
+ else if (value >= 0)
+ return 1;
+ } else if (p == TypeManager.int64_type){
+ return 1;
+ }
+ } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
+ LongConstant lc = (LongConstant) argument_expr;
+
+ if (p == TypeManager.uint64_type){
+ if (lc.Value > 0)
+ return 1;
+ }
+ }
+
+ if (q == null) {
+ Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
+
+ if (tmp != null)
+ return 1;
+ else
+ return 0;
+ }
+
+ Expression p_tmp = new EmptyExpression (p);
+ Expression q_tmp = new EmptyExpression (q);
+
+ if (Convert.ImplicitConversionExists (ec, p_tmp, q) == true &&
+ Convert.ImplicitConversionExists (ec, q_tmp, p) == false)
+ return 1;
+
+ if (p == TypeManager.sbyte_type)
+ if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
+ q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+ return 1;
+
+ if (p == TypeManager.short_type)
+ if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
+ q == TypeManager.uint64_type)
+ return 1;
+
+ if (p == TypeManager.int32_type)
+ if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+ return 1;
+
+ if (p == TypeManager.int64_type)
+ if (q == TypeManager.uint64_type)
+ return 1;
+
+ return 0;
+ }
+
+ /// <summary>
+ /// Determines "Better function"
+ /// </summary>
+ /// <remarks>
+ /// and returns an integer indicating :
+ /// 0 if candidate ain't better
+ /// 1 if candidate is better than the current best match
+ /// </remarks>
+ static int BetterFunction (EmitContext ec, ArrayList args,
+ MethodBase candidate, MethodBase best,
+ bool expanded_form, Location loc)
+ {
+ ParameterData candidate_pd = GetParameterData (candidate);
+ ParameterData best_pd;
+ int argument_count;
+
+ if (args == null)
+ argument_count = 0;
+ else
+ argument_count = args.Count;
+
+ int cand_count = candidate_pd.Count;
+
+ if (cand_count == 0 && argument_count == 0)
+ return 1;
+
+ if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
+ if (cand_count != argument_count)
+ return 0;
+
+ if (best == null) {
+ int x = 0;
+
+ if (argument_count == 0 && cand_count == 1 &&
+ candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
+ return 1;
+
+ for (int j = argument_count; j > 0;) {
+ j--;
+
+ Argument a = (Argument) args [j];
+ Type t = candidate_pd.ParameterType (j);
+
+ if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ t = TypeManager.GetElementType (t);
+
+ x = BetterConversion (ec, a, t, null, loc);
+
+ if (x <= 0)
+ break;
+ }
+
+ if (x > 0)
+ return 1;
+ else
+ return 0;
+ }
+
+ best_pd = GetParameterData (best);
+
+ int rating1 = 0, rating2 = 0;
+
+ for (int j = 0; j < argument_count; ++j) {
+ int x, y;
+
+ Argument a = (Argument) args [j];
+
+ Type ct = candidate_pd.ParameterType (j);
+ Type bt = best_pd.ParameterType (j);
+
+ if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ ct = TypeManager.GetElementType (ct);
+
+ if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ bt = TypeManager.GetElementType (bt);
+
+ x = BetterConversion (ec, a, ct, bt, loc);
+ y = BetterConversion (ec, a, bt, ct, loc);
+
+ if (x < y)
+ return 0;
+
+ rating1 += x;
+ rating2 += y;
+ }
+
+ if (rating1 > rating2)
+ return 1;
+ else
+ return 0;
+ }
+
+ public static string FullMethodDesc (MethodBase mb)
+ {
+ string ret_type = "";
+
+ if (mb is MethodInfo)
+ ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
+
+ StringBuilder sb = new StringBuilder (ret_type);
+ sb.Append (" ");
+ sb.Append (mb.ReflectedType.ToString ());
+ sb.Append (".");
+ sb.Append (mb.Name);
+
+ ParameterData pd = GetParameterData (mb);
+
+ int count = pd.Count;
+ sb.Append (" (");
+
+ for (int i = count; i > 0; ) {
+ i--;
+
+ sb.Append (pd.ParameterDesc (count - i - 1));
+ if (i != 0)
+ sb.Append (", ");
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+ }
+
+ public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
+ {
+ MemberInfo [] miset;
+ MethodGroupExpr union;
+
+ if (mg1 == null){
+ if (mg2 == null)
+ return null;
+ return (MethodGroupExpr) mg2;
+ } else {
+ if (mg2 == null)
+ return (MethodGroupExpr) mg1;
+ }
+
+ MethodGroupExpr left_set = null, right_set = null;
+ int length1 = 0, length2 = 0;
+
+ left_set = (MethodGroupExpr) mg1;
+ length1 = left_set.Methods.Length;
+
+ right_set = (MethodGroupExpr) mg2;
+ length2 = right_set.Methods.Length;
+
+ ArrayList common = new ArrayList ();
+
+ foreach (MethodBase l in left_set.Methods){
+ foreach (MethodBase r in right_set.Methods){
+ if (l != r)
+ continue;
+ common.Add (r);
+ break;
+ }
+ }
+
+ miset = new MemberInfo [length1 + length2 - common.Count];
+ left_set.Methods.CopyTo (miset, 0);
+
+ int k = length1;
+
+ foreach (MemberInfo mi in right_set.Methods){
+ if (!common.Contains (mi))
+ miset [k++] = mi;
+ }
+
+ union = new MethodGroupExpr (miset, loc);
+
+ return union;
+ }
+
+ /// <summary>
+ /// Determines is the candidate method, if a params method, is applicable
+ /// in its expanded form to the given set of arguments
+ /// </summary>
+ static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (candidate);
+
+ int pd_count = pd.Count;
+
+ if (pd_count == 0)
+ return false;
+
+ if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
+ return false;
+
+ if (pd_count - 1 > arg_count)
+ return false;
+
+ if (pd_count == 1 && arg_count == 0)
+ return true;
+
+ //
+ // If we have come this far, the case which remains is when the number of parameters
+ // is less than or equal to the argument count.
+ //
+ for (int i = 0; i < pd_count - 1; ++i) {
+
+ Argument a = (Argument) arguments [i];
+
+ Parameter.Modifier a_mod = a.GetParameterModifier () &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ Parameter.Modifier p_mod = pd.ParameterModifier (i) &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+
+ if (a_mod == p_mod) {
+
+ if (a_mod == Parameter.Modifier.NONE)
+ if (!Convert.ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
+ return false;
+
+ if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
+ Type pt = pd.ParameterType (i);
+
+ if (!pt.IsByRef)
+ pt = TypeManager.GetReferenceType (pt);
+
+ if (pt != a.Type)
+ return false;
+ }
+ } else
+ return false;
+
+ }
+
+ Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
+
+ for (int i = pd_count - 1; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+
+ if (!Convert.ImplicitStandardConversionExists (a.Expr, element_type))
+ return false;
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Determines if the candidate method is applicable (section 14.4.2.1)
+ /// to the given set of arguments
+ /// </summary>
+ static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+
+ ParameterData pd = GetParameterData (candidate);
+
+ int pd_count = pd.Count;
+
+ if (arg_count != pd.Count)
+ return false;
+
+ for (int i = arg_count; i > 0; ) {
+ i--;
+
+ Argument a = (Argument) arguments [i];
+
+ Parameter.Modifier a_mod = a.GetParameterModifier () &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ Parameter.Modifier p_mod = pd.ParameterModifier (i) &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+
+
+ if (a_mod == p_mod ||
+ (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
+ if (a_mod == Parameter.Modifier.NONE) {
+ if (!Convert.ImplicitConversionExists (ec,
+ a.Expr, pd.ParameterType (i)))
+ return false;
+ }
+
+ if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
+ Type pt = pd.ParameterType (i);
+
+ if (!pt.IsByRef)
+ pt = TypeManager.GetReferenceType (pt);
+
+ if (pt != a.Type)
+ return false;
+ }
+ } else
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+ /// <summary>
+ /// Find the Applicable Function Members (7.4.2.1)
+ ///
+ /// me: Method Group expression with the members to select.
+ /// it might contain constructors or methods (or anything
+ /// that maps to a method).
+ ///
+ /// Arguments: ArrayList containing resolved Argument objects.
+ ///
+ /// loc: The location if we want an error to be reported, or a Null
+ /// location for "probing" purposes.
+ ///
+ /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+ /// that is the best match of me on Arguments.
+ ///
+ /// </summary>
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ArrayList Arguments, Location loc)
+ {
+ MethodBase method = null;
+ Type applicable_type = null;
+ int argument_count;
+ ArrayList candidates = new ArrayList ();
+
+ //
+ // First we construct the set of applicable methods
+ //
+
+ //
+ // We start at the top of the type hierarchy and
+ // go down to find applicable methods
+ //
+ applicable_type = me.DeclaringType;
+
+ bool found_applicable = false;
+ foreach (MethodBase candidate in me.Methods) {
+ Type decl_type = candidate.DeclaringType;
+
+ //
+ // If we have already found an applicable method
+ // we eliminate all base types (Section 14.5.5.1)
+ //
+ if (decl_type != applicable_type &&
+ (applicable_type.IsSubclassOf (decl_type) ||
+ TypeManager.ImplementsInterface (applicable_type, decl_type)) &&
+ found_applicable)
+ continue;
+
+
+ // Check if candidate is applicable (section 14.4.2.1)
+ if (!IsApplicable (ec, Arguments, candidate))
+ continue;
+
+
+ candidates.Add (candidate);
+ applicable_type = candidate.DeclaringType;
+ found_applicable = true;
+
+ }
+
+
+ //
+ // Now we actually find the best method
+ //
+ foreach (MethodBase candidate in candidates) {
+ int x = BetterFunction (ec, Arguments, candidate, method, false, loc);
+
+ if (x == 0)
+ continue;
+
+ method = candidate;
+ }
+
+
+ if (Arguments == null)
+ argument_count = 0;
+ else
+ argument_count = Arguments.Count;
+
+ //
+ // Now we see if we can find params functions,
+ // applicable in their expanded form since if
+ // they were applicable in their normal form,
+ // they would have been selected above anyways
+ //
+ bool chose_params_expanded = false;
+
+ if (method == null) {
+ candidates = new ArrayList ();
+ foreach (MethodBase candidate in me.Methods){
+ if (!IsParamsMethodApplicable (ec, Arguments, candidate))
+ continue;
+
+ candidates.Add (candidate);
+
+ int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
+ if (x == 0)
+ continue;
+
+ method = candidate;
+ chose_params_expanded = true;
+ }
+ }
+
+ if (method == null) {
+ //
+ // Okay so we have failed to find anything so we
+ // return by providing info about the closest match
+ //
+ for (int i = 0; i < me.Methods.Length; ++i) {
+
+ MethodBase c = (MethodBase) me.Methods [i];
+ ParameterData pd = GetParameterData (c);
+
+ if (pd.Count != argument_count)
+ continue;
+
+ VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
+ null, loc);
+ }
+
+ if (!Location.IsNull (loc)) {
+ string report_name = me.Name;
+ if (report_name == ".ctor")
+ report_name = me.DeclaringType.ToString ();
+
+ Error_WrongNumArguments (loc, report_name, argument_count);
+ }
+
+ return null;
+ }
+
+ //
+ // Now check that there are no ambiguities i.e the selected method
+ // should be better than all the others
+ //
+
+ foreach (MethodBase candidate in candidates){
+ if (candidate == method)
+ continue;
+
+ //
+ // If a normal method is applicable in
+ // the sense that it has the same
+ // number of arguments, then the
+ // expanded params method is never
+ // applicable so we debar the params
+ // method.
+ //
+
+ if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
+ IsApplicable (ec, Arguments, method))
+ continue;
+
+ int x = BetterFunction (ec, Arguments, method, candidate,
+ chose_params_expanded, loc);
+
+ if (x != 1) {
+ Report.Error (
+ 121, loc,
+ "Ambiguous call when selecting function due to implicit casts");
+ return null;
+ }
+ }
+
+ //
+ // And now check if the arguments are all
+ // compatible, perform conversions if
+ // necessary etc. and return if everything is
+ // all right
+ //
+
+ if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
+ chose_params_expanded, null, loc))
+ return null;
+
+ return method;
+ }
+
+ static void Error_WrongNumArguments (Location loc, String name, int arg_count)
+ {
+ Report.Error (1501, loc,
+ "No overload for method `" + name + "' takes `" +
+ arg_count + "' arguments");
+ }
+
+ static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
+ Type delegate_type, string arg_sig, string par_desc)
+ {
+ if (delegate_type == null)
+ Report.Error (1502, loc,
+ "The best overloaded match for method '" +
+ FullMethodDesc (method) +
+ "' has some invalid arguments");
+ else
+ Report.Error (1594, loc,
+ "Delegate '" + delegate_type.ToString () +
+ "' has some invalid arguments.");
+ Report.Error (1503, loc,
+ String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
+ idx, arg_sig, par_desc));
+ }
+
+ public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
+ int argument_count,
+ MethodBase method,
+ bool chose_params_expanded,
+ Type delegate_type,
+ Location loc)
+ {
+ ParameterData pd = GetParameterData (method);
+ int pd_count = pd.Count;
+
+ for (int j = 0; j < argument_count; j++) {
+ Argument a = (Argument) Arguments [j];
+ Expression a_expr = a.Expr;
+ Type parameter_type = pd.ParameterType (j);
+ Parameter.Modifier pm = pd.ParameterModifier (j);
+
+ if (pm == Parameter.Modifier.PARAMS){
+ Parameter.Modifier am = a.GetParameterModifier ();
+
+ if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
+ if (!Location.IsNull (loc))
+ Error_InvalidArguments (
+ loc, j, method, delegate_type,
+ Argument.FullDesc (a), pd.ParameterDesc (j));
+ return false;
+ }
+
+ if (chose_params_expanded)
+ parameter_type = TypeManager.GetElementType (parameter_type);
+ } else {
+ //
+ // Check modifiers
+ //
+ if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
+ if (!Location.IsNull (loc))
+ Error_InvalidArguments (
+ loc, j, method, delegate_type,
+ Argument.FullDesc (a), pd.ParameterDesc (j));
+ return false;
+ }
+ }
+
+ //
+ // Check Type
+ //
+ if (a.Type != parameter_type){
+ Expression conv;
+
+ conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
+
+ if (conv == null) {
+ Console.WriteLine ("GAA: {0} {1} {2}",
+ pd.ParameterType (j),
+ pd.ParameterType (j).Assembly == CodeGen.AssemblyBuilder,
+ method.DeclaringType.Assembly == CodeGen.AssemblyBuilder);
+
+ if (!Location.IsNull (loc))
+ Error_InvalidArguments (
+ loc, j, method, delegate_type,
+ Argument.FullDesc (a), pd.ParameterDesc (j));
+ return false;
+ }
+
+ //
+ // Update the argument with the implicit conversion
+ //
+ if (a_expr != conv)
+ a.Expr = conv;
+ }
+
+ Parameter.Modifier a_mod = a.GetParameterModifier () &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ Parameter.Modifier p_mod = pd.ParameterModifier (j) &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+
+ if (a_mod != p_mod &&
+ pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
+ if (!Location.IsNull (loc)) {
+ Console.WriteLine ("A:P: " + a.GetParameterModifier ());
+ Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
+ Console.WriteLine ("PT: " + parameter_type.IsByRef);
+ Report.Error (1502, loc,
+ "The best overloaded match for method '" + FullMethodDesc (method)+
+ "' has some invalid arguments");
+ Report.Error (1503, loc,
+ "Argument " + (j+1) +
+ ": Cannot convert from '" + Argument.FullDesc (a)
+ + "' to '" + pd.ParameterDesc (j) + "'");
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // First, resolve the expression that is used to
+ // trigger the invocation
+ //
+ if (expr is BaseAccess)
+ is_base = true;
+
+ Expression old = expr;
+
+ expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+ if (expr == null)
+ return null;
+
+ if (!(expr is MethodGroupExpr)) {
+ Type expr_type = expr.Type;
+
+ if (expr_type != null){
+ bool IsDelegate = TypeManager.IsDelegateType (expr_type);
+ if (IsDelegate)
+ return (new DelegateInvocation (
+ this.expr, Arguments, loc)).Resolve (ec);
+ }
+ }
+
+ if (!(expr is MethodGroupExpr)){
+ expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
+ return null;
+ }
+
+ //
+ // Next, evaluate all the expressions in the argument list
+ //
+ if (Arguments != null){
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ MethodGroupExpr mg = (MethodGroupExpr) expr;
+ method = OverloadResolve (ec, mg, Arguments, loc);
+
+ if (method == null){
+ Error (-6,
+ "Could not find any applicable function for this argument list");
+ return null;
+ }
+
+ MethodInfo mi = method as MethodInfo;
+ if (mi != null) {
+ type = TypeManager.TypeToCoreType (mi.ReturnType);
+ if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
+ SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
+ }
+
+ if (type.IsPointer){
+ if (!ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+ }
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (is_base && method.IsAbstract){
+ Report.Error (205, loc, "Cannot call an abstract base member: " +
+ FullMethodDesc (method));
+ return null;
+ }
+
+ if ((method.Attributes & MethodAttributes.SpecialName) != 0){
+ if (TypeManager.IsSpecialMethod (method))
+ Report.Error (571, loc, method.Name + ": can not call operator or accessor");
+ }
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ // <summary>
+ // Emits the list of arguments as an array
+ // </summary>
+ static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
+ {
+ ILGenerator ig = ec.ig;
+ int count = arguments.Count - idx;
+ Argument a = (Argument) arguments [idx];
+ Type t = a.Expr.Type;
+ string array_type = t.FullName + "[]";
+ LocalBuilder array;
+
+ array = ig.DeclareLocal (TypeManager.LookupType (array_type));
+ IntConstant.EmitInt (ig, count);
+ ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
+ ig.Emit (OpCodes.Stloc, array);
+
+ int top = arguments.Count;
+ for (int j = idx; j < top; j++){
+ a = (Argument) arguments [j];
+
+ ig.Emit (OpCodes.Ldloc, array);
+ IntConstant.EmitInt (ig, j - idx);
+
+ bool is_stobj;
+ OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
+ if (is_stobj)
+ ig.Emit (OpCodes.Ldelema, t);
+
+ a.Emit (ec);
+
+ if (is_stobj)
+ ig.Emit (OpCodes.Stobj, t);
+ else
+ ig.Emit (op);
+ }
+ ig.Emit (OpCodes.Ldloc, array);
+ }
+
+ /// <summary>
+ /// Emits a list of resolved Arguments that are in the arguments
+ /// ArrayList.
+ ///
+ /// The MethodBase argument might be null if the
+ /// emission of the arguments is known not to contain
+ /// a `params' field (for example in constructors or other routines
+ /// that keep their arguments in this structure)
+ /// </summary>
+ public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
+ {
+ ParameterData pd;
+ if (mb != null)
+ pd = GetParameterData (mb);
+ else
+ pd = null;
+
+ //
+ // If we are calling a params method with no arguments, special case it
+ //
+ if (arguments == null){
+ if (pd != null && pd.Count > 0 &&
+ pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
+ ILGenerator ig = ec.ig;
+
+ IntConstant.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
+ }
+
+ return;
+ }
+
+ int top = arguments.Count;
+
+ for (int i = 0; i < top; i++){
+ Argument a = (Argument) arguments [i];
+
+ if (pd != null){
+ if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
+ //
+ // Special case if we are passing the same data as the
+ // params argument, do not put it in an array.
+ //
+ if (pd.ParameterType (i) == a.Type)
+ a.Emit (ec);
+ else
+ EmitParams (ec, i, arguments);
+ return;
+ }
+ }
+
+ a.Emit (ec);
+ }
+
+ if (pd != null && pd.Count > top &&
+ pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
+ ILGenerator ig = ec.ig;
+
+ IntConstant.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
+ }
+ }
+
+ /// <remarks>
+ /// is_base tells whether we want to force the use of the `call'
+ /// opcode instead of using callvirt. Call is required to call
+ /// a specific method, while callvirt will always use the most
+ /// recent method in the vtable.
+ ///
+ /// is_static tells whether this is an invocation on a static method
+ ///
+ /// instance_expr is an expression that represents the instance
+ /// it must be non-null if is_static is false.
+ ///
+ /// method is the method to invoke.
+ ///
+ /// Arguments is the list of arguments to pass to the method or constructor.
+ /// </remarks>
+ public static void EmitCall (EmitContext ec, bool is_base,
+ bool is_static, Expression instance_expr,
+ MethodBase method, ArrayList Arguments, Location loc)
+ {
+ ILGenerator ig = ec.ig;
+ bool struct_call = false;
+
+ Type decl_type = method.DeclaringType;
+
+ if (!RootContext.StdLib) {
+ // Replace any calls to the system's System.Array type with calls to
+ // the newly created one.
+ if (method == TypeManager.system_int_array_get_length)
+ method = TypeManager.int_array_get_length;
+ else if (method == TypeManager.system_int_array_get_rank)
+ method = TypeManager.int_array_get_rank;
+ else if (method == TypeManager.system_object_array_clone)
+ method = TypeManager.object_array_clone;
+ else if (method == TypeManager.system_int_array_get_length_int)
+ method = TypeManager.int_array_get_length_int;
+ else if (method == TypeManager.system_int_array_get_lower_bound_int)
+ method = TypeManager.int_array_get_lower_bound_int;
+ else if (method == TypeManager.system_int_array_get_upper_bound_int)
+ method = TypeManager.int_array_get_upper_bound_int;
+ else if (method == TypeManager.system_void_array_copyto_array_int)
+ method = TypeManager.void_array_copyto_array_int;
+ }
+
+ //
+ // This checks the `ConditionalAttribute' on the method, and the
+ // ObsoleteAttribute
+ //
+ TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
+ if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
+ return;
+ if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
+ return;
+
+ if (!is_static){
+ if (decl_type.IsValueType)
+ struct_call = true;
+ //
+ // If this is ourselves, push "this"
+ //
+ if (instance_expr == null){
+ ig.Emit (OpCodes.Ldarg_0);
+ } else {
+ //
+ // Push the instance expression
+ //
+ if (instance_expr.Type.IsValueType){
+ //
+ // Special case: calls to a function declared in a
+ // reference-type with a value-type argument need
+ // to have their value boxed.
+
+ struct_call = true;
+ if (decl_type.IsValueType){
+ //
+ // If the expression implements IMemoryLocation, then
+ // we can optimize and use AddressOf on the
+ // return.
+ //
+ // If not we have to use some temporary storage for
+ // it.
+ if (instance_expr is IMemoryLocation){
+ ((IMemoryLocation)instance_expr).
+ AddressOf (ec, AddressOp.LoadStore);
+ }
+ else {
+ Type t = instance_expr.Type;
+
+ instance_expr.Emit (ec);
+ LocalBuilder temp = ig.DeclareLocal (t);
+ ig.Emit (OpCodes.Stloc, temp);
+ ig.Emit (OpCodes.Ldloca, temp);
+ }
+ } else {
+ instance_expr.Emit (ec);
+ ig.Emit (OpCodes.Box, instance_expr.Type);
+ }
+ } else
+ instance_expr.Emit (ec);
+ }
+ }
+
+ EmitArguments (ec, method, Arguments);
+
+ if (is_static || struct_call || is_base){
+ if (method is MethodInfo) {
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ } else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ } else {
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+
+ EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, 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);
+ }
+ }
+ }
+
+ public class InvocationOrCast : ExpressionStatement
+ {
+ Expression expr;
+ Expression argument;
+
+ public InvocationOrCast (Expression expr, Expression argument, Location loc)
+ {
+ this.expr = expr;
+ this.argument = argument;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // First try to resolve it as a cast.
+ //
+ type = ec.DeclSpace.ResolveType (expr, true, loc);
+ if (type != null) {
+ Cast cast = new Cast (new TypeExpr (type, loc), argument, loc);
+ return cast.Resolve (ec);
+ }
+
+ //
+ // This can either be a type or a delegate invocation.
+ // Let's just resolve it and see what we'll get.
+ //
+ expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+ if (expr == null)
+ return null;
+
+ //
+ // Ok, so it's a Cast.
+ //
+ if (expr.eclass == ExprClass.Type) {
+ Cast cast = new Cast (new TypeExpr (expr.Type, loc), argument, loc);
+ return cast.Resolve (ec);
+ }
+
+ //
+ // It's a delegate invocation.
+ //
+ if (!TypeManager.IsDelegateType (expr.Type)) {
+ Error (149, "Method name expected");
+ return null;
+ }
+
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument (argument, Argument.AType.Expression));
+ DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
+ return invocation.Resolve (ec);
+ }
+
+ void error201 ()
+ {
+ Error (201, "Only assignment, call, increment, decrement and new object " +
+ "expressions can be used as a statement");
+ }
+
+ public override ExpressionStatement ResolveStatement (EmitContext ec)
+ {
+ //
+ // First try to resolve it as a cast.
+ //
+ type = ec.DeclSpace.ResolveType (expr, true, loc);
+ if (type != null) {
+ error201 ();
+ return null;
+ }
+
+ //
+ // This can either be a type or a delegate invocation.
+ // Let's just resolve it and see what we'll get.
+ //
+ expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+ if ((expr == null) || (expr.eclass == ExprClass.Type)) {
+ error201 ();
+ return null;
+ }
+
+ //
+ // It's a delegate invocation.
+ //
+ if (!TypeManager.IsDelegateType (expr.Type)) {
+ Error (149, "Method name expected");
+ return null;
+ }
+
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument (argument, Argument.AType.Expression));
+ DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
+ return invocation.ResolveStatement (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Cannot happen");
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ throw new Exception ("Cannot happen");
+ }
+ }
+
+ //
+ // This class is used to "disable" the code generation for the
+ // temporary variable when initializing value types.
+ //
+ class EmptyAddressOf : EmptyExpression, IMemoryLocation {
+ public void AddressOf (EmitContext ec, AddressOp Mode)
+ {
+ // nothing
+ }
+ }
+
+ /// <summary>
+ /// Implements the new expression
+ /// </summary>
+ public class New : ExpressionStatement, IMemoryLocation {
+ public readonly ArrayList Arguments;
+ public readonly Expression RequestedType;
+
+ MethodBase method = null;
+
+ //
+ // If set, the new expression is for a value_target, and
+ // we will not leave anything on the stack.
+ //
+ Expression value_target;
+ bool value_target_set = false;
+
+ public New (Expression requested_type, ArrayList arguments, Location l)
+ {
+ RequestedType = requested_type;
+ Arguments = arguments;
+ loc = l;
+ }
+
+ public bool SetValueTypeVariable (Expression value)
+ {
+ value_target = value;
+ value_target_set = true;
+ if (!(value_target is IMemoryLocation)){
+ Error_UnexpectedKind ("variable");
+ return false;
+ }
+ return true;
+ }
+
+ //
+ // This function is used to disable the following code sequence for
+ // value type initialization:
+ //
+ // AddressOf (temporary)
+ // Construct/Init
+ // LoadTemporary
+ //
+ // Instead the provide will have provided us with the address on the
+ // stack to store the results.
+ //
+ static Expression MyEmptyExpression;
+
+ public void DisableTemporaryValueType ()
+ {
+ if (MyEmptyExpression == null)
+ MyEmptyExpression = new EmptyAddressOf ();
+
+ //
+ // To enable this, look into:
+ // test-34 and test-89 and self bootstrapping.
+ //
+ // For instance, we can avoid a copy by using `newobj'
+ // instead of Call + Push-temp on value types.
+// value_target = MyEmptyExpression;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // The New DoResolve might be called twice when initializing field
+ // expressions (see EmitFieldInitializers, the call to
+ // GetInitializerExpression will perform a resolve on the expression,
+ // and later the assign will trigger another resolution
+ //
+ // This leads to bugs (#37014)
+ //
+ if (type != null)
+ return this;
+
+ type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
+
+ if (type == null)
+ return null;
+
+ bool IsDelegate = TypeManager.IsDelegateType (type);
+
+ if (IsDelegate)
+ return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+
+ if (type.IsInterface || type.IsAbstract){
+ Error (144, "It is not possible to create instances of interfaces or abstract classes");
+ return null;
+ }
+
+ bool is_struct = type.IsValueType;
+ eclass = ExprClass.Value;
+
+ //
+ // SRE returns a match for .ctor () on structs (the object constructor),
+ // so we have to manually ignore it.
+ //
+ if (is_struct && Arguments == null)
+ return this;
+
+ Expression ml;
+ ml = MemberLookupFinal (ec, null, type, ".ctor",
+ MemberTypes.Constructor,
+ AllBindingFlags | BindingFlags.DeclaredOnly, loc);
+
+ if (ml == null)
+ return null;
+
+ if (! (ml is MethodGroupExpr)){
+ if (!is_struct){
+ ml.Error_UnexpectedKind ("method group");
+ return null;
+ }
+ }
+
+ if (ml != null) {
+ if (Arguments != null){
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);
+
+ }
+
+ if (method == null) {
+ if (!is_struct || Arguments.Count > 0) {
+ Error (1501, String.Format (
+ "New invocation: Can not find a constructor in `{0}' for this argument list",
+ TypeManager.CSharpName (type)));
+ return null;
+ }
+ }
+
+ return this;
+ }
+
+ //
+ // This DoEmit can be invoked in two contexts:
+ // * As a mechanism that will leave a value on the stack (new object)
+ // * As one that wont (init struct)
+ //
+ // You can control whether a value is required on the stack by passing
+ // need_value_on_stack. The code *might* leave a value on the stack
+ // so it must be popped manually
+ //
+ // If we are dealing with a ValueType, we have a few
+ // situations to deal with:
+ //
+ // * The target is a ValueType, and we have been provided
+ // the instance (this is easy, we are being assigned).
+ //
+ // * The target of New is being passed as an argument,
+ // to a boxing operation or a function that takes a
+ // ValueType.
+ //
+ // In this case, we need to create a temporary variable
+ // that is the argument of New.
+ //
+ // Returns whether a value is left on the stack
+ //
+ bool DoEmit (EmitContext ec, bool need_value_on_stack)
+ {
+ bool is_value_type = type.IsValueType;
+ ILGenerator ig = ec.ig;
+
+ if (is_value_type){
+ IMemoryLocation ml;
+
+ // Allow DoEmit() to be called multiple times.
+ // We need to create a new LocalTemporary each time since
+ // you can't share LocalBuilders among ILGeneators.
+ if (!value_target_set)
+ value_target = new LocalTemporary (ec, type);
+
+ ml = (IMemoryLocation) value_target;
+ ml.AddressOf (ec, AddressOp.Store);
+ }
+
+ if (method != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+
+ if (is_value_type){
+ if (method == null)
+ ig.Emit (OpCodes.Initobj, type);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ if (need_value_on_stack){
+ value_target.Emit (ec);
+ return true;
+ }
+ return false;
+ } else {
+ ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
+ return true;
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec, true);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ if (DoEmit (ec, false))
+ ec.ig.Emit (OpCodes.Pop);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp Mode)
+ {
+ if (!type.IsValueType){
+ //
+ // We throw an exception. So far, I believe we only need to support
+ // value types:
+ // foreach (int j in new StructType ())
+ // see bug 42390
+ //
+ throw new Exception ("AddressOf should not be used for classes");
+ }
+
+ if (!value_target_set)
+ value_target = new LocalTemporary (ec, type);
+
+ IMemoryLocation ml = (IMemoryLocation) value_target;
+ ml.AddressOf (ec, AddressOp.Store);
+ if (method != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+
+ if (method == null)
+ ec.ig.Emit (OpCodes.Initobj, type);
+ else
+ ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+ ((IMemoryLocation) value_target).AddressOf (ec, Mode);
+ }
+ }
+
+ /// <summary>
+ /// 14.5.10.2: Represents an array creation expression.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// There are two possible scenarios here: one is an array creation
+ /// expression that specifies the dimensions and optionally the
+ /// initialization data and the other which does not need dimensions
+ /// specified but where initialization data is mandatory.
+ /// </remarks>
+ public class ArrayCreation : ExpressionStatement {
+ Expression requested_base_type;
+ ArrayList initializers;
+
+ //
+ // The list of Argument types.
+ // This is used to construct the `newarray' or constructor signature
+ //
+ ArrayList arguments;
+
+ //
+ // Method used to create the array object.
+ //
+ MethodBase new_method = null;
+
+ Type array_element_type;
+ Type underlying_type;
+ bool is_one_dimensional = false;
+ bool is_builtin_type = false;
+ bool expect_initializers = false;
+ int num_arguments = 0;
+ int dimensions = 0;
+ string rank;
+
+ ArrayList array_data;
+
+ Hashtable bounds;
+
+ //
+ // The number of array initializers that we can handle
+ // via the InitializeArray method - through EmitStaticInitializers
+ //
+ int num_automatic_initializers;
+
+ const int max_automatic_initializers = 6;
+
+ public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
+ {
+ this.requested_base_type = requested_base_type;
+ this.initializers = initializers;
+ this.rank = rank;
+ loc = l;
+
+ arguments = new ArrayList ();
+
+ foreach (Expression e in exprs) {
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+ num_arguments++;
+ }
+ }
+
+ public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
+ {
+ this.requested_base_type = requested_base_type;
+ this.initializers = initializers;
+ this.rank = rank;
+ loc = l;
+
+ //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
+ //
+ //string tmp = rank.Substring (rank.LastIndexOf ("["));
+ //
+ //dimensions = tmp.Length - 1;
+ expect_initializers = true;
+ }
+
+ public Expression FormArrayType (Expression base_type, int idx_count, string rank)
+ {
+ StringBuilder sb = new StringBuilder (rank);
+
+ sb.Append ("[");
+ for (int i = 1; i < idx_count; i++)
+ sb.Append (",");
+
+ sb.Append ("]");
+
+ return new ComposedCast (base_type, sb.ToString (), loc);
+ }
+
+ void Error_IncorrectArrayInitializer ()
+ {
+ Error (178, "Incorrectly structured array initializer");
+ }
+
+ public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
+ {
+ if (specified_dims) {
+ Argument a = (Argument) arguments [idx];
+
+ if (!a.Resolve (ec, loc))
+ return false;
+
+ if (!(a.Expr is Constant)) {
+ Error (150, "A constant value is expected");
+ return false;
+ }
+
+ int value = (int) ((Constant) a.Expr).GetValue ();
+
+ if (value != probe.Count) {
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+
+ bounds [idx] = value;
+ }
+
+ int child_bounds = -1;
+ foreach (object o in probe) {
+ if (o is ArrayList) {
+ int current_bounds = ((ArrayList) o).Count;
+
+ if (child_bounds == -1)
+ child_bounds = current_bounds;
+
+ else if (child_bounds != current_bounds){
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+ if (specified_dims && (idx + 1 >= arguments.Count)){
+ Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
+ return false;
+ }
+
+ bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
+ if (!ret)
+ return false;
+ } else {
+ if (child_bounds != -1){
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+
+ Expression tmp = (Expression) o;
+ tmp = tmp.Resolve (ec);
+ if (tmp == null)
+ continue;
+
+ // Console.WriteLine ("I got: " + tmp);
+ // Handle initialization from vars, fields etc.
+
+ Expression conv = Convert.ImplicitConversionRequired (
+ ec, tmp, underlying_type, loc);
+
+ if (conv == null)
+ return false;
+
+ if (conv is StringConstant)
+ array_data.Add (conv);
+ else if (conv is Constant) {
+ array_data.Add (conv);
+ num_automatic_initializers++;
+ } else
+ array_data.Add (conv);
+ }
+ }
+
+ return true;
+ }
+
+ public void UpdateIndices (EmitContext ec)
+ {
+ int i = 0;
+ for (ArrayList probe = initializers; probe != null;) {
+ if (probe.Count > 0 && probe [0] is ArrayList) {
+ Expression e = new IntConstant (probe.Count);
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+
+ bounds [i++] = probe.Count;
+
+ probe = (ArrayList) probe [0];
+
+ } else {
+ Expression e = new IntConstant (probe.Count);
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+
+ bounds [i++] = probe.Count;
+ probe = null;
+ }
+ }
+
+ }
+
+ public bool ValidateInitializers (EmitContext ec, Type array_type)
+ {
+ if (initializers == null) {
+ if (expect_initializers)
+ return false;
+ else
+ return true;
+ }
+
+ if (underlying_type == null)
+ return false;
+
+ //
+ // We use this to store all the date values in the order in which we
+ // will need to store them in the byte blob later
+ //
+ array_data = new ArrayList ();
+ bounds = new Hashtable ();
+
+ bool ret;
+
+ if (arguments != null) {
+ ret = CheckIndices (ec, initializers, 0, true);
+ return ret;
+ } else {
+ arguments = new ArrayList ();
+
+ ret = CheckIndices (ec, initializers, 0, false);
+
+ if (!ret)
+ return false;
+
+ UpdateIndices (ec);
+
+ if (arguments.Count != dimensions) {
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+
+ return ret;
+ }
+ }
+
+ void Error_NegativeArrayIndex ()
+ {
+ Error (284, "Can not create array with a negative size");
+ }
+
+ //
+ // Converts `source' to an int, uint, long or ulong.
+ //
+ Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
+ {
+ Expression target;
+
+ bool old_checked = ec.CheckState;
+ ec.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)
+ Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
+ }
+ }
+ }
+ ec.CheckState = old_checked;
+
+ //
+ // Only positive constants are allowed at compile time
+ //
+ if (target is Constant){
+ if (target is IntConstant){
+ if (((IntConstant) target).Value < 0){
+ Error_NegativeArrayIndex ();
+ return null;
+ }
+ }
+
+ if (target is LongConstant){
+ if (((LongConstant) target).Value < 0){
+ Error_NegativeArrayIndex ();
+ return null;
+ }
+ }
+
+ }
+
+ return target;
+ }
+
+ //
+ // Creates the type of the array
+ //
+ bool LookupType (EmitContext ec)
+ {
+ StringBuilder array_qualifier = new StringBuilder (rank);
+
+ //
+ // `In the first form allocates an array instace of the type that results
+ // from deleting each of the individual expression from the expression list'
+ //
+ if (num_arguments > 0) {
+ array_qualifier.Append ("[");
+ for (int i = num_arguments-1; i > 0; i--)
+ array_qualifier.Append (",");
+ array_qualifier.Append ("]");
+ }
+
+ //
+ // Lookup the type
+ //
+ Expression array_type_expr;
+ array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
+ type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
+
+ if (type == null)
+ return false;
+
+ underlying_type = type;
+ if (underlying_type.IsArray)
+ underlying_type = TypeManager.GetElementType (underlying_type);
+ dimensions = type.GetArrayRank ();
+
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ int arg_count;
+
+ if (!LookupType (ec))
+ return null;
+
+ //
+ // First step is to validate the initializers and fill
+ // in any missing bits
+ //
+ if (!ValidateInitializers (ec, type))
+ return null;
+
+ if (arguments == null)
+ arg_count = 0;
+ else {
+ arg_count = arguments.Count;
+ foreach (Argument a in arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+
+ Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
+ if (real_arg == null)
+ return null;
+
+ a.Expr = real_arg;
+ }
+ }
+
+ array_element_type = TypeManager.GetElementType (type);
+
+ if (arg_count == 1) {
+ is_one_dimensional = true;
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ is_builtin_type = TypeManager.IsBuiltinType (type);
+
+ if (is_builtin_type) {
+ Expression ml;
+
+ ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
+ AllBindingFlags, loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ ml.Error_UnexpectedKind ("method group");
+ return null;
+ }
+
+ if (ml == null) {
+ Error (-6, "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
+
+ if (new_method == null) {
+ Error (-6, "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ eclass = ExprClass.Value;
+ return this;
+ } else {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ArrayList args = new ArrayList ();
+
+ if (arguments != null) {
+ for (int i = 0; i < arg_count; i++)
+ args.Add (TypeManager.int32_type);
+ }
+
+ Type [] arg_types = null;
+
+ if (args.Count > 0)
+ arg_types = new Type [args.Count];
+
+ args.CopyTo (arg_types, 0);
+
+ new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
+ arg_types);
+
+ if (new_method == null) {
+ Error (-6, "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+ }
+
+ public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
+ {
+ int factor;
+ byte [] data;
+ byte [] element;
+ int count = array_data.Count;
+
+ if (underlying_type.IsEnum)
+ underlying_type = TypeManager.EnumToUnderlying (underlying_type);
+
+ factor = GetTypeSize (underlying_type);
+ if (factor == 0)
+ throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
+
+ data = new byte [(count * factor + 4) & ~3];
+ int idx = 0;
+
+ for (int i = 0; i < count; ++i) {
+ object v = array_data [i];
+
+ if (v is EnumConstant)
+ v = ((EnumConstant) v).Child;
+
+ if (v is Constant && !(v is StringConstant))
+ v = ((Constant) v).GetValue ();
+ else {
+ idx += factor;
+ continue;
+ }
+
+ if (underlying_type == TypeManager.int64_type){
+ if (!(v is Expression)){
+ long val = (long) v;
+
+ for (int j = 0; j < factor; ++j) {
+ data [idx + j] = (byte) (val & 0xFF);
+ val = (val >> 8);
+ }
+ }
+ } else if (underlying_type == TypeManager.uint64_type){
+ if (!(v is Expression)){
+ ulong val = (ulong) v;
+
+ for (int j = 0; j < factor; ++j) {
+ data [idx + j] = (byte) (val & 0xFF);
+ val = (val >> 8);
+ }
+ }
+ } else if (underlying_type == TypeManager.float_type) {
+ if (!(v is Expression)){
+ element = BitConverter.GetBytes ((float) v);
+
+ for (int j = 0; j < factor; ++j)
+ data [idx + j] = element [j];
+ }
+ } else if (underlying_type == TypeManager.double_type) {
+ if (!(v is Expression)){
+ element = BitConverter.GetBytes ((double) v);
+
+ for (int j = 0; j < factor; ++j)
+ data [idx + j] = element [j];
+ }
+ } else if (underlying_type == TypeManager.char_type){
+ if (!(v is Expression)){
+ int val = (int) ((char) v);
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) (val >> 8);
+ }
+ } else if (underlying_type == TypeManager.short_type){
+ if (!(v is Expression)){
+ int val = (int) ((short) v);
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) (val >> 8);
+ }
+ } else if (underlying_type == TypeManager.ushort_type){
+ if (!(v is Expression)){
+ int val = (int) ((ushort) v);
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) (val >> 8);
+ }
+ } else if (underlying_type == TypeManager.int32_type) {
+ if (!(v is Expression)){
+ int val = (int) v;
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) ((val >> 8) & 0xff);
+ data [idx+2] = (byte) ((val >> 16) & 0xff);
+ data [idx+3] = (byte) (val >> 24);
+ }
+ } else if (underlying_type == TypeManager.uint32_type) {
+ if (!(v is Expression)){
+ uint val = (uint) v;
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) ((val >> 8) & 0xff);
+ data [idx+2] = (byte) ((val >> 16) & 0xff);
+ data [idx+3] = (byte) (val >> 24);
+ }
+ } else if (underlying_type == TypeManager.sbyte_type) {
+ if (!(v is Expression)){
+ sbyte val = (sbyte) v;
+ data [idx] = (byte) val;
+ }
+ } else if (underlying_type == TypeManager.byte_type) {
+ if (!(v is Expression)){
+ byte val = (byte) v;
+ data [idx] = (byte) val;
+ }
+ } else if (underlying_type == TypeManager.bool_type) {
+ if (!(v is Expression)){
+ bool val = (bool) v;
+ data [idx] = (byte) (val ? 1 : 0);
+ }
+ } else if (underlying_type == TypeManager.decimal_type){
+ if (!(v is Expression)){
+ int [] bits = Decimal.GetBits ((decimal) v);
+ int p = idx;
+
+ // FIXME: For some reason, this doesn't work on the MS runtime.
+ int [] nbits = new int [4];
+ nbits [0] = bits [3];
+ nbits [1] = bits [2];
+ nbits [2] = bits [0];
+ nbits [3] = bits [1];
+
+ for (int j = 0; j < 4; j++){
+ data [p++] = (byte) (nbits [j] & 0xff);
+ data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
+ data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
+ data [p++] = (byte) (nbits [j] >> 24);
+ }
+ }
+ } else
+ throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
+
+ idx += factor;
+ }
+
+ return data;
+ }
+
+ //
+ // Emits the initializers for the array
+ //
+ void EmitStaticInitializers (EmitContext ec, bool is_expression)
+ {
+ //
+ // First, the static data
+ //
+ FieldBuilder fb;
+ ILGenerator ig = ec.ig;
+
+ byte [] data = MakeByteBlob (array_data, underlying_type, loc);
+
+ fb = RootContext.MakeStaticData (data);
+
+ if (is_expression)
+ ig.Emit (OpCodes.Dup);
+ ig.Emit (OpCodes.Ldtoken, fb);
+ ig.Emit (OpCodes.Call,
+ TypeManager.void_initializearray_array_fieldhandle);
+ }
+
+ //
+ // Emits pieces of the array that can not be computed at compile
+ // time (variables and string locations).
+ //
+ // This always expect the top value on the stack to be the array
+ //
+ void EmitDynamicInitializers (EmitContext ec, bool is_expression)
+ {
+ ILGenerator ig = ec.ig;
+ int dims = bounds.Count;
+ int [] current_pos = new int [dims];
+ int top = array_data.Count;
+ LocalBuilder temp = ig.DeclareLocal (type);
+
+ ig.Emit (OpCodes.Stloc, temp);
+
+ MethodInfo set = null;
+
+ if (dims != 1){
+ Type [] args;
+ ModuleBuilder mb = null;
+ mb = CodeGen.ModuleBuilder;
+ args = new Type [dims + 1];
+
+ int j;
+ for (j = 0; j < dims; j++)
+ args [j] = TypeManager.int32_type;
+
+ args [j] = array_element_type;
+
+ set = mb.GetArrayMethod (
+ type, "Set",
+ CallingConventions.HasThis | CallingConventions.Standard,
+ TypeManager.void_type, args);
+ }
+
+ for (int i = 0; i < top; i++){
+
+ Expression e = null;
+
+ if (array_data [i] is Expression)
+ e = (Expression) array_data [i];
+
+ if (e != null) {
+ //
+ // Basically we do this for string literals and
+ // other non-literal expressions
+ //
+ if (e is EnumConstant){
+ e = ((EnumConstant) e).Child;
+ }
+
+ if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
+ num_automatic_initializers <= max_automatic_initializers) {
+ Type etype = e.Type;
+
+ ig.Emit (OpCodes.Ldloc, temp);
+
+ for (int idx = 0; idx < dims; idx++)
+ IntConstant.EmitInt (ig, current_pos [idx]);
+
+ //
+ // If we are dealing with a struct, get the
+ // address of it, so we can store it.
+ //
+ if ((dims == 1) &&
+ etype.IsSubclassOf (TypeManager.value_type) &&
+ (!TypeManager.IsBuiltinType (etype) ||
+ etype == TypeManager.decimal_type)) {
+ if (e is New){
+ New n = (New) e;
+
+ //
+ // Let new know that we are providing
+ // the address where to store the results
+ //
+ n.DisableTemporaryValueType ();
+ }
+
+ ig.Emit (OpCodes.Ldelema, etype);
+ }
+
+ e.Emit (ec);
+
+ if (dims == 1)
+ ArrayAccess.EmitStoreOpcode (ig, array_element_type);
+ else
+ ig.Emit (OpCodes.Call, set);
+
+ }
+ }
+
+ //
+ // Advance counter
+ //
+ for (int j = dims - 1; j >= 0; j--){
+ current_pos [j]++;
+ if (current_pos [j] < (int) bounds [j])
+ break;
+ current_pos [j] = 0;
+ }
+ }
+
+ if (is_expression)
+ ig.Emit (OpCodes.Ldloc, temp);
+ }
+
+ void EmitArrayArguments (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ foreach (Argument a in arguments) {
+ Type atype = a.Type;
+ a.Emit (ec);
+
+ if (atype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_Ovf_U4);
+ else if (atype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I4);
+ }
+ }
+
+ void DoEmit (EmitContext ec, bool is_statement)
+ {
+ ILGenerator ig = ec.ig;
+
+ EmitArrayArguments (ec);
+ if (is_one_dimensional)
+ ig.Emit (OpCodes.Newarr, array_element_type);
+ else {
+ if (is_builtin_type)
+ ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
+ else
+ ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
+ }
+
+ if (initializers != null){
+ //
+ // FIXME: Set this variable correctly.
+ //
+ bool dynamic_initializers = true;
+
+ if (underlying_type != TypeManager.string_type &&
+ underlying_type != TypeManager.decimal_type &&
+ underlying_type != TypeManager.object_type) {
+ if (num_automatic_initializers > max_automatic_initializers)
+ EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
+ }
+
+ if (dynamic_initializers)
+ EmitDynamicInitializers (ec, !is_statement);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec, false);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ DoEmit (ec, true);
+ }
+
+ public object EncodeAsAttribute ()
+ {
+ if (!is_one_dimensional){
+ Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
+ return null;
+ }
+
+ if (array_data == null){
+ Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
+ return null;
+ }
+
+ object [] ret = new object [array_data.Count];
+ int i = 0;
+ foreach (Expression e in array_data){
+ object v;
+
+ if (e is NullLiteral)
+ v = null;
+ else {
+ if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
+ return null;
+ }
+ ret [i++] = v;
+ }
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Represents the `this' construct
+ /// </summary>
+ public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
+
+ Block block;
+ VariableInfo variable_info;
+
+ public This (Block block, Location loc)
+ {
+ this.loc = loc;
+ this.block = block;
+ }
+
+ public This (Location loc)
+ {
+ this.loc = loc;
+ }
+
+ public VariableInfo VariableInfo {
+ get { return variable_info; }
+ }
+
+ public bool VerifyFixed (bool is_expression)
+ {
+ return variable_info.LocalInfo.IsFixed;
+ }
+
+ public bool ResolveBase (EmitContext ec)
+ {
+ eclass = ExprClass.Variable;
+ type = ec.ContainerType;
+
+ if (ec.IsStatic) {
+ Error (26, "Keyword this not valid in static code");
+ return false;
+ }
+
+ if ((block != null) && (block.ThisVariable != null))
+ variable_info = block.GetVariableInfo (block.ThisVariable);
+
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!ResolveBase (ec))
+ return null;
+
+ if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
+ Error (188, "The this object cannot be used before all " +
+ "of its fields are assigned to");
+ variable_info.SetAssigned (ec);
+ return this;
+ }
+
+ if (ec.IsFieldInitializer) {
+ Error (27, "Keyword `this' can't be used outside a constructor, " +
+ "a method or a property.");
+ return null;
+ }
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (!ResolveBase (ec))
+ return null;
+
+ if (variable_info != null)
+ variable_info.SetAssigned (ec);
+
+ if (ec.TypeContainer is Class){
+ Error (1604, "Cannot assign to `this'");
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldarg_0);
+ if (ec.TypeContainer is Struct)
+ ig.Emit (OpCodes.Ldobj, type);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (ec.TypeContainer is Struct){
+ ig.Emit (OpCodes.Ldarg_0);
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stobj, type);
+ } else {
+ source.Emit (ec);
+ ig.Emit (OpCodes.Starg, 0);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+
+ // FIMXE
+ // FIGURE OUT WHY LDARG_S does not work
+ //
+ // consider: struct X { int val; int P { set { val = value; }}}
+ //
+ // Yes, this looks very bad. Look at `NOTAS' for
+ // an explanation.
+ // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
+ }
+ }
+
+ /// <summary>
+ /// Implements the typeof operator
+ /// </summary>
+ public class TypeOf : Expression {
+ public readonly Expression QueriedType;
+ Type typearg;
+
+ public TypeOf (Expression queried_type, Location l)
+ {
+ QueriedType = queried_type;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
+
+ if (typearg == null)
+ return null;
+
+ if (typearg == TypeManager.void_type) {
+ Error (673, "System.Void cannot be used from C# - " +
+ "use typeof (void) to get the void type object");
+ return null;
+ }
+
+ type = TypeManager.type_type;
+ eclass = ExprClass.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, typearg);
+ ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
+ }
+
+ public Type TypeArg {
+ get { return typearg; }
+ }
+ }
+
+ /// <summary>
+ /// Implements the `typeof (void)' operator
+ /// </summary>
+ public class TypeOfVoid : Expression {
+ public TypeOfVoid (Location l)
+ {
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.type_type;
+ eclass = ExprClass.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, TypeManager.void_type);
+ ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
+ }
+
+ public Type TypeArg {
+ get { return TypeManager.void_type; }
+ }
+ }
+
+ /// <summary>
+ /// Implements the sizeof expression
+ /// </summary>
+ public class SizeOf : Expression {
+ public readonly Expression QueriedType;
+ Type type_queried;
+
+ public SizeOf (Expression queried_type, Location l)
+ {
+ this.QueriedType = queried_type;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!ec.InUnsafe) {
+ Report.Error (
+ 233, loc, "Sizeof may only be used in an unsafe context " +
+ "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
+ return null;
+ }
+
+ type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
+ if (type_queried == null)
+ return null;
+
+ if (!TypeManager.IsUnmanagedType (type_queried)){
+ Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
+ return null;
+ }
+
+ type = TypeManager.int32_type;
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int size = GetTypeSize (type_queried);
+
+ if (size == 0)
+ ec.ig.Emit (OpCodes.Sizeof, type_queried);
+ else
+ IntConstant.EmitInt (ec.ig, size);
+ }
+ }
+
+ /// <summary>
+ /// Implements the member access expression
+ /// </summary>
+ public class MemberAccess : Expression {
+ public readonly string Identifier;
+ Expression expr;
+
+ public MemberAccess (Expression expr, string id, Location l)
+ {
+ this.expr = expr;
+ Identifier = id;
+ loc = l;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ static void error176 (Location loc, string name)
+ {
+ Report.Error (176, loc, "Static member `" +
+ name + "' cannot be accessed " +
+ "with an instance reference, qualify with a " +
+ "type name instead");
+ }
+
+ static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
+ {
+ if (left_original == null)
+ return false;
+
+ if (!(left_original is SimpleName))
+ return false;
+
+ SimpleName sn = (SimpleName) left_original;
+
+ Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
+ if (t != null)
+ return true;
+
+ return false;
+ }
+
+ public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
+ Expression left, Location loc,
+ Expression left_original)
+ {
+ bool left_is_type, left_is_explicit;
+
+ // If `left' is null, then we're called from SimpleNameResolve and this is
+ // a member in the currently defining class.
+ if (left == null) {
+ left_is_type = ec.IsStatic || ec.IsFieldInitializer;
+ left_is_explicit = false;
+
+ // Implicitly default to `this' unless we're static.
+ if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
+ left = ec.GetThis (loc);
+ } else {
+ left_is_type = left is TypeExpr;
+ left_is_explicit = true;
+ }
+
+ if (member_lookup is FieldExpr){
+ FieldExpr fe = (FieldExpr) member_lookup;
+ FieldInfo fi = fe.FieldInfo;
+ Type decl_type = fi.DeclaringType;
+
+ if (fi is FieldBuilder) {
+ Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
+
+ if (c != null) {
+ object o = c.LookupConstantValue ();
+ if (o == null)
+ return null;
+
+ object real_value = ((Constant) c.Expr).GetValue ();
+
+ return Constantify (real_value, fi.FieldType);
+ }
+ }
+
+ if (fi.IsLiteral) {
+ Type t = fi.FieldType;
+
+ object o;
+
+ if (fi is FieldBuilder)
+ o = TypeManager.GetValue ((FieldBuilder) fi);
+ else
+ o = fi.GetValue (fi);
+
+ if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
+ if (left_is_explicit && !left_is_type &&
+ !IdenticalNameAndTypeName (ec, left_original, loc)) {
+ error176 (loc, fe.FieldInfo.Name);
+ return null;
+ }
+
+ Expression enum_member = MemberLookup (
+ ec, decl_type, "value__", MemberTypes.Field,
+ AllBindingFlags, loc);
+
+ Enum en = TypeManager.LookupEnum (decl_type);
+
+ Constant c;
+ if (en != null)
+ c = Constantify (o, en.UnderlyingType);
+ else
+ c = Constantify (o, enum_member.Type);
+
+ return new EnumConstant (c, decl_type);
+ }
+
+ Expression exp = Constantify (o, t);
+
+ if (left_is_explicit && !left_is_type) {
+ error176 (loc, fe.FieldInfo.Name);
+ return null;
+ }
+
+ return exp;
+ }
+
+ if (fi.FieldType.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+ }
+
+ if (member_lookup is EventExpr) {
+ EventExpr ee = (EventExpr) member_lookup;
+
+ //
+ // If the event is local to this class, we transform ourselves into
+ // a FieldExpr
+ //
+
+ if (ee.EventInfo.DeclaringType == ec.ContainerType) {
+ MemberInfo mi = GetFieldFromEvent (ee);
+
+ if (mi == null) {
+ //
+ // If this happens, then we have an event with its own
+ // accessors and private field etc so there's no need
+ // to transform ourselves.
+ //
+ return ee;
+ }
+
+ Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
+
+ if (ml == null) {
+ Report.Error (-200, loc, "Internal error!!");
+ return null;
+ }
+
+ if (!left_is_explicit)
+ left = null;
+
+ return ResolveMemberAccess (ec, ml, left, loc, left_original);
+ }
+ }
+
+ if (member_lookup is IMemberExpr) {
+ IMemberExpr me = (IMemberExpr) member_lookup;
+
+ if (left_is_type){
+ MethodGroupExpr mg = me as MethodGroupExpr;
+ if ((mg != null) && left_is_explicit && left.Type.IsInterface)
+ mg.IsExplicitImpl = left_is_explicit;
+
+ if (!me.IsStatic){
+ if ((ec.IsFieldInitializer || ec.IsStatic) &&
+ IdenticalNameAndTypeName (ec, left_original, loc))
+ return member_lookup;
+
+ SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
+ return null;
+ }
+
+ } else {
+ if (!me.IsInstance){
+ if (IdenticalNameAndTypeName (ec, left_original, loc))
+ return member_lookup;
+
+ if (left_is_explicit) {
+ error176 (loc, me.Name);
+ return null;
+ }
+ }
+
+ //
+ // Since we can not check for instance objects in SimpleName,
+ // becaue of the rule that allows types and variables to share
+ // the name (as long as they can be de-ambiguated later, see
+ // IdenticalNameAndTypeName), we have to check whether left
+ // is an instance variable in a static context
+ //
+ // However, if the left-hand value is explicitly given, then
+ // it is already our instance expression, so we aren't in
+ // static context.
+ //
+
+ if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
+ IMemberExpr mexp = (IMemberExpr) left;
+
+ if (!mexp.IsStatic){
+ SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
+ return null;
+ }
+ }
+
+ me.InstanceExpression = left;
+ }
+
+ return member_lookup;
+ }
+
+ Console.WriteLine ("Left is: " + left);
+ Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
+ Environment.Exit (0);
+ return null;
+ }
+
+ public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
+ {
+ if (type != null)
+ throw new Exception ();
+
+ //
+ // Resolve the expression with flow analysis turned off, we'll do the definite
+ // assignment checks later. This is because we don't know yet what the expression
+ // will resolve to - it may resolve to a FieldExpr and in this case we must do the
+ // definite assignment check on the actual field and not on the whole struct.
+ //
+
+ Expression original = expr;
+ expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
+ if (expr == null)
+ return null;
+
+ if (expr is SimpleName){
+ SimpleName child_expr = (SimpleName) expr;
+
+ Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
+
+ return new_expr.Resolve (ec, flags);
+ }
+
+ //
+ // TODO: I mailed Ravi about this, and apparently we can get rid
+ // of this and put it in the right place.
+ //
+ // Handle enums here when they are in transit.
+ // Note that we cannot afford to hit MemberLookup in this case because
+ // it will fail to find any members at all
+ //
+
+ int errors = Report.Errors;
+
+ Type expr_type = expr.Type;
+ if (expr is TypeExpr){
+ if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
+ Error (122, "`" + expr_type + "' " +
+ "is inaccessible because of its protection level");
+ return null;
+ }
+
+ if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
+ Enum en = TypeManager.LookupEnum (expr_type);
+
+ if (en != null) {
+ object value = en.LookupEnumValue (ec, Identifier, loc);
+
+ if (value != null){
+ Constant c = Constantify (value, en.UnderlyingType);
+ return new EnumConstant (c, expr_type);
+ }
+ }
+ }
+ }
+
+ if (expr_type.IsPointer){
+ Error (23, "The `.' operator can not be applied to pointer operands (" +
+ TypeManager.CSharpName (expr_type) + ")");
+ return null;
+ }
+
+ Expression member_lookup;
+ member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
+ if (member_lookup == null)
+ return null;
+
+ if (member_lookup is TypeExpr) {
+ if (!(expr is TypeExpr) && !(expr is SimpleName)) {
+ Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
+ member_lookup.Type + "' instead");
+ return null;
+ }
+
+ return member_lookup;
+ }
+
+ member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
+ if (member_lookup == null)
+ return null;
+
+ // The following DoResolve/DoResolveLValue will do the definite assignment
+ // check.
+
+ if (right_side != null)
+ member_lookup = member_lookup.DoResolveLValue (ec, right_side);
+ else
+ member_lookup = member_lookup.DoResolve (ec);
+
+ return member_lookup;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return DoResolve (ec, null, ResolveFlags.VariableOrValue |
+ ResolveFlags.SimpleName | ResolveFlags.Type);
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
+ ResolveFlags.SimpleName | ResolveFlags.Type);
+ }
+
+ public override Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ string fname = null;
+ MemberAccess full_expr = this;
+ while (full_expr != null) {
+ if (fname != null)
+ fname = String.Concat (full_expr.Identifier, ".", fname);
+ else
+ fname = full_expr.Identifier;
+
+ if (full_expr.Expr is SimpleName) {
+ string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
+ Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
+ if (fully_qualified != null)
+ return new TypeExpr (fully_qualified, loc);
+ }
+
+ full_expr = full_expr.Expr as MemberAccess;
+ }
+
+ Expression new_expr = expr.ResolveAsTypeStep (ec);
+
+ if (new_expr == null)
+ return null;
+
+ if (new_expr is SimpleName){
+ SimpleName child_expr = (SimpleName) new_expr;
+
+ new_expr = new SimpleName (child_expr.Name, Identifier, loc);
+
+ return new_expr.ResolveAsTypeStep (ec);
+ }
+
+ Type expr_type = new_expr.Type;
+
+ if (expr_type.IsPointer){
+ Error (23, "The `.' operator can not be applied to pointer operands (" +
+ TypeManager.CSharpName (expr_type) + ")");
+ return null;
+ }
+
+ Expression member_lookup;
+ member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
+ if (member_lookup == null)
+ return null;
+
+ if (member_lookup is TypeExpr){
+ member_lookup.Resolve (ec, ResolveFlags.Type);
+ return member_lookup;
+ }
+
+ return null;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should not happen");
+ }
+
+ public override string ToString ()
+ {
+ return expr + "." + Identifier;
+ }
+ }
+
+ /// <summary>
+ /// Implements checked expressions
+ /// </summary>
+ public class CheckedExpr : Expression {
+
+ public Expression Expr;
+
+ public CheckedExpr (Expression e, Location l)
+ {
+ Expr = e;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ bool last_check = ec.CheckState;
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.CheckState = true;
+ ec.ConstantCheckState = true;
+ Expr = Expr.Resolve (ec);
+ ec.CheckState = last_check;
+ ec.ConstantCheckState = last_const_check;
+
+ if (Expr == null)
+ return null;
+
+ if (Expr is Constant)
+ return Expr;
+
+ eclass = Expr.eclass;
+ type = Expr.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ bool last_check = ec.CheckState;
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.CheckState = true;
+ ec.ConstantCheckState = true;
+ Expr.Emit (ec);
+ ec.CheckState = last_check;
+ ec.ConstantCheckState = last_const_check;
+ }
+
+ }
+
+ /// <summary>
+ /// Implements the unchecked expression
+ /// </summary>
+ public class UnCheckedExpr : Expression {
+
+ public Expression Expr;
+
+ public UnCheckedExpr (Expression e, Location l)
+ {
+ Expr = e;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ bool last_check = ec.CheckState;
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.CheckState = false;
+ ec.ConstantCheckState = false;
+ Expr = Expr.Resolve (ec);
+ ec.CheckState = last_check;
+ ec.ConstantCheckState = last_const_check;
+
+ if (Expr == null)
+ return null;
+
+ if (Expr is Constant)
+ return Expr;
+
+ eclass = Expr.eclass;
+ type = Expr.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ bool last_check = ec.CheckState;
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.CheckState = false;
+ ec.ConstantCheckState = false;
+ Expr.Emit (ec);
+ ec.CheckState = last_check;
+ ec.ConstantCheckState = last_const_check;
+ }
+
+ }
+
+ /// <summary>
+ /// An Element Access expression.
+ ///
+ /// During semantic analysis these are transformed into
+ /// IndexerAccess, ArrayAccess or a PointerArithmetic.
+ /// </summary>
+ public class ElementAccess : Expression {
+ public ArrayList Arguments;
+ public Expression Expr;
+
+ public ElementAccess (Expression e, ArrayList e_list, Location l)
+ {
+ Expr = e;
+
+ loc = l;
+
+ if (e_list == null)
+ return;
+
+ Arguments = new ArrayList ();
+ foreach (Expression tmp in e_list)
+ Arguments.Add (new Argument (tmp, Argument.AType.Expression));
+
+ }
+
+ bool CommonResolve (EmitContext ec)
+ {
+ Expr = Expr.Resolve (ec);
+
+ if (Expr == null)
+ return false;
+
+ if (Arguments == null)
+ return false;
+
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return false;
+ }
+
+ return true;
+ }
+
+ Expression MakePointerAccess ()
+ {
+ Type t = Expr.Type;
+
+ if (t == TypeManager.void_ptr_type){
+ Error (242, "The array index operation is not valid for void pointers");
+ return null;
+ }
+ if (Arguments.Count != 1){
+ Error (196, "A pointer must be indexed by a single value");
+ return null;
+ }
+ Expression p;
+
+ p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
+ return new Indirection (p, loc);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ //
+ // We perform some simple tests, and then to "split" the emit and store
+ // code we create an instance of a different class, and return that.
+ //
+ // I am experimenting with this pattern.
+ //
+ Type t = Expr.Type;
+
+ if (t == TypeManager.array_type){
+ Report.Error (21, loc, "Cannot use indexer on System.Array");
+ return null;
+ }
+
+ if (t.IsArray)
+ return (new ArrayAccess (this, loc)).Resolve (ec);
+ else if (t.IsPointer)
+ return MakePointerAccess ();
+ else
+ return (new IndexerAccess (this, loc)).Resolve (ec);
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ Type t = Expr.Type;
+ if (t.IsArray)
+ return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
+ else if (t.IsPointer)
+ return MakePointerAccess ();
+ else
+ return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be reached");
+ }
+ }
+
+ /// <summary>
+ /// Implements array access
+ /// </summary>
+ public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
+ //
+ // Points to our "data" repository
+ //
+ ElementAccess ea;
+
+ LocalTemporary [] cached_locations;
+
+ public ArrayAccess (ElementAccess ea_data, Location l)
+ {
+ ea = ea_data;
+ eclass = ExprClass.Variable;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ ExprClass eclass = ea.Expr.eclass;
+
+#if false
+ // As long as the type is valid
+ if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
+ eclass == ExprClass.Value)) {
+ ea.Expr.Error_UnexpectedKind ("variable or value");
+ return null;
+ }
+#endif
+
+ Type t = ea.Expr.Type;
+ if (t.GetArrayRank () != ea.Arguments.Count){
+ ea.Error (22,
+ "Incorrect number of indexes for array " +
+ " expected: " + t.GetArrayRank () + " got: " +
+ ea.Arguments.Count);
+ return null;
+ }
+
+ type = TypeManager.GetElementType (t);
+ if (type.IsPointer && !ec.InUnsafe){
+ UnsafeError (ea.Location);
+ return null;
+ }
+
+ foreach (Argument a in ea.Arguments){
+ Type argtype = a.Type;
+
+ if (argtype == TypeManager.int32_type ||
+ argtype == TypeManager.uint32_type ||
+ argtype == TypeManager.int64_type ||
+ argtype == TypeManager.uint64_type)
+ continue;
+
+ //
+ // Mhm. This is strage, because the Argument.Type is not the same as
+ // Argument.Expr.Type: the value changes depending on the ref/out setting.
+ //
+ // Wonder if I will run into trouble for this.
+ //
+ a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
+ if (a.Expr == null)
+ return null;
+ }
+
+ eclass = ExprClass.Variable;
+
+ return this;
+ }
+
+ /// <summary>
+ /// Emits the right opcode to load an object of Type `t'
+ /// from an array of T
+ /// </summary>
+ static public void EmitLoadOpcode (ILGenerator ig, Type type)
+ {
+ if (type == TypeManager.byte_type || type == TypeManager.bool_type)
+ ig.Emit (OpCodes.Ldelem_U1);
+ else if (type == TypeManager.sbyte_type)
+ ig.Emit (OpCodes.Ldelem_I1);
+ else if (type == TypeManager.short_type)
+ ig.Emit (OpCodes.Ldelem_I2);
+ else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
+ ig.Emit (OpCodes.Ldelem_U2);
+ else if (type == TypeManager.int32_type)
+ ig.Emit (OpCodes.Ldelem_I4);
+ else if (type == TypeManager.uint32_type)
+ ig.Emit (OpCodes.Ldelem_U4);
+ else if (type == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Ldelem_I8);
+ else if (type == TypeManager.int64_type)
+ ig.Emit (OpCodes.Ldelem_I8);
+ else if (type == TypeManager.float_type)
+ ig.Emit (OpCodes.Ldelem_R4);
+ else if (type == TypeManager.double_type)
+ ig.Emit (OpCodes.Ldelem_R8);
+ else if (type == TypeManager.intptr_type)
+ ig.Emit (OpCodes.Ldelem_I);
+ else if (type.IsValueType){
+ ig.Emit (OpCodes.Ldelema, type);
+ ig.Emit (OpCodes.Ldobj, type);
+ } else
+ ig.Emit (OpCodes.Ldelem_Ref);
+ }
+
+ /// <summary>
+ /// Emits the right opcode to store an object of Type `t'
+ /// from an array of T.
+ /// </summary>
+ static public void EmitStoreOpcode (ILGenerator ig, Type t)
+ {
+ bool is_stobj;
+ OpCode op = GetStoreOpcode (t, out is_stobj);
+ if (is_stobj)
+ ig.Emit (OpCodes.Stobj, t);
+ else
+ ig.Emit (op);
+ }
+
+ /// <summary>
+ /// Returns the right opcode to store an object of Type `t'
+ /// from an array of T.
+ /// </summary>
+ static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
+ {
+ //Console.WriteLine (new System.Diagnostics.StackTrace ());
+ is_stobj = false;
+ t = TypeManager.TypeToCoreType (t);
+ if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
+ t = TypeManager.EnumToUnderlying (t);
+ if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
+ t == TypeManager.bool_type)
+ return OpCodes.Stelem_I1;
+ else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
+ t == TypeManager.char_type)
+ return OpCodes.Stelem_I2;
+ else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
+ return OpCodes.Stelem_I4;
+ else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
+ return OpCodes.Stelem_I8;
+ else if (t == TypeManager.float_type)
+ return OpCodes.Stelem_R4;
+ else if (t == TypeManager.double_type)
+ return OpCodes.Stelem_R8;
+ else if (t == TypeManager.intptr_type) {
+ is_stobj = true;
+ return OpCodes.Stobj;
+ } else if (t.IsValueType) {
+ is_stobj = true;
+ return OpCodes.Stobj;
+ } else
+ return OpCodes.Stelem_Ref;
+ }
+
+ MethodInfo FetchGetMethod ()
+ {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ int arg_count = ea.Arguments.Count;
+ Type [] args = new Type [arg_count];
+ MethodInfo get;
+
+ for (int i = 0; i < arg_count; i++){
+ //args [i++] = a.Type;
+ args [i] = TypeManager.int32_type;
+ }
+
+ get = mb.GetArrayMethod (
+ ea.Expr.Type, "Get",
+ CallingConventions.HasThis |
+ CallingConventions.Standard,
+ type, args);
+ return get;
+ }
+
+
+ MethodInfo FetchAddressMethod ()
+ {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ int arg_count = ea.Arguments.Count;
+ Type [] args = new Type [arg_count];
+ MethodInfo address;
+ Type ret_type;
+
+ ret_type = TypeManager.GetReferenceType (type);
+
+ for (int i = 0; i < arg_count; i++){
+ //args [i++] = a.Type;
+ args [i] = TypeManager.int32_type;
+ }
+
+ address = mb.GetArrayMethod (
+ ea.Expr.Type, "Address",
+ CallingConventions.HasThis |
+ CallingConventions.Standard,
+ ret_type, args);
+
+ return address;
+ }
+
+ //
+ // Load the array arguments into the stack.
+ //
+ // If we have been requested to cache the values (cached_locations array
+ // initialized), then load the arguments the first time and store them
+ // in locals. otherwise load from local variables.
+ //
+ void LoadArrayAndArguments (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (cached_locations == null){
+ ea.Expr.Emit (ec);
+ foreach (Argument a in ea.Arguments){
+ Type argtype = a.Expr.Type;
+
+ a.Expr.Emit (ec);
+
+ if (argtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I);
+ else if (argtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I_Un);
+ }
+ return;
+ }
+
+ if (cached_locations [0] == null){
+ cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
+ ea.Expr.Emit (ec);
+ ig.Emit (OpCodes.Dup);
+ cached_locations [0].Store (ec);
+
+ int j = 1;
+
+ foreach (Argument a in ea.Arguments){
+ Type argtype = a.Expr.Type;
+
+ cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
+ a.Expr.Emit (ec);
+ if (argtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I);
+ else if (argtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I_Un);
+
+ ig.Emit (OpCodes.Dup);
+ cached_locations [j].Store (ec);
+ j++;
+ }
+ return;
+ }
+
+ foreach (LocalTemporary lt in cached_locations)
+ lt.Emit (ec);
+ }
+
+ public new void CacheTemporaries (EmitContext ec)
+ {
+ cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int rank = ea.Expr.Type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+
+ LoadArrayAndArguments (ec);
+
+ if (rank == 1)
+ EmitLoadOpcode (ig, type);
+ else {
+ MethodInfo method;
+
+ method = FetchGetMethod ();
+ ig.Emit (OpCodes.Call, method);
+ }
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ int rank = ea.Expr.Type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+ Type t = source.Type;
+
+ LoadArrayAndArguments (ec);
+
+ //
+ // The stobj opcode used by value types will need
+ // an address on the stack, not really an array/array
+ // pair
+ //
+ if (rank == 1){
+ if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
+ (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
+ ig.Emit (OpCodes.Ldelema, t);
+ }
+
+ source.Emit (ec);
+
+ if (rank == 1)
+ EmitStoreOpcode (ig, t);
+ else {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ int arg_count = ea.Arguments.Count;
+ Type [] args = new Type [arg_count + 1];
+ MethodInfo set;
+
+ for (int i = 0; i < arg_count; i++){
+ //args [i++] = a.Type;
+ args [i] = TypeManager.int32_type;
+ }
+
+ args [arg_count] = type;
+
+ set = mb.GetArrayMethod (
+ ea.Expr.Type, "Set",
+ CallingConventions.HasThis |
+ CallingConventions.Standard,
+ TypeManager.void_type, args);
+
+ ig.Emit (OpCodes.Call, set);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ int rank = ea.Expr.Type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+
+ LoadArrayAndArguments (ec);
+
+ if (rank == 1){
+ ig.Emit (OpCodes.Ldelema, type);
+ } else {
+ MethodInfo address = FetchAddressMethod ();
+ ig.Emit (OpCodes.Call, address);
+ }
+ }
+ }
+
+
+ class Indexers {
+ public ArrayList properties;
+ static Hashtable map;
+
+ static Indexers ()
+ {
+ map = new Hashtable ();
+ }
+
+ Indexers ()
+ {
+ properties = new ArrayList ();
+ }
+
+ void Append (MemberInfo [] mi)
+ {
+ foreach (PropertyInfo property in mi){
+ MethodInfo get, set;
+
+ get = property.GetGetMethod (true);
+ set = property.GetSetMethod (true);
+ properties.Add (new Pair (get, set));
+ }
+ }
+
+ static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
+ {
+ string p_name = TypeManager.IndexerPropertyName (lookup_type);
+
+ MemberInfo [] mi = TypeManager.MemberLookup (
+ caller_type, caller_type, lookup_type, MemberTypes.Property,
+ BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly, p_name);
+
+ if (mi == null || mi.Length == 0)
+ return null;
+
+ return mi;
+ }
+
+ static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
+ {
+ Indexers ix = (Indexers) map [lookup_type];
+
+ if (ix != null)
+ return ix;
+
+ Type copy = lookup_type;
+ while (copy != TypeManager.object_type && copy != null){
+ MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
+
+ if (mi != null){
+ if (ix == null)
+ ix = new Indexers ();
+
+ ix.Append (mi);
+ }
+
+ copy = copy.BaseType;
+ }
+
+ return ix;
+ }
+ }
+
+ /// <summary>
+ /// Expressions that represent an indexer call.
+ /// </summary>
+ public class IndexerAccess : Expression, IAssignMethod {
+ //
+ // Points to our "data" repository
+ //
+ MethodInfo get, set;
+ ArrayList set_arguments;
+ bool is_base_indexer;
+
+ protected Type indexer_type;
+ protected Type current_type;
+ protected Expression instance_expr;
+ protected ArrayList arguments;
+
+ public IndexerAccess (ElementAccess ea, Location loc)
+ : this (ea.Expr, false, loc)
+ {
+ this.arguments = ea.Arguments;
+ }
+
+ protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
+ Location loc)
+ {
+ this.instance_expr = instance_expr;
+ this.is_base_indexer = is_base_indexer;
+ this.eclass = ExprClass.Value;
+ this.loc = loc;
+ }
+
+ protected virtual bool CommonResolve (EmitContext ec)
+ {
+ indexer_type = instance_expr.Type;
+ current_type = ec.ContainerType;
+
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ ArrayList AllGetters = new ArrayList();
+ if (!CommonResolve (ec))
+ return null;
+
+ //
+ // Step 1: Query for all `Item' *properties*. Notice
+ // that the actual methods are pointed from here.
+ //
+ // This is a group of properties, piles of them.
+
+ bool found_any = false, found_any_getters = false;
+ Type lookup_type = indexer_type;
+
+ Indexers ilist;
+ ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
+ if (ilist != null) {
+ found_any = true;
+ if (ilist.properties != null) {
+ foreach (Pair o in ilist.properties) {
+ if (o.First != null)
+ AllGetters.Add(o.First);
+ }
+ }
+ }
+
+ if (AllGetters.Count > 0) {
+ found_any_getters = true;
+ get = (MethodInfo) Invocation.OverloadResolve (
+ ec, new MethodGroupExpr (AllGetters, loc), arguments, loc);
+ }
+
+ if (!found_any) {
+ Report.Error (21, loc,
+ "Type `" + TypeManager.CSharpName (indexer_type) +
+ "' does not have any indexers defined");
+ return null;
+ }
+
+ if (!found_any_getters) {
+ Error (154, "indexer can not be used in this context, because " +
+ "it lacks a `get' accessor");
+ return null;
+ }
+
+ if (get == null) {
+ Error (1501, "No Overload for method `this' takes `" +
+ arguments.Count + "' arguments");
+ return null;
+ }
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (get.IsAbstract && this is BaseIndexerAccess){
+ Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
+ return null;
+ }
+
+ type = get.ReturnType;
+ if (type.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+
+ eclass = ExprClass.IndexerAccess;
+ return this;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ ArrayList AllSetters = new ArrayList();
+ if (!CommonResolve (ec))
+ return null;
+
+ Type right_type = right_side.Type;
+
+ bool found_any = false, found_any_setters = false;
+
+ Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
+ if (ilist != null) {
+ found_any = true;
+ if (ilist.properties != null) {
+ foreach (Pair o in ilist.properties) {
+ if (o.Second != null)
+ AllSetters.Add(o.Second);
+ }
+ }
+ }
+ if (AllSetters.Count > 0) {
+ found_any_setters = true;
+ set_arguments = (ArrayList) arguments.Clone ();
+ set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
+ set = (MethodInfo) Invocation.OverloadResolve (
+ ec, new MethodGroupExpr (AllSetters, loc),
+ set_arguments, loc);
+ }
+
+ if (!found_any) {
+ Report.Error (21, loc,
+ "Type `" + TypeManager.CSharpName (indexer_type) +
+ "' does not have any indexers defined");
+ return null;
+ }
+
+ if (!found_any_setters) {
+ Error (154, "indexer can not be used in this context, because " +
+ "it lacks a `set' accessor");
+ return null;
+ }
+
+ if (set == null) {
+ Error (1501, "No Overload for method `this' takes `" +
+ arguments.Count + "' arguments");
+ return null;
+ }
+
+ //
+ // Only base will allow this invocation to happen.
+ //
+ if (set.IsAbstract && this is BaseIndexerAccess){
+ Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
+ return null;
+ }
+
+ //
+ // Now look for the actual match in the list of indexers to set our "return" type
+ //
+ type = TypeManager.void_type; // default value
+ foreach (Pair t in ilist.properties){
+ if (t.Second == set){
+ if (t.First != null)
+ type = ((MethodInfo) t.First).ReturnType;
+ break;
+ }
+ }
+
+ eclass = ExprClass.IndexerAccess;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc);
+ }
+
+ //
+ // source is ignored, because we already have a copy of it from the
+ // LValue resolution and we have already constructed a pre-cached
+ // version of the arguments (ea.set_arguments);
+ //
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc);
+ }
+ }
+
+ /// <summary>
+ /// The base operator for method names
+ /// </summary>
+ public class BaseAccess : Expression {
+ string member;
+
+ public BaseAccess (string member, Location l)
+ {
+ this.member = member;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expression c = CommonResolve (ec);
+
+ if (c == null)
+ return null;
+
+ //
+ // MethodGroups use this opportunity to flag an error on lacking ()
+ //
+ if (!(c is MethodGroupExpr))
+ return c.Resolve (ec);
+ return c;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ Expression c = CommonResolve (ec);
+
+ if (c == null)
+ return null;
+
+ //
+ // MethodGroups use this opportunity to flag an error on lacking ()
+ //
+ if (! (c is MethodGroupExpr))
+ return c.DoResolveLValue (ec, right_side);
+
+ return c;
+ }
+
+ Expression CommonResolve (EmitContext ec)
+ {
+ Expression member_lookup;
+ Type current_type = ec.ContainerType;
+ Type base_type = current_type.BaseType;
+ Expression e;
+
+ if (ec.IsStatic){
+ Error (1511, "Keyword base is not allowed in static method");
+ return null;
+ }
+
+ member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
+ AllMemberTypes, AllBindingFlags, loc);
+ if (member_lookup == null) {
+ MemberLookupFailed (ec, base_type, base_type, member, null, loc);
+ return null;
+ }
+
+ Expression left;
+
+ if (ec.IsStatic)
+ left = new TypeExpr (base_type, loc);
+ else
+ left = ec.GetThis (loc);
+
+ e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
+
+ if (e is PropertyExpr){
+ PropertyExpr pe = (PropertyExpr) e;
+
+ pe.IsBase = true;
+ }
+
+ return e;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be called");
+ }
+ }
+
+ /// <summary>
+ /// The base indexer operator
+ /// </summary>
+ public class BaseIndexerAccess : IndexerAccess {
+ public BaseIndexerAccess (ArrayList args, Location loc)
+ : base (null, true, loc)
+ {
+ arguments = new ArrayList ();
+ foreach (Expression tmp in args)
+ arguments.Add (new Argument (tmp, Argument.AType.Expression));
+ }
+
+ protected override bool CommonResolve (EmitContext ec)
+ {
+ instance_expr = ec.GetThis (loc);
+
+ current_type = ec.ContainerType.BaseType;
+ indexer_type = current_type;
+
+ foreach (Argument a in arguments){
+ if (!a.Resolve (ec, loc))
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// This class exists solely to pass the Type around and to be a dummy
+ /// that can be passed to the conversion functions (this is used by
+ /// foreach implementation to typecast the object return value from
+ /// get_Current into the proper type. All code has been generated and
+ /// we only care about the side effect conversions to be performed
+ ///
+ /// This is also now used as a placeholder where a no-action expression
+ /// is needed (the `New' class).
+ /// </summary>
+ public class EmptyExpression : Expression {
+ public EmptyExpression ()
+ {
+ type = TypeManager.object_type;
+ eclass = ExprClass.Value;
+ loc = Location.Null;
+ }
+
+ public EmptyExpression (Type t)
+ {
+ type = t;
+ eclass = ExprClass.Value;
+ loc = Location.Null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ // nothing, as we only exist to not do anything.
+ }
+
+ //
+ // This is just because we might want to reuse this bad boy
+ // instead of creating gazillions of EmptyExpressions.
+ // (CanImplicitConversion uses it)
+ //
+ public void SetType (Type t)
+ {
+ type = t;
+ }
+ }
+
+ public class UserCast : Expression {
+ MethodBase method;
+ Expression source;
+
+ public UserCast (MethodInfo method, Expression source, Location l)
+ {
+ this.method = method;
+ this.source = source;
+ type = method.ReturnType;
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ source.Emit (ec);
+
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+ }
+ }
+
+ // <summary>
+ // This class is used to "construct" the type during a typecast
+ // operation. Since the Type.GetType class in .NET can parse
+ // the type specification, we just use this to construct the type
+ // one bit at a time.
+ // </summary>
+ public class ComposedCast : Expression {
+ Expression left;
+ string dim;
+
+ public ComposedCast (Expression left, string dim, Location l)
+ {
+ this.left = left;
+ this.dim = dim;
+ loc = l;
+ }
+
+ public override Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
+ if (ltype == null)
+ return null;
+
+ //
+ // ltype.Fullname is already fully qualified, so we can skip
+ // a lot of probes, and go directly to TypeManager.LookupType
+ //
+ string cname = ltype.FullName + dim;
+ type = TypeManager.LookupTypeDirect (cname);
+ if (type == null){
+ //
+ // For arrays of enumerations we are having a problem
+ // with the direct lookup. Need to investigate.
+ //
+ // For now, fall back to the full lookup in that case.
+ //
+ type = RootContext.LookupType (
+ ec.DeclSpace, cname, false, loc);
+
+ if (type == null)
+ return null;
+ }
+
+ if (!ec.ResolvingTypeTree){
+ //
+ // If the above flag is set, this is being invoked from the ResolveType function.
+ // Upper layers take care of the type validity in this context.
+ //
+ if (!ec.InUnsafe && type.IsPointer){
+ UnsafeError (loc);
+ return null;
+ }
+ }
+
+ eclass = ExprClass.Type;
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return ResolveAsTypeStep (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("This should never be called");
+ }
+
+ public override string ToString ()
+ {
+ return left + dim;
+ }
+ }
+
+ //
+ // This class is used to represent the address of an array, used
+ // only by the Fixed statement, this is like the C "&a [0]" construct.
+ //
+ public class ArrayPtr : Expression {
+ Expression array;
+
+ public ArrayPtr (Expression array, Location l)
+ {
+ Type array_type = TypeManager.GetElementType (array.Type);
+
+ this.array = array;
+
+ type = TypeManager.GetPointerType (array_type);
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ array.Emit (ec);
+ IntLiteral.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+ }
+
+ //
+ // Used by the fixed statement
+ //
+ public class StringPtr : Expression {
+ LocalBuilder b;
+
+ public StringPtr (LocalBuilder b, Location l)
+ {
+ this.b = b;
+ eclass = ExprClass.Value;
+ type = TypeManager.char_ptr_type;
+ loc = l;
+ }
+
+ 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)
+ {
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldloc, b);
+ ig.Emit (OpCodes.Conv_I);
+ ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
+ ig.Emit (OpCodes.Add);
+ }
+ }
+
+ //
+ // Implements the `stackalloc' keyword
+ //
+ public class StackAlloc : Expression {
+ Type otype;
+ Expression t;
+ Expression count;
+
+ public StackAlloc (Expression type, Expression count, Location l)
+ {
+ t = type;
+ this.count = count;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ count = count.Resolve (ec);
+ if (count == null)
+ return null;
+
+ if (count.Type != TypeManager.int32_type){
+ count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
+ if (count == null)
+ return null;
+ }
+
+ if (ec.InCatch || ec.InFinally){
+ Error (255,
+ "stackalloc can not be used in a catch or finally block");
+ return null;
+ }
+
+ otype = ec.DeclSpace.ResolveType (t, false, loc);
+
+ if (otype == null)
+ return null;
+
+ if (!TypeManager.VerifyUnManaged (otype, loc))
+ return null;
+
+ type = TypeManager.GetPointerType (otype);
+ eclass = ExprClass.Value;
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int size = GetTypeSize (otype);
+ ILGenerator ig = ec.ig;
+
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, otype);
+ else
+ IntConstant.EmitInt (ig, size);
+ count.Emit (ec);
+ ig.Emit (OpCodes.Mul);
+ ig.Emit (OpCodes.Localloc);
+ }
+ }
+}
--- /dev/null
+// gen-il.cs: Generates MSIL code from the CIR.Tree
+//
+// Author: 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.IO;
+using System.Collections;
+using CIR;
+
+namespace MSIL {
+
+ public class Generator : CIR.ITreeDump {
+ StreamWriter o;
+ int indent = 0;
+
+ void output (string s)
+ {
+ Console.Write (s);
+ o.Write (s);
+ }
+
+ void space ()
+ {
+ output (new String (' ', indent * 2));
+ }
+
+ void ioutput (string s)
+ {
+ space ();
+ output (s);
+ }
+
+ void ioutputl (string s)
+ {
+ ioutput (s + "\n");
+ }
+
+ string ClassAttributes (Class c)
+ {
+ // FIXME
+ return "";
+ }
+
+ string ILName (string name)
+ {
+ return name;
+ }
+
+ string ClassExtends (Class c)
+ {
+ return "";
+ }
+
+ void GenerateFromClass (Class c)
+ {
+ ioutputl (".class " + ClassAttributes (c) + " " + ILName (c.Name));
+ ioutputl (ClassExtends (c));
+ ioutputl ("{");
+ indent++;
+
+
+
+ indent--;
+ ioutputl ("}");
+ }
+
+ void GenerateFromTypes (TypeContainer types)
+ {
+ if (types.Types == null)
+ return;
+
+ foreach (DictionaryEntry de in types.Types){
+ TypeContainer type = (TypeContainer) de.Value;
+
+ if (type is Class)
+ GenerateFromClass ((Class) type);
+ }
+
+ }
+
+ public int GenerateFromTree (Tree tree, StreamWriter os)
+ {
+ this.o = os;
+
+ ioutputl (".assembly test.exe { }");
+ GenerateFromTypes (tree.Types);
+ return 0;
+ }
+
+ public void ParseOptions (string options)
+ {
+ }
+
+ }
+}
--- /dev/null
+// cs-treedump.cs: Dumps the parsed tree to standard output
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc. (http://www.ximian.com)
+//
+// TODO:
+// Variable declarations
+// Fix precedence rules to lower the number of parenthesis.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+using CIR;
+
+namespace Generator {
+
+ public class TreeDump : CIR.ITreeDump {
+ StreamWriter o;
+ int indent;
+ bool indented;
+ bool tag_values;
+
+ void space ()
+ {
+ if (!indented)
+ output (new String (' ', indent * 8));
+ indented = true;
+ }
+
+ void output (string s)
+ {
+ Console.Write (s);
+ //o.Write (s);
+ }
+
+ void newline ()
+ {
+ output ("\n");
+ indented = false;
+ }
+
+ void output_newline (string s)
+ {
+ output (s);
+ newline ();
+ }
+
+ void ioutput (string s)
+ {
+ space ();
+ output (s);
+ }
+
+ string GetParameter (Parameter par)
+ {
+ Parameter.Modifier f = par.ModFlags;
+ string mod = "";
+
+ switch (f){
+ case Parameter.Modifier.REF:
+ mod = "ref "; break;
+ case Parameter.Modifier.OUT:
+ mod = "out "; break;
+ case Parameter.Modifier.PARAMS:
+ mod = "params "; break;
+ case Parameter.Modifier.NONE:
+ mod = ""; break;
+ }
+ return mod + par.Type + " " + par.Name;
+ }
+
+ string GetUnary (Unary u, int paren_level)
+ {
+ string e;
+ bool left = true;
+ string s = "0_ERROR>";
+ int prec = 0;
+
+ switch (u.Oper){
+ case Unary.Operator.UnaryPlus:
+ prec = 10;
+ s = "+";
+ break;
+
+ case Unary.Operator.UnaryNegation:
+ prec = 10;
+ s = "-";
+ break;
+
+ case Unary.Operator.LogicalNot:
+ s = "!";
+ prec = 10;
+ break;
+
+ case Unary.Operator.OnesComplement:
+ prec = 10;
+ s = "~";
+ break;
+
+ case Unary.Operator.Indirection:
+ prec = 10;
+ s = "*";
+ break;
+
+ case Unary.Operator.AddressOf:
+ prec = 10;
+ s = "&";
+ break;
+
+ case Unary.Operator.PreIncrement:
+ prec = 11;
+ s = "++";
+ break;
+
+ case Unary.Operator.PreDecrement:
+ prec = 11;
+ s = "--";
+ break;
+
+ case Unary.Operator.PostDecrement:
+ left = false;
+ prec = 12;
+ s = "--";
+ break;
+
+ case Unary.Operator.PostIncrement:
+ s = "++";
+ prec = 12;
+ left = false;
+ break;
+ }
+
+ e = GetExpression (u.Expr, prec);
+ if (left)
+ e = s + e;
+ else
+ e = e + s;
+
+ if (prec < paren_level)
+ return "(" + e + ")";
+ else
+ return e;
+ }
+
+ string GetBinary (Binary b, int paren_level)
+ {
+ string l, r;
+ string op = null;
+ bool assoc_left = true;
+ int prec = 0;
+
+ switch (b.Oper){
+ case Binary.Operator.Multiply:
+ prec = 9;
+ op = "*"; break;
+
+ case Binary.Operator.Division:
+ prec = 9;
+ op = "/"; break;
+
+ case Binary.Operator.Modulus:
+ prec = 9;
+ op = "%"; break;
+
+ case Binary.Operator.Addition:
+ prec = 8;
+ op = "+"; break;
+
+ case Binary.Operator.Subtraction:
+ prec = 8;
+ op = "-"; break;
+
+ case Binary.Operator.LeftShift:
+ prec = 7;
+ op = "<<"; break;
+
+ case Binary.Operator.RightShift:
+ prec = 7;
+ op = ">>"; break;
+
+ case Binary.Operator.LessThan:
+ prec = 6;
+ op = "<"; break;
+
+ case Binary.Operator.GreaterThan:
+ prec = 6;
+ op = ">"; break;
+
+ case Binary.Operator.LessThanOrEqual:
+ prec = 6;
+ op = "<="; break;
+
+ case Binary.Operator.GreaterThanOrEqual:
+ prec = 6;
+ op = ">="; break;
+
+ case Binary.Operator.Equality:
+ prec = 5;
+ op = "=="; break;
+
+ case Binary.Operator.Inequality:
+ prec = 5;
+ op = "!="; break;
+
+ case Binary.Operator.BitwiseAnd:
+ prec = 4;
+ op = "&"; break;
+
+ case Binary.Operator.BitwiseOr:
+ prec = 2;
+ op = "|"; break;
+
+ case Binary.Operator.LogicalAnd:
+ prec = 1;
+ op = "&&"; break;
+
+ case Binary.Operator.LogicalOr:
+ prec = 0;
+ op = "||"; break;
+
+ case Binary.Operator.ExclusiveOr:
+ prec = 3;
+ op = "^"; break;
+ }
+
+ l = GetExpression (b.Left, prec - (assoc_left ? 0 : 1));
+ r = GetExpression (b.Right, prec - (assoc_left ? 0 : 1));
+
+ if (prec <= paren_level)
+ return "(" + l + " " + op + " " + r + ")";
+ else
+ return l + " " + op + " " + r;
+ }
+
+ string GetCast (Cast c)
+ {
+ return "(" + c.TargetType + ") (" + GetExpression (c.Expr, 0) + ")";
+ }
+
+ string GetConditional (Conditional c)
+ {
+ return "(" + GetExpression (c.Expr, 0) + ") ? (" +
+ GetExpression (c.TrueExpr, 0) + ") : (" +
+ GetExpression (c.FalseExpr, 0) + ")";
+ }
+
+ string GetAssign (Assign a)
+ {
+ return GetExpression (a.Target, 0) + " = " + GetExpression (a.Source, 0);
+ }
+
+ string GetArguments (ArrayList args)
+ {
+ string r = "";
+
+ if (args != null){
+ int top = args.Count;
+
+ for (int i = 0; i < top; i++){
+ Argument arg = (Argument) args [i];
+
+ switch (arg.ArgType){
+ case Argument.AType.Ref:
+ r += "ref "; break;
+ case Argument.AType.Out:
+ r += "out "; break;
+ }
+ r += GetExpression (arg.Expr, 0);
+
+ if (i+1 != top)
+ r += ", ";
+ }
+ }
+
+ return "(" + r + ")";
+ }
+
+ string GetInvocation (Invocation i)
+ {
+ return GetExpression (i.Expr, 0) + " " + GetArguments (i.Arguments);
+ }
+
+ string GetNew (New n)
+ {
+ return "new " + n.RequestedType + GetArguments (n.Arguments);
+ }
+
+ string GetTypeOf (TypeOf t)
+ {
+ return "typeof (" + t.QueriedType + ")";
+ }
+
+ string GetSizeOf (SizeOf t)
+ {
+ return "sizeof (" + t.QueriedType + ")";
+ }
+
+ string GetMemberAccess (MemberAccess m)
+ {
+ return GetExpression (m.Expr, 0) +
+ (tag_values ? "/* member access */ . " : ".") +
+ m.Identifier;
+ }
+
+ string GetSimpleName (SimpleName n)
+ {
+ string s = n.Name;
+
+ if (s.StartsWith ("0_"))
+ return "id_" + s;
+ else
+ return s;
+ }
+
+ string GetProbe (Probe p)
+ {
+ string s = GetExpression (p.Expr, 6);
+
+ if (p.Oper == CIR.Probe.Operator.Is)
+ s += " is ";
+ else if (p.Oper == CIR.Probe.Operator.As)
+ s += " as ";
+ else
+ s += "UNHANDLED";
+
+ s += p.ProbeType;
+
+ return s;
+ }
+
+ string GetLocalVariableReference (LocalVariableReference l)
+ {
+ if (tag_values)
+ return "/* local var: */" + l.Name;
+ else
+ return l.Name;
+ }
+
+ string GetParameterReference (ParameterReference r)
+ {
+ if (tag_values)
+ return "/* par: */ " + r.Name;
+ else
+ return r.Name;
+ }
+
+ string GetExpression (Expression e, int paren_level)
+ {
+ if (e == null){
+ return "<NULL EXPRESSION>";
+ }
+
+ if (e is Unary)
+ return GetUnary ((Unary) e, paren_level);
+ else if (e is Binary)
+ return GetBinary ((Binary) e, paren_level);
+ else if (e is Cast)
+ return GetCast ((Cast) e);
+ else if (e is Conditional)
+ return GetConditional ((Conditional) e);
+ else if (e is SimpleName)
+ return GetSimpleName ((SimpleName)e);
+ else if (e is LocalVariableReference)
+ return GetLocalVariableReference ((LocalVariableReference) e);
+ else if (e is ParameterReference)
+ return GetParameterReference ((ParameterReference) e);
+ else if (e is Assign)
+ return GetAssign ((Assign) e);
+ else if (e is Literal)
+ return e.ToString ();
+ else if (e is Invocation)
+ return GetInvocation ((Invocation) e);
+ else if (e is New)
+ return GetNew ((New) e);
+ else if (e is This)
+ return "this";
+ else if (e is TypeOf)
+ return GetTypeOf ((TypeOf) e);
+ else if (e is SizeOf)
+ return GetSizeOf ((SizeOf) e);
+ else if (e is MemberAccess)
+ return GetMemberAccess ((MemberAccess) e);
+ else if (e is Probe)
+ return GetProbe ((Probe) e);
+ else
+ return "WARNING {" + e.ToString () + "} WARNING";
+ }
+
+ void GenerateParameters (Parameters pars)
+ {
+ Parameter [] pfixed;
+ Parameter parray;
+
+ pfixed = pars.FixedParameters;
+
+ if (pfixed != null){
+ for (int i = 0; i < pfixed.Length; i++){
+ output (GetParameter (pfixed [i]));
+ if (i+1 != pfixed.Length)
+ output (", ");
+ }
+ }
+
+ parray = pars.ArrayParameter;
+ if (parray != null){
+ output (GetParameter (parray));
+ }
+ }
+
+ void GenerateIf (If s)
+ {
+ bool do_indent;
+
+ output ("if (" + GetExpression (s.Expr, 0) + ") ");
+ do_indent = !(s.TrueStatement is Block);
+ if (do_indent)
+ indent++;
+ GenerateStatement (s.TrueStatement, true, false, false);
+ if (do_indent)
+ indent--;
+ if (s.FalseStatement != null){
+ ioutput ("else");
+ newline ();
+ GenerateStatement (s.FalseStatement, false, true, false);
+ }
+ }
+
+ void GenerateDo (Do s)
+ {
+ output ("do"); newline ();
+ indent++;
+ GenerateStatement (s.EmbeddedStatement, false, false, false);
+ indent--;
+ output (" while (" + GetExpression (s.Expr, 0) + ");");
+ newline ();
+ }
+
+ void GenerateWhile (While s)
+ {
+ output ("while (" + GetExpression (s.Expr, 0) + ")");
+ GenerateStatement (s.Statement, true, true, false);
+ }
+
+ void GenerateFor (For s)
+ {
+ output ("for (");
+ if (! (s.InitStatement is EmptyStatement))
+ GenerateStatement (s.InitStatement, true, true, true);
+ output ("; ");
+ output (GetExpression (s.Test, 0));
+ output ("; ");
+ if (! (s.Increment is EmptyStatement))
+ GenerateStatement (s.Increment, true, true, true);
+ output (") ");
+ GenerateStatement (s.Statement, true, true, false);
+ }
+
+ void GenerateReturn (Return s)
+ {
+ output ("return " +
+ (s.Expr != null ?
+ GetExpression (s.Expr, 0) : "" + ";") +
+ ";");
+ newline ();
+ }
+
+ void GenerateGoto (Goto s)
+ {
+ output ("goto " + s.Target + ";");
+ newline ();
+ }
+
+ void GenerateThrow (Throw s)
+ {
+ }
+
+ void GenerateStatementExpression (StatementExpression s)
+ {
+ output (GetExpression (s.Expr, 0) + ";");
+ newline ();
+ }
+
+ void GenerateSwitchLabels (ArrayList labels)
+ {
+ foreach (SwitchLabel sl in labels){
+ Expression lab = sl.Label;
+
+ if (lab == null){
+ ioutput ("default:");
+ newline ();
+ } else {
+ ioutput ("case " + GetExpression (lab, 0) + ":");
+ newline ();
+ }
+ }
+ }
+
+ void GenerateSwitch (Switch s)
+ {
+ output_newline ("switch (" + GetExpression (s.Expr, 0) + ")");
+ foreach (SwitchSection ss in s.Sections){
+ GenerateSwitchLabels (ss.Labels);
+ GenerateBlock (ss.Block, false, false);
+ }
+ }
+
+ void GenerateChecked (Checked c)
+ {
+ output ("checked ");
+ GenerateBlock (c.Block, false, false);
+ }
+
+ void GenerateUnchecked (Unchecked c)
+ {
+ output ("unchecked ");
+ GenerateBlock (c.Block, false, false);
+ }
+
+ void GenerateCatchClauses (ArrayList list)
+ {
+ foreach (Catch c in list){
+ space ();
+ output ("catch ");
+
+ if (c.Type != null){
+ output ("(" + c.Type +
+ (c.Name != null ? " " + c.Name : "") + ")");
+ }
+ GenerateBlock (c.Block, false, false);
+ }
+ }
+
+ void GenerateTry (Try t)
+ {
+ output ("try");
+ GenerateBlock (t.Block, false, false);
+
+ if (t.Specific != null){
+ GenerateCatchClauses (t.Specific);
+ }
+
+ if (t.General != null){
+ space ();
+ output ("catch");
+ GenerateBlock (t.Block, false, false);
+ }
+
+ if (t.Fini != null){
+ GenerateBlock (t.Fini, false, false);
+ }
+ }
+
+ void GenerateStatement (Statement s, bool doPlacement, bool blockFlushesLine, bool embedded)
+ {
+ if (s == null){
+ output ("WARNING: got a null Statement");
+ newline ();
+ return;
+ }
+
+ if (doPlacement){
+ if (s is Block){
+ GenerateBlock ((Block) s, doPlacement, embedded);
+ return;
+ } else
+ newline ();
+ }
+
+ space ();
+ if (s is If)
+ GenerateIf ((If) s);
+ else if (s is Do)
+ GenerateDo ((Do) s);
+ else if (s is While)
+ GenerateWhile ((While) s);
+ else if (s is For)
+ GenerateFor ((For) s);
+ else if (s is Return)
+ GenerateReturn ((Return) s);
+ else if (s is Goto)
+ GenerateGoto ((Goto) s);
+ else if (s is Throw)
+ GenerateThrow ((Throw) s);
+ else if (s is Break)
+ output_newline ("break;");
+ else if (s is Continue)
+ output_newline ("continue;");
+ else if (s is EmptyStatement)
+ output_newline ("/* empty statement */;");
+ else if (s is Block)
+ GenerateBlock ((Block) s, doPlacement, embedded);
+ else if (s is StatementExpression)
+ GenerateStatementExpression ((StatementExpression) s);
+ else if (s is Switch)
+ GenerateSwitch ((Switch) s);
+ else if (s is Checked)
+ GenerateChecked ((Checked) s);
+ else if (s is Unchecked)
+ GenerateUnchecked ((Unchecked) s);
+ else if (s is Try)
+ GenerateTry ((Try) s);
+ else {
+ System.Type t = s.GetType ();
+
+ output ("\n*****UNKNOWN Statement:" + t.ToString ());
+ }
+ }
+
+ //
+ // embedded is used only for things like the For thing
+ // that has blocks but for display purposes we want to keep
+ // without newlines.
+ void GenerateBlock (Block b, bool doPlacement, bool embedded)
+ {
+ if (b.Label != null)
+ output (b.Label + ":");
+
+ if (!b.Implicit){
+ if (!doPlacement)
+ space ();
+
+ output ("{");
+ if (!embedded)
+ newline ();
+ indent++;
+ }
+
+ if (b.Variables != null){
+ foreach (DictionaryEntry entry in b.Variables){
+ VariableInfo vi = (VariableInfo) entry.Value;
+
+ space ();
+ output_newline (
+ vi.Type + " " +
+ (string) entry.Key + ";");
+ }
+ newline ();
+ }
+
+ foreach (Statement s in b.Statements){
+ GenerateStatement (s, false, true, false);
+ }
+
+ if (!b.Implicit){
+ indent--;
+ ioutput ("}");
+ if (!embedded)
+ newline ();
+ }
+ }
+
+ void GenerateMethod (Method m)
+ {
+ ioutput (GetModifiers (m.ModFlags) +
+ m.ReturnType + " " +
+ m.Name + " (");
+ GenerateParameters (m.Parameters);
+ output_newline (")");
+
+
+ GenerateBlock (m.Block, false, false);
+ newline ();
+ }
+
+ void GenerateInterfaceMethod (InterfaceMethod imethod)
+ {
+ space ();
+ output (imethod.IsNew ? "new " : "");
+ output (imethod.ReturnType + " " + imethod.Name + " (");
+ GenerateParameters (imethod.Parameters);
+ output (");");
+ newline ();
+ }
+
+ void GenerateInterfaceProperty (InterfaceProperty iprop)
+ {
+ space ();
+ output (iprop.IsNew ? "new " : "");
+ output (iprop.Type + " " + iprop.Name + " { ");
+ if (iprop.HasGet) output ("get; ");
+ if (iprop.HasSet) output ("set; ");
+ output ("}");
+ newline ();
+ }
+
+ void GenerateInterfaceEvent (InterfaceEvent ievent)
+ {
+ space ();
+ output ((ievent.IsNew ? "new " : "") + "event ");
+ output (ievent.Type + " " + ievent.Name + ";");
+ newline ();
+ }
+
+ void GenerateInterfaceIndexer (InterfaceIndexer iindexer)
+ {
+ space ();
+ output (iindexer.IsNew ? "new " : "");
+ output (iindexer.Type + " this [");
+ output (iindexer.Parameters + "] {");
+ if (iindexer.HasGet) output ("get; ");
+ if (iindexer.HasSet) output ("set; ");
+ output ("}");
+ newline ();
+ }
+
+ string GenIfaceBases (Interface iface)
+ {
+ return GenBases (iface.Bases);
+ }
+
+ void GenerateInterface (Interface iface)
+ {
+ ioutput (GetModifiers (iface.ModFlags) + "interface " +
+ ClassName (iface.Name) + GenIfaceBases (iface) + " {");
+ newline ();
+ indent++;
+
+ if (iface.InterfaceMethods != null){
+ foreach (DictionaryEntry de in iface.InterfaceMethods){
+ InterfaceMethod method = (InterfaceMethod) de.Value;
+ GenerateInterfaceMethod (method);
+ }
+ }
+
+ if (iface.InterfaceProperties != null){
+ foreach (DictionaryEntry de in iface.InterfaceProperties){
+ InterfaceProperty iprop = (InterfaceProperty) de.Value;
+ GenerateInterfaceProperty (iprop);
+ }
+ }
+
+ if (iface.InterfaceEvents != null){
+ foreach (DictionaryEntry de in iface.InterfaceEvents){
+ InterfaceEvent ievent = (InterfaceEvent) de.Value;
+ GenerateInterfaceEvent (ievent);
+ }
+ }
+
+ if (iface.InterfaceIndexers != null){
+ foreach (DictionaryEntry de in iface.InterfaceIndexers){
+ InterfaceIndexer iindexer = (InterfaceIndexer) de.Value;
+ GenerateInterfaceIndexer (iindexer);
+ }
+ }
+ indent--;
+ ioutput ("}");
+ newline ();
+ newline ();
+ }
+
+ void GenerateField (Field f)
+ {
+ space ();
+ output (GetModifiers (f.ModFlags) +
+ f.Type + " " + f.Name);
+ if (f.Initializer != null){
+ if (f.Initializer is Expression)
+ output (" = " + GetExpression ((Expression) f.Initializer, 0));
+ else
+ output ("ADD SUPPORT FOR ARRAYS");
+ }
+ output (";");
+ newline ();
+ }
+
+ void GenerateConstructor (Constructor c)
+ {
+ ConstructorInitializer init = c.Initializer;
+
+ space ();
+ output (GetModifiers (c.ModFlags) + c.Name + " (");
+ GenerateParameters (c.Parameters);
+ output (")");
+
+ if (init != null){
+ if (init is ConstructorThisInitializer)
+ output (": this (");
+ else
+ output (": base (");
+ output (GetArguments (init.Arguments));
+ output (")");
+ }
+ newline ();
+ GenerateBlock (c.Block, false, false);
+ }
+
+ void GenerateProperty (Property prop)
+ {
+ space ();
+ output (GetModifiers (prop.ModFlags) + prop.Type +
+ " " + prop.Name + " {");
+ newline ();
+ indent++;
+ if (prop.Get != null){
+ space ();
+ output ("get ");
+ GenerateBlock (prop.Get, false, false);
+ newline ();
+ }
+
+ if (prop.Set != null){
+ space ();
+ output ("set ");
+ GenerateBlock (prop.Set, false, false);
+ }
+ indent--;
+ space ();
+ output ("}");
+ newline ();
+ }
+
+ void GenerateEnum (CIR.Enum e)
+ {
+ space ();
+ output ("enum " + e.Name + " {");
+ newline ();
+
+ indent++;
+ foreach (string name in e.ValueNames){
+ Expression expr = e [name];
+
+ space ();
+
+ output (name);
+ if (expr != null)
+ output (" = " + GetExpression (expr, 0));
+
+ output (",");
+ newline ();
+ }
+ indent--;
+ space ();
+ output_newline ("}");
+ }
+
+ void GenerateTypeContainerData (TypeContainer tc)
+ {
+ if (tc.Constants != null){
+ foreach (Constant c in tc.Constants){
+ space ();
+
+ output ("const " + c.ConstantType + " " + c.Name + " = " +
+ GetExpression (c.Expr, 0) + ";");
+ newline ();
+ }
+ newline ();
+ }
+
+ if (tc.Enums != null){
+ foreach (CIR.Enum e in tc.Enums)
+ GenerateEnum (e);
+ }
+
+ if (tc.Fields != null){
+ foreach (Field f in tc.Fields)
+ GenerateField (f);
+ newline ();
+ }
+
+ if (tc.Constructors != null){
+ foreach (Constructor c in tc.Constructors)
+ GenerateConstructor (c);
+
+ newline ();
+
+ }
+
+ if (tc.Properties != null){
+ foreach (Property prop in tc.Properties)
+ GenerateProperty (prop);
+ }
+
+ GenerateFromTypes (tc);
+
+ if (tc.Methods != null){
+ foreach (Method m in tc.Methods){
+ GenerateMethod (m);
+ }
+ }
+ }
+
+ string GetModifiers (int mod_flags)
+ {
+ string s = "";
+
+ for (int i = 1; i <= (int) CIR.Modifiers.TOP; i <<= 1){
+ if ((mod_flags & i) != 0)
+ s += Modifiers.Name (i) + " ";
+ }
+
+ return s;
+ }
+
+ string ClassName (string name)
+ {
+ return name;
+ //return name.Substring (1 + name.LastIndexOf ("."));
+ }
+
+ string GenBases (ArrayList bases)
+ {
+ if (bases == null)
+ return "";
+
+ string res = ": ";
+ int top = bases.Count;
+ for (int i = 0; i < bases.Count; i++){
+ Type t = (Type) bases [i];
+
+ res += t.Name;
+ if (i + 1 != top)
+ res += ", ";
+ }
+ return res;
+ }
+
+ string GenClassBases (Class c)
+ {
+ return GenBases (c.Bases);
+ }
+
+ void GenerateFromClass (Class c)
+ {
+ ioutput (GetModifiers (c.ModFlags) + "class " + ClassName (c.Name) +
+ " " + GenClassBases (c) + " {");
+ newline ();
+ indent++;
+
+ GenerateTypeContainerData (c);
+
+ indent--;
+ ioutput ("}");
+ newline ();
+ newline ();
+ }
+
+ void GenerateFromStruct (Struct s)
+ {
+ GenerateTypeContainerData (s);
+ }
+
+ void GenerateFromTypes (TypeContainer types)
+ {
+ if (types.Types == null)
+ return;
+
+ foreach (DictionaryEntry de in types.Types){
+ TypeContainer type = (TypeContainer) de.Value;
+
+ if (type is Class)
+ GenerateFromClass ((Class) type);
+ if (type is Struct)
+ GenerateFromStruct ((Struct) type);
+
+ }
+
+ if (types.Interfaces != null){
+ foreach (DictionaryEntry de in types.Interfaces){
+ Interface iface = (Interface) de.Value;
+
+ GenerateInterface (iface);
+ }
+ }
+ }
+
+ public int Dump (Tree tree, StreamWriter output)
+ {
+ this.o = output;
+
+ indent = 0;
+ GenerateFromTypes (tree.Types);
+
+ return 0;
+ }
+
+ public void ParseOptions (string options)
+ {
+ if (options == "tag")
+ tag_values = true;
+ }
+ }
+}
+
+
--- /dev/null
+//
+// generic.cs: Support classes for generics
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2003 Ximian, Inc.
+//
+using System;
+using System.Collections;
+
+namespace Mono.CSharp {
+
+ //
+ // Tracks the constraints for a type parameter
+ //
+ class Constraints {
+ string type_parameter;
+ ArrayList constraints;
+
+ //
+ // type_parameter is the identifier, constraints is an arraylist of
+ // Expressions (with types) or `true' for the constructor constraint.
+ //
+ public Constraints (string type_parameter, ArrayList constraints)
+ {
+ this.type_parameter = type_parameter;
+ this.constraints = constraints;
+ }
+ }
+
+ //
+ // This type represents a generic type parameter reference.
+ //
+ // These expressions are born in a fully resolved state.
+ //
+ public class TypeParameterExpr : TypeExpr {
+ string type_parameter;
+
+ public TypeParameterExpr (string type_parameter, Location l)
+ : base (typeof (object), l)
+ {
+ this.type_parameter = type_parameter;
+ }
+
+ public override string ToString ()
+ {
+ return "TypeParameter[" + type_parameter + "]";
+ }
+
+ public void Error_CannotUseAsUnmanagedType (Location loc)
+ {
+ Report.Error (-203, loc, "Can not use type parameter as unamanged type");
+ }
+ }
+}
--- /dev/null
+//
+// GenericParser.cs: The Base Parser for the Mono compilers
+//
+// Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)
+//
+// Licensed under the terms of the GNU GPL
+//
+// Copyright (C) 2001 Ximian, Inc.
+//
+using System;
+using System.Text;
+
+namespace Mono.Languages
+{
+ using System.Collections;
+
+ /// <summary>
+ /// Base class to support multiple Jay generated parsers
+ /// </summary>
+ public abstract class GenericParser
+ {
+ // Name of the file we are parsing
+ public string name;
+
+ // Input stream to parse from.
+ public System.IO.Stream input;
+
+ public abstract void parse ();
+
+ public virtual string[] extensions()
+ {
+ string [] list = { ".cs" };
+ return list;
+ }
+
+ public GenericParser()
+ {
+ //
+ // DO NOTHING: Derived classes should do their iniatilization here duties
+ //
+ }
+
+ protected bool yacc_verbose_flag = false;
+
+ public bool yacc_verbose
+ {
+ set
+ {
+ yacc_verbose_flag = value;
+ }
+
+ get
+ {
+ return yacc_verbose_flag;
+ }
+ }
+ }
+}
+
+
+
--- /dev/null
+//
+// interface.cs: Interface handler
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+//
+#define CACHE
+using System.Collections;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Interfaces
+ /// </summary>
+ public class Interface : DeclSpace, IMemberContainer {
+ const MethodAttributes interface_method_attributes =
+ MethodAttributes.Public |
+ MethodAttributes.Abstract |
+ MethodAttributes.HideBySig |
+ MethodAttributes.NewSlot |
+ MethodAttributes.Virtual;
+
+ const MethodAttributes property_attributes =
+ MethodAttributes.Public |
+ MethodAttributes.Abstract |
+ MethodAttributes.HideBySig |
+ MethodAttributes.NewSlot |
+ MethodAttributes.SpecialName |
+ MethodAttributes.Virtual;
+
+ ArrayList bases;
+
+ ArrayList defined_method;
+ ArrayList defined_indexer;
+ ArrayList defined_events;
+ ArrayList defined_properties;
+
+ ArrayList method_builders;
+ ArrayList property_builders;
+ ArrayList event_builders;
+
+ Attributes OptAttributes;
+
+ public string IndexerName;
+
+ IMemberContainer parent_container;
+ MemberCache member_cache;
+
+ bool members_defined;
+
+ // These will happen after the semantic analysis
+
+ // Hashtable defined_indexers;
+ // Hashtable defined_methods;
+
+ /// <summary>
+ /// Modifiers allowed in a class declaration
+ /// </summary>
+ public const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.UNSAFE |
+ Modifiers.PRIVATE;
+
+ public Interface (TypeContainer parent, string name, int mod, Attributes attrs, Location l)
+ : base (parent, name, l)
+ {
+ ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
+ OptAttributes = attrs;
+
+ method_builders = new ArrayList ();
+ property_builders = new ArrayList ();
+ event_builders = new ArrayList ();
+ }
+
+ public AdditionResult AddMethod (InterfaceMethod imethod)
+ {
+ string name = imethod.Name;
+ Object value = defined_names [name];
+
+ if (value != null){
+ if (!(value is InterfaceMethod))
+ return AdditionResult.NameExists;
+ }
+
+ if (defined_method == null)
+ defined_method = new ArrayList ();
+
+ defined_method.Add (imethod);
+ if (value == null)
+ DefineName (name, imethod);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddProperty (InterfaceProperty iprop)
+ {
+ AdditionResult res;
+ string name = iprop.Name;
+
+ if ((res = IsValid (name, name)) != AdditionResult.Success)
+ return res;
+
+ DefineName (name, iprop);
+
+ if (defined_properties == null)
+ defined_properties = new ArrayList ();
+
+ defined_properties.Add (iprop);
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddEvent (InterfaceEvent ievent)
+ {
+ string name = ievent.Name;
+ AdditionResult res;
+
+ if ((res = IsValid (name, name)) != AdditionResult.Success)
+ return res;
+
+ DefineName (name, ievent);
+
+ if (defined_events == null)
+ defined_events = new ArrayList ();
+
+ defined_events.Add (ievent);
+ return AdditionResult.Success;
+ }
+
+ public bool AddIndexer (InterfaceIndexer iindexer)
+ {
+ if (defined_indexer == null)
+ defined_indexer = new ArrayList ();
+
+ defined_indexer.Add (iindexer);
+ return true;
+ }
+
+ public ArrayList InterfaceMethods {
+ get {
+ return defined_method;
+ }
+ }
+
+ public ArrayList InterfaceProperties {
+ get {
+ return defined_properties;
+ }
+ }
+
+ public ArrayList InterfaceEvents {
+ get {
+ return defined_events;
+ }
+ }
+
+ public ArrayList InterfaceIndexers {
+ get {
+ return defined_indexer;
+ }
+ }
+
+ public ArrayList Bases {
+ get {
+ return bases;
+ }
+
+ set {
+ bases = value;
+ }
+ }
+
+ public virtual TypeAttributes InterfaceAttr {
+ get {
+ TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
+
+ if (IsTopLevel == false) {
+
+ if ((ModFlags & Modifiers.PROTECTED) != 0
+ && (ModFlags & Modifiers.INTERNAL) != 0)
+ x |= TypeAttributes.NestedFamORAssem;
+ else if ((ModFlags & Modifiers.PROTECTED) != 0)
+ x |= TypeAttributes.NestedFamily;
+ else if ((ModFlags & Modifiers.INTERNAL) != 0)
+ x |= TypeAttributes.NestedAssembly;
+ else if ((ModFlags & Modifiers.PUBLIC) != 0)
+ x |= TypeAttributes.NestedPublic;
+ else
+ x |= TypeAttributes.NestedPrivate;
+ } else {
+ if ((ModFlags & Modifiers.PUBLIC) != 0)
+ x |= TypeAttributes.Public;
+ else if ((ModFlags & Modifiers.PRIVATE) != 0)
+ x |= TypeAttributes.NotPublic;
+ }
+
+ if ((ModFlags & Modifiers.ABSTRACT) != 0)
+ x |= TypeAttributes.Abstract;
+
+ if ((ModFlags & Modifiers.SEALED) != 0)
+ x |= TypeAttributes.Sealed;
+
+ return x;
+ }
+ }
+
+ void Error111 (InterfaceMemberBase ib)
+ {
+ Report.Error (
+ 111,
+ "Interface `" + Name + "' already contains a definition with the " +
+ "same return value and parameter types for member `" + ib.Name + "'");
+ }
+
+ bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
+ {
+ if (!TypeManager.RegisterMethod (mb, ip, types))
+ return false;
+
+ method_builders.Add (mb);
+ return true;
+ }
+
+ //
+ // This might trigger a definition of the methods. This happens only
+ // with Attributes, as Attribute classes are processed before interfaces.
+ // Ideally, we should make everything just define recursively in terms
+ // of its dependencies.
+ //
+ public MethodInfo [] GetMethods (TypeContainer container)
+ {
+ int n = 0;
+
+ if (!members_defined){
+ if (DefineMembers (container))
+ n = method_builders.Count;
+ } else
+ n = method_builders.Count;
+
+ MethodInfo [] mi = new MethodInfo [n];
+
+ method_builders.CopyTo (mi, 0);
+
+ return mi;
+ }
+
+ // Hack around System.Reflection as found everywhere else
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList ();
+
+ if ((mt & MemberTypes.Method) != 0) {
+ foreach (MethodBuilder mb in method_builders)
+ if (filter (mb, criteria))
+ members.Add (mb);
+ }
+
+ if ((mt & MemberTypes.Property) != 0) {
+ foreach (PropertyBuilder pb in property_builders)
+ if (filter (pb, criteria))
+ members.Add (pb);
+ }
+
+ if ((mt & MemberTypes.Event) != 0) {
+ foreach (MyEventBuilder eb in event_builders)
+ if (filter (eb, criteria))
+ members.Add (eb);
+ }
+
+ if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
+ MemberList parent_mi;
+
+ parent_mi = TypeContainer.FindMembers (
+ TypeBuilder.BaseType, mt, bf, filter, criteria);
+
+ members.AddRange (parent_mi);
+ }
+
+ return new MemberList (members);
+ }
+
+ public override MemberCache MemberCache {
+ get {
+ return member_cache;
+ }
+ }
+
+ //
+ // Populates the methods in the interface
+ //
+ void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
+ {
+ Type return_type = im.ReturnType.Type;
+ if (return_type == null)
+ return_type = this.ResolveType (im.ReturnType, false, im.Location);
+
+ Type [] arg_types = im.ParameterTypes (this);
+ MethodBuilder mb;
+ Parameter [] p;
+ int i;
+
+ if (return_type == null)
+ return;
+
+ if (return_type.IsPointer && !UnsafeOK (this))
+ return;
+
+ if (arg_types == null)
+ return;
+
+ foreach (Type t in arg_types){
+
+ if (t == null)
+ return;
+
+ if (t.IsPointer && !UnsafeOK (this))
+ return;
+ }
+
+ //
+ // Create the method
+ //
+ mb = TypeBuilder.DefineMethod (
+ im.Name, interface_method_attributes,
+ return_type, arg_types);
+
+ InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
+
+ if (!RegisterMethod (mb, ip, arg_types)) {
+ Error111 (im);
+ return;
+ }
+
+ //
+ // Define each type attribute (in/out/ref) and
+ // the argument names.
+ //
+ p = im.Parameters.FixedParameters;
+ if (p != null){
+ for (i = 0; i < p.Length; i++)
+ mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
+
+ if (i != arg_types.Length)
+ Console.WriteLine ("Implement the type definition for params");
+ }
+
+ EmitContext ec = new EmitContext (parent, decl_space, Location, null,
+ return_type, ModFlags, false);
+
+ if (im.OptAttributes != null)
+ Attribute.ApplyAttributes (ec, mb, im, im.OptAttributes);
+ }
+
+ //
+ // Populates the properties in the interface
+ //
+ void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
+ {
+ PropertyBuilder pb;
+ MethodBuilder get = null, set = null;
+ ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
+ if (ip.Type == null)
+ return;
+
+ Type prop_type = ip.Type.Type;
+ Type [] setter_args = new Type [1];
+
+ if (prop_type == null)
+ return;
+
+ if (prop_type.IsPointer && !UnsafeOK (this))
+ return;
+
+ setter_args [0] = prop_type;
+
+ //
+ // FIXME: properties are missing the following
+ // flags: hidebysig newslot specialname
+ //
+ pb = TypeBuilder.DefineProperty (
+ ip.Name, PropertyAttributes.None,
+ prop_type, null);
+
+ if (ip.HasGet){
+ get = TypeBuilder.DefineMethod (
+ "get_" + ip.Name, property_attributes ,
+ prop_type, null);
+
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ Type [] null_types = null;
+ InternalParameters inp = new InternalParameters
+ (null_types, Parameters.EmptyReadOnlyParameters);
+
+ if (!RegisterMethod (get, inp, null)) {
+ Error111 (ip);
+ return;
+ }
+
+ pb.SetGetMethod (get);
+ }
+
+ if (ip.HasSet){
+ setter_args [0] = prop_type;
+
+ set = TypeBuilder.DefineMethod (
+ "set_" + ip.Name, property_attributes,
+ TypeManager.void_type, setter_args);
+
+ set.DefineParameter (1, ParameterAttributes.None, "value");
+ pb.SetSetMethod (set);
+
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ Parameter [] parms = new Parameter [1];
+ parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
+ InternalParameters ipp = new InternalParameters (
+ this, new Parameters (parms, null, Location.Null));
+
+ if (!RegisterMethod (set, ipp, setter_args)) {
+ Error111 (ip);
+ return;
+ }
+ }
+
+ EmitContext ec = new EmitContext (parent, decl_space, Location, null,
+ null, ModFlags, false);
+
+ if (ip.OptAttributes != null)
+ Attribute.ApplyAttributes (ec, pb, ip, ip.OptAttributes);
+
+ TypeManager.RegisterProperty (pb, get, set);
+ property_builders.Add (pb);
+ }
+
+ //
+ // Populates the events in the interface
+ //
+ void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
+ {
+ //
+ // FIXME: We need to do this after delegates have been
+ // declared or we declare them recursively.
+ //
+ MyEventBuilder eb;
+ MethodBuilder add = null, remove = null;
+ ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
+ if (ie.Type == null)
+ return;
+
+ Type event_type = ie.Type.Type;
+
+ if (event_type == null)
+ return;
+
+ if (event_type.IsPointer && !UnsafeOK (this))
+ return;
+
+ Type [] parameters = new Type [1];
+ parameters [0] = event_type;
+
+ eb = new MyEventBuilder (null, TypeBuilder, ie.Name,
+ EventAttributes.None, event_type);
+
+ //
+ // Now define the accessors
+ //
+ string add_name = "add_" + ie.Name;
+
+ add = TypeBuilder.DefineMethod (
+ add_name, property_attributes, null, parameters);
+ add.DefineParameter (1, ParameterAttributes.None, "value");
+ eb.SetAddOnMethod (add);
+
+ string remove_name = "remove_" + ie.Name;
+ remove = TypeBuilder.DefineMethod (
+ remove_name, property_attributes, null, parameters);
+ remove.DefineParameter (1, ParameterAttributes.None, "value");
+ eb.SetRemoveOnMethod (remove);
+
+ Parameter [] parms = new Parameter [1];
+ parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
+ InternalParameters ip = new InternalParameters (
+ this, new Parameters (parms, null, Location.Null));
+
+ if (!RegisterMethod (add, ip, parameters)) {
+ Error111 (ie);
+ return;
+ }
+
+ if (!RegisterMethod (remove, ip, parameters)) {
+ Error111 (ie);
+ return;
+ }
+
+ EmitContext ec = new EmitContext (parent, decl_space, Location, null,
+ null, ModFlags, false);
+
+
+ if (ie.OptAttributes != null)
+ Attribute.ApplyAttributes (ec, eb, ie, ie.OptAttributes);
+
+ TypeManager.RegisterEvent (eb, add, remove);
+ event_builders.Add (eb);
+ }
+
+ //
+ // Populates the indexers in the interface
+ //
+ void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
+ {
+ PropertyBuilder pb;
+ ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
+ if (ii.Type == null)
+ return;
+
+ Type prop_type = ii.Type.Type;
+ Type [] arg_types = ii.ParameterTypes (this);
+ Type [] value_arg_types;
+
+ if (prop_type == null)
+ return;
+
+ if (prop_type.IsPointer && !UnsafeOK (this))
+ return;
+
+ //
+ // Sets up the extra invisible `value' argument for setters.
+ //
+ if (arg_types != null){
+ int count = arg_types.Length;
+ value_arg_types = new Type [count + 1];
+
+ arg_types.CopyTo (value_arg_types, 0);
+ value_arg_types [count] = prop_type;
+
+ foreach (Type t in arg_types){
+ if (t.IsPointer && !UnsafeOK (this))
+ return;
+ }
+ } else {
+ value_arg_types = new Type [1];
+
+ value_arg_types [1] = prop_type;
+ }
+
+ EmitContext ec = new EmitContext (parent, decl_space, Location, null,
+ null, ModFlags, false);
+
+ IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
+ if (IndexerName == null)
+ IndexerName = "Item";
+
+ pb = TypeBuilder.DefineProperty (
+ IndexerName, PropertyAttributes.None,
+ prop_type, arg_types);
+
+ MethodBuilder set_item = null, get_item = null;
+ if (ii.HasGet){
+ Parameter [] p = ii.Parameters.FixedParameters;
+
+ get_item = TypeBuilder.DefineMethod (
+ "get_" + IndexerName, property_attributes,
+ prop_type, arg_types);
+ pb.SetGetMethod (get_item);
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ InternalParameters ip = new InternalParameters (
+ arg_types, ii.Parameters);
+
+ if (!RegisterMethod (get_item, ip, arg_types)) {
+ Error111 (ii);
+ return;
+ }
+
+ if (p != null){
+ for (int i = 0; i < p.Length; i++)
+ get_item.DefineParameter (
+ i + 1,
+ p [i].Attributes, p [i].Name);
+ }
+ }
+
+ if (ii.HasSet){
+ Parameter [] p = ii.Parameters.FixedParameters;
+ Parameter [] pv;
+ int i = 0;
+
+ pv = new Parameter [p.Length + 1];
+ p.CopyTo (pv, 0);
+ pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
+ Parameters value_params = new Parameters (pv, null, Location.Null);
+ value_params.GetParameterInfo (decl_space);
+
+ set_item = TypeBuilder.DefineMethod (
+ "set_" + IndexerName, property_attributes,
+ TypeManager.void_type, value_arg_types);
+ pb.SetSetMethod (set_item);
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ InternalParameters ip = new InternalParameters (
+ value_arg_types, value_params);
+ if (!RegisterMethod (set_item, ip, value_arg_types)) {
+ Error111 (ii);
+ return;
+ }
+
+ if (p != null){
+ for (; i < p.Length; i++)
+ set_item.DefineParameter (
+ i + 1,
+ p [i].Attributes, p [i].Name);
+ }
+
+ set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
+ }
+
+ if (ii.OptAttributes != null)
+ Attribute.ApplyAttributes (ec, pb, ii, ii.OptAttributes);
+
+ property_builders.Add (pb);
+ }
+
+ /// <summary>
+ /// Performs the semantic analysis for all the interface members
+ /// that were declared
+ /// </summary>
+ bool SemanticAnalysis ()
+ {
+ Hashtable methods = new Hashtable ();
+
+
+ if (defined_method != null){
+ foreach (InterfaceMethod im in defined_method){
+ string sig = im.GetSignature (this);
+
+ //
+ // If there was an undefined Type on the signatures
+ //
+ if (sig == null)
+ continue;
+
+ if (methods [sig] != null){
+ Error111 (im);
+ return false;
+ }
+ }
+ }
+
+ //
+ // FIXME: Here I should check i
+ //
+ return true;
+ }
+
+ Type GetInterfaceTypeByName (string name)
+ {
+ Type t = FindType (Location, name);
+
+ if (t == null) {
+ Report.Error (246, Location, "The type or namespace `" + name +
+ "' could not be found");
+ return null;
+ }
+
+ if (t.IsInterface)
+ return t;
+
+ string cause;
+
+ if (t.IsValueType)
+ cause = "is a struct";
+ else if (t.IsClass)
+ cause = "is a class";
+ else
+ cause = "Should not happen.";
+
+ Report.Error (527, Location, "`"+name+"' " + cause +
+ ", need an interface instead");
+
+ return null;
+ }
+
+ //
+ // Returns the list of interfaces that this interface implements
+ // Or null if it does not implement any interface.
+ //
+ // Sets the error boolean accoringly.
+ //
+ Type [] GetInterfaceBases (out bool error)
+ {
+ Type [] tbases;
+ int i;
+
+ error = false;
+ if (Bases == null)
+ return null;
+
+ tbases = new Type [Bases.Count];
+ i = 0;
+
+ foreach (string name in Bases){
+ Type t;
+
+ t = GetInterfaceTypeByName (name);
+ if (t == null){
+ error = true;
+ return null;
+ }
+
+ if (!Parent.AsAccessible (t, ModFlags))
+ Report.Error (61, Location,
+ "Inconsistent accessibility: base interface `" +
+ TypeManager.CSharpName (t) + "' is less " +
+ "accessible than interface `" +
+ Name + "'");
+
+ tbases [i++] = t;
+ }
+
+ return TypeManager.ExpandInterfaces (tbases);
+ }
+
+ //
+ // <summary>
+ // Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
+ // </summary>
+ //
+ // TODO:
+ // Rework the way we recurse, because for recursive
+ // definitions of interfaces (A:B and B:A) we report the
+ // error twice, rather than once.
+
+ public override TypeBuilder DefineType ()
+ {
+ Type [] ifaces;
+ bool error;
+
+ if (TypeBuilder != null)
+ return TypeBuilder;
+
+ if (InTransit)
+ return null;
+
+ InTransit = true;
+
+ ifaces = GetInterfaceBases (out error);
+
+ if (error)
+ return null;
+
+ if (IsTopLevel) {
+ if (TypeManager.NamespaceClash (Name, Location))
+ return null;
+
+ ModuleBuilder builder = CodeGen.ModuleBuilder;
+
+ TypeBuilder = builder.DefineType (
+ Name,
+ InterfaceAttr,
+ (Type)null, // Parent Type
+ ifaces);
+ RootContext.RegisterOrder (this);
+ } else {
+ TypeBuilder builder = Parent.TypeBuilder;
+
+ TypeBuilder = builder.DefineNestedType (
+ Basename,
+ InterfaceAttr,
+ (Type) null, //parent type
+ ifaces);
+
+ TypeContainer tc = TypeManager.LookupTypeContainer (builder);
+ tc.RegisterOrder (this);
+ }
+
+ TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
+ InTransit = false;
+
+ return TypeBuilder;
+ }
+
+ //
+ // Defines the indexers, and also verifies that the IndexerNameAttribute in the
+ // interface is consistent. Either it is `Item' or it is the name defined by all the
+ // indexers with the `IndexerName' attribute.
+ //
+ // Turns out that the IndexerNameAttribute is applied to each indexer,
+ // but it is never emitted, instead a DefaultName attribute is attached
+ // to the interface
+ //
+ void DefineIndexers (TypeContainer parent)
+ {
+ string interface_indexer_name = null;
+
+ foreach (InterfaceIndexer ii in defined_indexer){
+
+ PopulateIndexer (parent, this, ii);
+
+ if (interface_indexer_name == null){
+ interface_indexer_name = IndexerName;
+ continue;
+ }
+
+ if (IndexerName == interface_indexer_name)
+ continue;
+
+ Report.Error (
+ 668, "Two indexers have different names, " +
+ " you should use the same name for all your indexers");
+ }
+ if (interface_indexer_name == null)
+ interface_indexer_name = "Item";
+ IndexerName = interface_indexer_name;
+ }
+
+ /// <summary>
+ /// Performs semantic analysis, and then generates the IL interfaces
+ /// </summary>
+ public override bool DefineMembers (TypeContainer parent)
+ {
+ if (members_defined)
+ return true;
+
+ if (!SemanticAnalysis ())
+ return false;
+
+
+ if (defined_method != null){
+ foreach (InterfaceMethod im in defined_method)
+ PopulateMethod (parent, this, im);
+ }
+
+ if (defined_properties != null){
+ foreach (InterfaceProperty ip in defined_properties)
+ PopulateProperty (parent, this, ip);
+ }
+
+ if (defined_events != null)
+ foreach (InterfaceEvent ie in defined_events)
+ PopulateEvent (parent, this, ie);
+
+ if (defined_indexer != null) {
+ DefineIndexers (parent);
+
+ CustomAttributeBuilder cb = EmitDefaultMemberAttr (
+ parent, IndexerName, ModFlags, Location);
+ if (cb != null)
+ TypeBuilder.SetCustomAttribute (cb);
+ }
+
+#if CACHE
+ if (TypeBuilder.BaseType != null)
+ parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
+
+ member_cache = new MemberCache (this);
+#endif
+ members_defined = true;
+ return true;
+ }
+
+
+ //
+ // In the case of Interfaces, there is nothing to do here
+ //
+ public override bool Define (TypeContainer parent)
+ {
+ return true;
+ }
+
+ /// <summary>
+ /// Applies all the attributes.
+ /// </summary>
+ public void Emit (TypeContainer tc)
+ {
+ if (OptAttributes != null) {
+ EmitContext ec = new EmitContext (tc, this, Location, null, null,
+ ModFlags, false);
+ Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
+ }
+ }
+
+ public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
+ string name,
+ int flags,
+ Location loc)
+ {
+ EmitContext ec = new EmitContext (parent, loc, null, null, flags);
+
+ Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
+ ".ctor", MemberTypes.Constructor,
+ BindingFlags.Public | BindingFlags.Instance,
+ Location.Null);
+
+ if (!(ml is MethodGroupExpr)) {
+ Console.WriteLine ("Internal error !!!!");
+ return null;
+ }
+
+ MethodGroupExpr mg = (MethodGroupExpr) ml;
+
+ MethodBase constructor = mg.Methods [0];
+
+ string [] vals = { name };
+
+ CustomAttributeBuilder cb = null;
+ try {
+ cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
+ } catch {
+ Report.Warning (-100, "Can not set the indexer default member attribute");
+ }
+
+ return cb;
+ }
+
+ //
+ // IMemberContainer
+ //
+
+ string IMemberContainer.Name {
+ get {
+ return Name;
+ }
+ }
+
+ Type IMemberContainer.Type {
+ get {
+ return TypeBuilder;
+ }
+ }
+
+ IMemberContainer IMemberContainer.Parent {
+ get {
+ return parent_container;
+ }
+ }
+
+ MemberCache IMemberContainer.MemberCache {
+ get {
+ return member_cache;
+ }
+ }
+
+ bool IMemberContainer.IsInterface {
+ get {
+ return true;
+ }
+ }
+
+ MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
+ {
+ // Interfaces only contain instance members.
+ if ((bf & BindingFlags.Instance) == 0)
+ return MemberList.Empty;
+ if ((bf & BindingFlags.Public) == 0)
+ return MemberList.Empty;
+
+ ArrayList members = new ArrayList ();
+
+ if ((mt & MemberTypes.Method) != 0)
+ members.AddRange (method_builders);
+
+ if ((mt & MemberTypes.Property) != 0)
+ members.AddRange (property_builders);
+
+ if ((mt & MemberTypes.Event) != 0)
+ members.AddRange (event_builders);
+
+ return new MemberList (members);
+ }
+ }
+
+ public class InterfaceMemberBase {
+ public readonly string Name;
+ public readonly bool IsNew;
+ public Attributes OptAttributes;
+
+ public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
+ {
+ Name = name;
+ IsNew = is_new;
+ OptAttributes = attrs;
+ }
+ }
+
+ public class InterfaceProperty : InterfaceMemberBase {
+ public readonly bool HasSet;
+ public readonly bool HasGet;
+ public readonly Location Location;
+ public Expression Type;
+
+ public InterfaceProperty (Expression type, string name,
+ bool is_new, bool has_get, bool has_set,
+ Attributes attrs, Location loc)
+ : base (name, is_new, attrs)
+ {
+ Type = type;
+ HasGet = has_get;
+ HasSet = has_set;
+ Location = loc;
+ }
+ }
+
+ public class InterfaceEvent : InterfaceMemberBase {
+ public readonly Location Location;
+ public Expression Type;
+
+ public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
+ Location loc)
+ : base (name, is_new, attrs)
+ {
+ Type = type;
+ Location = loc;
+ }
+ }
+
+ public class InterfaceMethod : InterfaceMemberBase {
+ public Expression ReturnType;
+ public readonly Parameters Parameters;
+ public readonly Location Location;
+
+ public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
+ Attributes attrs, Location l)
+ : base (name, is_new, attrs)
+ {
+ this.ReturnType = return_type;
+ this.Parameters = args;
+ Location = l;
+ }
+
+ /// <summary>
+ /// Returns the signature for this interface method
+ /// </summary>
+ public string GetSignature (DeclSpace ds)
+ {
+ ReturnType = ds.ResolveTypeExpr (ReturnType, false, Location);
+ if (ReturnType == null)
+ return null;
+
+ Type ret = ReturnType.Type;
+ string args = Parameters.GetSignature (ds);
+
+ if ((ret == null) || (args == null))
+ return null;
+
+ return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
+ }
+
+ public Type [] ParameterTypes (DeclSpace ds)
+ {
+ return Parameters.GetParameterInfo (ds);
+ }
+ }
+
+ public class InterfaceIndexer : InterfaceMemberBase {
+ public readonly bool HasGet, HasSet;
+ public readonly Parameters Parameters;
+ public readonly Location Location;
+ public Expression Type;
+
+ public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
+ bool is_new, Attributes attrs, Location loc)
+ : base ("", is_new, attrs)
+ {
+ Type = type;
+ Parameters = args;
+ HasGet = do_get;
+ HasSet = do_set;
+ Location = loc;
+ }
+
+ public Type [] ParameterTypes (DeclSpace ds)
+ {
+ return Parameters.GetParameterInfo (ds);
+ }
+ }
+}
--- /dev/null
+//
+// iterators.cs: Support for implementing iterators
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2003 Ximian, Inc.
+//
+// TODO:
+// Flow analysis for Yield.
+// Emit calls to parent object constructor.
+//
+// Generics note:
+// Current should be defined to return T, and IEnumerator.Current returns object
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ public interface IIteratorContainer {
+
+ //
+ // Invoked if a yield statement is found in the body
+ //
+ void SetYields ();
+ }
+
+ public class Yield : Statement {
+ public Expression expr;
+
+ public Yield (Expression expr, Location l)
+ {
+ this.expr = expr;
+ loc = l;
+ }
+
+ public static bool CheckContext (EmitContext ec, Location loc)
+ {
+ if (ec.InFinally){
+ Report.Error (-208, loc, "yield statement can not appear in finally clause");
+ return false;
+ }
+ if (ec.InCatch){
+ Report.Error (-209, loc, "yield statement can not appear in the catch clause");
+ return false;
+ }
+ if (ec.InAnonymousMethod){
+ Report.Error (-209, loc, "yield statement can not appear inside an anonymoud method");
+ return false;
+ }
+
+ //
+ // FIXME: Missing check for Yield inside try block that contains catch clauses
+ //
+ return true;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
+ if (!CheckContext (ec, loc))
+ return false;
+
+ Type iterator_type = IteratorHandler.Current.IteratorType;
+ if (expr.Type != iterator_type){
+ expr = Convert.ImplicitConversionRequired (ec, expr, iterator_type, loc);
+ if (expr == null)
+ return false;
+ }
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ IteratorHandler.Current.MarkYield (ec, expr);
+
+ return false;
+ }
+ }
+
+ public class YieldBreak : Statement {
+
+ public YieldBreak (Location l)
+ {
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (!Yield.CheckContext (ec, loc))
+ return false;
+
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
+ return false;
+ }
+ }
+
+ public class IteratorHandler {
+ //
+ // Points to the current iterator handler, will be probed by
+ // Yield and YieldBreak to get their context information
+ //
+ public static IteratorHandler Current;
+
+ //
+ // The typebuilder to the proxy class we create
+ //
+ TypeBuilder enumerator_proxy_class;
+ TypeBuilder enumerable_proxy_class;
+
+ //
+ // The type of this iterator, object by default.
+ //
+ public Type IteratorType;
+
+ //
+ // The members we create on the proxy class
+ //
+ MethodBuilder move_next_method;
+ MethodBuilder reset_method;
+ MethodBuilder get_current_method;
+ MethodBuilder dispose_method;
+ MethodBuilder getenumerator_method;
+ PropertyBuilder current_property;
+ ConstructorBuilder enumerator_proxy_constructor;
+ ConstructorBuilder enumerable_proxy_constructor;
+
+ //
+ // The PC for the state machine.
+ //
+ FieldBuilder pc_field;
+
+ //
+ // The value computed for Current
+ //
+ FieldBuilder current_field;
+
+ //
+ // Used to reference fields on the container class (instance methods)
+ //
+ public FieldBuilder this_field;
+ public FieldBuilder enumerable_this_field;
+
+ //
+ // References the parameters
+ //
+
+ public FieldBuilder [] parameter_fields;
+ FieldBuilder [] enumerable_parameter_fields;
+
+ //
+ // The state as we generate the iterator
+ //
+ ArrayList resume_labels = new ArrayList ();
+ int pc;
+
+ //
+ // Context from the original method
+ //
+ string name;
+ TypeContainer container;
+ Type return_type;
+ Type [] param_types;
+ InternalParameters parameters;
+ Block original_block;
+ Location loc;
+ int modifiers;
+
+ static int proxy_count;
+ string MakeProxyName ()
+ {
+ return String.Format ("__Proxy_{0}", proxy_count++);
+ }
+
+ public void EmitYieldBreak (ILGenerator ig, bool add_return)
+ {
+ ig.Emit (OpCodes.Ldarg_0);
+ IntConstant.EmitInt (ig, -1);
+ ig.Emit (OpCodes.Stfld, pc_field);
+ if (add_return){
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ret);
+ }
+ }
+
+ void EmitThrowInvalidOp (ILGenerator ig)
+ {
+ ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
+ ig.Emit (OpCodes.Throw);
+ }
+
+ void Create_MoveNext ()
+ {
+ move_next_method = enumerator_proxy_class.DefineMethod (
+ "System.IEnumerator.MoveNext",
+ MethodAttributes.HideBySig | MethodAttributes.NewSlot |
+ MethodAttributes.Virtual,
+ CallingConventions.HasThis, TypeManager.bool_type, TypeManager.NoTypes);
+ enumerator_proxy_class.DefineMethodOverride (move_next_method, TypeManager.bool_movenext_void);
+
+ ILGenerator ig = move_next_method.GetILGenerator ();
+ EmitContext ec = new EmitContext (
+ container, loc, ig,
+ TypeManager.void_type, modifiers);
+
+ Label dispatcher = ig.DefineLabel ();
+ ig.Emit (OpCodes.Br, dispatcher);
+ Label entry_point = ig.DefineLabel ();
+ ig.MarkLabel (entry_point);
+ resume_labels.Add (entry_point);
+
+ Current = this;
+ SymbolWriter sw = CodeGen.SymbolWriter;
+ if ((sw != null) && !Location.IsNull (loc) && !Location.IsNull (original_block.EndLocation)) {
+ sw.OpenMethod (container, move_next_method, loc, original_block.EndLocation);
+
+ ec.EmitTopBlock (original_block, parameters, loc);
+
+ sw.CloseMethod ();
+ } else {
+ ec.EmitTopBlock (original_block, parameters, loc);
+ }
+ Current = null;
+
+ EmitYieldBreak (ig, true);
+
+ //
+ // FIXME: Split the switch in blocks that can be consumed by switch.
+ //
+ ig.MarkLabel (dispatcher);
+
+ Label [] labels = new Label [resume_labels.Count];
+ resume_labels.CopyTo (labels);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, pc_field);
+ ig.Emit (OpCodes.Switch, labels);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ret);
+ }
+
+ //
+ // Invoked when a local variable declaration needs to be mapped to
+ // a field in our proxy class
+ //
+ public FieldBuilder MapVariable (string name, Type t)
+ {
+ return enumerator_proxy_class.DefineField ("v" + name, t, FieldAttributes.Public);
+ }
+
+ void Create_Reset ()
+ {
+ reset_method = enumerator_proxy_class.DefineMethod (
+ "System.IEnumerator.Reset",
+ MethodAttributes.HideBySig | MethodAttributes.NewSlot |
+ MethodAttributes.Virtual,
+ CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
+ enumerator_proxy_class.DefineMethodOverride (reset_method, TypeManager.void_reset_void);
+ ILGenerator ig = reset_method.GetILGenerator ();
+ EmitThrowInvalidOp (ig);
+ }
+
+ void Create_Current ()
+ {
+ get_current_method = enumerator_proxy_class.DefineMethod (
+ "System.IEnumerator.get_Current",
+ MethodAttributes.HideBySig | MethodAttributes.SpecialName |
+ MethodAttributes.NewSlot | MethodAttributes.Virtual,
+ CallingConventions.HasThis, TypeManager.object_type, TypeManager.NoTypes);
+ enumerator_proxy_class.DefineMethodOverride (get_current_method, TypeManager.object_getcurrent_void);
+
+ current_property = enumerator_proxy_class.DefineProperty (
+ "Current",
+ PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
+ TypeManager.object_type, null);
+
+ current_property.SetGetMethod (get_current_method);
+
+ ILGenerator ig = get_current_method.GetILGenerator ();
+
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, pc_field);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ Label return_current = ig.DefineLabel ();
+ ig.Emit (OpCodes.Bgt, return_current);
+ EmitThrowInvalidOp (ig);
+
+ ig.MarkLabel (return_current);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, current_field);
+ ig.Emit (OpCodes.Ret);
+ }
+
+ void Create_Dispose ()
+ {
+ dispose_method = enumerator_proxy_class.DefineMethod (
+ "System.IDisposable.Dispose",
+ MethodAttributes.HideBySig | MethodAttributes.SpecialName |
+ MethodAttributes.NewSlot | MethodAttributes.Virtual,
+ CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
+ enumerator_proxy_class.DefineMethodOverride (dispose_method, TypeManager.void_dispose_void);
+ ILGenerator ig = dispose_method.GetILGenerator ();
+
+ EmitYieldBreak (ig, false);
+ ig.Emit (OpCodes.Ret);
+ }
+
+ void Create_GetEnumerator ()
+ {
+ getenumerator_method = enumerable_proxy_class.DefineMethod (
+ "IEnumerable.GetEnumerator",
+ MethodAttributes.HideBySig | MethodAttributes.SpecialName |
+ MethodAttributes.NewSlot | MethodAttributes.Virtual,
+ CallingConventions.HasThis, TypeManager.ienumerator_type, TypeManager.NoTypes);
+
+ enumerable_proxy_class.DefineMethodOverride (getenumerator_method, TypeManager.ienumerable_getenumerator_void);
+ ILGenerator ig = getenumerator_method.GetILGenerator ();
+
+ if (enumerable_this_field != null){
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, enumerable_this_field);
+ }
+ for (int i = 0; i < parameters.Count; i++){
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
+ }
+ ig.Emit (OpCodes.Newobj, (ConstructorInfo) enumerator_proxy_constructor);
+ ig.Emit (OpCodes.Ret);
+ }
+
+ void LoadArgs (ILGenerator ig)
+ {
+ int count = parameters.Count;
+ if ((modifiers & Modifiers.STATIC) == 0)
+ count++;
+
+ for (int i = 0; i < count; i++)
+ ParameterReference.EmitLdArg (ig, i);
+ }
+
+ //
+ // Called back from Yield
+ //
+ public void MarkYield (EmitContext ec, Expression expr)
+ {
+ ILGenerator ig = ec.ig;
+
+ // Store the new current
+ ig.Emit (OpCodes.Ldarg_0);
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Stfld, current_field);
+
+ // increment pc
+ pc++;
+ ig.Emit (OpCodes.Ldarg_0);
+ IntConstant.EmitInt (ig, pc);
+ ig.Emit (OpCodes.Stfld, pc_field);
+
+ // Return ok.
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Ret);
+
+ Label resume_point = ig.DefineLabel ();
+ ig.MarkLabel (resume_point);
+ resume_labels.Add (resume_point);
+ }
+
+ void ComputeConstructorTypes (out Type [] constructor_types, out Parameters constructor_parameters)
+ {
+ bool is_static = (modifiers & Modifiers.STATIC) != 0;
+
+ if (is_static && parameters.Count == 0){
+ constructor_types = TypeManager.NoTypes;
+ constructor_parameters = Parameters.EmptyReadOnlyParameters;
+ return;
+ }
+
+ int count = (is_static ? 0 : 1) + parameters.Count;
+ constructor_types = new Type [count];
+ Parameter [] pars = new Parameter [count];
+ constructor_parameters = new Parameters (pars, null, loc);
+
+ int i = 0;
+ if (!is_static){
+ constructor_types [0] = container.TypeBuilder;
+
+ Parameter THIS = new Parameter (
+ new TypeExpr (container.TypeBuilder, loc), "this", Parameter.Modifier.NONE, null);
+ pars [0] = THIS;
+ i++;
+ }
+
+ for (int j = 0; j < parameters.Count; j++, i++){
+ Type partype = parameters.ParameterType (j);
+
+ pars [i] = new Parameter (new TypeExpr (partype, loc),
+ parameters.ParameterName (j),
+ Parameter.Modifier.NONE, null);
+ constructor_types [i] = partype;
+ }
+ }
+
+ //
+ // Creates the IEnumerator Proxy class
+ //
+ void MakeEnumeratorProxy ()
+ {
+ Type [] proxy_base_interfaces = new Type [2];
+ proxy_base_interfaces [0] = TypeManager.ienumerator_type;
+ proxy_base_interfaces [1] = TypeManager.idisposable_type;
+ TypeBuilder container_builder = container.TypeBuilder;
+
+ //
+ // Create the class
+ //
+ enumerator_proxy_class = container_builder.DefineNestedType (
+ MakeProxyName (), TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
+ TypeManager.object_type, proxy_base_interfaces);
+
+ TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
+
+ //
+ // Define our fields
+ //
+ pc_field = enumerator_proxy_class.DefineField ("PC", TypeManager.int32_type, FieldAttributes.Private);
+ current_field = enumerator_proxy_class.DefineField ("current", IteratorType, FieldAttributes.Private);
+ if ((modifiers & Modifiers.STATIC) == 0)
+ this_field = enumerator_proxy_class.DefineField ("THIS", container.TypeBuilder, FieldAttributes.Private);
+
+ parameter_fields = new FieldBuilder [parameters.Count];
+ for (int i = 0; i < parameters.Count; i++){
+ parameter_fields [i] = enumerator_proxy_class.DefineField (
+ String.Format ("p{0}_{1}", i, parameters.ParameterName (i)),
+ parameters.ParameterType (i), FieldAttributes.Private);
+ }
+
+ //
+ // Define a constructor
+ //
+ // FIXME: currently its parameterless
+ Type [] constructor_types;
+ Parameters constructor_parameters;
+
+ ComputeConstructorTypes (out constructor_types, out constructor_parameters);
+
+ enumerator_proxy_constructor = enumerator_proxy_class.DefineConstructor (
+ MethodAttributes.Public | MethodAttributes.HideBySig |
+ MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
+ CallingConventions.HasThis, constructor_types);
+ InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
+ TypeManager.RegisterMethod (enumerator_proxy_constructor, parameter_info, constructor_types);
+
+ //
+ // Our constructor
+ //
+ ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+
+ int arg_start;
+ if (this_field != null){
+ arg_start = 2;
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldarg_1);
+ ig.Emit (OpCodes.Stfld, this_field);
+ } else {
+ arg_start = 1;
+ }
+ for (int i = 0; i < parameters.Count; i++){
+ ig.Emit (OpCodes.Ldarg_0);
+ ParameterReference.EmitLdArg (ig, i + arg_start);
+ ig.Emit (OpCodes.Stfld, parameter_fields [i]);
+ }
+ ig.Emit (OpCodes.Ret);
+ }
+
+ //
+ // Creates the IEnumerable proxy class
+ //
+ void MakeEnumerableProxy ()
+ {
+ TypeBuilder container_builder = container.TypeBuilder;
+ Type [] proxy_base_interfaces = new Type [1];
+ proxy_base_interfaces [0] = TypeManager.ienumerable_type;
+
+ //
+ // Creates the Enumerable proxy class.
+ //
+ enumerable_proxy_class = container_builder.DefineNestedType (
+ MakeProxyName (), TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
+ TypeManager.object_type, proxy_base_interfaces);
+
+ //
+ // Constructor
+ //
+ Type [] constructor_types;
+ Parameters constructor_parameters;
+
+ ComputeConstructorTypes (out constructor_types, out constructor_parameters);
+ if ((modifiers & Modifiers.STATIC) == 0){
+ enumerable_this_field = enumerable_proxy_class.DefineField (
+ "THIS", container.TypeBuilder, FieldAttributes.Private);
+ }
+ enumerable_parameter_fields = new FieldBuilder [parameters.Count];
+ for (int i = 0; i < parameters.Count; i++){
+ enumerable_parameter_fields [i] = enumerable_proxy_class.DefineField (
+ String.Format ("p{0}_{1}", i, parameters.ParameterName (i)),
+ parameters.ParameterType (i), FieldAttributes.Private);
+ }
+
+ enumerable_proxy_constructor = enumerable_proxy_class.DefineConstructor (
+ MethodAttributes.Public | MethodAttributes.HideBySig |
+ MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
+ CallingConventions.HasThis, constructor_types);
+ InternalParameters parameter_info = new InternalParameters (constructor_types, constructor_parameters);
+ TypeManager.RegisterMethod (enumerable_proxy_constructor, parameter_info, constructor_types);
+
+ ILGenerator ig = enumerable_proxy_constructor.GetILGenerator ();
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+
+ int first_arg;
+ if (enumerable_this_field != null){
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldarg_1);
+ ig.Emit (OpCodes.Stfld, enumerable_this_field);
+ first_arg = 2;
+ } else
+ first_arg = 1;
+
+ for (int i = 0; i < parameters.Count; i++){
+ ig.Emit (OpCodes.Ldarg_0);
+ ParameterReference.EmitLdArg (ig, i + first_arg);
+ ig.Emit (OpCodes.Stfld, enumerable_parameter_fields [i]);
+ }
+ ig.Emit (OpCodes.Ret);
+ }
+
+ //
+ // Populates the Enumerator Proxy class
+ //
+ void PopulateProxy ()
+ {
+ RootContext.RegisterHelperClass (enumerator_proxy_class);
+
+ Create_MoveNext ();
+ Create_Reset ();
+ Create_Current ();
+ Create_Dispose ();
+
+ if (return_type == TypeManager.ienumerable_type){
+ Create_GetEnumerator ();
+ RootContext.RegisterHelperClass (enumerable_proxy_class);
+ }
+ }
+
+
+ //
+ // This is invoked by the EmitCode hook
+ //
+ void SetupIterator ()
+ {
+ PopulateProxy ();
+ }
+
+ //
+ // Our constructor
+ //
+ public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
+ InternalParameters parameters, int modifiers, Location loc)
+ {
+ this.name = name;
+ this.container = container;
+ this.return_type = return_type;
+ this.param_types = param_types;
+ this.parameters = parameters;
+ this.modifiers = modifiers;
+ this.loc = loc;
+
+ IteratorType = TypeManager.object_type;
+
+ RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
+ }
+
+ //
+ // This class is just an expression that evaluates to a type, and the
+ // type is our internal proxy class. Used in the generated new body
+ // of the original method
+ //
+ class NewInnerType : Expression {
+ IteratorHandler handler;
+
+ public NewInnerType (IteratorHandler handler, Location l)
+ {
+ this.handler = handler;
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // Create the proxy class type.
+ handler.MakeEnumeratorProxy ();
+
+ if (handler.return_type == TypeManager.ienumerable_type)
+ handler.MakeEnumerableProxy ();
+
+ type = handler.return_type;
+ return this;
+ }
+
+ public override Expression ResolveAsTypeStep (EmitContext ec)
+ {
+ return DoResolve (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ handler.LoadArgs (ec.ig);
+
+ if (handler.return_type == TypeManager.ienumerable_type)
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerable_proxy_constructor);
+ else
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerator_proxy_constructor);
+ }
+ }
+
+ //
+ // This return statement tricks return into not flagging an error for being
+ // used in a Yields method
+ //
+ class NoCheckReturn : Return {
+ public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
+ {
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ ec.InIterator = false;
+ bool ret_val = base.Resolve (ec);
+ ec.InIterator = true;
+
+ return ret_val;
+ }
+ }
+
+ //
+ // Returns the new block for the method, or null on failure
+ //
+ public Block Setup (Block block)
+ {
+ if (return_type != TypeManager.ienumerator_type &&
+ return_type != TypeManager.ienumerable_type){
+ Report.Error (
+ -205, loc, String.Format (
+ "The method `{0}' contains a yield statement, but has an invalid return type for an iterator",
+ name));
+ return null;
+ }
+
+ for (int i = 0; i < parameters.Count; i++){
+ Parameter.Modifier mod = parameters.ParameterModifier (i);
+ if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
+ Report.Error (-207, loc, String.Format (
+ "Parameter {0} of `{1}' is {2} and not allowed for an iterator method",
+ i+1, name, parameters.ParameterDesc (i)));
+ return null;
+ }
+ }
+
+ original_block = block;
+ Block b = new Block (null);
+
+ // return new InnerClass ()
+ b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
+ return b;
+ }
+ }
+}
+
--- /dev/null
+//
+// literal.cs: Literal representation for the IL tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+//
+// Notice that during parsing we create objects of type Literal, but the
+// types are not loaded (thats why the Resolve method has to assign the
+// type at that point).
+//
+// Literals differ from the constants in that we know we encountered them
+// as a literal in the source code (and some extra rules apply there) and
+// they have to be resolved (since during parsing we have not loaded the
+// types yet) while constants are created only after types have been loaded
+// and are fully resolved when born.
+//
+
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ public class NullLiteral : Constant {
+ public static readonly NullLiteral Null;
+
+ static NullLiteral ()
+ {
+ Null = new NullLiteral ();
+ }
+
+ public NullLiteral ()
+ {
+ eclass = ExprClass.Value;
+ }
+
+ override public string AsString ()
+ {
+ return "null";
+ }
+
+ public override object GetValue ()
+ {
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.object_type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldnull);
+ }
+ }
+
+ //
+ // A null literal in a pointer context
+ //
+ public class NullPointer : NullLiteral {
+ public new static readonly NullLiteral Null;
+
+ static NullPointer ()
+ {
+ Null = new NullPointer ();
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Conv_U);
+ }
+ }
+
+ public class BoolLiteral : BoolConstant {
+ public BoolLiteral (bool val) : base (val)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.bool_type;
+ return this;
+ }
+ }
+
+ public class CharLiteral : CharConstant {
+ public CharLiteral (char c) : base (c)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.char_type;
+ return this;
+ }
+ }
+
+ public class IntLiteral : IntConstant {
+ public IntLiteral (int l) : base (l)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.int32_type;
+ return this;
+ }
+ }
+
+ public class UIntLiteral : UIntConstant {
+ public UIntLiteral (uint l) : base (l)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.uint32_type;
+ return this;
+ }
+ }
+
+ public class LongLiteral : LongConstant {
+ public LongLiteral (long l) : base (l)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.int64_type;
+
+ return this;
+ }
+ }
+
+ public class ULongLiteral : ULongConstant {
+ public ULongLiteral (ulong l) : base (l)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.uint64_type;
+ return this;
+ }
+ }
+
+ public class FloatLiteral : FloatConstant {
+
+ public FloatLiteral (float f) : base (f)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.float_type;
+ return this;
+ }
+ }
+
+ public class DoubleLiteral : DoubleConstant {
+ public DoubleLiteral (double d) : base (d)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.double_type;
+
+ return this;
+ }
+ }
+
+ public class DecimalLiteral : DecimalConstant {
+ public DecimalLiteral (decimal d) : base (d)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.decimal_type;
+ return this;
+ }
+ }
+
+ public class StringLiteral : StringConstant {
+ public StringLiteral (string s) : base (s)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.string_type;
+
+ return this;
+ }
+ }
+}
--- /dev/null
+//
+// location.cs: Keeps track of the location of source code entity
+//
+// Author:
+// Miguel de Icaza
+//
+// (C) 2001 Ximian, Inc.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Diagnostics.SymbolStore;
+
+namespace Mono.CSharp {
+ /// <summary>
+ /// This is one single source file.
+ /// </summary>
+ /// <remarks>
+ /// This is intentionally a class and not a struct since we need
+ /// to pass this by reference.
+ /// </remarks>
+ public sealed class SourceFile {
+ public readonly string Name;
+ public readonly string Path;
+ public readonly int Index;
+ public ISymbolDocumentWriter SymbolDocument;
+
+ public SourceFile (string name, string path, int index)
+ {
+ this.Index = index;
+ this.Name = name;
+ this.Path = path;
+ }
+ }
+
+ /// <summary>
+ /// Keeps track of the location in the program
+ /// </summary>
+ ///
+ /// <remarks>
+ /// This uses a compact representation and a couple of auxiliary
+ /// structures to keep track of tokens to (file,line) mappings.
+ ///
+ /// We could probably also keep track of columns by storing those
+ /// in 8 bits (and say, map anything after char 255 to be `255+').
+ /// </remarks>
+ public struct Location {
+ public int token;
+
+ static ArrayList source_list;
+ static Hashtable source_files;
+ static int source_bits;
+ static int source_mask;
+ static int source_count;
+ static int module_base;
+ static int current_source;
+
+ public readonly static Location Null;
+
+ static Location ()
+ {
+ source_files = new Hashtable ();
+ source_list = new ArrayList ();
+ current_source = 0;
+ module_base = 0;
+ Null.token = 0;
+ }
+
+ // <summary>
+ // This must be called before parsing/tokenizing any files.
+ // </summary>
+ static public void AddFile (string name)
+ {
+ string path = Path.GetFullPath (name);
+
+ if (source_files.Contains (path)){
+ Report.Error (
+ 1516,
+ "Source file `" + name + "' specified multiple times");
+ Environment.Exit (1);
+ }
+
+ source_files.Add (path, ++source_count);
+ source_list.Add (new SourceFile (name, path, source_count));
+ }
+
+ static public SourceFile[] SourceFiles {
+ get {
+ SourceFile[] retval = new SourceFile [source_list.Count];
+ source_list.CopyTo (retval, 0);
+ return retval;
+ }
+ }
+
+ static int log2 (int number)
+ {
+ int bits = 0;
+ while (number > 0) {
+ bits++;
+ number /= 2;
+ }
+
+ return bits;
+ }
+
+ // <summary>
+ // After adding all source files we want to compile with AddFile(), this method
+ // must be called to `reserve' an appropriate number of bits in the token for the
+ // source file. We reserve some extra space for files we encounter via #line
+ // directives while parsing.
+ // </summary>
+ static public void Initialize ()
+ {
+ source_bits = log2 (source_list.Count) + 2;
+ source_mask = (1 << source_bits) - 1;
+ }
+
+ // <remarks>
+ // This is used when we encounter a #line preprocessing directive.
+ // </remarks>
+ static public SourceFile LookupFile (string name)
+ {
+ string path = Path.GetFullPath (name);
+
+ if (!source_files.Contains (path)) {
+ if (source_count >= (1 << source_bits))
+ return new SourceFile (name, path, 0);
+
+ source_files.Add (path, ++source_count);
+ SourceFile retval = new SourceFile (name, path, source_count);
+ source_list.Add (retval);
+ return retval;
+ }
+
+ int index = (int) source_files [path];
+ return (SourceFile) source_list [index - 1];
+ }
+
+ static public void Push (SourceFile file)
+ {
+ current_source = file.Index;
+ module_base = current_source << source_bits;
+ }
+
+ // <remarks>
+ // If we're compiling with debugging support, this is called between parsing and
+ // code generation to register all the source files with the symbol writer. //
+ // </remarks>
+ static public void DefineSymbolDocuments (SymbolWriter symwriter)
+ {
+ foreach (SourceFile file in source_list)
+ file.SymbolDocument = symwriter.DefineDocument (file.Path);
+ }
+
+ public Location (int row)
+ {
+ if (row < 0)
+ token = 0;
+ else
+ token = current_source + (row << source_bits);
+ }
+
+ public override string ToString ()
+ {
+ return Name + ": (" + Row + ")";
+ }
+
+ /// <summary>
+ /// Whether the Location is Null
+ /// </summary>
+ static public bool IsNull (Location l)
+ {
+ return l.token == 0;
+ }
+
+ public string Name {
+ get {
+ int index = token & source_mask;
+ if ((token == 0) || (index == 0))
+ return "Internal";
+
+ SourceFile file = (SourceFile) source_list [index - 1];
+ return file.Name;
+ }
+ }
+
+ public int Row {
+ get {
+ if (token == 0)
+ return 1;
+
+ return token >> source_bits;
+ }
+ }
+
+ public int File {
+ get {
+ return token & source_mask;
+ }
+ }
+
+ // The ISymbolDocumentWriter interface is used by the symbol writer to
+ // describe a single source file - for each source file there's exactly
+ // one corresponding ISymbolDocumentWriter instance.
+ //
+ // This class has an internal hash table mapping source document names
+ // to such ISymbolDocumentWriter instances - so there's exactly one
+ // instance per document.
+ //
+ // This property returns the ISymbolDocumentWriter instance which belongs
+ // to the location's source file.
+ //
+ // If we don't have a symbol writer, this property is always null.
+ public ISymbolDocumentWriter SymbolDocument {
+ get {
+ int index = token & source_mask;
+ if (index == 0)
+ return null;
+ SourceFile file = (SourceFile) source_list [index - 1];
+ return file.SymbolDocument;
+ }
+ }
+ }
+}
--- /dev/null
+<configuration>\r
+ <system.diagnostics>\r
+ <trace autoflush="true" indentsize="4">\r
+ <listeners>\r
+ <add name="compilerLogListener" type="System.Diagnostics.TextWriterTraceListener,System"\r
+ initializeData="mcs.log" />\r
+ <remove type="System.Diagnostics.DefaultTraceListener,System"/>\r
+ </listeners>\r
+ </trace>\r
+ </system.diagnostics>\r
+</configuration>\r
--- /dev/null
+//
+// modifiers.cs: Modifier handling.
+//
+using System;
+using System.Reflection;
+
+namespace Mono.CSharp {
+ public class Modifiers {
+
+ //
+ // The ordering of the following 4 constants
+ // has been carefully done.
+ //
+ public const int PROTECTED = 0x0001;
+ public const int PUBLIC = 0x0002;
+ public const int PRIVATE = 0x0004;
+ public const int INTERNAL = 0x0008;
+ public const int NEW = 0x0010;
+ public const int ABSTRACT = 0x0020;
+ public const int SEALED = 0x0040;
+ public const int STATIC = 0x0080;
+ public const int READONLY = 0x0100;
+ public const int VIRTUAL = 0x0200;
+ public const int OVERRIDE = 0x0400;
+ public const int EXTERN = 0x0800;
+ public const int VOLATILE = 0x1000;
+ public const int UNSAFE = 0x2000;
+ public const int TOP = 0x2000;
+
+ //
+ // We use this internally to flag that the method contains an iterator
+ //
+ public const int METHOD_YIELDS = 0x8000;
+
+ public const int Accessibility =
+ PUBLIC | PROTECTED | INTERNAL | PRIVATE;
+
+ static public string Name (int i)
+ {
+ string s = "";
+
+ switch (i) {
+ case Modifiers.NEW:
+ s = "new"; break;
+ case Modifiers.PUBLIC:
+ s = "public"; break;
+ case Modifiers.PROTECTED:
+ s = "protected"; break;
+ case Modifiers.INTERNAL:
+ s = "internal"; break;
+ case Modifiers.PRIVATE:
+ s = "private"; break;
+ case Modifiers.ABSTRACT:
+ s = "abstract"; break;
+ case Modifiers.SEALED:
+ s = "sealed"; break;
+ case Modifiers.STATIC:
+ s = "static"; break;
+ case Modifiers.READONLY:
+ s = "readonly"; break;
+ case Modifiers.VIRTUAL:
+ s = "virtual"; break;
+ case Modifiers.OVERRIDE:
+ s = "override"; break;
+ case Modifiers.EXTERN:
+ s = "extern"; break;
+ case Modifiers.VOLATILE:
+ s = "volatile"; break;
+ }
+
+ return s;
+ }
+
+ public static TypeAttributes TypeAttr (int mod_flags, bool is_toplevel)
+ {
+ TypeAttributes t = 0;
+
+ if (is_toplevel){
+ if ((mod_flags & PUBLIC) != 0)
+ t |= TypeAttributes.Public;
+ if ((mod_flags & PRIVATE) != 0)
+ t |= TypeAttributes.NotPublic;
+ } else {
+ if ((mod_flags & PUBLIC) != 0)
+ t |= TypeAttributes.NestedPublic;
+ if ((mod_flags & PRIVATE) != 0)
+ t |= TypeAttributes.NestedPrivate;
+ if ((mod_flags & PROTECTED) != 0 && (mod_flags & INTERNAL) != 0)
+ t |= TypeAttributes.NestedFamORAssem;
+ if ((mod_flags & PROTECTED) != 0)
+ t |= TypeAttributes.NestedFamily;
+ if ((mod_flags & INTERNAL) != 0)
+ t |= TypeAttributes.NestedAssembly;
+ }
+
+ if ((mod_flags & SEALED) != 0)
+ t |= TypeAttributes.Sealed;
+ if ((mod_flags & ABSTRACT) != 0)
+ t |= TypeAttributes.Abstract;
+
+ return t;
+ }
+
+ public static TypeAttributes TypeAttr (int mod_flags, TypeContainer caller)
+ {
+ TypeAttributes t = TypeAttr (mod_flags, caller.IsTopLevel);
+
+ // If we do not have static constructors, static methods
+ // can be invoked without initializing the type.
+ if (!caller.HaveStaticConstructor)
+ t |= TypeAttributes.BeforeFieldInit;
+
+ return t;
+ }
+
+ public static FieldAttributes FieldAttr (int mod_flags)
+ {
+ FieldAttributes fa = 0;
+
+ if ((mod_flags & PUBLIC) != 0)
+ fa |= FieldAttributes.Public;
+ if ((mod_flags & PRIVATE) != 0)
+ fa |= FieldAttributes.Private;
+ if ((mod_flags & PROTECTED) != 0){
+ if ((mod_flags & INTERNAL) != 0)
+ fa |= FieldAttributes.FamORAssem;
+ else
+ fa |= FieldAttributes.Family;
+ } else {
+ if ((mod_flags & INTERNAL) != 0)
+ fa |= FieldAttributes.Assembly;
+ }
+
+ if ((mod_flags & STATIC) != 0)
+ fa |= FieldAttributes.Static;
+ if ((mod_flags & READONLY) != 0)
+ fa |= FieldAttributes.InitOnly;
+
+ return fa;
+ }
+
+ public static MethodAttributes MethodAttr (int mod_flags)
+ {
+ MethodAttributes ma = 0;
+
+ if ((mod_flags & PUBLIC) != 0)
+ ma |= MethodAttributes.Public;
+ if ((mod_flags & PRIVATE) != 0)
+ ma |= MethodAttributes.Private;
+ if ((mod_flags & PROTECTED) != 0){
+ if ((mod_flags & INTERNAL) != 0)
+ ma |= MethodAttributes.FamORAssem;
+ else
+ ma |= MethodAttributes.Family;
+ } else {
+ if ((mod_flags & INTERNAL) != 0)
+ ma |= MethodAttributes.Assembly;
+ }
+
+ if ((mod_flags & STATIC) != 0)
+ ma |= MethodAttributes.Static;
+ if ((mod_flags & ABSTRACT) != 0){
+ ma |= MethodAttributes.Abstract | MethodAttributes.Virtual |
+ MethodAttributes.HideBySig;
+ }
+ if ((mod_flags & SEALED) != 0)
+ ma |= MethodAttributes.Final;
+
+ if ((mod_flags & VIRTUAL) != 0)
+ ma |= MethodAttributes.Virtual;
+
+ if ((mod_flags & OVERRIDE) != 0)
+ ma |= MethodAttributes.Virtual | MethodAttributes.HideBySig;
+ else {
+ if ((ma & MethodAttributes.Virtual) != 0)
+ ma |= MethodAttributes.NewSlot;
+ }
+
+ if ((mod_flags & NEW) != 0)
+ ma |= MethodAttributes.HideBySig;
+
+ return ma;
+ }
+
+ // <summary>
+ // Checks the object @mod modifiers to be in @allowed.
+ // Returns the new mask. Side effect: reports any
+ // incorrect attributes.
+ // </summary>
+ public static int Check (int allowed, int mod, int def_access, Location l)
+ {
+ int invalid_flags = (~allowed) & mod;
+ int i;
+
+ if (invalid_flags == 0){
+ int a = mod;
+
+ if ((mod & Modifiers.UNSAFE) != 0){
+ if (!RootContext.Unsafe){
+ Report.Error (227, l,
+ "Unsafe code requires the --unsafe command " +
+ "line option to be specified");
+ }
+ }
+
+ //
+ // If no accessibility bits provided
+ // then provide the defaults.
+ //
+ if ((mod & Accessibility) == 0){
+ mod |= def_access;
+ return mod;
+ }
+
+ //
+ // Make sure that no conflicting accessibility
+ // bits have been set. Protected+Internal is
+ // allowed, that is why they are placed on bits
+ // 1 and 4 (so the shift 3 basically merges them)
+ //
+ a &= 15;
+ a |= (a >> 3);
+ a = ((a & 2) >> 1) + (a & 5);
+ a = ((a & 4) >> 2) + (a & 3);
+ if (a > 1)
+ Report.Error (107, l, "More than one protection modifier specified");
+
+ return mod;
+ }
+
+ for (i = 1; i < TOP; i <<= 1){
+ if ((i & invalid_flags) == 0)
+ continue;
+
+ Error_InvalidModifier (l, Name (i));
+ }
+
+ return allowed & mod;
+ }
+
+ public static void Error_InvalidModifier (Location l, string name)
+ {
+ Report.Error (106, l, "the modifier " + name + " is not valid for this item");
+ }
+ }
+}
--- /dev/null
+//
+// namespace.cs: Tracks namespaces
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+using System;
+using System.Collections;
+using Mono.Languages;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Keeps track of the namespaces defined in the C# code.
+ /// </summary>
+ public class Namespace {
+ static ArrayList all_namespaces = new ArrayList ();
+
+ Namespace parent;
+ string name, fullname;
+ ArrayList entries;
+ Hashtable namespaces;
+
+ /// <summary>
+ /// Constructor Takes the current namespace and the
+ /// name. This is bootstrapped with parent == null
+ /// and name = ""
+ /// </summary>
+ public Namespace (Namespace parent, string name)
+ {
+ this.name = name;
+ this.parent = parent;
+
+ string pname = parent != null ? parent.Name : "";
+
+ if (pname == "")
+ fullname = name;
+ else
+ fullname = parent.Name + "." + name;
+
+ entries = new ArrayList ();
+ namespaces = new Hashtable ();
+
+ all_namespaces.Add (this);
+ }
+
+ public static Namespace Root = new Namespace (null, "");
+
+ 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;
+ }
+
+ public static Namespace LookupNamespace (string name, bool create)
+ {
+ return Root.GetNamespace (name, create);
+ }
+
+ public void AddNamespaceEntry (NamespaceEntry entry)
+ {
+ entries.Add (entry);
+ }
+
+ static public ArrayList UserDefinedNamespaces {
+ get {
+ return all_namespaces;
+ }
+ }
+
+ /// <summary>
+ /// The qualified name of the current namespace
+ /// </summary>
+ public string Name {
+ 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 static void DefineNamespaces (SymbolWriter symwriter)
+ {
+ foreach (Namespace ns in all_namespaces) {
+ foreach (NamespaceEntry entry in ns.entries)
+ entry.DefineNamespace (symwriter);
+ }
+ }
+
+ /// <summary>
+ /// Used to validate that all the using clauses are correct
+ /// after we are finished parsing all the files.
+ /// </summary>
+ public static void VerifyUsing ()
+ {
+ foreach (Namespace ns in all_namespaces) {
+ foreach (NamespaceEntry entry in ns.entries)
+ entry.VerifyUsing ();
+ }
+ }
+
+ public override string ToString ()
+ {
+ if (this == Root)
+ return "Namespace (<root>)";
+ else
+ 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;
+
+ //
+ // 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 {
+ public readonly string Name;
+ public readonly NamespaceEntry NamespaceEntry;
+ public readonly Location Location;
+
+ public UsingEntry (NamespaceEntry entry, string name, Location loc)
+ {
+ Name = name;
+ NamespaceEntry = entry;
+ Location = loc;
+ }
+
+ Namespace resolved_ns;
+
+ public Namespace Resolve ()
+ {
+ if (resolved_ns != null)
+ return resolved_ns;
+
+ Namespace curr_ns = NamespaceEntry.NS;
+ while ((curr_ns != null) && (resolved_ns == null)) {
+ string full_name = DeclSpace.MakeFQN (curr_ns.Name, Name);
+ resolved_ns = curr_ns.GetNamespace (Name, false);
+
+ if (resolved_ns == null)
+ curr_ns = curr_ns.Parent;
+ }
+
+ return resolved_ns;
+ }
+ }
+
+ public class AliasEntry {
+ public readonly string Name;
+ public readonly string Alias;
+ public readonly NamespaceEntry NamespaceEntry;
+ public readonly Location Location;
+
+ public AliasEntry (NamespaceEntry entry, string name, string alias, Location loc)
+ {
+ Name = name;
+ Alias = alias;
+ NamespaceEntry = entry;
+ Location = loc;
+ }
+
+ object resolved;
+
+ public object Resolve ()
+ {
+ if (resolved != null)
+ return resolved;
+
+ int pos = Alias.IndexOf ('.');
+ if (pos >= 0) {
+ string first = Alias.Substring (0, pos);
+ }
+
+ NamespaceEntry curr_ns = NamespaceEntry;
+ while ((curr_ns != null) && (resolved == null)) {
+ string full_name = DeclSpace.MakeFQN (curr_ns.Name, Alias);
+ resolved = curr_ns.LookupName (Alias);
+
+ if (resolved == null)
+ curr_ns = curr_ns.Parent;
+ }
+
+ return resolved;
+ }
+ }
+
+ public NamespaceEntry (NamespaceEntry parent, SourceFile file, string name)
+ : this (parent, file, name, false)
+ { }
+
+ protected NamespaceEntry (NamespaceEntry parent, SourceFile file, string name, bool is_implicit)
+ {
+ this.parent = parent;
+ this.file = file;
+ this.IsImplicit = is_implicit;
+ this.ID = ++next_id;
+
+ if (!is_implicit && (parent != null))
+ ns = parent.NS.GetNamespace (name, true);
+ else if (name != null)
+ ns = Namespace.LookupNamespace (name, true);
+ else
+ ns = Namespace.Root;
+ ns.AddNamespaceEntry (this);
+
+ if ((parent != null) && (parent.NS != ns.Parent))
+ implicit_parent = new NamespaceEntry (parent, file, ns.Parent.Name, true);
+ else
+ implicit_parent = parent;
+ }
+
+ static int next_id = 0;
+ public readonly int ID;
+ public readonly bool IsImplicit;
+
+ public string Name {
+ get {
+ return ns.Name;
+ }
+ }
+
+ public Namespace NS {
+ get {
+ return ns;
+ }
+ }
+
+ public NamespaceEntry Parent {
+ get {
+ return parent;
+ }
+ }
+
+ public NamespaceEntry ImplicitParent {
+ get {
+ return implicit_parent;
+ }
+ }
+
+ /// <summary>
+ /// Records a new namespace for resolving name references
+ /// </summary>
+ public void Using (string ns, Location loc)
+ {
+ if (DeclarationFound){
+ Report.Error (1529, loc, "A using clause must precede all other namespace elements");
+ return;
+ }
+
+ if (ns == Name)
+ return;
+
+ if (using_clauses == null)
+ using_clauses = new ArrayList ();
+
+ foreach (UsingEntry old_entry in using_clauses){
+ if (old_entry.Name == ns){
+ Report.Warning (105, loc, "The using directive for '" + ns +
+ "' appeared previously in this namespace");
+ return;
+ }
+ }
+
+ UsingEntry ue = new UsingEntry (this, ns, loc);
+ using_clauses.Add (ue);
+ }
+
+ public void UsingAlias (string alias, string namespace_or_type, Location loc)
+ {
+ if (aliases == null)
+ aliases = new Hashtable ();
+
+ if (aliases.Contains (alias)){
+ Report.Error (1537, loc, "The using alias `" + alias +
+ "' appeared previously in this namespace");
+ return;
+ }
+
+ aliases [alias] = new AliasEntry (this, alias, namespace_or_type, loc);
+ }
+
+ protected AliasEntry GetAliasEntry (string alias)
+ {
+ AliasEntry entry = null;
+
+ if (aliases != null)
+ entry = (AliasEntry) aliases [alias];
+ if (entry == null && Parent != null)
+ entry = Parent.GetAliasEntry (alias);
+
+ return entry;
+ }
+
+ public string LookupAlias (string alias)
+ {
+ AliasEntry entry = GetAliasEntry (alias);
+
+ if (entry == null)
+ return null;
+
+ object resolved = entry.Resolve ();
+ if (resolved == null)
+ return null;
+ else if (resolved is Namespace)
+ return ((Namespace) resolved).Name;
+ else
+ return ((Type) resolved).FullName;
+ }
+
+ public object LookupName (string name)
+ {
+ Namespace ns = Namespace.LookupNamespace (name, false);
+ if (ns != null)
+ return ns;
+
+ int pos = name.IndexOf ('.');
+ AliasEntry alias = null;
+ if (pos >= 0) {
+ string first = name.Substring (0, pos);
+ string last = name.Substring (pos + 1);
+
+ alias = GetAliasEntry (first);
+ if (alias != null)
+ return LookupName (DeclSpace.MakeFQN (alias.Alias, last));
+ }
+
+ Type t = TypeManager.LookupType (name);
+ if (t != null)
+ return t;
+
+ alias = GetAliasEntry (name);
+ if (alias != null)
+ return LookupName (alias.Alias);
+
+ return null;
+ }
+
+ public Namespace[] GetUsingTable ()
+ {
+ ArrayList list = new ArrayList ();
+
+ if (using_clauses == null)
+ return new Namespace [0];
+
+ foreach (UsingEntry ue in using_clauses) {
+ Namespace using_ns = ue.Resolve ();
+ if (using_ns == null)
+ continue;
+
+ list.Add (using_ns);
+ }
+
+ Namespace[] retval = new Namespace [list.Count];
+ list.CopyTo (retval, 0);
+ return retval;
+ }
+
+ public void DefineNamespace (SymbolWriter symwriter)
+ {
+ if (symfile_id != 0)
+ return;
+ if (parent != null)
+ parent.DefineNamespace (symwriter);
+
+ string[] 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;
+ } else {
+ using_list = new string [0];
+ }
+
+ int parent_id = parent != null ? parent.symfile_id : 0;
+ symfile_id = symwriter.DefineNamespace (ns.Name, file, using_list, parent_id);
+ }
+
+ public int SymbolFileID {
+ get {
+ return symfile_id;
+ }
+ }
+
+ static void Msgtry (string s)
+ {
+ Console.WriteLine (" Try using -r:" + s);
+ }
+
+ protected void error246 (Location loc, string name)
+ {
+ if (TypeManager.LookupType (name) != null)
+ Report.Error (138, loc, "The using keyword only lets you specify a namespace, " +
+ "`" + name + "' is a class not a namespace.");
+ else {
+ Report.Error (246, loc, "The namespace `" + name +
+ "' can not be found (missing assembly reference?)");
+
+ switch (name){
+ case "Gtk": case "GtkSharp":
+ Msgtry ("gtk-sharp");
+ break;
+
+ case "Gdk": case "GdkSharp":
+ Msgtry ("gdk-sharp");
+ break;
+
+ case "Glade": case "GladeSharp":
+ Msgtry ("glade-sharp");
+ break;
+
+ case "System.Drawing":
+ Msgtry ("System.Drawing");
+ break;
+
+ case "System.Web.Services":
+ Msgtry ("System.Web.Services");
+ break;
+
+ case "System.Web":
+ Msgtry ("System.Web");
+ break;
+
+ case "System.Data":
+ Msgtry ("System.Data");
+ break;
+
+ case "System.Windows.Forms":
+ Msgtry ("System.Windows.Forms");
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Used to validate that all the using clauses are correct
+ /// after we are finished parsing all the files.
+ /// </summary>
+ public void VerifyUsing ()
+ {
+ if (using_clauses != null){
+ foreach (UsingEntry ue in using_clauses){
+ if (ue.Resolve () != null)
+ continue;
+
+ error246 (ue.Location, ue.Name);
+ }
+ }
+
+ if (aliases != null){
+ foreach (DictionaryEntry de in aliases){
+ AliasEntry alias = (AliasEntry) de.Value;
+
+ if (alias.Resolve () != null)
+ continue;
+
+ error246 (alias.Location, alias.Alias);
+ }
+ }
+ }
+
+ public override string ToString ()
+ {
+ if (NS == Namespace.Root)
+ return "NamespaceEntry (<root>)";
+ else
+ return String.Format ("NamespaceEntry ({0},{1},{2})", Name, IsImplicit, ID);
+ }
+ }
+}
--- /dev/null
+#else
+
+ bla bla bla
+ //
+ // This code is more conformant to the spec (it follows it step by step),
+ // but it has not been tested yet, and there is nothing here that is not
+ // caught by the above code. But it might be a better foundation to improve
+ // on in the future
+ //
+ public ResolveTypeMemberAccess (EmitContext ec, Expression member_lookup,
+ Expression left, Location loc)
+ {
+ if (member_lookup is TypeExpr){
+ member_lookup.Resolve (ec);
+ return member_lookup;
+ }
+
+ if (member_lookup is MethodGroupExpr){
+ if (!mg.RemoveStaticMethods ()){
+ SimpleName.Error120 (loc, mg.Methods [0].Name);
+ return null;
+ }
+
+ return member_lookup;
+ }
+
+ if (member_lookup is PropertyExpr){
+ PropertyExpr pe = (PropertyExpr) member_lookup;
+
+ if (!pe.IsStatic){
+ SimpleName.Error120 (loc, pe.PropertyInfo.Name);
+ return null;
+ }
+ return pe;
+ }
+
+ if (member_lookup is FieldExpr){
+ FieldExpr fe = (FieldExpr) member_lookup;
+ FieldInfo fi = fe.FieldInfo;
+
+ if (fi is FieldBuilder) {
+ Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
+
+ if (c != null) {
+ object o = c.LookupConstantValue (ec);
+ return Constantify (o, fi.FieldType);
+ }
+ }
+
+ if (fi.IsLiteral) {
+ Type t = fi.FieldType;
+ Type decl_type = fi.DeclaringType;
+ object o;
+
+ if (fi is FieldBuilder)
+ o = TypeManager.GetValue ((FieldBuilder) fi);
+ else
+ o = fi.GetValue (fi);
+
+ if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
+ Expression enum_member = MemberLookup (
+ ec, decl_type, "value__", loc);
+
+ Enum en = TypeManager.LookupEnum (decl_type);
+
+ Constant c;
+ if (en != null)
+ c = Constantify (o, en.UnderlyingType);
+ else
+ c = Constantify (o, enum_member.Type);
+
+ return new EnumConstant (c, decl_type);
+ }
+
+ Expression exp = Constantify (o, t);
+
+ return exp;
+ }
+
+ if (!fe.FieldInfo.IsStatic){
+ error176 (loc, fe.FieldInfo.Name);
+ return null;
+ }
+ return member_lookup;
+ }
+
+ if (member_lookup is EventExpr){
+
+ EventExpr ee = (EventExpr) member_lookup;
+
+ //
+ // If the event is local to this class, we transform ourselves into
+ // a FieldExpr
+ //
+
+ Expression ml = MemberLookup (
+ ec, ec.TypeContainer.TypeBuilder, ee.EventInfo.Name,
+ MemberTypes.Event, AllBindingFlags, loc);
+
+ if (ml != null) {
+ MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);
+
+ ml = ExprClassFromMemberInfo (ec, mi, loc);
+
+ if (ml == null) {
+ Report.Error (-200, loc, "Internal error!!");
+ return null;
+ }
+
+ return ResolveMemberAccess (ec, ml, left, loc);
+ }
+
+ if (!ee.IsStatic) {
+ SimpleName.Error120 (loc, ee.EventInfo.Name);
+ return null;
+ }
+
+ return ee;
+ }
+
+ Console.WriteLine ("Left is: " + left);
+ Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
+ Environment.Exit (0);
+
+ return null;
+ }
+
+ public ResolveInstanceMemberAccess (EmitContext ec, Expression member_lookup,
+ Expression left, Location loc)
+ {
+ if (member_lookup is MethodGroupExpr){
+ //
+ // Instance.MethodGroup
+ //
+ if (!mg.RemoveStaticMethods ()){
+ error176 (loc, mg.Methods [0].Name);
+ return null;
+ }
+
+ mg.InstanceExpression = left;
+
+ return member_lookup;
+ }
+
+ if (member_lookup is PropertyExpr){
+ PropertyExpr pe = (PropertyExpr) member_lookup;
+
+ if (pe.IsStatic){
+ error176 (loc, pe.PropertyInfo.Name);
+ return null;
+ }
+ Console.WriteLine ("HERE *************");
+ pe.InstanceExpression = left;
+
+ return pe;
+ }
+
+ Type left_type = left.type;
+
+ if (left_type.IsValueType){
+ } else {
+
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are the sole users of ResolveWithSimpleName (ie, the only
+ // ones that can cope with it
+ //
+ expr = expr.ResolveWithSimpleName (ec);
+
+ if (expr == null)
+ return null;
+
+ if (expr is SimpleName){
+ SimpleName child_expr = (SimpleName) expr;
+
+ expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
+
+ return expr.ResolveWithSimpleName (ec);
+ }
+
+ //
+ // Handle enums here when they are in transit.
+ // Note that we cannot afford to hit MemberLookup in this case because
+ // it will fail to find any members at all (Why?)
+ //
+
+ Type expr_type = expr.Type;
+ if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
+
+ Enum en = TypeManager.LookupEnum (expr_type);
+
+ if (en != null) {
+ object value = en.LookupEnumValue (ec, Identifier, loc);
+
+ if (value == null)
+ return null;
+
+ Constant c = Constantify (value, en.UnderlyingType);
+ return new EnumConstant (c, expr_type);
+ }
+ }
+
+ member_lookup = MemberLookup (ec, expr.Type, Identifier, loc);
+
+ if (member_lookup == null)
+ return null;
+
+ if (expr is TypeExpr)
+ return ResolveTypeMemberAccess (ec, member_lookup, expr, loc);
+ else
+ return ResolveInstanceMemberAccess (ec, member_lookup, expr, loc);
+ }
+#endif
--- /dev/null
+//
+// parameter.cs: Parameter definition.
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+//
+//
+//
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections;
+
+namespace Mono.CSharp {
+
+
+ /// <summary>
+ /// Represents a single method parameter
+ /// </summary>
+ public class Parameter {
+ [Flags]
+ public enum Modifier : byte {
+ NONE = 0,
+ REF = 1,
+ OUT = 2,
+ PARAMS = 4,
+ // This is a flag which says that it's either REF or OUT.
+ ISBYREF = 8
+ }
+
+ public readonly Expression TypeName;
+ public readonly Modifier ModFlags;
+ public Attributes OptAttributes;
+ public readonly string Name;
+ public Type parameter_type;
+
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
+ {
+ Name = name;
+ ModFlags = mod;
+ TypeName = type;
+ OptAttributes = attrs;
+ }
+
+ // <summary>
+ // Resolve is used in method definitions
+ // </summary>
+ public bool Resolve (DeclSpace ds, Location l)
+ {
+ parameter_type = ds.ResolveType (TypeName, false, l);
+
+ if (parameter_type == TypeManager.void_type){
+ Report.Error (1536, l, "`void' parameter is not permitted");
+ return false;
+ }
+
+ return parameter_type != null;
+ }
+
+ public Type ExternalType ()
+ {
+ if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
+ return TypeManager.GetReferenceType (parameter_type);
+
+ return parameter_type;
+ }
+
+ public Type ParameterType {
+ get {
+ return parameter_type;
+ }
+ }
+
+ public ParameterAttributes Attributes {
+ get {
+ int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
+ switch ((Modifier) flags) {
+ case Modifier.NONE:
+ return ParameterAttributes.None;
+ case Modifier.REF:
+ return ParameterAttributes.None;
+ case Modifier.OUT:
+ return ParameterAttributes.Out;
+ case Modifier.PARAMS:
+ return 0;
+ }
+
+ return ParameterAttributes.None;
+ }
+ }
+
+ /// <summary>
+ /// Returns the signature for this parameter evaluating it on the
+ /// @tc context
+ /// </summary>
+ public string GetSignature (DeclSpace ds, Location loc)
+ {
+ if (parameter_type == null){
+ if (!Resolve (ds, loc))
+ return null;
+ }
+
+ return ExternalType ().FullName;
+ }
+ }
+
+ /// <summary>
+ /// Represents the methods parameters
+ /// </summary>
+ public class Parameters {
+ public Parameter [] FixedParameters;
+ public readonly Parameter ArrayParameter;
+ string signature;
+ Type [] types;
+ Location loc;
+
+ static Parameters empty_parameters;
+
+ public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
+ {
+ FixedParameters = fixed_parameters;
+ ArrayParameter = array_parameter;
+ loc = l;
+ }
+
+ /// <summary>
+ /// This is used to reuse a set of empty parameters, because they
+ /// are common
+ /// </summary>
+ public static Parameters EmptyReadOnlyParameters {
+ get {
+ if (empty_parameters == null)
+ empty_parameters = new Parameters (null, null, Location.Null);
+
+ return empty_parameters;
+ }
+ }
+
+ public bool Empty {
+ get {
+ return (FixedParameters == null) && (ArrayParameter == null);
+ }
+ }
+
+ public void ComputeSignature (DeclSpace ds)
+ {
+ signature = "";
+ if (FixedParameters != null){
+ for (int i = 0; i < FixedParameters.Length; i++){
+ Parameter par = FixedParameters [i];
+
+ signature += par.GetSignature (ds, loc);
+ }
+ }
+ //
+ // Note: as per the spec, the `params' arguments (ArrayParameter)
+ // are not used in the signature computation for a method
+ //
+ }
+
+ static void Error_DuplicateParameterName (string name)
+ {
+ Report.Error (
+ 100, "The parameter name `" + name + "' is a duplicate");
+ }
+
+ public bool VerifyArgs ()
+ {
+ int count;
+ int i, j;
+
+ if (FixedParameters == null)
+ return true;
+
+ count = FixedParameters.Length;
+ string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
+ for (i = 0; i < count; i++){
+ string base_name = FixedParameters [i].Name;
+
+ for (j = i + 1; j < count; j++){
+ if (base_name != FixedParameters [j].Name)
+ continue;
+ Error_DuplicateParameterName (base_name);
+ return false;
+ }
+
+ if (base_name == array_par_name){
+ Error_DuplicateParameterName (base_name);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Returns the signature of the Parameters evaluated in
+ /// the @tc environment
+ /// </summary>
+ public string GetSignature (DeclSpace ds)
+ {
+ if (signature == null){
+ VerifyArgs ();
+ ComputeSignature (ds);
+ }
+
+ return signature;
+ }
+
+ /// <summary>
+ /// Returns the paramenter information based on the name
+ /// </summary>
+ public Parameter GetParameterByName (string name, out int idx)
+ {
+ idx = 0;
+ int i = 0;
+
+ if (FixedParameters != null){
+ foreach (Parameter par in FixedParameters){
+ if (par.Name == name){
+ idx = i;
+ return par;
+ }
+ i++;
+ }
+ }
+
+ if (ArrayParameter != null){
+ if (name == ArrayParameter.Name){
+ idx = i;
+ return ArrayParameter;
+ }
+ }
+
+ return null;
+ }
+
+ bool ComputeParameterTypes (DeclSpace ds)
+ {
+ int extra = (ArrayParameter != null) ? 1 : 0;
+ int i = 0;
+ int pc;
+
+ if (FixedParameters == null)
+ pc = extra;
+ else
+ pc = extra + FixedParameters.Length;
+
+ types = new Type [pc];
+
+ if (!VerifyArgs ()){
+ FixedParameters = null;
+ return false;
+ }
+
+ bool failed = false;
+ if (FixedParameters != null){
+ foreach (Parameter p in FixedParameters){
+ Type t = null;
+
+ if (p.Resolve (ds, loc))
+ t = p.ExternalType ();
+ else
+ failed = true;
+
+ types [i] = t;
+ i++;
+ }
+ }
+
+ if (extra > 0){
+ if (ArrayParameter.Resolve (ds, loc))
+ types [i] = ArrayParameter.ExternalType ();
+ else
+ failed = true;
+ }
+
+ if (failed){
+ types = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ //
+ // This variant is used by Delegates, because they need to
+ // resolve/define names, instead of the plain LookupType
+ //
+ public bool ComputeAndDefineParameterTypes (DeclSpace ds)
+ {
+ int extra = (ArrayParameter != null) ? 1 : 0;
+ int i = 0;
+ int pc;
+
+ if (FixedParameters == null)
+ pc = extra;
+ else
+ pc = extra + FixedParameters.Length;
+
+ types = new Type [pc];
+
+ if (!VerifyArgs ()){
+ FixedParameters = null;
+ return false;
+ }
+
+ bool ok_flag = true;
+
+ if (FixedParameters != null){
+ foreach (Parameter p in FixedParameters){
+ Type t = null;
+
+ if (p.Resolve (ds, loc))
+ t = p.ExternalType ();
+ else
+ ok_flag = false;
+
+ types [i] = t;
+ i++;
+ }
+ }
+
+ if (extra > 0){
+ if (ArrayParameter.Resolve (ds, loc))
+ types [i] = ArrayParameter.ExternalType ();
+ else
+ ok_flag = false;
+ }
+
+ //
+ // invalidate the cached types
+ //
+ if (!ok_flag){
+ types = null;
+ }
+
+ return ok_flag;
+ }
+
+ /// <summary>
+ /// Returns the argument types as an array
+ /// </summary>
+ static Type [] no_types = new Type [0];
+
+ public Type [] GetParameterInfo (DeclSpace ds)
+ {
+ if (types != null)
+ return types;
+
+ if (FixedParameters == null && ArrayParameter == null)
+ return no_types;
+
+ if (ComputeParameterTypes (ds) == false){
+ types = null;
+ return null;
+ }
+
+ return types;
+ }
+
+ /// <summary>
+ /// Returns the type of a given parameter, and stores in the `is_out'
+ /// boolean whether this is an out or ref parameter.
+ ///
+ /// Note that the returned type will not contain any dereference in this
+ /// case (ie, you get "int" for a ref int instead of "int&"
+ /// </summary>
+ public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
+ {
+ mod = Parameter.Modifier.NONE;
+
+ if (!VerifyArgs ()){
+ FixedParameters = null;
+ return null;
+ }
+
+ if (FixedParameters == null && ArrayParameter == null)
+ return null;
+
+ if (types == null)
+ if (ComputeParameterTypes (ds) == false)
+ return null;
+
+ //
+ // If this is a request for the variable lenght arg.
+ //
+ int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
+ if (idx == array_idx)
+ return types [idx];
+
+ //
+ // Otherwise, it is a fixed parameter
+ //
+ Parameter p = FixedParameters [idx];
+ mod = p.ModFlags;
+
+ if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
+ mod |= Parameter.Modifier.ISBYREF;
+
+ return p.ParameterType;
+ }
+
+ public CallingConventions GetCallingConvention ()
+ {
+ // For now this is the only correc thing to do
+ return CallingConventions.Standard;
+ }
+ }
+}
+
+
+
--- /dev/null
+//
+// System.CodeDOM CodeParameterCollection Class implementation
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+
+namespace Mono.CSharp {
+
+ using System.Collections;
+ using System;
+
+ public class ParameterCollection : IList, ICollection, IEnumerable {
+
+ ArrayList parameters;
+
+ //
+ // Constructors
+ //
+ public ParameterCollection ()
+ {
+ parameters = new ArrayList ();
+ }
+
+ //
+ // Properties
+ //
+ public int Count {
+ get {
+ return parameters.Count;
+ }
+ }
+
+ //
+ // Methods
+ //
+ public void Add (Parameter value)
+ {
+ parameters.Add (value);
+ }
+
+ public void AddRange (Parameter [] values)
+ {
+ foreach (Parameter ca in values)
+ parameters.Add (ca);
+
+ }
+
+ public void Clear ()
+ {
+ parameters.Clear ();
+ }
+
+ private class Enumerator : IEnumerator {
+ private ParameterCollection collection;
+ private int currentIndex = -1;
+
+ internal Enumerator (ParameterCollection collection)
+ {
+ this.collection = collection;
+ }
+
+ public object Current {
+ get {
+ if (currentIndex == collection.Count)
+ throw new InvalidOperationException ();
+ return collection [currentIndex];
+ }
+ }
+
+ public bool MoveNext ()
+ {
+ if (currentIndex > collection.Count)
+ throw new InvalidOperationException ();
+ return ++currentIndex < collection.Count;
+ }
+
+ public void Reset ()
+ {
+ currentIndex = -1;
+ }
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return new ParameterCollection.Enumerator (this);
+ }
+
+ //
+ // IList method implementations
+ //
+ public int Add (object value)
+ {
+ return parameters.Add (value);
+ }
+
+ public bool Contains (Object value)
+ {
+ return parameters.Contains (value);
+ }
+
+ public int IndexOf (Object value)
+ {
+ return parameters.IndexOf (value);
+ }
+
+ public void Insert (int index, Object value)
+ {
+ parameters [index] = value;
+ }
+
+ public object this[int index] {
+ get {
+ return parameters [index];
+ }
+
+ set {
+ parameters [index] = value;
+ }
+ }
+
+ public void Remove (object value)
+ {
+ parameters.Remove (value);
+ }
+
+ public void RemoveAt (int index)
+ {
+ parameters.RemoveAt (index);
+ }
+
+ //
+ // ICollection method implementations
+ //
+ public void CopyTo (Array array, int index)
+ {
+ parameters.CopyTo (array, index);
+ }
+
+ public object SyncRoot {
+ get {
+ return parameters.SyncRoot;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ public bool IsSynchronized {
+ get {
+ return parameters.IsSynchronized;
+ }
+ }
+
+ public bool IsFixedSize {
+ get {
+ return false;
+ }
+ }
+ }
+}
--- /dev/null
+\r
+namespace Compiler {\r
+\r
+ using System;\r
+\r
+ abstract public class Parser {\r
+ public string name;\r
+ public System.IO.Stream input;\r
+ \r
+ public Parser (Mono.CSharp.Tree tree, string name, System.IO.Stream stream) \r
+ {\r
+ this.tree = tree;\r
+ this.name = name;\r
+ this.input = stream;\r
+ }\r
+\r
+ public string getName (){\r
+ return name;\r
+ }\r
+\r
+ abstract public int parse ();\r
+ }\r
+}\r
--- /dev/null
+//
+// pending.cs: Pending method implementation
+//
+// Author:
+// Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
+//
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.CSharp {
+
+ struct TypeAndMethods {
+ public Type type;
+ public MethodInfo [] methods;
+
+ //
+ // Whether it is optional, this is used to allow the explicit/implicit
+ // implementation when a parent class already implements an interface.
+ //
+ // For example:
+ //
+ // class X : IA { } class Y : X, IA { IA.Explicit (); }
+ //
+ public bool optional;
+
+ // Far from ideal, but we want to avoid creating a copy
+ // of methods above.
+ public Type [][] args;
+
+ //
+ // This flag on the method says `We found a match, but
+ // because it was private, we could not use the match
+ //
+ public bool [] found;
+
+ // If a method is defined here, then we always need to
+ // create a proxy for it. This is used when implementing
+ // an interface's indexer with a different IndexerName.
+ public MethodInfo [] need_proxy;
+ }
+
+ public class PendingImplementation {
+ /// <summary>
+ /// The container for this PendingImplementation
+ /// </summary>
+ TypeContainer container;
+
+ /// <summary>
+ /// This filter is used by FindMembers, and it is used to
+ /// extract only virtual/abstract fields
+ /// </summary>
+ static MemberFilter virtual_method_filter;
+
+ /// <summary>
+ /// This is the array of TypeAndMethods that describes the pending implementations
+ /// (both interfaces and abstract methods in parent class)
+ /// </summary>
+ TypeAndMethods [] pending_implementations;
+
+ static bool IsVirtualFilter (MemberInfo m, object filterCriteria)
+ {
+ if (!(m is MethodInfo))
+ return false;
+
+ return ((MethodInfo) m).IsVirtual;
+ }
+
+ /// <summary>
+ /// Inits the virtual_method_filter
+ /// </summary>
+ static PendingImplementation ()
+ {
+ virtual_method_filter = new MemberFilter (IsVirtualFilter);
+ }
+
+ // <remarks>
+ // Returns a list of the abstract methods that are exposed by all of our
+ // parents that we must implement. Notice that this `flattens' the
+ // method search space, and takes into account overrides.
+ // </remarks>
+ static ArrayList GetAbstractMethods (Type t)
+ {
+ ArrayList list = null;
+ bool searching = true;
+ Type current_type = t;
+
+ do {
+ MemberList mi;
+
+ mi = TypeContainer.FindMembers (
+ current_type, MemberTypes.Method,
+ BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly,
+ virtual_method_filter, null);
+
+ if (current_type == TypeManager.object_type)
+ searching = false;
+ else {
+ current_type = current_type.BaseType;
+ if (!current_type.IsAbstract)
+ searching = false;
+ }
+
+ if (mi.Count == 0)
+ continue;
+
+ if (mi.Count == 1 && !(mi [0] is MethodBase))
+ searching = false;
+ else
+ list = TypeManager.CopyNewMethods (list, mi);
+ } while (searching);
+
+ if (list == null)
+ return null;
+
+ for (int i = 0; i < list.Count; i++){
+ while (list.Count > i && !((MethodInfo) list [i]).IsAbstract)
+ list.RemoveAt (i);
+ }
+
+ if (list.Count == 0)
+ return null;
+
+ return list;
+ }
+
+ PendingImplementation (TypeContainer container, MissingInterfacesInfo [] missing_ifaces, ArrayList abstract_methods, int total)
+ {
+ TypeBuilder type_builder = container.TypeBuilder;
+
+ this.container = container;
+ pending_implementations = new TypeAndMethods [total];
+
+ int i = 0;
+ foreach (MissingInterfacesInfo missing in missing_ifaces){
+ MethodInfo [] mi;
+ Type t = missing.Type;
+
+ if (t is TypeBuilder){
+ Interface iface;
+
+ iface = TypeManager.LookupInterface (t);
+
+ mi = iface.GetMethods (container);
+ } else
+ mi = t.GetMethods ();
+
+ int count = mi.Length;
+ pending_implementations [i].type = missing.Type;
+ pending_implementations [i].optional = missing.Optional;
+ pending_implementations [i].methods = mi;
+ pending_implementations [i].args = new Type [count][];
+ pending_implementations [i].found = new bool [count];
+ pending_implementations [i].need_proxy = new MethodInfo [count];
+
+ int j = 0;
+ foreach (MethodInfo m in mi){
+ Type [] types = TypeManager.GetArgumentTypes (m);
+
+ pending_implementations [i].args [j] = types;
+ j++;
+ }
+ i++;
+ }
+
+ if (abstract_methods != null){
+ int count = abstract_methods.Count;
+ pending_implementations [i].methods = new MethodInfo [count];
+ pending_implementations [i].need_proxy = new MethodInfo [count];
+
+ abstract_methods.CopyTo (pending_implementations [i].methods, 0);
+ pending_implementations [i].found = new bool [count];
+ pending_implementations [i].args = new Type [count][];
+ pending_implementations [i].type = type_builder;
+
+ int j = 0;
+ foreach (MemberInfo m in abstract_methods){
+ MethodInfo mi = (MethodInfo) m;
+
+ Type [] types = TypeManager.GetArgumentTypes (mi);
+
+ pending_implementations [i].args [j] = types;
+ j++;
+ }
+ }
+ }
+
+ struct MissingInterfacesInfo {
+ public Type Type;
+ public bool Optional;
+
+ public MissingInterfacesInfo (Type t)
+ {
+ Type = t;
+ Optional = false;
+ }
+ }
+
+ static MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0];
+
+ static MissingInterfacesInfo [] GetMissingInterfaces (TypeBuilder type_builder)
+ {
+ //
+ // Notice that TypeBuilders will only return the interfaces that the Type
+ // is supposed to implement, not all the interfaces that the type implements.
+ //
+ // Completely broken. Anyways, we take advantage of this, so we only register
+ // the implementations that we need, as they are those that are listed by the
+ // TypeBuilder.
+ //
+ Type [] implementing_ifaces = type_builder.GetInterfaces ();
+ int count = implementing_ifaces.Length;
+
+ if (implementing_ifaces.Length == 0)
+ return EmptyMissingInterfacesInfo;
+
+ MissingInterfacesInfo [] missing_info = new MissingInterfacesInfo [count];
+
+ for (int i = 0; i < count; i++)
+ missing_info [i] = new MissingInterfacesInfo (implementing_ifaces [i]);
+
+
+ //
+ // Now, we have to extract the interfaces implements by our parents, and
+ // remove them from the implementing_ifaces array.
+ //
+ for (Type t = type_builder.BaseType; t != null; t = t.BaseType){
+ Type [] base_ifaces = t.GetInterfaces ();
+
+ foreach (Type base_iface in base_ifaces){
+ for (int i = 0; i < count; i++){
+ if (implementing_ifaces [i] == base_iface)
+ missing_info [i].Optional = true;
+ }
+ }
+
+ //
+ // When we reach a `Type' instead of `TypeBuilder', the GetInterfaces
+ // call would have returned all of the parent implementations, so we can end.
+ //
+ if (!(t is TypeBuilder))
+ break;
+ }
+
+ return missing_info;
+ }
+
+ //
+ // Factory method: if there are pending implementation methods, we return a PendingImplementation
+ // object, otherwise we return null.
+ //
+ // Register method implementations are either abstract methods
+ // flagged as such on the base class or interface methods
+ //
+ static public PendingImplementation GetPendingImplementations (TypeContainer container)
+ {
+ TypeBuilder type_builder = container.TypeBuilder;
+ MissingInterfacesInfo [] missing_interfaces;
+ Type b = type_builder.BaseType;
+
+ missing_interfaces = GetMissingInterfaces (type_builder);
+
+ //
+ // If we are implementing an abstract class, and we are not
+ // ourselves abstract, and there are abstract methods (C# allows
+ // abstract classes that have no abstract methods), then allocate
+ // one slot.
+ //
+ // We also pre-compute the methods.
+ //
+ bool implementing_abstract = ((b != null) && b.IsAbstract && !type_builder.IsAbstract);
+ ArrayList abstract_methods = null;
+
+ if (implementing_abstract){
+ abstract_methods = GetAbstractMethods (b);
+
+ if (abstract_methods == null)
+ implementing_abstract = false;
+ }
+
+ int total = missing_interfaces.Length + (implementing_abstract ? 1 : 0);
+ if (total == 0)
+ return null;
+
+ return new PendingImplementation (container, missing_interfaces, abstract_methods, total);
+ }
+
+ public enum Operation {
+ //
+ // If you change this, review the whole InterfaceMethod routine as there
+ // are a couple of assumptions on these three states
+ //
+ Lookup, ClearOne, ClearAll
+ }
+
+ /// <summary>
+ /// Whether the specified method is an interface method implementation
+ /// </summary>
+ public MethodInfo IsInterfaceMethod (Type t, string name, Type ret_type, Type [] args)
+ {
+ return InterfaceMethod (t, name, ret_type, args, Operation.Lookup, null);
+ }
+
+ public MethodInfo IsInterfaceIndexer (Type t, Type ret_type, Type [] args)
+ {
+ return InterfaceMethod (t, null, ret_type, args, Operation.Lookup, null);
+ }
+
+ public void ImplementMethod (Type t, string name, Type ret_type, Type [] args, bool clear_one)
+ {
+ InterfaceMethod (t, name, ret_type, args,
+ clear_one ? Operation.ClearOne : Operation.ClearAll, null);
+ }
+
+ public void ImplementIndexer (Type t, MethodInfo mi, Type ret_type, Type [] args, bool clear_one)
+ {
+ InterfaceMethod (t, mi.Name, ret_type, args,
+ clear_one ? Operation.ClearOne : Operation.ClearAll, mi);
+ }
+
+ /// <remarks>
+ /// If a method in Type `t' (or null to look in all interfaces
+ /// and the base abstract class) with name `Name', return type `ret_type' and
+ /// arguments `args' implements an interface, this method will
+ /// return the MethodInfo that this method implements.
+ ///
+ /// If `name' is null, we operate solely on the method's signature. This is for
+ /// instance used when implementing indexers.
+ ///
+ /// The `Operation op' controls whether to lookup, clear the pending bit, or clear
+ /// all the methods with the given signature.
+ ///
+ /// The `MethodInfo need_proxy' is used when we're implementing an interface's
+ /// indexer in a class. If the new indexer's IndexerName does not match the one
+ /// that was used in the interface, then we always need to create a proxy for it.
+ ///
+ /// </remarks>
+ public MethodInfo InterfaceMethod (Type t, string name, Type ret_type, Type [] args,
+ Operation op, MethodInfo need_proxy)
+ {
+ int arg_len = args.Length;
+
+ if (pending_implementations == null)
+ return null;
+
+ foreach (TypeAndMethods tm in pending_implementations){
+ if (!(t == null || tm.type == t))
+ continue;
+
+ int method_count = tm.methods.Length;
+ MethodInfo m;
+ for (int i = 0; i < method_count; i++){
+ m = tm.methods [i];
+
+ if (m == null)
+ continue;
+
+ // `need_proxy' is not null when we're implementing an
+ // interface indexer and this is Clear(One/All) operation.
+ // If `name' is null, then we do a match solely based on the
+ // signature and not on the name (this is done in the Lookup
+ // for an interface indexer).
+ if ((name != null) && (need_proxy == null) && (name != m.Name))
+ continue;
+
+ if (ret_type != m.ReturnType){
+ if (!((ret_type == null && m.ReturnType == TypeManager.void_type) ||
+ (m.ReturnType == null && ret_type == TypeManager.void_type)))
+ continue;
+ }
+
+ //
+ // Check if we have the same parameters
+ //
+ if (tm.args [i].Length != arg_len)
+ continue;
+
+ int j, top = args.Length;
+ bool fail = false;
+
+ for (j = 0; j < top; j++){
+ if (tm.args [i][j] != args[j]){
+ fail = true;
+ break;
+ }
+ }
+ if (fail)
+ continue;
+
+ if (op != Operation.Lookup){
+ // If `t != null', then this is an explicitly interface
+ // implementation and we can always clear the method.
+ // `need_proxy' is not null if we're implementing an
+ // interface indexer. In this case, we need to create
+ // a proxy if the implementation's IndexerName doesn't
+ // match the IndexerName in the interface.
+ if ((t == null) && (need_proxy != null) && (name != m.Name))
+ tm.need_proxy [i] = need_proxy;
+ else
+ tm.methods [i] = null;
+ }
+ tm.found [i] = true;
+
+ //
+ // Lookups and ClearOne return
+ //
+ if (op != Operation.ClearAll)
+ return m;
+ }
+
+ // If a specific type was requested, we can stop now.
+ if (tm.type == t)
+ return null;
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// C# allows this kind of scenarios:
+ /// interface I { void M (); }
+ /// class X { public void M (); }
+ /// class Y : X, I { }
+ ///
+ /// For that case, we create an explicit implementation function
+ /// I.M in Y.
+ /// </summary>
+ void DefineProxy (Type iface, MethodInfo parent_method, MethodInfo iface_method,
+ Type [] args)
+ {
+ MethodBuilder proxy;
+
+ string proxy_name = iface.Name + "." + iface_method.Name;
+
+ proxy = container.TypeBuilder.DefineMethod (
+ proxy_name,
+ MethodAttributes.HideBySig |
+ MethodAttributes.NewSlot |
+ MethodAttributes.Virtual,
+ CallingConventions.Standard | CallingConventions.HasThis,
+ parent_method.ReturnType, args);
+
+ int top = args.Length;
+ ILGenerator ig = proxy.GetILGenerator ();
+
+ ig.Emit (OpCodes.Ldarg_0);
+ for (int i = 0; i < top; i++){
+ switch (i){
+ case 0:
+ ig.Emit (OpCodes.Ldarg_1); break;
+ case 1:
+ ig.Emit (OpCodes.Ldarg_2); break;
+ case 2:
+ ig.Emit (OpCodes.Ldarg_3); break;
+ default:
+ ig.Emit (OpCodes.Ldarg, i - 1); break;
+ }
+ }
+ ig.Emit (OpCodes.Call, parent_method);
+ ig.Emit (OpCodes.Ret);
+
+ container.TypeBuilder.DefineMethodOverride (proxy, iface_method);
+ }
+
+ /// <summary>
+ /// This function tells whether one of our parent classes implements
+ /// the given method (which turns out, it is valid to have an interface
+ /// implementation in a parent
+ /// </summary>
+ bool ParentImplements (Type iface_type, MethodInfo mi)
+ {
+ MethodSignature ms;
+
+ Type [] args = TypeManager.GetArgumentTypes (mi);
+ ms = new MethodSignature (mi.Name, mi.ReturnType, args);
+ MemberList list = TypeContainer.FindMembers (
+ container.TypeBuilder.BaseType, MemberTypes.Method | MemberTypes.Property,
+ BindingFlags.Public | BindingFlags.Instance,
+ MethodSignature.method_signature_filter, ms);
+
+ if (list.Count == 0)
+ return false;
+
+ MethodInfo parent = (MethodInfo) list [0];
+ if (!parent.IsAbstract)
+ DefineProxy (iface_type, parent, mi, args);
+ return true;
+ }
+
+ /// <summary>
+ /// Verifies that any pending abstract methods or interface methods
+ /// were implemented.
+ /// </summary>
+ public bool VerifyPendingMethods ()
+ {
+ int top = pending_implementations.Length;
+ bool errors = false;
+ int i;
+
+ for (i = 0; i < top; i++){
+ Type type = pending_implementations [i].type;
+ int j = 0;
+
+ foreach (MethodInfo mi in pending_implementations [i].methods){
+ if (mi == null)
+ continue;
+
+ if (type.IsInterface){
+ MethodInfo need_proxy =
+ pending_implementations [i].need_proxy [j];
+
+ if (need_proxy != null) {
+ Type [] args = TypeManager.GetArgumentTypes (mi);
+ DefineProxy (type, need_proxy, mi, args);
+ continue;
+ }
+
+ if (ParentImplements (type, mi))
+ continue;
+
+ if (pending_implementations [i].optional)
+ continue;
+
+ string extra = "";
+
+ if (pending_implementations [i].found [j])
+ extra = ". (method might be non-public or static)";
+ Report.Error (
+ 536, container.Location,
+ "`" + container.Name + "' does not implement " +
+ "interface member `" +
+ type.FullName + "." + mi.Name + "'" + extra);
+ } else {
+ Report.Error (
+ 534, container.Location,
+ "`" + container.Name + "' does not implement " +
+ "inherited abstract member `" +
+ type.FullName + "." + mi.Name + "'");
+ }
+ errors = true;
+ j++;
+ }
+ }
+ return errors;
+ }
+ } /* end of class */
+}
--- /dev/null
+//
+// report.cs: report errors and warnings.
+//
+// Author: Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc. (http://www.ximian.com)
+//
+
+//
+// FIXME: currently our class library does not support custom number format strings
+//
+using System;
+using System.Text;
+using System.Collections;
+using System.Diagnostics;
+
+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;
+
+ //
+ // 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
+ //
+ static Hashtable warning_ignore_table;
+
+ static void Check (int code)
+ {
+ if (code == expected_error){
+ if (Fatal)
+ throw new Exception ();
+
+ Environment.Exit (0);
+ }
+ }
+
+ static public void RealError (string msg)
+ {
+ Errors++;
+ Console.WriteLine (msg);
+
+ if (Stacktrace)
+ Console.WriteLine (new StackTrace ().ToString ());
+ if (Fatal)
+ throw new Exception (msg);
+ }
+
+ static public void Error (int code, Location l, string text)
+ {
+ if (code < 0)
+ code = 8000-code;
+
+ string msg = String.Format (
+ "{0}({1}) error CS{2:0000}: {3}", l.Name, l.Row, code, text);
+// "{0}({1}) error CS{2}: {3}", l.Name, l.Row, code, text);
+
+ RealError (msg);
+ Check (code);
+ }
+
+ static public void Warning (int code, Location l, string text)
+ {
+ if (code < 0)
+ code = 8000-code;
+
+ if (warning_ignore_table != null){
+ if (warning_ignore_table.Contains (code))
+ return;
+ }
+
+ if (WarningsAreErrors)
+ Error (code, l, text);
+ else {
+ string row;
+
+ if (Location.IsNull (l))
+ row = "";
+ else
+ row = l.Row.ToString ();
+
+ Console.WriteLine (String.Format (
+ "{0}({1}) warning CS{2:0000}: {3}",
+// "{0}({1}) warning CS{2}: {3}",
+ l.Name, row, code, text));
+ Warnings++;
+ Check (code);
+
+ if (Stacktrace)
+ Console.WriteLine (new StackTrace ().ToString ());
+ }
+ }
+
+ static public void Warning (int code, string text)
+ {
+ Warning (code, Location.Null, text);
+ }
+
+ static public void Warning (int code, int level, string text)
+ {
+ if (RootContext.WarningLevel >= level)
+ Warning (code, Location.Null, text);
+ }
+
+ static public void Warning (int code, int level, Location l, string text)
+ {
+ if (RootContext.WarningLevel >= level)
+ Warning (code, l, text);
+ }
+
+ static public void Error (int code, string text)
+ {
+ if (code < 0)
+ code = 8000-code;
+
+ string msg = String.Format ("error CS{0:0000}: {1}", code, text);
+// string msg = String.Format ("error CS{0}: {1}", code, text);
+
+ RealError (msg);
+ Check (code);
+ }
+
+ static public void Message (Message m)
+ {
+ if (m is ErrorMessage)
+ Error (m.code, m.text);
+ else
+ Warning (m.code, m.text);
+ }
+
+ 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 class Message {
+ public int code;
+ public string text;
+
+ public Message (int code, string text)
+ {
+ this.code = code;
+ this.text = text;
+ }
+ }
+
+ public class WarningMessage : Message {
+ public WarningMessage (int code, string text) : base (code, text)
+ {
+ }
+ }
+
+ public class ErrorMessage : Message {
+ public ErrorMessage (int code, string text) : base (code, text)
+ {
+ }
+
+ //
+ // For compatibility reasons with old code.
+ //
+ public static void report_error (string error)
+ {
+ Console.Write ("ERROR: ");
+ Console.WriteLine (error);
+ }
+ }
+
+ 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 ()
+ : base ("Internal error")
+ {
+ }
+
+ public InternalErrorException (string message)
+ : base (message)
+ {
+ }
+ }
+}
--- /dev/null
+//
+// rootcontext.cs: keeps track of our tree representation, and assemblies loaded.
+//
+// Author: Miguel de Icaza (miguel@ximian.com)
+// Ravi Pratap (ravi@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.Diagnostics;
+
+namespace Mono.CSharp {
+
+ public class RootContext {
+
+ //
+ // Contains the parsed tree
+ //
+ static Tree tree;
+
+ //
+ // This hashtable contains all of the #definitions across the source code
+ // it is used by the ConditionalAttribute handler.
+ //
+ public static Hashtable AllDefines = new Hashtable ();
+
+ //
+ // The list of global attributes (those that target the assembly)
+ //
+ static Hashtable global_attributes = new Hashtable ();
+
+ //
+ // Whether we are being linked against the standard libraries.
+ // This is only used to tell whether `System.Object' should
+ // have a parent or not.
+ //
+ public static bool StdLib = true;
+
+ //
+ // This keeps track of the order in which classes were defined
+ // so that we can poulate them in that order.
+ //
+ // Order is important, because we need to be able to tell by
+ // examining the parent's list of methods which ones are virtual
+ // or abstract as well as the parent names (to implement new,
+ // override).
+ //
+ static ArrayList type_container_resolve_order;
+ static ArrayList interface_resolve_order;
+ static ArrayList attribute_types;
+
+ //
+ // Holds a reference to the Private Implementation Details
+ // class.
+ //
+ static ArrayList helper_classes;
+
+ static TypeBuilder impl_details_class;
+
+ public static int WarningLevel = 2;
+
+ //
+ // If set, enable C# version 2 features
+ //
+ public static bool V2;
+ //
+ // Constructor
+ //
+ static RootContext ()
+ {
+ tree = new Tree ();
+ interface_resolve_order = new ArrayList ();
+ type_container_resolve_order = new ArrayList ();
+ }
+
+ static public Tree Tree {
+ get {
+ return tree;
+ }
+ }
+
+ static public string MainClass;
+
+ public static void RegisterOrder (Interface iface)
+ {
+ interface_resolve_order.Add (iface);
+ }
+
+ public static void RegisterOrder (TypeContainer tc)
+ {
+ type_container_resolve_order.Add (tc);
+ }
+
+ public static void RegisterAttribute (TypeContainer tc)
+ {
+ if (attribute_types == null)
+ attribute_types = new ArrayList ();
+
+ attribute_types.Add (tc);
+ }
+
+ //
+ // The default compiler checked state
+ //
+ static public bool Checked = false;
+
+ //
+ // Whether to allow Unsafe code
+ //
+ static public bool Unsafe = false;
+
+ static string MakeFQN (string nsn, string name)
+ {
+ if (nsn == "")
+ return name;
+ return String.Concat (nsn, ".", name);
+ }
+
+ // <remarks>
+ // This function is used to resolve the hierarchy tree.
+ // It processes interfaces, structs and classes in that order.
+ //
+ // It creates the TypeBuilder's as it processes the user defined
+ // types.
+ // </remarks>
+ static public void ResolveTree ()
+ {
+ //
+ // Process the attribute types separately and before anything else
+ //
+ if (attribute_types != null)
+ foreach (TypeContainer tc in attribute_types)
+ tc.DefineType ();
+
+ //
+ // Interfaces are processed next, as classes and
+ // structs might inherit from an object or implement
+ // a set of interfaces, we need to be able to tell
+ // them appart by just using the TypeManager.
+ //
+ TypeContainer root = Tree.Types;
+
+ ArrayList ifaces = root.Interfaces;
+ if (ifaces != null){
+ foreach (Interface i in ifaces)
+ i.DefineType ();
+ }
+
+ foreach (TypeContainer tc in root.Types)
+ tc.DefineType ();
+
+ if (root.Delegates != null)
+ foreach (Delegate d in root.Delegates)
+ d.DefineType ();
+
+ if (root.Enums != null)
+ foreach (Enum e in root.Enums)
+ e.DefineType ();
+ }
+
+ static void Error_TypeConflict (string name, Location loc)
+ {
+ Report.Error (
+ 520, loc, "`" + name + "' conflicts with a predefined type");
+ }
+
+ static void Error_TypeConflict (string name)
+ {
+ Report.Error (
+ 520, "`" + name + "' conflicts with a predefined type");
+ }
+
+ //
+ // Resolves a single class during the corlib bootstrap process
+ //
+ static TypeBuilder BootstrapCorlib_ResolveClass (TypeContainer root, string name)
+ {
+ object o = root.GetDefinition (name);
+ if (o == null){
+ Report.Error (518, "The predefined type `" + name + "' is not defined");
+ return null;
+ }
+
+ if (!(o is Class)){
+ if (o is DeclSpace){
+ DeclSpace d = (DeclSpace) o;
+
+ Error_TypeConflict (name, d.Location);
+ } else
+ Error_TypeConflict (name);
+
+ return null;
+ }
+
+ return ((DeclSpace) o).DefineType ();
+ }
+
+ //
+ // Resolves a struct during the corlib bootstrap process
+ //
+ static void BootstrapCorlib_ResolveStruct (TypeContainer root, string name)
+ {
+ object o = root.GetDefinition (name);
+ if (o == null){
+ Report.Error (518, "The predefined type `" + name + "' is not defined");
+ return;
+ }
+
+ if (!(o is Struct)){
+ if (o is DeclSpace){
+ DeclSpace d = (DeclSpace) o;
+
+ Error_TypeConflict (name, d.Location);
+ } else
+ Error_TypeConflict (name);
+
+ return;
+ }
+
+ ((DeclSpace) o).DefineType ();
+ }
+
+ //
+ // Resolves a struct during the corlib bootstrap process
+ //
+ static void BootstrapCorlib_ResolveInterface (TypeContainer root, string name)
+ {
+ object o = root.GetDefinition (name);
+ if (o == null){
+ Report.Error (518, "The predefined type `" + name + "' is not defined");
+ return;
+ }
+
+ if (!(o is Interface)){
+ if (o is DeclSpace){
+ DeclSpace d = (DeclSpace) o;
+
+ Error_TypeConflict (name, d.Location);
+ } else
+ Error_TypeConflict (name);
+
+ return;
+ }
+
+ ((DeclSpace) o).DefineType ();
+ }
+
+ //
+ // Resolves a delegate during the corlib bootstrap process
+ //
+ static void BootstrapCorlib_ResolveDelegate (TypeContainer root, string name)
+ {
+ object o = root.GetDefinition (name);
+ if (o == null){
+ Report.Error (518, "The predefined type `" + name + "' is not defined");
+ Environment.Exit (0);
+ }
+
+ if (!(o is Delegate)){
+ Error_TypeConflict (name);
+ return;
+ }
+
+ ((DeclSpace) o).DefineType ();
+ }
+
+
+ /// <summary>
+ /// Resolves the core types in the compiler when compiling with --nostdlib
+ /// </summary>
+ static public void ResolveCore ()
+ {
+ TypeContainer root = Tree.Types;
+
+ TypeManager.object_type = BootstrapCorlib_ResolveClass (root, "System.Object");
+ TypeManager.value_type = BootstrapCorlib_ResolveClass (root, "System.ValueType");
+ TypeManager.attribute_type = BootstrapCorlib_ResolveClass (root, "System.Attribute");
+
+ string [] interfaces_first_stage = {
+ "System.IComparable", "System.ICloneable",
+ "System.IConvertible",
+
+ "System.Collections.IEnumerable",
+ "System.Collections.ICollection",
+ "System.Collections.IEnumerator",
+ "System.Collections.IList",
+ "System.IAsyncResult",
+ "System.IDisposable",
+
+ "System.Runtime.Serialization.ISerializable",
+
+ "System.Reflection.IReflect",
+ "System.Reflection.ICustomAttributeProvider"
+ };
+
+ foreach (string iname in interfaces_first_stage)
+ BootstrapCorlib_ResolveInterface (root, iname);
+
+ //
+ // These are the base value types
+ //
+ string [] structs_first_stage = {
+ "System.Byte", "System.SByte",
+ "System.Int16", "System.UInt16",
+ "System.Int32", "System.UInt32",
+ "System.Int64", "System.UInt64",
+ };
+
+ foreach (string cname in structs_first_stage)
+ BootstrapCorlib_ResolveStruct (root, cname);
+
+ //
+ // Now, we can load the enumerations, after this point,
+ // we can use enums.
+ //
+ TypeManager.InitEnumUnderlyingTypes ();
+
+ string [] structs_second_stage = {
+ "System.Single", "System.Double",
+ "System.Char", "System.Boolean",
+ "System.Decimal", "System.Void",
+ "System.RuntimeFieldHandle",
+ "System.RuntimeTypeHandle",
+ "System.IntPtr"
+ };
+
+ foreach (string cname in structs_second_stage)
+ BootstrapCorlib_ResolveStruct (root, cname);
+
+ //
+ // These are classes that depends on the core interfaces
+ //
+ string [] classes_second_stage = {
+ "System.Reflection.MemberInfo",
+ "System.Type",
+ "System.Exception",
+
+ //
+ // These are not really important in the order, but they
+ // are used by the compiler later on (typemanager/CoreLookupType-d)
+ //
+ "System.Runtime.CompilerServices.RuntimeHelpers",
+ "System.Reflection.DefaultMemberAttribute",
+ "System.Threading.Monitor",
+
+ "System.AttributeUsageAttribute",
+ "System.Runtime.InteropServices.DllImportAttribute",
+ "System.Runtime.CompilerServices.MethodImplAttribute",
+ "System.Runtime.InteropServices.MarshalAsAttribute",
+ "System.Diagnostics.ConditionalAttribute",
+ "System.ObsoleteAttribute",
+ "System.ParamArrayAttribute",
+ "System.Security.UnverifiableCodeAttribute",
+ "System.Runtime.CompilerServices.IndexerNameAttribute",
+ "System.Runtime.InteropServices.InAttribute",
+ "System.InvalidOperationException"
+
+ };
+
+ // We must store them here before calling BootstrapCorlib_ResolveDelegate.
+ TypeManager.string_type = BootstrapCorlib_ResolveClass (root, "System.String");
+ TypeManager.enum_type = BootstrapCorlib_ResolveClass (root, "System.Enum");
+ TypeManager.array_type = BootstrapCorlib_ResolveClass (root, "System.Array");
+ TypeManager.multicast_delegate_type = BootstrapCorlib_ResolveClass (root, "System.MulticastDelegate");
+ TypeManager.delegate_type = BootstrapCorlib_ResolveClass (root, "System.Delegate");
+
+ foreach (string cname in classes_second_stage)
+ BootstrapCorlib_ResolveClass (root, cname);
+
+ BootstrapCorlib_ResolveDelegate (root, "System.AsyncCallback");
+ }
+
+ // <summary>
+ // Closes all open types
+ // </summary>
+ //
+ // <remarks>
+ // We usually use TypeBuilder types. When we are done
+ // creating the type (which will happen after we have added
+ // methods, fields, etc) we need to "Define" them before we
+ // can save the Assembly
+ // </remarks>
+ static public void CloseTypes ()
+ {
+ TypeContainer root = Tree.Types;
+
+ ArrayList ifaces = root.Interfaces;
+
+ if (root.Enums != null)
+ foreach (Enum en in root.Enums)
+ en.CloseType ();
+
+ if (attribute_types != null)
+ foreach (TypeContainer tc in attribute_types)
+ tc.CloseType ();
+
+ foreach (Interface iface in interface_resolve_order)
+ iface.CloseType ();
+
+ //
+ // We do this in two passes, first we close the structs,
+ // then the classes, because it seems the code needs it this
+ // way. If this is really what is going on, we should probably
+ // make sure that we define the structs in order as well.
+ //
+ foreach (TypeContainer tc in type_container_resolve_order){
+ if (tc is Struct && tc.Parent == tree.Types){
+ tc.CloseType ();
+ }
+ }
+
+ foreach (TypeContainer tc in type_container_resolve_order){
+ if (!(tc is Struct && tc.Parent == tree.Types))
+ tc.CloseType ();
+ }
+
+ if (root.Delegates != null)
+ foreach (Delegate d in root.Delegates)
+ d.CloseType ();
+
+
+ //
+ // If we have a <PrivateImplementationDetails> class, close it
+ //
+ if (helper_classes != null){
+ foreach (TypeBuilder type_builder in helper_classes)
+ type_builder.CreateType ();
+ }
+ }
+
+ /// <summary>
+ /// Used to register classes that need to be closed after all the
+ /// user defined classes
+ /// </summary>
+ public static void RegisterHelperClass (TypeBuilder helper_class)
+ {
+ if (helper_classes == null)
+ helper_classes = new ArrayList ();
+ helper_classes.Add (helper_class);
+ }
+
+ //
+ // This idea is from Felix Arrese-Igor
+ //
+ // Returns : the implicit parent of a composite namespace string
+ // eg. Implicit parent of A.B is A
+ //
+ static public string ImplicitParent (string ns)
+ {
+ int i = ns.LastIndexOf (".");
+ if (i < 0)
+ return null;
+
+ return ns.Substring (0, i);
+ }
+
+ static Type NamespaceLookup (DeclSpace ds, string name, Location loc)
+ {
+ Type t;
+
+ //
+ // Try in the current namespace and all its implicit parents
+ //
+ for (NamespaceEntry ns = ds.Namespace; ns != null; ns = ns.ImplicitParent) {
+ t = TypeManager.LookupType (MakeFQN (ns.Name, name));
+ if (t != null) {
+ if (!ds.CheckAccessLevel (t))
+ t = null;
+ }
+ if (t != null)
+ return t;
+ }
+
+ //
+ // It's possible that name already is fully qualified. So we do
+ // a simple direct lookup without adding any namespace names
+ //
+ t = TypeManager.LookupType (name);
+ if (t != null)
+ return t;
+
+ //
+ // Try the aliases in the current namespace
+ //
+ string alias = ds.Namespace.LookupAlias (name);
+
+ if (alias != null) {
+ t = TypeManager.LookupType (alias);
+ if (t != null)
+ return t;
+
+ t = TypeManager.LookupType (MakeFQN (alias, name));
+ if (t != null)
+ return t;
+ }
+
+ for (NamespaceEntry ns = ds.Namespace; ns != null; ns = ns.Parent) {
+ //
+ // Look in the namespace ns
+ //
+ t = TypeManager.LookupType (MakeFQN (ns.Name, name));
+ if (t != null) {
+ if (!ds.CheckAccessLevel (t))
+ t = null;
+ }
+ if (t != null)
+ return t;
+
+ //
+ // Then try with the using clauses
+ //
+ Type match = null;
+ foreach (Namespace using_ns in ns.GetUsingTable ()) {
+ string full_name = DeclSpace.MakeFQN (using_ns.Name, name);
+ match = TypeManager.LookupType (full_name);
+ if (match != null){
+ if (t != null) {
+ if (ds.CheckAccessLevel (match)) {
+ DeclSpace.Error_AmbiguousTypeReference (loc, name, t, match);
+ return null;
+ }
+ continue;
+ } else {
+ if (ds.CheckAccessLevel (match))
+ t = match;
+ }
+ }
+ }
+
+ if (t != null)
+ return t;
+
+ //
+ // Try with aliases
+ //
+ string a = ns.LookupAlias (name);
+ if (a != null) {
+ t = TypeManager.LookupType (a);
+ if (t != null)
+ return t;
+
+ t = TypeManager.LookupType (MakeFQN (a, name));
+ if (t != null)
+ return t;
+ }
+ }
+
+ return null;
+ }
+
+ //
+ // Public function used to locate types, this can only
+ // be used after the ResolveTree function has been invoked.
+ //
+ // Returns: Type or null if they type can not be found.
+ //
+ // Come to think of it, this should be a DeclSpace
+ //
+ static public Type LookupType (DeclSpace ds, string name, bool silent, Location loc)
+ {
+ Type t;
+
+ if (ds.Cache.Contains (name)){
+ t = (Type) ds.Cache [name];
+ if (t != null)
+ return t;
+ } else {
+ //
+ // For the case the type we are looking for is nested within this one
+ // or is in any base class
+ //
+ DeclSpace containing_ds = ds;
+ while (containing_ds != null){
+ Type current_type = containing_ds.TypeBuilder;
+
+ while (current_type != null) {
+ //
+ // nested class
+ //
+ t = TypeManager.LookupType (current_type.FullName + "." + name);
+ if (t != null){
+ ds.Cache [name] = t;
+ return t;
+ }
+
+ current_type = current_type.BaseType;
+ }
+
+ containing_ds = containing_ds.Parent;
+ }
+
+ t = NamespaceLookup (ds, name, loc);
+ if (t != null){
+ ds.Cache [name] = t;
+ return t;
+ }
+ }
+
+ if (!silent)
+ Report.Error (246, loc, "Cannot find type `"+name+"'");
+
+ return null;
+ }
+
+ // <summary>
+ // This is the silent version of LookupType, you can use this
+ // to `probe' for a type
+ // </summary>
+ static public Type LookupType (TypeContainer tc, string name, Location loc)
+ {
+ return LookupType (tc, name, true, loc);
+ }
+
+ static public bool IsNamespace (string name)
+ {
+ Namespace ns;
+
+ if (tree.Namespaces != null){
+ ns = (Namespace) tree.Namespaces [name];
+
+ if (ns != null)
+ return true;
+ }
+
+ return false;
+ }
+
+ static void Report1530 (Location loc)
+ {
+ Report.Error (1530, loc, "Keyword new not allowed for namespace elements");
+ }
+
+ static public void PopulateCoreType (TypeContainer root, string name)
+ {
+ DeclSpace ds = (DeclSpace) root.GetDefinition (name);
+
+ ds.DefineMembers (root);
+ ds.Define (root);
+ }
+
+ static public void BootCorlib_PopulateCoreTypes ()
+ {
+ TypeContainer root = tree.Types;
+
+ PopulateCoreType (root, "System.Object");
+ PopulateCoreType (root, "System.ValueType");
+ PopulateCoreType (root, "System.Attribute");
+ }
+
+ // <summary>
+ // Populates the structs and classes with fields and methods
+ // </summary>
+ //
+ // This is invoked after all interfaces, structs and classes
+ // have been defined through `ResolveTree'
+ static public void PopulateTypes ()
+ {
+ TypeContainer root = Tree.Types;
+
+ if (attribute_types != null)
+ foreach (TypeContainer tc in attribute_types)
+ tc.DefineMembers (root);
+
+ if (interface_resolve_order != null){
+ foreach (Interface iface in interface_resolve_order)
+ if ((iface.ModFlags & Modifiers.NEW) == 0)
+ iface.DefineMembers (root);
+ else
+ Report1530 (iface.Location);
+ }
+
+
+ if (type_container_resolve_order != null){
+ if (RootContext.StdLib){
+ foreach (TypeContainer tc in type_container_resolve_order)
+ tc.DefineMembers (root);
+ } else {
+ foreach (TypeContainer tc in type_container_resolve_order) {
+ // When compiling corlib, these types have already been
+ // populated from BootCorlib_PopulateCoreTypes ().
+ if (((tc.Name == "System.Object") ||
+ (tc.Name == "System.Attribute") ||
+ (tc.Name == "System.ValueType")))
+ continue;
+
+ tc.DefineMembers (root);
+ }
+ }
+ }
+
+ ArrayList delegates = root.Delegates;
+ if (delegates != null){
+ foreach (Delegate d in delegates)
+ if ((d.ModFlags & Modifiers.NEW) == 0)
+ d.DefineMembers (root);
+ else
+ Report1530 (d.Location);
+ }
+
+ ArrayList enums = root.Enums;
+ if (enums != null){
+ foreach (Enum en in enums)
+ if ((en.ModFlags & Modifiers.NEW) == 0)
+ en.DefineMembers (root);
+ else
+ Report1530 (en.Location);
+ }
+ }
+
+ //
+ // A generic hook delegate
+ //
+ public delegate void Hook ();
+
+ //
+ // A hook invoked when the code has been generated.
+ //
+ public static event Hook EmitCodeHook;
+
+ //
+ // DefineTypes is used to fill in the members of each type.
+ //
+ static public void DefineTypes ()
+ {
+ TypeContainer root = Tree.Types;
+
+ if (attribute_types != null)
+ foreach (TypeContainer tc in attribute_types)
+ tc.Define (root);
+
+ if (interface_resolve_order != null){
+ foreach (Interface iface in interface_resolve_order)
+ if ((iface.ModFlags & Modifiers.NEW) == 0)
+ iface.Define (root);
+ }
+
+
+ if (type_container_resolve_order != null){
+ foreach (TypeContainer tc in type_container_resolve_order) {
+ // When compiling corlib, these types have already been
+ // populated from BootCorlib_PopulateCoreTypes ().
+ if (!RootContext.StdLib &&
+ ((tc.Name == "System.Object") ||
+ (tc.Name == "System.Attribute") ||
+ (tc.Name == "System.ValueType")))
+ continue;
+
+ if ((tc.ModFlags & Modifiers.NEW) == 0)
+ tc.Define (root);
+ }
+ }
+
+ ArrayList delegates = root.Delegates;
+ if (delegates != null){
+ foreach (Delegate d in delegates)
+ if ((d.ModFlags & Modifiers.NEW) == 0)
+ d.Define (root);
+ }
+
+ ArrayList enums = root.Enums;
+ if (enums != null){
+ foreach (Enum en in enums)
+ if ((en.ModFlags & Modifiers.NEW) == 0)
+ en.Define (root);
+ }
+ }
+
+ static public void EmitCode ()
+ {
+ //
+ // Because of the strange way in which we do things, global
+ // attributes must be processed first.
+ //
+ if (global_attributes.Count > 0){
+ AssemblyBuilder ab = CodeGen.AssemblyBuilder;
+ TypeContainer dummy = new TypeContainer (null, "", new Location (-1));
+ EmitContext temp_ec = new EmitContext (
+ dummy, Mono.CSharp.Location.Null, null, null, 0, false);
+
+ foreach (DictionaryEntry de in global_attributes){
+ NamespaceEntry ns = (NamespaceEntry) de.Key;
+ Attributes attrs = (Attributes) de.Value;
+
+ dummy.Namespace = ns;
+ Attribute.ApplyAttributes (temp_ec, ab, ab, attrs);
+ }
+ }
+
+ if (attribute_types != null)
+ foreach (TypeContainer tc in attribute_types)
+ tc.Emit ();
+
+ if (interface_resolve_order != null){
+ foreach (Interface iface in interface_resolve_order)
+ iface.Emit (Tree.Types);
+ }
+
+ if (type_container_resolve_order != null) {
+ foreach (TypeContainer tc in type_container_resolve_order)
+ tc.EmitConstants ();
+
+ foreach (TypeContainer tc in type_container_resolve_order)
+ tc.Emit ();
+ }
+
+ //
+ // Run any hooks after all the types have been defined.
+ // This is used to create nested auxiliary classes for example
+ //
+
+ if (EmitCodeHook != null)
+ EmitCodeHook ();
+
+
+ if (Unsafe) {
+ if (TypeManager.unverifiable_code_ctor == null) {
+ Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
+ return;
+ }
+
+ CustomAttributeBuilder cb = new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor,
+ new object [0]);
+ CodeGen.ModuleBuilder.SetCustomAttribute (cb);
+ }
+ }
+
+ //
+ // Public Field, used to track which method is the public entry
+ // point.
+ //
+ static public MethodInfo EntryPoint;
+
+ //
+ // Track the location of the entry point.
+ //
+ static public Location EntryPointLocation;
+
+ //
+ // These are used to generate unique names on the structs and fields.
+ //
+ static int field_count;
+
+ //
+ // Makes an initialized struct, returns the field builder that
+ // references the data. Thanks go to Sergey Chaban for researching
+ // how to do this. And coming up with a shorter mechanism than I
+ // was able to figure out.
+ //
+ // This works but makes an implicit public struct $ArrayType$SIZE and
+ // makes the fields point to it. We could get more control if we did
+ // use instead:
+ //
+ // 1. DefineNestedType on the impl_details_class with our struct.
+ //
+ // 2. Define the field on the impl_details_class
+ //
+ static public FieldBuilder MakeStaticData (byte [] data)
+ {
+ FieldBuilder fb;
+ int size = data.Length;
+
+ if (impl_details_class == null){
+ impl_details_class = CodeGen.ModuleBuilder.DefineType (
+ "<PrivateImplementationDetails>",
+ TypeAttributes.NotPublic,
+ TypeManager.object_type);
+
+ RegisterHelperClass (impl_details_class);
+ }
+
+ fb = impl_details_class.DefineInitializedData (
+ "$$field-" + (field_count++), data,
+ FieldAttributes.Static | FieldAttributes.Assembly);
+
+ return fb;
+ }
+
+ //
+ // Adds a global attribute that was declared in `container',
+ // the attribute is in `attr', and it was defined at `loc'
+ //
+ static public void AddGlobalAttributeSection (TypeContainer container, AttributeSection attr)
+ {
+ NamespaceEntry ns = container.Namespace;
+ Attributes a = (Attributes) global_attributes [ns];
+
+ if (a == null)
+ global_attributes [ns] = new Attributes (attr);
+ else
+ a.AddAttributeSection (attr);
+ }
+ }
+}
+
+
--- /dev/null
+//
+// statement.cs: Statement representation for the IL tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Martin Baulig (martin@gnome.org)
+//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+//
+
+using System;
+using System.Text;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+
+namespace Mono.CSharp {
+
+ using System.Collections;
+
+ public abstract class Statement {
+ public Location loc;
+
+ ///
+ /// Resolves the statement, true means that all sub-statements
+ /// did resolve ok.
+ //
+ public virtual bool Resolve (EmitContext ec)
+ {
+ return true;
+ }
+
+ /// <summary>
+ /// Return value indicates whether all code paths emitted return.
+ /// </summary>
+ protected abstract bool DoEmit (EmitContext ec);
+
+ /// <summary>
+ /// Return value indicates whether all code paths emitted return.
+ /// </summary>
+ public virtual bool Emit (EmitContext ec)
+ {
+ ec.Mark (loc, true);
+ return DoEmit (ec);
+ }
+
+ /// <remarks>
+ /// Encapsulates the emission of a boolean test and jumping to a
+ /// destination.
+ ///
+ /// This will emit the bool expression in `bool_expr' and if
+ /// `target_is_for_true' is true, then the code will generate a
+ /// brtrue to the target. Otherwise a brfalse.
+ /// </remarks>
+ public static void EmitBoolExpression (EmitContext ec, Expression bool_expr,
+ Label target, bool target_is_for_true)
+ {
+ ILGenerator ig = ec.ig;
+
+ bool invert = false;
+ if (bool_expr is Unary){
+ Unary u = (Unary) bool_expr;
+
+ if (u.Oper == Unary.Operator.LogicalNot){
+ invert = true;
+
+ u.EmitLogicalNot (ec);
+ }
+ } else if (bool_expr is Binary){
+ Binary b = (Binary) bool_expr;
+
+ if (b.EmitBranchable (ec, target, target_is_for_true))
+ return;
+ }
+
+ if (!invert)
+ bool_expr.Emit (ec);
+
+ if (target_is_for_true){
+ if (invert)
+ ig.Emit (OpCodes.Brfalse, target);
+ else
+ ig.Emit (OpCodes.Brtrue, target);
+ } else {
+ if (invert)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ }
+ }
+
+ public static void Warning_DeadCodeFound (Location loc)
+ {
+ Report.Warning (162, loc, "Unreachable code detected");
+ }
+ }
+
+ public class EmptyStatement : Statement {
+ public override bool Resolve (EmitContext ec)
+ {
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ return false;
+ }
+ }
+
+ public class If : Statement {
+ Expression expr;
+ public Statement TrueStatement;
+ public Statement FalseStatement;
+
+ public If (Expression expr, Statement trueStatement, Location l)
+ {
+ this.expr = expr;
+ TrueStatement = trueStatement;
+ loc = l;
+ }
+
+ public If (Expression expr,
+ Statement trueStatement,
+ Statement falseStatement,
+ Location l)
+ {
+ this.expr = expr;
+ TrueStatement = trueStatement;
+ FalseStatement = falseStatement;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ Report.Debug (1, "START IF BLOCK", loc);
+
+ expr = Expression.ResolveBoolean (ec, expr, loc);
+ if (expr == null){
+ return false;
+ }
+
+ ec.StartFlowBranching (FlowBranchingType.BLOCK, loc);
+
+ if (!TrueStatement.Resolve (ec)) {
+ ec.KillFlowBranching ();
+ return false;
+ }
+
+ ec.CurrentBranching.CreateSibling ();
+
+ if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) {
+ ec.KillFlowBranching ();
+ return false;
+ }
+
+ ec.EndFlowBranching ();
+
+ Report.Debug (1, "END IF BLOCK", loc);
+
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label false_target = ig.DefineLabel ();
+ Label end;
+ bool is_true_ret, is_false_ret;
+
+ //
+ // Dead code elimination
+ //
+ if (expr is BoolConstant){
+ bool take = ((BoolConstant) expr).Value;
+
+ if (take){
+ if (FalseStatement != null){
+ Warning_DeadCodeFound (FalseStatement.loc);
+ }
+ return TrueStatement.Emit (ec);
+ } else {
+ Warning_DeadCodeFound (TrueStatement.loc);
+ if (FalseStatement != null)
+ return FalseStatement.Emit (ec);
+ }
+ }
+
+ EmitBoolExpression (ec, expr, false_target, false);
+
+ is_true_ret = TrueStatement.Emit (ec);
+ is_false_ret = is_true_ret;
+
+ if (FalseStatement != null){
+ bool branch_emitted = false;
+
+ end = ig.DefineLabel ();
+ if (!is_true_ret){
+ ig.Emit (OpCodes.Br, end);
+ branch_emitted = true;
+ }
+
+ ig.MarkLabel (false_target);
+ is_false_ret = FalseStatement.Emit (ec);
+
+ if (branch_emitted)
+ ig.MarkLabel (end);
+ } else {
+ ig.MarkLabel (false_target);
+ is_false_ret = false;
+ }
+
+ return is_true_ret && is_false_ret;
+ }
+ }
+
+ public class Do : Statement {
+ public Expression expr;
+ public readonly Statement EmbeddedStatement;
+ bool infinite, may_return;
+
+ public Do (Statement statement, Expression boolExpr, Location l)
+ {
+ expr = boolExpr;
+ EmbeddedStatement = statement;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = true;
+
+ ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+
+ if (!EmbeddedStatement.Resolve (ec))
+ ok = false;
+
+ expr = Expression.ResolveBoolean (ec, expr, loc);
+ if (expr == null)
+ ok = false;
+ else if (expr is BoolConstant){
+ bool res = ((BoolConstant) expr).Value;
+
+ if (res)
+ infinite = true;
+ }
+
+ ec.CurrentBranching.Infinite = infinite;
+ FlowReturns returns = ec.EndFlowBranching ();
+ may_return = returns != FlowReturns.NEVER;
+
+ return ok;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label loop = ig.DefineLabel ();
+ Label old_begin = ec.LoopBegin;
+ Label old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
+ int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
+
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+ ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
+
+ ig.MarkLabel (loop);
+ EmbeddedStatement.Emit (ec);
+ ig.MarkLabel (ec.LoopBegin);
+
+ //
+ // Dead code elimination
+ //
+ if (expr is BoolConstant){
+ bool res = ((BoolConstant) expr).Value;
+
+ if (res)
+ ec.ig.Emit (OpCodes.Br, loop);
+ } else
+ EmitBoolExpression (ec, expr, loop, true);
+
+ ig.MarkLabel (ec.LoopEnd);
+
+ ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
+
+ if (infinite)
+ return may_return == false;
+ else
+ return false;
+ }
+ }
+
+ public class While : Statement {
+ public Expression expr;
+ public readonly Statement Statement;
+ bool may_return, empty, infinite;
+
+ public While (Expression boolExpr, Statement statement, Location l)
+ {
+ this.expr = boolExpr;
+ Statement = statement;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = true;
+
+ expr = Expression.ResolveBoolean (ec, expr, loc);
+ if (expr == null)
+ return false;
+
+ ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+
+ //
+ // Inform whether we are infinite or not
+ //
+ if (expr is BoolConstant){
+ BoolConstant bc = (BoolConstant) expr;
+
+ if (bc.Value == false){
+ Warning_DeadCodeFound (Statement.loc);
+ empty = true;
+ } else
+ infinite = true;
+ } else {
+ //
+ // We are not infinite, so the loop may or may not be executed.
+ //
+ ec.CurrentBranching.CreateSibling ();
+ }
+
+ if (!Statement.Resolve (ec))
+ ok = false;
+
+ if (empty)
+ ec.KillFlowBranching ();
+ else {
+ ec.CurrentBranching.Infinite = infinite;
+ FlowReturns returns = ec.EndFlowBranching ();
+ may_return = returns != FlowReturns.NEVER;
+ }
+
+ return ok;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ if (empty)
+ return false;
+
+ ILGenerator ig = ec.ig;
+ Label old_begin = ec.LoopBegin;
+ Label old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
+ int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
+ bool ret;
+
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+ ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
+
+ //
+ // Inform whether we are infinite or not
+ //
+ if (expr is BoolConstant){
+ BoolConstant bc = (BoolConstant) expr;
+
+ ig.MarkLabel (ec.LoopBegin);
+ Statement.Emit (ec);
+ ig.Emit (OpCodes.Br, ec.LoopBegin);
+
+ //
+ // Inform that we are infinite (ie, `we return'), only
+ // if we do not `break' inside the code.
+ //
+ ret = may_return == false;
+ ig.MarkLabel (ec.LoopEnd);
+ } else {
+ Label while_loop = ig.DefineLabel ();
+
+ ig.Emit (OpCodes.Br, ec.LoopBegin);
+ ig.MarkLabel (while_loop);
+
+ Statement.Emit (ec);
+
+ ig.MarkLabel (ec.LoopBegin);
+
+ EmitBoolExpression (ec, expr, while_loop, true);
+ ig.MarkLabel (ec.LoopEnd);
+
+ ret = false;
+ }
+
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
+ ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
+
+ return ret;
+ }
+ }
+
+ public class For : Statement {
+ Expression Test;
+ readonly Statement InitStatement;
+ readonly Statement Increment;
+ readonly Statement Statement;
+ bool may_return, infinite, empty;
+
+ public For (Statement initStatement,
+ Expression test,
+ Statement increment,
+ Statement statement,
+ Location l)
+ {
+ InitStatement = initStatement;
+ Test = test;
+ Increment = increment;
+ Statement = statement;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = true;
+
+ if (InitStatement != null){
+ if (!InitStatement.Resolve (ec))
+ ok = false;
+ }
+
+ if (Test != null){
+ Test = Expression.ResolveBoolean (ec, Test, loc);
+ if (Test == null)
+ ok = false;
+ else if (Test is BoolConstant){
+ BoolConstant bc = (BoolConstant) Test;
+
+ if (bc.Value == false){
+ Warning_DeadCodeFound (Statement.loc);
+ empty = true;
+ } else
+ infinite = true;
+ }
+ } else
+ infinite = true;
+
+ ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+ if (!infinite)
+ ec.CurrentBranching.CreateSibling ();
+
+ if (!Statement.Resolve (ec))
+ ok = false;
+
+ if (Increment != null){
+ if (!Increment.Resolve (ec))
+ ok = false;
+ }
+
+ if (empty)
+ ec.KillFlowBranching ();
+ else {
+ ec.CurrentBranching.Infinite = infinite;
+ FlowReturns returns = ec.EndFlowBranching ();
+ may_return = returns != FlowReturns.NEVER;
+ }
+
+ return ok;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ if (empty)
+ return false;
+
+ ILGenerator ig = ec.ig;
+ Label old_begin = ec.LoopBegin;
+ Label old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
+ int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
+ Label loop = ig.DefineLabel ();
+ Label test = ig.DefineLabel ();
+
+ if (InitStatement != null)
+ if (! (InitStatement is EmptyStatement))
+ InitStatement.Emit (ec);
+
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+ ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
+
+ ig.Emit (OpCodes.Br, test);
+ ig.MarkLabel (loop);
+ Statement.Emit (ec);
+
+ ig.MarkLabel (ec.LoopBegin);
+ if (!(Increment is EmptyStatement))
+ Increment.Emit (ec);
+
+ ig.MarkLabel (test);
+ //
+ // If test is null, there is no test, and we are just
+ // an infinite loop
+ //
+ if (Test != null){
+ //
+ // The Resolve code already catches the case for Test == BoolConstant (false)
+ // so we know that this is true
+ //
+ if (Test is BoolConstant)
+ ig.Emit (OpCodes.Br, loop);
+ else
+ EmitBoolExpression (ec, Test, loop, true);
+ } else
+ ig.Emit (OpCodes.Br, loop);
+ ig.MarkLabel (ec.LoopEnd);
+
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
+ ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
+
+ //
+ // Inform whether we are infinite or not
+ //
+ if (Test != null){
+ if (Test is BoolConstant){
+ BoolConstant bc = (BoolConstant) Test;
+
+ if (bc.Value)
+ return may_return == false;
+ }
+ return false;
+ } else
+ return may_return == false;
+ }
+ }
+
+ public class StatementExpression : Statement {
+ ExpressionStatement expr;
+
+ public StatementExpression (ExpressionStatement expr, Location l)
+ {
+ this.expr = expr;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ expr = expr.ResolveStatement (ec);
+ return expr != null;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ expr.EmitStatement (ec);
+
+ return false;
+ }
+
+ public override string ToString ()
+ {
+ return "StatementExpression (" + expr + ")";
+ }
+ }
+
+ /// <summary>
+ /// Implements the return statement
+ /// </summary>
+ public class Return : Statement {
+ public Expression Expr;
+
+ public Return (Expression expr, Location l)
+ {
+ Expr = expr;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (Expr != null){
+ Expr = Expr.Resolve (ec);
+ if (Expr == null)
+ return false;
+ }
+
+ if (ec.InIterator){
+ Report.Error (-206, loc, "Return statement not allowed inside iterators");
+ return false;
+ }
+
+ FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
+
+ if (ec.CurrentBranching.InTryBlock ())
+ ec.CurrentBranching.AddFinallyVector (vector);
+ else
+ vector.CheckOutParameters (ec.CurrentBranching);
+
+ vector.Returns = FlowReturns.ALWAYS;
+ vector.Breaks = FlowReturns.ALWAYS;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ if (ec.InFinally){
+ Report.Error (157, loc, "Control can not leave the body of the finally block");
+ return false;
+ }
+
+ if (ec.ReturnType == null){
+ if (Expr != null){
+ Report.Error (127, loc, "Return with a value not allowed here");
+ return true;
+ }
+ } else {
+ if (Expr == null){
+ Report.Error (126, loc, "An object of type `" +
+ TypeManager.CSharpName (ec.ReturnType) + "' is " +
+ "expected for the return statement");
+ return true;
+ }
+
+ if (Expr.Type != ec.ReturnType)
+ Expr = Convert.ImplicitConversionRequired (
+ ec, Expr, ec.ReturnType, loc);
+
+ if (Expr == null)
+ return true;
+
+ Expr.Emit (ec);
+
+ if (ec.InTry || ec.InCatch)
+ ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
+ }
+
+ if (ec.InTry || ec.InCatch) {
+ if (!ec.HasReturnLabel) {
+ ec.ReturnLabel = ec.ig.DefineLabel ();
+ ec.HasReturnLabel = true;
+ }
+ ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
+ } else {
+ ec.ig.Emit (OpCodes.Ret);
+ ec.NeedExplicitReturn = false;
+ }
+
+ return true;
+ }
+ }
+
+ public class Goto : Statement {
+ string target;
+ Block block;
+ LabeledStatement label;
+
+ public override bool Resolve (EmitContext ec)
+ {
+ label = block.LookupLabel (target);
+ if (label == null){
+ Report.Error (
+ 159, loc,
+ "No such label `" + target + "' in this scope");
+ return false;
+ }
+
+ // If this is a forward goto.
+ if (!label.IsDefined)
+ label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
+
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+
+ return true;
+ }
+
+ public Goto (Block parent_block, string label, Location l)
+ {
+ block = parent_block;
+ loc = l;
+ target = label;
+ }
+
+ public string Target {
+ get {
+ return target;
+ }
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ Label l = label.LabelTarget (ec);
+ ec.ig.Emit (OpCodes.Br, l);
+
+ return false;
+ }
+ }
+
+ public class LabeledStatement : Statement {
+ public readonly Location Location;
+ string label_name;
+ bool defined;
+ bool referenced;
+ Label label;
+
+ ArrayList vectors;
+
+ public LabeledStatement (string label_name, Location l)
+ {
+ this.label_name = label_name;
+ this.Location = l;
+ }
+
+ public Label LabelTarget (EmitContext ec)
+ {
+ if (defined)
+ return label;
+ label = ec.ig.DefineLabel ();
+ defined = true;
+
+ return label;
+ }
+
+ public bool IsDefined {
+ get {
+ return defined;
+ }
+ }
+
+ public bool HasBeenReferenced {
+ get {
+ return referenced;
+ }
+ }
+
+ public void AddUsageVector (FlowBranching.UsageVector vector)
+ {
+ if (vectors == null)
+ vectors = new ArrayList ();
+
+ vectors.Add (vector.Clone ());
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (vectors != null)
+ ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
+ else {
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER;
+ }
+
+ referenced = true;
+
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ LabelTarget (ec);
+ ec.ig.MarkLabel (label);
+
+ return false;
+ }
+ }
+
+
+ /// <summary>
+ /// `goto default' statement
+ /// </summary>
+ public class GotoDefault : Statement {
+
+ public GotoDefault (Location l)
+ {
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ if (ec.Switch == null){
+ Report.Error (153, loc, "goto default is only valid in a switch statement");
+ return false;
+ }
+
+ if (!ec.Switch.GotDefault){
+ Report.Error (159, loc, "No default target on switch statement");
+ return false;
+ }
+ ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// `goto case' statement
+ /// </summary>
+ public class GotoCase : Statement {
+ Expression expr;
+ Label label;
+
+ public GotoCase (Expression e, Location l)
+ {
+ expr = e;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (ec.Switch == null){
+ Report.Error (153, loc, "goto case is only valid in a switch statement");
+ return false;
+ }
+
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
+
+ if (!(expr is Constant)){
+ Report.Error (159, loc, "Target expression for goto case is not constant");
+ return false;
+ }
+
+ object val = Expression.ConvertIntLiteral (
+ (Constant) expr, ec.Switch.SwitchType, loc);
+
+ if (val == null)
+ return false;
+
+ SwitchLabel sl = (SwitchLabel) ec.Switch.Elements [val];
+
+ if (sl == null){
+ Report.Error (
+ 159, loc,
+ "No such label 'case " + val + "': for the goto case");
+ return false;
+ }
+
+ label = sl.ILLabelCode;
+
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Br, label);
+ return true;
+ }
+ }
+
+ public class Throw : Statement {
+ Expression expr;
+
+ public Throw (Expression expr, Location l)
+ {
+ this.expr = expr;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (expr != null){
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
+
+ ExprClass eclass = expr.eclass;
+
+ if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
+ eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
+ expr.Error_UnexpectedKind ("value, variable, property or indexer access ");
+ return false;
+ }
+
+ Type t = expr.Type;
+
+ if ((t != TypeManager.exception_type) &&
+ !t.IsSubclassOf (TypeManager.exception_type) &&
+ !(expr is NullLiteral)) {
+ Report.Error (155, loc,
+ "The type caught or thrown must be derived " +
+ "from System.Exception");
+ return false;
+ }
+ }
+
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.EXCEPTION;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.EXCEPTION;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ if (expr == null){
+ if (ec.InCatch)
+ ec.ig.Emit (OpCodes.Rethrow);
+ else {
+ Report.Error (
+ 156, loc,
+ "A throw statement with no argument is only " +
+ "allowed in a catch clause");
+ }
+ return false;
+ }
+
+ expr.Emit (ec);
+
+ ec.ig.Emit (OpCodes.Throw);
+
+ return true;
+ }
+ }
+
+ public class Break : Statement {
+
+ public Break (Location l)
+ {
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ ec.CurrentBranching.MayLeaveLoop = true;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (ec.InLoop == false && ec.Switch == null){
+ Report.Error (139, loc, "No enclosing loop or switch to continue to");
+ return false;
+ }
+
+ if (ec.InTry || ec.InCatch)
+ ig.Emit (OpCodes.Leave, ec.LoopEnd);
+ else
+ ig.Emit (OpCodes.Br, ec.LoopEnd);
+
+ return false;
+ }
+ }
+
+ public class Continue : Statement {
+
+ public Continue (Location l)
+ {
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ Label begin = ec.LoopBegin;
+
+ if (!ec.InLoop){
+ Report.Error (139, loc, "No enclosing loop to continue to");
+ return false;
+ }
+
+ //
+ // UGH: Non trivial. This Br might cross a try/catch boundary
+ // How can we tell?
+ //
+ // while () {
+ // try { ... } catch { continue; }
+ // }
+ //
+ // From:
+ // try {} catch { while () { continue; }}
+ //
+ if (ec.TryCatchLevel > ec.LoopBeginTryCatchLevel)
+ ec.ig.Emit (OpCodes.Leave, begin);
+ else if (ec.TryCatchLevel < ec.LoopBeginTryCatchLevel)
+ throw new Exception ("Should never happen");
+ else
+ ec.ig.Emit (OpCodes.Br, begin);
+ return false;
+ }
+ }
+
+ // <summary>
+ // This is used in the control flow analysis code to specify whether the
+ // current code block may return to its enclosing block before reaching
+ // its end.
+ // </summary>
+ public enum FlowReturns {
+ // It can never return.
+ NEVER,
+
+ // This means that the block contains a conditional return statement
+ // somewhere.
+ SOMETIMES,
+
+ // The code always returns, ie. there's an unconditional return / break
+ // statement in it.
+ ALWAYS,
+
+ // The code always throws an exception.
+ EXCEPTION,
+
+ // The current code block is unreachable. This happens if it's immediately
+ // following a FlowReturns.ALWAYS block.
+ UNREACHABLE
+ }
+
+ // <summary>
+ // This is a special bit vector which can inherit from another bit vector doing a
+ // copy-on-write strategy. The inherited vector may have a smaller size than the
+ // current one.
+ // </summary>
+ public class MyBitVector {
+ public readonly int Count;
+ public readonly MyBitVector InheritsFrom;
+
+ bool is_dirty;
+ BitArray vector;
+
+ public MyBitVector (int Count)
+ : this (null, Count)
+ { }
+
+ public MyBitVector (MyBitVector InheritsFrom, int Count)
+ {
+ this.InheritsFrom = InheritsFrom;
+ this.Count = Count;
+ }
+
+ // <summary>
+ // Checks whether this bit vector has been modified. After setting this to true,
+ // we won't use the inherited vector anymore, but our own copy of it.
+ // </summary>
+ public bool IsDirty {
+ get {
+ return is_dirty;
+ }
+
+ set {
+ if (!is_dirty)
+ initialize_vector ();
+ }
+ }
+
+ // <summary>
+ // Get/set bit `index' in the bit vector.
+ // </summary>
+ public bool this [int index]
+ {
+ get {
+ if (index > Count)
+ throw new ArgumentOutOfRangeException ();
+
+ // We're doing a "copy-on-write" strategy here; as long
+ // as nobody writes to the array, we can use our parent's
+ // copy instead of duplicating the vector.
+
+ if (vector != null)
+ return vector [index];
+ else if (InheritsFrom != null) {
+ BitArray inherited = InheritsFrom.Vector;
+
+ if (index < inherited.Count)
+ return inherited [index];
+ else
+ return false;
+ } else
+ return false;
+ }
+
+ set {
+ if (index > Count)
+ throw new ArgumentOutOfRangeException ();
+
+ // Only copy the vector if we're actually modifying it.
+
+ if (this [index] != value) {
+ initialize_vector ();
+
+ vector [index] = value;
+ }
+ }
+ }
+
+ // <summary>
+ // If you explicitly convert the MyBitVector to a BitArray, you will get a deep
+ // copy of the bit vector.
+ // </summary>
+ public static explicit operator BitArray (MyBitVector vector)
+ {
+ vector.initialize_vector ();
+ return vector.Vector;
+ }
+
+ // <summary>
+ // Performs an `or' operation on the bit vector. The `new_vector' may have a
+ // different size than the current one.
+ // </summary>
+ public void Or (MyBitVector new_vector)
+ {
+ BitArray new_array = new_vector.Vector;
+
+ initialize_vector ();
+
+ int upper;
+ if (vector.Count < new_array.Count)
+ upper = vector.Count;
+ else
+ upper = new_array.Count;
+
+ for (int i = 0; i < upper; i++)
+ vector [i] = vector [i] | new_array [i];
+ }
+
+ // <summary>
+ // Perfonrms an `and' operation on the bit vector. The `new_vector' may have
+ // a different size than the current one.
+ // </summary>
+ public void And (MyBitVector new_vector)
+ {
+ BitArray new_array = new_vector.Vector;
+
+ initialize_vector ();
+
+ int lower, upper;
+ if (vector.Count < new_array.Count)
+ lower = upper = vector.Count;
+ else {
+ lower = new_array.Count;
+ upper = vector.Count;
+ }
+
+ for (int i = 0; i < lower; i++)
+ vector [i] = vector [i] & new_array [i];
+
+ for (int i = lower; i < upper; i++)
+ vector [i] = false;
+ }
+
+ // <summary>
+ // This does a deep copy of the bit vector.
+ // </summary>
+ public MyBitVector Clone ()
+ {
+ MyBitVector retval = new MyBitVector (Count);
+
+ retval.Vector = Vector;
+
+ return retval;
+ }
+
+ BitArray Vector {
+ get {
+ if (vector != null)
+ return vector;
+ else if (!is_dirty && (InheritsFrom != null))
+ return InheritsFrom.Vector;
+
+ initialize_vector ();
+
+ return vector;
+ }
+
+ set {
+ initialize_vector ();
+
+ for (int i = 0; i < Math.Min (vector.Count, value.Count); i++)
+ vector [i] = value [i];
+ }
+ }
+
+ void initialize_vector ()
+ {
+ if (vector != null)
+ return;
+
+ vector = new BitArray (Count, false);
+ if (InheritsFrom != null)
+ Vector = InheritsFrom.Vector;
+
+ is_dirty = true;
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder ("MyBitVector (");
+
+ BitArray vector = Vector;
+ sb.Append (Count);
+ sb.Append (",");
+ if (!IsDirty)
+ sb.Append ("INHERITED - ");
+ for (int i = 0; i < vector.Count; i++) {
+ if (i > 0)
+ sb.Append (",");
+ sb.Append (vector [i]);
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+ }
+ }
+
+ // <summary>
+ // The type of a FlowBranching.
+ // </summary>
+ public enum FlowBranchingType {
+ // Normal (conditional or toplevel) block.
+ BLOCK,
+
+ // A loop block.
+ LOOP_BLOCK,
+
+ // Try/Catch block.
+ EXCEPTION,
+
+ // Switch block.
+ SWITCH,
+
+ // Switch section.
+ SWITCH_SECTION
+ }
+
+ // <summary>
+ // A new instance of this class is created every time a new block is resolved
+ // and if there's branching in the block's control flow.
+ // </summary>
+ public class FlowBranching {
+ // <summary>
+ // The type of this flow branching.
+ // </summary>
+ public readonly FlowBranchingType Type;
+
+ // <summary>
+ // The block this branching is contained in. This may be null if it's not
+ // a top-level block and it doesn't declare any local variables.
+ // </summary>
+ public readonly Block Block;
+
+ // <summary>
+ // The parent of this branching or null if this is the top-block.
+ // </summary>
+ public readonly FlowBranching Parent;
+
+ // <summary>
+ // Start-Location of this flow branching.
+ // </summary>
+ public readonly Location Location;
+
+ // <summary>
+ // A list of UsageVectors. A new vector is added each time control flow may
+ // take a different path.
+ // </summary>
+ public UsageVector[] Siblings;
+
+ // <summary>
+ // If this is an infinite loop.
+ // </summary>
+ public bool Infinite;
+
+ // <summary>
+ // If we may leave the current loop.
+ // </summary>
+ public bool MayLeaveLoop;
+
+ //
+ // Private
+ //
+ VariableMap param_map, local_map;
+ ArrayList finally_vectors;
+
+ static int next_id = 0;
+ int id;
+
+ // <summary>
+ // Performs an `And' operation on the FlowReturns status
+ // (for instance, a block only returns ALWAYS if all its siblings
+ // always return).
+ // </summary>
+ public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
+ {
+ if (b == FlowReturns.UNREACHABLE)
+ return a;
+
+ switch (a) {
+ case FlowReturns.NEVER:
+ if (b == FlowReturns.NEVER)
+ return FlowReturns.NEVER;
+ else
+ return FlowReturns.SOMETIMES;
+
+ case FlowReturns.SOMETIMES:
+ return FlowReturns.SOMETIMES;
+
+ case FlowReturns.ALWAYS:
+ if ((b == FlowReturns.ALWAYS) || (b == FlowReturns.EXCEPTION))
+ return FlowReturns.ALWAYS;
+ else
+ return FlowReturns.SOMETIMES;
+
+ case FlowReturns.EXCEPTION:
+ if (b == FlowReturns.EXCEPTION)
+ return FlowReturns.EXCEPTION;
+ else if (b == FlowReturns.ALWAYS)
+ return FlowReturns.ALWAYS;
+ else
+ return FlowReturns.SOMETIMES;
+ }
+
+ return b;
+ }
+
+ // <summary>
+ // The vector contains a BitArray with information about which local variables
+ // and parameters are already initialized at the current code position.
+ // </summary>
+ public class UsageVector {
+ // <summary>
+ // If this is true, then the usage vector has been modified and must be
+ // merged when we're done with this branching.
+ // </summary>
+ public bool IsDirty;
+
+ // <summary>
+ // The number of parameters in this block.
+ // </summary>
+ public readonly int CountParameters;
+
+ // <summary>
+ // The number of locals in this block.
+ // </summary>
+ public readonly int CountLocals;
+
+ // <summary>
+ // If not null, then we inherit our state from this vector and do a
+ // copy-on-write. If null, then we're the first sibling in a top-level
+ // block and inherit from the empty vector.
+ // </summary>
+ public readonly UsageVector InheritsFrom;
+
+ //
+ // Private.
+ //
+ MyBitVector locals, parameters;
+ FlowReturns real_returns, real_breaks;
+ bool is_finally;
+
+ static int next_id = 0;
+ int id;
+
+ //
+ // Normally, you should not use any of these constructors.
+ //
+ public UsageVector (UsageVector parent, int num_params, int num_locals)
+ {
+ this.InheritsFrom = parent;
+ this.CountParameters = num_params;
+ this.CountLocals = num_locals;
+ this.real_returns = FlowReturns.NEVER;
+ this.real_breaks = FlowReturns.NEVER;
+
+ if (parent != null) {
+ locals = new MyBitVector (parent.locals, CountLocals);
+ if (num_params > 0)
+ parameters = new MyBitVector (parent.parameters, num_params);
+ real_returns = parent.Returns;
+ real_breaks = parent.Breaks;
+ } else {
+ locals = new MyBitVector (null, CountLocals);
+ if (num_params > 0)
+ parameters = new MyBitVector (null, num_params);
+ }
+
+ id = ++next_id;
+ }
+
+ public UsageVector (UsageVector parent)
+ : this (parent, parent.CountParameters, parent.CountLocals)
+ { }
+
+ // <summary>
+ // This does a deep copy of the usage vector.
+ // </summary>
+ public UsageVector Clone ()
+ {
+ UsageVector retval = new UsageVector (null, CountParameters, CountLocals);
+
+ retval.locals = locals.Clone ();
+ if (parameters != null)
+ retval.parameters = parameters.Clone ();
+ retval.real_returns = real_returns;
+ retval.real_breaks = real_breaks;
+
+ return retval;
+ }
+
+ public bool IsAssigned (VariableInfo var)
+ {
+ if (!var.IsParameter && AlwaysBreaks)
+ return true;
+
+ return var.IsAssigned (var.IsParameter ? parameters : locals);
+ }
+
+ public void SetAssigned (VariableInfo var)
+ {
+ if (!var.IsParameter && AlwaysBreaks)
+ return;
+
+ var.SetAssigned (var.IsParameter ? parameters : locals);
+ }
+
+ public bool IsFieldAssigned (VariableInfo var, string name)
+ {
+ if (!var.IsParameter && AlwaysBreaks)
+ return true;
+
+ return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
+ }
+
+ public void SetFieldAssigned (VariableInfo var, string name)
+ {
+ if (!var.IsParameter && AlwaysBreaks)
+ return;
+
+ var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
+ }
+
+ // <summary>
+ // Specifies when the current block returns.
+ // If this is FlowReturns.UNREACHABLE, then control can never reach the
+ // end of the method (so that we don't need to emit a return statement).
+ // The same applies for FlowReturns.EXCEPTION, but in this case the return
+ // value will never be used.
+ // </summary>
+ public FlowReturns Returns {
+ get {
+ return real_returns;
+ }
+
+ set {
+ real_returns = value;
+ }
+ }
+
+ // <summary>
+ // Specifies whether control may return to our containing block
+ // before reaching the end of this block. This happens if there
+ // is a break/continue/goto/return in it.
+ // This can also be used to find out whether the statement immediately
+ // following the current block may be reached or not.
+ // </summary>
+ public FlowReturns Breaks {
+ get {
+ return real_breaks;
+ }
+
+ set {
+ real_breaks = value;
+ }
+ }
+
+ public bool AlwaysBreaks {
+ get {
+ return (Breaks == FlowReturns.ALWAYS) ||
+ (Breaks == FlowReturns.EXCEPTION) ||
+ (Breaks == FlowReturns.UNREACHABLE);
+ }
+ }
+
+ public bool MayBreak {
+ get {
+ return Breaks != FlowReturns.NEVER;
+ }
+ }
+
+ public bool AlwaysReturns {
+ get {
+ return (Returns == FlowReturns.ALWAYS) ||
+ (Returns == FlowReturns.EXCEPTION);
+ }
+ }
+
+ public bool MayReturn {
+ get {
+ return (Returns == FlowReturns.SOMETIMES) ||
+ (Returns == FlowReturns.ALWAYS);
+ }
+ }
+
+ // <summary>
+ // Merge a child branching.
+ // </summary>
+ public FlowReturns MergeChildren (FlowBranching branching, UsageVector[] children)
+ {
+ MyBitVector new_locals = null;
+ MyBitVector new_params = null;
+
+ FlowReturns new_returns = FlowReturns.NEVER;
+ FlowReturns new_breaks = FlowReturns.NEVER;
+ bool new_returns_set = false, new_breaks_set = false;
+
+ Report.Debug (2, "MERGING CHILDREN", branching, branching.Type,
+ this, children.Length);
+
+ foreach (UsageVector child in children) {
+ Report.Debug (2, " MERGING CHILD", child, child.is_finally);
+
+ if (!child.is_finally) {
+ if (child.Breaks != FlowReturns.UNREACHABLE) {
+ // If Returns is already set, perform an
+ // `And' operation on it, otherwise just set just.
+ if (!new_returns_set) {
+ new_returns = child.Returns;
+ new_returns_set = true;
+ } else
+ new_returns = AndFlowReturns (
+ new_returns, child.Returns);
+ }
+
+ // If Breaks is already set, perform an
+ // `And' operation on it, otherwise just set just.
+ if (!new_breaks_set) {
+ new_breaks = child.Breaks;
+ new_breaks_set = true;
+ } else
+ new_breaks = AndFlowReturns (
+ new_breaks, child.Breaks);
+ }
+
+ // Ignore unreachable children.
+ if (child.Returns == FlowReturns.UNREACHABLE)
+ continue;
+
+ // A local variable is initialized after a flow branching if it
+ // has been initialized in all its branches which do neither
+ // always return or always throw an exception.
+ //
+ // If a branch may return, but does not always return, then we
+ // can treat it like a never-returning branch here: control will
+ // only reach the code position after the branching if we did not
+ // return here.
+ //
+ // It's important to distinguish between always and sometimes
+ // returning branches here:
+ //
+ // 1 int a;
+ // 2 if (something) {
+ // 3 return;
+ // 4 a = 5;
+ // 5 }
+ // 6 Console.WriteLine (a);
+ //
+ // The if block in lines 3-4 always returns, so we must not look
+ // at the initialization of `a' in line 4 - thus it'll still be
+ // uninitialized in line 6.
+ //
+ // On the other hand, the following is allowed:
+ //
+ // 1 int a;
+ // 2 if (something)
+ // 3 a = 5;
+ // 4 else
+ // 5 return;
+ // 6 Console.WriteLine (a);
+ //
+ // Here, `a' is initialized in line 3 and we must not look at
+ // line 5 since it always returns.
+ //
+ if (child.is_finally) {
+ if (new_locals == null)
+ new_locals = locals.Clone ();
+ new_locals.Or (child.locals);
+
+ if (parameters != null) {
+ if (new_params == null)
+ new_params = parameters.Clone ();
+ new_params.Or (child.parameters);
+ }
+ } else {
+ if (!child.AlwaysReturns && !child.AlwaysBreaks) {
+ if (new_locals != null)
+ new_locals.And (child.locals);
+ else {
+ new_locals = locals.Clone ();
+ new_locals.Or (child.locals);
+ }
+ } else if (children.Length == 1) {
+ new_locals = locals.Clone ();
+ new_locals.Or (child.locals);
+ }
+
+ // An `out' parameter must be assigned in all branches which do
+ // not always throw an exception.
+ if (parameters != null) {
+ bool and_params = child.Breaks != FlowReturns.EXCEPTION;
+ if (branching.Type == FlowBranchingType.EXCEPTION)
+ and_params &= child.Returns != FlowReturns.NEVER;
+ if (and_params) {
+ if (new_params != null)
+ new_params.And (child.parameters);
+ else {
+ new_params = parameters.Clone ();
+ new_params.Or (child.parameters);
+ }
+ } else if ((children.Length == 1) || (new_params == null)) {
+ new_params = parameters.Clone ();
+ new_params.Or (child.parameters);
+ }
+ }
+ }
+ }
+
+ Returns = new_returns;
+ if ((branching.Type == FlowBranchingType.BLOCK) ||
+ (branching.Type == FlowBranchingType.EXCEPTION) ||
+ (new_breaks == FlowReturns.UNREACHABLE) ||
+ (new_breaks == FlowReturns.EXCEPTION))
+ Breaks = new_breaks;
+ else if (branching.Type == FlowBranchingType.SWITCH_SECTION)
+ Breaks = new_returns;
+ else if (branching.Type == FlowBranchingType.SWITCH){
+ if (new_breaks == FlowReturns.ALWAYS)
+ Breaks = FlowReturns.ALWAYS;
+ }
+
+ //
+ // We've now either reached the point after the branching or we will
+ // never get there since we always return or always throw an exception.
+ //
+ // If we can reach the point after the branching, mark all locals and
+ // parameters as initialized which have been initialized in all branches
+ // we need to look at (see above).
+ //
+
+ if (((new_breaks != FlowReturns.ALWAYS) &&
+ (new_breaks != FlowReturns.EXCEPTION) &&
+ (new_breaks != FlowReturns.UNREACHABLE)) ||
+ (children.Length == 1)) {
+ if (new_locals != null)
+ locals.Or (new_locals);
+
+ if (new_params != null)
+ parameters.Or (new_params);
+ }
+
+ Report.Debug (2, "MERGING CHILDREN DONE", branching.Type,
+ new_params, new_locals, new_returns, new_breaks,
+ branching.Infinite, branching.MayLeaveLoop, this);
+
+ if (branching.Type == FlowBranchingType.SWITCH_SECTION) {
+ if ((new_breaks != FlowReturns.ALWAYS) &&
+ (new_breaks != FlowReturns.EXCEPTION) &&
+ (new_breaks != FlowReturns.UNREACHABLE))
+ Report.Error (163, branching.Location,
+ "Control cannot fall through from one " +
+ "case label to another");
+ }
+
+ if (branching.Infinite && !branching.MayLeaveLoop) {
+ Report.Debug (1, "INFINITE", new_returns, new_breaks,
+ Returns, Breaks, this);
+
+ // We're actually infinite.
+ if (new_returns == FlowReturns.NEVER) {
+ Breaks = FlowReturns.UNREACHABLE;
+ return FlowReturns.UNREACHABLE;
+ }
+
+ // If we're an infinite loop and do not break, the code after
+ // the loop can never be reached. However, if we may return
+ // from the loop, then we do always return (or stay in the loop
+ // forever).
+ if ((new_returns == FlowReturns.SOMETIMES) ||
+ (new_returns == FlowReturns.ALWAYS)) {
+ Returns = FlowReturns.ALWAYS;
+ return FlowReturns.ALWAYS;
+ }
+ }
+
+ if (branching.Type == FlowBranchingType.LOOP_BLOCK) {
+ Report.Debug (2, "MERGING LOOP BLOCK DONE", branching,
+ branching.Infinite, branching.MayLeaveLoop,
+ new_breaks, new_returns);
+
+ // If we may leave the loop, then we do not always return.
+ if (branching.MayLeaveLoop && (new_returns == FlowReturns.ALWAYS)) {
+ Returns = FlowReturns.SOMETIMES;
+ return FlowReturns.SOMETIMES;
+ }
+
+ // A `break' in a loop does not "break" in the outer block.
+ Breaks = FlowReturns.NEVER;
+ }
+
+ return new_returns;
+ }
+
+ // <summary>
+ // Tells control flow analysis that the current code position may be reached with
+ // a forward jump from any of the origins listed in `origin_vectors' which is a
+ // list of UsageVectors.
+ //
+ // This is used when resolving forward gotos - in the following example, the
+ // variable `a' is uninitialized in line 8 becase this line may be reached via
+ // the goto in line 4:
+ //
+ // 1 int a;
+ //
+ // 3 if (something)
+ // 4 goto World;
+ //
+ // 6 a = 5;
+ //
+ // 7 World:
+ // 8 Console.WriteLine (a);
+ //
+ // </summary>
+ public void MergeJumpOrigins (ICollection origin_vectors)
+ {
+ Report.Debug (1, "MERGING JUMP ORIGIN", this);
+
+ real_breaks = FlowReturns.NEVER;
+ real_returns = FlowReturns.NEVER;
+
+ foreach (UsageVector vector in origin_vectors) {
+ Report.Debug (1, " MERGING JUMP ORIGIN", vector);
+
+ locals.And (vector.locals);
+ if (parameters != null)
+ parameters.And (vector.parameters);
+ Breaks = AndFlowReturns (Breaks, vector.Breaks);
+ Returns = AndFlowReturns (Returns, vector.Returns);
+ }
+
+ Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
+ }
+
+ // <summary>
+ // This is used at the beginning of a finally block if there were
+ // any return statements in the try block or one of the catch blocks.
+ // </summary>
+ public void MergeFinallyOrigins (ICollection finally_vectors)
+ {
+ Report.Debug (1, "MERGING FINALLY ORIGIN", this);
+
+ real_breaks = FlowReturns.NEVER;
+
+ foreach (UsageVector vector in finally_vectors) {
+ Report.Debug (1, " MERGING FINALLY ORIGIN", vector);
+
+ if (parameters != null)
+ parameters.And (vector.parameters);
+ Breaks = AndFlowReturns (Breaks, vector.Breaks);
+ }
+
+ is_finally = true;
+
+ Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
+ }
+
+ public void CheckOutParameters (FlowBranching branching)
+ {
+ if (parameters != null)
+ branching.CheckOutParameters (parameters, branching.Location);
+ }
+
+ // <summary>
+ // Performs an `or' operation on the locals and the parameters.
+ // </summary>
+ public void Or (UsageVector new_vector)
+ {
+ locals.Or (new_vector.locals);
+ if (parameters != null)
+ parameters.Or (new_vector.parameters);
+ }
+
+ // <summary>
+ // Performs an `and' operation on the locals.
+ // </summary>
+ public void AndLocals (UsageVector new_vector)
+ {
+ locals.And (new_vector.locals);
+ }
+
+ // <summary>
+ // Returns a deep copy of the parameters.
+ // </summary>
+ public MyBitVector Parameters {
+ get {
+ if (parameters != null)
+ return parameters.Clone ();
+ else
+ return null;
+ }
+ }
+
+ // <summary>
+ // Returns a deep copy of the locals.
+ // </summary>
+ public MyBitVector Locals {
+ get {
+ return locals.Clone ();
+ }
+ }
+
+ //
+ // Debugging stuff.
+ //
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ sb.Append ("Vector (");
+ sb.Append (id);
+ sb.Append (",");
+ sb.Append (Returns);
+ sb.Append (",");
+ sb.Append (Breaks);
+ if (parameters != null) {
+ sb.Append (" - ");
+ sb.Append (parameters);
+ }
+ sb.Append (" - ");
+ sb.Append (locals);
+ sb.Append (")");
+
+ return sb.ToString ();
+ }
+ }
+
+ FlowBranching (FlowBranchingType type, Location loc)
+ {
+ this.Block = null;
+ this.Location = loc;
+ this.Type = type;
+ id = ++next_id;
+ }
+
+ // <summary>
+ // Creates a new flow branching for `block'.
+ // This is used from Block.Resolve to create the top-level branching of
+ // the block.
+ // </summary>
+ public FlowBranching (Block block, Location loc)
+ : this (FlowBranchingType.BLOCK, loc)
+ {
+ Block = block;
+ Parent = null;
+
+ param_map = block.ParameterMap;
+ local_map = block.LocalMap;
+
+ UsageVector vector = new UsageVector (null, param_map.Length, local_map.Length);
+
+ AddSibling (vector);
+ }
+
+ // <summary>
+ // Creates a new flow branching which is contained in `parent'.
+ // You should only pass non-null for the `block' argument if this block
+ // introduces any new variables - in this case, we need to create a new
+ // usage vector with a different size than our parent's one.
+ // </summary>
+ public FlowBranching (FlowBranching parent, FlowBranchingType type,
+ Block block, Location loc)
+ : this (type, loc)
+ {
+ Parent = parent;
+ Block = block;
+
+ UsageVector vector;
+ if (Block != null) {
+ param_map = Block.ParameterMap;
+ local_map = Block.LocalMap;
+
+ vector = new UsageVector (parent.CurrentUsageVector, param_map.Length,
+ local_map.Length);
+ } else {
+ param_map = Parent.param_map;
+ local_map = Parent.local_map;
+ vector = new UsageVector (Parent.CurrentUsageVector);
+ }
+
+ AddSibling (vector);
+
+ switch (Type) {
+ case FlowBranchingType.EXCEPTION:
+ finally_vectors = new ArrayList ();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ void AddSibling (UsageVector uv)
+ {
+ if (Siblings != null) {
+ UsageVector[] ns = new UsageVector [Siblings.Length + 1];
+ for (int i = 0; i < Siblings.Length; ++i)
+ ns [i] = Siblings [i];
+ Siblings = ns;
+ } else {
+ Siblings = new UsageVector [1];
+ }
+ Siblings [Siblings.Length - 1] = uv;
+ }
+
+ // <summary>
+ // Returns the branching's current usage vector.
+ // </summary>
+ public UsageVector CurrentUsageVector
+ {
+ get {
+ return Siblings [Siblings.Length - 1];
+ }
+ }
+
+ // <summary>
+ // Creates a sibling of the current usage vector.
+ // </summary>
+ public void CreateSibling ()
+ {
+ AddSibling (new UsageVector (Parent.CurrentUsageVector));
+
+ Report.Debug (1, "CREATED SIBLING", CurrentUsageVector);
+ }
+
+ // <summary>
+ // Creates a sibling for a `finally' block.
+ // </summary>
+ public void CreateSiblingForFinally ()
+ {
+ if (Type != FlowBranchingType.EXCEPTION)
+ throw new NotSupportedException ();
+
+ CreateSibling ();
+
+ CurrentUsageVector.MergeFinallyOrigins (finally_vectors);
+ }
+
+ // <summary>
+ // Check whether all `out' parameters have been assigned.
+ // </summary>
+ public void CheckOutParameters (MyBitVector parameters, Location loc)
+ {
+ if (InTryBlock ())
+ return;
+
+ for (int i = 0; i < param_map.Count; i++) {
+ VariableInfo var = param_map [i];
+
+ if (var == null)
+ continue;
+
+ if (var.IsAssigned (parameters))
+ continue;
+
+ Report.Error (177, loc, "The out parameter `" +
+ param_map.VariableNames [i] + "' must be " +
+ "assigned before control leave the current method.");
+ }
+ }
+
+ // <summary>
+ // Merge a child branching.
+ // </summary>
+ public FlowReturns MergeChild (FlowBranching child)
+ {
+ FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings);
+
+ if ((child.Type != FlowBranchingType.LOOP_BLOCK) &&
+ (child.Type != FlowBranchingType.SWITCH_SECTION))
+ MayLeaveLoop |= child.MayLeaveLoop;
+
+ return returns;
+ }
+
+ // <summary>
+ // Does the toplevel merging.
+ // </summary>
+ public FlowReturns MergeTopBlock ()
+ {
+ if ((Type != FlowBranchingType.BLOCK) || (Block == null))
+ throw new NotSupportedException ();
+
+ UsageVector vector = new UsageVector (null, param_map.Length, local_map.Length);
+
+ Report.Debug (1, "MERGING TOP BLOCK", Location, vector);
+
+ vector.MergeChildren (this, Siblings);
+
+ if (Siblings.Length == 1)
+ Siblings [0] = vector;
+ else {
+ Siblings = null;
+ AddSibling (vector);
+ }
+
+ Report.Debug (1, "MERGING TOP BLOCK DONE", Location, vector);
+
+ if (vector.Breaks != FlowReturns.EXCEPTION) {
+ if (!vector.AlwaysBreaks)
+ CheckOutParameters (CurrentUsageVector.Parameters, Location);
+ return vector.AlwaysBreaks ? FlowReturns.ALWAYS : vector.Returns;
+ } else
+ return FlowReturns.EXCEPTION;
+ }
+
+ public bool InTryBlock ()
+ {
+ if (finally_vectors != null)
+ return true;
+ else if (Parent != null)
+ return Parent.InTryBlock ();
+ else
+ return false;
+ }
+
+ public void AddFinallyVector (UsageVector vector)
+ {
+ if (finally_vectors != null) {
+ finally_vectors.Add (vector.Clone ());
+ return;
+ }
+
+ if (Parent != null)
+ Parent.AddFinallyVector (vector);
+ else
+ throw new NotSupportedException ();
+ }
+
+ public bool IsAssigned (VariableInfo vi)
+ {
+ return CurrentUsageVector.IsAssigned (vi);
+ }
+
+ public bool IsFieldAssigned (VariableInfo vi, string field_name)
+ {
+ if (CurrentUsageVector.IsAssigned (vi))
+ return true;
+
+ return CurrentUsageVector.IsFieldAssigned (vi, field_name);
+ }
+
+ public void SetAssigned (VariableInfo vi)
+ {
+ CurrentUsageVector.SetAssigned (vi);
+ }
+
+ public void SetFieldAssigned (VariableInfo vi, string name)
+ {
+ CurrentUsageVector.SetFieldAssigned (vi, name);
+ }
+
+ public bool IsReachable ()
+ {
+ bool reachable;
+
+ switch (Type) {
+ case FlowBranchingType.SWITCH_SECTION:
+ // The code following a switch block is reachable unless the switch
+ // block always returns.
+ reachable = !CurrentUsageVector.AlwaysReturns;
+ break;
+
+ case FlowBranchingType.LOOP_BLOCK:
+ // The code following a loop is reachable unless the loop always
+ // returns or it's an infinite loop without any `break's in it.
+ reachable = !CurrentUsageVector.AlwaysReturns &&
+ (CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE);
+ break;
+
+ default:
+ // The code following a block or exception is reachable unless the
+ // block either always returns or always breaks.
+ if (MayLeaveLoop)
+ reachable = true;
+ else
+ reachable = !CurrentUsageVector.AlwaysBreaks &&
+ !CurrentUsageVector.AlwaysReturns;
+ break;
+ }
+
+ Report.Debug (1, "REACHABLE", this, Type, CurrentUsageVector.Returns,
+ CurrentUsageVector.Breaks, CurrentUsageVector, MayLeaveLoop,
+ reachable);
+
+ return reachable;
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder ("FlowBranching (");
+
+ sb.Append (id);
+ sb.Append (",");
+ sb.Append (Type);
+ if (Block != null) {
+ sb.Append (" - ");
+ sb.Append (Block.ID);
+ sb.Append (" - ");
+ sb.Append (Block.StartLocation);
+ }
+ sb.Append (" - ");
+ sb.Append (Siblings.Length);
+ sb.Append (" - ");
+ sb.Append (CurrentUsageVector);
+ sb.Append (")");
+ return sb.ToString ();
+ }
+ }
+
+ // <summary>
+ // This is used by the flow analysis code to keep track of the type of local variables
+ // and variables.
+ //
+ // The flow code uses a BitVector to keep track of whether a variable has been assigned
+ // or not. This is easy for fundamental types (int, char etc.) or reference types since
+ // you can only assign the whole variable as such.
+ //
+ // For structs, we also need to keep track of all its fields. To do this, we allocate one
+ // bit for the struct itself (it's used if you assign/access the whole struct) followed by
+ // one bit for each of its fields.
+ //
+ // This class computes this `layout' for each type.
+ // </summary>
+ public class TypeInfo
+ {
+ public readonly Type Type;
+
+ // <summary>
+ // Total number of bits a variable of this type consumes in the flow vector.
+ // </summary>
+ public readonly int TotalLength;
+
+ // <summary>
+ // Number of bits the simple fields of a variable of this type consume
+ // in the flow vector.
+ // </summary>
+ public readonly int Length;
+
+ // <summary>
+ // This is only used by sub-structs.
+ // </summary>
+ public readonly int Offset;
+
+ // <summary>
+ // If this is a struct.
+ // </summary>
+ public readonly bool IsStruct;
+
+ // <summary>
+ // If this is a struct, all fields which are structs theirselves.
+ // </summary>
+ public TypeInfo[] SubStructInfo;
+
+ protected readonly StructInfo struct_info;
+ private static Hashtable type_hash = new Hashtable ();
+
+ public static TypeInfo GetTypeInfo (Type type)
+ {
+ TypeInfo info = (TypeInfo) type_hash [type];
+ if (info != null)
+ return info;
+
+ info = new TypeInfo (type);
+ type_hash.Add (type, info);
+ return info;
+ }
+
+ public static TypeInfo GetTypeInfo (TypeContainer tc)
+ {
+ TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
+ if (info != null)
+ return info;
+
+ info = new TypeInfo (tc);
+ type_hash.Add (tc.TypeBuilder, info);
+ return info;
+ }
+
+ private TypeInfo (Type type)
+ {
+ this.Type = type;
+
+ struct_info = StructInfo.GetStructInfo (type);
+ if (struct_info != null) {
+ Length = struct_info.Length;
+ TotalLength = struct_info.TotalLength;
+ SubStructInfo = struct_info.StructFields;
+ IsStruct = true;
+ } else {
+ Length = 0;
+ TotalLength = 1;
+ IsStruct = false;
+ }
+ }
+
+ private TypeInfo (TypeContainer tc)
+ {
+ this.Type = tc.TypeBuilder;
+
+ struct_info = StructInfo.GetStructInfo (tc);
+ if (struct_info != null) {
+ Length = struct_info.Length;
+ TotalLength = struct_info.TotalLength;
+ SubStructInfo = struct_info.StructFields;
+ IsStruct = true;
+ } else {
+ Length = 0;
+ TotalLength = 1;
+ IsStruct = false;
+ }
+ }
+
+ protected TypeInfo (StructInfo struct_info, int offset)
+ {
+ this.struct_info = struct_info;
+ this.Offset = offset;
+ this.Length = struct_info.Length;
+ this.TotalLength = struct_info.TotalLength;
+ this.SubStructInfo = struct_info.StructFields;
+ this.Type = struct_info.Type;
+ this.IsStruct = true;
+ }
+
+ public int GetFieldIndex (string name)
+ {
+ if (struct_info == null)
+ return 0;
+
+ return struct_info [name];
+ }
+
+ public TypeInfo GetSubStruct (string name)
+ {
+ if (struct_info == null)
+ return null;
+
+ return struct_info.GetStructField (name);
+ }
+
+ // <summary>
+ // A struct's constructor must always assign all fields.
+ // This method checks whether it actually does so.
+ // </summary>
+ public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
+ {
+ if (struct_info == null)
+ return true;
+
+ bool ok = true;
+ for (int i = 0; i < struct_info.Count; i++) {
+ FieldInfo field = struct_info.Fields [i];
+
+ if (!branching.IsFieldAssigned (vi, field.Name)) {
+ Report.Error (171, loc,
+ "Field `" + TypeManager.CSharpName (Type) +
+ "." + field.Name + "' must be fully initialized " +
+ "before control leaves the constructor");
+ ok = false;
+ }
+ }
+
+ return ok;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
+ Type, Offset, Length, TotalLength);
+ }
+
+ protected class StructInfo {
+ public readonly Type Type;
+ public readonly FieldInfo[] Fields;
+ public readonly TypeInfo[] StructFields;
+ public readonly int Count;
+ public readonly int CountPublic;
+ public readonly int CountNonPublic;
+ public readonly int Length;
+ public readonly int TotalLength;
+ public readonly bool HasStructFields;
+
+ private static Hashtable field_type_hash = new Hashtable ();
+ private Hashtable struct_field_hash;
+ private Hashtable field_hash;
+
+ protected bool InTransit = false;
+
+ // Private constructor. To save memory usage, we only need to create one instance
+ // of this class per struct type.
+ private StructInfo (Type type)
+ {
+ this.Type = type;
+
+ field_type_hash.Add (type, this);
+
+ if (type is TypeBuilder) {
+ TypeContainer tc = TypeManager.LookupTypeContainer (type);
+
+ ArrayList fields = tc.Fields;
+
+ ArrayList public_fields = new ArrayList ();
+ ArrayList non_public_fields = new ArrayList ();
+
+ if (fields != null) {
+ foreach (Field field in fields) {
+ if ((field.ModFlags & Modifiers.STATIC) != 0)
+ continue;
+ if ((field.ModFlags & Modifiers.PUBLIC) != 0)
+ public_fields.Add (field.FieldBuilder);
+ else
+ non_public_fields.Add (field.FieldBuilder);
+ }
+ }
+
+ CountPublic = public_fields.Count;
+ CountNonPublic = non_public_fields.Count;
+ Count = CountPublic + CountNonPublic;
+
+ Fields = new FieldInfo [Count];
+ public_fields.CopyTo (Fields, 0);
+ non_public_fields.CopyTo (Fields, CountPublic);
+ } else {
+ FieldInfo[] public_fields = type.GetFields (
+ BindingFlags.Instance|BindingFlags.Public);
+ FieldInfo[] non_public_fields = type.GetFields (
+ BindingFlags.Instance|BindingFlags.NonPublic);
+
+ CountPublic = public_fields.Length;
+ CountNonPublic = non_public_fields.Length;
+ Count = CountPublic + CountNonPublic;
+
+ Fields = new FieldInfo [Count];
+ public_fields.CopyTo (Fields, 0);
+ non_public_fields.CopyTo (Fields, CountPublic);
+ }
+
+ struct_field_hash = new Hashtable ();
+ field_hash = new Hashtable ();
+
+ Length = 0;
+ StructFields = new TypeInfo [Count];
+ StructInfo[] sinfo = new StructInfo [Count];
+
+ InTransit = true;
+
+ for (int i = 0; i < Count; i++) {
+ FieldInfo field = (FieldInfo) Fields [i];
+
+ sinfo [i] = GetStructInfo (field.FieldType);
+ if (sinfo [i] == null)
+ field_hash.Add (field.Name, ++Length);
+ else if (sinfo [i].InTransit) {
+ Report.Error (523, String.Format (
+ "Struct member '{0}.{1}' of type '{2}' causes " +
+ "a cycle in the structure layout",
+ type, field.Name, sinfo [i].Type));
+ sinfo [i] = null;
+ return;
+ }
+ }
+
+ InTransit = false;
+
+ TotalLength = Length + 1;
+ for (int i = 0; i < Count; i++) {
+ FieldInfo field = (FieldInfo) Fields [i];
+
+ if (sinfo [i] == null)
+ continue;
+
+ field_hash.Add (field.Name, TotalLength);
+
+ HasStructFields = true;
+ StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
+ struct_field_hash.Add (field.Name, StructFields [i]);
+ TotalLength += sinfo [i].TotalLength;
+ }
+ }
+
+ public int this [string name] {
+ get {
+ if (field_hash.Contains (name))
+ return (int) field_hash [name];
+ else
+ return 0;
+ }
+ }
+
+ public TypeInfo GetStructField (string name)
+ {
+ return (TypeInfo) struct_field_hash [name];
+ }
+
+ public static StructInfo GetStructInfo (Type type)
+ {
+ if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
+ TypeManager.IsBuiltinType (type))
+ return null;
+
+ StructInfo info = (StructInfo) field_type_hash [type];
+ if (info != null)
+ return info;
+
+ return new StructInfo (type);
+ }
+
+ public static StructInfo GetStructInfo (TypeContainer tc)
+ {
+ StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
+ if (info != null)
+ return info;
+
+ return new StructInfo (tc.TypeBuilder);
+ }
+ }
+ }
+
+ // <summary>
+ // This is used by the flow analysis code to store information about a single local variable
+ // or parameter. Depending on the variable's type, we need to allocate one or more elements
+ // in the BitVector - if it's a fundamental or reference type, we just need to know whether
+ // it has been assigned or not, but for structs, we need this information for each of its fields.
+ // </summary>
+ public class VariableInfo {
+ public readonly string Name;
+ public readonly TypeInfo TypeInfo;
+
+ // <summary>
+ // The bit offset of this variable in the flow vector.
+ // </summary>
+ public readonly int Offset;
+
+ // <summary>
+ // The number of bits this variable needs in the flow vector.
+ // The first bit always specifies whether the variable as such has been assigned while
+ // the remaining bits contain this information for each of a struct's fields.
+ // </summary>
+ public readonly int Length;
+
+ // <summary>
+ // If this is a parameter of local variable.
+ // </summary>
+ public readonly bool IsParameter;
+
+ public readonly LocalInfo LocalInfo;
+ public readonly int ParameterIndex;
+
+ readonly VariableInfo Parent;
+ VariableInfo[] sub_info;
+
+ protected VariableInfo (string name, Type type, int offset)
+ {
+ this.Name = name;
+ this.Offset = offset;
+ this.TypeInfo = TypeInfo.GetTypeInfo (type);
+
+ Length = TypeInfo.TotalLength;
+
+ Initialize ();
+ }
+
+ protected VariableInfo (VariableInfo parent, TypeInfo type)
+ {
+ this.Name = parent.Name;
+ this.TypeInfo = type;
+ this.Offset = parent.Offset + type.Offset;
+ this.Parent = parent;
+ this.Length = type.TotalLength;
+
+ this.IsParameter = parent.IsParameter;
+ this.LocalInfo = parent.LocalInfo;
+ this.ParameterIndex = parent.ParameterIndex;
+
+ Initialize ();
+ }
+
+ protected void Initialize ()
+ {
+ TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
+ if (sub_fields != null) {
+ sub_info = new VariableInfo [sub_fields.Length];
+ for (int i = 0; i < sub_fields.Length; i++) {
+ if (sub_fields [i] != null)
+ sub_info [i] = new VariableInfo (this, sub_fields [i]);
+ }
+ } else
+ sub_info = new VariableInfo [0];
+ }
+
+ public VariableInfo (LocalInfo local_info, int offset)
+ : this (local_info.Name, local_info.VariableType, offset)
+ {
+ this.LocalInfo = local_info;
+ this.IsParameter = false;
+ }
+
+ public VariableInfo (string name, Type type, int param_idx, int offset)
+ : this (name, type, offset)
+ {
+ this.ParameterIndex = param_idx;
+ this.IsParameter = true;
+ }
+
+ public bool IsAssigned (EmitContext ec)
+ {
+ return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this);
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (IsAssigned (ec))
+ return true;
+
+ Report.Error (165, loc,
+ "Use of unassigned local variable `" + Name + "'");
+ ec.CurrentBranching.SetAssigned (this);
+ return false;
+ }
+
+ public bool IsAssigned (MyBitVector vector)
+ {
+ if (vector [Offset])
+ return true;
+
+ for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
+ if (vector [parent.Offset])
+ return true;
+
+ // Return unless this is a struct.
+ if (!TypeInfo.IsStruct)
+ return false;
+
+ // Ok, so each field must be assigned.
+ for (int i = 0; i < TypeInfo.Length; i++) {
+ if (!vector [Offset + i + 1])
+ return false;
+ }
+
+ // Ok, now check all fields which are structs.
+ for (int i = 0; i < sub_info.Length; i++) {
+ VariableInfo sinfo = sub_info [i];
+ if (sinfo == null)
+ continue;
+
+ if (!sinfo.IsAssigned (vector))
+ return false;
+ }
+
+ vector [Offset] = true;
+ return true;
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetAssigned (this);
+ }
+
+ public void SetAssigned (MyBitVector vector)
+ {
+ vector [Offset] = true;
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
+ {
+ if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name))
+ return true;
+
+ Report.Error (170, loc,
+ "Use of possibly unassigned field `" + name + "'");
+ ec.CurrentBranching.SetFieldAssigned (this, name);
+ return false;
+ }
+
+ public bool IsFieldAssigned (MyBitVector vector, string field_name)
+ {
+ int field_idx = TypeInfo.GetFieldIndex (field_name);
+
+ if (field_idx == 0)
+ return true;
+
+ return vector [Offset + field_idx];
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string name)
+ {
+ if (ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetFieldAssigned (this, name);
+ }
+
+ public void SetFieldAssigned (MyBitVector vector, string field_name)
+ {
+ int field_idx = TypeInfo.GetFieldIndex (field_name);
+
+ if (field_idx == 0)
+ return;
+
+ vector [Offset + field_idx] = true;
+ }
+
+ public VariableInfo GetSubStruct (string name)
+ {
+ TypeInfo type = TypeInfo.GetSubStruct (name);
+
+ if (type == null)
+ return null;
+
+ return new VariableInfo (this, type);
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
+ Name, TypeInfo, Offset, Length, IsParameter);
+ }
+ }
+
+ // <summary>
+ // This is used by the flow code to hold the `layout' of the flow vector for
+ // all locals and all parameters (ie. we create one instance of this class for the
+ // locals and another one for the params).
+ // </summary>
+ public class VariableMap {
+ // <summary>
+ // The number of variables in the map.
+ // </summary>
+ public readonly int Count;
+
+ // <summary>
+ // Total length of the flow vector for this map.
+ // <summary>
+ public readonly int Length;
+
+ // <summary>
+ // Type and name of all the variables.
+ // Note that this is null for variables for which we do not need to compute
+ // assignment info.
+ // </summary>
+ public readonly Type[] VariableTypes;
+ public readonly string[] VariableNames;
+
+ VariableInfo[] map;
+
+ public VariableMap (InternalParameters ip)
+ {
+ Count = ip != null ? ip.Count : 0;
+ map = new VariableInfo [Count];
+ VariableNames = new string [Count];
+ VariableTypes = new Type [Count];
+ Length = 0;
+
+ for (int i = 0; i < Count; i++) {
+ Parameter.Modifier mod = ip.ParameterModifier (i);
+
+ if ((mod & Parameter.Modifier.OUT) == 0)
+ continue;
+
+ VariableNames [i] = ip.ParameterName (i);
+ VariableTypes [i] = TypeManager.GetElementType (ip.ParameterType (i));
+
+ map [i] = new VariableInfo (VariableNames [i], VariableTypes [i], i, Length);
+ Length += map [i].Length;
+ }
+ }
+
+ public VariableMap (LocalInfo[] locals)
+ : this (null, locals)
+ { }
+
+ public VariableMap (VariableMap parent, LocalInfo[] locals)
+ {
+ int offset = 0, start = 0;
+ if (parent != null) {
+ offset = parent.Length;
+ start = parent.Count;
+ }
+
+ Count = locals.Length + start;
+ map = new VariableInfo [Count];
+ VariableNames = new string [Count];
+ VariableTypes = new Type [Count];
+ Length = offset;
+
+ if (parent != null) {
+ parent.map.CopyTo (map, 0);
+ parent.VariableNames.CopyTo (VariableNames, 0);
+ parent.VariableTypes.CopyTo (VariableTypes, 0);
+ }
+
+ for (int i = start; i < Count; i++) {
+ LocalInfo li = locals [i-start];
+
+ if (li.VariableType == null)
+ continue;
+
+ VariableNames [i] = li.Name;
+ VariableTypes [i] = li.VariableType;
+
+ map [i] = li.VariableInfo = new VariableInfo (li, Length);
+ Length += map [i].Length;
+ }
+ }
+
+ // <summary>
+ // Returns the VariableInfo for variable @index or null if we don't need to
+ // compute assignment info for this variable.
+ // </summary>
+ public VariableInfo this [int index] {
+ get {
+ return map [index];
+ }
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("VariableMap ({0}:{1})", Count, Length);
+ }
+ }
+
+ public class LocalInfo {
+ public Expression Type;
+
+ //
+ // Most of the time a variable will be stored in a LocalBuilder
+ //
+ // But sometimes, it will be stored in a field. The context of the field will
+ // be stored in the EmitContext
+ //
+ //
+ public LocalBuilder LocalBuilder;
+ public FieldBuilder FieldBuilder;
+
+ public Type VariableType;
+ public readonly string Name;
+ public readonly Location Location;
+ public readonly Block Block;
+
+ public VariableInfo VariableInfo;
+
+ public bool Used;
+ public bool Assigned;
+ public bool ReadOnly;
+ public bool IsFixed;
+
+ public LocalInfo (Expression type, string name, Block block, Location l)
+ {
+ Type = type;
+ Name = name;
+ Block = block;
+ LocalBuilder = null;
+ Location = l;
+ }
+
+ public LocalInfo (TypeContainer tc, Block block, Location l)
+ {
+ VariableType = tc.TypeBuilder;
+ Block = block;
+ LocalBuilder = null;
+ Location = l;
+ }
+
+ public bool IsThisAssigned (EmitContext ec, Location loc)
+ {
+ VariableInfo vi = Block.GetVariableInfo (this);
+ if (vi == null)
+ throw new Exception ();
+
+ if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (vi))
+ return true;
+
+ return vi.TypeInfo.IsFullyInitialized (ec.CurrentBranching, vi, loc);
+ }
+
+ public bool Resolve (DeclSpace decl)
+ {
+ if (VariableType == null)
+ VariableType = decl.ResolveType (Type, false, Location);
+
+ if (VariableType == null)
+ return false;
+
+ return true;
+ }
+
+ public void MakePinned ()
+ {
+ TypeManager.MakePinned (LocalBuilder);
+ IsFixed = true;
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("LocalInfo ({0},{1},{2},{3})",
+ Name, Type, VariableInfo, Location);
+ }
+ }
+
+ /// <summary>
+ /// Block represents a C# block.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// This class is used in a number of places: either to represent
+ /// explicit blocks that the programmer places or implicit blocks.
+ ///
+ /// Implicit blocks are used as labels or to introduce variable
+ /// declarations.
+ /// </remarks>
+ public class Block : Statement {
+ public readonly Block Parent;
+ public readonly Location StartLocation;
+ public Location EndLocation = Location.Null;
+
+ [Flags]
+ public enum Flags : byte {
+ Implicit = 1,
+ Unchecked = 2
+ }
+ Flags flags;
+
+ public bool Implicit {
+ get {
+ return (flags & Flags.Implicit) != 0;
+ }
+ }
+
+ public bool Unchecked {
+ get {
+ return (flags & Flags.Unchecked) != 0;
+ }
+ set {
+ flags |= Flags.Unchecked;
+ }
+ }
+
+ //
+ // The statements in this block
+ //
+ ArrayList statements;
+
+ //
+ // An array of Blocks. We keep track of children just
+ // to generate the local variable declarations.
+ //
+ // Statements and child statements are handled through the
+ // statements.
+ //
+ ArrayList children;
+
+ //
+ // Labels. (label, block) pairs.
+ //
+ Hashtable labels;
+
+ //
+ // Keeps track of (name, type) pairs
+ //
+ Hashtable variables;
+
+ //
+ // Keeps track of constants
+ Hashtable constants;
+
+ //
+ // If this is a switch section, the enclosing switch block.
+ //
+ Block switch_block;
+
+ bool used = false;
+
+ static int id;
+
+ int this_id;
+
+ public Block (Block parent)
+ : this (parent, (Flags) 0, Location.Null, Location.Null)
+ { }
+
+ public Block (Block parent, Flags flags)
+ : this (parent, flags, Location.Null, Location.Null)
+ { }
+
+ public Block (Block parent, Flags flags, Parameters parameters)
+ : this (parent, flags, parameters, Location.Null, Location.Null)
+ { }
+
+ public Block (Block parent, Location start, Location end)
+ : this (parent, (Flags) 0, start, end)
+ { }
+
+ public Block (Block parent, Parameters parameters, Location start, Location end)
+ : this (parent, (Flags) 0, parameters, start, end)
+ { }
+
+ public Block (Block parent, Flags flags, Location start, Location end)
+ : this (parent, flags, Parameters.EmptyReadOnlyParameters, start, end)
+ { }
+
+ public Block (Block parent, Flags flags, Parameters parameters,
+ Location start, Location end)
+ {
+ if (parent != null)
+ parent.AddChild (this);
+
+ this.Parent = parent;
+ this.flags = flags;
+ this.parameters = parameters;
+ this.StartLocation = start;
+ this.EndLocation = end;
+ this.loc = start;
+ this_id = id++;
+ statements = new ArrayList ();
+ }
+
+ public Block CreateSwitchBlock (Location start)
+ {
+ Block new_block = new Block (this, start, start);
+ new_block.switch_block = this;
+ return new_block;
+ }
+
+ public int ID {
+ get {
+ return this_id;
+ }
+ }
+
+ void AddChild (Block b)
+ {
+ if (children == null)
+ children = new ArrayList ();
+
+ children.Add (b);
+ }
+
+ public void SetEndLocation (Location loc)
+ {
+ EndLocation = loc;
+ }
+
+ /// <summary>
+ /// Adds a label to the current block.
+ /// </summary>
+ ///
+ /// <returns>
+ /// false if the name already exists in this block. true
+ /// otherwise.
+ /// </returns>
+ ///
+ public bool AddLabel (string name, LabeledStatement target)
+ {
+ if (switch_block != null)
+ return switch_block.AddLabel (name, target);
+
+ if (labels == null)
+ labels = new Hashtable ();
+ if (labels.Contains (name))
+ return false;
+
+ labels.Add (name, target);
+ return true;
+ }
+
+ public LabeledStatement LookupLabel (string name)
+ {
+ if (switch_block != null)
+ return switch_block.LookupLabel (name);
+
+ if (labels != null){
+ if (labels.Contains (name))
+ return ((LabeledStatement) labels [name]);
+ }
+
+ if (Parent != null)
+ return Parent.LookupLabel (name);
+
+ return null;
+ }
+
+ LocalInfo this_variable = null;
+
+ // <summary>
+ // Returns the "this" instance variable of this block.
+ // See AddThisVariable() for more information.
+ // </summary>
+ public LocalInfo ThisVariable {
+ get {
+ if (this_variable != null)
+ return this_variable;
+ else if (Parent != null)
+ return Parent.ThisVariable;
+ else
+ return null;
+ }
+ }
+
+ Hashtable child_variable_names;
+
+ // <summary>
+ // Marks a variable with name @name as being used in a child block.
+ // If a variable name has been used in a child block, it's illegal to
+ // declare a variable with the same name in the current block.
+ // </summary>
+ public void AddChildVariableName (string name)
+ {
+ if (child_variable_names == null)
+ child_variable_names = new Hashtable ();
+
+ if (!child_variable_names.Contains (name))
+ child_variable_names.Add (name, true);
+ }
+
+ // <summary>
+ // Marks all variables from block @block and all its children as being
+ // used in a child block.
+ // </summary>
+ public void AddChildVariableNames (Block block)
+ {
+ if (block.Variables != null) {
+ foreach (string name in block.Variables.Keys)
+ AddChildVariableName (name);
+ }
+
+ if (block.children != null) {
+ foreach (Block child in block.children)
+ AddChildVariableNames (child);
+ }
+
+ if (block.child_variable_names != null) {
+ foreach (string name in block.child_variable_names.Keys)
+ AddChildVariableName (name);
+ }
+ }
+
+ // <summary>
+ // Checks whether a variable name has already been used in a child block.
+ // </summary>
+ public bool IsVariableNameUsedInChildBlock (string name)
+ {
+ if (child_variable_names == null)
+ return false;
+
+ return child_variable_names.Contains (name);
+ }
+
+ // <summary>
+ // This is used by non-static `struct' constructors which do not have an
+ // initializer - in this case, the constructor must initialize all of the
+ // struct's fields. To do this, we add a "this" variable and use the flow
+ // analysis code to ensure that it's been fully initialized before control
+ // leaves the constructor.
+ // </summary>
+ public LocalInfo AddThisVariable (TypeContainer tc, Location l)
+ {
+ if (this_variable != null)
+ return this_variable;
+
+ if (variables == null)
+ variables = new Hashtable ();
+
+ this_variable = new LocalInfo (tc, this, l);
+
+ variables.Add ("this", this_variable);
+
+ return this_variable;
+ }
+
+ public LocalInfo AddVariable (Expression type, string name, Parameters pars, Location l)
+ {
+ if (variables == null)
+ variables = new Hashtable ();
+
+ LocalInfo vi = GetLocalInfo (name);
+ if (vi != null) {
+ if (vi.Block != this)
+ Report.Error (136, l, "A local variable named `" + name + "' " +
+ "cannot be declared in this scope since it would " +
+ "give a different meaning to `" + name + "', which " +
+ "is already used in a `parent or current' scope to " +
+ "denote something else");
+ else
+ Report.Error (128, l, "A local variable `" + name + "' is already " +
+ "defined in this scope");
+ return null;
+ }
+
+ if (IsVariableNameUsedInChildBlock (name)) {
+ Report.Error (136, l, "A local variable named `" + name + "' " +
+ "cannot be declared in this scope since it would " +
+ "give a different meaning to `" + name + "', which " +
+ "is already used in a `child' scope to denote something " +
+ "else");
+ return null;
+ }
+
+ if (pars != null) {
+ int idx = 0;
+ Parameter p = pars.GetParameterByName (name, out idx);
+ if (p != null) {
+ Report.Error (136, l, "A local variable named `" + name + "' " +
+ "cannot be declared in this scope since it would " +
+ "give a different meaning to `" + name + "', which " +
+ "is already used in a `parent or current' scope to " +
+ "denote something else");
+ return null;
+ }
+ }
+
+ vi = new LocalInfo (type, name, this, l);
+
+ variables.Add (name, vi);
+
+ if (variables_initialized)
+ throw new Exception ();
+
+ // Console.WriteLine ("Adding {0} to {1}", name, ID);
+ return vi;
+ }
+
+ public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
+ {
+ if (AddVariable (type, name, pars, l) == null)
+ return false;
+
+ if (constants == null)
+ constants = new Hashtable ();
+
+ constants.Add (name, value);
+ return true;
+ }
+
+ public Hashtable Variables {
+ get {
+ return variables;
+ }
+ }
+
+ public LocalInfo GetLocalInfo (string name)
+ {
+ if (variables != null) {
+ object temp;
+ temp = variables [name];
+
+ if (temp != null){
+ return (LocalInfo) temp;
+ }
+ }
+
+ if (Parent != null)
+ return Parent.GetLocalInfo (name);
+
+ return null;
+ }
+
+ public VariableInfo GetVariableInfo (LocalInfo li)
+ {
+ return li.VariableInfo;
+ }
+
+ public Expression GetVariableType (string name)
+ {
+ LocalInfo vi = GetLocalInfo (name);
+
+ if (vi != null)
+ return vi.Type;
+
+ return null;
+ }
+
+ public Expression GetConstantExpression (string name)
+ {
+ if (constants != null) {
+ object temp;
+ temp = constants [name];
+
+ if (temp != null)
+ return (Expression) temp;
+ }
+
+ if (Parent != null)
+ return Parent.GetConstantExpression (name);
+
+ return null;
+ }
+
+ /// <summary>
+ /// True if the variable named @name is a constant
+ /// </summary>
+ public bool IsConstant (string name)
+ {
+ Expression e = null;
+
+ e = GetConstantExpression (name);
+
+ return e != null;
+ }
+
+ /// <summary>
+ /// Use to fetch the statement associated with this label
+ /// </summary>
+ public Statement this [string name] {
+ get {
+ return (Statement) labels [name];
+ }
+ }
+
+ Parameters parameters = null;
+ public Parameters Parameters {
+ get {
+ if (Parent != null)
+ return Parent.Parameters;
+
+ return parameters;
+ }
+ }
+
+ /// <returns>
+ /// A list of labels that were not used within this block
+ /// </returns>
+ public string [] GetUnreferenced ()
+ {
+ // FIXME: Implement me
+ return null;
+ }
+
+ public void AddStatement (Statement s)
+ {
+ statements.Add (s);
+ used = true;
+ }
+
+ public bool Used {
+ get {
+ return used;
+ }
+ }
+
+ public void Use ()
+ {
+ used = true;
+ }
+
+ VariableMap param_map, local_map;
+ bool variables_initialized = false;
+
+ public VariableMap ParameterMap {
+ get {
+ if (!variables_initialized)
+ throw new Exception ();
+
+ return param_map;
+ }
+ }
+
+ public VariableMap LocalMap {
+ get {
+ if (!variables_initialized)
+ throw new Exception ();
+
+ return local_map;
+ }
+ }
+
+ /// <summary>
+ /// Emits the variable declarations and labels.
+ /// </summary>
+ /// <remarks>
+ /// tc: is our typecontainer (to resolve type references)
+ /// ig: is the code generator:
+ /// toplevel: the toplevel block. This is used for checking
+ /// that no two labels with the same name are used.
+ /// </remarks>
+ public void EmitMeta (EmitContext ec, InternalParameters ip, Block toplevel)
+ {
+ DeclSpace ds = ec.DeclSpace;
+ ILGenerator ig = ec.ig;
+
+ //
+ // Compute the VariableMap's.
+ //
+ // Unfortunately, we don't know the type when adding variables with
+ // AddVariable(), so we need to compute this info here.
+ //
+
+ LocalInfo[] locals;
+ if (variables != null) {
+ foreach (LocalInfo li in variables.Values)
+ li.Resolve (ec.DeclSpace);
+
+ locals = new LocalInfo [variables.Count];
+ variables.Values.CopyTo (locals, 0);
+ } else
+ locals = new LocalInfo [0];
+
+ if (Parent != null)
+ local_map = new VariableMap (Parent.LocalMap, locals);
+ else
+ local_map = new VariableMap (locals);
+
+ param_map = new VariableMap (ip);
+ variables_initialized = true;
+
+ bool old_check_state = ec.ConstantCheckState;
+ ec.ConstantCheckState = (flags & Flags.Unchecked) == 0;
+ bool remap_locals = ec.RemapToProxy;
+
+ //
+ // Process this block variables
+ //
+ if (variables != null){
+ foreach (DictionaryEntry de in variables){
+ string name = (string) de.Key;
+ LocalInfo vi = (LocalInfo) de.Value;
+
+ if (vi.VariableType == null)
+ continue;
+
+ Type variable_type = vi.VariableType;
+
+ if (variable_type.IsPointer){
+ //
+ // Am not really convinced that this test is required (Microsoft does it)
+ // but the fact is that you would not be able to use the pointer variable
+ // *anyways*
+ //
+ if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type),
+ vi.Location))
+ continue;
+ }
+
+ if (remap_locals)
+ vi.FieldBuilder = ec.MapVariable (name, vi.VariableType);
+ else
+ vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
+
+ if (constants == null)
+ continue;
+
+ Expression cv = (Expression) constants [name];
+ if (cv == null)
+ continue;
+
+ ec.CurrentBlock = this;
+ Expression e = cv.Resolve (ec);
+ if (e == null)
+ continue;
+
+ if (!(e is Constant)){
+ Report.Error (133, vi.Location,
+ "The expression being assigned to `" +
+ name + "' must be constant (" + e + ")");
+ continue;
+ }
+
+ constants.Remove (name);
+ constants.Add (name, e);
+ }
+ }
+ ec.ConstantCheckState = old_check_state;
+
+ //
+ // Now, handle the children
+ //
+ if (children != null){
+ foreach (Block b in children)
+ b.EmitMeta (ec, ip, toplevel);
+ }
+ }
+
+ public void UsageWarning ()
+ {
+ string name;
+
+ if (variables != null){
+ foreach (DictionaryEntry de in variables){
+ LocalInfo vi = (LocalInfo) de.Value;
+
+ if (vi.Used)
+ continue;
+
+ name = (string) de.Key;
+
+ if (vi.Assigned){
+ Report.Warning (
+ 219, vi.Location, "The variable `" + name +
+ "' is assigned but its value is never used");
+ } else {
+ Report.Warning (
+ 168, vi.Location, "The variable `" +
+ name +
+ "' is declared but never used");
+ }
+ }
+ }
+
+ if (children != null)
+ foreach (Block b in children)
+ b.UsageWarning ();
+ }
+
+ bool has_ret = false;
+
+ public override bool Resolve (EmitContext ec)
+ {
+ Block prev_block = ec.CurrentBlock;
+ bool ok = true;
+
+ ec.CurrentBlock = this;
+ ec.StartFlowBranching (this);
+
+ Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+
+ ArrayList new_statements = new ArrayList ();
+ bool unreachable = false, warning_shown = false;
+
+ foreach (Statement s in statements){
+ if (unreachable && !(s is LabeledStatement)) {
+ if (!warning_shown && !(s is EmptyStatement)) {
+ warning_shown = true;
+ Warning_DeadCodeFound (s.loc);
+ }
+
+ continue;
+ }
+
+ if (s.Resolve (ec) == false) {
+ ok = false;
+ continue;
+ }
+
+ if (s is LabeledStatement)
+ unreachable = false;
+ else
+ unreachable = ! ec.CurrentBranching.IsReachable ();
+
+ new_statements.Add (s);
+ }
+
+ statements = new_statements;
+
+ Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+
+ FlowReturns returns = ec.EndFlowBranching ();
+ ec.CurrentBlock = prev_block;
+
+ // If we're a non-static `struct' constructor which doesn't have an
+ // initializer, then we must initialize all of the struct's fields.
+ if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
+ !this_variable.IsThisAssigned (ec, loc))
+ ok = false;
+
+ if ((labels != null) && (RootContext.WarningLevel >= 2)) {
+ foreach (LabeledStatement label in labels.Values)
+ if (!label.HasBeenReferenced)
+ Report.Warning (164, label.Location,
+ "This label has not been referenced");
+ }
+
+ if ((returns == FlowReturns.ALWAYS) ||
+ (returns == FlowReturns.EXCEPTION) ||
+ (returns == FlowReturns.UNREACHABLE))
+ has_ret = true;
+
+ return ok;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ foreach (Statement s in statements)
+ s.Emit (ec);
+
+ return has_ret;
+ }
+
+ public override bool Emit (EmitContext ec)
+ {
+ Block prev_block = ec.CurrentBlock;
+
+ ec.CurrentBlock = this;
+
+ bool emit_debug_info = (CodeGen.SymbolWriter != null);
+ bool is_lexical_block = !Implicit && (Parent != null);
+
+ if (emit_debug_info) {
+ if (is_lexical_block)
+ ec.ig.BeginScope ();
+
+ if (variables != null) {
+ foreach (DictionaryEntry de in variables) {
+ string name = (string) de.Key;
+ LocalInfo vi = (LocalInfo) de.Value;
+
+ if (vi.LocalBuilder == null)
+ continue;
+
+ vi.LocalBuilder.SetLocalSymInfo (name);
+ }
+ }
+ }
+
+ ec.Mark (StartLocation, true);
+ bool retval = DoEmit (ec);
+ ec.Mark (EndLocation, true);
+
+ if (emit_debug_info && is_lexical_block)
+ ec.ig.EndScope ();
+
+ ec.CurrentBlock = prev_block;
+
+ return retval;
+ }
+ }
+
+ public class SwitchLabel {
+ Expression label;
+ object converted;
+ public Location loc;
+ public Label ILLabel;
+ public Label ILLabelCode;
+
+ //
+ // if expr == null, then it is the default case.
+ //
+ public SwitchLabel (Expression expr, Location l)
+ {
+ label = expr;
+ loc = l;
+ }
+
+ public Expression Label {
+ get {
+ return label;
+ }
+ }
+
+ public object Converted {
+ get {
+ return converted;
+ }
+ }
+
+ //
+ // Resolves the expression, reduces it to a literal if possible
+ // and then converts it to the requested type.
+ //
+ public bool ResolveAndReduce (EmitContext ec, Type required_type)
+ {
+ ILLabel = ec.ig.DefineLabel ();
+ ILLabelCode = ec.ig.DefineLabel ();
+
+ if (label == null)
+ return true;
+
+ Expression e = label.Resolve (ec);
+
+ if (e == null)
+ return false;
+
+ if (!(e is Constant)){
+ Report.Error (150, loc, "A constant value is expected, got: " + e);
+ return false;
+ }
+
+ if (e is StringConstant || e is NullLiteral){
+ if (required_type == TypeManager.string_type){
+ converted = e;
+ ILLabel = ec.ig.DefineLabel ();
+ return true;
+ }
+ }
+
+ converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
+ if (converted == null)
+ return false;
+
+ return true;
+ }
+ }
+
+ public class SwitchSection {
+ // An array of SwitchLabels.
+ public readonly ArrayList Labels;
+ public readonly Block Block;
+
+ public SwitchSection (ArrayList labels, Block block)
+ {
+ Labels = labels;
+ Block = block;
+ }
+ }
+
+ public class Switch : Statement {
+ public readonly ArrayList Sections;
+ public Expression Expr;
+
+ /// <summary>
+ /// Maps constants whose type type SwitchType to their SwitchLabels.
+ /// </summary>
+ public Hashtable Elements;
+
+ /// <summary>
+ /// The governing switch type
+ /// </summary>
+ public Type SwitchType;
+
+ //
+ // Computed
+ //
+ bool got_default;
+ Label default_target;
+ Expression new_expr;
+
+ //
+ // The types allowed to be implicitly cast from
+ // on the governing type
+ //
+ static Type [] allowed_types;
+
+ public Switch (Expression e, ArrayList sects, Location l)
+ {
+ Expr = e;
+ Sections = sects;
+ loc = l;
+ }
+
+ public bool GotDefault {
+ get {
+ return got_default;
+ }
+ }
+
+ public Label DefaultTarget {
+ get {
+ return default_target;
+ }
+ }
+
+ //
+ // Determines the governing type for a switch. The returned
+ // expression might be the expression from the switch, or an
+ // expression that includes any potential conversions to the
+ // integral types or to string.
+ //
+ Expression SwitchGoverningType (EmitContext ec, Type t)
+ {
+ if (t == TypeManager.int32_type ||
+ t == TypeManager.uint32_type ||
+ t == TypeManager.char_type ||
+ t == TypeManager.byte_type ||
+ t == TypeManager.sbyte_type ||
+ t == TypeManager.ushort_type ||
+ t == TypeManager.short_type ||
+ t == TypeManager.uint64_type ||
+ t == TypeManager.int64_type ||
+ t == TypeManager.string_type ||
+ t == TypeManager.bool_type ||
+ t.IsSubclassOf (TypeManager.enum_type))
+ return Expr;
+
+ if (allowed_types == null){
+ allowed_types = new Type [] {
+ TypeManager.sbyte_type,
+ TypeManager.byte_type,
+ TypeManager.short_type,
+ TypeManager.ushort_type,
+ TypeManager.int32_type,
+ TypeManager.uint32_type,
+ TypeManager.int64_type,
+ TypeManager.uint64_type,
+ TypeManager.char_type,
+ TypeManager.bool_type,
+ TypeManager.string_type
+ };
+ }
+
+ //
+ // Try to find a *user* defined implicit conversion.
+ //
+ // If there is no implicit conversion, or if there are multiple
+ // conversions, we have to report an error
+ //
+ Expression converted = null;
+ foreach (Type tt in allowed_types){
+ Expression e;
+
+ e = Convert.ImplicitUserConversion (ec, Expr, tt, loc);
+ if (e == null)
+ continue;
+
+ if (converted != null){
+ Report.Error (-12, loc, "More than one conversion to an integral " +
+ " type exists for type `" +
+ TypeManager.CSharpName (Expr.Type)+"'");
+ return null;
+ } else
+ converted = e;
+ }
+ return converted;
+ }
+
+ void error152 (string n)
+ {
+ Report.Error (
+ 152, "The label `" + n + ":' " +
+ "is already present on this switch statement");
+ }
+
+ //
+ // Performs the basic sanity checks on the switch statement
+ // (looks for duplicate keys and non-constant expressions).
+ //
+ // It also returns a hashtable with the keys that we will later
+ // use to compute the switch tables
+ //
+ bool CheckSwitch (EmitContext ec)
+ {
+ Type compare_type;
+ bool error = false;
+ Elements = new Hashtable ();
+
+ got_default = false;
+
+ if (TypeManager.IsEnumType (SwitchType)){
+ compare_type = TypeManager.EnumToUnderlying (SwitchType);
+ } else
+ compare_type = SwitchType;
+
+ foreach (SwitchSection ss in Sections){
+ foreach (SwitchLabel sl in ss.Labels){
+ if (!sl.ResolveAndReduce (ec, SwitchType)){
+ error = true;
+ continue;
+ }
+
+ if (sl.Label == null){
+ if (got_default){
+ error152 ("default");
+ error = true;
+ }
+ got_default = true;
+ continue;
+ }
+
+ object key = sl.Converted;
+
+ if (key is Constant)
+ key = ((Constant) key).GetValue ();
+
+ if (key == null)
+ key = NullLiteral.Null;
+
+ string lname = null;
+ if (compare_type == TypeManager.uint64_type){
+ ulong v = (ulong) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.int64_type){
+ long v = (long) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.uint32_type){
+ uint v = (uint) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.char_type){
+ char v = (char) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.byte_type){
+ byte v = (byte) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.sbyte_type){
+ sbyte v = (sbyte) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.short_type){
+ short v = (short) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.ushort_type){
+ ushort v = (ushort) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.string_type){
+ if (key is NullLiteral){
+ if (Elements.Contains (NullLiteral.Null))
+ lname = "null";
+ else
+ Elements.Add (NullLiteral.Null, null);
+ } else {
+ string s = (string) key;
+
+ if (Elements.Contains (s))
+ lname = s;
+ else
+ Elements.Add (s, sl);
+ }
+ } else if (compare_type == TypeManager.int32_type) {
+ int v = (int) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ } else if (compare_type == TypeManager.bool_type) {
+ bool v = (bool) key;
+
+ if (Elements.Contains (v))
+ lname = v.ToString ();
+ else
+ Elements.Add (v, sl);
+ }
+ else
+ {
+ throw new Exception ("Unknown switch type!" +
+ SwitchType + " " + compare_type);
+ }
+
+ if (lname != null){
+ error152 ("case + " + lname);
+ error = true;
+ }
+ }
+ }
+ if (error)
+ return false;
+
+ return true;
+ }
+
+ void EmitObjectInteger (ILGenerator ig, object k)
+ {
+ if (k is int)
+ IntConstant.EmitInt (ig, (int) k);
+ else if (k is Constant) {
+ EmitObjectInteger (ig, ((Constant) k).GetValue ());
+ }
+ else if (k is uint)
+ IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
+ else if (k is long)
+ {
+ if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
+ {
+ IntConstant.EmitInt (ig, (int) (long) k);
+ ig.Emit (OpCodes.Conv_I8);
+ }
+ else
+ LongConstant.EmitLong (ig, (long) k);
+ }
+ else if (k is ulong)
+ {
+ if ((ulong) k < (1L<<32))
+ {
+ IntConstant.EmitInt (ig, (int) (long) k);
+ ig.Emit (OpCodes.Conv_U8);
+ }
+ else
+ {
+ LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));
+ }
+ }
+ else if (k is char)
+ IntConstant.EmitInt (ig, (int) ((char) k));
+ else if (k is sbyte)
+ IntConstant.EmitInt (ig, (int) ((sbyte) k));
+ else if (k is byte)
+ IntConstant.EmitInt (ig, (int) ((byte) k));
+ else if (k is short)
+ IntConstant.EmitInt (ig, (int) ((short) k));
+ else if (k is ushort)
+ IntConstant.EmitInt (ig, (int) ((ushort) k));
+ else if (k is bool)
+ IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
+ else
+ throw new Exception ("Unhandled case");
+ }
+
+ // structure used to hold blocks of keys while calculating table switch
+ class KeyBlock : IComparable
+ {
+ public KeyBlock (long _nFirst)
+ {
+ nFirst = nLast = _nFirst;
+ }
+ public long nFirst;
+ public long nLast;
+ public ArrayList rgKeys = null;
+ public int Length
+ {
+ get { return (int) (nLast - nFirst + 1); }
+ }
+ public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
+ {
+ return kbLast.nLast - kbFirst.nFirst + 1;
+ }
+ public int CompareTo (object obj)
+ {
+ KeyBlock kb = (KeyBlock) obj;
+ int nLength = Length;
+ int nLengthOther = kb.Length;
+ if (nLengthOther == nLength)
+ return (int) (kb.nFirst - nFirst);
+ return nLength - nLengthOther;
+ }
+ }
+
+ /// <summary>
+ /// This method emits code for a lookup-based switch statement (non-string)
+ /// Basically it groups the cases into blocks that are at least half full,
+ /// and then spits out individual lookup opcodes for each block.
+ /// It emits the longest blocks first, and short blocks are just
+ /// handled with direct compares.
+ /// </summary>
+ /// <param name="ec"></param>
+ /// <param name="val"></param>
+ /// <returns></returns>
+ bool TableSwitchEmit (EmitContext ec, LocalBuilder val)
+ {
+ int cElements = Elements.Count;
+ object [] rgKeys = new object [cElements];
+ Elements.Keys.CopyTo (rgKeys, 0);
+ Array.Sort (rgKeys);
+
+ // initialize the block list with one element per key
+ ArrayList rgKeyBlocks = new ArrayList ();
+ foreach (object key in rgKeys)
+ rgKeyBlocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
+
+ KeyBlock kbCurr;
+ // iteratively merge the blocks while they are at least half full
+ // there's probably a really cool way to do this with a tree...
+ while (rgKeyBlocks.Count > 1)
+ {
+ ArrayList rgKeyBlocksNew = new ArrayList ();
+ kbCurr = (KeyBlock) rgKeyBlocks [0];
+ for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
+ {
+ KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
+ if ((kbCurr.Length + kb.Length) * 2 >= KeyBlock.TotalLength (kbCurr, kb))
+ {
+ // merge blocks
+ kbCurr.nLast = kb.nLast;
+ }
+ else
+ {
+ // start a new block
+ rgKeyBlocksNew.Add (kbCurr);
+ kbCurr = kb;
+ }
+ }
+ rgKeyBlocksNew.Add (kbCurr);
+ if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
+ break;
+ rgKeyBlocks = rgKeyBlocksNew;
+ }
+
+ // initialize the key lists
+ foreach (KeyBlock kb in rgKeyBlocks)
+ kb.rgKeys = new ArrayList ();
+
+ // fill the key lists
+ int iBlockCurr = 0;
+ if (rgKeyBlocks.Count > 0) {
+ kbCurr = (KeyBlock) rgKeyBlocks [0];
+ foreach (object key in rgKeys)
+ {
+ bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast :
+ System.Convert.ToInt64 (key) > kbCurr.nLast;
+ if (fNextBlock)
+ kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];
+ kbCurr.rgKeys.Add (key);
+ }
+ }
+
+ // sort the blocks so we can tackle the largest ones first
+ rgKeyBlocks.Sort ();
+
+ // okay now we can start...
+ ILGenerator ig = ec.ig;
+ Label lblEnd = ig.DefineLabel (); // at the end ;-)
+ Label lblDefault = ig.DefineLabel ();
+
+ Type typeKeys = null;
+ if (rgKeys.Length > 0)
+ typeKeys = rgKeys [0].GetType (); // used for conversions
+
+ for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
+ {
+ KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
+ lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
+ if (kb.Length <= 2)
+ {
+ foreach (object key in kb.rgKeys)
+ {
+ ig.Emit (OpCodes.Ldloc, val);
+ EmitObjectInteger (ig, key);
+ SwitchLabel sl = (SwitchLabel) Elements [key];
+ ig.Emit (OpCodes.Beq, sl.ILLabel);
+ }
+ }
+ else
+ {
+ // TODO: if all the keys in the block are the same and there are
+ // no gaps/defaults then just use a range-check.
+ if (SwitchType == TypeManager.int64_type ||
+ SwitchType == TypeManager.uint64_type)
+ {
+ // TODO: optimize constant/I4 cases
+
+ // check block range (could be > 2^31)
+ ig.Emit (OpCodes.Ldloc, val);
+ EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
+ ig.Emit (OpCodes.Blt, lblDefault);
+ ig.Emit (OpCodes.Ldloc, val);
+ EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
+ ig.Emit (OpCodes.Bgt, lblDefault);
+
+ // normalize range
+ ig.Emit (OpCodes.Ldloc, val);
+ if (kb.nFirst != 0)
+ {
+ EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));
+ ig.Emit (OpCodes.Sub);
+ }
+ ig.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels!
+ }
+ else
+ {
+ // normalize range
+ ig.Emit (OpCodes.Ldloc, val);
+ int nFirst = (int) kb.nFirst;
+ if (nFirst > 0)
+ {
+ IntConstant.EmitInt (ig, nFirst);
+ ig.Emit (OpCodes.Sub);
+ }
+ else if (nFirst < 0)
+ {
+ IntConstant.EmitInt (ig, -nFirst);
+ ig.Emit (OpCodes.Add);
+ }
+ }
+
+ // first, build the list of labels for the switch
+ int iKey = 0;
+ int cJumps = kb.Length;
+ Label [] rgLabels = new Label [cJumps];
+ for (int iJump = 0; iJump < cJumps; iJump++)
+ {
+ object key = kb.rgKeys [iKey];
+ if (System.Convert.ToInt64 (key) == kb.nFirst + iJump)
+ {
+ SwitchLabel sl = (SwitchLabel) Elements [key];
+ rgLabels [iJump] = sl.ILLabel;
+ iKey++;
+ }
+ else
+ rgLabels [iJump] = lblDefault;
+ }
+ // emit the switch opcode
+ ig.Emit (OpCodes.Switch, rgLabels);
+ }
+
+ // mark the default for this block
+ if (iBlock != 0)
+ ig.MarkLabel (lblDefault);
+ }
+
+ // TODO: find the default case and emit it here,
+ // to prevent having to do the following jump.
+ // make sure to mark other labels in the default section
+
+ // the last default just goes to the end
+ ig.Emit (OpCodes.Br, lblDefault);
+
+ // now emit the code for the sections
+ bool fFoundDefault = false;
+ bool fAllReturn = true;
+ foreach (SwitchSection ss in Sections)
+ {
+ foreach (SwitchLabel sl in ss.Labels)
+ {
+ ig.MarkLabel (sl.ILLabel);
+ ig.MarkLabel (sl.ILLabelCode);
+ if (sl.Label == null)
+ {
+ ig.MarkLabel (lblDefault);
+ fFoundDefault = true;
+ }
+ }
+ bool returns = ss.Block.Emit (ec);
+ fAllReturn &= returns;
+ //ig.Emit (OpCodes.Br, lblEnd);
+ }
+
+ if (!fFoundDefault) {
+ ig.MarkLabel (lblDefault);
+ fAllReturn = false;
+ }
+ ig.MarkLabel (lblEnd);
+
+ return fAllReturn;
+ }
+ //
+ // This simple emit switch works, but does not take advantage of the
+ // `switch' opcode.
+ // TODO: remove non-string logic from here
+ // TODO: binary search strings?
+ //
+ bool SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
+ {
+ ILGenerator ig = ec.ig;
+ Label end_of_switch = ig.DefineLabel ();
+ Label next_test = ig.DefineLabel ();
+ Label null_target = ig.DefineLabel ();
+ bool default_found = false;
+ bool first_test = true;
+ bool pending_goto_end = false;
+ bool all_return = true;
+ bool null_found;
+
+ ig.Emit (OpCodes.Ldloc, val);
+
+ if (Elements.Contains (NullLiteral.Null)){
+ ig.Emit (OpCodes.Brfalse, null_target);
+ } else
+ ig.Emit (OpCodes.Brfalse, default_target);
+
+ ig.Emit (OpCodes.Ldloc, val);
+ ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
+ ig.Emit (OpCodes.Stloc, val);
+
+ int section_count = Sections.Count;
+ for (int section = 0; section < section_count; section++){
+ SwitchSection ss = (SwitchSection) Sections [section];
+ Label sec_begin = ig.DefineLabel ();
+
+ if (pending_goto_end)
+ ig.Emit (OpCodes.Br, end_of_switch);
+
+ int label_count = ss.Labels.Count;
+ null_found = false;
+ for (int label = 0; label < label_count; label++){
+ SwitchLabel sl = (SwitchLabel) ss.Labels [label];
+ ig.MarkLabel (sl.ILLabel);
+
+ if (!first_test){
+ ig.MarkLabel (next_test);
+ next_test = ig.DefineLabel ();
+ }
+ //
+ // If we are the default target
+ //
+ if (sl.Label == null){
+ ig.MarkLabel (default_target);
+ default_found = true;
+ } else {
+ object lit = sl.Converted;
+
+ if (lit is NullLiteral){
+ null_found = true;
+ if (label_count == 1)
+ ig.Emit (OpCodes.Br, next_test);
+ continue;
+
+ }
+ StringConstant str = (StringConstant) lit;
+
+ ig.Emit (OpCodes.Ldloc, val);
+ ig.Emit (OpCodes.Ldstr, str.Value);
+ if (label_count == 1)
+ ig.Emit (OpCodes.Bne_Un, next_test);
+ else {
+ if (label+1 == label_count)
+ ig.Emit (OpCodes.Bne_Un, next_test);
+ else
+ ig.Emit (OpCodes.Beq, sec_begin);
+ }
+ }
+ }
+ if (null_found)
+ ig.MarkLabel (null_target);
+ ig.MarkLabel (sec_begin);
+ foreach (SwitchLabel sl in ss.Labels)
+ ig.MarkLabel (sl.ILLabelCode);
+
+ bool returns = ss.Block.Emit (ec);
+ if (returns)
+ pending_goto_end = false;
+ else {
+ all_return = false;
+ pending_goto_end = true;
+ }
+ first_test = false;
+ }
+ if (!default_found){
+ ig.MarkLabel (default_target);
+ all_return = false;
+ }
+ ig.MarkLabel (next_test);
+ ig.MarkLabel (end_of_switch);
+
+ return all_return;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ Expr = Expr.Resolve (ec);
+ if (Expr == null)
+ return false;
+
+ new_expr = SwitchGoverningType (ec, Expr.Type);
+ if (new_expr == null){
+ Report.Error (151, loc, "An integer type or string was expected for switch");
+ return false;
+ }
+
+ // Validate switch.
+ SwitchType = new_expr.Type;
+
+ if (!CheckSwitch (ec))
+ return false;
+
+ Switch old_switch = ec.Switch;
+ ec.Switch = this;
+ ec.Switch.SwitchType = SwitchType;
+
+ ec.StartFlowBranching (FlowBranchingType.SWITCH, loc);
+
+ bool first = true;
+ foreach (SwitchSection ss in Sections){
+ if (!first)
+ ec.CurrentBranching.CreateSibling ();
+ else
+ first = false;
+
+ if (ss.Block.Resolve (ec) != true)
+ return false;
+ }
+
+
+ if (!got_default)
+ ec.CurrentBranching.CreateSibling ();
+
+ ec.EndFlowBranching ();
+ ec.Switch = old_switch;
+
+ return true;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ // Store variable for comparission purposes
+ LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
+ new_expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Stloc, value);
+
+ ILGenerator ig = ec.ig;
+
+ default_target = ig.DefineLabel ();
+
+ //
+ // Setup the codegen context
+ //
+ Label old_end = ec.LoopEnd;
+ Switch old_switch = ec.Switch;
+
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.Switch = this;
+
+ // Emit Code.
+ bool all_return;
+ if (SwitchType == TypeManager.string_type)
+ all_return = SimpleSwitchEmit (ec, value);
+ else
+ all_return = TableSwitchEmit (ec, value);
+
+ // Restore context state.
+ ig.MarkLabel (ec.LoopEnd);
+
+ //
+ // Restore the previous context
+ //
+ ec.LoopEnd = old_end;
+ ec.Switch = old_switch;
+
+ return all_return;
+ }
+ }
+
+ public class Lock : Statement {
+ Expression expr;
+ Statement Statement;
+
+ public Lock (Expression expr, Statement stmt, Location l)
+ {
+ this.expr = expr;
+ Statement = stmt;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+ return Statement.Resolve (ec) && expr != null;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ Type type = expr.Type;
+ bool val;
+
+ if (type.IsValueType){
+ Report.Error (185, loc, "lock statement requires the expression to be " +
+ " a reference type (type is: `" +
+ TypeManager.CSharpName (type) + "'");
+ return false;
+ }
+
+ ILGenerator ig = ec.ig;
+ LocalBuilder temp = ig.DeclareLocal (type);
+
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Dup);
+ ig.Emit (OpCodes.Stloc, temp);
+ ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+
+ // try
+ Label end = ig.BeginExceptionBlock ();
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+ Label finish = ig.DefineLabel ();
+ val = Statement.Emit (ec);
+ ec.InTry = old_in_try;
+ // ig.Emit (OpCodes.Leave, finish);
+
+ ig.MarkLabel (finish);
+
+ // finally
+ ig.BeginFinallyBlock ();
+ ig.Emit (OpCodes.Ldloc, temp);
+ ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
+ ig.EndExceptionBlock ();
+
+ return val;
+ }
+ }
+
+ public class Unchecked : Statement {
+ public readonly Block Block;
+
+ public Unchecked (Block b)
+ {
+ Block = b;
+ b.Unchecked = true;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool previous_state = ec.CheckState;
+ bool previous_state_const = ec.ConstantCheckState;
+
+ ec.CheckState = false;
+ ec.ConstantCheckState = false;
+ bool ret = Block.Resolve (ec);
+ ec.CheckState = previous_state;
+ ec.ConstantCheckState = previous_state_const;
+
+ return ret;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ bool previous_state = ec.CheckState;
+ bool previous_state_const = ec.ConstantCheckState;
+ bool val;
+
+ ec.CheckState = false;
+ ec.ConstantCheckState = false;
+ val = Block.Emit (ec);
+ ec.CheckState = previous_state;
+ ec.ConstantCheckState = previous_state_const;
+
+ return val;
+ }
+ }
+
+ public class Checked : Statement {
+ public readonly Block Block;
+
+ public Checked (Block b)
+ {
+ Block = b;
+ b.Unchecked = false;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool previous_state = ec.CheckState;
+ bool previous_state_const = ec.ConstantCheckState;
+
+ ec.CheckState = true;
+ ec.ConstantCheckState = true;
+ bool ret = Block.Resolve (ec);
+ ec.CheckState = previous_state;
+ ec.ConstantCheckState = previous_state_const;
+
+ return ret;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ bool previous_state = ec.CheckState;
+ bool previous_state_const = ec.ConstantCheckState;
+ bool val;
+
+ ec.CheckState = true;
+ ec.ConstantCheckState = true;
+ val = Block.Emit (ec);
+ ec.CheckState = previous_state;
+ ec.ConstantCheckState = previous_state_const;
+
+ return val;
+ }
+ }
+
+ public class Unsafe : Statement {
+ public readonly Block Block;
+
+ public Unsafe (Block b)
+ {
+ Block = b;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool previous_state = ec.InUnsafe;
+ bool val;
+
+ ec.InUnsafe = true;
+ val = Block.Resolve (ec);
+ ec.InUnsafe = previous_state;
+
+ return val;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ bool previous_state = ec.InUnsafe;
+ bool val;
+
+ ec.InUnsafe = true;
+ val = Block.Emit (ec);
+ ec.InUnsafe = previous_state;
+
+ return val;
+ }
+ }
+
+ //
+ // Fixed statement
+ //
+ public class Fixed : Statement {
+ Expression type;
+ ArrayList declarators;
+ Statement statement;
+ Type expr_type;
+ FixedData[] data;
+
+ struct FixedData {
+ public bool is_object;
+ public LocalInfo vi;
+ public Expression expr;
+ public Expression converted;
+ }
+
+ public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
+ {
+ this.type = type;
+ declarators = decls;
+ statement = stmt;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (!ec.InUnsafe){
+ Expression.UnsafeError (loc);
+ return false;
+ }
+
+ expr_type = ec.DeclSpace.ResolveType (type, false, loc);
+ if (expr_type == null)
+ return false;
+
+ if (ec.RemapToProxy){
+ Report.Error (-210, loc, "Fixed statement not allowed in iterators");
+ return false;
+ }
+
+ data = new FixedData [declarators.Count];
+
+ if (!expr_type.IsPointer){
+ Report.Error (209, loc, "Variables in a fixed statement must be pointers");
+ return false;
+ }
+
+ int i = 0;
+ foreach (Pair p in declarators){
+ LocalInfo vi = (LocalInfo) p.First;
+ Expression e = (Expression) p.Second;
+
+ vi.VariableInfo = null;
+
+ //
+ // The rules for the possible declarators are pretty wise,
+ // but the production on the grammar is more concise.
+ //
+ // So we have to enforce these rules here.
+ //
+ // We do not resolve before doing the case 1 test,
+ // because the grammar is explicit in that the token &
+ // is present, so we need to test for this particular case.
+ //
+
+ //
+ // Case 1: & object.
+ //
+ if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
+ Expression child = ((Unary) e).Expr;
+
+ vi.MakePinned ();
+ if (child is ParameterReference || child is LocalVariableReference){
+ Report.Error (
+ 213, loc,
+ "No need to use fixed statement for parameters or " +
+ "local variable declarations (address is already " +
+ "fixed)");
+ return false;
+ }
+
+ ec.InFixedInitializer = true;
+ e = e.Resolve (ec);
+ ec.InFixedInitializer = false;
+ if (e == null)
+ return false;
+
+ child = ((Unary) e).Expr;
+
+ if (!TypeManager.VerifyUnManaged (child.Type, loc))
+ return false;
+
+ data [i].is_object = true;
+ data [i].expr = e;
+ data [i].converted = null;
+ data [i].vi = vi;
+ i++;
+
+ continue;
+ }
+
+ ec.InFixedInitializer = true;
+ e = e.Resolve (ec);
+ ec.InFixedInitializer = false;
+ if (e == null)
+ return false;
+
+ //
+ // Case 2: Array
+ //
+ if (e.Type.IsArray){
+ Type array_type = TypeManager.GetElementType (e.Type);
+
+ vi.MakePinned ();
+ //
+ // Provided that array_type is unmanaged,
+ //
+ if (!TypeManager.VerifyUnManaged (array_type, loc))
+ return false;
+
+ //
+ // and T* is implicitly convertible to the
+ // pointer type given in the fixed statement.
+ //
+ ArrayPtr array_ptr = new ArrayPtr (e, loc);
+
+ Expression converted = Convert.ImplicitConversionRequired (
+ ec, array_ptr, vi.VariableType, loc);
+ if (converted == null)
+ return false;
+
+ data [i].is_object = false;
+ data [i].expr = e;
+ data [i].converted = converted;
+ data [i].vi = vi;
+ i++;
+
+ continue;
+ }
+
+ //
+ // Case 3: string
+ //
+ if (e.Type == TypeManager.string_type){
+ data [i].is_object = false;
+ data [i].expr = e;
+ data [i].converted = null;
+ data [i].vi = vi;
+ i++;
+ }
+ }
+
+ return statement.Resolve (ec);
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ bool is_ret = false;
+ LocalBuilder [] clear_list = new LocalBuilder [data.Length];
+
+ for (int i = 0; i < data.Length; i++) {
+ LocalInfo vi = data [i].vi;
+
+ //
+ // Case 1: & object.
+ //
+ if (data [i].is_object) {
+ //
+ // Store pointer in pinned location
+ //
+ data [i].expr.Emit (ec);
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ clear_list [i] = vi.LocalBuilder;
+ continue;
+ }
+
+ //
+ // Case 2: Array
+ //
+ if (data [i].expr.Type.IsArray){
+ //
+ // Store pointer in pinned location
+ //
+ data [i].converted.Emit (ec);
+
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ clear_list [i] = vi.LocalBuilder;
+ continue;
+ }
+
+ //
+ // Case 3: string
+ //
+ if (data [i].expr.Type == TypeManager.string_type){
+ LocalBuilder pinned_string = ig.DeclareLocal (TypeManager.string_type);
+ TypeManager.MakePinned (pinned_string);
+ clear_list [i] = pinned_string;
+
+ data [i].expr.Emit (ec);
+ ig.Emit (OpCodes.Stloc, pinned_string);
+
+ Expression sptr = new StringPtr (pinned_string, loc);
+ Expression converted = Convert.ImplicitConversionRequired (
+ ec, sptr, vi.VariableType, loc);
+
+ if (converted == null)
+ continue;
+
+ converted.Emit (ec);
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ }
+ }
+
+ is_ret = statement.Emit (ec);
+
+ if (is_ret)
+ return is_ret;
+ //
+ // Clear the pinned variable
+ //
+ for (int i = 0; i < data.Length; i++) {
+ LocalInfo vi = data [i].vi;
+
+ if (data [i].is_object || data [i].expr.Type.IsArray) {
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Conv_U);
+ ig.Emit (OpCodes.Stloc, clear_list [i]);
+ } else if (data [i].expr.Type == TypeManager.string_type){
+ ig.Emit (OpCodes.Ldnull);
+ ig.Emit (OpCodes.Stloc, clear_list [i]);
+ }
+ }
+
+ return is_ret;
+ }
+ }
+
+ public class Catch {
+ public readonly string Name;
+ public readonly Block Block;
+ public readonly Location Location;
+
+ Expression type_expr;
+ Type type;
+
+ public Catch (Expression type, string name, Block block, Location l)
+ {
+ type_expr = type;
+ Name = name;
+ Block = block;
+ Location = l;
+ }
+
+ public Type CatchType {
+ get {
+ return type;
+ }
+ }
+
+ public bool IsGeneral {
+ get {
+ return type_expr == null;
+ }
+ }
+
+ public bool Resolve (EmitContext ec)
+ {
+ if (type_expr != null) {
+ type = ec.DeclSpace.ResolveType (type_expr, false, Location);
+ if (type == null)
+ return false;
+
+ if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
+ Report.Error (155, Location,
+ "The type caught or thrown must be derived " +
+ "from System.Exception");
+ return false;
+ }
+ } else
+ type = null;
+
+ if (!Block.Resolve (ec))
+ return false;
+
+ return true;
+ }
+ }
+
+ public class Try : Statement {
+ public readonly Block Fini, Block;
+ public readonly ArrayList Specific;
+ public readonly Catch General;
+
+ //
+ // specific, general and fini might all be null.
+ //
+ public Try (Block block, ArrayList specific, Catch general, Block fini, Location l)
+ {
+ if (specific == null && general == null){
+ Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
+ }
+
+ this.Block = block;
+ this.Specific = specific;
+ this.General = general;
+ this.Fini = fini;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = true;
+
+ ec.StartFlowBranching (FlowBranchingType.EXCEPTION, Block.StartLocation);
+
+ Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
+
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+
+ if (!Block.Resolve (ec))
+ ok = false;
+
+ ec.InTry = old_in_try;
+
+ FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
+
+ Report.Debug (1, "START OF CATCH BLOCKS", vector);
+
+ foreach (Catch c in Specific){
+ ec.CurrentBranching.CreateSibling ();
+ Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
+
+ if (c.Name != null) {
+ LocalInfo vi = c.Block.GetLocalInfo (c.Name);
+ if (vi == null)
+ throw new Exception ();
+
+ vi.VariableInfo = null;
+ }
+
+ bool old_in_catch = ec.InCatch;
+ ec.InCatch = true;
+
+ if (!c.Resolve (ec))
+ ok = false;
+
+ ec.InCatch = old_in_catch;
+
+ FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
+
+ if (!current.AlwaysReturns && !current.AlwaysBreaks)
+ vector.AndLocals (current);
+ else
+ vector.Or (current);
+ }
+
+ Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
+
+ if (General != null){
+ ec.CurrentBranching.CreateSibling ();
+ Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
+
+ bool old_in_catch = ec.InCatch;
+ ec.InCatch = true;
+
+ if (!General.Resolve (ec))
+ ok = false;
+
+ ec.InCatch = old_in_catch;
+
+ FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
+
+ if (!current.AlwaysReturns && !current.AlwaysBreaks)
+ vector.AndLocals (current);
+ else
+ vector.Or (current);
+ }
+
+ Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
+
+ if (Fini != null) {
+ if (ok)
+ ec.CurrentBranching.CreateSiblingForFinally ();
+ Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+
+ bool old_in_finally = ec.InFinally;
+ ec.InFinally = true;
+
+ if (!Fini.Resolve (ec))
+ ok = false;
+
+ ec.InFinally = old_in_finally;
+ }
+
+ FlowReturns returns = ec.EndFlowBranching ();
+
+ FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
+
+ Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
+
+ if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) {
+ ec.CurrentBranching.CheckOutParameters (f_vector.Parameters, loc);
+ }
+
+ ec.CurrentBranching.CurrentUsageVector.Or (vector);
+
+ Report.Debug (1, "END OF TRY", ec.CurrentBranching);
+
+ if (returns != FlowReturns.ALWAYS) {
+ // Unfortunately, System.Reflection.Emit automatically emits a leave
+ // to the end of the finally block. This is a problem if `returns'
+ // is true since we may jump to a point after the end of the method.
+ // As a workaround, emit an explicit ret here.
+ ec.NeedExplicitReturn = true;
+ }
+
+ return ok;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label end;
+ Label finish = ig.DefineLabel ();;
+ bool returns;
+
+ ec.TryCatchLevel++;
+ end = ig.BeginExceptionBlock ();
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+ returns = Block.Emit (ec);
+ ec.InTry = old_in_try;
+
+ //
+ // System.Reflection.Emit provides this automatically:
+ // ig.Emit (OpCodes.Leave, finish);
+
+ bool old_in_catch = ec.InCatch;
+ ec.InCatch = true;
+ DeclSpace ds = ec.DeclSpace;
+
+ foreach (Catch c in Specific){
+ LocalInfo vi;
+
+ ig.BeginCatchBlock (c.CatchType);
+
+ if (c.Name != null){
+ vi = c.Block.GetLocalInfo (c.Name);
+ if (vi == null)
+ throw new Exception ("Variable does not exist in this block");
+
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ } else
+ ig.Emit (OpCodes.Pop);
+
+ if (!c.Block.Emit (ec))
+ returns = false;
+ }
+
+ if (General != null){
+ ig.BeginCatchBlock (TypeManager.object_type);
+ ig.Emit (OpCodes.Pop);
+ if (!General.Block.Emit (ec))
+ returns = false;
+ }
+ ec.InCatch = old_in_catch;
+
+ ig.MarkLabel (finish);
+ if (Fini != null){
+ ig.BeginFinallyBlock ();
+ bool old_in_finally = ec.InFinally;
+ ec.InFinally = true;
+ Fini.Emit (ec);
+ ec.InFinally = old_in_finally;
+ }
+
+ ig.EndExceptionBlock ();
+ ec.TryCatchLevel--;
+
+ return returns;
+ }
+ }
+
+ public class Using : Statement {
+ object expression_or_block;
+ Statement Statement;
+ ArrayList var_list;
+ Expression expr;
+ Type expr_type;
+ Expression conv;
+ Expression [] converted_vars;
+ ExpressionStatement [] assign;
+
+ public Using (object expression_or_block, Statement stmt, Location l)
+ {
+ this.expression_or_block = expression_or_block;
+ Statement = stmt;
+ loc = l;
+ }
+
+ //
+ // Resolves for the case of using using a local variable declaration.
+ //
+ bool ResolveLocalVariableDecls (EmitContext ec)
+ {
+ bool need_conv = false;
+ expr_type = ec.DeclSpace.ResolveType (expr, false, loc);
+ int i = 0;
+
+ if (expr_type == null)
+ return false;
+
+ //
+ // The type must be an IDisposable or an implicit conversion
+ // must exist.
+ //
+ converted_vars = new Expression [var_list.Count];
+ assign = new ExpressionStatement [var_list.Count];
+ if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
+ foreach (DictionaryEntry e in var_list){
+ Expression var = (Expression) e.Key;
+
+ var = var.ResolveLValue (ec, new EmptyExpression ());
+ if (var == null)
+ return false;
+
+ converted_vars [i] = Convert.ImplicitConversionRequired (
+ ec, var, TypeManager.idisposable_type, loc);
+
+ if (converted_vars [i] == null)
+ return false;
+ i++;
+ }
+ need_conv = true;
+ }
+
+ i = 0;
+ foreach (DictionaryEntry e in var_list){
+ LocalVariableReference var = (LocalVariableReference) e.Key;
+ Expression new_expr = (Expression) e.Value;
+ Expression a;
+
+ a = new Assign (var, new_expr, loc);
+ a = a.Resolve (ec);
+ if (a == null)
+ return false;
+
+ if (!need_conv)
+ converted_vars [i] = var;
+ assign [i] = (ExpressionStatement) a;
+ i++;
+ }
+
+ return true;
+ }
+
+ bool ResolveExpression (EmitContext ec)
+ {
+ if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
+ conv = Convert.ImplicitConversionRequired (
+ ec, expr, TypeManager.idisposable_type, loc);
+
+ if (conv == null)
+ return false;
+ }
+
+ return true;
+ }
+
+ //
+ // Emits the code for the case of using using a local variable declaration.
+ //
+ bool EmitLocalVariableDecls (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ int i = 0;
+
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+ for (i = 0; i < assign.Length; i++) {
+ assign [i].EmitStatement (ec);
+
+ ig.BeginExceptionBlock ();
+ }
+ Statement.Emit (ec);
+ ec.InTry = old_in_try;
+
+ bool old_in_finally = ec.InFinally;
+ ec.InFinally = true;
+ var_list.Reverse ();
+ foreach (DictionaryEntry e in var_list){
+ LocalVariableReference var = (LocalVariableReference) e.Key;
+ Label skip = ig.DefineLabel ();
+ i--;
+
+ ig.BeginFinallyBlock ();
+
+ var.Emit (ec);
+ ig.Emit (OpCodes.Brfalse, skip);
+ converted_vars [i].Emit (ec);
+ ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ ig.MarkLabel (skip);
+ ig.EndExceptionBlock ();
+ }
+ ec.InFinally = old_in_finally;
+
+ return false;
+ }
+
+ bool EmitExpression (EmitContext ec)
+ {
+ //
+ // Make a copy of the expression and operate on that.
+ //
+ ILGenerator ig = ec.ig;
+ LocalBuilder local_copy = ig.DeclareLocal (expr_type);
+ if (conv != null)
+ conv.Emit (ec);
+ else
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Stloc, local_copy);
+
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+ ig.BeginExceptionBlock ();
+ Statement.Emit (ec);
+ ec.InTry = old_in_try;
+
+ Label skip = ig.DefineLabel ();
+ bool old_in_finally = ec.InFinally;
+ ig.BeginFinallyBlock ();
+ ig.Emit (OpCodes.Ldloc, local_copy);
+ ig.Emit (OpCodes.Brfalse, skip);
+ ig.Emit (OpCodes.Ldloc, local_copy);
+ ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ ig.MarkLabel (skip);
+ ec.InFinally = old_in_finally;
+ ig.EndExceptionBlock ();
+
+ return false;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ if (expression_or_block is DictionaryEntry){
+ expr = (Expression) ((DictionaryEntry) expression_or_block).Key;
+ var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
+
+ if (!ResolveLocalVariableDecls (ec))
+ return false;
+
+ } else if (expression_or_block is Expression){
+ expr = (Expression) expression_or_block;
+
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
+
+ expr_type = expr.Type;
+
+ if (!ResolveExpression (ec))
+ return false;
+ }
+
+ return Statement.Resolve (ec);
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ if (expression_or_block is DictionaryEntry)
+ return EmitLocalVariableDecls (ec);
+ else if (expression_or_block is Expression)
+ return EmitExpression (ec);
+
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Implementation of the foreach C# statement
+ /// </summary>
+ public class Foreach : Statement {
+ Expression type;
+ LocalVariableReference variable;
+ Expression expr;
+ Statement statement;
+ ForeachHelperMethods hm;
+ Expression empty, conv;
+ Type array_type, element_type;
+ Type var_type;
+
+ public Foreach (Expression type, LocalVariableReference var, Expression expr,
+ Statement stmt, Location l)
+ {
+ this.type = type;
+ this.variable = var;
+ this.expr = expr;
+ statement = stmt;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
+
+ var_type = ec.DeclSpace.ResolveType (type, false, loc);
+ if (var_type == null)
+ return false;
+
+ //
+ // We need an instance variable. Not sure this is the best
+ // way of doing this.
+ //
+ // FIXME: When we implement propertyaccess, will those turn
+ // out to return values in ExprClass? I think they should.
+ //
+ if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
+ expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
+ error1579 (expr.Type);
+ return false;
+ }
+
+ if (expr.Type.IsArray) {
+ array_type = expr.Type;
+ element_type = TypeManager.GetElementType (array_type);
+
+ empty = new EmptyExpression (element_type);
+ } else {
+ hm = ProbeCollectionType (ec, expr.Type);
+ if (hm == null){
+ error1579 (expr.Type);
+ return false;
+ }
+
+ array_type = expr.Type;
+ element_type = hm.element_type;
+
+ empty = new EmptyExpression (hm.element_type);
+ }
+
+ ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+ ec.CurrentBranching.CreateSibling ();
+
+ //
+ //
+ // FIXME: maybe we can apply the same trick we do in the
+ // array handling to avoid creating empty and conv in some cases.
+ //
+ // Although it is not as important in this case, as the type
+ // will not likely be object (what the enumerator will return).
+ //
+ conv = Convert.ExplicitConversion (ec, empty, var_type, loc);
+ if (conv == null)
+ return false;
+
+ if (variable.ResolveLValue (ec, empty) == null)
+ return false;
+
+ if (!statement.Resolve (ec))
+ return false;
+
+ FlowReturns returns = ec.EndFlowBranching ();
+
+ return true;
+ }
+
+ //
+ // Retrieves a `public bool MoveNext ()' method from the Type `t'
+ //
+ static MethodInfo FetchMethodMoveNext (Type t)
+ {
+ MemberList move_next_list;
+
+ move_next_list = TypeContainer.FindMembers (
+ t, MemberTypes.Method,
+ BindingFlags.Public | BindingFlags.Instance,
+ Type.FilterName, "MoveNext");
+ if (move_next_list.Count == 0)
+ return null;
+
+ foreach (MemberInfo m in move_next_list){
+ MethodInfo mi = (MethodInfo) m;
+ Type [] args;
+
+ args = TypeManager.GetArgumentTypes (mi);
+ if (args != null && args.Length == 0){
+ if (mi.ReturnType == TypeManager.bool_type)
+ return mi;
+ }
+ }
+ return null;
+ }
+
+ //
+ // Retrieves a `public T get_Current ()' method from the Type `t'
+ //
+ static MethodInfo FetchMethodGetCurrent (Type t)
+ {
+ MemberList move_next_list;
+
+ move_next_list = TypeContainer.FindMembers (
+ t, MemberTypes.Method,
+ BindingFlags.Public | BindingFlags.Instance,
+ Type.FilterName, "get_Current");
+ if (move_next_list.Count == 0)
+ return null;
+
+ foreach (MemberInfo m in move_next_list){
+ MethodInfo mi = (MethodInfo) m;
+ Type [] args;
+
+ args = TypeManager.GetArgumentTypes (mi);
+ if (args != null && args.Length == 0)
+ return mi;
+ }
+ return null;
+ }
+
+ //
+ // This struct records the helper methods used by the Foreach construct
+ //
+ class ForeachHelperMethods {
+ public EmitContext ec;
+ public MethodInfo get_enumerator;
+ public MethodInfo move_next;
+ public MethodInfo get_current;
+ public Type element_type;
+ public Type enumerator_type;
+ public bool is_disposable;
+
+ public ForeachHelperMethods (EmitContext ec)
+ {
+ this.ec = ec;
+ this.element_type = TypeManager.object_type;
+ this.enumerator_type = TypeManager.ienumerator_type;
+ this.is_disposable = true;
+ }
+ }
+
+ static bool GetEnumeratorFilter (MemberInfo m, object criteria)
+ {
+ if (m == null)
+ return false;
+
+ if (!(m is MethodInfo))
+ return false;
+
+ if (m.Name != "GetEnumerator")
+ return false;
+
+ MethodInfo mi = (MethodInfo) m;
+ Type [] args = TypeManager.GetArgumentTypes (mi);
+ if (args != null){
+ if (args.Length != 0)
+ return false;
+ }
+ ForeachHelperMethods hm = (ForeachHelperMethods) criteria;
+ EmitContext ec = hm.ec;
+
+ //
+ // Check whether GetEnumerator is accessible to us
+ //
+ MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ Type declaring = mi.DeclaringType;
+ if (prot == MethodAttributes.Private){
+ if (declaring != ec.ContainerType)
+ return false;
+ } else if (prot == MethodAttributes.FamANDAssem){
+ // If from a different assembly, false
+ if (!(mi is MethodBuilder))
+ return false;
+ //
+ // Are we being invoked from the same class, or from a derived method?
+ //
+ if (ec.ContainerType != declaring){
+ if (!ec.ContainerType.IsSubclassOf (declaring))
+ return false;
+ }
+ } else if (prot == MethodAttributes.FamORAssem){
+ if (!(mi is MethodBuilder ||
+ ec.ContainerType == declaring ||
+ ec.ContainerType.IsSubclassOf (declaring)))
+ return false;
+ } if (prot == MethodAttributes.Family){
+ if (!(ec.ContainerType == declaring ||
+ ec.ContainerType.IsSubclassOf (declaring)))
+ return false;
+ }
+
+ if ((mi.ReturnType == TypeManager.ienumerator_type) && (declaring == TypeManager.string_type))
+ //
+ // Apply the same optimization as MS: skip the GetEnumerator
+ // returning an IEnumerator, and use the one returning a
+ // CharEnumerator instead. This allows us to avoid the
+ // try-finally block and the boxing.
+ //
+ return false;
+
+ //
+ // Ok, we can access it, now make sure that we can do something
+ // with this `GetEnumerator'
+ //
+
+ if (mi.ReturnType == TypeManager.ienumerator_type ||
+ TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType) ||
+ (!RootContext.StdLib && TypeManager.ImplementsInterface (mi.ReturnType, TypeManager.ienumerator_type))) {
+ if (declaring != TypeManager.string_type) {
+ hm.move_next = TypeManager.bool_movenext_void;
+ hm.get_current = TypeManager.object_getcurrent_void;
+ return true;
+ }
+ }
+
+ //
+ // Ok, so they dont return an IEnumerable, we will have to
+ // find if they support the GetEnumerator pattern.
+ //
+ Type return_type = mi.ReturnType;
+
+ hm.move_next = FetchMethodMoveNext (return_type);
+ if (hm.move_next == null)
+ return false;
+ hm.get_current = FetchMethodGetCurrent (return_type);
+ if (hm.get_current == null)
+ return false;
+
+ hm.element_type = hm.get_current.ReturnType;
+ hm.enumerator_type = return_type;
+ hm.is_disposable = !hm.enumerator_type.IsSealed ||
+ TypeManager.ImplementsInterface (
+ hm.enumerator_type, TypeManager.idisposable_type);
+
+ return true;
+ }
+
+ /// <summary>
+ /// This filter is used to find the GetEnumerator method
+ /// on which IEnumerator operates
+ /// </summary>
+ static MemberFilter FilterEnumerator;
+
+ static Foreach ()
+ {
+ FilterEnumerator = new MemberFilter (GetEnumeratorFilter);
+ }
+
+ void error1579 (Type t)
+ {
+ Report.Error (1579, loc,
+ "foreach statement cannot operate on variables of type `" +
+ t.FullName + "' because that class does not provide a " +
+ " GetEnumerator method or it is inaccessible");
+ }
+
+ static bool TryType (Type t, ForeachHelperMethods hm)
+ {
+ MemberList mi;
+
+ mi = TypeContainer.FindMembers (t, MemberTypes.Method,
+ BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Instance,
+ FilterEnumerator, hm);
+
+ if (mi.Count == 0)
+ return false;
+
+ hm.get_enumerator = (MethodInfo) mi [0];
+ return true;
+ }
+
+ //
+ // Looks for a usable GetEnumerator in the Type, and if found returns
+ // the three methods that participate: GetEnumerator, MoveNext and get_Current
+ //
+ ForeachHelperMethods ProbeCollectionType (EmitContext ec, Type t)
+ {
+ ForeachHelperMethods hm = new ForeachHelperMethods (ec);
+
+ if (TryType (t, hm))
+ return hm;
+
+ //
+ // Now try to find the method in the interfaces
+ //
+ while (t != null){
+ Type [] ifaces = t.GetInterfaces ();
+
+ foreach (Type i in ifaces){
+ if (TryType (i, hm))
+ return hm;
+ }
+
+ //
+ // Since TypeBuilder.GetInterfaces only returns the interface
+ // types for this type, we have to keep looping, but once
+ // we hit a non-TypeBuilder (ie, a Type), then we know we are
+ // done, because it returns all the types
+ //
+ if ((t is TypeBuilder))
+ t = t.BaseType;
+ else
+ break;
+ }
+
+ return null;
+ }
+
+ //
+ // FIXME: possible optimization.
+ // We might be able to avoid creating `empty' if the type is the sam
+ //
+ bool EmitCollectionForeach (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ LocalBuilder enumerator, disposable;
+
+ enumerator = ig.DeclareLocal (hm.enumerator_type);
+ if (hm.is_disposable)
+ disposable = ig.DeclareLocal (TypeManager.idisposable_type);
+ else
+ disposable = null;
+
+ //
+ // Instantiate the enumerator
+ //
+ if (expr.Type.IsValueType){
+ if (expr is IMemoryLocation){
+ IMemoryLocation ml = (IMemoryLocation) expr;
+
+ ml.AddressOf (ec, AddressOp.Load);
+ } else
+ throw new Exception ("Expr " + expr + " of type " + expr.Type +
+ " does not implement IMemoryLocation");
+ ig.Emit (OpCodes.Call, hm.get_enumerator);
+ } else {
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
+ }
+ ig.Emit (OpCodes.Stloc, enumerator);
+
+ //
+ // Protect the code in a try/finalize block, so that
+ // if the beast implement IDisposable, we get rid of it
+ //
+ Label l;
+ bool old_in_try = ec.InTry;
+
+ if (hm.is_disposable) {
+ l = ig.BeginExceptionBlock ();
+ ec.InTry = true;
+ }
+
+ Label end_try = ig.DefineLabel ();
+
+ ig.MarkLabel (ec.LoopBegin);
+ ig.Emit (OpCodes.Ldloc, enumerator);
+ ig.Emit (OpCodes.Callvirt, hm.move_next);
+ ig.Emit (OpCodes.Brfalse, end_try);
+ ig.Emit (OpCodes.Ldloc, enumerator);
+ ig.Emit (OpCodes.Callvirt, hm.get_current);
+
+ variable.EmitAssign (ec, conv);
+ statement.Emit (ec);
+ ig.Emit (OpCodes.Br, ec.LoopBegin);
+ ig.MarkLabel (end_try);
+ ec.InTry = old_in_try;
+
+ // The runtime provides this for us.
+ // ig.Emit (OpCodes.Leave, end);
+
+ //
+ // Now the finally block
+ //
+ if (hm.is_disposable) {
+ Label end_finally = ig.DefineLabel ();
+ bool old_in_finally = ec.InFinally;
+ ec.InFinally = true;
+ ig.BeginFinallyBlock ();
+
+ ig.Emit (OpCodes.Ldloc, enumerator);
+ ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
+ ig.Emit (OpCodes.Stloc, disposable);
+ ig.Emit (OpCodes.Ldloc, disposable);
+ ig.Emit (OpCodes.Brfalse, end_finally);
+ ig.Emit (OpCodes.Ldloc, disposable);
+ ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ ig.MarkLabel (end_finally);
+ ec.InFinally = old_in_finally;
+
+ // The runtime generates this anyways.
+ // ig.Emit (OpCodes.Endfinally);
+
+ ig.EndExceptionBlock ();
+ }
+
+ ig.MarkLabel (ec.LoopEnd);
+ return false;
+ }
+
+ //
+ // FIXME: possible optimization.
+ // We might be able to avoid creating `empty' if the type is the sam
+ //
+ bool EmitArrayForeach (EmitContext ec)
+ {
+ int rank = array_type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+
+ LocalBuilder copy = ig.DeclareLocal (array_type);
+
+ //
+ // Make our copy of the array
+ //
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Stloc, copy);
+
+ if (rank == 1){
+ LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type);
+
+ Label loop, test;
+
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Stloc, counter);
+ test = ig.DefineLabel ();
+ ig.Emit (OpCodes.Br, test);
+
+ loop = ig.DefineLabel ();
+ ig.MarkLabel (loop);
+
+ ig.Emit (OpCodes.Ldloc, copy);
+ ig.Emit (OpCodes.Ldloc, counter);
+
+ //
+ // Load the value, we load the value using the underlying type,
+ // then we use the variable.EmitAssign to load using the proper cast.
+ //
+ ArrayAccess.EmitLoadOpcode (ig, element_type);
+ variable.EmitAssign (ec, conv);
+
+ statement.Emit (ec);
+
+ ig.MarkLabel (ec.LoopBegin);
+ ig.Emit (OpCodes.Ldloc, counter);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Add);
+ ig.Emit (OpCodes.Stloc, counter);
+
+ ig.MarkLabel (test);
+ ig.Emit (OpCodes.Ldloc, counter);
+ ig.Emit (OpCodes.Ldloc, copy);
+ ig.Emit (OpCodes.Ldlen);
+ ig.Emit (OpCodes.Conv_I4);
+ ig.Emit (OpCodes.Blt, loop);
+ } else {
+ LocalBuilder [] dim_len = new LocalBuilder [rank];
+ LocalBuilder [] dim_count = new LocalBuilder [rank];
+ Label [] loop = new Label [rank];
+ Label [] test = new Label [rank];
+ int dim;
+
+ for (dim = 0; dim < rank; dim++){
+ dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type);
+ dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type);
+ test [dim] = ig.DefineLabel ();
+ loop [dim] = ig.DefineLabel ();
+ }
+
+ for (dim = 0; dim < rank; dim++){
+ ig.Emit (OpCodes.Ldloc, copy);
+ IntLiteral.EmitInt (ig, dim);
+ ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
+ ig.Emit (OpCodes.Stloc, dim_len [dim]);
+ }
+
+ for (dim = 0; dim < rank; dim++){
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Stloc, dim_count [dim]);
+ ig.Emit (OpCodes.Br, test [dim]);
+ ig.MarkLabel (loop [dim]);
+ }
+
+ ig.Emit (OpCodes.Ldloc, copy);
+ for (dim = 0; dim < rank; dim++)
+ ig.Emit (OpCodes.Ldloc, dim_count [dim]);
+
+ //
+ // FIXME: Maybe we can cache the computation of `get'?
+ //
+ Type [] args = new Type [rank];
+ MethodInfo get;
+
+ for (int i = 0; i < rank; i++)
+ args [i] = TypeManager.int32_type;
+
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ get = mb.GetArrayMethod (
+ array_type, "Get",
+ CallingConventions.HasThis| CallingConventions.Standard,
+ var_type, args);
+ ig.Emit (OpCodes.Call, get);
+ variable.EmitAssign (ec, conv);
+ statement.Emit (ec);
+ ig.MarkLabel (ec.LoopBegin);
+ for (dim = rank - 1; dim >= 0; dim--){
+ ig.Emit (OpCodes.Ldloc, dim_count [dim]);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Add);
+ ig.Emit (OpCodes.Stloc, dim_count [dim]);
+
+ ig.MarkLabel (test [dim]);
+ ig.Emit (OpCodes.Ldloc, dim_count [dim]);
+ ig.Emit (OpCodes.Ldloc, dim_len [dim]);
+ ig.Emit (OpCodes.Blt, loop [dim]);
+ }
+ }
+ ig.MarkLabel (ec.LoopEnd);
+
+ return false;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ bool ret_val;
+
+ ILGenerator ig = ec.ig;
+
+ Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
+ int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+ ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
+
+ if (hm != null)
+ ret_val = EmitCollectionForeach (ec);
+ else
+ ret_val = EmitArrayForeach (ec);
+
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
+ ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
+
+ return ret_val;
+ }
+ }
+}
--- /dev/null
+//
+// System.CodeDOM CodeStatementCollection Class implementation
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+
+namespace Mono.CSharp {
+
+ using System.Collections;
+ using System;
+
+ public class StatementCollection : IList, ICollection, IEnumerable {
+
+ ArrayList statements;
+
+ //
+ // Constructors
+ //
+ public StatementCollection ()
+ {
+ statements = new ArrayList ();
+ }
+
+ //
+ // Properties
+ //
+ public int Count {
+ get {
+ return statements.Count;
+ }
+ }
+
+ //
+ // Methods
+ //
+ public void Add (Statement value)
+ {
+ statements.Add (value);
+ }
+
+ public void AddRange (Statement [] values)
+ {
+ foreach (Statement ca in values)
+ statements.Add (ca);
+
+ }
+
+ public void Clear ()
+ {
+ statements.Clear ();
+ }
+
+ private class Enumerator : IEnumerator {
+ private StatementCollection collection;
+ private int currentIndex = -1;
+
+ internal Enumerator (StatementCollection collection)
+ {
+ this.collection = collection;
+ }
+
+ public object Current {
+ get {
+ if (currentIndex == collection.Count)
+ throw new InvalidOperationException ();
+ return collection [currentIndex];
+ }
+ }
+
+ public bool MoveNext ()
+ {
+ if (currentIndex > collection.Count)
+ throw new InvalidOperationException ();
+ return ++currentIndex < collection.Count;
+ }
+
+ public void Reset ()
+ {
+ currentIndex = -1;
+ }
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return new StatementCollection.Enumerator (this);
+ }
+
+ //
+ // IList method implementations
+ //
+ public int Add (object value)
+ {
+ return statements.Add (value);
+ }
+
+ public bool Contains (Object value)
+ {
+ return statements.Contains (value);
+ }
+
+ public int IndexOf (Object value)
+ {
+ return statements.IndexOf (value);
+ }
+
+ public void Insert (int index, Object value)
+ {
+ statements [index] = value;
+ }
+
+ public object this[int index] {
+ get {
+ return statements [index];
+ }
+
+ set {
+ statements [index] = value;
+ }
+ }
+
+ public void Remove (object value)
+ {
+ statements.Remove (value);
+ }
+
+ public void RemoveAt (int index)
+ {
+ statements.RemoveAt (index);
+ }
+
+ //
+ // ICollection method implementations
+ //
+ public void CopyTo (Array array, int index)
+ {
+ statements.CopyTo (array, index);
+ }
+
+ public object SyncRoot {
+ get {
+ return statements.SyncRoot;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ public bool IsSynchronized {
+ get {
+ return statements.IsSynchronized;
+ }
+ }
+
+ public bool IsFixedSize {
+ get {
+ return false;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// support.cs: Support routines to work around the fact that System.Reflection.Emit
+// can not introspect types that are being constructed
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+//
+
+using System;
+using System.Text;
+using System.Reflection;
+using System.Collections;
+using System.Reflection.Emit;
+using System.Globalization;
+
+namespace Mono.CSharp {
+
+ public interface ParameterData {
+ Type ParameterType (int pos);
+ int Count { get; }
+ string ParameterName (int pos);
+ string ParameterDesc (int pos);
+ Parameter.Modifier ParameterModifier (int pos);
+ }
+
+ public class ReflectionParameters : ParameterData {
+ ParameterInfo [] pi;
+ bool last_arg_is_params = false;
+
+ public ReflectionParameters (ParameterInfo [] pi)
+ {
+ object [] attrs;
+
+ this.pi = pi;
+ int count = pi.Length-1;
+
+ if (count >= 0) {
+ attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true);
+
+ if (attrs == null)
+ return;
+
+ if (attrs.Length == 0)
+ return;
+
+ last_arg_is_params = true;
+ }
+ }
+
+ public Type ParameterType (int pos)
+ {
+ if (last_arg_is_params && pos >= pi.Length - 1)
+ return pi [pi.Length - 1].ParameterType;
+ else {
+ Type t = pi [pos].ParameterType;
+
+ return t;
+ }
+ }
+
+ public string ParameterName (int pos)
+ {
+ if (last_arg_is_params && pos >= pi.Length - 1)
+ return pi [pi.Length - 1].Name;
+ else
+ return pi [pos].Name;
+ }
+
+ public string ParameterDesc (int pos)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ if (pi [pos].IsIn)
+ sb.Append ("in ");
+
+ Type partype = ParameterType (pos);
+ if (partype.IsByRef){
+ partype = TypeManager.GetElementType (partype);
+ if (pi [pos].IsOut)
+ sb.Append ("out ");
+ else
+ sb.Append ("ref ");
+ }
+
+ if (pos >= pi.Length - 1 && last_arg_is_params)
+ sb.Append ("params ");
+
+ sb.Append (TypeManager.CSharpName (partype));
+
+ return sb.ToString ();
+
+ }
+
+ public Parameter.Modifier ParameterModifier (int pos)
+ {
+ int len = pi.Length;
+
+ if (pos >= len - 1)
+ if (last_arg_is_params)
+ return Parameter.Modifier.PARAMS;
+
+ Type t = pi [pos].ParameterType;
+ if (t.IsByRef){
+ if ((pi [pos].Attributes & ParameterAttributes.Out) != 0)
+ return Parameter.Modifier.ISBYREF | Parameter.Modifier.OUT;
+ else
+ return Parameter.Modifier.ISBYREF | Parameter.Modifier.REF;
+ }
+
+ return Parameter.Modifier.NONE;
+ }
+
+ public int Count {
+ get {
+ return pi.Length;
+ }
+ }
+
+ }
+
+ public class InternalParameters : ParameterData {
+ Type [] param_types;
+
+ public readonly Parameters Parameters;
+
+ public InternalParameters (Type [] param_types, Parameters parameters)
+ {
+ this.param_types = param_types;
+ this.Parameters = parameters;
+ }
+
+ public InternalParameters (DeclSpace ds, Parameters parameters)
+ : this (parameters.GetParameterInfo (ds), parameters)
+ {
+ }
+
+ public int Count {
+ get {
+ if (param_types == null)
+ return 0;
+
+ return param_types.Length;
+ }
+ }
+
+ Parameter GetParameter (int pos)
+ {
+ Parameter [] fixed_pars = Parameters.FixedParameters;
+ if (fixed_pars != null){
+ int len = fixed_pars.Length;
+ if (pos < len)
+ return Parameters.FixedParameters [pos];
+ }
+
+ return Parameters.ArrayParameter;
+ }
+
+ public Type ParameterType (int pos)
+ {
+ if (param_types == null)
+ return null;
+
+ return GetParameter (pos).ExternalType ();
+ }
+
+
+ public string ParameterName (int pos)
+ {
+ return GetParameter (pos).Name;
+ }
+
+ public string ParameterDesc (int pos)
+ {
+ string tmp = String.Empty;
+ Parameter p = GetParameter (pos);
+
+ //
+ // We need to and for REF/OUT, because if either is set the
+ // extra flag ISBYREF will be set as well
+ //
+ if ((p.ModFlags & Parameter.Modifier.REF) != 0)
+ tmp = "ref ";
+ else if ((p.ModFlags & Parameter.Modifier.OUT) != 0)
+ tmp = "out ";
+ else if (p.ModFlags == Parameter.Modifier.PARAMS)
+ tmp = "params ";
+
+ Type t = ParameterType (pos);
+
+ return tmp + TypeManager.CSharpName (t);
+ }
+
+ public Parameter.Modifier ParameterModifier (int pos)
+ {
+ Parameter.Modifier mod = GetParameter (pos).ModFlags;
+
+ if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
+ mod |= Parameter.Modifier.ISBYREF;
+
+ return mod;
+ }
+
+ }
+
+ class PtrHashtable : Hashtable {
+ class PtrComparer : IComparer {
+ public int Compare (object x, object y)
+ {
+ if (x == y)
+ return 0;
+ else
+ return 1;
+ }
+ }
+
+ public PtrHashtable ()
+ {
+ comparer = new PtrComparer ();
+ }
+ }
+
+ //
+ // Compares member infos based on their name and
+ // also allows one argument to be a string
+ //
+ class MemberInfoCompare : IComparer {
+
+ public int Compare (object a, object b)
+ {
+ if (a == null || b == null){
+ Console.WriteLine ("Invalid information passed");
+ throw new Exception ();
+ }
+
+ if (a is string)
+ return String.Compare ((string) a, ((MemberInfo)b).Name);
+
+ if (b is string)
+ return String.Compare (((MemberInfo)a).Name, (string) b);
+
+ return String.Compare (((MemberInfo)a).Name, ((MemberInfo)b).Name);
+ }
+ }
+
+ struct Pair {
+ public object First;
+ public object Second;
+
+ public Pair (object f, object s)
+ {
+ First = f;
+ Second = s;
+ }
+ }
+
+}
--- /dev/null
+//
+// symbolwriter.cs: The symbol writer
+//
+// Author:
+// Martin Baulig (martin@ximian.com)
+//
+// (C) 2003 Ximian, Inc.
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics.SymbolStore;
+
+namespace Mono.CSharp {
+ public class SymbolWriter {
+ ISymbolWriter symwriter;
+ MethodInfo define_namespace;
+ MethodInfo open_method;
+
+ protected SymbolWriter (ISymbolWriter symwriter)
+ {
+ this.symwriter = symwriter;
+ }
+
+ bool Initialize ()
+ {
+ Type type = symwriter.GetType ();
+ define_namespace = type.GetMethod ("DefineNamespace", new Type[] {
+ typeof (string), typeof (ISymbolDocumentWriter),
+ typeof (string []), typeof (int) });
+ if (define_namespace == null)
+ return false;
+
+ open_method = type.GetMethod ("OpenMethod", new Type[] {
+ typeof (ISymbolDocumentWriter), typeof (int), typeof (int),
+ typeof (int), typeof (int), typeof (MethodBase), typeof (int) });
+ if (open_method == null)
+ return false;
+
+ Location.DefineSymbolDocuments (this);
+ Namespace.DefineNamespaces (this);
+
+ return true;
+ }
+
+ public ISymbolDocumentWriter DefineDocument (string path)
+ {
+ return symwriter.DefineDocument (
+ path, SymLanguageType.CSharp, SymLanguageVendor.Microsoft,
+ SymDocumentType.Text);
+ }
+
+ public int DefineNamespace (string name, SourceFile file, string[] using_list, int parent)
+ {
+ return (int) define_namespace.Invoke (symwriter, new object[] {
+ name, file.SymbolDocument, using_list, parent });
+ }
+
+ public void OpenMethod (TypeContainer parent, MethodBase method, Location start, Location end)
+ {
+ int ns_id = parent.Namespace.SymbolFileID;
+ open_method.Invoke (symwriter, new object[] {
+ start.SymbolDocument, start.Row, 0, end.Row, 0, method, ns_id });
+ }
+
+ public void CloseMethod ()
+ {
+ symwriter.CloseMethod ();
+ }
+
+ public static SymbolWriter GetSymbolWriter (ModuleBuilder module)
+ {
+ ISymbolWriter symwriter = module.GetSymWriter ();
+
+ if (symwriter == null)
+ return null;
+
+ SymbolWriter writer = new SymbolWriter (symwriter);
+ if (!writer.Initialize ())
+ return null;
+
+ return writer;
+ }
+ }
+}
--- /dev/null
+//
+// tree.cs: keeps a tree representation of the generated code
+//
+// Author: Miguel de Icaza (miguel@gnu.org)
+//
+// 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.IO;
+
+namespace Mono.CSharp
+{
+
+ public interface ITreeDump {
+ int Dump (Tree tree, StreamWriter output);
+ void ParseOptions (string options);
+ }
+
+ // <summary>
+ //
+ // We store here all the toplevel types that we have parsed,
+ // this is the root of all information we have parsed.
+ //
+ // </summary>
+
+ public class Tree {
+ TypeContainer root_types;
+
+ // <summary>
+ // Keeps track of namespaces defined in the source code
+ // </summary>
+ Hashtable namespaces;
+
+ // <summary>
+ // Keeps track of all the types definied (classes, structs, ifaces, enums)
+ // </summary>
+ Hashtable decls;
+
+ public Tree ()
+ {
+ root_types = new TypeContainer (null, "", new Location (-1));
+
+ decls = new Hashtable ();
+ namespaces = new Hashtable ();
+ }
+
+ public void RecordDecl (string name, DeclSpace ds)
+ {
+ if (decls.Contains (name)){
+ Report.Error (
+ 101, ds.Location,
+ "There is already a definition for `" + name + "'");
+ DeclSpace other = (DeclSpace) decls [name];
+ Report.Error (0,
+ other.Location, "(Location of symbol related to previous error)");
+ return;
+ }
+ decls.Add (name, ds);
+ }
+
+ public NamespaceEntry RecordNamespace (NamespaceEntry parent, SourceFile file, string name)
+ {
+ NamespaceEntry ns = new NamespaceEntry (parent, file, name);
+
+ if (namespaces.Contains (file)){
+ Hashtable ns_ns = (Hashtable) namespaces [file];
+
+ if (ns_ns.Contains (ns.Name))
+ return (NamespaceEntry) ns_ns [ns.Name];
+ ns_ns.Add (ns.Name, ns);
+ } else {
+ Hashtable new_table = new Hashtable ();
+ namespaces [file] = new_table;
+
+ new_table.Add (ns.Name, ns);
+ }
+
+ return ns;
+ }
+
+ //
+ // FIXME: Why are we using Types?
+ //
+ public TypeContainer Types {
+ get {
+ return root_types;
+ }
+ }
+
+ public Hashtable Decls {
+ get {
+ return decls;
+ }
+ }
+
+ public Hashtable Namespaces {
+ get {
+ return namespaces;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// typemanager.cs: C# type manager
+//
+// Author: 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)
+//
+//
+
+//
+// We will eventually remove the SIMPLE_SPEEDUP, and should never change
+// the behavior of the compilation. This can be removed if we rework
+// the code to get a list of namespaces available.
+//
+#define SIMPLE_SPEEDUP
+
+using System;
+using System.IO;
+using System.Globalization;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Runtime.CompilerServices;
+using System.Diagnostics;
+
+namespace Mono.CSharp {
+
+public class TypeManager {
+ //
+ // A list of core types that the compiler requires or uses
+ //
+ static public Type object_type;
+ static public Type value_type;
+ static public Type string_type;
+ static public Type int32_type;
+ static public Type uint32_type;
+ static public Type int64_type;
+ static public Type uint64_type;
+ static public Type float_type;
+ static public Type double_type;
+ static public Type char_type;
+ static public Type char_ptr_type;
+ static public Type short_type;
+ static public Type decimal_type;
+ static public Type bool_type;
+ static public Type sbyte_type;
+ static public Type byte_type;
+ static public Type ushort_type;
+ static public Type enum_type;
+ static public Type delegate_type;
+ static public Type multicast_delegate_type;
+ static public Type void_type;
+ static public Type enumeration_type;
+ static public Type array_type;
+ static public Type runtime_handle_type;
+ static public Type icloneable_type;
+ static public Type type_type;
+ static public Type ienumerator_type;
+ static public Type ienumerable_type;
+ static public Type idisposable_type;
+ static public Type default_member_type;
+ static public Type iasyncresult_type;
+ static public Type asynccallback_type;
+ static public Type intptr_type;
+ static public Type monitor_type;
+ static public Type runtime_field_handle_type;
+ static public Type attribute_type;
+ static public Type attribute_usage_type;
+ static public Type dllimport_type;
+ static public Type unverifiable_code_type;
+ static public Type methodimpl_attr_type;
+ static public Type marshal_as_attr_type;
+ static public Type param_array_type;
+ static public Type guid_attr_type;
+ static public Type void_ptr_type;
+ static public Type indexer_name_type;
+ static public Type exception_type;
+ static public Type invalid_operation_exception_type;
+ static public object obsolete_attribute_type;
+ static public object conditional_attribute_type;
+ static public Type in_attribute_type;
+
+ //
+ // An empty array of types
+ //
+ static public Type [] NoTypes;
+
+
+ //
+ // Expressions representing the internal types. Used during declaration
+ // definition.
+ //
+ static public Expression system_object_expr, system_string_expr;
+ static public Expression system_boolean_expr, system_decimal_expr;
+ static public Expression system_single_expr, system_double_expr;
+ static public Expression system_sbyte_expr, system_byte_expr;
+ static public Expression system_int16_expr, system_uint16_expr;
+ static public Expression system_int32_expr, system_uint32_expr;
+ static public Expression system_int64_expr, system_uint64_expr;
+ static public Expression system_char_expr, system_void_expr;
+ static public Expression system_asynccallback_expr;
+ static public Expression system_iasyncresult_expr;
+
+ //
+ // This is only used when compiling corlib
+ //
+ static public Type system_int32_type;
+ static public Type system_array_type;
+ static public Type system_type_type;
+ static public Type system_assemblybuilder_type;
+ static public MethodInfo system_int_array_get_length;
+ static public MethodInfo system_int_array_get_rank;
+ static public MethodInfo system_object_array_clone;
+ static public MethodInfo system_int_array_get_length_int;
+ static public MethodInfo system_int_array_get_lower_bound_int;
+ static public MethodInfo system_int_array_get_upper_bound_int;
+ static public MethodInfo system_void_array_copyto_array_int;
+
+
+ //
+ // Internal, not really used outside
+ //
+ static Type runtime_helpers_type;
+
+ //
+ // These methods are called by code generated by the compiler
+ //
+ static public MethodInfo string_concat_string_string;
+ static public MethodInfo string_concat_string_string_string;
+ static public MethodInfo string_concat_string_string_string_string;
+ static public MethodInfo string_concat_object_object;
+ static public MethodInfo string_isinterneted_string;
+ static public MethodInfo system_type_get_type_from_handle;
+ static public MethodInfo object_getcurrent_void;
+ static public MethodInfo bool_movenext_void;
+ static public MethodInfo ienumerable_getenumerator_void;
+ static public MethodInfo void_reset_void;
+ static public MethodInfo void_dispose_void;
+ static public MethodInfo void_monitor_enter_object;
+ static public MethodInfo void_monitor_exit_object;
+ static public MethodInfo void_initializearray_array_fieldhandle;
+ static public MethodInfo int_getlength_int;
+ static public MethodInfo delegate_combine_delegate_delegate;
+ static public MethodInfo delegate_remove_delegate_delegate;
+ static public MethodInfo int_get_offset_to_string_data;
+ static public MethodInfo int_array_get_length;
+ static public MethodInfo int_array_get_rank;
+ static public MethodInfo object_array_clone;
+ static public MethodInfo int_array_get_length_int;
+ static public MethodInfo int_array_get_lower_bound_int;
+ static public MethodInfo int_array_get_upper_bound_int;
+ static public MethodInfo void_array_copyto_array_int;
+
+ //
+ // The attribute constructors.
+ //
+ static public ConstructorInfo object_ctor;
+ static public ConstructorInfo cons_param_array_attribute;
+ static public ConstructorInfo void_decimal_ctor_five_args;
+ static public ConstructorInfo unverifiable_code_ctor;
+ static public ConstructorInfo invalid_operation_ctor;
+
+ // <remarks>
+ // Holds the Array of Assemblies that have been loaded
+ // (either because it is the default or the user used the
+ // -r command line option)
+ // </remarks>
+ static Assembly [] assemblies;
+
+ // <remarks>
+ // Keeps a list of module builders. We used this to do lookups
+ // on the modulebuilder using GetType -- needed for arrays
+ // </remarks>
+ static ModuleBuilder [] modules;
+
+ // <remarks>
+ // This is the type_cache from the assemblies to avoid
+ // hitting System.Reflection on every lookup.
+ // </summary>
+ static Hashtable types;
+
+ // <remarks>
+ // This is used to hotld the corresponding TypeContainer objects
+ // since we need this in FindMembers
+ // </remarks>
+ static Hashtable typecontainers;
+
+ // <remarks>
+ // Keeps track of those types that are defined by the
+ // user's program
+ // </remarks>
+ static ArrayList user_types;
+
+ static PtrHashtable builder_to_declspace;
+
+ // <remarks>
+ // Tracks the interfaces implemented by typebuilders. We only
+ // enter those who do implement or or more interfaces
+ // </remarks>
+ static PtrHashtable builder_to_ifaces;
+
+ // <remarks>
+ // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
+ // the arguments to the method
+ // </remarks>
+ static Hashtable method_arguments;
+
+ // <remarks>
+ // Maps PropertyBuilder to a Type array that contains
+ // the arguments to the indexer
+ // </remarks>
+ static Hashtable indexer_arguments;
+
+ // <remarks>
+ // Maybe `method_arguments' should be replaced and only
+ // method_internal_params should be kept?
+ // <remarks>
+ static Hashtable method_internal_params;
+
+ // <remarks>
+ // Keeps track of attribute types
+ // </remarks>
+
+ static Hashtable builder_to_attr;
+
+ // <remarks>
+ // Keeps track of methods
+ // </remarks>
+
+ static Hashtable builder_to_method;
+
+ struct Signature {
+ public string name;
+ public Type [] args;
+ }
+
+ /// <summary>
+ /// A filter for Findmembers that uses the Signature object to
+ /// extract objects
+ /// </summary>
+ static bool SignatureFilter (MemberInfo mi, object criteria)
+ {
+ Signature sig = (Signature) criteria;
+
+ if (!(mi is MethodBase))
+ return false;
+
+ if (mi.Name != sig.name)
+ return false;
+
+ int count = sig.args.Length;
+
+ if (mi is MethodBuilder || mi is ConstructorBuilder){
+ Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
+
+ if (candidate_args.Length != count)
+ return false;
+
+ for (int i = 0; i < count; i++)
+ if (candidate_args [i] != sig.args [i])
+ return false;
+
+ return true;
+ } else {
+ ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
+
+ if (pars.Length != count)
+ return false;
+
+ for (int i = 0; i < count; i++)
+ if (pars [i].ParameterType != sig.args [i])
+ return false;
+ return true;
+ }
+ }
+
+ // A delegate that points to the filter above.
+ static MemberFilter signature_filter;
+
+ //
+ // These are expressions that represent some of the internal data types, used
+ // elsewhere
+ //
+ static void InitExpressionTypes ()
+ {
+ system_object_expr = new TypeLookupExpression ("System.Object");
+ system_string_expr = new TypeLookupExpression ("System.String");
+ system_boolean_expr = new TypeLookupExpression ("System.Boolean");
+ system_decimal_expr = new TypeLookupExpression ("System.Decimal");
+ system_single_expr = new TypeLookupExpression ("System.Single");
+ system_double_expr = new TypeLookupExpression ("System.Double");
+ system_sbyte_expr = new TypeLookupExpression ("System.SByte");
+ system_byte_expr = new TypeLookupExpression ("System.Byte");
+ system_int16_expr = new TypeLookupExpression ("System.Int16");
+ system_uint16_expr = new TypeLookupExpression ("System.UInt16");
+ system_int32_expr = new TypeLookupExpression ("System.Int32");
+ system_uint32_expr = new TypeLookupExpression ("System.UInt32");
+ system_int64_expr = new TypeLookupExpression ("System.Int64");
+ system_uint64_expr = new TypeLookupExpression ("System.UInt64");
+ system_char_expr = new TypeLookupExpression ("System.Char");
+ system_void_expr = new TypeLookupExpression ("System.Void");
+ system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
+ system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
+ }
+
+ static TypeManager ()
+ {
+ assemblies = new Assembly [0];
+ modules = null;
+ user_types = new ArrayList ();
+
+ types = new Hashtable ();
+ typecontainers = new Hashtable ();
+
+ builder_to_declspace = new PtrHashtable ();
+ builder_to_attr = new PtrHashtable ();
+ builder_to_method = new PtrHashtable ();
+ method_arguments = new PtrHashtable ();
+ method_internal_params = new PtrHashtable ();
+ indexer_arguments = new PtrHashtable ();
+ builder_to_ifaces = new PtrHashtable ();
+
+ NoTypes = new Type [0];
+
+ signature_filter = new MemberFilter (SignatureFilter);
+ InitExpressionTypes ();
+ }
+
+ public static void HandleDuplicate (string name, Type t)
+ {
+ Type prev = (Type) types [name];
+ TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
+
+ if (tc != null){
+ //
+ // This probably never happens, as we catch this before
+ //
+ Report.Error (-17, "The type `" + name + "' has already been defined.");
+ return;
+ }
+
+ Location l;
+ tc = builder_to_declspace [t] as TypeContainer;
+ if (tc != null){
+ Report.Warning (
+ 1595, "The type `" + name + "' is defined in an existing assembly;"+
+ " Using the new definition from: " + tc.Location);
+ } else {
+ Report.Warning (
+ 1595, "The type `" + name + "' is defined in an existing assembly;");
+ }
+
+ Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
+
+ types.Remove (name);
+ types.Add (name, t);
+ }
+
+ public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
+ {
+ try {
+ types.Add (name, t);
+ } catch {
+ HandleDuplicate (name, t);
+ }
+ user_types.Add (t);
+
+ if (ifaces != null)
+ builder_to_ifaces [t] = ifaces;
+ }
+
+ //
+ // This entry point is used by types that we define under the covers
+ //
+ public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
+ {
+ if (ifaces != null)
+ builder_to_ifaces [tb] = ifaces;
+ }
+
+ public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
+ {
+ builder_to_declspace.Add (t, tc);
+ typecontainers.Add (name, tc);
+ AddUserType (name, t, ifaces);
+ }
+
+ public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
+ {
+ try {
+ types.Add (name, t);
+ } catch {
+ HandleDuplicate (name, t);
+ }
+
+ builder_to_declspace.Add (t, del);
+ }
+
+ public static void AddEnumType (string name, TypeBuilder t, Enum en)
+ {
+ try {
+ types.Add (name, t);
+ } catch {
+ HandleDuplicate (name, t);
+ }
+ builder_to_declspace.Add (t, en);
+ }
+
+ public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
+ {
+ AddUserType (name, t, ifaces);
+ builder_to_declspace.Add (t, i);
+ }
+
+ public static void AddMethod (MethodBuilder builder, MethodData method)
+ {
+ builder_to_method.Add (builder, method);
+ }
+
+ public static void RegisterAttrType (Type t, TypeContainer tc)
+ {
+ builder_to_attr.Add (t, tc);
+ }
+
+ /// <summary>
+ /// Returns the DeclSpace whose Type is `t' or null if there is no
+ /// DeclSpace for `t' (ie, the Type comes from a library)
+ /// </summary>
+ public static DeclSpace LookupDeclSpace (Type t)
+ {
+ return builder_to_declspace [t] as DeclSpace;
+ }
+
+ /// <summary>
+ /// Returns the TypeContainer whose Type is `t' or null if there is no
+ /// TypeContainer for `t' (ie, the Type comes from a library)
+ /// </summary>
+ public static TypeContainer LookupTypeContainer (Type t)
+ {
+ return builder_to_declspace [t] as TypeContainer;
+ }
+
+ public static IMemberContainer LookupMemberContainer (Type t)
+ {
+ if (t is TypeBuilder) {
+ IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
+ if (container != null)
+ return container;
+ }
+
+ return TypeHandle.GetTypeHandle (t);
+ }
+
+ public static Interface LookupInterface (Type t)
+ {
+ return builder_to_declspace [t] as Interface;
+ }
+
+ public static Delegate LookupDelegate (Type t)
+ {
+ return builder_to_declspace [t] as Delegate;
+ }
+
+ public static Enum LookupEnum (Type t)
+ {
+ return builder_to_declspace [t] as Enum;
+ }
+
+ public static TypeContainer LookupAttr (Type t)
+ {
+ return (TypeContainer) builder_to_attr [t];
+ }
+
+ /// <summary>
+ /// Registers an assembly to load types from.
+ /// </summary>
+ public static void AddAssembly (Assembly a)
+ {
+ int top = assemblies.Length;
+ Assembly [] n = new Assembly [top + 1];
+
+ assemblies.CopyTo (n, 0);
+
+ n [top] = a;
+ assemblies = n;
+ }
+
+ /// <summary>
+ /// Registers a module builder to lookup types from
+ /// </summary>
+ public static void AddModule (ModuleBuilder mb)
+ {
+ int top = modules != null ? modules.Length : 0;
+ ModuleBuilder [] n = new ModuleBuilder [top + 1];
+
+ if (modules != null)
+ modules.CopyTo (n, 0);
+ n [top] = mb;
+ modules = n;
+ }
+
+ static Hashtable references = new Hashtable ();
+
+ //
+ // Gets the reference to T version of the Type (T&)
+ //
+ public static Type GetReferenceType (Type t)
+ {
+ string tname = t.FullName + "&";
+
+ Type ret = t.Assembly.GetType (tname);
+
+ //
+ // If the type comes from the assembly we are building
+ // We need the Hashtable, because .NET 1.1 will return different instance types
+ // every time we call ModuleBuilder.GetType.
+ //
+ if (ret == null){
+ if (references [t] == null)
+ references [t] = CodeGen.ModuleBuilder.GetType (tname);
+ ret = (Type) references [t];
+ }
+
+ return ret;
+ }
+
+ static Hashtable pointers = new Hashtable ();
+
+ //
+ // Gets the pointer to T version of the Type (T*)
+ //
+ public static Type GetPointerType (Type t)
+ {
+ string tname = t.FullName + "*";
+
+ Type ret = t.Assembly.GetType (tname);
+
+ //
+ // If the type comes from the assembly we are building
+ // We need the Hashtable, because .NET 1.1 will return different instance types
+ // every time we call ModuleBuilder.GetType.
+ //
+ if (ret == null){
+ if (pointers [t] == null)
+ pointers [t] = CodeGen.ModuleBuilder.GetType (tname);
+
+ ret = (Type) pointers [t];
+ }
+
+ return ret;
+ }
+
+ //
+ // Low-level lookup, cache-less
+ //
+ static Type LookupTypeReflection (string name)
+ {
+ Type t;
+
+ foreach (Assembly a in assemblies){
+ t = a.GetType (name);
+ if (t == null)
+ continue;
+
+ TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
+ if (ta == TypeAttributes.NotPublic ||
+ ta == TypeAttributes.NestedPrivate ||
+ ta == TypeAttributes.NestedAssembly ||
+ ta == TypeAttributes.NestedFamANDAssem)
+ continue;
+ return t;
+ }
+
+ foreach (ModuleBuilder mb in modules) {
+ t = mb.GetType (name);
+ if (t != null)
+ return t;
+ }
+
+ return null;
+ }
+
+ static Hashtable negative_hits = new Hashtable ();
+
+ //
+ // This function is used when you want to avoid the lookups, and want to go
+ // directly to the source. This will use the cache.
+ //
+ // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
+ // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
+ // way to test things other than doing a fullname compare
+ //
+ public static Type LookupTypeDirect (string name)
+ {
+ Type t = (Type) types [name];
+ if (t != null)
+ return t;
+
+ t = LookupTypeReflection (name);
+ if (t == null)
+ return null;
+
+ types [name] = t;
+ return t;
+ }
+
+ /// <summary>
+ /// Returns the Type associated with @name, takes care of the fact that
+ /// reflection expects nested types to be separated from the main type
+ /// with a "+" instead of a "."
+ /// </summary>
+ public static Type LookupType (string name)
+ {
+ Type t;
+
+ //
+ // First lookup in user defined and cached values
+ //
+
+ t = (Type) types [name];
+ if (t != null)
+ return t;
+
+ // Two thirds of the failures are caught here.
+ if (negative_hits.Contains (name))
+ return null;
+
+ string [] elements = name.Split ('.');
+ int count = elements.Length;
+
+ for (int n = 1; n <= count; n++){
+ string top_level_type = String.Join (".", elements, 0, n);
+
+ // One third of the failures are caught here.
+ if (negative_hits.Contains (top_level_type))
+ continue;
+
+ t = (Type) types [top_level_type];
+ if (t == null){
+ t = LookupTypeReflection (top_level_type);
+ if (t == null){
+ negative_hits [top_level_type] = true;
+ continue;
+ }
+ }
+
+ if (count == n){
+ types [name] = t;
+ return t;
+ }
+
+ //
+ // We know that System.Object does not have children, and since its the parent of
+ // all the objects, it always gets probbed for inner classes.
+ //
+ if (top_level_type == "System.Object")
+ return null;
+
+ string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
+ //Console.WriteLine ("Looking up: " + newt + " " + name);
+ t = LookupTypeReflection (newt);
+ if (t == null)
+ negative_hits [name] = true;
+ else
+ types [name] = t;
+ return t;
+ }
+ negative_hits [name] = true;
+ return null;
+ }
+
+ /// <summary>
+ /// Computes the namespaces that we import from the assemblies we reference.
+ /// </summary>
+ public static void ComputeNamespaces ()
+ {
+ MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces");
+
+ //
+ // First add the assembly namespaces
+ //
+ if (assembly_get_namespaces != null){
+ int count = assemblies.Length;
+ int total;
+
+ for (int i = 0; i < count; i++){
+ Assembly a = assemblies [i];
+ string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
+ foreach (string ns in namespaces){
+ if (ns == "")
+ continue;
+ Namespace.LookupNamespace (ns, true);
+ }
+ }
+ } else {
+ foreach (Assembly a in assemblies){
+ foreach (Type t in a.GetTypes ()){
+ string ns = t.Namespace;
+
+ // t.Namespace returns null for <PrivateImplDetails>
+ if (ns == ""|| ns == null)
+ continue;
+ Namespace.LookupNamespace (ns, true);
+ }
+ }
+ }
+ }
+
+ public static bool NamespaceClash (string name, Location loc)
+ {
+ if (Namespace.LookupNamespace (name, false) == null)
+ return false;
+
+ Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
+ return true;
+ }
+
+ /// <summary>
+ /// Returns the C# name of a type if possible, or the full type name otherwise
+ /// </summary>
+ static public string CSharpName (Type t)
+ {
+ return Regex.Replace (t.FullName,
+ @"^System\." +
+ @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
+ @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
+ @"Boolean|String|Void)" +
+ @"(\W+|\b)",
+ new MatchEvaluator (CSharpNameMatch));
+ }
+
+ static String CSharpNameMatch (Match match)
+ {
+ string s = match.Groups [1].Captures [0].Value;
+ return s.ToLower ().
+ Replace ("int32", "int").
+ Replace ("uint32", "uint").
+ Replace ("int16", "short").
+ Replace ("uint16", "ushort").
+ Replace ("int64", "long").
+ Replace ("uint64", "ulong").
+ Replace ("single", "float").
+ Replace ("boolean", "bool")
+ + match.Groups [2].Captures [0].Value;
+ }
+
+ /// <summary>
+ /// Returns the signature of the method
+ /// </summary>
+ static public string CSharpSignature (MethodBase mb)
+ {
+ string sig = "(";
+
+ //
+ // FIXME: We should really have a single function to do
+ // everything instead of the following 5 line pattern
+ //
+ ParameterData iparams = LookupParametersByBuilder (mb);
+
+ if (iparams == null){
+ ParameterInfo [] pi = mb.GetParameters ();
+ iparams = new ReflectionParameters (pi);
+ }
+
+ for (int i = 0; i < iparams.Count; i++) {
+ if (i > 0) {
+ sig += ", ";
+ }
+ sig += iparams.ParameterDesc(i);
+ }
+ sig += ")";
+
+ return mb.DeclaringType.Name + "." + mb.Name + sig;
+ }
+
+ /// <summary>
+ /// Looks up a type, and aborts if it is not found. This is used
+ /// by types required by the compiler
+ /// </summary>
+ static Type CoreLookupType (string name)
+ {
+ Type t = LookupTypeDirect (name);
+
+ if (t == null){
+ Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
+ Environment.Exit (0);
+ }
+
+ return t;
+ }
+
+ /// <summary>
+ /// Returns the MethodInfo for a method named `name' defined
+ /// in type `t' which takes arguments of types `args'
+ /// </summary>
+ static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
+ {
+ MemberList list;
+ Signature sig;
+
+ sig.name = name;
+ sig.args = args;
+
+ list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
+ signature_filter, sig);
+ if (list.Count == 0) {
+ if (report_errors)
+ Report.Error (-19, "Can not find the core function `" + name + "'");
+ return null;
+ }
+
+ MethodInfo mi = list [0] as MethodInfo;
+ if (mi == null) {
+ if (report_errors)
+ Report.Error (-19, "Can not find the core function `" + name + "'");
+ return null;
+ }
+
+ return mi;
+ }
+
+ static MethodInfo GetMethod (Type t, string name, Type [] args)
+ {
+ return GetMethod (t, name, args, true);
+ }
+
+
+ /// <summary>
+ /// Returns the ConstructorInfo for "args"
+ /// </summary>
+ static ConstructorInfo GetConstructor (Type t, Type [] args)
+ {
+ MemberList list;
+ Signature sig;
+
+ sig.name = ".ctor";
+ sig.args = args;
+
+ list = FindMembers (t, MemberTypes.Constructor,
+ instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
+ signature_filter, sig);
+ if (list.Count == 0){
+ Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
+ return null;
+ }
+
+ ConstructorInfo ci = list [0] as ConstructorInfo;
+ if (ci == null){
+ Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
+ return null;
+ }
+
+ return ci;
+ }
+
+ public static void InitEnumUnderlyingTypes ()
+ {
+
+ int32_type = CoreLookupType ("System.Int32");
+ int64_type = CoreLookupType ("System.Int64");
+ uint32_type = CoreLookupType ("System.UInt32");
+ uint64_type = CoreLookupType ("System.UInt64");
+ byte_type = CoreLookupType ("System.Byte");
+ sbyte_type = CoreLookupType ("System.SByte");
+ short_type = CoreLookupType ("System.Int16");
+ ushort_type = CoreLookupType ("System.UInt16");
+ }
+
+ /// <remarks>
+ /// The types have to be initialized after the initial
+ /// population of the type has happened (for example, to
+ /// bootstrap the corlib.dll
+ /// </remarks>
+ public static void InitCoreTypes ()
+ {
+ object_type = CoreLookupType ("System.Object");
+ value_type = CoreLookupType ("System.ValueType");
+
+ InitEnumUnderlyingTypes ();
+
+ char_type = CoreLookupType ("System.Char");
+ string_type = CoreLookupType ("System.String");
+ float_type = CoreLookupType ("System.Single");
+ double_type = CoreLookupType ("System.Double");
+ char_ptr_type = CoreLookupType ("System.Char*");
+ decimal_type = CoreLookupType ("System.Decimal");
+ bool_type = CoreLookupType ("System.Boolean");
+ enum_type = CoreLookupType ("System.Enum");
+
+ multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
+ delegate_type = CoreLookupType ("System.Delegate");
+
+ array_type = CoreLookupType ("System.Array");
+ void_type = CoreLookupType ("System.Void");
+ type_type = CoreLookupType ("System.Type");
+
+ runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
+ runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
+ default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
+ runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
+ asynccallback_type = CoreLookupType ("System.AsyncCallback");
+ iasyncresult_type = CoreLookupType ("System.IAsyncResult");
+ ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
+ ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
+ idisposable_type = CoreLookupType ("System.IDisposable");
+ icloneable_type = CoreLookupType ("System.ICloneable");
+ monitor_type = CoreLookupType ("System.Threading.Monitor");
+ intptr_type = CoreLookupType ("System.IntPtr");
+
+ attribute_type = CoreLookupType ("System.Attribute");
+ attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
+ dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
+ methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
+ marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
+ param_array_type = CoreLookupType ("System.ParamArrayAttribute");
+ in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
+
+ //
+ // Sigh. Remove this before the release. Wonder what versions of Mono
+ // people are running.
+ //
+ guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
+
+ unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
+
+ void_ptr_type = CoreLookupType ("System.Void*");
+
+ indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
+
+ exception_type = CoreLookupType ("System.Exception");
+ invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
+
+ //
+ // Attribute types
+ //
+ obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
+ conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
+
+ //
+ // When compiling corlib, store the "real" types here.
+ //
+ if (!RootContext.StdLib) {
+ system_int32_type = typeof (System.Int32);
+ system_array_type = typeof (System.Array);
+ system_type_type = typeof (System.Type);
+ system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
+
+ Type [] void_arg = { };
+ system_int_array_get_length = GetMethod (
+ system_array_type, "get_Length", void_arg);
+ system_int_array_get_rank = GetMethod (
+ system_array_type, "get_Rank", void_arg);
+ system_object_array_clone = GetMethod (
+ system_array_type, "Clone", void_arg);
+
+ Type [] system_int_arg = { system_int32_type };
+ system_int_array_get_length_int = GetMethod (
+ system_array_type, "GetLength", system_int_arg);
+ system_int_array_get_upper_bound_int = GetMethod (
+ system_array_type, "GetUpperBound", system_int_arg);
+ system_int_array_get_lower_bound_int = GetMethod (
+ system_array_type, "GetLowerBound", system_int_arg);
+
+ Type [] system_array_int_arg = { system_array_type, system_int32_type };
+ system_void_array_copyto_array_int = GetMethod (
+ system_array_type, "CopyTo", system_array_int_arg);
+
+ Type [] system_3_type_arg = {
+ system_type_type, system_type_type, system_type_type };
+ Type [] system_4_type_arg = {
+ system_type_type, system_type_type, system_type_type, system_type_type };
+
+ MethodInfo set_corlib_type_builders = GetMethod (
+ system_assemblybuilder_type, "SetCorlibTypeBuilders",
+ system_4_type_arg, false);
+
+ if (set_corlib_type_builders != null) {
+ object[] args = new object [4];
+ args [0] = object_type;
+ args [1] = value_type;
+ args [2] = enum_type;
+ args [3] = void_type;
+
+ set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
+ } else {
+ // Compatibility for an older version of the class libs.
+ set_corlib_type_builders = GetMethod (
+ system_assemblybuilder_type, "SetCorlibTypeBuilders",
+ system_3_type_arg, true);
+
+ if (set_corlib_type_builders == null) {
+ Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
+ return;
+ }
+
+ object[] args = new object [3];
+ args [0] = object_type;
+ args [1] = value_type;
+ args [2] = enum_type;
+
+ set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
+ }
+ }
+ }
+
+ //
+ // The helper methods that are used by the compiler
+ //
+ public static void InitCodeHelpers ()
+ {
+ //
+ // Now load the default methods that we use.
+ //
+ Type [] string_string = { string_type, string_type };
+ string_concat_string_string = GetMethod (
+ string_type, "Concat", string_string);
+ Type [] string_string_string = { string_type, string_type, string_type };
+ string_concat_string_string_string = GetMethod (
+ string_type, "Concat", string_string_string);
+ Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
+ string_concat_string_string_string_string = GetMethod (
+ string_type, "Concat", string_string_string_string);
+
+ Type [] object_object = { object_type, object_type };
+ string_concat_object_object = GetMethod (
+ string_type, "Concat", object_object);
+
+ Type [] string_ = { string_type };
+ string_isinterneted_string = GetMethod (
+ string_type, "IsInterned", string_);
+
+ Type [] runtime_type_handle = { runtime_handle_type };
+ system_type_get_type_from_handle = GetMethod (
+ type_type, "GetTypeFromHandle", runtime_type_handle);
+
+ Type [] delegate_delegate = { delegate_type, delegate_type };
+ delegate_combine_delegate_delegate = GetMethod (
+ delegate_type, "Combine", delegate_delegate);
+
+ delegate_remove_delegate_delegate = GetMethod (
+ delegate_type, "Remove", delegate_delegate);
+
+ //
+ // Void arguments
+ //
+ Type [] void_arg = { };
+ object_getcurrent_void = GetMethod (
+ ienumerator_type, "get_Current", void_arg);
+ bool_movenext_void = GetMethod (
+ ienumerator_type, "MoveNext", void_arg);
+ void_reset_void = GetMethod (
+ ienumerator_type, "Reset", void_arg);
+ void_dispose_void = GetMethod (
+ idisposable_type, "Dispose", void_arg);
+ int_get_offset_to_string_data = GetMethod (
+ runtime_helpers_type, "get_OffsetToStringData", void_arg);
+ int_array_get_length = GetMethod (
+ array_type, "get_Length", void_arg);
+ int_array_get_rank = GetMethod (
+ array_type, "get_Rank", void_arg);
+ ienumerable_getenumerator_void = GetMethod (
+ ienumerable_type, "GetEnumerator", void_arg);
+
+ //
+ // Int32 arguments
+ //
+ Type [] int_arg = { int32_type };
+ int_array_get_length_int = GetMethod (
+ array_type, "GetLength", int_arg);
+ int_array_get_upper_bound_int = GetMethod (
+ array_type, "GetUpperBound", int_arg);
+ int_array_get_lower_bound_int = GetMethod (
+ array_type, "GetLowerBound", int_arg);
+
+ //
+ // System.Array methods
+ //
+ object_array_clone = GetMethod (
+ array_type, "Clone", void_arg);
+ Type [] array_int_arg = { array_type, int32_type };
+ void_array_copyto_array_int = GetMethod (
+ array_type, "CopyTo", array_int_arg);
+
+ //
+ // object arguments
+ //
+ Type [] object_arg = { object_type };
+ void_monitor_enter_object = GetMethod (
+ monitor_type, "Enter", object_arg);
+ void_monitor_exit_object = GetMethod (
+ monitor_type, "Exit", object_arg);
+
+ Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
+
+ void_initializearray_array_fieldhandle = GetMethod (
+ runtime_helpers_type, "InitializeArray", array_field_handle_arg);
+
+ //
+ // Array functions
+ //
+ int_getlength_int = GetMethod (
+ array_type, "GetLength", int_arg);
+
+ //
+ // Decimal constructors
+ //
+ Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
+ void_decimal_ctor_five_args = GetConstructor (
+ decimal_type, dec_arg);
+
+ //
+ // Attributes
+ //
+ cons_param_array_attribute = GetConstructor (
+ param_array_type, void_arg);
+
+ unverifiable_code_ctor = GetConstructor (
+ unverifiable_code_type, void_arg);
+
+ //
+ // InvalidOperationException
+ //
+ invalid_operation_ctor = GetConstructor (
+ invalid_operation_exception_type, void_arg);
+
+
+ // Object
+ object_ctor = GetConstructor (object_type, void_arg);
+
+ }
+
+ const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
+
+ static Hashtable type_hash = new Hashtable ();
+
+ /// <remarks>
+ /// This is the "old", non-cache based FindMembers() function. We cannot use
+ /// the cache here because there is no member name argument.
+ /// </remarks>
+ public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ DeclSpace decl = (DeclSpace) builder_to_declspace [t];
+
+ //
+ // `builder_to_declspace' contains all dynamic types.
+ //
+ if (decl != null) {
+ MemberList list;
+ Timer.StartTimer (TimerType.FindMembers);
+ list = decl.FindMembers (mt, bf, filter, criteria);
+ Timer.StopTimer (TimerType.FindMembers);
+ return list;
+ }
+
+ //
+ // We have to take care of arrays specially, because GetType on
+ // a TypeBuilder array will return a Type, not a TypeBuilder,
+ // and we can not call FindMembers on this type.
+ //
+ if (t.IsSubclassOf (TypeManager.array_type))
+ return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
+
+ //
+ // Since FindMembers will not lookup both static and instance
+ // members, we emulate this behaviour here.
+ //
+ if ((bf & instance_and_static) == instance_and_static){
+ MemberInfo [] i_members = t.FindMembers (
+ mt, bf & ~BindingFlags.Static, filter, criteria);
+
+ int i_len = i_members.Length;
+ if (i_len == 1){
+ MemberInfo one = i_members [0];
+
+ //
+ // If any of these are present, we are done!
+ //
+ if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
+ return new MemberList (i_members);
+ }
+
+ MemberInfo [] s_members = t.FindMembers (
+ mt, bf & ~BindingFlags.Instance, filter, criteria);
+
+ int s_len = s_members.Length;
+ if (i_len > 0 || s_len > 0)
+ return new MemberList (i_members, s_members);
+ else {
+ if (i_len > 0)
+ return new MemberList (i_members);
+ else
+ return new MemberList (s_members);
+ }
+ }
+
+ return new MemberList (t.FindMembers (mt, bf, filter, criteria));
+ }
+
+
+ /// <summary>
+ /// This method is only called from within MemberLookup. It tries to use the member
+ /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
+ /// flag tells the caller whether we used the cache or not. If we used the cache, then
+ /// our return value will already contain all inherited members and the caller don't need
+ /// to check base classes and interfaces anymore.
+ /// </summary>
+ private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
+ string name, out bool used_cache)
+ {
+ bool not_loaded_corlib = (t.Assembly == CodeGen.AssemblyBuilder);
+
+ //
+ // We have to take care of arrays specially, because GetType on
+ // a TypeBuilder array will return a Type, not a TypeBuilder,
+ // and we can not call FindMembers on this type.
+ //
+ if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
+ used_cache = true;
+ return TypeHandle.ArrayType.MemberCache.FindMembers (
+ mt, bf, name, FilterWithClosure_delegate, null);
+ }
+
+ //
+ // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
+ // and we can ask the DeclSpace for the MemberCache.
+ //
+ if (t is TypeBuilder) {
+ DeclSpace decl = (DeclSpace) builder_to_declspace [t];
+ MemberCache cache = decl.MemberCache;
+
+ //
+ // If this DeclSpace has a MemberCache, use it.
+ //
+
+ if (cache != null) {
+ used_cache = true;
+ return cache.FindMembers (
+ mt, bf, name, FilterWithClosure_delegate, null);
+ }
+
+ // If there is no MemberCache, we need to use the "normal" FindMembers.
+
+ MemberList list;
+ Timer.StartTimer (TimerType.FindMembers);
+ list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
+ FilterWithClosure_delegate, name);
+ Timer.StopTimer (TimerType.FindMembers);
+ used_cache = false;
+ return list;
+ }
+
+ //
+ // This call will always succeed. There is exactly one TypeHandle instance per
+ // type, TypeHandle.GetTypeHandle() will either return it or create a new one
+ // if it didn't already exist.
+ //
+ TypeHandle handle = TypeHandle.GetTypeHandle (t);
+
+ used_cache = true;
+ return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
+ }
+
+ public static bool IsBuiltinType (Type t)
+ {
+ if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
+ t == int64_type || t == uint64_type || t == float_type || t == double_type ||
+ t == char_type || t == short_type || t == decimal_type || t == bool_type ||
+ t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
+ return true;
+ else
+ return false;
+ }
+
+ //
+ // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
+ // the pieces in the code where we use IsBuiltinType and special case decimal_type.
+ //
+ public static bool IsCLRType (Type t)
+ {
+ if (t == object_type || t == int32_type || t == uint32_type ||
+ t == int64_type || t == uint64_type || t == float_type || t == double_type ||
+ t == char_type || t == short_type || t == bool_type ||
+ t == sbyte_type || t == byte_type || t == ushort_type)
+ return true;
+ else
+ return false;
+ }
+
+ public static bool IsDelegateType (Type t)
+ {
+ if (t.IsSubclassOf (TypeManager.delegate_type))
+ return true;
+ else
+ return false;
+ }
+
+ public static bool IsEnumType (Type t)
+ {
+ if (t == TypeManager.enum_type || t.IsSubclassOf (TypeManager.enum_type))
+ return true;
+ else
+ return false;
+ }
+
+ //
+ // Whether a type is unmanaged. This is used by the unsafe code (25.2)
+ //
+ public static bool IsUnmanagedType (Type t)
+ {
+ if (IsBuiltinType (t) && t != TypeManager.string_type)
+ return true;
+
+ if (IsEnumType (t))
+ return true;
+
+ if (t.IsPointer)
+ return true;
+
+ if (IsValueType (t)){
+ if (t is TypeBuilder){
+ TypeContainer tc = LookupTypeContainer (t);
+
+ foreach (Field f in tc.Fields){
+ if (f.FieldBuilder.IsStatic)
+ continue;
+ if (!IsUnmanagedType (f.FieldBuilder.FieldType))
+ return false;
+ }
+ } else {
+ FieldInfo [] fields = t.GetFields ();
+
+ foreach (FieldInfo f in fields){
+ if (f.IsStatic)
+ continue;
+ if (!IsUnmanagedType (f.FieldType))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool IsValueType (Type t)
+ {
+ if (t.IsSubclassOf (TypeManager.value_type) && (t != TypeManager.enum_type))
+ return true;
+ else
+ return false;
+ }
+
+ public static bool IsInterfaceType (Type t)
+ {
+ Interface iface = builder_to_declspace [t] as Interface;
+
+ if (iface != null)
+ return true;
+ else
+ return false;
+ }
+
+ //
+ // Checks whether `type' is a subclass or nested child of `parent'.
+ //
+ public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
+ {
+ do {
+ if ((type == parent) || type.IsSubclassOf (parent))
+ return true;
+
+ // Handle nested types.
+ type = type.DeclaringType;
+ } while (type != null);
+
+ return false;
+ }
+
+ //
+ // Checks whether `type' is a nested child of `parent'.
+ //
+ public static bool IsNestedChildOf (Type type, Type parent)
+ {
+ if (type == parent)
+ return false;
+
+ type = type.DeclaringType;
+ while (type != null) {
+ if (type == parent)
+ return true;
+
+ type = type.DeclaringType;
+ }
+
+ return false;
+ }
+
+ //
+ // Do the right thing when returning the element type of
+ // an array type based on whether we
+ //
+ public static Type GetElementType (Type t)
+ {
+ if (RootContext.StdLib)
+ return t.GetElementType ();
+ else
+ return TypeToCoreType (t.GetElementType ());
+ }
+
+ /// <summary>
+ /// Returns the User Defined Types
+ /// </summary>
+ public static ArrayList UserTypes {
+ get {
+ return user_types;
+ }
+ }
+
+ public static Hashtable TypeContainers {
+ get {
+ return typecontainers;
+ }
+ }
+
+ static Hashtable attr_to_allowmult;
+
+ public static void RegisterAttributeAllowMultiple (Type attr_type, bool allow)
+ {
+ if (attr_to_allowmult == null)
+ attr_to_allowmult = new PtrHashtable ();
+
+ if (attr_to_allowmult.Contains (attr_type))
+ return;
+
+ attr_to_allowmult.Add (attr_type, allow);
+
+ }
+
+ public static bool AreMultipleAllowed (Type attr_type)
+ {
+ if (!(attr_type is TypeBuilder)) {
+ System.Attribute [] attrs = System.Attribute.GetCustomAttributes (attr_type);
+
+ foreach (System.Attribute tmp in attrs)
+ if (tmp is AttributeUsageAttribute) {
+ return ((AttributeUsageAttribute) tmp).AllowMultiple;
+ }
+
+ return false;
+ }
+
+ if (attr_to_allowmult == null)
+ return false;
+
+ return (bool) attr_to_allowmult [attr_type];
+ }
+
+ static Hashtable builder_to_constant;
+
+ public static void RegisterConstant (FieldBuilder fb, Const c)
+ {
+ if (builder_to_constant == null)
+ builder_to_constant = new PtrHashtable ();
+
+ if (builder_to_constant.Contains (fb))
+ return;
+
+ builder_to_constant.Add (fb, c);
+ }
+
+ public static Const LookupConstant (FieldBuilder fb)
+ {
+ if (builder_to_constant == null)
+ return null;
+
+ return (Const) builder_to_constant [fb];
+ }
+
+ /// <summary>
+ /// Gigantic work around for missing features in System.Reflection.Emit follows.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Since System.Reflection.Emit can not return MethodBase.GetParameters
+ /// for anything which is dynamic, and we need this in a number of places,
+ /// we register this information here, and use it afterwards.
+ /// </remarks>
+ static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
+ {
+ if (args == null)
+ args = NoTypes;
+
+ method_arguments.Add (mb, args);
+ method_internal_params.Add (mb, ip);
+
+ return true;
+ }
+
+ static public InternalParameters LookupParametersByBuilder (MethodBase mb)
+ {
+ if (! (mb is ConstructorBuilder || mb is MethodBuilder))
+ return null;
+
+ if (method_internal_params.Contains (mb))
+ return (InternalParameters) method_internal_params [mb];
+ else
+ throw new Exception ("Argument for Method not registered" + mb);
+ }
+
+ /// <summary>
+ /// Returns the argument types for a method based on its methodbase
+ ///
+ /// For dynamic methods, we use the compiler provided types, for
+ /// methods from existing assemblies we load them from GetParameters,
+ /// and insert them into the cache
+ /// </summary>
+ static public Type [] GetArgumentTypes (MethodBase mb)
+ {
+ if (method_arguments.Contains (mb))
+ return (Type []) method_arguments [mb];
+ else {
+ ParameterInfo [] pi = mb.GetParameters ();
+ int c = pi.Length;
+ Type [] types = new Type [c];
+
+ for (int i = 0; i < c; i++)
+ types [i] = pi [i].ParameterType;
+
+ method_arguments.Add (mb, types);
+ return types;
+ }
+ }
+
+ /// <summary>
+ /// Returns the argument types for an indexer based on its PropertyInfo
+ ///
+ /// For dynamic indexers, we use the compiler provided types, for
+ /// indexers from existing assemblies we load them from GetParameters,
+ /// and insert them into the cache
+ /// </summary>
+ static public Type [] GetArgumentTypes (PropertyInfo indexer)
+ {
+ if (indexer_arguments.Contains (indexer))
+ return (Type []) indexer_arguments [indexer];
+ else if (indexer is PropertyBuilder)
+ // If we're a PropertyBuilder and not in the
+ // `indexer_arguments' hash, then we're a property and
+ // not an indexer.
+ return NoTypes;
+ else {
+ ParameterInfo [] pi = indexer.GetIndexParameters ();
+ // Property, not an indexer.
+ if (pi == null)
+ return NoTypes;
+ int c = pi.Length;
+ Type [] types = new Type [c];
+
+ for (int i = 0; i < c; i++)
+ types [i] = pi [i].ParameterType;
+
+ indexer_arguments.Add (indexer, types);
+ return types;
+ }
+ }
+
+ // <remarks>
+ // This is a workaround the fact that GetValue is not
+ // supported for dynamic types
+ // </remarks>
+ static Hashtable fields = new Hashtable ();
+ static public bool RegisterFieldValue (FieldBuilder fb, object value)
+ {
+ if (fields.Contains (fb))
+ return false;
+
+ fields.Add (fb, value);
+
+ return true;
+ }
+
+ static public object GetValue (FieldBuilder fb)
+ {
+ return fields [fb];
+ }
+
+ static Hashtable fieldbuilders_to_fields = new Hashtable ();
+ static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
+ {
+ if (fieldbuilders_to_fields.Contains (fb))
+ return false;
+
+ fieldbuilders_to_fields.Add (fb, f);
+ return true;
+ }
+
+ static public FieldBase GetField (FieldInfo fb)
+ {
+ return (FieldBase) fieldbuilders_to_fields [fb];
+ }
+
+ static Hashtable events;
+
+ static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
+ {
+ if (events == null)
+ events = new Hashtable ();
+
+ if (events.Contains (eb))
+ return false;
+
+ events.Add (eb, new Pair (add, remove));
+
+ return true;
+ }
+
+ static public MethodInfo GetAddMethod (EventInfo ei)
+ {
+ if (ei is MyEventBuilder) {
+ Pair pair = (Pair) events [ei];
+
+ return (MethodInfo) pair.First;
+ } else
+ return ei.GetAddMethod ();
+ }
+
+ static public MethodInfo GetRemoveMethod (EventInfo ei)
+ {
+ if (ei is MyEventBuilder) {
+ Pair pair = (Pair) events [ei];
+
+ return (MethodInfo) pair.Second;
+ } else
+ return ei.GetRemoveMethod ();
+ }
+
+ static Hashtable priv_fields_events;
+
+ static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
+ {
+ if (priv_fields_events == null)
+ priv_fields_events = new Hashtable ();
+
+ if (priv_fields_events.Contains (einfo))
+ return false;
+
+ priv_fields_events.Add (einfo, builder);
+
+ return true;
+ }
+
+ static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
+ {
+ if (priv_fields_events == null)
+ return null;
+ else
+ return (MemberInfo) priv_fields_events [ei];
+ }
+
+ static Hashtable properties;
+
+ static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
+ {
+ if (properties == null)
+ properties = new Hashtable ();
+
+ if (properties.Contains (pb))
+ return false;
+
+ properties.Add (pb, new Pair (get, set));
+
+ return true;
+ }
+
+ static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
+ MethodBase set, Type[] args)
+ {
+ if (!RegisterProperty (pb, get,set))
+ return false;
+
+ indexer_arguments.Add (pb, args);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Given an array of interface types, expand and eliminate repeated ocurrences
+ /// of an interface.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
+ /// be IA, IB, IC.
+ /// </remarks>
+ public static Type [] ExpandInterfaces (Type [] base_interfaces)
+ {
+ ArrayList new_ifaces = new ArrayList ();
+
+ foreach (Type iface in base_interfaces){
+ if (!new_ifaces.Contains (iface))
+ new_ifaces.Add (iface);
+
+ Type [] implementing = TypeManager.GetInterfaces (iface);
+
+ foreach (Type imp in implementing){
+ if (!new_ifaces.Contains (imp))
+ new_ifaces.Add (imp);
+ }
+ }
+ Type [] ret = new Type [new_ifaces.Count];
+ new_ifaces.CopyTo (ret, 0);
+ return ret;
+ }
+
+ /// <summary>
+ /// This function returns the interfaces in the type `t'. Works with
+ /// both types and TypeBuilders.
+ /// </summary>
+ public static Type [] GetInterfaces (Type t)
+ {
+ //
+ // The reason for catching the Array case is that Reflection.Emit
+ // will not return a TypeBuilder for Array types of TypeBuilder types,
+ // but will still throw an exception if we try to call GetInterfaces
+ // on the type.
+ //
+ // Since the array interfaces are always constant, we return those for
+ // the System.Array
+ //
+
+ if (t.IsArray)
+ t = TypeManager.array_type;
+
+ if (t is TypeBuilder){
+ Type [] parent_ifaces;
+
+ if (t.BaseType == null)
+ parent_ifaces = NoTypes;
+ else
+ parent_ifaces = GetInterfaces (t.BaseType);
+ Type [] type_ifaces = (Type []) builder_to_ifaces [t];
+ if (type_ifaces == null)
+ type_ifaces = NoTypes;
+
+ int parent_count = parent_ifaces.Length;
+ Type [] result = new Type [parent_count + type_ifaces.Length];
+ parent_ifaces.CopyTo (result, 0);
+ type_ifaces.CopyTo (result, parent_count);
+
+ return result;
+ } else
+ return t.GetInterfaces ();
+ }
+
+ /// <remarks>
+ /// The following is used to check if a given type implements an interface.
+ /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
+ /// </remarks>
+ public static bool ImplementsInterface (Type t, Type iface)
+ {
+ Type [] interfaces;
+
+ //
+ // FIXME OPTIMIZATION:
+ // as soon as we hit a non-TypeBuiler in the interface
+ // chain, we could return, as the `Type.GetInterfaces'
+ // will return all the interfaces implement by the type
+ // or its parents.
+ //
+ do {
+ interfaces = GetInterfaces (t);
+
+ if (interfaces != null){
+ foreach (Type i in interfaces){
+ if (i == iface)
+ return true;
+ }
+ }
+
+ t = t.BaseType;
+ } while (t != null);
+
+ return false;
+ }
+
+ // This is a custom version of Convert.ChangeType() which works
+ // with the TypeBuilder defined types when compiling corlib.
+ public static object ChangeType (object value, Type conversionType, out bool error)
+ {
+ if (!(value is IConvertible)){
+ error = true;
+ return null;
+ }
+
+ IConvertible convertValue = (IConvertible) value;
+ CultureInfo ci = CultureInfo.CurrentCulture;
+ NumberFormatInfo provider = ci.NumberFormat;
+
+ //
+ // We must use Type.Equals() here since `conversionType' is
+ // the TypeBuilder created version of a system type and not
+ // the system type itself. You cannot use Type.GetTypeCode()
+ // on such a type - it'd always return TypeCode.Object.
+ //
+ error = false;
+ try {
+ if (conversionType.Equals (typeof (Boolean)))
+ return (object)(convertValue.ToBoolean (provider));
+ else if (conversionType.Equals (typeof (Byte)))
+ return (object)(convertValue.ToByte (provider));
+ else if (conversionType.Equals (typeof (Char)))
+ return (object)(convertValue.ToChar (provider));
+ else if (conversionType.Equals (typeof (DateTime)))
+ return (object)(convertValue.ToDateTime (provider));
+ else if (conversionType.Equals (typeof (Decimal)))
+ return (object)(convertValue.ToDecimal (provider));
+ else if (conversionType.Equals (typeof (Double)))
+ return (object)(convertValue.ToDouble (provider));
+ else if (conversionType.Equals (typeof (Int16)))
+ return (object)(convertValue.ToInt16 (provider));
+ else if (conversionType.Equals (typeof (Int32)))
+ return (object)(convertValue.ToInt32 (provider));
+ else if (conversionType.Equals (typeof (Int64)))
+ return (object)(convertValue.ToInt64 (provider));
+ else if (conversionType.Equals (typeof (SByte)))
+ return (object)(convertValue.ToSByte (provider));
+ else if (conversionType.Equals (typeof (Single)))
+ return (object)(convertValue.ToSingle (provider));
+ else if (conversionType.Equals (typeof (String)))
+ return (object)(convertValue.ToString (provider));
+ else if (conversionType.Equals (typeof (UInt16)))
+ return (object)(convertValue.ToUInt16 (provider));
+ else if (conversionType.Equals (typeof (UInt32)))
+ return (object)(convertValue.ToUInt32 (provider));
+ else if (conversionType.Equals (typeof (UInt64)))
+ return (object)(convertValue.ToUInt64 (provider));
+ else if (conversionType.Equals (typeof (Object)))
+ return (object)(value);
+ else
+ error = true;
+ } catch {
+ error = true;
+ }
+ return null;
+ }
+
+ //
+ // This is needed, because enumerations from assemblies
+ // do not report their underlyingtype, but they report
+ // themselves
+ //
+ public static Type EnumToUnderlying (Type t)
+ {
+ if (t == TypeManager.enum_type)
+ return t;
+
+ t = t.UnderlyingSystemType;
+ if (!TypeManager.IsEnumType (t))
+ return t;
+
+ if (t is TypeBuilder) {
+ // slow path needed to compile corlib
+ if (t == TypeManager.bool_type ||
+ t == TypeManager.byte_type ||
+ t == TypeManager.sbyte_type ||
+ t == TypeManager.char_type ||
+ t == TypeManager.short_type ||
+ t == TypeManager.ushort_type ||
+ t == TypeManager.int32_type ||
+ t == TypeManager.uint32_type ||
+ t == TypeManager.int64_type ||
+ t == TypeManager.uint64_type)
+ return t;
+ throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
+ }
+ TypeCode tc = Type.GetTypeCode (t);
+
+ switch (tc){
+ case TypeCode.Boolean:
+ return TypeManager.bool_type;
+ case TypeCode.Byte:
+ return TypeManager.byte_type;
+ case TypeCode.SByte:
+ return TypeManager.sbyte_type;
+ case TypeCode.Char:
+ return TypeManager.char_type;
+ case TypeCode.Int16:
+ return TypeManager.short_type;
+ case TypeCode.UInt16:
+ return TypeManager.ushort_type;
+ case TypeCode.Int32:
+ return TypeManager.int32_type;
+ case TypeCode.UInt32:
+ return TypeManager.uint32_type;
+ case TypeCode.Int64:
+ return TypeManager.int64_type;
+ case TypeCode.UInt64:
+ return TypeManager.uint64_type;
+ }
+ throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
+ }
+
+ //
+ // When compiling corlib and called with one of the core types, return
+ // the corresponding typebuilder for that type.
+ //
+ public static Type TypeToCoreType (Type t)
+ {
+ if (RootContext.StdLib || (t is TypeBuilder))
+ return t;
+
+ TypeCode tc = Type.GetTypeCode (t);
+
+ switch (tc){
+ case TypeCode.Boolean:
+ return TypeManager.bool_type;
+ case TypeCode.Byte:
+ return TypeManager.byte_type;
+ case TypeCode.SByte:
+ return TypeManager.sbyte_type;
+ case TypeCode.Char:
+ return TypeManager.char_type;
+ case TypeCode.Int16:
+ return TypeManager.short_type;
+ case TypeCode.UInt16:
+ return TypeManager.ushort_type;
+ case TypeCode.Int32:
+ return TypeManager.int32_type;
+ case TypeCode.UInt32:
+ return TypeManager.uint32_type;
+ case TypeCode.Int64:
+ return TypeManager.int64_type;
+ case TypeCode.UInt64:
+ return TypeManager.uint64_type;
+ case TypeCode.String:
+ return TypeManager.string_type;
+ default:
+ if (t == typeof (void))
+ return TypeManager.void_type;
+ if (t == typeof (object))
+ return TypeManager.object_type;
+ if (t == typeof (System.Type))
+ return TypeManager.type_type;
+ return t;
+ }
+ }
+
+ /// <summary>
+ /// Utility function that can be used to probe whether a type
+ /// is managed or not.
+ /// </summary>
+ public static bool VerifyUnManaged (Type t, Location loc)
+ {
+ if (t.IsValueType || t.IsPointer){
+ //
+ // FIXME: this is more complex, we actually need to
+ // make sure that the type does not contain any
+ // classes itself
+ //
+ return true;
+ }
+
+ if (!RootContext.StdLib && (t == TypeManager.decimal_type))
+ // We need this explicit check here to make it work when
+ // compiling corlib.
+ return true;
+
+ Report.Error (
+ 208, loc,
+ "Cannot take the address or size of a variable of a managed type ('" +
+ CSharpName (t) + "')");
+ return false;
+ }
+
+ /// <summary>
+ /// Returns the name of the indexer in a given type.
+ /// </summary>
+ /// <remarks>
+ /// The default is not always `Item'. The user can change this behaviour by
+ /// using the DefaultMemberAttribute in the class.
+ ///
+ /// For example, the String class indexer is named `Chars' not `Item'
+ /// </remarks>
+ public static string IndexerPropertyName (Type t)
+ {
+ if (t is TypeBuilder) {
+ if (t.IsInterface) {
+ Interface i = LookupInterface (t);
+
+ if ((i == null) || (i.IndexerName == null))
+ return "Item";
+
+ return i.IndexerName;
+ } else {
+ TypeContainer tc = LookupTypeContainer (t);
+
+ if ((tc == null) || (tc.IndexerName == null))
+ return "Item";
+
+ return tc.IndexerName;
+ }
+ }
+
+ System.Attribute attr = System.Attribute.GetCustomAttribute (
+ t, TypeManager.default_member_type);
+ if (attr != null){
+ DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
+ return dma.MemberName;
+ }
+
+ return "Item";
+ }
+
+ public static void MakePinned (LocalBuilder builder)
+ {
+ //
+ // FIXME: Flag the "LocalBuilder" type as being
+ // pinned. Figure out API.
+ //
+ }
+
+
+ //
+ // Returns whether the array of memberinfos contains the given method
+ //
+ static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
+ {
+ Type [] new_args = TypeManager.GetArgumentTypes (new_method);
+
+ foreach (MethodBase method in array){
+ if (method.Name != new_method.Name)
+ continue;
+
+ Type [] old_args = TypeManager.GetArgumentTypes (method);
+ int old_count = old_args.Length;
+ int i;
+
+ if (new_args.Length != old_count)
+ continue;
+
+ for (i = 0; i < old_count; i++){
+ if (old_args [i] != new_args [i])
+ break;
+ }
+ if (i != old_count)
+ continue;
+
+ return true;
+ }
+ return false;
+ }
+
+ //
+ // We copy methods from `new_members' into `target_list' if the signature
+ // for the method from in the new list does not exist in the target_list
+ //
+ // The name is assumed to be the same.
+ //
+ public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
+ {
+ if (target_list == null){
+ target_list = new ArrayList ();
+
+ foreach (MemberInfo mi in new_members){
+ if (mi is MethodBase)
+ target_list.Add (mi);
+ }
+ return target_list;
+ }
+
+ MemberInfo [] target_array = new MemberInfo [target_list.Count];
+ target_list.CopyTo (target_array, 0);
+
+ foreach (MemberInfo mi in new_members){
+ MethodBase new_method = (MethodBase) mi;
+
+ if (!ArrayContainsMethod (target_array, new_method))
+ target_list.Add (new_method);
+ }
+ return target_list;
+ }
+
+ [Flags]
+ public enum MethodFlags {
+ IsObsolete = 1,
+ IsObsoleteError = 2,
+ ShouldIgnore = 3
+ }
+
+ //
+ // Returns the TypeManager.MethodFlags for this method.
+ // This emits an error 619 / warning 618 if the method is obsolete.
+ // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
+ //
+ static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
+ {
+ MethodFlags flags = 0;
+
+ if (mb.DeclaringType is TypeBuilder){
+ MethodData method = (MethodData) builder_to_method [mb];
+ if (method == null) {
+ // FIXME: implement Obsolete attribute on Property,
+ // Indexer and Event.
+ return 0;
+ }
+
+ return method.GetMethodFlags (loc);
+ }
+
+ object [] attrs = mb.GetCustomAttributes (true);
+ foreach (object ta in attrs){
+ if (!(ta is System.Attribute)){
+ Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
+ continue;
+ }
+ System.Attribute a = (System.Attribute) ta;
+ if (a.TypeId == TypeManager.obsolete_attribute_type){
+ ObsoleteAttribute oa = (ObsoleteAttribute) a;
+
+ string method_desc = TypeManager.CSharpSignature (mb);
+
+ if (oa.IsError) {
+ Report.Error (619, loc, "Method `" + method_desc +
+ "' is obsolete: `" + oa.Message + "'");
+ return MethodFlags.IsObsoleteError;
+ } else
+ Report.Warning (618, loc, "Method `" + method_desc +
+ "' is obsolete: `" + oa.Message + "'");
+
+ flags |= MethodFlags.IsObsolete;
+
+ continue;
+ }
+
+ //
+ // Skip over conditional code.
+ //
+ if (a.TypeId == TypeManager.conditional_attribute_type){
+ ConditionalAttribute ca = (ConditionalAttribute) a;
+
+ if (RootContext.AllDefines [ca.ConditionString] == null)
+ flags |= MethodFlags.ShouldIgnore;
+ }
+ }
+
+ return flags;
+ }
+
+#region MemberLookup implementation
+
+ //
+ // Name of the member
+ //
+ static string closure_name;
+
+ //
+ // Whether we allow private members in the result (since FindMembers
+ // uses NonPublic for both protected and private), we need to distinguish.
+ //
+ static bool closure_private_ok;
+
+ //
+ // Who is invoking us and which type is being queried currently.
+ //
+ static Type closure_invocation_type;
+ static Type closure_queried_type;
+ static Type closure_qualifier_type;
+
+ //
+ // The assembly that defines the type is that is calling us
+ //
+ static Assembly closure_invocation_assembly;
+
+ static internal bool FilterNone (MemberInfo m, object filter_criteria)
+ {
+ return true;
+ }
+
+ //
+ // This filter filters by name + whether it is ok to include private
+ // members in the search
+ //
+ static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
+ {
+ //
+ // Hack: we know that the filter criteria will always be in the `closure'
+ // fields.
+ //
+
+ if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
+ return false;
+
+ if (((closure_qualifier_type == null) || (closure_qualifier_type == closure_invocation_type)) &&
+ (m.DeclaringType == closure_invocation_type))
+ return true;
+
+ //
+ // Ugly: we need to find out the type of `m', and depending
+ // on this, tell whether we accept or not
+ //
+ if (m is MethodBase){
+ MethodBase mb = (MethodBase) m;
+ MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
+
+ if (ma == MethodAttributes.Private)
+ return closure_private_ok || (closure_invocation_type == m.DeclaringType) ||
+ IsNestedChildOf (closure_invocation_type, m.DeclaringType);
+
+ //
+ // FamAndAssem requires that we not only derivate, but we are on the
+ // same assembly.
+ //
+ if (ma == MethodAttributes.FamANDAssem){
+ if (closure_invocation_assembly != mb.DeclaringType.Assembly)
+ return false;
+ }
+
+ // Assembly and FamORAssem succeed if we're in the same assembly.
+ if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
+ if (closure_invocation_assembly == mb.DeclaringType.Assembly)
+ return true;
+ }
+
+ // We already know that we aren't in the same assembly.
+ if (ma == MethodAttributes.Assembly)
+ return false;
+
+ // Family and FamANDAssem require that we derive.
+ if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
+ if (closure_invocation_type == null)
+ return false;
+
+ if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
+ return false;
+
+ // 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 (!mb.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
+ (closure_qualifier_type != null) &&
+ closure_invocation_type.IsSubclassOf (closure_qualifier_type))
+ return false;
+
+ return true;
+ }
+
+ // Public.
+ return true;
+ }
+
+ if (m is FieldInfo){
+ FieldInfo fi = (FieldInfo) m;
+ FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
+
+ if (fa == FieldAttributes.Private)
+ return closure_private_ok || (closure_invocation_type == m.DeclaringType) ||
+ IsNestedChildOf (closure_invocation_type, m.DeclaringType);
+
+ //
+ // FamAndAssem requires that we not only derivate, but we are on the
+ // same assembly.
+ //
+ if (fa == FieldAttributes.FamANDAssem){
+ if (closure_invocation_assembly != fi.DeclaringType.Assembly)
+ return false;
+ }
+
+ // Assembly and FamORAssem succeed if we're in the same assembly.
+ if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
+ if (closure_invocation_assembly == fi.DeclaringType.Assembly)
+ return true;
+ }
+
+ // We already know that we aren't in the same assembly.
+ if (fa == FieldAttributes.Assembly)
+ return false;
+
+ // Family and FamANDAssem require that we derive.
+ if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
+ if (closure_invocation_type == null)
+ return false;
+
+ if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
+ return false;
+
+ // 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 (!fi.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
+ (closure_qualifier_type != null) &&
+ closure_invocation_type.IsSubclassOf (closure_qualifier_type))
+ return false;
+
+ return true;
+ }
+
+ // Public.
+ return true;
+ }
+
+ //
+ // EventInfos and PropertyInfos, return true because they lack permission
+ // informaiton, so we need to check later on the methods.
+ //
+ return true;
+ }
+
+ static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
+ static MemberFilter FilterNone_delegate = new MemberFilter (FilterNone);
+
+ //
+ // Looks up a member called `name' in the `queried_type'. This lookup
+ // is done by code that is contained in the definition for `invocation_type'
+ // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
+ //
+ // `invocation_type' is used to check whether we're allowed to access the requested
+ // member wrt its protection level.
+ //
+ // When called from MemberAccess, `qualifier_type' is the type which is used to access
+ // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
+ // is B and qualifier_type is A). This is used to do the CS1540 check.
+ //
+ // When resolving a SimpleName, `qualifier_type' is null.
+ //
+ // The `qualifier_type' is used for the CS1540 check; it's normally either null or
+ // the same than `queried_type' - except when we're being called from BaseAccess;
+ // in this case, `invocation_type' is the current type and `queried_type' the base
+ // type, so this'd normally trigger a CS1540.
+ //
+ // The binding flags are `bf' and the kind of members being looked up are `mt'
+ //
+ // The return value always includes private members which code in `invocation_type'
+ // is allowed to access (using the specified `qualifier_type' if given); only use
+ // BindingFlags.NonPublic to bypass the permission check.
+ //
+ // Returns an array of a single element for everything but Methods/Constructors
+ // that might return multiple matches.
+ //
+ public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
+ Type queried_type, MemberTypes mt,
+ BindingFlags original_bf, string name)
+ {
+ Timer.StartTimer (TimerType.MemberLookup);
+
+ MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
+ queried_type, mt, original_bf, name);
+
+ Timer.StopTimer (TimerType.MemberLookup);
+
+ return retval;
+ }
+
+ static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
+ Type queried_type, MemberTypes mt,
+ BindingFlags original_bf, string name)
+ {
+ BindingFlags bf = original_bf;
+
+ ArrayList method_list = null;
+ Type current_type = queried_type;
+ bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
+ bool skip_iface_check = true, used_cache = false;
+ bool always_ok_flag = false;
+
+ closure_name = name;
+ closure_invocation_type = invocation_type;
+ closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
+ closure_qualifier_type = qualifier_type;
+
+ //
+ // If we are a nested class, we always have access to our container
+ // type names
+ //
+ if (invocation_type != null){
+ string invocation_name = invocation_type.FullName;
+ if (invocation_name.IndexOf ('+') != -1){
+ string container = queried_type.FullName + "+";
+ int container_length = container.Length;
+
+ if (invocation_name.Length > container_length){
+ string shared = invocation_name.Substring (0, container_length);
+
+ if (shared == container)
+ always_ok_flag = true;
+ }
+ }
+ }
+
+ do {
+ MemberList list;
+
+ //
+ // `NonPublic' is lame, because it includes both protected and
+ // private methods, so we need to control this behavior by
+ // explicitly tracking if a private method is ok or not.
+ //
+ // The possible cases are:
+ // public, private and protected (internal does not come into the
+ // equation)
+ //
+ if ((invocation_type != null) &&
+ ((invocation_type == current_type) ||
+ IsNestedChildOf (invocation_type, current_type)) ||
+ always_ok_flag)
+ bf = original_bf | BindingFlags.NonPublic;
+ else
+ bf = original_bf;
+
+ closure_private_ok = (original_bf & BindingFlags.NonPublic) != 0;
+ closure_queried_type = current_type;
+
+ Timer.StopTimer (TimerType.MemberLookup);
+
+ list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
+
+ Timer.StartTimer (TimerType.MemberLookup);
+
+ //
+ // When queried for an interface type, the cache will automatically check all
+ // inherited members, so we don't need to do this here. However, this only
+ // works if we already used the cache in the first iteration of this loop.
+ //
+ // If we used the cache in any further iteration, we can still terminate the
+ // loop since the cache always looks in all parent classes.
+ //
+
+ if (used_cache)
+ searching = false;
+ else
+ skip_iface_check = false;
+
+ if (current_type == TypeManager.object_type)
+ searching = false;
+ else {
+ current_type = current_type.BaseType;
+
+ //
+ // This happens with interfaces, they have a null
+ // basetype. Look members up in the Object class.
+ //
+ if (current_type == null)
+ current_type = TypeManager.object_type;
+ }
+
+ if (list.Count == 0)
+ continue;
+
+ //
+ // Events and types are returned by both `static' and `instance'
+ // searches, which means that our above FindMembers will
+ // return two copies of the same.
+ //
+ if (list.Count == 1 && !(list [0] is MethodBase)){
+ return (MemberInfo []) list;
+ }
+
+ //
+ // Multiple properties: we query those just to find out the indexer
+ // name
+ //
+ if (list [0] is PropertyInfo)
+ return (MemberInfo []) list;
+
+ //
+ // We found an event: the cache lookup returns both the event and
+ // its private field.
+ //
+ if (list [0] is EventInfo) {
+ if ((list.Count == 2) && (list [1] is FieldInfo))
+ return new MemberInfo [] { list [0] };
+
+ // Oooops
+ return null;
+ }
+
+ //
+ // We found methods, turn the search into "method scan"
+ // mode.
+ //
+
+ method_list = CopyNewMethods (method_list, list);
+ mt &= (MemberTypes.Method | MemberTypes.Constructor);
+ } while (searching);
+
+ if (method_list != null && method_list.Count > 0) {
+ return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
+ }
+ //
+ // This happens if we already used the cache in the first iteration, in this case
+ // the cache already looked in all interfaces.
+ //
+ if (skip_iface_check)
+ return null;
+
+ //
+ // Interfaces do not list members they inherit, so we have to
+ // scan those.
+ //
+ if (!queried_type.IsInterface)
+ return null;
+
+ if (queried_type.IsArray)
+ queried_type = TypeManager.array_type;
+
+ Type [] ifaces = GetInterfaces (queried_type);
+ if (ifaces == null)
+ return null;
+
+ foreach (Type itype in ifaces){
+ MemberInfo [] x;
+
+ x = MemberLookup (null, null, itype, mt, bf, name);
+ if (x != null)
+ return x;
+ }
+
+ return null;
+ }
+
+ //
+ // This is used to extract properties and event declarations from a type
+ //
+ static MemberInfo [] SpecialContainerLookup (Type t, bool is_static)
+ {
+ BindingFlags bf = BindingFlags.DeclaredOnly | (is_static ? BindingFlags.Static : BindingFlags.Instance);
+
+ bf |= BindingFlags.Public | BindingFlags.NonPublic;
+
+ if (t is TypeBuilder) {
+ DeclSpace decl = (DeclSpace) builder_to_declspace [t];
+
+ return (MemberInfo []) decl.FindMembers (
+ MemberTypes.Property | MemberTypes.Event,
+ bf, FilterNone_delegate, null);
+ } else {
+ return t.FindMembers (MemberTypes.Property | MemberTypes.Event,
+ bf, FilterNone_delegate, null);
+
+ }
+ }
+
+ public static bool IsSpecialMethod (MethodBase mb)
+ {
+ Type t = mb.DeclaringType;
+
+ MemberInfo [] matches = TypeManager.SpecialContainerLookup (t, mb.IsStatic);
+ if (matches == null)
+ return false;
+
+ foreach (MemberInfo mi in matches){
+ if (mi is PropertyBuilder){
+ Pair p = (Pair) properties [mi];
+
+ if (p.First == mb || p.Second == mb)
+ return true;
+ } else if (mi is PropertyInfo){
+ MethodInfo [] methods = ((PropertyInfo) mi).GetAccessors (true);
+
+ foreach (MethodInfo m in methods){
+ if (m == mb)
+ return true;
+ }
+ } else if (mi is MyEventBuilder){
+ Pair p = (Pair) events [mi];
+
+ if (p.First == mb || p.Second == mb)
+ return true;
+ } else if (mi is EventInfo){
+ EventInfo ei = ((EventInfo) mi);
+
+ if (ei.GetAddMethod (true) == mb)
+ return true;
+
+ if (ei.GetRemoveMethod (true) == mb)
+ return true;
+
+ if (ei.GetRaiseMethod (true) == mb)
+ return true;
+ }
+ }
+
+ //
+ // Now check if it is an operator method
+ //
+ string s = mb.Name;
+
+ if (s.StartsWith ("op_")){
+ foreach (string name in Unary.oper_names){
+ if (s == name)
+ return true;
+ }
+
+ foreach (string name in Binary.oper_names){
+ if (s == name)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+#endregion
+
+}
+
+/// <summary>
+/// There is exactly one instance of this class per type.
+/// </summary>
+public sealed class TypeHandle : IMemberContainer {
+ public readonly TypeHandle BaseType;
+
+ readonly int id = ++next_id;
+ static int next_id = 0;
+
+ /// <summary>
+ /// Lookup a TypeHandle instance for the given type. If the type doesn't have
+ /// a TypeHandle yet, a new instance of it is created. This static method
+ /// ensures that we'll only have one TypeHandle instance per type.
+ /// </summary>
+ public static TypeHandle GetTypeHandle (Type t)
+ {
+ TypeHandle handle = (TypeHandle) type_hash [t];
+ if (handle != null)
+ return handle;
+
+ handle = new TypeHandle (t);
+ type_hash.Add (t, handle);
+ return handle;
+ }
+
+ /// <summary>
+ /// Returns the TypeHandle for TypeManager.object_type.
+ /// </summary>
+ public static IMemberContainer ObjectType {
+ get {
+ if (object_type != null)
+ return object_type;
+
+ object_type = GetTypeHandle (TypeManager.object_type);
+
+ return object_type;
+ }
+ }
+
+ /// <summary>
+ /// Returns the TypeHandle for TypeManager.array_type.
+ /// </summary>
+ public static IMemberContainer ArrayType {
+ get {
+ if (array_type != null)
+ return array_type;
+
+ array_type = GetTypeHandle (TypeManager.array_type);
+
+ return array_type;
+ }
+ }
+
+ private static PtrHashtable type_hash = new PtrHashtable ();
+
+ private static TypeHandle object_type = null;
+ private static TypeHandle array_type = null;
+
+ private Type type;
+ private bool is_interface;
+ private MemberCache member_cache;
+
+ private TypeHandle (Type type)
+ {
+ this.type = type;
+ if (type.BaseType != null)
+ BaseType = GetTypeHandle (type.BaseType);
+ else if ((type != TypeManager.object_type) && (type != typeof (object)))
+ is_interface = true;
+ this.member_cache = new MemberCache (this);
+ }
+
+ // IMemberContainer methods
+
+ public string Name {
+ get {
+ return type.FullName;
+ }
+ }
+
+ public Type Type {
+ get {
+ return type;
+ }
+ }
+
+ public IMemberContainer Parent {
+ get {
+ return BaseType;
+ }
+ }
+
+ public bool IsInterface {
+ get {
+ return is_interface;
+ }
+ }
+
+ public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
+ {
+ if (mt == MemberTypes.Event)
+ return new MemberList (type.GetEvents (bf | BindingFlags.DeclaredOnly));
+ else
+ return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
+ null, null));
+ }
+
+ // IMemberFinder methods
+
+ public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
+ MemberFilter filter, object criteria)
+ {
+ return member_cache.FindMembers (mt, bf, name, filter, criteria);
+ }
+
+ public MemberCache MemberCache {
+ get {
+ return member_cache;
+ }
+ }
+
+ public override string ToString ()
+ {
+ if (BaseType != null)
+ return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
+ else
+ return "TypeHandle (" + id + "," + Name + ")";
+ }
+}
+
+}