Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs/mbas
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/mbas')
-rw-r--r--mcs/mbas/.cvsignore14
-rw-r--r--mcs/mbas/AssemblyInfo.cs88
-rw-r--r--mcs/mbas/ChangeLog126
-rw-r--r--mcs/mbas/assign.cs492
-rw-r--r--mcs/mbas/attribute.cs910
-rw-r--r--mcs/mbas/cfold.cs1088
-rw-r--r--mcs/mbas/class.cs4835
-rw-r--r--mcs/mbas/codegen.cs683
-rw-r--r--mcs/mbas/const.cs232
-rw-r--r--mcs/mbas/constant.cs974
-rw-r--r--mcs/mbas/decl.cs1233
-rw-r--r--mcs/mbas/delegate.cs771
-rw-r--r--mcs/mbas/driver.cs661
-rw-r--r--mcs/mbas/ecore.cs4387
-rw-r--r--mcs/mbas/enum.cs613
-rw-r--r--mcs/mbas/expression.cs7119
-rw-r--r--mcs/mbas/genericparser.cs336
-rw-r--r--mcs/mbas/interface.cs1061
-rw-r--r--mcs/mbas/literal.cs187
-rw-r--r--mcs/mbas/location.cs154
-rw-r--r--mcs/mbas/makefile50
-rw-r--r--mcs/mbas/makefile.gnu60
-rw-r--r--mcs/mbas/mb-parser.jay2954
-rw-r--r--mcs/mbas/mb-tokenizer.cs888
-rw-r--r--mcs/mbas/mbas.csproj264
-rw-r--r--mcs/mbas/mbas.icobin0 -> 2686 bytes
-rw-r--r--mcs/mbas/mbas.sln33
-rw-r--r--mcs/mbas/modifiers.cs241
-rw-r--r--mcs/mbas/module.cs74
-rw-r--r--mcs/mbas/namespace.cs179
-rw-r--r--mcs/mbas/parameter.cs537
-rw-r--r--mcs/mbas/pending.cs514
-rw-r--r--mcs/mbas/report.cs359
-rw-r--r--mcs/mbas/rootcontext.cs840
-rw-r--r--mcs/mbas/statement.cs5416
-rw-r--r--mcs/mbas/statementCollection.cs166
-rw-r--r--mcs/mbas/support.cs258
-rw-r--r--mcs/mbas/testmbas/.cvsignore6
-rw-r--r--mcs/mbas/testmbas/AssemblyInfo.vb31
-rw-r--r--mcs/mbas/testmbas/WriteOK.vb19
-rw-r--r--mcs/mbas/testmbas/ctest.vb33
-rw-r--r--mcs/mbas/testmbas/filelist1
-rw-r--r--mcs/mbas/testmbas/gtk.vb19
-rw-r--r--mcs/mbas/testmbas/test.vb43
-rw-r--r--mcs/mbas/testmbas/test2.vb14
-rw-r--r--mcs/mbas/testmbas/test3.vb51
-rw-r--r--mcs/mbas/testmbas/test4.vb16
-rw-r--r--mcs/mbas/testmbas/test5.vb32
-rw-r--r--mcs/mbas/testmbas/testm.vb11
-rw-r--r--mcs/mbas/tree.cs109
-rw-r--r--mcs/mbas/typemanager.cs2355
51 files changed, 41537 insertions, 0 deletions
diff --git a/mcs/mbas/.cvsignore b/mcs/mbas/.cvsignore
new file mode 100644
index 00000000000..632875e2664
--- /dev/null
+++ b/mcs/mbas/.cvsignore
@@ -0,0 +1,14 @@
+mbas.pdb
+mbas.exe
+mb-parser.cs
+y.output
+*.pdb
+mbas.csproj.user
+mbas.suo
+D/bin
+D/obj
+D/bin/*
+D/obj/*
+update.bat
+mcs.*.log
+*.dll
diff --git a/mcs/mbas/AssemblyInfo.cs b/mcs/mbas/AssemblyInfo.cs
new file mode 100644
index 00000000000..de3cf1c56cc
--- /dev/null
+++ b/mcs/mbas/AssemblyInfo.cs
@@ -0,0 +1,88 @@
+// MonoBASIC Compiler, this is a compiler for the MonoBASIC language, which is a superset of Visual Basic.NET
+// Copyright (C) 2002 Rafael Teixeira
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("MonoBASIC Compiler")]
+[assembly: AssemblyDescription("This is a compiler for the MonoBASIC language, \nwhich is a superset of Visual Basic.NET")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("(c)2002 Rafael Teixeira")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: Mono.Author("Ravi Pratap, Miguel de Icaza, Rafael Teixeira, Marco Ridoni")]
+//[assembly: Mono.Author("Miguel de Icaza")]
+//[assembly: Mono.Author("Rafael Teixeira")]
+
+[assembly: Mono.About("Distributed under the GPL")]
+
+[assembly: Mono.UsageComplement("SOURCE-FILES")]
+
+//[assembly: Mono.LicensingWith(Mono.GetOptions.Licenses.GPL)]
+//[assembly: Mono.ForMoreInformation("http://www.go-mono.com")]
+//[assembly: Mono.UsageClause("mbas [options] source-files")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/mcs/mbas/ChangeLog b/mcs/mbas/ChangeLog
new file mode 100644
index 00000000000..9e49a98b702
--- /dev/null
+++ b/mcs/mbas/ChangeLog
@@ -0,0 +1,126 @@
+2003-01-13 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * added cleanup method to tokenizer as needed but modifications made in jay
+
+2003-01-12 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * changed test target in makefile work
+ * corrected authors list to include Marco
+
+2002-10-23 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged many sources from mcs/mcs, to resync
+
+2002-10-20 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * using Mono.GetOptions preliminar support for response files,
+ changed the makefile target 'test' for use o response file testmbas/filelist
+
+2002-10-20 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged many sources from mcs/mcs, to resync
+
+2002-10-05 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged many sources from mcs/mcs, to resync
+
+2002-08-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged many sources from mcs/mcs, to resync
+
+2002-09-03 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * integrated new version of Mono.GetOptions (reflection/attributes-based)
+
+2002-08-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged expression.cs from mcs/mcs, to resync
+
+2002-08-29 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged assign.cs, attribute.cs, class.cs, codegen.cs, const.cs, decl.cs, delegate.cs, ecore.cs, enum.cs,
+ expression.cs, interface.cs, pending.cs, report.cs, rootcontext.cs, statement.cs, support.cs and
+ typemanager.cs from mcs/mcs, to resync
+
+2002-08-06 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * added "test" target to makefile
+ * merged assign.cs, attribute.cs, cfold.cs, class.cs, codegen.cs, const.cs, constant.cs,
+ decl.cs, delegate.cs, ecore.cs, enum.cs, expression.cs, interface.cs, modifiers.cs, parameter.cs,
+ pending.cs, report.cs, rootcontext.cs, statement.cs, support.cs and typemanager.cs from mcs/mcs, to resync
+
+2002-07-14 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged assign.cs, class.cs, ecore.cs, expression.cs, statement.cs and typemanager from mcs/mcs, to resync
+
+2002-07-09 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged attribute.cs, ecore.cs, namespace.cs and statement.cs from mcs/mcs, to resync
+
+2002-07-06 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged attribute.cs, class.cs, codegen.cs, ecore.cs, expression.cs,
+ modifiers.cs, namespace.cs, report.cs, rootcontext.cs, statement.cs and typemanager.cs from mcs/mcs, to resync
+ * changed driver.cs to follow mcs lead on error/warning counting and reporting
+
+2002-06-23 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged attribute.cs, class.cs, ecore.cs, rootcontext.cs, support.cs and typemanager.cs from mcs/mcs, to resync
+ * makefile makes csc reference a copy of Mono.GetOptions.dll (mbas.sln now compiles to mbas dir instead of mbas/bin/Debug)
+
+2002-06-21 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged attribute.cs, class.cs, interface.cs, expression.cs, ecore.cs,
+ modifiers.cs, rootcontext.cs, statement.cs and typemanager.cs from mcs/mcs, to resync
+ * added pending.cs from mcs/mcs, to resync
+
+2002-06-15 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged assign.cs, attribute.cs, enum.cs and namespace.cs from mcs/mcs, to resync
+ * namespace.cs needed some fixing, because CSharpParser isnŽt available
+
+2002-06-15 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged delegate.cs, ecore.cs, typemanager.cs and rootcontext.cs from mcs/mcs, to resolve expression.cs blues
+
+2002-06-15 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * oops merged expression.cs from mcs/mcs is breaking my make
+ * driver.cs, assemblyinfo.cs wasnŽt ready for prime time (offending lines were commented out)
+
+2002-06-15 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged expression.cs from mcs/mcs
+
+2002-06-12 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * corrected Module.TypeAttr property getter in module.cs
+
+2002-06-12 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged typemanager.cs from mcs/mcs
+
+2002-06-10 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged expression.cs and interface.cs from mcs/mcs
+
+2002-06-09 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged const.cs, enum.cs, expression.cs and typemanager.cs from mcs/mcs
+ * comments on module.cs
+
+2002-06-07 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged class.cs, attribute.cs from mcs/mcs
+
+2002-06-07 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged class.cs, enum.cs, expression.cs, interface.cs, rootcontext.cs and typemanager.cs from mcs/mcs
+ * added module.cs (class Mono.MonoBASIC.Module - derived from Mono.CSharp.Class)
+ * added System.XML and Microsoft.VisualBasic to the default config (driver.cs)
+
+2002-06-07 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged class.cs and ecore.cs from mcs/mcs
+
+2002-06-02 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * copied methods MakeName and CheckDef from mcs\cs-parser.jay to GenericParser.cs
+ where they are inherited by mb-parser.jay/cs
+ * put some code on the Module rule in mb-parser.jay to at least generate a class in the assembly,
+ if I jump over the entry-point check code, while debugging
+
+2002-05-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * class Mono.MonoBASIC.Tokenizer now handles
+ - all valid line-terminators (CR, LF, CRLF, LS and PS)
+ - escaped identifiers (like [Integer])
+ - old-fashioned comments syntax (REM Blah-Blah)
+
+2002-05-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * modified mbas.ico to be a small version of monoŽs logo (see mcs\MonoIcon.png)
+
+2002-05-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * squashed some reduce/reduce conflicts out of mb-parser.jay
+
+2002-05-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+ * merged codegen.cs from mcs
+ * altered Driver.cs to work with new codegen.cs
+
+2002-05-27 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
+
+ * merged all I could from mcs source files into mbas
+ * added VS.NET Solution and Project Files for mbas
+ * added icon file and a vb-sources-filled testmbas directory
+ * started this ChangeLog
diff --git a/mcs/mbas/assign.cs b/mcs/mbas/assign.cs
new file mode 100644
index 00000000000..225283189fd
--- /dev/null
+++ b/mcs/mbas/assign.cs
@@ -0,0 +1,492 @@
+//
+// assign.cs: Assignments.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Martin Baulig (martin@gnome.org)
+//
+// (C) 2001, 2002 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;
+ }
+
+ 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 = new Assign ((Assign) source, 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)
+ 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 = ConvertImplicitRequired (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;
+
+ n.ValueTypeVariable = target;
+ return n;
+ }
+
+ 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.Error118 ("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 = ConvertExplicit (ec, source, target_type, loc);
+ if (source == null){
+ Error_CannotConvertImplicit (loc, source_type, target_type);
+ return null;
+ }
+
+ //
+ // 2. and the original right side is implicitly convertible to
+ // the type of target_type.
+ //
+ if (StandardConversionExists (a.original_source, target_type))
+ return this;
+
+ Error_CannotConvertImplicit (loc, a.original_source.Type, target_type);
+ return null;
+ }
+ }
+
+ source = ConvertImplicitRequired (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;
+ }
+
+ //
+ // 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);
+ }
+
+ 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 (is_statement)
+ am.EmitAssign (ec, temp_source);
+ else {
+ LocalTemporary tempo;
+
+ tempo = new LocalTemporary (ec, source.Type);
+
+ temp_source.Emit (ec);
+ tempo.Store (ec);
+ am.EmitAssign (ec, tempo);
+ tempo.Emit (ec);
+ tempo.Release (ec);
+ }
+
+ 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;
+ }
+
+ public Expression ResolveSource (EmitContext ec)
+ {
+ return original_source.Resolve (ec);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ target = target.ResolveLValue (ec, source);
+ if (target == null)
+ return null;
+
+ original_source = original_source.Resolve (ec);
+ if (original_source == 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);
+ }
+ }
+}
+
+
+
+
diff --git a/mcs/mbas/attribute.cs b/mcs/mbas/attribute.cs
new file mode 100644
index 00000000000..988c435b52f
--- /dev/null
+++ b/mcs/mbas/attribute.cs
@@ -0,0 +1,910 @@
+//
+// attribute.cs: Attribute Handler
+//
+// Author: 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.Diagnostics;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Mono.CSharp {
+
+ public class Attribute {
+ public readonly string Name;
+ public readonly ArrayList Arguments;
+
+ Location Location;
+
+ public Type Type;
+
+ //
+ // The following are only meaningful when the attribute
+ // being emitted is one of the builtin ones
+ //
+ AttributeTargets Targets;
+ bool AllowMultiple;
+ bool Inherited;
+
+ bool UsageAttr = false;
+
+ MethodImplOptions ImplOptions;
+ UnmanagedType UnmanagedType;
+ CustomAttributeBuilder cb;
+
+ public Attribute (string name, ArrayList args, Location loc)
+ {
+ Name = name;
+ Arguments = args;
+ Location = loc;
+ }
+
+ void Error_InvalidNamedArgument (string name)
+ {
+ Report.Error (617, Location, "'" + name + "' is not a valid named attribute " +
+ "argument. Named attribute arguments must be fields which are not " +
+ "readonly, static or const, or properties with a set accessor which "+
+ "are not static.");
+ }
+
+ void Error_AttributeArgumentNotValid ()
+ {
+ Report.Error (182, Location,
+ "An attribute argument must be a constant expression, typeof " +
+ "expression or array creation expression");
+ }
+
+ static void Error_AttributeConstructorMismatch (Location loc)
+ {
+ Report.Error (
+ -6, loc,
+ "Could not find a constructor for this argument list.");
+ }
+
+ private Type CheckAttributeType (EmitContext ec) {
+ Type t;
+ bool isattributeclass = true;
+
+ t = RootContext.LookupType (ec.DeclSpace, Name, true, Location);
+ if (t != null) {
+ isattributeclass = t.IsSubclassOf (TypeManager.attribute_type);
+ if (isattributeclass)
+ return t;
+ }
+ t = RootContext.LookupType (ec.DeclSpace, Name + "Attribute", true, Location);
+ if (t != null) {
+ if (t.IsSubclassOf (TypeManager.attribute_type))
+ return t;
+ }
+ if (!isattributeclass) {
+ Report.Error (616, Location, "'" + Name + "': is not an attribute class");
+ return null;
+ }
+ if (t != null) {
+ Report.Error (616, Location, "'" + Name + "Attribute': is not an attribute class");
+ return null;
+ }
+ Report.Error (
+ 246, Location, "Could not find attribute '" + Name + "' (are you" +
+ " missing a using directive or an assembly reference ?)");
+ return null;
+ }
+
+ public Type ResolveType (EmitContext ec)
+ {
+ Type = CheckAttributeType (ec);
+ return Type;
+ }
+
+
+ public CustomAttributeBuilder Resolve (EmitContext ec)
+ {
+ if (Type == null)
+ Type = CheckAttributeType (ec);
+ if (Type == null)
+ return null;
+
+ bool MethodImplAttr = false;
+ bool MarshalAsAttr = false;
+
+ UsageAttr = false;
+
+ if (Type == TypeManager.attribute_usage_type)
+ UsageAttr = true;
+ if (Type == TypeManager.methodimpl_attr_type)
+ MethodImplAttr = true;
+ if (Type == TypeManager.marshal_as_attr_type)
+ MarshalAsAttr = true;
+
+ // Now we extract the positional and named arguments
+
+ ArrayList pos_args = new ArrayList ();
+ ArrayList named_args = new ArrayList ();
+ int pos_arg_count = 0;
+
+ if (Arguments != null) {
+ pos_args = (ArrayList) Arguments [0];
+ if (pos_args != null)
+ pos_arg_count = pos_args.Count;
+ if (Arguments.Count > 1)
+ named_args = (ArrayList) Arguments [1];
+ }
+
+ object [] pos_values = new object [pos_arg_count];
+
+ //
+ // First process positional arguments
+ //
+
+ int i;
+ for (i = 0; i < pos_arg_count; i++) {
+ Argument a = (Argument) pos_args [i];
+ Expression e;
+
+ if (!a.Resolve (ec, Location))
+ return null;
+
+ e = a.Expr;
+
+ if (e is Constant) {
+ pos_values [i] = ((Constant) e).GetValue ();
+ } else if (e is TypeOf) {
+ pos_values [i] = ((TypeOf) e).TypeArg;
+ } else {
+ Error_AttributeArgumentNotValid ();
+ return null;
+ }
+
+ if (UsageAttr)
+ this.Targets = (AttributeTargets) pos_values [0];
+
+ if (MethodImplAttr)
+ this.ImplOptions = (MethodImplOptions) pos_values [0];
+
+ if (MarshalAsAttr)
+ this.UnmanagedType =
+ (System.Runtime.InteropServices.UnmanagedType) pos_values [0];
+ }
+
+ //
+ // Now process named arguments
+ //
+
+ ArrayList field_infos = new ArrayList ();
+ ArrayList prop_infos = new ArrayList ();
+ ArrayList field_values = new ArrayList ();
+ ArrayList prop_values = new ArrayList ();
+
+ for (i = 0; i < named_args.Count; i++) {
+ DictionaryEntry de = (DictionaryEntry) named_args [i];
+ string member_name = (string) de.Key;
+ Argument a = (Argument) de.Value;
+ Expression e;
+
+ if (!a.Resolve (ec, Location))
+ return null;
+
+ Expression member = Expression.MemberLookup (
+ ec, Type, member_name,
+ MemberTypes.Field | MemberTypes.Property,
+ BindingFlags.Public | BindingFlags.Instance,
+ Location);
+
+ if (member == null || !(member is PropertyExpr || member is FieldExpr)) {
+ Error_InvalidNamedArgument (member_name);
+ return null;
+ }
+
+ e = a.Expr;
+ if (member is PropertyExpr) {
+ PropertyExpr pe = (PropertyExpr) member;
+ PropertyInfo pi = pe.PropertyInfo;
+
+ if (!pi.CanWrite) {
+ Error_InvalidNamedArgument (member_name);
+ return null;
+ }
+
+ if (e is Constant) {
+ object o = ((Constant) e).GetValue ();
+ prop_values.Add (o);
+
+ if (UsageAttr) {
+ if (member_name == "AllowMultiple")
+ this.AllowMultiple = (bool) o;
+ if (member_name == "Inherited")
+ this.Inherited = (bool) o;
+ }
+
+ } else if (e is TypeOf) {
+ prop_values.Add (((TypeOf) e).TypeArg);
+ } else {
+ Error_AttributeArgumentNotValid ();
+ return null;
+ }
+
+ prop_infos.Add (pi);
+
+ } else if (member is FieldExpr) {
+ FieldExpr fe = (FieldExpr) member;
+ FieldInfo fi = fe.FieldInfo;
+
+ if (fi.IsInitOnly) {
+ Error_InvalidNamedArgument (member_name);
+ return null;
+ }
+
+ //
+ // Handle charset here, and set the TypeAttributes
+
+ if (e is Constant){
+ object value = ((Constant) e).GetValue ();
+
+ field_values.Add (value);
+ } else if (e is TypeOf) {
+ field_values.Add (((TypeOf) e).TypeArg);
+ } else {
+ Error_AttributeArgumentNotValid ();
+ return null;
+ }
+
+ field_infos.Add (fi);
+ }
+ }
+
+ Expression mg = Expression.MemberLookup (
+ ec, Type, ".ctor", MemberTypes.Constructor,
+ BindingFlags.Public | BindingFlags.Instance, Location);
+
+ if (mg == null) {
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ MethodBase constructor = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) mg, pos_args, Location);
+
+ if (constructor == null) {
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ //
+ // Now we perform some checks on the positional args as they
+ // cannot be null for a constructor which expects a parameter
+ // of type object
+ //
+
+ ParameterData pd = Invocation.GetParameterData (constructor);
+
+ for (int j = 0; j < pos_arg_count; ++j) {
+ Argument a = (Argument) pos_args [j];
+
+ if (a.Expr is NullLiteral && pd.ParameterType (j) == TypeManager.object_type) {
+ Error_AttributeArgumentNotValid ();
+ return null;
+ }
+ }
+
+ PropertyInfo [] prop_info_arr = new PropertyInfo [prop_infos.Count];
+ FieldInfo [] field_info_arr = new FieldInfo [field_infos.Count];
+ object [] field_values_arr = new object [field_values.Count];
+ object [] prop_values_arr = new object [prop_values.Count];
+
+ field_infos.CopyTo (field_info_arr, 0);
+ field_values.CopyTo (field_values_arr, 0);
+
+ prop_values.CopyTo (prop_values_arr, 0);
+ prop_infos.CopyTo (prop_info_arr, 0);
+
+ try {
+ cb = new CustomAttributeBuilder (
+ (ConstructorInfo) constructor, pos_values,
+ prop_info_arr, prop_values_arr,
+ field_info_arr, field_values_arr);
+
+ } catch (NullReferenceException) {
+ //
+ // Don't know what to do here
+ //
+ } catch {
+ //
+ // Sample:
+ // using System.ComponentModel;
+ // [DefaultValue (CollectionChangeAction.Add)]
+ // class X { static void Main () {} }
+ //
+ Report.Warning (
+ -23, Location,
+ "The compiler can not encode this attribute in .NET due to\n" +
+ "\ta bug in the .NET runtime. Try the Mono runtime");
+ }
+
+ return cb;
+ }
+
+ static string GetValidPlaces (Attribute attr)
+ {
+ StringBuilder sb = new StringBuilder ();
+ AttributeTargets targets = 0;
+
+ TypeContainer a = TypeManager.LookupAttr (attr.Type);
+
+ if (a == null) {
+
+ System.Attribute [] attrs = null;
+
+ try {
+ attrs = System.Attribute.GetCustomAttributes (attr.Type);
+
+ } catch {
+ Report.Error (-20, attr.Location, "Cannot find attribute type " + attr.Name +
+ " (maybe you forgot to set the usage using the" +
+ " AttributeUsage attribute ?).");
+ return null;
+ }
+
+ foreach (System.Attribute tmp in attrs)
+ if (tmp is AttributeUsageAttribute) {
+ targets = ((AttributeUsageAttribute) tmp).ValidOn;
+ break;
+ }
+ } else
+ targets = a.Targets;
+
+
+ if ((targets & AttributeTargets.Assembly) != 0)
+ sb.Append ("'assembly' ");
+
+ if ((targets & AttributeTargets.Class) != 0)
+ sb.Append ("'class' ");
+
+ if ((targets & AttributeTargets.Constructor) != 0)
+ sb.Append ("'constructor' ");
+
+ if ((targets & AttributeTargets.Delegate) != 0)
+ sb.Append ("'delegate' ");
+
+ if ((targets & AttributeTargets.Enum) != 0)
+ sb.Append ("'enum' ");
+
+ if ((targets & AttributeTargets.Event) != 0)
+ sb.Append ("'event' ");
+
+ if ((targets & AttributeTargets.Field) != 0)
+ sb.Append ("'field' ");
+
+ if ((targets & AttributeTargets.Interface) != 0)
+ sb.Append ("'interface' ");
+
+ if ((targets & AttributeTargets.Method) != 0)
+ sb.Append ("'method' ");
+
+ if ((targets & AttributeTargets.Module) != 0)
+ sb.Append ("'module' ");
+
+ if ((targets & AttributeTargets.Parameter) != 0)
+ sb.Append ("'parameter' ");
+
+ if ((targets & AttributeTargets.Property) != 0)
+ sb.Append ("'property' ");
+
+ if ((targets & AttributeTargets.ReturnValue) != 0)
+ sb.Append ("'return value' ");
+
+ if ((targets & AttributeTargets.Struct) != 0)
+ sb.Append ("'struct' ");
+
+ return sb.ToString ();
+
+ }
+
+ public static void Error_AttributeNotValidForElement (Attribute a, Location loc)
+ {
+ Report.Error (
+ 592, loc, "Attribute '" + a.Name +
+ "' is not valid on this declaration type. " +
+ "It is valid on " + GetValidPlaces (a) + "declarations only.");
+ }
+
+ public static bool CheckAttribute (Attribute a, object element)
+ {
+ TypeContainer attr = TypeManager.LookupAttr (a.Type);
+ AttributeTargets targets = 0;
+
+
+ if (attr == null) {
+
+ System.Attribute [] attrs = null;
+
+ try {
+ attrs = System.Attribute.GetCustomAttributes (a.Type);
+
+ } catch {
+ Report.Error (-20, a.Location, "Cannot find attribute type " + a.Name +
+ " (maybe you forgot to set the usage using the" +
+ " AttributeUsage attribute ?).");
+ return false;
+ }
+
+ foreach (System.Attribute tmp in attrs)
+ if (tmp is AttributeUsageAttribute)
+ targets = ((AttributeUsageAttribute) tmp).ValidOn;
+ } else
+ targets = attr.Targets;
+
+ if (element is Class) {
+ if ((targets & AttributeTargets.Class) != 0)
+ return true;
+ else
+ return false;
+
+ } else if (element is Struct) {
+ if ((targets & AttributeTargets.Struct) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Constructor) {
+ if ((targets & AttributeTargets.Constructor) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Delegate) {
+ if ((targets & AttributeTargets.Delegate) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Enum) {
+ if ((targets & AttributeTargets.Enum) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Event || element is InterfaceEvent) {
+ if ((targets & AttributeTargets.Event) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Field || element is FieldBuilder) {
+ if ((targets & AttributeTargets.Field) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Interface) {
+ if ((targets & AttributeTargets.Interface) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Method || element is Operator || element is InterfaceMethod || element is Accessor) {
+ if ((targets & AttributeTargets.Method) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is ParameterBuilder) {
+ if ((targets & AttributeTargets.Parameter) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is Property || element is Indexer ||
+ element is InterfaceProperty || element is InterfaceIndexer) {
+ if ((targets & AttributeTargets.Property) != 0)
+ return true;
+ else
+ return false;
+ } else if (element is AssemblyBuilder){
+ if ((targets & AttributeTargets.Assembly) != 0)
+ return true;
+ else
+ return false;
+ }
+
+ return false;
+ }
+
+ //
+ // This method should be invoked to pull the IndexerName attribute from an
+ // Indexer if it exists.
+ //
+ public static string ScanForIndexerName (EmitContext ec, Attributes opt_attrs)
+ {
+ if (opt_attrs == null)
+ return null;
+ if (opt_attrs.AttributeSections == null)
+ return null;
+
+ foreach (AttributeSection asec in opt_attrs.AttributeSections) {
+ if (asec.Attributes == null)
+ continue;
+
+ foreach (Attribute a in asec.Attributes){
+ if (a.ResolveType (ec) == null)
+ return null;
+
+ if (a.Type != TypeManager.indexer_name_type)
+ continue;
+
+ //
+ // So we have found an IndexerName, pull the data out.
+ //
+ if (a.Arguments == null || a.Arguments [0] == null){
+ Error_AttributeConstructorMismatch (a.Location);
+ return null;
+ }
+ ArrayList pos_args = (ArrayList) a.Arguments [0];
+ if (pos_args.Count == 0){
+ Error_AttributeConstructorMismatch (a.Location);
+ return null;
+ }
+
+ Argument arg = (Argument) pos_args [0];
+ if (!arg.Resolve (ec, a.Location))
+ return null;
+
+ Expression e = arg.Expr;
+ if (!(e is StringConstant)){
+ Error_AttributeConstructorMismatch (a.Location);
+ return null;
+ }
+
+ //
+ // Remove the attribute from the list
+ //
+ asec.Attributes.Remove (a);
+
+ return (((StringConstant) e).Value);
+ }
+ }
+ return null;
+ }
+
+ //
+ // This pulls the condition name out of a Conditional attribute
+ //
+ public string Conditional_GetConditionName ()
+ {
+ //
+ // So we have a Conditional, pull the data out.
+ //
+ if (Arguments == null || Arguments [0] == null){
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ ArrayList pos_args = (ArrayList) Arguments [0];
+ if (pos_args.Count != 1){
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ Argument arg = (Argument) pos_args [0];
+ if (!(arg.Expr is StringConstant)){
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ return ((StringConstant) arg.Expr).Value;
+ }
+
+ //
+ // This pulls the obsolete message and error flag out of an Obsolete attribute
+ //
+ public string Obsolete_GetObsoleteMessage (out bool is_error)
+ {
+ is_error = false;
+ //
+ // So we have an Obsolete, pull the data out.
+ //
+ if (Arguments == null || Arguments [0] == null)
+ return "";
+
+ ArrayList pos_args = (ArrayList) Arguments [0];
+ if (pos_args.Count == 0)
+ return "";
+ else if (pos_args.Count > 2){
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ Argument arg = (Argument) pos_args [0];
+ if (!(arg.Expr is StringConstant)){
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+
+ if (pos_args.Count == 2){
+ Argument arg2 = (Argument) pos_args [1];
+ if (!(arg2.Expr is BoolConstant)){
+ Error_AttributeConstructorMismatch (Location);
+ return null;
+ }
+ is_error = ((BoolConstant) arg2.Expr).Value;
+ }
+
+ return ((StringConstant) arg.Expr).Value;
+ }
+
+ //
+ // Applies the attributes to the `builder'.
+ //
+ public static void ApplyAttributes (EmitContext ec, object builder, object kind,
+ Attributes opt_attrs, Location loc)
+ {
+ if (opt_attrs == null)
+ return;
+ if (opt_attrs.AttributeSections == null)
+ return;
+
+ foreach (AttributeSection asec in opt_attrs.AttributeSections) {
+ if (asec.Attributes == null)
+ continue;
+
+ if (asec.Target == "assembly" && !(builder is AssemblyBuilder))
+ continue;
+
+ foreach (Attribute a in asec.Attributes) {
+ CustomAttributeBuilder cb = a.Resolve (ec);
+
+ if (cb == null)
+ continue;
+
+ if (!(kind is TypeContainer))
+ if (!CheckAttribute (a, kind)) {
+ Error_AttributeNotValidForElement (a, loc);
+ return;
+ }
+
+ if (kind is Method || kind is Operator || kind is InterfaceMethod ||
+ kind is Accessor) {
+ if (a.Type == TypeManager.methodimpl_attr_type) {
+ if (a.ImplOptions == MethodImplOptions.InternalCall)
+ ((MethodBuilder) builder).
+ SetImplementationFlags (
+ MethodImplAttributes.InternalCall |
+ MethodImplAttributes.Runtime);
+ } else if (a.Type != TypeManager.dllimport_type){
+ ((MethodBuilder) builder).SetCustomAttribute (cb);
+ }
+ } else if (kind is Constructor) {
+ ((ConstructorBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is Field) {
+ ((FieldBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is Property || kind is Indexer ||
+ kind is InterfaceProperty || kind is InterfaceIndexer) {
+ ((PropertyBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is Event || kind is InterfaceEvent) {
+ ((MyEventBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is ParameterBuilder) {
+
+ if (a.Type == TypeManager.marshal_as_attr_type) {
+ UnmanagedMarshal marshal =
+ UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
+
+ ((ParameterBuilder) builder).SetMarshal (marshal);
+ } else
+ ((ParameterBuilder) builder).SetCustomAttribute (cb);
+
+ } else if (kind is Enum) {
+ ((TypeBuilder) builder).SetCustomAttribute (cb);
+
+ } else if (kind is TypeContainer) {
+ TypeContainer tc = (TypeContainer) kind;
+
+ if (a.UsageAttr) {
+ tc.Targets = a.Targets;
+ tc.AllowMultiple = a.AllowMultiple;
+ tc.Inherited = a.Inherited;
+
+ } else if (a.Type == TypeManager.default_member_type) {
+ if (tc.Indexers != null) {
+ Report.Error (646, loc,
+ "Cannot specify the DefaultMember attribute on" +
+ " a type containing an indexer");
+ return;
+ }
+
+ } else {
+ if (!CheckAttribute (a, kind)) {
+ Error_AttributeNotValidForElement (a, loc);
+ return;
+ }
+ }
+
+ try {
+ ((TypeBuilder) builder).SetCustomAttribute (cb);
+ } catch (System.ArgumentException) {
+ Report.Warning (
+ -21, loc,
+ "The CharSet named property on StructLayout\n"+
+ "\tdoes not work correctly on Microsoft.NET\n"+
+ "\tYou might want to remove the CharSet declaration\n"+
+ "\tor compile using the Mono runtime instead of the\n"+
+ "\tMicrosoft .NET runtime");
+ }
+
+ } else if (kind is Interface) {
+ Interface iface = (Interface) kind;
+
+ if ((a.Type == TypeManager.default_member_type) &&
+ (iface.InterfaceIndexers != null)) {
+ Report.Error (
+ 646, loc,
+ "Cannot specify the DefaultMember attribute on" +
+ " a type containing an indexer");
+ return;
+ }
+
+ if (!CheckAttribute (a, kind)) {
+ Error_AttributeNotValidForElement (a, loc);
+ return;
+ }
+
+ ((TypeBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is AssemblyBuilder){
+ ((AssemblyBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is ModuleBuilder) {
+ ((ModuleBuilder) builder).SetCustomAttribute (cb);
+ } else if (kind is FieldBuilder) {
+ ((FieldBuilder) builder).SetCustomAttribute (cb);
+ } else
+ throw new Exception ("Unknown kind: " + kind);
+ }
+ }
+ }
+
+ public MethodBuilder DefinePInvokeMethod (EmitContext ec, TypeBuilder builder, string name,
+ MethodAttributes flags, Type ret_type, Type [] param_types)
+ {
+ //
+ // We extract from the attribute the information we need
+ //
+
+ if (Arguments == null) {
+ Console.WriteLine ("Internal error : this is not supposed to happen !");
+ return null;
+ }
+
+ Type = CheckAttributeType (ec);
+ if (Type == null)
+ return null;
+
+ ArrayList named_args = new ArrayList ();
+
+ ArrayList pos_args = (ArrayList) Arguments [0];
+ if (Arguments.Count > 1)
+ named_args = (ArrayList) Arguments [1];
+
+
+ string dll_name = null;
+
+ Argument tmp = (Argument) pos_args [0];
+
+ if (!tmp.Resolve (ec, Location))
+ return null;
+
+ if (tmp.Expr is Constant)
+ dll_name = (string) ((Constant) tmp.Expr).GetValue ();
+ else {
+ Error_AttributeArgumentNotValid ();
+ return null;
+ }
+
+ // Now we process the named arguments
+ CallingConvention cc = CallingConvention.Winapi;
+ CharSet charset = CharSet.Ansi;
+ bool preserve_sig = true;
+ bool exact_spelling = false;
+ bool set_last_err = false;
+ string entry_point = null;
+
+ for (int i = 0; i < named_args.Count; i++) {
+
+ DictionaryEntry de = (DictionaryEntry) named_args [i];
+
+ string member_name = (string) de.Key;
+ Argument a = (Argument) de.Value;
+
+ if (!a.Resolve (ec, Location))
+ return null;
+
+ Expression member = Expression.MemberLookup (
+ ec, Type, member_name,
+ MemberTypes.Field | MemberTypes.Property,
+ BindingFlags.Public | BindingFlags.Instance,
+ Location);
+
+ if (member == null || !(member is FieldExpr)) {
+ Error_InvalidNamedArgument (member_name);
+ return null;
+ }
+
+ if (member is FieldExpr) {
+ FieldExpr fe = (FieldExpr) member;
+ FieldInfo fi = fe.FieldInfo;
+
+ if (fi.IsInitOnly) {
+ Error_InvalidNamedArgument (member_name);
+ return null;
+ }
+
+ if (a.Expr is Constant) {
+ Constant c = (Constant) a.Expr;
+
+ if (member_name == "CallingConvention")
+ cc = (CallingConvention) c.GetValue ();
+ else if (member_name == "CharSet")
+ charset = (CharSet) c.GetValue ();
+ else if (member_name == "EntryPoint")
+ entry_point = (string) c.GetValue ();
+ else if (member_name == "SetLastError")
+ set_last_err = (bool) c.GetValue ();
+ else if (member_name == "ExactSpelling")
+ exact_spelling = (bool) c.GetValue ();
+ else if (member_name == "PreserveSig")
+ preserve_sig = (bool) c.GetValue ();
+ } else {
+ Error_AttributeArgumentNotValid ();
+ return null;
+ }
+
+ }
+ }
+
+ if (entry_point == null)
+ entry_point = name;
+
+ MethodBuilder mb = builder.DefinePInvokeMethod (
+ name, dll_name, entry_point, flags | MethodAttributes.HideBySig,
+ CallingConventions.Standard,
+ ret_type,
+ param_types,
+ cc,
+ charset);
+
+ if (preserve_sig)
+ mb.SetImplementationFlags (MethodImplAttributes.PreserveSig);
+
+ return mb;
+ }
+
+ }
+
+ public class AttributeSection {
+
+ public readonly string Target;
+ public readonly ArrayList Attributes;
+
+ public AttributeSection (string target, ArrayList attrs)
+ {
+ Target = target;
+ Attributes = attrs;
+ }
+
+ }
+
+ public class Attributes {
+ public ArrayList AttributeSections;
+ public Location Location;
+
+ public Attributes (AttributeSection a, Location loc)
+ {
+ AttributeSections = new ArrayList ();
+ AttributeSections.Add (a);
+
+ }
+
+ public void AddAttribute (AttributeSection a)
+ {
+ if (a != null)
+ AttributeSections.Add (a);
+ }
+ }
+}
diff --git a/mcs/mbas/cfold.cs b/mcs/mbas/cfold.cs
new file mode 100644
index 00000000000..72726d97335
--- /dev/null
+++ b/mcs/mbas/cfold.cs
@@ -0,0 +1,1088 @@
+//
+// cfold.cs: Constant Folding
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2002 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)
+ //
+ 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 &&
+ !Expression.ImplicitConversionExists (ec, match, other.Type)) {
+ Expression.Error_CannotConvertImplicit (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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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 (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;
+ }
+ }
+}
diff --git a/mcs/mbas/class.cs b/mcs/mbas/class.cs
new file mode 100644
index 00000000000..79bc25f53a0
--- /dev/null
+++ b/mcs/mbas/class.cs
@@ -0,0 +1,4835 @@
+
+//
+// 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 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;
+using System.Diagnostics.SymbolStore;
+
+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;
+
+ if ((res = IsValid (basename)) != AdditionResult.Success)
+ return res;
+
+ if (constants == null)
+ constants = new ArrayList ();
+
+ constants.Add (constant);
+ DefineName (Name + "." + basename, constant);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddEnum (Mono.CSharp.Enum e)
+ {
+ AdditionResult res;
+
+ if ((res = IsValid (e.Basename)) != 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;
+
+ if ((res = IsValid (c.Basename)) != AdditionResult.Success)
+ return res;
+
+
+
+ DefineName (c.Name, c);
+ types.Add (c);
+
+ // FIXME: Do we really need to explicitly add an empty default static constructor?
+ if (c.default_static_constructor == null)
+ {
+ bool isModule = c is Mono.MonoBASIC.Module;
+ Constructor dc = new Constructor ("New", Parameters.EmptyReadOnlyParameters, null, c.Location);
+ dc.ModFlags = isModule ? Modifiers.PUBLIC | Modifiers.STATIC : Modifiers.PUBLIC;
+ c.AddConstructor (dc);
+ }
+ // --------------------------------------------------------------
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddStruct (Struct s)
+ {
+ AdditionResult res;
+
+ if ((res = IsValid (s.Basename)) != AdditionResult.Success)
+ return res;
+
+ DefineName (s.Name, s);
+ types.Add (s);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddDelegate (Delegate d)
+ {
+ AdditionResult res;
+
+ if ((res = IsValid (d.Basename)) != 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 != "New")
+ 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;
+
+ if ((res = IsValid (iface.Basename)) != 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;
+
+ if ((res = IsValid (basename)) != 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 (Name + "." + basename, field);
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddProperty (Property prop)
+ {
+ AdditionResult res;
+ string basename = prop.Name;
+
+ if ((res = IsValid (basename)) != AdditionResult.Success)
+ return res;
+
+ if (properties == null)
+ properties = new ArrayList ();
+
+ if (prop.Name.IndexOf (".") != -1)
+ properties.Insert (0, prop);
+ else
+ properties.Add (prop);
+ DefineName (Name + "." + basename, prop);
+
+ return AdditionResult.Success;
+ }
+
+ public AdditionResult AddEvent (Event e)
+ {
+ AdditionResult res;
+ string basename = e.Name;
+
+ if ((res = IsValid (basename)) != AdditionResult.Success)
+ return res;
+
+ if (events == null)
+ events = new ArrayList ();
+
+ events.Add (e);
+ DefineName (Name + "." + basename, 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;
+ Expression a = new Assign (fe, e, l);
+
+ a = a.Resolve (ec);
+ if (a == null)
+ return false;
+
+ if (a is ExpressionStatement)
+ ((ExpressionStatement) a).EmitStatement (ec);
+ else {
+ throw new Exception ("Assign.Resolve returned a non ExpressionStatement");
+ }
+ }
+
+ 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.Null),
+ Location.Null);
+
+ 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 (!AsAccessible (parent, ModFlags))
+ Report.Error (60, Location,
+ "Inconsistent accessibility: base class `" +
+ TypeManager.CSharpName (parent) + "' is less " +
+ "accessible than class `" +
+ Name + "'");
+
+ } else {
+ start = 0;
+ }
+
+ 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);
+ 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.IsSealed) {
+ string detail = "";
+
+ if (t.IsValueType)
+ detail = " (a class can not inherit from a struct/enum)";
+
+ Report.Error (509, "class `"+ Name +
+ "': Cannot inherit from sealed class `"+
+ bases [i]+"'"+detail);
+ 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){
+ 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 (weird API issue)
+ if (!is_class && !have_nonstatic_fields && (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)
+ 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;
+
+ foreach (Indexer i in Indexers){
+ 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 parent)
+ {
+ 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);
+ }
+ }
+
+ 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 parent)
+ {
+ 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)
+ {
+ TypeContainer tc = TypeManager.LookupTypeContainer (t);
+
+ if (tc != null)
+ return tc.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, Location);
+
+ //
+ // Check for internal or private fields that were never assigned
+ //
+ if (fields != null && RootContext.WarningLevel >= 3) {
+ 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 (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 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;
+ string name = MakeName (n);
+
+ //
+ // At most one of static, virtual or override
+ //
+ if ((flags & Modifiers.STATIC) != 0){
+ if ((flags & vao) != 0){
+ Report.Error (
+ 112, loc, "static method " + name + "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, name +
+ " 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, name + " can not be both abstract and extern");
+ ok = false;
+ }
+
+ if ((flags & Modifiers.VIRTUAL) != 0){
+ Report.Error (
+ 503, loc, name + " can not be both abstract and virtual");
+ ok = false;
+ }
+
+ if ((ModFlags & Modifiers.ABSTRACT) == 0){
+ Report.Error (
+ 513, loc, name +
+ " is abstract but its container class is not");
+ ok = false;
+
+ }
+ }
+
+ if ((flags & Modifiers.PRIVATE) != 0){
+ if ((flags & vao) != 0){
+ Report.Error (
+ 621, loc, name +
+ " virtual or abstract members can not be private");
+ ok = false;
+ }
+ }
+
+ if ((flags & Modifiers.SEALED) != 0){
+ if ((flags & Modifiers.OVERRIDE) == 0){
+ Report.Error (
+ 238, loc, name +
+ " 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 = parent.GetElementType ();
+
+ 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 <=
+ //
+ // They are matched based on the return type and the argument types
+ //
+ void CheckPairedOperators ()
+ {
+ Hashtable pairs = new Hashtable (null, null);
+
+ // Register all the operators we care about.
+ foreach (Operator op in operators){
+ int reg = 0;
+
+ switch (op.OperatorType){
+ case Operator.OpType.Equality:
+ reg = 1; break;
+ case Operator.OpType.Inequality:
+ reg = 2; 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;
+ }
+ }
+
+ //
+ // 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");
+ }
+ }
+
+
+ }
+
+ 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;
+ 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 parent)
+ {
+ // Check if arguments were correct
+ parameter_types = Parameters.GetParameterInfo (parent);
+ if ((parameter_types == null) || !CheckParameters (parent, parameter_types))
+ return false;
+
+ parameter_info = new InternalParameters (parent, Parameters);
+
+ 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;
+ }
+
+ public void LabelParameters (EmitContext ec, Type [] parameters, MethodBase builder)
+ {
+ LabelParameters (ec, parameters, builder, null);
+ }
+
+ public void LabelParameters (EmitContext ec, Type [] parameters, MethodBase builder, Parameters p_params)
+ {
+ //
+ // Define each type attribute (in/out/ref) and
+ // the argument names.
+ //
+ Parameter [] p = p_params == null ? Parameters.FixedParameters : p_params.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;
+
+ if (mb == null)
+ pb = cb.DefineParameter (
+ i + 1, p [i].Attributes, p [i].Name);
+ else
+ pb = mb.DefineParameter (
+ i + 1, p [i].Attributes, p [i].Name);
+
+ Attributes attr = p [i].OptAttributes;
+ if (attr != null)
+ Attribute.ApplyAttributes (ec, pb, pb, attr, Location);
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+
+ public class Method : MethodCore {
+ 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)
+ {
+ if (RootContext.WarningLevel < 4)
+ return;
+
+ 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) &&
+ (t.GetElementType() == 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 parent)
+ {
+ // Check whether arguments were correct.
+ if (!DoDefineParameters (parent))
+ return false;
+
+ MethodSignature ms = new MethodSignature (Name, null, ParameterTypes);
+ if (!IsOperator) {
+ MemberList mi_this;
+
+ mi_this = TypeContainer.FindMembers (
+ parent.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 `" + parent.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 = parent.TypeBuilder.BaseType;
+
+ // ptype is only null for System.Object while compiling corlib.
+ if (ptype != null){
+ MemberList mi, mi_static, mi_instance;
+
+ mi_static = TypeContainer.FindMembers (
+ ptype, MemberTypes.Method,
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static,
+ MethodSignature.inheritable_method_signature_filter, ms);
+
+ 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 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 (parent, 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, parent.MakeName (Name) + ": cannot " +
+ "change return type when overriding " +
+ "inherited member " + name);
+ return false;
+ }
+ }
+ } else {
+ if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (parent);
+
+ if ((ModFlags & Modifiers.OVERRIDE) != 0){
+ Report.Error (115, Location,
+ parent.MakeName (Name) +
+ " no suitable methods found to override");
+ }
+ }
+ } else if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (parent);
+
+ return true;
+ }
+
+ //
+ // Creates the type
+ //
+ public override bool Define (TypeContainer parent)
+ {
+ if (!DoDefine (parent))
+ return false;
+
+ if (!CheckBase (parent))
+ return false;
+
+ CallingConventions cc = GetCallingConvention (parent is Class);
+
+ MethodData = new MethodData (this, null, MemberType, ParameterTypes,
+ ParameterInfo, cc, OptAttributes,
+ ModFlags, flags, true);
+
+ if (!MethodData.Define (parent))
+ return false;
+
+ MethodBuilder = MethodData.MethodBuilder;
+
+ //
+ // This is used to track the Entry Point,
+ //
+ if (Name == "Main" &&
+ ((ModFlags & Modifiers.STATIC) != 0) &&
+ (RootContext.MainClass == null ||
+ RootContext.MainClass == parent.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 parent)
+ {
+ MethodData.Emit (parent, Block, this);
+ }
+ }
+
+ 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, true, 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, 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){
+ if (ec.IsStatic)
+ Invocation.EmitCall (ec, true, true, null, parent_constructor, argument_list, loc);
+ else
+ Invocation.EmitCall (ec, true, false, ec.This, 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 parent)
+ {
+ MethodAttributes ca = (MethodAttributes.RTSpecialName |
+ MethodAttributes.SpecialName);
+
+ // Check if arguments were correct.
+ if (!DoDefineParameters (parent))
+ return false;
+
+ if ((ModFlags & Modifiers.STATIC) != 0)
+ ca |= MethodAttributes.Static;
+ else {
+ if (parent 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 = parent.TypeBuilder.DefineConstructor (
+ ca, GetCallingConvention (parent is Class), ParameterTypes);
+
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ if (!TypeManager.RegisterMethod (ConstructorBuilder, ParameterInfo, ParameterTypes)) {
+ Report.Error (
+ 111, Location,
+ "Class `" +parent.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 parent)
+ {
+ ILGenerator ig = ConstructorBuilder.GetILGenerator ();
+ EmitContext ec = new EmitContext (parent, Location, ig, null, ModFlags, true);
+
+ if ((ModFlags & Modifiers.STATIC) == 0){
+ if (parent is Class && Initializer == null)
+ Initializer = new ConstructorBaseInitializer (
+ null, Parameters.EmptyReadOnlyParameters, parent.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, ParameterTypes, ConstructorBuilder);
+
+ //
+ // Classes can have base initializers and instance field initializers.
+ //
+ if (parent is Class){
+ if ((ModFlags & Modifiers.STATIC) == 0)
+ parent.EmitFieldInitializers (ec);
+ }
+ if (Initializer != null)
+ Initializer.Emit (ec);
+
+ if ((ModFlags & Modifiers.STATIC) != 0)
+ parent.EmitFieldInitializers (ec);
+
+ Attribute.ApplyAttributes (ec, ConstructorBuilder, this, OptAttributes, Location);
+
+ // If this is a non-static `struct' constructor and doesn't have any
+ // initializer, it must initialize all of the struct's fields.
+ if ((parent is Struct) && ((ModFlags & Modifiers.STATIC) == 0) &&
+ (Initializer == null))
+ Block.AddThisVariable (parent, Location);
+
+ ec.EmitTopBlock (Block, ParameterInfo, Location);
+ }
+ }
+
+ 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;
+ ArrayList 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 = new ArrayList ();
+ }
+
+ //
+ // 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;
+ }
+
+ 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;
+ }
+
+ foreach (string condition in 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 parent)
+ {
+ 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 (parent.Pending != null){
+ if (member is Indexer)
+ implementing = parent.Pending.IsInterfaceIndexer (
+ member.InterfaceType, ReturnType, ParameterTypes);
+ else
+ implementing = parent.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){
+ //
+ // We already catch different accessibility settings
+ // so we just need to check that we are not private
+ //
+ if ((modifiers & Modifiers.PRIVATE) != 0)
+ implementing = null;
+
+ //
+ // Static is not allowed
+ //
+ if ((modifiers & Modifiers.STATIC) != 0)
+ implementing = null;
+ } else {
+ if ((modifiers & (Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0){
+ Modifiers.Error_InvalidModifier (Location, "public, virtual or abstract");
+ implementing = null;
+ }
+ }
+ }
+
+ //
+ // If implementing is still valid, set flags
+ //
+ if (implementing != null){
+ //
+ // When implementing interface methods, set NewSlot.
+ //
+ if (implementing.DeclaringType.IsInterface)
+ flags |= MethodAttributes.NewSlot;
+
+ flags |=
+ MethodAttributes.Virtual |
+ MethodAttributes.HideBySig;
+
+ // 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 (
+ parent, Location, null, ReturnType, modifiers);
+
+ builder = dllimport_attribute.DefinePInvokeMethod (
+ ec, parent.TypeBuilder, method_name, flags,
+ ReturnType, ParameterTypes);
+ } else
+ builder = parent.TypeBuilder.DefineMethod (
+ method_name, flags, CallingConventions,
+ ReturnType, ParameterTypes);
+
+ if (builder == null)
+ return false;
+
+ if (IsImplementing) {
+ //
+ // clear the pending implemntation flag
+ //
+ if (member is Indexer) {
+ parent.Pending.ImplementIndexer (
+ member.InterfaceType, builder, ReturnType,
+ ParameterTypes, true);
+ } else
+ parent.Pending.ImplementMethod (
+ member.InterfaceType, name, ReturnType,
+ ParameterTypes, member.IsExplicitImpl);
+
+ if (member.IsExplicitImpl)
+ parent.TypeBuilder.DefineMethodOverride (
+ builder, implementing);
+ }
+
+ if (!TypeManager.RegisterMethod (builder, ParameterInfo, ParameterTypes)) {
+ Report.Error (111, Location,
+ "Class `" + parent.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 parent, Block block, object kind)
+ {
+ ILGenerator ig;
+ EmitContext ec;
+
+ if ((flags & MethodAttributes.PinvokeImpl) == 0)
+ ig = builder.GetILGenerator ();
+ else
+ ig = null;
+
+ ec = new EmitContext (parent, Location, ig, ReturnType, modifiers);
+
+ if (OptAttributes != null)
+ Attribute.ApplyAttributes (ec, builder, kind, OptAttributes, Location);
+
+ if (member is MethodCore)
+ ((MethodCore) member).LabelParameters (ec, ParameterTypes, MethodBuilder);
+
+ //
+ // abstract or extern methods have no bodies
+ //
+ if ((modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0){
+ if (block == null)
+ 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 {
+ ISymbolWriter sw = CodeGen.SymbolWriter;
+
+ if ((sw != null) && !Location.IsNull (Location) &&
+ !Location.IsNull (block.EndLocation)) {
+ Location end = block.EndLocation;
+ MethodToken token = MethodBuilder.GetToken ();
+ sw.OpenMethod (new SymbolToken (token.Token));
+ // Avoid error if we don't support debugging for the platform
+ try {
+ sw.SetMethodSourceRange (Location.SymbolDocument,
+ Location.Row, 0,
+ end.SymbolDocument,
+ end.Row, 0);
+ } catch (Exception) {
+ }
+
+ ec.EmitTopBlock (block, member.Name, ParameterInfo, Location);
+
+ sw.CloseMethod ();
+ } else
+ ec.EmitTopBlock (block, member.Name, 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, 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 parent)
+ {
+ return true;
+ }
+
+ protected virtual bool CheckParameters (TypeContainer parent, Type [] parameters)
+ {
+ bool error = false;
+
+ foreach (Type partype in parameters){
+ if (partype.IsPointer && !UnsafeOK (parent))
+ error = true;
+
+ if (parent.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
+ 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 parent)
+ {
+ if (Name == null)
+ Name = "this";
+
+ if (!parent.MethodModifiersValid (ModFlags, Name, Location))
+ return false;
+
+ flags = Modifiers.MethodAttr (ModFlags);
+
+ // Lookup Type, verify validity
+ MemberType = parent.ResolveType (Type, false, Location);
+ if (MemberType == null)
+ return false;
+
+ // verify accessibility
+ if (!parent.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)
+ 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 (parent))
+ 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 (
+ parent, ExplicitInterfaceName, false, Location);
+ if (InterfaceType == null)
+ return false;
+
+ // Compute the full name that we need to export.
+ Name = InterfaceType.FullName + "." + ShortName;
+
+ if (!parent.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;
+ }
+ }
+
+ // Private.
+ readonly Object init;
+ 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 parent)
+ {
+ Type t = parent.ResolveType (Type, false, Location);
+
+ if (t == null)
+ return false;
+
+ if (!parent.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 (parent))
+ return false;
+
+ if (RootContext.WarningLevel > 1){
+ Type ptype = parent.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){
+ if (TypeManager.IsEnumType (t))
+ t = TypeManager.EnumToUnderlying (t);
+
+ if (!((t == TypeManager.bool_type) ||
+ (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.char_type) ||
+ (t == TypeManager.float_type))){
+ Report.Error (
+ 677, Location, parent.MakeName (Name) +
+ " A volatile field can not be of type `" +
+ TypeManager.CSharpName (t) + "'");
+ return false;
+ }
+ }
+ }
+
+ FieldAttributes fa = Modifiers.FieldAttr (ModFlags);
+
+ if (parent is Struct &&
+ ((fa & FieldAttributes.Static) == 0) &&
+ t == parent.TypeBuilder &&
+ !TypeManager.IsBuiltinType (t)){
+ Report.Error (523, Location, "Struct member `" + parent.Name + "." + Name +
+ "' causes a cycle in the structure layout");
+ return false;
+ }
+ FieldBuilder = parent.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, Location);
+ }
+ }
+
+ //
+ // `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 parent)
+ {
+ if (!base.DoDefine (parent))
+ return false;
+
+ ec = new EmitContext (parent, Location, null, MemberType, ModFlags);
+
+ return true;
+ }
+
+ //
+ // Checks our base implementation if any
+ //
+ protected override bool CheckBase (TypeContainer parent)
+ {
+ // Check whether arguments were correct.
+ if (!DoDefineParameters (parent))
+ 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 (parent.TypeBuilder);
+ ms = new MethodSignature (name, null, ParameterTypes);
+ base_name = TypeManager.IndexerPropertyName (parent.TypeBuilder.BaseType);
+ base_ms = new MethodSignature (base_name, null, ParameterTypes);
+ } else {
+ report_name = Name;
+ ms = base_ms = new MethodSignature (Name, null, ParameterTypes);
+ }
+
+ MemberList props_this;
+
+ props_this = TypeContainer.FindMembers (
+ parent.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 `" + parent.Name + "' " +
+ "already defines a member called `" + report_name + "' " +
+ "with the same parameter types");
+ return false;
+ }
+
+ //
+ // Find properties with the same name on the base class
+ //
+ MemberList props;
+ MemberList props_static = TypeContainer.FindMembers (
+ parent.TypeBuilder.BaseType, MemberTypes.Property,
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static,
+ MethodSignature.inheritable_property_signature_filter, base_ms);
+
+ MemberList props_instance = TypeContainer.FindMembers (
+ parent.TypeBuilder.BaseType, MemberTypes.Property,
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
+ MethodSignature.inheritable_property_signature_filter,
+ base_ms);
+
+ //
+ // Find if we have anything
+ //
+ if (props_static.Count > 0)
+ props = props_static;
+ else if (props_instance.Count > 0)
+ props = props_instance;
+ else
+ props = null;
+
+ //
+ // If we have something on the base.
+ if (props != null && props.Count > 0){
+ PropertyInfo pi = (PropertyInfo) props [0];
+
+ MethodInfo inherited_get = TypeManager.GetPropertyGetter (pi);
+ MethodInfo inherited_set = TypeManager.GetPropertySetter (pi);
+
+ MethodInfo reference = inherited_get == null ?
+ inherited_set : inherited_get;
+
+ if (reference != null) {
+ string name = reference.DeclaringType.Name + "." + report_name;
+
+ if (!CheckMethodAgainstBase (parent, flags, reference, name))
+ return false;
+ }
+
+ if (((ModFlags & Modifiers.NEW) == 0) && (pi.PropertyType != MemberType)) {
+ Report.Error (508, parent.MakeName (Name) + ": cannot " +
+ "change return type when overriding inherited " +
+ "member `" + pi.DeclaringType + "." + pi.Name + "'");
+ return false;
+ }
+ } else {
+ if ((ModFlags & Modifiers.NEW) != 0)
+ WarningNotHiding (parent);
+
+ if ((ModFlags & Modifiers.OVERRIDE) != 0){
+ if (this is Indexer)
+ Report.Error (115, Location,
+ parent.MakeName (Name) +
+ " no suitable indexers found to override");
+ else
+ Report.Error (115, Location,
+ parent.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, Location);
+/*
+ if (GetData != null)
+ GetData.Emit (tc, Get.Block, Get);
+
+ if (SetData != null)
+ SetData.Emit (tc, Set.Block, Set);
+*/
+ }
+ }
+
+ 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;
+
+ string set_parameter_name;
+ Parameters get_params;
+ Parameters set_params;
+
+ public Property (Expression type, string name, int mod_flags,
+ Accessor get_block, Accessor set_block,
+ Attributes attrs, Location loc, string set_name,
+ Parameters p_get, Parameters p_set)
+ : base (type, name, mod_flags, AllowedModifiers,
+ p_set, // FIXME ???????????
+ get_block, set_block, attrs, loc)
+ {
+ set_parameter_name = set_name;
+ get_params = p_get;
+ set_params = p_set;
+ }
+
+ 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)
+ {
+ set_parameter_name = "Value";
+ get_params = Parameters.EmptyReadOnlyParameters;
+ set_params = Parameters.EmptyReadOnlyParameters;
+ }
+
+ public override bool Define (TypeContainer parent)
+ {
+ Type [] g_parameters=null, s_parameters=null;
+ Parameter [] g_parms, s_parms;
+ InternalParameters g_ip=null, s_ip=null;
+
+ if (!DoDefine (parent))
+ return false;
+
+ if (!CheckBase (parent))
+ return false;
+
+ flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
+
+ if (Get != null) {
+ if (get_params == Parameters.EmptyReadOnlyParameters)
+ {
+ g_parameters = TypeManager.NoTypes;
+ g_ip = new InternalParameters (
+ parent, Parameters.EmptyReadOnlyParameters);
+ }
+ else
+ {
+ g_parameters = new Type [get_params.FixedParameters.Length];
+ for (int i = 0; i < get_params.FixedParameters.Length; i ++)
+ {
+ g_parameters[i] = get_params.FixedParameters[i].ParameterType;
+ }
+ g_parms = new Parameter [get_params.FixedParameters.Length];
+ for (int i = 0; i < get_params.FixedParameters.Length; i ++)
+ {
+ Parameter tp = get_params.FixedParameters[i];
+ g_parms[i] = new Parameter (tp.TypeName, tp.Name,
+ Parameter.Modifier.NONE, null);
+ }
+ g_ip = new InternalParameters (
+ parent, new Parameters (g_parms, null, Location));
+ }
+
+ GetData = new MethodData (this, "get", MemberType,
+ g_parameters, g_ip, CallingConventions.Standard,
+ Get.OptAttributes, ModFlags, flags, false);
+
+ if (!GetData.Define (parent))
+ return false;
+
+ GetBuilder = GetData.MethodBuilder;
+ }
+
+ if (Set != null) {
+ if (set_params == Parameters.EmptyReadOnlyParameters)
+ {
+ s_parameters = new Type [1];
+ s_parameters [0] = MemberType;
+
+ s_parms = new Parameter [1];
+ s_parms [0] = new Parameter (Type, /* was "value" */ set_parameter_name,
+ Parameter.Modifier.NONE, null);
+ }
+ else
+ {
+ s_parameters = new Type [set_params.FixedParameters.Length];
+ for (int i = 0; i < set_params.FixedParameters.Length; i ++)
+ {
+ s_parameters[i] = set_params.FixedParameters[i].ParameterType;
+ }
+
+ s_parms = new Parameter [set_params.FixedParameters.Length];
+ for (int i = 0; i < set_params.FixedParameters.Length; i ++)
+ {
+ Parameter tp = set_params.FixedParameters[i];
+ s_parms[i] = new Parameter (tp.TypeName, tp.Name,
+ Parameter.Modifier.NONE, null);
+ }
+ }
+
+ s_ip = new InternalParameters (
+ parent, new Parameters (s_parms, null, Location));
+
+
+ SetData = new MethodData (this, "set", TypeManager.void_type,
+ s_parameters, s_ip, CallingConventions.Standard,
+ Set.OptAttributes, ModFlags, flags, false);
+
+ if (!SetData.Define (parent))
+ return false;
+
+ SetBuilder = SetData.MethodBuilder;
+ SetBuilder.DefineParameter (1, ParameterAttributes.None,
+ /* was "value" */ set_parameter_name);
+ }
+
+ // FIXME - PropertyAttributes.HasDefault ?
+
+ PropertyAttributes prop_attr =
+ PropertyAttributes.RTSpecialName |
+ PropertyAttributes.SpecialName;
+
+ if (!IsExplicitImpl){
+ PropertyBuilder = parent.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 `" + parent.Name +
+ "' already contains a definition for the property `" +
+ Name + "'");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void Emit (TypeContainer tc)
+ {
+ base.Emit (tc);
+
+ if (GetData != null)
+ {
+ Parameters = get_params;
+ GetData.Emit (tc, Get.Block, Get);
+ }
+
+ if (SetData != null)
+ {
+ Parameters = set_params;
+ SetData.Emit (tc, Set.Block, Set);
+ }
+
+ }
+ }
+
+ /// </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;
+
+ public MyEventBuilder (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;
+ 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 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 parent)
+ {
+ EventAttributes e_attr = EventAttributes.RTSpecialName | EventAttributes.SpecialName;
+
+ if (!DoDefine (parent))
+ return false;
+
+ if (!MemberType.IsSubclassOf (TypeManager.delegate_type)) {
+ Report.Error (66, Location, "'" + parent.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, /* was "value" */ this.Name, Parameter.Modifier.NONE, null);
+ InternalParameters ip = new InternalParameters (
+ parent, new Parameters (parms, null, Location));
+
+ if (!CheckBase (parent))
+ 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, false);
+
+ if (!AddData.Define (parent))
+ return false;
+
+ AddBuilder = AddData.MethodBuilder;
+ AddBuilder.DefineParameter (1, ParameterAttributes.None, /* was "value" */ this.Name);
+
+ RemoveData = new MethodData (this, "remove", TypeManager.void_type,
+ parameter_types, ip, CallingConventions.Standard,
+ (Remove != null) ? Remove.OptAttributes : null,
+ ModFlags, flags, false);
+
+ if (!RemoveData.Define (parent))
+ return false;
+
+ RemoveBuilder = RemoveData.MethodBuilder;
+ RemoveBuilder.DefineParameter (1, ParameterAttributes.None, /* was "value" */ this.Name);
+
+ if (!IsExplicitImpl){
+ EventBuilder = new MyEventBuilder (
+ parent.TypeBuilder, Name, e_attr, MemberType);
+
+ if (Add == null && Remove == null) {
+ FieldBuilder = parent.TypeBuilder.DefineField (
+ Name, MemberType,
+ FieldAttributes.FamANDAssem | ((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 `" + parent.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, Location);
+
+ if (Add != null)
+ AddData.Emit (tc, Add.Block, Add);
+ 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);
+ 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 parent)
+ {
+ PropertyAttributes prop_attr =
+ PropertyAttributes.RTSpecialName |
+ PropertyAttributes.SpecialName;
+
+ if (!DoDefine (parent))
+ 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 (parent))
+ return false;
+
+ if (Get != null){
+ InternalParameters ip = new InternalParameters (parent, Parameters);
+
+ GetData = new MethodData (this, "get", MemberType,
+ ParameterTypes, ip, CallingConventions.Standard,
+ Get.OptAttributes, ModFlags, flags, false);
+
+ if (!GetData.Define (parent))
+ 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");
+ // 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, /* was "value" */ this.Name, Parameter.Modifier.NONE, null);
+
+ Parameters set_formal_params = new Parameters (tmp, null, Location);
+
+ InternalParameters ip = new InternalParameters (parent, set_formal_params);
+
+ SetData = new MethodData (this, "set", TypeManager.void_type,
+ set_pars, ip, CallingConventions.Standard,
+ Set.OptAttributes, ModFlags, flags, false);
+
+ if (!SetData.Define (parent))
+ 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, /* was "value" */ this.Name);
+
+ 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 = parent.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 readonly 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 parent)
+ {
+ return parent.Name + ".operator " + OperatorType + " (" + FirstArgType + "," +
+ SecondArgType + ")";
+ }
+
+ public override bool Define (TypeContainer parent)
+ {
+ 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 (parent) +
+ "' 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, Mono.CSharp.Location.Null);
+
+ OperatorMethod.IsOperator = true;
+ OperatorMethod.Define (parent);
+
+ 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 parent)
+ {
+ EmitContext ec = new EmitContext (parent, Location, null, null, ModFlags);
+ Attribute.ApplyAttributes (ec, OperatorMethodBuilder, this, OptAttributes, Location);
+
+ //
+ // abstract or extern methods have no bodies
+ //
+ if ((ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
+ return;
+
+ OperatorMethod.Block = Block;
+ OperatorMethod.Emit (parent);
+ }
+
+ 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;
+
+ /// <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_property_signature_filter;
+
+ static MethodSignature ()
+ {
+ method_signature_filter = new MemberFilter (MemberSignatureCompare);
+ inheritable_method_signature_filter = new MemberFilter (
+ InheritableMemberSignatureCompare);
+ inheritable_property_signature_filter = new MemberFilter (
+ InheritablePropertySignatureCompare);
+ }
+
+ 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 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)
+ {
+ if (MemberSignatureCompare (m, filter_criteria)){
+ MethodInfo mi = (MethodInfo) m;
+ MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ // If only accessible to the current class.
+ if (prot == MethodAttributes.Private)
+ 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;
+ }
+ return false;
+ }
+
+ //
+ // This filter should be used when we are requesting properties 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 InheritablePropertySignatureCompare (MemberInfo m, object filter_criteria)
+ {
+ if (MemberSignatureCompare (m, filter_criteria)){
+ PropertyInfo pi = (PropertyInfo) m;
+
+ MethodInfo inherited_get = TypeManager.GetPropertyGetter (pi);
+ MethodInfo inherited_set = TypeManager.GetPropertySetter (pi);
+
+ MethodInfo mi = inherited_get == null ? inherited_set : inherited_get;
+
+ MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
+
+ // If only accessible to the current class.
+ if (prot == MethodAttributes.Private)
+ 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;
+ }
+ return false;
+ }
+ }
+}
diff --git a/mcs/mbas/codegen.cs b/mcs/mbas/codegen.cs
new file mode 100644
index 00000000000..0ffad11aad5
--- /dev/null
+++ b/mcs/mbas/codegen.cs
@@ -0,0 +1,683 @@
+//
+// 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;
+using System.Diagnostics.SymbolStore;
+
+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 ISymbolWriter 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;
+
+ //
+ // This routine initializes the Mono runtime SymbolWriter.
+ //
+ static bool InitMonoSymbolWriter (string basename, string symbol_output,
+ string exe_output_file, string[] debug_args)
+ {
+ Type itype = SymbolWriter.GetType ();
+ if (itype == null)
+ return false;
+
+ Type[] arg_types = new Type [3];
+ arg_types [0] = typeof (string);
+ arg_types [1] = typeof (string);
+ arg_types [2] = typeof (string[]);
+
+ MethodInfo initialize = itype.GetMethod ("Initialize", arg_types);
+ if (initialize == null)
+ return false;
+
+ object[] args = new object [3];
+ args [0] = exe_output_file;
+ args [1] = symbol_output;
+ args [2] = debug_args;
+
+ initialize.Invoke (SymbolWriter, args);
+ return true;
+ }
+
+ //
+ // Initializes the symbol writer
+ //
+ static void InitializeSymbolWriter (string basename, string symbol_output,
+ string exe_output_file, string[] args)
+ {
+ SymbolWriter = ModuleBuilder.GetSymWriter ();
+
+ //
+ // If we got an ISymbolWriter instance, initialize it.
+ //
+ if (SymbolWriter == null) {
+ Report.Warning (
+ -18, "Cannot find any symbol writer");
+ return;
+ }
+
+ //
+ // Due to lacking documentation about the first argument of the
+ // Initialize method, we cannot use Microsoft's default symbol
+ // writer yet.
+ //
+ // If we're using the mono symbol writer, the SymbolWriter object
+ // is of type MonoSymbolWriter - but that's defined in a dynamically
+ // loaded DLL - that's why we're doing a comparision based on the type
+ // name here instead of using `SymbolWriter is MonoSymbolWriter'.
+ //
+ Type sym_type = ((object) SymbolWriter).GetType ();
+
+ switch (sym_type.Name){
+ case "MonoSymbolWriter":
+ if (!InitMonoSymbolWriter (basename, symbol_output,
+ exe_output_file, args))
+ Report.Warning (
+ -18, "Cannot initialize the symbol writer");
+ break;
+
+ default:
+ Report.Warning (
+ -18, "Cannot generate debugging information on this platform");
+ break;
+ }
+ }
+
+ //
+ // Initializes the code generator variables
+ //
+ static public void Init (string name, string output, bool want_debugging_support,
+ string[] debug_args)
+ {
+ AssemblyName an;
+
+ FileName = output;
+ an = new AssemblyName ();
+ an.Name = TrimExt (Basename (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);
+
+ int pos = output.LastIndexOf (".");
+
+ string basename;
+ if (pos > 0)
+ basename = output.Substring (0, pos);
+ else
+ basename = output;
+
+ string symbol_output = basename + ".dbg";
+
+ if (want_debugging_support)
+ InitializeSymbolWriter (basename, symbol_output, output, debug_args);
+ else {
+ try {
+ File.Delete (symbol_output);
+ } catch {
+ // Ignore errors.
+ }
+ }
+ }
+
+ static public void Save (string name)
+ {
+ try {
+ AssemblyBuilder.Save (Basename (name));
+ } catch (System.IO.IOException io){
+ Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
+ }
+ }
+
+ static public void SaveSymbols ()
+ {
+ if (SymbolWriter != null) {
+ // If we have a symbol writer, call its Close() method to write
+ // the symbol file to disk.
+ //
+ // When using Mono's default symbol writer, the Close() method must
+ // be called after the assembly has already been written to disk since
+ // it opens the assembly and reads its metadata.
+ SymbolWriter.Close ();
+ }
+ }
+ }
+
+ /// <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 TypeContainer 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;
+
+ /// <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 in a Catch block
+ /// </summary>
+ public bool InCatch;
+
+ /// <summary>
+ /// Whether we are inside an unsafe block
+ /// </summary>
+ public bool InUnsafe;
+
+ /// <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 (TypeContainer 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;
+ ReturnType = return_type;
+ IsConstructor = is_constructor;
+ CurrentBlock = null;
+
+ 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 ();
+ }
+
+ // <summary>
+ // Checks whether the local variable `vi' is already initialized
+ // at the current point of the method's control flow.
+ // If this method returns false, the caller must report an
+ // error 165.
+ // </summary>
+ public bool IsVariableAssigned (VariableInfo vi)
+ {
+ if (DoFlowAnalysis)
+ return CurrentBranching.IsVariableAssigned (vi);
+ else
+ return true;
+ }
+
+ // <summary>
+ // Marks the local variable `vi' as being initialized at the current
+ // current point of the method's control flow.
+ // </summary>
+ public void SetVariableAssigned (VariableInfo vi)
+ {
+ if (DoFlowAnalysis)
+ CurrentBranching.SetVariableAssigned (vi);
+ }
+
+ // <summary>
+ // Checks whether the parameter `number' is already initialized
+ // at the current point of the method's control flow.
+ // If this method returns false, the caller must report an
+ // error 165. This is only necessary for `out' parameters and the
+ // call will always succeed for non-`out' parameters.
+ // </summary>
+ public bool IsParameterAssigned (int number)
+ {
+ if (DoFlowAnalysis)
+ return CurrentBranching.IsParameterAssigned (number);
+ else
+ return true;
+ }
+
+ // <summary>
+ // Marks the parameter `number' as being initialized at the current
+ // current point of the method's control flow. This is only necessary
+ // for `out' parameters.
+ // </summary>
+ public void SetParameterAssigned (int number)
+ {
+ if (DoFlowAnalysis)
+ CurrentBranching.SetParameterAssigned (number);
+ }
+
+ // These are two overloaded methods for EmitTopBlock
+ // since in MonoBasic functions we need the Function name
+ // along with its top block, in order to be able to
+ // retrieve the return value when there is no explicit
+ // 'Return' statement
+ public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
+ {
+ EmitTopBlock (block, "", ip, loc);
+ }
+
+ public void EmitTopBlock (Block block, string bname, InternalParameters ip, Location loc)
+ {
+ bool has_ret = false;
+
+// Console.WriteLine ("Emitting: " + loc);
+
+ if (CodeGen.SymbolWriter != null)
+ Mark (loc);
+
+ if (block != null){
+ int errors = Report.Errors;
+
+ block.EmitMeta (this, block);
+
+ if (Report.Errors == errors){
+ bool old_do_flow_analysis = DoFlowAnalysis;
+ DoFlowAnalysis = true;
+
+ FlowBranching cfb = new FlowBranching (block, ip, 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 ();
+ }
+ }
+ }
+
+ if (ReturnType != null && !has_ret){
+ //
+ // mcs here would report an error (and justly so), but functions without
+ // an explicit return value are perfectly legal in MonoBasic
+ //
+
+ VariableInfo vi = block.GetVariableInfo (bname);
+ if (vi != null)
+ {
+ ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
+ ig.Emit (OpCodes.Ret);
+ }
+ else
+ Report.Error (-200, "This is not supposed to happen !");
+ return;
+ }
+
+ if (HasReturnLabel)
+ ig.MarkLabel (ReturnLabel);
+ if (return_value != null){
+ ig.Emit (OpCodes.Ldloc, return_value);
+ ig.Emit (OpCodes.Ret);
+ } else {
+ if (!InTry){
+ if (!has_ret || HasReturnLabel)
+ 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)
+ {
+ if ((CodeGen.SymbolWriter != null) && !Location.IsNull (loc)) {
+ ISymbolDocumentWriter doc = loc.SymbolDocument;
+
+ if (doc != null)
+ ig.MarkSequencePoint (doc, loc.Row, 0, loc.Row, 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;
+ }
+
+ /// <summary>
+ /// A dynamic This that is shared by all variables in a emitcontext.
+ /// Created on demand.
+ /// </summary>
+ public Expression my_this;
+ public Expression This {
+ get {
+ if (my_this == null) {
+ if (CurrentBlock != null)
+ my_this = new This (CurrentBlock, loc);
+ else
+ my_this = new This (loc);
+
+ my_this = my_this.Resolve (this);
+ }
+
+ return my_this;
+ }
+ }
+ }
+}
diff --git a/mcs/mbas/const.cs b/mcs/mbas/const.cs
new file mode 100644
index 00000000000..2708592a86e
--- /dev/null
+++ b/mcs/mbas/const.cs
@@ -0,0 +1,232 @@
+//
+// 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;
+
+ 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;
+
+ 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 (EmitContext ec)
+ {
+ 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 (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 {
+ Report.Error (150, Location, "A constant value is expected");
+ return null;
+ }
+ }
+
+ ConstantValue = ((Constant) Expr).GetValue ();
+
+ if (type != Expr.Type) {
+ try {
+ ConstantValue = TypeManager.ChangeType (ConstantValue, type);
+ } catch {
+ Expression.Error_CannotConvertImplicit (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)
+ {
+ EmitContext ec = new EmitContext (parent, Location, null, type, ModFlags);
+ LookupConstantValue (ec);
+
+ return;
+ }
+ }
+}
+
+
diff --git a/mcs/mbas/constant.cs b/mcs/mbas/constant.cs
new file mode 100644
index 00000000000..4030080a0b2
--- /dev/null
+++ b/mcs/mbas/constant.cs
@@ -0,0 +1,974 @@
+//
+// 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)
+ Error_CannotConvertImplicit (loc, Type, TypeManager.double_type);
+
+ return c;
+ }
+
+ public FloatConstant ToFloat (Location loc)
+ {
+ FloatConstant c = ConvertToFloat ();
+
+ if (c == null)
+ Error_CannotConvertImplicit (loc, Type, TypeManager.float_type);
+
+ return c;
+ }
+
+ public ULongConstant ToULong (Location loc)
+ {
+ ULongConstant c = ConvertToULong ();
+
+ if (c == null)
+ Error_CannotConvertImplicit (loc, Type, TypeManager.uint64_type);
+
+ return c;
+ }
+
+ public LongConstant ToLong (Location loc)
+ {
+ LongConstant c = ConvertToLong ();
+
+ if (c == null)
+ Error_CannotConvertImplicit (loc, Type, TypeManager.int64_type);
+
+ return c;
+ }
+
+ public UIntConstant ToUInt (Location loc)
+ {
+ UIntConstant c = ConvertToUInt ();
+
+ if (c == null)
+ Error_CannotConvertImplicit (loc, Type, TypeManager.uint32_type);
+
+ return c;
+ }
+
+ public IntConstant ToInt (Location loc)
+ {
+ IntConstant c = ConvertToInt ();
+
+ if (c == null)
+ Error_CannotConvertImplicit (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);
+ }
+ }
+
+}
+
+
diff --git a/mcs/mbas/decl.cs b/mcs/mbas/decl.cs
new file mode 100644
index 00000000000..a18ced8b8e5
--- /dev/null
+++ b/mcs/mbas/decl.cs
@@ -0,0 +1,1233 @@
+//
+// 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) {
+ 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;
+
+ 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>
+ /// 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 Namespace 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 name)
+ {
+ if (name == Basename)
+ return AdditionResult.EnclosingClash;
+
+ if (defined_names.Contains (name))
+ return AdditionResult.NameExists;
+
+ return AdditionResult.Success;
+ }
+
+ /// <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);
+ }
+
+ /// <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)
+ {
+ string prefix = (nsn == "" ? "" : nsn + ".");
+
+ return prefix + 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;
+
+ int errors = Report.Errors;
+ Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
+ if (d == null || d.eclass != ExprClass.Type){
+ if (!silent && errors == Report.Errors){
+ Report.Error (246, loc, "Cannot find type `"+ e.ToString () +"'");
+ }
+ 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);
+
+ Expression d = e.Resolve (type_resolve_ec, ResolveFlags.Type);
+ if (d == null || d.eclass != ExprClass.Type){
+ if (!silent){
+ Report.Error (246, loc, "Cannot find type `"+ e +"'");
+ }
+ return null;
+ }
+
+ return d;
+ }
+
+ 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 current_type = containing_ds.TypeBuilder;
+
+ while (current_type != null) {
+ string pre = current_type.FullName;
+
+ t = LookupInterfaceOrClass (pre, name, out error);
+ if (error)
+ return null;
+
+ if (t != null)
+ 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 (string ns = Namespace.Name; ns != null; ns = RootContext.ImplicitParent (ns)) {
+
+ t = LookupInterfaceOrClass (ns, 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 (Namespace 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
+ //
+ ArrayList using_list = ns.UsingTable;
+
+ if (using_list == null)
+ continue;
+
+ Type match = null;
+ foreach (Namespace.UsingEntry ue in using_list){
+ match = LookupInterfaceOrClass (ue.Name, name, out error);
+ if (error)
+ return null;
+
+ if (match != null){
+ if (t != null){
+ Error_AmbiguousTypeReference (loc, name, t, match);
+ return null;
+ }
+
+ t = match;
+ ue.Used = true;
+ }
+ }
+ 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, type);
+ AddMethods (BindingFlags.Static | BindingFlags.NonPublic, 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;
+
+ 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);
+ }
+ }
+}
diff --git a/mcs/mbas/delegate.cs b/mcs/mbas/delegate.cs
new file mode 100644
index 00000000000..add8e2579b1
--- /dev/null
+++ b/mcs/mbas/delegate.cs
@@ -0,0 +1,771 @@
+//
+// delegate.cs: Delegate Handler
+//
+// Author: 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.Text;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Holds Delegates
+ /// </summary>
+ public class Delegate : DeclSpace {
+ public Expression ReturnType;
+ public Parameters Parameters;
+ public Attributes OptAttributes;
+
+ public ConstructorBuilder ConstructorBuilder;
+ public MethodBuilder InvokeBuilder;
+ public MethodBuilder BeginInvokeBuilder;
+ public MethodBuilder EndInvokeBuilder;
+
+ Type [] param_types;
+ Type ret_type;
+
+ Expression instance_expr;
+ MethodBase delegate_method;
+
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.UNSAFE |
+ Modifiers.PRIVATE;
+
+ public Delegate (TypeContainer parent, Expression type, int mod_flags,
+ string name, Parameters param_list,
+ Attributes attrs, Location l)
+ : base (parent, name, l)
+ {
+ this.ReturnType = type;
+ ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
+ IsTopLevel ? Modifiers.INTERNAL :
+ Modifiers.PRIVATE, l);
+ Parameters = param_list;
+ OptAttributes = attrs;
+ }
+
+ public override TypeBuilder DefineType ()
+ {
+ TypeAttributes attr;
+
+ if (TypeBuilder != null)
+ return TypeBuilder;
+
+ if (IsTopLevel) {
+ ModuleBuilder builder = CodeGen.ModuleBuilder;
+ attr = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed;
+
+ TypeBuilder = builder.DefineType (
+ Name, attr, TypeManager.multicast_delegate_type);
+ } else {
+ TypeBuilder builder = Parent.TypeBuilder;
+ attr = TypeAttributes.NestedPublic | TypeAttributes.Class |
+ TypeAttributes.Sealed;
+
+ string name = Name.Substring (1 + Name.LastIndexOf ('.'));
+ TypeBuilder = builder.DefineNestedType (
+ name, attr, TypeManager.multicast_delegate_type);
+ }
+
+ TypeManager.AddDelegateType (Name, TypeBuilder, this);
+
+ return TypeBuilder;
+ }
+
+ public override bool DefineMembers (TypeContainer container)
+ {
+ return true;
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ MethodAttributes mattr;
+ int i;
+
+ // FIXME: POSSIBLY make this static, as it is always constant
+ //
+ Type [] const_arg_types = new Type [2];
+ const_arg_types [0] = TypeManager.object_type;
+ const_arg_types [1] = TypeManager.intptr_type;
+
+ mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |
+ MethodAttributes.HideBySig | MethodAttributes.Public;
+
+ ConstructorBuilder = TypeBuilder.DefineConstructor (mattr,
+ CallingConventions.Standard,
+ const_arg_types);
+
+ ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");
+ ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ //
+ // FIXME: POSSIBLY make these static, as they are always the same
+ Parameter [] fixed_pars = new Parameter [2];
+ fixed_pars [0] = new Parameter (null, null, Parameter.Modifier.NONE, null);
+ fixed_pars [1] = new Parameter (null, null, Parameter.Modifier.NONE, null);
+ Parameters const_parameters = new Parameters (fixed_pars, null, Location);
+
+ TypeManager.RegisterMethod (
+ ConstructorBuilder,
+ new InternalParameters (const_arg_types, const_parameters),
+ const_arg_types);
+
+
+ ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ //
+ // Here the various methods like Invoke, BeginInvoke etc are defined
+ //
+ // First, call the `out of band' special method for
+ // defining recursively any types we need:
+
+ if (!Parameters.ComputeAndDefineParameterTypes (this))
+ return false;
+
+ param_types = Parameters.GetParameterInfo (this);
+ if (param_types == null)
+ return false;
+
+ //
+ // Invoke method
+ //
+
+ // Check accessibility
+ foreach (Type partype in param_types)
+ if (!container.AsAccessible (partype, ModFlags)) {
+ Report.Error (59, Location,
+ "Inconsistent accessibility: parameter type `" +
+ TypeManager.CSharpName (partype) + "` is less " +
+ "accessible than delegate `" + Name + "'");
+ return false;
+ }
+
+ ReturnType = ResolveTypeExpr (ReturnType, false, Location);
+ ret_type = ReturnType.Type;
+ if (ret_type == null)
+ return false;
+
+ if (!container.AsAccessible (ret_type, ModFlags)) {
+ Report.Error (58, Location,
+ "Inconsistent accessibility: return type `" +
+ TypeManager.CSharpName (ret_type) + "` is less " +
+ "accessible than delegate `" + Name + "'");
+ return false;
+ }
+
+ //
+ // We don't have to check any others because they are all
+ // guaranteed to be accessible - they are standard types.
+ //
+
+ CallingConventions cc = Parameters.GetCallingConvention ();
+
+ mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;
+
+ InvokeBuilder = TypeBuilder.DefineMethod ("Invoke",
+ mattr,
+ cc,
+ ret_type,
+ param_types);
+
+ i = 0;
+ if (Parameters.FixedParameters != null){
+ int top = Parameters.FixedParameters.Length;
+ Parameter p;
+
+ for (; i < top; i++) {
+ p = Parameters.FixedParameters [i];
+
+ InvokeBuilder.DefineParameter (
+ i+1, p.Attributes, p.Name);
+ }
+ }
+ if (Parameters.ArrayParameter != null){
+ Parameter p = Parameters.ArrayParameter;
+
+ InvokeBuilder.DefineParameter (
+ i+1, p.Attributes, p.Name);
+ }
+
+ InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ TypeManager.RegisterMethod (InvokeBuilder,
+ new InternalParameters (container, Parameters),
+ param_types);
+
+ //
+ // BeginInvoke
+ //
+ int params_num = param_types.Length;
+ Type [] async_param_types = new Type [params_num + 2];
+
+ param_types.CopyTo (async_param_types, 0);
+
+ async_param_types [params_num] = TypeManager.asynccallback_type;
+ async_param_types [params_num + 1] = TypeManager.object_type;
+
+ mattr = MethodAttributes.Public | MethodAttributes.HideBySig |
+ MethodAttributes.Virtual | MethodAttributes.NewSlot;
+
+ BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",
+ mattr,
+ cc,
+ TypeManager.iasyncresult_type,
+ async_param_types);
+
+ i = 0;
+ if (Parameters.FixedParameters != null){
+ int top = Parameters.FixedParameters.Length;
+ Parameter p;
+
+ for (i = 0 ; i < top; i++) {
+ p = Parameters.FixedParameters [i];
+
+ BeginInvokeBuilder.DefineParameter (
+ i+1, p.Attributes, p.Name);
+ }
+ }
+ if (Parameters.ArrayParameter != null){
+ Parameter p = Parameters.ArrayParameter;
+
+ BeginInvokeBuilder.DefineParameter (
+ i+1, p.Attributes, p.Name);
+ i++;
+ }
+
+ BeginInvokeBuilder.DefineParameter (i + 1, ParameterAttributes.None, "callback");
+ BeginInvokeBuilder.DefineParameter (i + 2, ParameterAttributes.None, "object");
+
+ BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ Parameter [] async_params = new Parameter [params_num + 2];
+ int n = 0;
+ if (Parameters.FixedParameters != null){
+ Parameters.FixedParameters.CopyTo (async_params, 0);
+ n = Parameters.FixedParameters.Length;
+ }
+ if (Parameters.ArrayParameter != null)
+ async_params [n] = Parameters.ArrayParameter;
+
+ async_params [params_num] = new Parameter (
+ TypeManager.system_asynccallback_expr, "callback",
+ Parameter.Modifier.NONE, null);
+ async_params [params_num + 1] = new Parameter (
+ TypeManager.system_object_expr, "object",
+ Parameter.Modifier.NONE, null);
+
+ Parameters async_parameters = new Parameters (async_params, null, Location);
+
+ async_parameters.ComputeAndDefineParameterTypes (this);
+ TypeManager.RegisterMethod (BeginInvokeBuilder,
+ new InternalParameters (container, async_parameters),
+ async_param_types);
+
+ //
+ // EndInvoke
+ //
+ Type [] end_param_types = new Type [1];
+ end_param_types [0] = TypeManager.iasyncresult_type;
+
+ EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke",
+ mattr,
+ cc,
+ ret_type,
+ end_param_types);
+ EndInvokeBuilder.DefineParameter (1, ParameterAttributes.None, "result");
+
+ EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ Parameter [] end_params = new Parameter [1];
+ end_params [0] = new Parameter (
+ TypeManager.system_iasyncresult_expr, "result",
+ Parameter.Modifier.NONE, null);
+
+ TypeManager.RegisterMethod (
+ EndInvokeBuilder, new InternalParameters (
+ container,
+ new Parameters (
+ end_params, null, Location)),
+ end_param_types);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Verifies whether the method in question is compatible with the delegate
+ /// Returns the method itself if okay and null if not.
+ /// </summary>
+ public static MethodBase VerifyMethod (EmitContext ec, Type delegate_type, MethodBase mb,
+ Location loc)
+ {
+ ParameterData pd = Invocation.GetParameterData (mb);
+
+ int pd_count = pd.Count;
+
+ Expression ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return null;
+ }
+
+ MethodBase invoke_mb = ((MethodGroupExpr) ml).Methods [0];
+
+ ParameterData invoke_pd = Invocation.GetParameterData (invoke_mb);
+
+ if (invoke_pd.Count != pd_count)
+ return null;
+
+ for (int i = pd_count; i > 0; ) {
+ i--;
+
+ if (invoke_pd.ParameterType (i) == pd.ParameterType (i))
+ continue;
+ else
+ return null;
+ }
+
+ if (((MethodInfo) invoke_mb).ReturnType == ((MethodInfo) mb).ReturnType)
+ return mb;
+ else
+ return null;
+ }
+
+ // <summary>
+ // Verifies whether the invocation arguments are compatible with the
+ // delegate's target method
+ // </summary>
+ public static bool VerifyApplicability (EmitContext ec,
+ Type delegate_type,
+ ArrayList args,
+ Location loc)
+ {
+ int arg_count;
+
+ if (args == null)
+ arg_count = 0;
+ else
+ arg_count = args.Count;
+
+ Expression ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!" + delegate_type);
+ return false;
+ }
+
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];
+ ParameterData pd = Invocation.GetParameterData (mb);
+
+ int pd_count = pd.Count;
+
+ bool not_params_method = (pd_count == 0) ||
+ (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS);
+
+ if (not_params_method && pd_count != arg_count) {
+ Report.Error (1593, loc,
+ "Delegate '" + delegate_type.ToString ()
+ + "' does not take '" + arg_count + "' arguments");
+ return false;
+ }
+
+ return Invocation.VerifyArgumentsCompat (ec, args, arg_count, mb, !not_params_method,
+ delegate_type, loc);
+ }
+
+ /// <summary>
+ /// Verifies whether the delegate in question is compatible with this one in
+ /// order to determine if instantiation from the same is possible.
+ /// </summary>
+ public static bool VerifyDelegate (EmitContext ec, Type delegate_type, Type probe_type, Location loc)
+ {
+ Expression ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return false;
+ }
+
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];
+ ParameterData pd = Invocation.GetParameterData (mb);
+
+ Expression probe_ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(probe_ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return false;
+ }
+
+ MethodBase probe_mb = ((MethodGroupExpr) probe_ml).Methods [0];
+ ParameterData probe_pd = Invocation.GetParameterData (probe_mb);
+
+ if (((MethodInfo) mb).ReturnType != ((MethodInfo) probe_mb).ReturnType)
+ return false;
+
+ if (pd.Count != probe_pd.Count)
+ return false;
+
+ for (int i = pd.Count; i > 0; ) {
+ i--;
+
+ if (pd.ParameterType (i) != probe_pd.ParameterType (i) ||
+ pd.ParameterModifier (i) != probe_pd.ParameterModifier (i))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static string FullDelegateDesc (Type del_type, MethodBase mb, ParameterData pd)
+ {
+ StringBuilder sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
+
+ sb.Append (" " + del_type.ToString ());
+ sb.Append (" (");
+
+ int length = pd.Count;
+
+ for (int i = length; i > 0; ) {
+ i--;
+
+ sb.Append (TypeManager.CSharpName (pd.ParameterType (length - i - 1)));
+ if (i != 0)
+ sb.Append (", ");
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+
+ }
+
+ // Hack around System.Reflection as found everywhere else
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList ();
+
+ if ((mt & MemberTypes.Method) != 0) {
+ if (ConstructorBuilder != null)
+ if (filter (ConstructorBuilder, criteria))
+ members.Add (ConstructorBuilder);
+
+ if (InvokeBuilder != null)
+ if (filter (InvokeBuilder, criteria))
+ members.Add (InvokeBuilder);
+
+ if (BeginInvokeBuilder != null)
+ if (filter (BeginInvokeBuilder, criteria))
+ members.Add (BeginInvokeBuilder);
+
+ if (EndInvokeBuilder != null)
+ if (filter (EndInvokeBuilder, criteria))
+ members.Add (EndInvokeBuilder);
+ }
+
+ return new MemberList (members);
+ }
+
+ public override MemberCache MemberCache {
+ get {
+ return null;
+ }
+ }
+
+ public Expression InstanceExpression {
+ get {
+ return instance_expr;
+ }
+ set {
+ instance_expr = value;
+ }
+ }
+
+ public MethodBase TargetMethod {
+ get {
+ return delegate_method;
+ }
+ set {
+ delegate_method = value;
+ }
+ }
+
+ public Type TargetReturnType {
+ get {
+ return ret_type;
+ }
+ }
+
+ public Type [] ParameterTypes {
+ get {
+ return param_types;
+ }
+ }
+
+ }
+
+ public class NewDelegate : Expression {
+
+ public ArrayList Arguments;
+
+ MethodBase constructor_method;
+ MethodBase delegate_method;
+ Expression delegate_instance_expr;
+
+ public NewDelegate (Type type, ArrayList Arguments, Location loc)
+ {
+ this.type = type;
+ this.Arguments = Arguments;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (Arguments == null) {
+ Report.Error (-11, loc,
+ "Delegate creation expression takes only one argument");
+ return null;
+ }
+
+ if (Arguments.Count != 1) {
+ Report.Error (-11, loc,
+ "Delegate creation expression takes only one argument");
+ return null;
+ }
+
+ Expression ml = Expression.MemberLookup (
+ ec, type, ".ctor", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");
+ return null;
+ }
+
+ constructor_method = ((MethodGroupExpr) ml).Methods [0];
+ Argument a = (Argument) Arguments [0];
+
+ if (!a.ResolveMethodGroup (ec, Location))
+ return null;
+
+ Expression e = a.Expr;
+
+ Expression invoke_method = Expression.MemberLookup (
+ ec, type, "Invoke", MemberTypes.Method,
+ Expression.AllBindingFlags, loc);
+
+ if (invoke_method == null) {
+ Report.Error (-200, loc, "Internal error ! Could not find Invoke method!");
+ return null;
+ }
+
+ if (e is MethodGroupExpr) {
+ MethodGroupExpr mg = (MethodGroupExpr) e;
+
+ foreach (MethodInfo mi in mg.Methods){
+ delegate_method = Delegate.VerifyMethod (ec, type, mi, loc);
+
+ if (delegate_method != null)
+ break;
+ }
+
+ if (delegate_method == null) {
+ string method_desc;
+ if (mg.Methods.Length > 1)
+ method_desc = mg.Methods [0].Name;
+ else
+ method_desc = Invocation.FullMethodDesc (mg.Methods [0]);
+
+ MethodBase dm = ((MethodGroupExpr) invoke_method).Methods [0];
+ ParameterData param = Invocation.GetParameterData (dm);
+ string delegate_desc = Delegate.FullDelegateDesc (type, dm, param);
+
+ Report.Error (123, loc, "Method '" + method_desc + "' does not " +
+ "match delegate '" + delegate_desc + "'");
+
+ return null;
+ }
+
+ //
+ // Check safe/unsafe of the delegate
+ //
+ if (!ec.InUnsafe){
+ ParameterData param = Invocation.GetParameterData (delegate_method);
+ int count = param.Count;
+
+ for (int i = 0; i < count; i++){
+ if (param.ParameterType (i).IsPointer){
+ Expression.UnsafeError (loc);
+ return null;
+ }
+ }
+ }
+
+ if (mg.InstanceExpression != null)
+ delegate_instance_expr = mg.InstanceExpression.Resolve (ec);
+ else {
+ if (!ec.IsStatic)
+ delegate_instance_expr = ec.This;
+ else
+ delegate_instance_expr = null;
+ }
+
+ if (delegate_instance_expr != null)
+ if (delegate_instance_expr.Type.IsValueType)
+ delegate_instance_expr = new BoxedCast (delegate_instance_expr);
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ Type e_type = e.Type;
+
+ if (!TypeManager.IsDelegateType (e_type)) {
+ Report.Error (-12, loc, "Cannot create a delegate from something " +
+ "not a delegate or a method.");
+ return null;
+ }
+
+ // This is what MS' compiler reports. We could always choose
+ // to be more verbose and actually give delegate-level specifics
+
+ if (!Delegate.VerifyDelegate (ec, type, e_type, loc)) {
+ Report.Error (29, loc, "Cannot implicitly convert type '" + e_type + "' " +
+ "to type '" + type + "'");
+ return null;
+ }
+
+ delegate_instance_expr = e;
+ delegate_method = ((MethodGroupExpr) invoke_method).Methods [0];
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (delegate_instance_expr == null ||
+ delegate_method.IsStatic)
+ ec.ig.Emit (OpCodes.Ldnull);
+ else
+ delegate_instance_expr.Emit (ec);
+
+ if (delegate_method.IsVirtual) {
+ ec.ig.Emit (OpCodes.Dup);
+ ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);
+ } else
+ ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);
+ }
+ }
+
+ public class DelegateInvocation : ExpressionStatement {
+
+ public Expression InstanceExpr;
+ public ArrayList Arguments;
+
+ MethodBase method;
+
+ public DelegateInvocation (Expression instance_expr, ArrayList args, Location loc)
+ {
+ this.InstanceExpr = instance_expr;
+ this.Arguments = args;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (InstanceExpr is EventExpr) {
+
+ EventInfo ei = ((EventExpr) InstanceExpr).EventInfo;
+
+ Expression ml = MemberLookup (
+ ec, ec.ContainerType, ei.Name,
+ MemberTypes.Event, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
+
+ if (ml == null) {
+ //
+ // If this is the case, then the Event does not belong
+ // to this Type and so, according to the spec
+ // cannot be accessed directly
+ //
+ // Note that target will not appear as an EventExpr
+ // in the case it is being referenced within the same type container;
+ // it will appear as a FieldExpr in that case.
+ //
+
+ Assign.error70 (ei, loc);
+ return null;
+ }
+ }
+
+
+ Type del_type = InstanceExpr.Type;
+ if (del_type == null)
+ return null;
+
+ if (Arguments != null){
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ if (!Delegate.VerifyApplicability (ec, del_type, Arguments, loc))
+ return null;
+
+ Expression lookup = Expression.MemberLookup (ec, del_type, "Invoke", loc);
+ if (!(lookup is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return null;
+ }
+
+ method = ((MethodGroupExpr) lookup).Methods [0];
+ type = ((MethodInfo) method).ReturnType;
+ eclass = ExprClass.Value;
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Delegate del = TypeManager.LookupDelegate (InstanceExpr.Type);
+
+ //
+ // Invocation on delegates call the virtual Invoke member
+ // so we are always `instance' calls
+ //
+ Invocation.EmitCall (ec, false, false, InstanceExpr, method, Arguments, loc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ //
+ // Pop the return value if there is one
+ //
+ if (method is MethodInfo){
+ if (((MethodInfo) method).ReturnType != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ }
+}
diff --git a/mcs/mbas/driver.cs b/mcs/mbas/driver.cs
new file mode 100644
index 00000000000..d0b5ac74d7e
--- /dev/null
+++ b/mcs/mbas/driver.cs
@@ -0,0 +1,661 @@
+//
+// driver.cs: The compiler command line driver.
+//
+// Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
+// Based on mcs by : Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2002 Rafael Teixeira
+//
+
+namespace Mono.Languages
+{
+ using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Collections;
+ using System.IO;
+ using System.Globalization;
+ using Mono.CSharp;
+ using Mono.GetOptions;
+
+ enum Target
+ {
+ Library, Exe, Module, WinExe
+ };
+
+ /// <summary>
+ /// The compiler driver.
+ /// </summary>
+ public class Driver : Options
+ {
+
+ [Option("Verbose parsing (for debugging the parser)",'v')]
+ public bool verbose { set { GenericParser.yacc_verbose_flag = value; } }
+
+ [Option("Specifies PARAM as main (starting) class", 'm')]
+ public string main { set { RootContext.MainClass = value; } }
+
+ [Option("About the MonoBASIC compiler", "about")]
+ public override WhatToDoNext DoAbout()
+ {
+ return base.DoAbout();
+ }
+
+ [Option("Adds PARAM to the assembly link path", 'L')]
+ public string[] LinkPaths = null;
+
+ [Option("Defines the symbol PARAM", "define")]
+ public string[] Defines = null;
+
+ [Option("Only parses the source file (for debugging the tokenizer)", "parse")]
+ public bool parse_only = false;
+
+
+ [Option("Disables implicit references to assemblies", "noconfig")]
+ public bool NoConfig { set { load_default_config = !value; } }
+
+ [Option("Allows unsafe code", "unsafe")]
+ public bool AllowUnsafeCode { set { RootContext.Unsafe = value; } }
+
+ [Option("Specifies output file", 'o', "output")]
+ public string output_file = null;
+
+ [Option("Only tokenizes source files", "tokenize")]
+ public bool tokenize = false;
+
+ [Option("Set default context to checked", "checked")]
+ public bool Checked { set { RootContext.Checked = value; } }
+
+ [Option("Shows stack trace at Error location", "Stacktrace")]
+ public bool Stacktrace { set { Report.Stacktrace = value; } }
+
+ [Option(-1, "References an assembly", 'r')]
+ public string reference { set { references.Add(value); } }
+
+ [Option("Adds PARAM as a resource", "resource")]
+ public string[] resources;
+
+ [Option("Set default context to checked", "nostdlib")]
+ public bool nostdlib { set { RootContext.StdLib = !value; } }
+
+ [Option("Makes errors fatal", "fatal")]
+ public bool Fatal { set { Report.Fatal = value; } }
+
+ [Option("Treat warnings as errors", "werror")]
+ public bool WarningsAreErrors { set { Report.WarningsAreErrors = value; } }
+
+ [Option("Ignores warning number PARAM", "nowarn")]
+ public WhatToDoNext SetIgnoreWarning(int warn)
+ {
+ Report.SetIgnoreWarning(warn);
+ return WhatToDoNext.GoAhead;
+ }
+
+ [Option("Recursively compiles the files in PARAM ([dir]/file)", "recurse")]
+ public WhatToDoNext recurse(string DirName)
+ {
+ AddFiles (DirName, true);
+ return WhatToDoNext.GoAhead;
+ }
+
+
+ [Option("Write symbolic debugging information to FILE-debug.s", 'g', "debug")]
+ public bool want_debugging_support = false;
+
+ [Option("Debugger arguments", "debug-args")]
+ public WhatToDoNext SetDebugArgs(string args)
+ {
+ char[] sep = { ',' };
+ debug_arglist.AddRange (args.Split (sep));
+ return WhatToDoNext.GoAhead;
+ }
+
+ [Option("Specifies the target (PARAM is one of: exe, winexe, library, module)", "target")]
+ public WhatToDoNext SetTarget(string type)
+ {
+ 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;
+ }
+ return WhatToDoNext.GoAhead;
+ }
+
+ [Option("Sets warning level (the highest is 4, the default)", "wlevel")]
+ public int wlevel { set { RootContext.WarningLevel = value; } }
+
+ [Option("Displays time stamps of various compiler events")]
+ public bool timestamp
+ {
+ set
+ {
+ timestamps = true;
+ last_time = DateTime.Now;
+ debug_arglist.Add("timestamp");
+ }
+ }
+
+ // TODO : response file support
+
+
+ ArrayList defines = new ArrayList();
+ ArrayList references = new ArrayList();
+ ArrayList soft_references = new ArrayList();
+ string first_source = null;
+ Target target = Target.Exe;
+ string target_ext = ".exe";
+ ArrayList debug_arglist = new ArrayList ();
+ bool timestamps = false;
+ Hashtable source_files = new Hashtable ();
+ bool load_default_config = true;
+
+ //
+ // Last time we took the time
+ //
+ DateTime last_time;
+ void ShowTime (string msg)
+ {
+ DateTime now = DateTime.Now;
+ TimeSpan span = now - last_time;
+ last_time = now;
+
+ Console.WriteLine (
+ "[{0:00}:{1:000}] {2}",
+ (int) span.TotalSeconds, span.Milliseconds, msg);
+ }
+
+ public static int Main (string[] args)
+ {
+ Driver Exec = new Driver();
+
+ Exec.MainDriver(args);
+
+ if (Report.Errors == 0)
+ {
+ Console.Write("Compilation succeeded");
+ if (Report.Warnings > 0)
+ {
+ Console.Write(" - {0} warning(s)", Report.Warnings);
+ }
+ Console.WriteLine();
+ return 0;
+ }
+ else
+ {
+ Console.WriteLine("Compilation failed: {0} Error(s), {1} warnings",
+ Report.Errors, Report.Warnings);
+ return 1;
+ }
+ }
+
+ public int 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);
+ return 0;
+ } catch (FileNotFoundException){
+ foreach (string dir in LinkPaths){
+ string full_path = dir + "/" + assembly + ".dll";
+
+ try {
+ a = Assembly.LoadFrom (full_path);
+ TypeManager.AddAssembly (a);
+ return 0;
+ } catch (FileNotFoundException ff) {
+ total_log += ff.FusionLog;
+ continue;
+ }
+ }
+ if (soft)
+ return 0;
+ } catch (BadImageFormatException f) {
+ Error ("// Bad file format while loading assembly");
+ Error ("Log: " + f.FusionLog);
+ return 1;
+ } catch (FileLoadException f){
+ Error ("File Load Exception: " + assembly);
+ Error ("Log: " + f.FusionLog);
+ return 1;
+ } catch (ArgumentNullException){
+ Error ("// Argument Null exception ");
+ return 1;
+ }
+
+ Report.Error (6, "Can not find assembly `" + assembly + "'" );
+ Console.WriteLine ("Log: \n" + total_log);
+
+ return 0;
+ }
+
+ void Error(string message)
+ {
+ Console.WriteLine(message);
+ }
+
+ /// <summary>
+ /// Loads all assemblies referenced on the command line
+ /// </summary>
+ public int LoadReferences ()
+ {
+ int errors = 0;
+
+ foreach (string r in references)
+ errors += LoadAssembly (r, false);
+
+ foreach (string r in soft_references)
+ errors += LoadAssembly (r, true);
+
+ return errors;
+ }
+
+ void SetupDefaultDefines ()
+ {
+ defines = new ArrayList ();
+ defines.Add ("__MonoBASIC__");
+ }
+
+
+ //
+ // Returns the directory where the system assemblies are installed
+ //
+ string GetSystemDir ()
+ {
+ Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
+
+ foreach (Assembly a in assemblies){
+ string codebase = a.CodeBase;
+ if (codebase.EndsWith ("corlib.dll")){
+ return codebase.Substring (0, codebase.LastIndexOf ("/"));
+ }
+ }
+
+ Report.Error (-15, "Can not compute my system path");
+ return "";
+ }
+
+ //
+ // Given a path specification, splits the path from the file/pattern
+ //
+ 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;
+ }
+
+ bool AddFiles (string spec, bool recurse)
+ {
+ string path, pattern;
+
+ SplitPathAndPattern(spec, out path, out pattern);
+ if (pattern.IndexOf("*") == -1)
+ {
+ AddFile(spec);
+ return true;
+ }
+
+ string [] files = null;
+ try {
+ files = Directory.GetFiles(path, pattern);
+ } catch (System.IO.DirectoryNotFoundException) {
+ Report.Error (2001, "Source file `" + spec + "' could not be found");
+ return false;
+ } catch (System.IO.IOException){
+ Report.Error (2001, "Source file `" + spec + "' could not be found");
+ return false;
+ }
+ foreach (string f in files)
+ AddFile (f);
+
+ if (!recurse)
+ return true;
+
+ 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
+ AddFiles (d + "/" + pattern, true);
+ }
+
+ return true;
+ }
+
+ void DefineDefaultConfig ()
+ {
+ //
+ // For now the "default config" is harcoded into the compiler
+ // we can move this outside later
+ //
+ string [] default_config =
+ {
+ "System",
+ "System.Data",
+ "System.Xml",
+ "Microsoft.VisualBasic" ,
+#if EXTRA_DEFAULT_REFS
+ //
+ // Is it worth pre-loading all this stuff?
+ //
+ "Accessibility",
+ "System.Configuration.Install",
+ "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
+ };
+
+ foreach (string def in default_config)
+ soft_references.Add(def);
+ }
+
+ [ArgumentProcessor]
+ public void AddFile(string fileName)
+ {
+ string f = fileName;
+ if (first_source == null)
+ first_source = f;
+
+ if (source_files.Contains(f))
+ Report.Error(1516, "Source file '" + f + "' specified multiple times");
+ else
+ source_files.Add(f, f);
+ }
+
+ void ProcessSourceFile(string filename)
+ {
+ if (tokenize)
+ GenericParser.Tokenize(filename);
+ else
+ GenericParser.Parse(filename);
+ }
+
+ string outputFile_Name = null;
+
+ string outputFileName
+ {
+ get
+ {
+ if (outputFile_Name == null)
+ {
+ if (output_file == null)
+ {
+ int pos = first_source.LastIndexOf(".");
+
+ if (pos > 0)
+ output_file = first_source.Substring(0, pos);
+ else
+ output_file = first_source;
+ }
+ string bname = CodeGen.Basename(output_file);
+ if (bname.IndexOf(".") == -1)
+ output_file += target_ext;
+ outputFile_Name = output_file;
+ }
+ return outputFile_Name;
+ }
+ }
+
+ /// <summary>
+ /// Parses the arguments, and calls the compilation process.
+ /// </summary>
+ void MainDriver(string [] args)
+ {
+ ProcessArgs(args);
+ CompileAll();
+ }
+
+ public Driver()
+ {
+ SetupDefaultDefines();
+ }
+
+ bool ParseAll() // Phase 1
+ {
+ if (first_source == null)
+ {
+ Report.Error(2008, "No files to compile were specified");
+ return false;
+ }
+
+ foreach(string filename in source_files.Values)
+ ProcessSourceFile(filename);
+
+ if (tokenize || parse_only || (Report.Errors > 0))
+ return false;
+
+ return true; // everything went well go ahead
+ }
+
+ void InitializeDebuggingSupport()
+ {
+ string[] debug_args = new string [debug_arglist.Count];
+ debug_arglist.CopyTo(debug_args);
+ CodeGen.Init(outputFileName, outputFileName, want_debugging_support, debug_args);
+ TypeManager.AddModule(CodeGen.ModuleBuilder);
+ }
+
+ public bool ResolveAllTypes() // Phase 2
+ {
+ // Load Core Library for default compilation
+ if (RootContext.StdLib)
+ references.Insert(0, "mscorlib");
+
+ if (load_default_config)
+ DefineDefaultConfig();
+
+ if (timestamps)
+ ShowTime("Loading references");
+
+ // Load assemblies required
+ if (LoadReferences() > 0)
+ {
+ Error ("Could not load one or more assemblies");
+ return false;
+ }
+
+ if (timestamps)
+ ShowTime("References loaded");
+
+ InitializeDebuggingSupport();
+
+ //
+ // 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 (Report.Errors > 0)
+ return false;
+
+ if (timestamps)
+ ShowTime (" Core Types done");
+
+ if (timestamps)
+ ShowTime ("Resolving tree");
+
+ // The second pass of the compiler
+ RootContext.ResolveTree ();
+ if (Report.Errors > 0)
+ return false;
+
+ if (timestamps)
+ ShowTime ("Populate tree");
+
+ if (!RootContext.StdLib)
+ RootContext.BootCorlib_PopulateCoreTypes();
+ if (Report.Errors > 0)
+ return false;
+
+ RootContext.PopulateTypes();
+ if (Report.Errors > 0)
+ return false;
+
+ TypeManager.InitCodeHelpers();
+ if (Report.Errors > 0)
+ return false;
+
+ return true;
+ }
+
+ bool GenerateAssembly()
+ {
+ //
+ // The code generator
+ //
+ if (timestamps)
+ ShowTime ("Emitting code");
+
+ RootContext.EmitCode();
+ if (Report.Errors > 0)
+ return false;
+
+ if (timestamps)
+ ShowTime (" done");
+
+
+ if (timestamps)
+ ShowTime ("Closing types");
+
+ RootContext.CloseTypes ();
+ if (Report.Errors > 0)
+ return false;
+
+ if (timestamps)
+ ShowTime (" done");
+
+ PEFileKinds k = PEFileKinds.ConsoleApplication;
+
+ if (target == Target.Library || target == Target.Module)
+ k = PEFileKinds.Dll;
+ 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)
+ {
+ Report.Error (5001, "Program " + outputFileName +
+ " does not have an entry point defined");
+ return false;
+ }
+
+ CodeGen.AssemblyBuilder.SetEntryPoint (ep, k);
+ }
+
+ // Add the resources
+ if (resources != null)
+ foreach (string file in resources)
+ CodeGen.AssemblyBuilder.AddResourceFile (file, file);
+
+ CodeGen.Save(outputFileName);
+
+ if (timestamps)
+ ShowTime ("Saved output");
+
+
+ if (want_debugging_support)
+ {
+ CodeGen.SaveSymbols ();
+ if (timestamps)
+ ShowTime ("Saved symbols");
+ }
+
+ return true;
+ }
+
+ public void CompileAll()
+ {
+ if (!ParseAll()) // Phase 1
+ return;
+
+ if (!ResolveAllTypes()) // Phase 2
+ return;
+
+ if (!GenerateAssembly()) // Phase 3
+ return;
+
+ if (Report.ExpectedError != 0)
+ Error("Failed to report expected Error " + Report.ExpectedError);
+ }
+
+ }
+}
diff --git a/mcs/mbas/ecore.cs b/mcs/mbas/ecore.cs
new file mode 100644
index 00000000000..98ae385087f
--- /dev/null
+++ b/mcs/mbas/ecore.cs
@@ -0,0 +1,4387 @@
+//
+// ecore.cs: Core of the Expression representation for the intermediate tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 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 {
+ /// <summary>
+ /// Checks whether the variable has already been assigned at
+ /// the current position of the method's control flow and
+ /// reports an appropriate error message if not.
+ ///
+ /// If the variable is a struct, then this call checks whether
+ /// all of its fields (including all private ones) have been
+ /// assigned.
+ /// </summary>
+ bool IsAssigned (EmitContext ec, Location loc);
+
+ /// <summary>
+ /// Checks whether field `name' in this struct has been assigned.
+ /// </summary>
+ bool IsFieldAssigned (EmitContext ec, string name, Location loc);
+
+ /// <summary>
+ /// Tells the flow analysis code that the variable has already
+ /// been assigned at the current code position.
+ ///
+ /// If the variable is a struct, this call marks all its fields
+ /// (including private fields) as being assigned.
+ /// </summary>
+ void SetAssigned (EmitContext ec);
+
+ /// <summary>
+ /// Tells the flow analysis code that field `name' in this struct
+ /// has already been assigned atthe current code position.
+ /// </summary>
+ void SetFieldAssigned (EmitContext ec, string name);
+ }
+
+ /// <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;
+ }
+ }
+
+ /// <summary>
+ /// Expression which resolves to a type.
+ /// </summary>
+ public interface ITypeExpression
+ {
+ /// <summary>
+ /// Resolve the expression, but only lookup types.
+ /// </summary>
+ Expression DoResolveType (EmitContext ec);
+ }
+
+ /// <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);
+ }
+
+ 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) + "'");
+ }
+
+ /// <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);
+ }
+
+ /// <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)
+ {
+ // Are we doing a types-only search ?
+ if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) {
+ ITypeExpression type_expr = this as ITypeExpression;
+
+ if (type_expr == null)
+ return null;
+
+ return type_expr.DoResolveType (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) {
+
+ object lookup = TypeManager.MemberLookup (
+ ec.ContainerType, ec.ContainerType, AllMemberTypes,
+ AllBindingFlags | BindingFlags.NonPublic, s.Name);
+ if (lookup != null)
+ Error (122, "`" + s.Name + "' " +
+ "is inaccessible because of its protection level");
+ else
+ Error (103, "The name `" + s.Name + "' could not be " +
+ "found in `" + ec.DeclSpace.Name + "'");
+ return null;
+ }
+
+ return s;
+ }
+
+ if ((e is TypeExpr) || (e is ComposedCast)) {
+ if ((flags & ResolveFlags.Type) == 0) {
+ e.Error118 (flags);
+ return null;
+ }
+
+ return e;
+ }
+
+ switch (e.eclass) {
+ case ExprClass.Type:
+ if ((flags & ResolveFlags.VariableOrValue) == 0) {
+ e.Error118 (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) {
+ e.Error118 (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;
+
+ Report.Error (
+ 103, loc,
+ "The name `" + s.Name + "' could not be found in `" +
+ ec.DeclSpace.Name + "'");
+ 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 t, string name,
+ MemberTypes mt, BindingFlags bf, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
+ }
+
+ //
+ // Lookup type `t' for code in class `invocation_type'. Note that it's important
+ // to set `invocation_type' correctly since this method also checks whether the
+ // invoking class is allowed to access the member in class `t'. When you want to
+ // explicitly do a lookup in the base class, you must set both `t' and `invocation_type'
+ // to the base class (although a derived class can access protected members of its base
+ // class it cannot do so through an instance of the base class (error CS1540)).
+ //
+
+ public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t,
+ string name, MemberTypes mt, BindingFlags bf,
+ Location loc)
+ {
+ MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name);
+
+ if (mi == null)
+ return null;
+
+ int count = mi.Length;
+
+ if (count > 1)
+ return new MethodGroupExpr (mi, loc);
+
+ if (mi [0] is MethodBase)
+ return new MethodGroupExpr (mi, loc);
+
+ 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 t, string name, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, t, name,
+ AllMemberTypes, AllBindingFlags, loc);
+ }
+
+ public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc)
+ {
+ return MemberLookup (ec, ec.ContainerType, t, 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 t, string name,
+ Location loc)
+ {
+ return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc);
+ }
+
+ public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
+ MemberTypes mt, BindingFlags bf, Location loc)
+ {
+ Expression e;
+
+ int errors = Report.Errors;
+
+ e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
+
+ if (e != null)
+ return e;
+
+ // Error has already been reported.
+ if (errors < Report.Errors)
+ return null;
+
+ e = MemberLookup (ec, t, name, AllMemberTypes,
+ AllBindingFlags | BindingFlags.NonPublic, loc);
+ if (e == null){
+ Report.Error (
+ 117, loc, "`" + t + "' does not contain a definition " +
+ "for `" + name + "'");
+ } else {
+ Report.Error (
+ 122, loc, "`" + t + "." + name +
+ "' is inaccessible due to its protection level");
+ }
+
+ return null;
+ }
+
+ static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
+ {
+ EventInfo ei = event_expr.EventInfo;
+
+ return TypeManager.GetPrivateFieldOfEvent (ei);
+ }
+
+ 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 || target_type == TypeManager.value_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)
+ return new EmptyCast (expr, target_type);
+ } 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 StandardConversionExists
+ // 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 && !target_type.IsValueType)
+ return new EmptyCast (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);
+ }
+ }
+
+ // 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 = expr_type.GetElementType ();
+
+ if (MyEmptyExpr == null)
+ MyEmptyExpr = new EmptyExpression ();
+
+ MyEmptyExpr.SetType (expr_element_type);
+ Type target_element_type = target_type.GetElementType ();
+
+ if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
+ if (StandardConversionExists (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.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.IsSubclassOf (TypeManager.delegate_type))
+ if (target_type == TypeManager.icloneable_type)
+ return new EmptyCast (expr, target_type);
+
+ return null;
+
+ }
+
+ return null;
+ }
+
+ /// <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 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;
+ }
+
+ //
+ // 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))
+ 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 = target_type.GetElementType ();
+
+ if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
+ if (StandardConversionExists (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.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.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>
+ /// Same as StandardConversionExists 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 (StandardConversionExists (expr, target_type) == true)
+ return true;
+
+ Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
+
+ if (dummy != null)
+ return true;
+
+ return false;
+ }
+
+ /// <summary>
+ /// Determines if a standard implicit conversion exists from
+ /// expr_type to target_type
+ /// </summary>
+ public static bool StandardConversionExists (Expression expr, Type target_type)
+ {
+ Type expr_type = 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;
+ }
+
+ 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.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 (StandardConversionExists (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 (StandardConversionExists (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 (StandardConversionExists (priv_fms_expr, source_type))
+ src_types_set.Add (param_type);
+ else {
+ if (StandardConversionExists (source, param_type))
+ src_types_set.Add (param_type);
+ }
+ } else {
+ //
+ // Only if S is encompassed by param_type
+ //
+ if (StandardConversionExists (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 (StandardConversionExists (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 (StandardConversionExists (priv_fms_expr, target))
+ tgt_types_set.Add (ret_type);
+ else {
+ priv_fms_expr.SetType (target);
+ if (StandardConversionExists (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 (StandardConversionExists (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 (StandardConversionExists (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;
+
+ //
+ // FIXME : How does the False operator come into the picture ?
+ // This doesn't look complete and very correct !
+ //
+ if (target_type == TypeManager.bool_type && !look_for_explicit)
+ op_name = "op_True";
+ else
+ op_name = "op_Implicit";
+
+ MethodGroupExpr union3;
+
+ mg1 = MethodLookup (ec, source_type, op_name, loc);
+ if (source_type.BaseType != null)
+ mg2 = 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 = 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 = 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 = MemberLookup (ec, source_type, op_name, loc);
+ if (source_type.BaseType != null)
+ mg6 = MethodLookup (ec, source_type.BaseType, op_name, loc);
+
+ mg7 = MemberLookup (ec, target_type, op_name, loc);
+ if (target_type.BaseType != null)
+ mg8 = 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 = ConvertExplicitStandard (ec, source, most_specific_source, loc);
+ else
+ source = ConvertImplicitStandard (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 = ConvertImplicitStandard (ec, e, target, loc);
+ else
+ e = ConvertExplicitStandard (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 ConvertImplicit (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+ Expression e;
+
+ if (expr_type == target_type)
+ return expr;
+
+ if (target_type == null)
+ throw new Exception ("Target type is null");
+
+ e = ConvertImplicitStandard (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 `ConvertImplicit' in that the
+ /// user defined implicit conversions are excluded.
+ /// </summary>
+ static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+ Expression e;
+
+ if (expr_type == target_type)
+ 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.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
+ IntLiteral i = (IntLiteral) expr;
+
+ if (i.Value == 0)
+ return new EmptyCast (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 (target_type.GetElementType()==expr_type.GetElementType())
+ return expr;
+ }
+ }
+
+ if (target_type.IsPointer){
+ if (expr is NullLiteral)
+ 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 protected Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
+ {
+ int value = ic.Value;
+
+ //
+ // FIXME: This could return constants instead of EmptyCasts
+ //
+ 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);
+ }
+
+ 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_CannotConvertImplicit (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
+ /// ConvertImplicit. If there is no implicit conversion, then
+ /// an error is signaled
+ /// </summary>
+ static public Expression ConvertImplicitRequired (EmitContext ec, Expression source,
+ Type target_type, Location loc)
+ {
+ Expression e;
+
+ e = ConvertImplicit (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_CannotConvertImplicit (loc, source.Type, target_type);
+
+ return null;
+ }
+
+ /// <summary>
+ /// Performs the explicit numeric conversions
+ /// </summary>
+ static Expression ConvertNumericExplicit (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 (StandardConversionExists (expr, real_target_type)){
+ Expression ce = ConvertImplicitStandard (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 = source_type.GetElementType ();
+ Type target_element_type = target_type.GetElementType ();
+
+ 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 ConvertReferenceExplicit (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 = source_type.GetElementType ();
+ Type target_element_type = target_type.GetElementType ();
+
+ 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 ConvertExplicit (EmitContext ec, Expression expr,
+ Type target_type, Location loc)
+ {
+ Type expr_type = expr.Type;
+ Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
+
+ if (ne != null)
+ return ne;
+
+ ne = ConvertNumericExplicit (ec, expr, target_type, loc);
+ if (ne != null)
+ return ne;
+
+ //
+ // Unboxing conversion.
+ //
+ if (expr_type == TypeManager.object_type && target_type.IsValueType)
+ return new UnboxCast (expr, target_type);
+
+ //
+ // Enum types
+ //
+ if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
+ Expression e;
+
+ //
+ // FIXME: Is there any reason we should have EnumConstant
+ // dealt with here instead of just using always the
+ // UnderlyingSystemType to wrap the type?
+ //
+ if (expr is EnumConstant)
+ e = ((EnumConstant) expr).Child;
+ else {
+ e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
+ }
+
+ Expression t = ConvertImplicit (ec, e, target_type, loc);
+ if (t != null)
+ return t;
+
+ t = ConvertNumericExplicit (ec, e, target_type, loc);
+ if (t != null)
+ return t;
+
+ Error_CannotConvertType (loc, expr_type, target_type);
+ return null;
+ }
+
+ ne = ConvertReferenceExplicit (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){
+ if (target_type == TypeManager.sbyte_type ||
+ target_type == TypeManager.byte_type ||
+ 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){
+ Expression e = new EmptyCast (expr, TypeManager.uint32_type);
+ Expression ci, ce;
+
+ ci = ConvertImplicitStandard (ec, e, target_type, loc);
+
+ if (ci != null)
+ return ci;
+
+ ce = ConvertNumericExplicit (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, expr_type, target_type);
+ return null;
+ }
+
+ /// <summary>
+ /// Same as ConvertExplicit, only it doesn't include user defined conversions
+ /// </summary>
+ static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
+ Type target_type, Location l)
+ {
+ Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
+
+ if (ne != null)
+ return ne;
+
+ ne = ConvertNumericExplicit (ec, expr, target_type, l);
+ if (ne != null)
+ return ne;
+
+ ne = ConvertReferenceExplicit (expr, target_type);
+ if (ne != null)
+ return ne;
+
+ Error_CannotConvertType (l, expr.Type, target_type);
+ return null;
+ }
+
+ 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 Error118 (string expected)
+ {
+ string kind = "Unknown";
+
+ kind = ExprClassName (eclass);
+
+ Error (118, "Expression denotes a `" + kind +
+ "' where a `" + expected + "' was expected");
+ }
+
+ public void Error118 (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)
+ {
+ 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
+ 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 = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
+ if (target == null)
+ Expression.Error_CannotConvertImplicit (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 {
+
+ /// <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);
+ }
+ }
+
+ /// <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 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 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, ITypeExpression {
+ public readonly string Name;
+
+ public SimpleName (string name, Location l)
+ {
+ Name = name;
+ loc = l;
+ }
+
+ 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 Expression DoResolveType (EmitContext ec)
+ {
+ //
+ // Stage 3: Lookup symbol in the various namespaces.
+ //
+ DeclSpace ds = ec.DeclSpace;
+ Type t;
+ string alias_value;
+
+ if (ec.ResolvingTypeTree){
+ 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);
+ }
+
+ if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
+ return new TypeExpr (t, loc);
+
+
+ //
+ // Stage 2 part b: Lookup up if we are an alias to a type
+ // or a namespace.
+ //
+ // Since we are cheating: we only do the Alias lookup for
+ // namespaces if the name does not include any dots in it
+ //
+
+ alias_value = ec.DeclSpace.LookupAlias (Name);
+
+ if (Name.IndexOf ('.') == -1 && 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);
+ }
+
+ // 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;
+
+ //
+ // Stage 1: Performed by the parser (binding to locals or parameters).
+ //
+ Block current_block = ec.CurrentBlock;
+ if (current_block != null && current_block.IsVariableDefined (Name)){
+ LocalVariableReference var;
+
+ var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
+
+ if (right_side != null)
+ return var.ResolveLValue (ec, right_side);
+ else
+ return var.Resolve (ec);
+ }
+
+ if (current_block != null){
+ 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, idx, Name, loc);
+
+ if (right_side != null)
+ return param.ResolveLValue (ec, right_side);
+ else
+ return param.Resolve (ec);
+ }
+ }
+
+ //
+ // Stage 2: Lookup members
+ //
+
+ //
+ // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder
+ // Hence we have two different cases
+ //
+
+ DeclSpace lookup_ds = ec.DeclSpace;
+ do {
+ if (lookup_ds.TypeBuilder == null)
+ break;
+
+ e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
+ if (e != null)
+ break;
+
+ //
+ // Classes/structs keep looking, enums break
+ //
+ if (lookup_ds is TypeContainer)
+ lookup_ds = ((TypeContainer) lookup_ds).Parent;
+ else
+ break;
+ } while (lookup_ds != null);
+
+ if (e == null && ec.ContainerType != null)
+ e = MemberLookup (ec, ec.ContainerType, Name, loc);
+
+ if (e == null)
+ return DoResolveType (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;
+
+/* FIXME If this is not commented out, it seems that it's not possible to reach class members in mBas.
+ Maybe a grammar-related problem?
+
+ if (!me.IsStatic &&
+ TypeManager.IsNestedChildOf (me.InstanceExpression.Type, 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, ITypeExpression {
+ public TypeExpr (Type t, Location l)
+ {
+ Type = t;
+ eclass = ExprClass.Type;
+ loc = l;
+ }
+
+ public virtual Expression DoResolveType (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 DoResolveType (EmitContext ec)
+ {
+ if (type == null)
+ type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return DoResolveType (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 {
+ 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;
+ }
+ }
+
+ 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 (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 `" + Methods [0].DeclaringType + "." +
+ Methods [0].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 {
+ public readonly FieldInfo FieldInfo;
+ Expression instance_expr;
+
+ 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;
+ }
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (!FieldInfo.IsStatic){
+ if (instance_expr == null){
+ throw new Exception ("non-static FieldExpr without instance var\n" +
+ "You have to assign the Instance variable\n" +
+ "Of the FieldExpr to set this\n");
+ }
+
+ // 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.IsFieldAssigned (ec, FieldInfo.Name, loc))
+ return null;
+
+ 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.SetFieldAssigned (ec, FieldInfo.Name);
+
+ Expression e = DoResolve (ec);
+
+ if (e == null)
+ return null;
+
+ if (!FieldInfo.IsInitOnly)
+ return this;
+
+ //
+ // InitOnly fields can only be assigned in constructors
+ //
+
+ if (ec.IsConstructor)
+ return this;
+
+ Report_AssignToReadonly (true);
+
+ return null;
+ }
+
+ 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);
+ } else {
+ if (instance_expr.Type.IsValueType){
+ IMemoryLocation ml;
+ LocalTemporary tempo = null;
+
+ if (!(instance_expr is IMemoryLocation)){
+ tempo = new LocalTemporary (
+ ec, instance_expr.Type);
+
+ InstanceExpression.Emit (ec);
+ tempo.Store (ec);
+ ml = tempo;
+ } else
+ ml = (IMemoryLocation) instance_expr;
+
+ ml.AddressOf (ec, AddressOp.Load);
+ } 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){
+ if (instance is IMemoryLocation){
+ IMemoryLocation ml = (IMemoryLocation) instance;
+
+ ml.AddressOf (ec, AddressOp.Store);
+ } else
+ throw new Exception ("The " + instance + " of type " +
+ instance.Type +
+ " represents a ValueType and does " +
+ "not implement IMemoryLocation");
+ } 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);
+ }
+
+ if (is_static)
+ ig.Emit (OpCodes.Stsfld, FieldInfo);
+ else
+ ig.Emit (OpCodes.Stfld, FieldInfo);
+
+ if (FieldInfo is FieldBuilder){
+ FieldBase f = TypeManager.GetField (FieldInfo);
+
+ f.status |= Field.Status.ASSIGNED;
+ }
+ }
+
+ 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)
+ ig.Emit (OpCodes.Volatile);
+ }
+
+ if (FieldInfo is FieldBuilder){
+ FieldBase f = TypeManager.GetField (FieldInfo);
+
+ 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 {
+ if (instance_expr is IMemoryLocation)
+ ((IMemoryLocation)instance_expr).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;
+ public bool IsBase;
+ MethodInfo getter, setter;
+ bool is_static;
+ public ArrayList PropertyArgs;
+
+ Expression instance_expr;
+
+ public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
+ {
+ PropertyInfo = pi;
+ eclass = ExprClass.PropertyAccess;
+ PropertyArgs = new ArrayList();
+ 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 (!PropertyInfo.CanWrite){
+ Report.Error (200, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be assigned to, as it has not set accessor");
+ return false;
+ }
+
+ return true;
+ }
+
+ void ResolveAccessors (EmitContext ec)
+ {
+ BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
+ MemberInfo [] group;
+
+ group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
+ MemberTypes.Method, flags, "get_" + PropertyInfo.Name);
+
+ //
+ // The first method is the closest to us
+ //
+ if (group != null && group.Length > 0){
+ getter = (MethodInfo) group [0];
+
+ if (getter.IsStatic)
+ is_static = true;
+ }
+
+ //
+ // The first method is the closest to us
+ //
+ group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
+ MemberTypes.Method, flags, "set_" + PropertyInfo.Name);
+ if (group != null && group.Length > 0){
+ setter = (MethodInfo) group [0];
+ if (setter.IsStatic)
+ is_static = true;
+ }
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ if (getter == 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 ((instance_expr == null) && ec.IsStatic && !is_static) {
+ SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
+ return null;
+ }
+
+ if (instance_expr != null) {
+ instance_expr = instance_expr.DoResolve (ec);
+ if (instance_expr == null)
+ return null;
+ }
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (setter == 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 (instance_expr != null) {
+ instance_expr = instance_expr.DoResolve (ec);
+ if (instance_expr == null)
+ 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, PropertyArgs, 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 ();
+//HERE
+ args.Add (arg);
+ Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, PropertyArgs,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)
+ type = ((MyEventBuilder) EventInfo).EventType;
+ 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);
+ }
+ }
+}
diff --git a/mcs/mbas/enum.cs b/mcs/mbas/enum.cs
new file mode 100644
index 00000000000..691fcbe6b12
--- /dev/null
+++ b/mcs/mbas/enum.cs
@@ -0,0 +1,613 @@
+//
+// 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;
+
+ 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.sbyte_type) {
+ Report.Error (1008, Location,
+ "Type byte, sbyte, short, ushort, int, uint, " +
+ "long, or ulong expected (got: " +
+ TypeManager.CSharpName (UnderlyingType) + ")");
+ return null;
+ }
+
+ if (IsTopLevel) {
+ 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)
+ 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;
+ }
+
+ /// <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);
+ default_value = LookupEnumValue (ec, n, m_loc);
+ 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);
+ val = val.Resolve (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)){
+ Expression.Error_CannotConvertImplicit (
+ loc, c.Type, UnderlyingType);
+ return null;
+ }
+ }
+ }
+
+ FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
+ | FieldAttributes.Literal;
+
+ FieldBuilder fb = TypeBuilder.DefineField (name, UnderlyingType, attr);
+
+ try {
+ default_value = TypeManager.ChangeType (default_value, UnderlyingType);
+ } catch {
+ 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], loc);
+
+ 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 (parent, 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 {
+ FieldBuilder fb = TypeBuilder.DefineField (
+ name, UnderlyingType, attr);
+
+ if (default_value == null) {
+ Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
+ "fit in its type");
+ return false;
+ }
+
+ try {
+ default_value = TypeManager.ChangeType (default_value, UnderlyingType);
+ } catch {
+ 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], loc);
+ }
+
+ default_value = GetNextDefaultValue (default_value);
+ }
+
+ Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
+
+ return true;
+ }
+
+ //
+ // IMemberFinder
+ //
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList ();
+
+ if ((mt & MemberTypes.Field) != 0) {
+ 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];
+ }
+ }
+ }
+}
diff --git a/mcs/mbas/expression.cs b/mcs/mbas/expression.cs
new file mode 100644
index 00000000000..f0097687fae
--- /dev/null
+++ b/mcs/mbas/expression.cs
@@ -0,0 +1,7119 @@
+//
+// 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;
+
+ 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);
+ args.Add (new Argument (e, Argument.AType.Expression));
+ 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 ();
+ }
+
+ static 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;
+ Error23 (expr_type);
+ return false;
+ }
+
+ 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) {
+ 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 = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
+ if (e != null){
+ type = TypeManager.int32_type;
+ return this;
+ }
+ e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
+ if (e != null){
+ type = TypeManager.uint32_type;
+ return this;
+ }
+ e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
+ if (e != null){
+ type = TypeManager.int64_type;
+ return this;
+ }
+ e = ConvertImplicit (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;
+ }
+
+ string ptr_type_name = Expr.Type.FullName + "*";
+ type = TypeManager.LookupType (ptr_type_name);
+
+ 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
+ // ConvertImplicit 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 = ConvertImplicit (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 = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ expr = ConvertImplicit (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.TypeToCoreType (expr.Type.GetElementType ());
+ 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);
+ return;
+ }
+ 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);
+ }
+ }
+
+ /// <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)
+ ///
+ /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
+ /// PostDecrement, that way we could save the `Mode' byte as well.
+ /// </remarks>
+ public class UnaryMutator : ExpressionStatement {
+ public enum Mode : byte {
+ PreIncrement, PreDecrement, PostIncrement, PostDecrement
+ }
+
+ 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.Error118 ("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 (t.GetElementType ());
+ }
+
+ //
+ // Loads the proper "1" into the stack based on the type
+ //
+ static void LoadOne (ILGenerator ig, Type t)
+ {
+ if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
+ ig.Emit (OpCodes.Ldc_I8, 1L);
+ 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);
+ }
+
+
+ //
+ // FIXME: We need some way of avoiding the use of temp_storage
+ // for some types of storage (parameters, local variables,
+ // static fields) and single-dimension array access.
+ //
+ void EmitCode (EmitContext ec, bool is_expr)
+ {
+ ILGenerator ig = ec.ig;
+ IAssignMethod ia = (IAssignMethod) expr;
+ Type expr_type = expr.Type;
+
+ if (temp_storage == null)
+ temp_storage = new LocalTemporary (ec, expr_type);
+
+ ia.CacheTemporaries (ec);
+ ig.Emit (OpCodes.Nop);
+ switch (mode){
+ case Mode.PreIncrement:
+ case Mode.PreDecrement:
+ if (method == null){
+ expr.Emit (ec);
+
+ LoadOne (ig, expr_type);
+
+ //
+ // Select the opcode based on the check state (then the type)
+ // and the actual operation
+ //
+ if (ec.CheckState){
+ if (expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.int64_type){
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ } else if (expr_type == TypeManager.uint32_type ||
+ expr_type == TypeManager.uint64_type){
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub_Ovf_Un);
+ else
+ ig.Emit (OpCodes.Add_Ovf_Un);
+ } else {
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ }
+ } else {
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub);
+ else
+ ig.Emit (OpCodes.Add);
+ }
+ } 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);
+
+ LoadOne (ig, expr_type);
+
+ if (ec.CheckState){
+ if (expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.int64_type){
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ } else if (expr_type == TypeManager.uint32_type ||
+ expr_type == TypeManager.uint64_type){
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub_Ovf_Un);
+ else
+ ig.Emit (OpCodes.Add_Ovf_Un);
+ } else {
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ }
+ } else {
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub);
+ else
+ ig.Emit (OpCodes.Add);
+ }
+ } 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);
+ ig.Emit (OpCodes.Nop);
+ IntConstant.EmitInt (ig, 1);
+ return;
+ case Action.LeaveOnStack:
+ // the `e != null' rule.
+ 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 = ConvertImplicitStandard (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 (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 = ConvertImplicit (ec, expr, probe_type, loc);
+ if (e != null){
+ expr = e;
+ do_isinst = false;
+ return this;
+ }
+
+ if (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;
+ }
+ }
+
+ /// <summary>
+ /// Attempts to do a compile-time folding of a constant cast.
+ /// </summary>
+ Expression TryReduce (EmitContext ec, Type target_type)
+ {
+ if (expr is ByteConstant){
+ byte v = ((ByteConstant) expr).Value;
+
+ 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.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 (expr is SByteConstant){
+ sbyte v = ((SByteConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) 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 (expr is ShortConstant){
+ short v = ((ShortConstant) 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.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 (expr is UShortConstant){
+ ushort v = ((UShortConstant) 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.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 (expr is IntConstant){
+ int v = ((IntConstant) 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.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 (expr is UIntConstant){
+ uint v = ((UIntConstant) 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.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 (expr is LongConstant){
+ long v = ((LongConstant) 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.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 (expr is ULongConstant){
+ ulong v = ((ULongConstant) 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.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 (expr is FloatConstant){
+ float v = ((FloatConstant) 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 (expr is DoubleConstant){
+ double v = ((DoubleConstant) 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);
+ }
+
+ 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 = ConvertExplicit (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!!!
+ static 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 ConvertImplicit (ec, expr, target_type, new Location (-1));
+ }
+
+ 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)
+ + "'");
+ }
+
+ //
+ // Note that handling the case l == Decimal || r == Decimal
+ // is taken care of by the Step 1 Operator Overload resolution.
+ //
+ bool DoNumericPromotions (EmitContext ec, Type l, Type r)
+ {
+ if (l == TypeManager.double_type || r == TypeManager.double_type){
+ //
+ // If either operand is of type double, the other operand is
+ // conveted to type double.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
+
+ type = TypeManager.double_type;
+ } else if (l == TypeManager.float_type || r == TypeManager.float_type){
+ //
+ // if either operand is of type float, the other operand is
+ // converted to type float.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
+ type = TypeManager.float_type;
+ } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
+ 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 = 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 = ImplicitNumericConversion (ec, right, l, loc);
+ if (e != null)
+ right = e;
+ }
+ }
+ other = right.Type;
+ } else {
+ if (left is IntConstant){
+ e = 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 = 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 (l == TypeManager.int64_type || r == TypeManager.int64_type){
+ //
+ // If either operand is of type long, the other operand is converted
+ // to type long.
+ //
+ if (l != TypeManager.int64_type)
+ left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
+ if (r != TypeManager.int64_type)
+ right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
+
+ type = TypeManager.int64_type;
+ } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
+ //
+ // 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 = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
+
+ if (r != TypeManager.decimal_type)
+ right = ConvertImplicit (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);
+ }
+
+ 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 = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
+ ((e = ConvertImplicit (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;
+
+ //
+ // 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);
+ }
+
+ // string + string
+ method = TypeManager.string_concat_string_string;
+ } else {
+ // string + object
+ method = TypeManager.string_concat_object_object;
+ right = ConvertImplicit (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 = ConvertImplicit (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 (!(StandardConversionExists (left, r) ||
+ StandardConversionExists (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 = ConvertImplicit (ec, right, l, loc);
+ if (temp != null)
+ right = temp;
+ else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ } if (!lie){
+ temp = ConvertImplicit (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){
+ 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){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ //
+ // 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
+ //
+ DoNumericPromotions (ec, l, r);
+ 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.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;
+
+ if (left.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ left + ") at Line: " + loc.Row);
+ if (right.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ right + ") at Line: "+ loc.Row);
+
+ eclass = ExprClass.Value;
+
+ if (left is Constant && right is Constant){
+ Expression e = ConstantFold.BinaryFold (
+ ec, oper, (Constant) left, (Constant) right, 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 (!(oper == Operator.LessThan ||
+ oper == Operator.GreaterThan ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThanOrEqual))
+ return false;
+
+
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ bool isUnsigned = is_unsigned (left.Type);
+
+ 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 (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 (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 ();
+
+ 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 ();
+
+ 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);
+
+ switch (oper){
+ case Operator.Multiply:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Mul_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Mul_Ovf_Un;
+ else
+ opcode = OpCodes.Mul;
+ } else
+ opcode = OpCodes.Mul;
+
+ break;
+
+ case Operator.Division:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ opcode = OpCodes.Div_Un;
+ else
+ opcode = OpCodes.Div;
+ break;
+
+ case Operator.Modulus:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ 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 (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ 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 (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Sub_Ovf_Un;
+ else
+ opcode = OpCodes.Sub;
+ } else
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.RightShift:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ 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:
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.LessThan:
+ opcode = OpCodes.Clt;
+ break;
+
+ case Operator.GreaterThan:
+ opcode = OpCodes.Cgt;
+ break;
+
+ case Operator.LessThanOrEqual:
+ ec.ig.Emit (OpCodes.Cgt);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.GreaterThanOrEqual:
+ ec.ig.Emit (OpCodes.Clt);
+ ec.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;
+ }
+ }
+ }
+
+ 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 (op_type.GetElementType ());
+
+ if (right.Type.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);
+ ig.Emit (OpCodes.Mul);
+ }
+ 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.ConvertImplicitRequired (
+ ec, expr, TypeManager.bool_type, loc);
+
+ 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 = ConvertImplicit (ec, trueExpr, false_type, loc);
+ if (conv != null){
+ //
+ // Check if both can convert implicitl to each other's type
+ //
+ if (ConvertImplicit (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 = ConvertImplicit(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;
+ 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,
+ VariableInfo variable_info, bool is_readonly)
+ : this (block, name, l)
+ {
+ this.variable_info = variable_info;
+ this.is_readonly = is_readonly;
+ }
+
+ public VariableInfo VariableInfo {
+ get {
+ if (variable_info == null) {
+ variable_info = Block.GetVariableInfo (Name);
+ is_readonly = variable_info.ReadOnly;
+ }
+ return variable_info;
+ }
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ return VariableInfo.IsAssigned (ec, loc);
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
+ {
+ return VariableInfo.IsFieldAssigned (ec, name, loc);
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ VariableInfo.SetAssigned (ec);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string name)
+ {
+ VariableInfo.SetFieldAssigned (ec, name);
+ }
+
+ public bool IsReadOnly {
+ get {
+ if (variable_info == null) {
+ variable_info = Block.GetVariableInfo (Name);
+ is_readonly = variable_info.ReadOnly;
+ }
+ return is_readonly;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ VariableInfo vi = VariableInfo;
+
+ if (Block.IsConstant (Name)) {
+ Expression e = Block.GetConstantExpression (Name);
+
+ vi.Used = true;
+ return e;
+ }
+
+ if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
+ return null;
+
+ type = vi.VariableType;
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ VariableInfo vi = VariableInfo;
+
+ if (ec.DoFlowAnalysis)
+ ec.SetVariableAssigned (vi);
+
+ 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 override void Emit (EmitContext ec)
+ {
+ VariableInfo vi = VariableInfo;
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
+ vi.Used = true;
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+ VariableInfo vi = VariableInfo;
+
+ vi.Assigned = true;
+
+ source.Emit (ec);
+
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ VariableInfo vi = VariableInfo;
+
+ ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
+ }
+ }
+
+ /// <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;
+ public Parameter.Modifier mod;
+ public bool is_ref, is_out;
+
+ public ParameterReference (Parameters pars, int idx, string name, Location loc)
+ {
+ this.pars = pars;
+ this.idx = idx;
+ this.name = name;
+ this.loc = loc;
+ eclass = ExprClass.Variable;
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (!is_out || !ec.DoFlowAnalysis)
+ return true;
+
+ if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
+ Report.Error (165, loc,
+ "Use of unassigned local variable `" + name + "'");
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+ {
+ if (!is_out || !ec.DoFlowAnalysis)
+ return true;
+
+ if (ec.CurrentBranching.IsParameterAssigned (idx))
+ return true;
+
+ if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
+ Report.Error (170, loc,
+ "Use of possibly unassigned field `" + field_name + "'");
+ return false;
+ }
+
+ return true;
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (is_out && ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetParameterAssigned (idx);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string field_name)
+ {
+ if (is_out && ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetParameterAssigned (idx, field_name);
+ }
+
+ //
+ // 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)
+ {
+ 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 && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
+ return null;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ 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 && ec.DoFlowAnalysis)
+ ec.SetParameterAssigned (idx);
+
+ return this;
+ }
+
+ static 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;
+ 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;
+ 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)
+ {
+ 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,
+ NoArg
+ };
+
+ 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.LookupType (Expr.Type.ToString () + "&");
+ 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)
+ {
+ // Optional void arguments - MyCall (1,,2) - are resolved later
+ // in VerifyArgsCompat
+ if (ArgType == AType.NoArg)
+ {
+ return true;
+ }
+
+ 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 ArrayList Arguments;
+
+ Expression expr;
+ MethodBase method = null;
+ bool is_base;
+
+ static Hashtable method_parameter_cache;
+ static MemberFilter CompareName;
+
+ 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;
+ CompareName = new MemberFilter (compare_name_filter);
+ }
+
+ 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 (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 (value >= UInt16.MinValue && value <= UInt16.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 (value >= 0)
+ 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 = ConvertImplicit (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 (StandardConversionExists (p_tmp, q) == true &&
+ StandardConversionExists (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 = t.GetElementType ();
+
+ 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 = ct.GetElementType ();
+
+ if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ bt = bt.GetElementType ();
+
+ 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 + 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 (!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.LookupType (pt.FullName + "&");
+
+ if (pt != a.Type)
+ return false;
+ }
+ } else
+ return false;
+
+ }
+
+ Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
+
+ for (int i = pd_count - 1; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+
+ if (!StandardConversionExists (a.Expr, element_type))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
+ {
+ 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 (!ImplicitConversionExists (ec, a.Expr, ptype))
+ return false;
+
+ if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
+ Type pt = pd.ParameterType (i);
+
+ if (!pt.IsByRef)
+ pt = TypeManager.LookupType (pt.FullName + "&");
+
+ if (pt != a.Type)
+ return false;
+ }
+ } else
+ 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, ref ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count, ps_count, po_count;
+ Type param_type;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (candidate);
+ Parameters ps = GetFullParameters (candidate);
+
+ if (ps == null) {
+ ps_count = 0;
+ po_count = 0;
+ }
+ else
+ {
+ ps_count = ps.CountStandardParams();
+ po_count = ps.CountOptionalParams();
+ }
+ int pd_count = pd.Count;
+
+ // Validate argument count
+ if (po_count == 0) {
+ if (arg_count != pd.Count)
+ return false;
+ }
+ else
+ {
+ if ((arg_count < ps_count) || (arg_count > pd_count))
+ return false;
+ }
+
+ if (arg_count > 0) {
+ for (int i = arg_count; i > 0 ; ) {
+ i--;
+
+ Argument a = (Argument) arguments [i];
+ if (a.ArgType == Argument.AType.NoArg){
+ Parameter p = (Parameter) ps.FixedParameters[i];
+ a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
+ param_type = p.ParameterInitializer.Type;
+ }
+ else
+ param_type = pd.ParameterType (i);
+
+ if (!CheckParameterAgainstArgument (ec, pd, i, a, param_type))
+ return (false);
+ }
+ }
+ else
+ {
+ // If we have no arguments AND the first parameter is optional
+ // we must check for a candidate (the loop above wouldn't)
+ if (po_count > 0) {
+ ArrayList arglist = new ArrayList();
+
+ // Since we got so far, there's no need to check if
+ // arguments are optional; we simply retrieve
+ // parameter default values and build a brand-new
+ // argument list.
+
+ for (int i = 0; i < ps.FixedParameters.Length; i++) {
+ Parameter p = ps.FixedParameters[i];
+ Argument a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
+ a.Resolve(ec, Location.Null);
+ arglist.Add (a);
+ }
+ arguments = arglist;
+ return true;
+ }
+ }
+ // We've found a candidate, so we exchange the dummy NoArg arguments
+ // with new arguments containing the default value for that parameter
+ for (int i = 0; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+ if (a.ArgType == Argument.AType.NoArg){
+ Parameter p = (Parameter) ps.FixedParameters[i];
+ a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
+ a.Resolve(ec, Location.Null);
+ arguments [i] = a;
+ }
+ }
+
+ return true;
+ }
+
+ static bool compare_name_filter (MemberInfo m, object filterCriteria)
+ {
+ return (m.Name == ((string) filterCriteria));
+ }
+
+ static Parameters GetFullParameters (MethodBase mb)
+ {
+ TypeContainer tc = TypeManager.LookupTypeContainer (mb.DeclaringType);
+ InternalParameters ip = TypeManager.LookupParametersByBuilder(mb);
+
+ return (ip != null) ? ip.Parameters : null;
+ }
+
+ // We need an overload for OverloadResolve because Invocation.DoResolve
+ // must pass Arguments by reference, since a later call to IsApplicable
+ // can change the argument list if optional parameters are defined
+ // in the method declaration
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ArrayList Arguments, Location loc)
+ {
+ ArrayList a = Arguments;
+ return OverloadResolve (ec, me, ref a, loc);
+ }
+
+ /// <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,
+ ref ArrayList Arguments, Location loc)
+ {
+ ArrayList afm = new ArrayList ();
+ MethodBase method = null;
+ Type current_type = null;
+ int argument_count;
+ ArrayList candidates = new ArrayList ();
+
+ foreach (MethodBase candidate in me.Methods){
+ int x;
+
+ // If we're going one level higher in the class hierarchy, abort if
+ // we already found an applicable method.
+ if (candidate.DeclaringType != current_type) {
+ current_type = candidate.DeclaringType;
+ if (method != null)
+ break;
+ }
+
+ // Check if candidate is applicable (section 14.4.2.1)
+ if (!IsApplicable (ec, ref Arguments, candidate))
+ continue;
+
+ candidates.Add (candidate);
+ 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);
+ }
+
+ 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, ref 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 method;
+ else
+ return null;
+ }
+
+ public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
+ int argument_count,
+ MethodBase method,
+ bool chose_params_expanded,
+ Type delegate_type,
+ Location loc)
+ {
+ return (VerifyArgumentsCompat (ec, Arguments, argument_count,
+ method, chose_params_expanded, delegate_type, loc, null));
+ }
+
+ public static bool VerifyArgumentsCompat (EmitContext ec,
+ ArrayList Arguments,
+ int argument_count,
+ MethodBase method,
+ bool chose_params_expanded,
+ Type delegate_type,
+ Location loc,
+ string InvokingProperty)
+ {
+ 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);
+
+ if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
+ chose_params_expanded)
+ parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
+
+ if (a.Type != parameter_type){
+ Expression conv;
+
+ conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
+
+ if (conv == null) {
+ if (!Location.IsNull (loc)) {
+ if (delegate_type == null)
+ if (InvokingProperty == null)
+ Report.Error (1502, loc,
+ "The best overloaded match for method '" +
+ FullMethodDesc (method) +
+ "' has some invalid arguments");
+ else
+ Report.Error (1502, loc,
+ "Property '" +
+ InvokingProperty +
+ "' has some invalid arguments");
+ else
+ Report.Error (1594, loc,
+ "Delegate '" + delegate_type.ToString () +
+ "' has some invalid arguments.");
+ Report.Error (1503, loc,
+ "Argument " + (j+1) +
+ ": Cannot convert from '" + Argument.FullDesc (a)
+ + "' to '" + 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)) {
+ 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
+ //
+ Expression expr_to_return = null;
+
+ if (expr is BaseAccess)
+ is_base = true;
+
+ 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.Error118 (ResolveFlags.MethodGroup);
+ return null;
+ }
+ */
+ //
+ // Next, evaluate all the expressions in the argument list
+ //
+ if (Arguments != null)
+ {
+ foreach (Argument a in Arguments)
+ {
+ if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
+ Report.Error (999, "This item cannot have empty arguments");
+
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ if (expr is MethodGroupExpr)
+ {
+ MethodGroupExpr mg = (MethodGroupExpr) expr;
+ method = OverloadResolve (ec, mg, ref 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;
+ }
+ }
+ eclass = ExprClass.Value;
+ expr_to_return = this;
+ }
+
+ if (expr is PropertyExpr)
+ {
+ PropertyExpr pe = ((PropertyExpr) expr);
+ pe.PropertyArgs = (ArrayList) Arguments.Clone();
+ Arguments.Clear();
+ Arguments = new ArrayList();
+ MethodBase mi = pe.PropertyInfo.GetGetMethod(true);
+
+ if(VerifyArgumentsCompat (ec, pe.PropertyArgs,
+ pe.PropertyArgs.Count, mi, false, null, loc, pe.Name))
+ {
+
+ expr_to_return = pe.DoResolve (ec);
+ expr_to_return.eclass = ExprClass.PropertyAccess;
+ }
+ }
+
+ if (expr is FieldExpr) {
+ // If we are here, expr must be an ArrayAccess
+ // FIXME: we should check dimensions, etc.
+ ArrayList idxs = new ArrayList();
+ foreach (Argument a in Arguments)
+ {
+ idxs.Add (a.Expr);
+ }
+ ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
+ ArrayAccess aa = new ArrayAccess (ea, expr.Location);
+ expr_to_return = aa.DoResolve(ec);
+ expr_to_return.eclass = ExprClass.Variable;
+ }
+
+ return expr_to_return;
+ }
+
+ // <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);
+ a.Emit (ec);
+
+ ArrayAccess.EmitStoreOpcode (ig, t);
+ }
+ 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, pd.ParameterType (0).GetElementType ());
+ }
+ 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, pd.ParameterType (top).GetElementType ());
+ }
+ }
+
+ /// <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)
+ {
+ EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);
+ }
+
+ public static void EmitCall (EmitContext ec, bool is_base,
+ bool is_static, Expression instance_expr,
+ MethodBase method, ArrayList Arguments, ArrayList prop_args, 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);
+ }
+ }
+
+ if (prop_args != null && prop_args.Count > 0)
+ {
+ if (Arguments == null)
+ Arguments = new ArrayList();
+
+ for (int i = prop_args.Count-1; i >=0 ; i--)
+ {
+ Arguments.Insert (0,prop_args[i]);
+ }
+
+ }
+
+ 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);
+ }
+ }
+
+ static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
+ {
+ int top = prop_args.Count;
+
+ for (int i = 0; i < top; i++)
+ {
+ Argument a = (Argument) prop_args [i];
+ a.Emit (ec);
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+
+ //
+ // 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 {
+ 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 Expression ValueTypeVariable {
+ get {
+ return value_target;
+ }
+
+ set {
+ value_target = value;
+ value_target_set = 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)
+ {
+ 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 = false;
+ 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, type, ".ctor",
+ MemberTypes.Constructor,
+ AllBindingFlags | BindingFlags.Public, loc);
+
+ if (ml == null)
+ return null;
+
+ if (! (ml is MethodGroupExpr)){
+ if (!is_struct){
+ ml.Error118 ("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,
+ "New invocation: Can not find a constructor for " +
+ "this argument list");
+ 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);
+ }
+ }
+
+ /// <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;
+
+ 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;
+ }
+ 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 = ConvertImplicitRequired (
+ 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 = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
+ if (target == null)
+ Expression.Error_CannotConvertImplicit (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.TypeToCoreType (underlying_type.GetElementType ());
+ 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.TypeToCoreType (type.GetElementType ());
+
+ 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.Error118 ("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;
+
+ for (int j = 0; j < 4; j++){
+ data [p++] = (byte) (bits [j] & 0xff);
+ data [p++] = (byte) ((bits [j] >> 8) & 0xff);
+ data [p++] = (byte) ((bits [j] >> 16) & 0xff);
+ data [p++] = (byte) (bits [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 StringConstant || !(e is Constant) ||
+ num_automatic_initializers <= 2) {
+ 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.object_type) {
+ if (num_automatic_initializers > 2)
+ 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);
+ }
+
+ }
+
+ /// <summary>
+ /// Represents the `this' construct
+ /// </summary>
+ public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
+
+ Block block;
+ VariableInfo vi;
+
+ public This (Block block, Location loc)
+ {
+ this.loc = loc;
+ this.block = block;
+ }
+
+ public This (Location loc)
+ {
+ this.loc = loc;
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (vi == null)
+ return true;
+
+ return vi.IsAssigned (ec, loc);
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+ {
+ if (vi == null)
+ return true;
+
+ return vi.IsFieldAssigned (ec, field_name, loc);
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (vi != null)
+ vi.SetAssigned (ec);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string field_name)
+ {
+ if (vi != null)
+ vi.SetFieldAssigned (ec, field_name);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ eclass = ExprClass.Variable;
+ type = ec.ContainerType;
+
+ if (ec.IsStatic){
+ Error (26, "Keyword this not valid in static code");
+ return null;
+ }
+
+ if (block != null)
+ vi = block.ThisVariable;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ DoResolve (ec);
+
+ VariableInfo vi = ec.CurrentBlock.ThisVariable;
+ if (vi != null)
+ vi.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;
+
+ 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 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) {
+ Error (233, "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, "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, ITypeExpression {
+ public readonly string Identifier;
+ Expression expr;
+ Expression member_lookup;
+
+ 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.This;
+ } 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 (ec);
+ 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 : we should instead flag an error
+ //
+ Assign.error70 (ee.EventInfo, loc);
+ return null;
+ }
+
+ Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
+
+ if (ml == null) {
+ Report.Error (-200, loc, "Internal error!!");
+ return 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 (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;
+ }
+
+ if (member_lookup is TypeExpr){
+ member_lookup.Resolve (ec, ResolveFlags.Type);
+ 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) && (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;
+ }
+
+ member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
+
+ if (member_lookup == null){
+ // Error has already been reported.
+ if (errors < Report.Errors)
+ return null;
+
+ //
+ // Try looking the member up from the same type, if we find
+ // it, we know that the error was due to limited visibility
+ //
+ object lookup = TypeManager.MemberLookup (
+ expr_type, expr_type, AllMemberTypes, AllBindingFlags |
+ BindingFlags.NonPublic, Identifier);
+ if (lookup == null)
+ Error (117, "`" + expr_type + "' does not contain a " +
+ "definition for `" + Identifier + "'");
+ else if ((expr_type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (expr_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 expr_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, AllMemberTypes,
+ AllBindingFlags, Identifier);
+
+ if (lookup != null)
+ Error (1540, "Cannot access protected member `" +
+ expr_type + "." + Identifier + "' " +
+ "via a qualifier of type `" +
+ TypeManager.CSharpName (expr_type) + "'; the " +
+ "qualifier must be of type `" +
+ TypeManager.CSharpName (ec.ContainerType) + "' " +
+ "(or derived from it)");
+ else
+ Error (122, "`" + expr_type + "." + Identifier + "' " +
+ "is inaccessible because of its protection level");
+ } else
+ Error (122, "`" + expr_type + "." + Identifier + "' " +
+ "is inaccessible because of its protection level");
+
+ return null;
+ }
+
+ if (member_lookup is TypeExpr){
+ member_lookup.Resolve (ec, ResolveFlags.Type);
+ return member_lookup;
+ } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
+ return null;
+
+ 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 Expression DoResolveType (EmitContext ec)
+ {
+ return DoResolve (ec, null, ResolveFlags.Type);
+ }
+
+ 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_const_check = ec.ConstantCheckState;
+
+ ec.ConstantCheckState = true;
+ Expr = Expr.Resolve (ec);
+ 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_const_check = ec.ConstantCheckState;
+
+ ec.ConstantCheckState = false;
+ Expr = Expr.Resolve (ec);
+ 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 or ArrayAccess
+ /// </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 = 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.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.Error118 ("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.TypeToCoreType (t.GetElementType ());
+ 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)
+ {
+ 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)
+ ig.Emit (OpCodes.Stelem_I1);
+ else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
+ ig.Emit (OpCodes.Stelem_I2);
+ else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
+ ig.Emit (OpCodes.Stelem_I4);
+ else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Stelem_I8);
+ else if (t == TypeManager.float_type)
+ ig.Emit (OpCodes.Stelem_R4);
+ else if (t == TypeManager.double_type)
+ ig.Emit (OpCodes.Stelem_R8);
+ else if (t == TypeManager.intptr_type)
+ ig.Emit (OpCodes.Stelem_I);
+ else if (t.IsValueType){
+ ig.Emit (OpCodes.Stobj, t);
+ } else
+ ig.Emit (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;
+ string ptr_type_name;
+ Type ret_type;
+
+ ptr_type_name = type.FullName + "&";
+ ret_type = Type.GetType (ptr_type_name);
+
+ //
+ // It is a type defined by the source code we are compiling
+ //
+ if (ret_type == null){
+ ret_type = mb.GetType (ptr_type_name);
+ }
+
+ 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 getters, setters;
+ static Hashtable map;
+
+ static Indexers ()
+ {
+ map = new Hashtable ();
+ }
+
+ Indexers (MemberInfo [] mi)
+ {
+ foreach (PropertyInfo property in mi){
+ MethodInfo get, set;
+
+ get = property.GetGetMethod (true);
+ if (get != null){
+ if (getters == null)
+ getters = new ArrayList ();
+
+ getters.Add (get);
+ }
+
+ set = property.GetSetMethod (true);
+ if (set != null){
+ if (setters == null)
+ setters = new ArrayList ();
+ setters.Add (set);
+ }
+ }
+ }
+
+ static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
+ {
+ Indexers ix = (Indexers) map [lookup_type];
+
+ if (ix != null)
+ return ix;
+
+ string p_name = TypeManager.IndexerPropertyName (lookup_type);
+
+ MemberInfo [] mi = TypeManager.MemberLookup (
+ caller_type, lookup_type, MemberTypes.Property,
+ BindingFlags.Public | BindingFlags.Instance, p_name);
+
+ if (mi == null || mi.Length == 0)
+ return null;
+
+ ix = new Indexers (mi);
+ map [lookup_type] = ix;
+
+ return ix;
+ }
+
+ static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
+ {
+ Indexers ix = (Indexers) map [lookup_type];
+
+ if (ix != null)
+ return ix;
+
+ ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
+ if (ix != null)
+ return ix;
+
+ Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
+ if (ifaces != null) {
+ foreach (Type itype in ifaces) {
+ ix = GetIndexersForTypeOrInterface (caller_type, itype);
+ if (ix != null)
+ return ix;
+ }
+ }
+
+ Report.Error (21, loc,
+ "Type `" + TypeManager.CSharpName (lookup_type) +
+ "' does not have any indexers defined");
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Expressions that represent an indexer call.
+ /// </summary>
+ public class IndexerAccess : Expression, IAssignMethod {
+ //
+ // Points to our "data" repository
+ //
+ MethodInfo get, set;
+ Indexers ilist;
+ 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)
+ {
+ 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.
+
+ if (ilist == null)
+ ilist = Indexers.GetIndexersForType (
+ current_type, indexer_type, loc);
+
+ //
+ // Step 2: find the proper match
+ //
+ if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
+ get = (MethodInfo) Invocation.OverloadResolve (
+ ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
+
+ if (get == null){
+ Error (154, "indexer can not be used in this context, because " +
+ "it lacks a `get' accessor");
+ 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)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ Type right_type = right_side.Type;
+
+ if (ilist == null)
+ ilist = Indexers.GetIndexersForType (
+ current_type, indexer_type, loc);
+
+ if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
+ set_arguments = (ArrayList) arguments.Clone ();
+ set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
+
+ set = (MethodInfo) Invocation.OverloadResolve (
+ ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
+ }
+
+ if (set == null){
+ Error (200, "indexer X.this [" + TypeManager.CSharpName (right_type) +
+ "] lacks a `set' accessor");
+ return null;
+ }
+
+ type = TypeManager.void_type;
+ eclass = ExprClass.IndexerAccess;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Invocation.EmitCall (ec, false, 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, false, 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 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, base_type, base_type, member,
+ AllMemberTypes, AllBindingFlags, loc);
+ if (member_lookup == null) {
+ Error (117,
+ TypeManager.CSharpName (base_type) + " does not " +
+ "contain a definition for `" + member + "'");
+ return null;
+ }
+
+ Expression left;
+
+ if (ec.IsStatic)
+ left = new TypeExpr (base_type, loc);
+ else
+ left = ec.This;
+
+ 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.This;
+
+ 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.
+ // (CanConvertImplicit 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, ITypeExpression {
+ Expression left;
+ string dim;
+
+ public ComposedCast (Expression left, string dim, Location l)
+ {
+ this.left = left;
+ this.dim = dim;
+ loc = l;
+ }
+
+ public Expression DoResolveType (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 DoResolveType (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 = array.Type.GetElementType ();
+
+ this.array = array;
+
+ string array_ptr_type_name = array_type.FullName + "*";
+
+ type = Type.GetType (array_ptr_type_name);
+ if (type == null){
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+
+ type = mb.GetType (array_ptr_type_name);
+ }
+
+ 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, array.Type.GetElementType ());
+ }
+
+ 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 = ConvertImplicitRequired (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;
+
+ string ptr_name = otype.FullName + "*";
+ type = Type.GetType (ptr_name);
+ if (type == null){
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+
+ type = mb.GetType (ptr_name);
+ }
+ 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);
+ }
+ }
+}
diff --git a/mcs/mbas/genericparser.cs b/mcs/mbas/genericparser.cs
new file mode 100644
index 00000000000..2b7a27c381c
--- /dev/null
+++ b/mcs/mbas/genericparser.cs
@@ -0,0 +1,336 @@
+//
+// 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.
+//
+
+namespace Mono.Languages
+{
+ using System;
+ using System.Reflection;
+ using System.Collections;
+ using System.IO;
+ using Mono.CSharp;
+
+ /// <summary>
+ /// Base class to support multiple Jay generated parsers
+ /// </summary>
+ public abstract class GenericParser
+ {
+ // ---------------------------------------------------
+ // Class state
+
+ // Count of errors found while parsing
+ static protected int global_errors;
+
+ // Maps extensions to specific parsers
+ static private Hashtable mapOfParsers;
+
+ // Indicates if parsing should be verbose
+ static public bool yacc_verbose_flag = false;
+
+ // Context to use
+ static public ArrayList defines;
+
+ // ---------------------------------------------------
+ // Instance state
+
+ // Name of the file we are parsing
+ protected string name;
+
+ // Input stream to parse from.
+ protected System.IO.TextReader input;
+
+ // Current namespace definition
+ protected Namespace current_namespace;
+
+ // Current typecontainer definition
+ protected TypeContainer current_container;
+
+ // ---------------------------------------------------
+ // What the descendants MUST reimplement
+
+ /// <summary>
+ /// Parses the current "input"
+ /// </summary>
+ public abstract int parse();
+
+ /// <summary>
+ /// Lists the extensions this parser can handle
+ /// </summary>
+ public abstract string[] extensions();
+ /* {
+ string [] list = { ".cs" };
+ return list;
+ } */
+
+ // ---------------------------------------------------
+ // What the descendants DONT HAVE to reimplement
+
+ /// <summary>
+ /// Initializes this parser from a file and parses it
+ /// </summary>
+ /// <param name="fileName">Name of the file to be parsed</param>
+ /// <param name="context">Context to output the parsed tree</param>
+ public int ParseFile(string fileName)
+ {
+ // file exceptions must be caught by caller
+
+ global_errors = 0;
+ name = fileName;
+ // TODO: Encoding switching as needed
+ // We are here forcing StreamReader to assume current system codepage,
+ // because normally it defaults to UTF-8
+ input = new StreamReader(fileName, System.Text.Encoding.Default);
+ //rc = context;
+ return parse();
+ }
+
+ /// <summary>
+ /// Initializes this parser from a string and parses it
+ /// </summary>
+ /// <param name="source">String to be parsed</param>
+ /// <param name="sourceName">Name of the source to be parsed (just for error reporting)</param>
+ /// <param name="context">Context to output the parsed tree</param>
+ public int ParseString(string source, string sourceName)
+ {
+ global_errors = 0;
+ name = sourceName;
+ input = new StringReader(source);
+ //rc = context;
+ return parse();
+ }
+
+ // ---------------------------------------------------
+ // Class methods
+
+ static private void MapParsers()
+ {
+
+ mapOfParsers = new Hashtable();
+
+ Assembly thisAssembly = Assembly.GetExecutingAssembly();
+ foreach(Type type in thisAssembly.GetTypes())
+ {
+ if (type.BaseType != null)
+ if (type.BaseType.FullName == "Mono.Languages.GenericParser")
+ {
+ GenericParser parser = (GenericParser)Activator.CreateInstance(type);
+ foreach(string fileExtension in parser.extensions())
+ {
+ string theFileExtension = fileExtension.ToLower();
+ if (mapOfParsers.Contains(theFileExtension))
+ Console.WriteLine("[TRACE] " + type.FullName + " can't try to parse '" + theFileExtension + "' files too");
+ else
+ mapOfParsers.Add(theFileExtension, parser);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Find the descendant parser that knows how to parse the specified file
+ /// based on the files extension
+ /// </summary>
+ /// <param name="fileName">Name of the file to be parsed</param>
+ public static GenericParser GetSpecificParserFor(string fileName)
+ {
+ int i;
+ string fileExtension;
+
+ if (mapOfParsers == null)
+ MapParsers();
+
+ if ((i = fileName.LastIndexOf(".")) < 0)
+ return null;
+ else
+ fileExtension = fileName.Substring(i).ToLower();
+
+ return (GenericParser)mapOfParsers[fileExtension];
+ }
+
+
+ public static int Tokenize(string fileName)
+ {
+ GenericParser parser = GetSpecificParserFor(fileName);
+
+ if (parser == null)
+ {
+ Console.WriteLine("Do not know how to compile " + fileName);
+ return 1;
+ }
+
+/* Stream input;
+
+ try {
+ input = File.OpenRead (input_file);
+
+ } catch {
+ Report.Error (2001, "Source file '" + input_file + "' could not be opened");
+ return 1;
+ }
+
+ using (input){
+ Tokenizer lexer = new Tokenizer (input, input_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 0;
+ }
+
+
+ /// <summary>
+ /// Find the descendant parser that knows how to parse the specified file
+ /// based on the files extension, and parses it using the chosen parser
+ /// </summary>
+ /// <param name="fileName">Name of the file to be parsed</param>
+ /// <param name="context">Context to output the parsed tree</param>
+ public static int Parse(string fileName)
+ {
+ int errors;
+ GenericParser parser = GetSpecificParserFor(fileName);
+
+ if (parser == null)
+ {
+ Console.WriteLine("Do not know how to compile " + fileName);
+ return 1;
+ }
+
+ try
+ {
+ errors = parser.ParseFile(fileName);
+ }
+ catch (FileNotFoundException ex)
+ {
+ error(2001, "Source file \'" + fileName + "\' could not be found!!!");
+ Console.WriteLine (ex);
+ return 1;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine (ex);
+ Console.WriteLine ("Compilation aborted");
+ return 1;
+ }
+
+ return errors;
+ }
+
+ // <summary>
+ // Given the @class_name name, it creates a fully qualified name
+ // based on the containing declaration space
+ // </summary>
+ protected 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>
+ protected 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;
+ }
+ }
+
+ // <summary>
+ // Used to report back to the user the result of a declaration
+ // in the current declaration space
+ // </summary>
+ protected void CheckDef (bool result, string name, Location l)
+ {
+ if (result)
+ return;
+ CheckDef (AdditionResult.NameExists, name, l);
+ }
+
+
+ /// <summary>
+ /// Emits error messages and increments a global count of them
+ /// </summary>
+ /// <param name="code"></param>
+ /// <param name="desc"></param>
+ static public void error (int code, string desc)
+ {
+ Console.WriteLine ("error MC"+code+": "+ desc);
+ global_errors++;
+ }
+
+ // Emits error messages with location info.
+ // FIXME : Ideally, all error reporting should happen
+ // with Report.Error but how do you get at that non-static
+ // method everywhere you need it ?
+ static public void error (int code, Mono.CSharp.Location l, string text)
+ {
+ Console.WriteLine (l.Name + "(" + l.Row + ",?" + /*l.Col +*/
+ "): error MC" + code + ": " + text);
+ global_errors++;
+ }
+
+ // ---------------------------------------------------
+ // Constructors
+
+ public GenericParser()
+ {
+ // DO NOTHING
+ }
+
+ }
+}
+
+
+
diff --git a/mcs/mbas/interface.cs b/mcs/mbas/interface.cs
new file mode 100644
index 00000000000..1d2dc2f5cca
--- /dev/null
+++ b/mcs/mbas/interface.cs
@@ -0,0 +1,1061 @@
+//
+// 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)) != 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)) != 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 = 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, Location);
+ }
+
+ //
+ // 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);
+ 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, Location);
+
+ 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);
+ 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 (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, Location);
+
+ 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);
+ 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, Location);
+
+ 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) {
+ 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 (!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;
+ }
+
+ /// <summary>
+ /// Applies all the attributes.
+ /// </summary>
+ public override bool Define (TypeContainer parent)
+ {
+ if (OptAttributes != null) {
+ EmitContext ec = new EmitContext (parent, this, Location, null, null,
+ ModFlags, false);
+ Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location);
+ }
+
+ return true;
+ }
+
+ 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 readonly 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)
+ {
+ Type ret = ds.ResolveType (ReturnType, false, Location);
+ 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);
+ }
+ }
+}
diff --git a/mcs/mbas/literal.cs b/mcs/mbas/literal.cs
new file mode 100644
index 00000000000..a307030db6a
--- /dev/null
+++ b/mcs/mbas/literal.cs
@@ -0,0 +1,187 @@
+//
+// 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 ()
+ {
+ if (Null != null)
+ throw new Exception ("More than one null has been created!");
+ 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);
+ }
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/mcs/mbas/location.cs b/mcs/mbas/location.cs
new file mode 100644
index 00000000000..72c4485aef9
--- /dev/null
+++ b/mcs/mbas/location.cs
@@ -0,0 +1,154 @@
+//
+// 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>
+ /// 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 Hashtable map;
+ static Hashtable sym_docs;
+ static ArrayList list;
+ static int global_count;
+ static int module_base;
+
+ public readonly static Location Null;
+
+ static Location ()
+ {
+ map = new Hashtable ();
+ list = new ArrayList ();
+ sym_docs = new Hashtable ();
+ global_count = 0;
+ module_base = 0;
+ Null.token = -1;
+ }
+
+ static public void Push (string name)
+ {
+ map.Remove (global_count);
+ map.Add (global_count, name);
+ list.Add (global_count);
+ module_base = global_count;
+ }
+
+ public Location (int row)
+ {
+ if (row < 0)
+ token = -1;
+ else {
+ token = module_base + row;
+ if (global_count < token)
+ global_count = token;
+ }
+ }
+
+ public override string ToString ()
+ {
+ return Name + ": (" + Row + ")";
+ }
+
+ /// <summary>
+ /// Whether the Location is Null
+ /// </summary>
+ static public bool IsNull (Location l)
+ {
+ return l.token == -1;
+ }
+
+ public string Name {
+ get {
+ int best = 0;
+
+ if (token < 0)
+ return "Internal";
+
+ foreach (int b in list){
+ if (token > b)
+ best = b;
+ }
+ return (string) map [best];
+ }
+ }
+
+ public int Row {
+ get {
+ int best = 0;
+
+ if (token < 0)
+ return 1;
+
+ foreach (int b in list){
+ if (token > b)
+ best = b;
+ }
+ return token - best;
+ }
+ }
+
+ // 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 {
+ ISymbolWriter sw = CodeGen.SymbolWriter;
+ ISymbolDocumentWriter doc;
+
+ if (token < 0)
+ return null;
+
+ // If we don't have a symbol writer, return null.
+ if (sw == null)
+ return null;
+
+ string path = Path.GetFullPath (Name);
+
+ if (sym_docs.Contains (path))
+ // If we already created an ISymbolDocumentWriter
+ // instance for this document, return it.
+ doc = (ISymbolDocumentWriter) sym_docs [path];
+ else {
+ // Create a new ISymbolDocumentWriter instance and
+ // store it in the hash table.
+ doc = sw.DefineDocument (path, SymLanguageType.CSharp,
+ SymLanguageVendor.Microsoft,
+ SymDocumentType.Text);
+
+ sym_docs.Add (path, doc);
+ }
+
+ return doc;
+ }
+ }
+ }
+}
diff --git a/mcs/mbas/makefile b/mcs/mbas/makefile
new file mode 100644
index 00000000000..c1336de45ad
--- /dev/null
+++ b/mcs/mbas/makefile
@@ -0,0 +1,50 @@
+CSC=mcs
+CSCFLAGS=/nologo /optimize /target:exe /r:System.dll /r:Mono.GetOptions.dll /out:mbas.exe
+
+COMPILER_SOURCES = \
+ AssemblyInfo.cs \
+ assign.cs \
+ attribute.cs \
+ cfold.cs \
+ class.cs \
+ codegen.cs \
+ const.cs \
+ constant.cs \
+ decl.cs \
+ delegate.cs \
+ driver.cs \
+ enum.cs \
+ ecore.cs \
+ expression.cs \
+ genericparser.cs \
+ interface.cs \
+ literal.cs \
+ location.cs \
+ mb-parser.cs \
+ mb-tokenizer.cs \
+ modifiers.cs \
+ module.cs \
+ namespace.cs \
+ parameter.cs \
+ pending.cs \
+ report.cs \
+ rootcontext.cs \
+ statement.cs \
+ statementCollection.cs \
+ support.cs \
+ tree.cs \
+ typemanager.cs
+
+all: mbas.exe
+
+test: mbas.exe
+ mono mbas.exe --main WriteOK testmbas/WriteOK.vb
+
+mbas.exe: $(COMPILER_SOURCES)
+ $(CSC) $(CSCFLAGS) $(COMPILER_SOURCES)
+
+clean:
+ rm -f mbas.exe y.output mbas.pdb *~ .*~ mb-parser.cs mbas.log response
+
+mb-parser.cs: mb-parser.jay
+ ../jay/jay -ctv < ../jay/skeleton.cs mb-parser.jay > mb-parser.cs
diff --git a/mcs/mbas/makefile.gnu b/mcs/mbas/makefile.gnu
new file mode 100644
index 00000000000..bacfdcc3eac
--- /dev/null
+++ b/mcs/mbas/makefile.gnu
@@ -0,0 +1,60 @@
+MCS = mcs
+MCS_FLAGS = /target:exe $(MCS_DEFINES)
+INSTALL = /usr/bin/install
+prefix = /usr
+
+COMPILER_SOURCES = \
+ AssemblyInfo.cs \
+ assign.cs \
+ attribute.cs \
+ cfold.cs \
+ class.cs \
+ codegen.cs \
+ const.cs \
+ constant.cs \
+ decl.cs \
+ delegate.cs \
+ driver.cs \
+ enum.cs \
+ ecore.cs \
+ expression.cs \
+ genericparser.cs \
+ interface.cs \
+ literal.cs \
+ location.cs \
+ mb-parser.cs \
+ mb-tokenizer.cs \
+ modifiers.cs \
+ module.cs \
+ namespace.cs \
+ parameter.cs \
+ pending.cs \
+ report.cs \
+ rootcontext.cs \
+ statement.cs \
+ statementCollection.cs \
+ support.cs \
+ tree.cs \
+ typemanager.cs
+
+all: mbas.exe
+
+mbas.exe: $(COMPILER_SOURCES)
+ $(MCS) $(MCSFLAGS) /r:Mono.GetOptions.dll /out:mbas.exe $(COMPILER_SOURCES)
+
+clean:
+ rm -f mbas.exe y.output mbas.pdb *~ .*~ mb-parser.cs mbas.log response
+
+mb-parser.cs: mb-parser.jay
+ ../jay/jay -ctv < ../jay/skeleton.cs mb-parser.jay > mb-parser.cs
+
+install: all
+ mkdir -p $(prefix)/bin/
+ $(INSTALL) -m 755 mbas.exe $(prefix)/bin/
+
+test:
+ mono mbas.exe --main WriteOK testmbas/WriteOK.vb
+
+test-gtk:
+ mono mbas.exe testmbas/gtk.vb -r gtk-sharp
+
diff --git a/mcs/mbas/mb-parser.jay b/mcs/mbas/mb-parser.jay
new file mode 100644
index 00000000000..b37bb9cee4a
--- /dev/null
+++ b/mcs/mbas/mb-parser.jay
@@ -0,0 +1,2954 @@
+%{
+//
+// Mono.MonoBASIC.Parser.cs (from .jay): The Parser for the MonoBASIC compiler
+//
+// Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)
+//
+// Licensed under the terms of the GNU GPL
+//
+// Copyright (C) 2001 A Rafael D Teixeira
+//
+// TODO:
+// Nearly everything
+//
+
+namespace Mono.MonoBASIC
+{
+ using System.Text;
+ using System;
+ using System.Reflection;
+ using System.Collections;
+ using Mono.Languages;
+ using Mono.CSharp;
+
+ /// <summary>
+ /// The MonoBASIC Parser
+ /// </summary>
+ public class Parser : GenericParser
+ {
+
+
+ /// <summary>
+ /// Current block is used to add statements as we find
+ /// them.
+ /// </summary>
+ Block current_block;
+
+ /// <summary>
+ /// Tmp block is used to store block endings in if/select's
+ /// </summary>
+ Block tmp_block;
+
+ /// <summary>
+ /// Tmp block is used to store tmp copies of expressions
+ /// </summary>
+ Expression tmp_expr;
+
+ /// <summary>
+ /// Tmp catch is used to store catch clauses in try..catch..finally
+ /// </summary>
+ ArrayList tmp_catch_clauses;
+
+ /// <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>
+ /// This are used when parsing parameters in property
+ /// declarations.
+ /// </summary>
+ Parameters set_parameters;
+ Parameters get_parameters;
+
+ /// <summary>
+ /// This is used by the sub_header parser to store modifiers
+ /// to be passed to sub/constructor
+ /// </summary>
+ int current_modifiers;
+
+ /// <summary>
+ /// This is used by the sub_header parser to store attributes
+ /// to be passed to sub/constructor
+ /// </summary>
+ Attributes current_attributes;
+
+ /// <summary>
+ /// Using during property parsing to describe the implicit
+ /// value parameter that is passed to the "set" accessor
+ /// method
+ /// </summary>
+ string get_implicit_value_parameter_name;
+
+ // <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 get_implicit_value_parameter_type;
+
+ /// <summary>
+ /// Using during property parsing to describe the implicit
+ /// value parameter that is passed to the "set" accessor
+ /// method
+ /// </summary>
+ string set_implicit_value_parameter_name;
+
+ // <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 set_implicit_value_parameter_type;
+
+ // An out-of-band stack.
+ //
+ Stack oob_stack;
+
+ DoOptions do_type;
+ //
+ // Switch stack.
+ //
+ Stack switch_stack;
+
+ bool UseExtendedSyntax; // for ".mbs" files
+
+ public override string[] extensions()
+ {
+ string [] list = { ".vb", ".mbs" };
+ return list;
+ }
+
+%}
+
+%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 MonoBASIC keywords
+ */
+%token ADDHANDLER
+%token ADDRESSOF
+%token ALIAS
+%token AND
+%token ANDALSO
+%token ANSI
+%token AS
+%token ASSEMBLY
+%token AUTO
+%token BOOLEAN
+%token BYREF
+%token BYTE
+%token BYVAL
+%token CALL
+%token CASE
+%token CATCH
+%token CBOOL
+%token CBYTE
+%token CCHAR
+%token CDATE
+%token CDEC
+%token CDBL
+%token CHAR
+%token CINT
+%token CLASS
+%token CLNG
+%token COBJ
+//%token COMPARE
+%token CONST
+%token CSHORT
+%token CSNG
+%token CSTR
+%token CTYPE
+%token DATE
+%token DECIMAL
+%token DECLARE
+%token DEFAULT
+%token DELEGATE
+%token DESCRIPTION // MonoBASIC extension
+%token DIM
+%token DO
+%token DOUBLE
+%token EACH
+%token ELSE
+%token ELSEIF
+%token END
+%token ENUM
+%token EOL
+%token ERASE
+%token ERROR
+%token EVENT
+%token EXIT
+//%token EXPLICIT
+%token FALSE
+%token FINALLY
+%token FOR
+%token FRIEND
+%token FUNCTION
+%token GET
+%token GETTYPE
+%token GOTO
+%token HANDLES
+%token IF
+%token IMPLEMENTS
+%token IMPORTS
+%token IN
+%token INHERITS
+%token INTEGER
+%token INTERFACE
+%token IS
+%token LET
+%token LIB
+%token LIKE
+%token LONG
+%token LOOP
+%token ME
+%token MOD
+%token MODULE
+%token MUSTINHERIT
+%token MUSTOVERRIDE
+%token MYBASE
+%token MYCLASS
+%token NAMESPACE
+%token NEW
+%token NEXT
+%token NOT
+%token NOTHING
+%token NOTINHERITABLE
+%token NOTOVERRIDABLE
+%token OBJECT
+%token ON
+%token OPTION
+%token OPTIONAL
+%token OR
+%token ORELSE
+%token OVERLOADS
+%token OVERRIDABLE
+%token OVERRIDES
+%token PARAMETER // MonoBASIC extension
+%token PARAM_ARRAY
+%token PRESERVE
+%token PRIVATE
+%token PROPERTY
+%token PROTECTED
+%token PUBLIC
+%token RAISEEVENT
+%token READONLY
+%token REDIM
+%token REM
+%token REMOVEHANDLER
+%token RESUME
+%token RETURN
+%token SELECT
+%token SET
+%token SHADOWS
+%token SHARED
+%token SHORT
+%token SINGLE
+%token SIZEOF
+%token STATIC
+%token STEP
+%token STOP
+%token STRING
+%token STRUCTURE
+%token SUB
+%token SUMMARY // MonoBASIC extension
+%token SYNCLOCK
+%token THEN
+%token THROW
+%token TO
+%token TRUE
+%token TRY
+%token TYPEOF
+%token UNICODE
+%token UNTIL
+%token VARIANT
+%token WHEN
+%token WHILE
+%token WITH
+%token WITHEVENTS
+%token WRITEONLY
+%token XOR
+
+/* MonoBASIC single character operators/punctuation. */
+%token OPEN_BRACKET "["
+%token CLOSE_BRACKET "]"
+%token OPEN_PARENS "("
+%token CLOSE_PARENS ")"
+%token DOT "."
+%token COMMA ","
+%token COLON ":"
+
+%token PLUS "+"
+%token MINUS "-"
+%token ASSIGN "="
+%token OP_LT "<"
+%token OP_GT ">"
+%token STAR "*"
+%token PERCENT "%"
+%token DIV "/"
+%token OP_EXP "^"
+%token INTERR "?"
+%token OP_IDIV "\\"
+%token OP_CONCAT "&"
+
+/* MonoBASIC multi-character operators. */
+%token OP_LE "<="
+%token OP_GE ">="
+%token OP_EQ "=="
+%token OP_NE "<>"
+%token OP_AND //"and"
+%token OP_OR //"or"
+%token OP_XOR //"xor"
+%token OP_MODULUS //"mod"
+%token OP_MULT_ASSIGN "*="
+%token OP_DIV_ASSIGN "/="
+%token OP_IDIV_ASSIGN "\\="
+%token OP_ADD_ASSIGN "+="
+%token OP_SUB_ASSIGN "-="
+%token OP_CONCAT_ASSIGN "&="
+%token OP_EXP_ASSIGN "^="
+
+/* Numbers */
+%token LITERAL_INTEGER "int literal"
+%token LITERAL_SINGLE "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 BITWISE_NOT CARRET UMINUS
+%nonassoc OP_INC OP_DEC
+%left OPEN_PARENS
+%left OPEN_BRACKET OPEN_BRACE
+%left DOT
+%nonassoc HIGHPREC
+
+%start compilation_unit
+%%
+
+compilation_unit
+ : opt_imports_directives
+ opt_attributes
+ opt_declarations
+ EOF
+ {
+ $$ = $3;
+ }
+ ;
+
+opt_declarations
+ : /* empty */
+ | declarations
+ ;
+
+declarations
+ : declaration
+ | declarations declaration
+ ;
+
+declaration
+ : namespace_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 if ($1 is Module){
+ Module m = (Module) $1;
+ mod_flags = m.ModFlags;
+ name = m.Name;
+ } else
+ break;
+
+ if ((mod_flags & (Modifiers.PRIVATE|Modifiers.PROTECTED)) != 0){
+ Report.Error (
+ 1527, lexer.Location,
+ "Namespace elements cannot be explicitly " +
+ "declared private or protected in '" + name + "'");
+ }
+ }
+ ;
+
+qualified_identifier
+ : IDENTIFIER
+ | qualified_identifier DOT IDENTIFIER
+ {
+ $$ = (($1).ToString ()) + "." + ($3.ToString ());
+ }
+ ;
+opt_imports_directives
+ : /* empty */
+ | imports_directives
+ ;
+
+imports_directives
+ : imports_directive
+ | imports_directives imports_directive
+ ;
+
+imports_directive
+ : /* imports_alias_directive
+ | */ imports_namespace_directive
+ ;
+
+imports_namespace_directive
+ : IMPORTS qualified_identifier EOL
+ {
+ current_namespace.Using ((string) $2, lexer.Location);
+ }
+ ;
+
+opt_attributes
+ : /* empty */
+ | OP_LT attribute_list OP_GT
+ ;
+
+attribute_list
+ : attribute
+ | attribute_list COMMA attribute
+ ;
+
+attribute
+ : IDENTIFIER
+ ;
+
+namespace_declaration
+ : NAMESPACE qualified_identifier EOL
+ {
+ current_namespace = RootContext.Tree.RecordNamespace(current_namespace, name, (string)$2);
+ }
+ opt_imports_directives
+ opt_declarations
+ END NAMESPACE EOL
+ {
+ current_namespace = current_namespace.Parent;
+ }
+ ;
+
+type_declaration
+ : opt_attributes
+ opt_modifiers
+ {
+ current_attributes = (Attributes) $1;
+ current_modifiers = (int) $2;
+ }
+ type_spec_declaration
+ ;
+
+type_spec_declaration
+ : class_declaration
+ | module_declaration
+ | interface_declaration
+ | delegate_declaration
+// | struct_declaration
+// | enum_declaration
+ ;
+
+class_declaration
+ : CLASS IDENTIFIER EOL opt_class_base
+ {
+ Class new_class;
+ string name;
+
+ name = MakeName ((string) $2);
+
+ new_class = new Class (current_container, name, current_modifiers,
+ (Attributes) current_attributes, lexer.Location);
+
+ current_container = new_class;
+ current_container.Namespace = current_namespace;
+ RootContext.Tree.RecordDecl (name, new_class);
+ }
+ opt_class_member_declarations
+ END CLASS EOL
+ {
+ Class new_class = (Class) current_container;
+ new_class.Bases = (ArrayList) $4;
+
+ current_container = current_container.Parent;
+ CheckDef (current_container.AddClass (new_class), new_class.Name, new_class.Location);
+
+ $$ = new_class;
+ }
+ ;
+
+opt_class_base
+ : /* empty */ { $$ = null; }
+ | class_base { $$ = $1; }
+ ;
+
+class_base
+ : inherits_or_implements type_list EOL { $$ = $2; }
+ ;
+
+inherits_or_implements
+ : INHERITS
+ | IMPLEMENTS
+ ;
+
+opt_modifiers
+ : /* empty */ { $$ = (int) 0; current_modifiers = 0; }
+ | modifiers { $$ = $1; current_modifiers = (int) $1; }
+ ;
+
+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
+ : PUBLIC { $$ = Modifiers.PUBLIC; }
+ | PROTECTED { $$ = Modifiers.PROTECTED; }
+ | PRIVATE { $$ = Modifiers.PRIVATE; }
+ | STATIC { $$ = Modifiers.STATIC; }
+ /* FIXME: FRIEND and PROTECTED FRIEND are missing */
+ ;
+
+module_declaration
+ : MODULE IDENTIFIER EOL
+ {
+ Module new_module;
+ string name;
+ // FIXME : Check for valid module modifiers
+ name = MakeName((string) $2);
+ new_module = new Module(current_container,
+ name,
+ current_modifiers,
+ (Attributes) current_attributes,
+ lexer.Location);
+ current_container = new_module;
+ current_container.Namespace = current_namespace;
+ RootContext.Tree.RecordDecl(name, new_module);
+ }
+ opt_class_member_declarations
+ END MODULE EOL
+ {
+ Module new_module = (Module)current_container;
+
+ current_container = current_container.Parent;
+ CheckDef (current_container.AddClass(new_module), new_module.Name, new_module.Location);
+
+ $$ = new_module;
+ }
+ ;
+
+opt_class_member_declarations
+ : /* empty */
+ | class_member_declarations
+ ;
+
+class_member_declarations
+ : class_member_declaration
+ | class_member_declarations class_member_declaration
+ ;
+
+class_member_declaration
+ : opt_attributes
+ opt_modifiers
+ {
+ current_attributes = (Attributes) $1;
+ current_modifiers = (int) $2;
+ }
+ class_member_declarator
+ {
+ $$ = $3;
+ }
+ ;
+
+class_member_declarator
+ : constructor_declaration
+ | method_declaration
+ {
+ Method method = (Method) $1;
+ CheckDef (current_container.AddMethod (method), method.Name, method.Location);
+ }
+ | field_declaration
+ | property_declaration
+// | event_declaration
+ | withevents_declaration /* This is a field but must be treated specially, see below */
+ | type_declaration
+ ;
+
+
+method_declaration
+ : sub_declaration
+ | func_declaration
+ ;
+
+sub_declaration
+ : SUB IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_evt_handler EOL
+ {
+
+ current_local_parameters = (Parameters) $4;
+ start_block();
+ }
+ opt_local_declarations
+ {
+ /* This is WEIRD: declaring a method (sub) in a module as static will
+ trigger a syntax error, but the same methods MUST be static in order
+ to be properly called
+ */
+ if (current_container is Module) {
+ if (current_modifiers == Modifiers.STATIC) {
+ Report.Error (30810, lexer.Location, "Methods cannot be declared 'Static'");
+ }
+ else
+ {
+ current_modifiers = Modifiers.STATIC;
+ }
+ }
+ }
+ opt_statement_list
+ END SUB EOL
+ {
+ Method method = new Method (TypeManager.system_void_expr, (int) current_modifiers, (string) $2,
+ (Parameters) current_local_parameters, null, lexer.Location);
+
+ method.Block = (Block) end_block();
+ $$ = method;
+
+ if ($6 != null) { /* we have an event handler to take care of */
+ // This wouldn't work: AddHandler ((Expression)$6, (string) $2);
+ string evt_def = ((MemberAccess)$6).ToString();
+ int pos = evt_def.LastIndexOf (".");
+ string evt_target = ((string) $2).Substring (0, pos);
+
+ foreach (Property p in current_container.Properties) {
+ if (p.Name == evt_target) {
+ // FIXME: See below
+ // RemoveHandler (p.Set.Block, (Expression)$6, (string) $2);
+ AddHandler (p.Set.Block, (Expression)$6, (string) $2);
+ break;
+ }
+ }
+
+
+ }
+ }
+ ;
+
+func_declaration
+ : FUNCTION IDENTIFIER
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS AS type EOL
+ {
+
+ current_local_parameters = (Parameters) $4;
+ start_block();
+ }
+ opt_local_declarations
+ {
+ /* This is WEIRD: declaring a method (sub) in a module as static will
+ trigger a syntax error, but the same methods MUST be static in order
+ to be properly called
+ */
+ if (current_container is Module) {
+ if (current_modifiers == Modifiers.STATIC) {
+ Report.Error (30810, lexer.Location, "Methods cannot be declared 'Static'");
+ }
+ else
+ {
+ current_modifiers = Modifiers.STATIC;
+ }
+ }
+ // Add local var declaration
+ // for return value
+ ArrayList retval = new ArrayList ();
+ retval.Add (new VariableDeclaration ((string) $2, null, lexer.Location));
+ declare_local_variables ((Expression) $7, retval, lexer.Location);
+ }
+ opt_statement_list
+ END FUNCTION EOL
+ {
+ Method method = new Method ((Expression) $7, (int) current_modifiers, (string) $2,
+ (Parameters) current_local_parameters, null, lexer.Location);
+
+ method.Block = end_block();
+ $$ = method;
+
+ }
+ ;
+
+interface_declaration
+ : INTERFACE IDENTIFIER EOL
+ {
+ Interface new_interface;
+ string full_interface_name = MakeName ((string) $2);
+
+ new_interface = new Interface (current_container, full_interface_name, (int) current_modifiers,
+ (Attributes) current_attributes, 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
+ {
+ Interface new_interface = (Interface) current_interface;
+
+ if ($5 != null)
+ new_interface.Bases = (ArrayList) $5;
+
+ current_interface = null;
+ CheckDef (current_container.AddInterface (new_interface),
+ new_interface.Name, new_interface.Location);
+
+ }
+ END INTERFACE EOL
+ ;
+
+opt_interface_base
+ : /* empty */ { $$ = null; }
+ | interface_base
+ ;
+
+interface_base
+ : INHERITS interface_type_list { $$ = $2; }
+ ;
+
+interface_type_list
+ : interface_type
+ {
+ ArrayList interfaces = new ArrayList ();
+
+ interfaces.Add ($1);
+ $$ = interfaces;
+ }
+ | interface_type_list COMMA interface_type
+ {
+ ArrayList interfaces = (ArrayList) $1;
+ interfaces.Add ($3);
+ $$ = interfaces;
+ }
+ ;
+
+interface_body
+ : opt_interface_member_declarations
+ ;
+
+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);
+ }
+ ;
+
+opt_new
+ : /* empty */ { $$ = false; }
+ | NEW { $$ = true; }
+ ;
+
+interface_method_declaration
+ : SUB IDENTIFIER
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS EOL
+ {
+ $$ = new InterfaceMethod (TypeManager.system_void_expr, (string) $2, false,
+ (Parameters) $4, current_attributes, lexer.Location);
+ }
+ | FUNCTION IDENTIFIER
+ OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS AS type
+ {
+ $$ = new InterfaceMethod (
+ (Expression) $7, (string) $2, false, (Parameters) $4,
+ current_attributes, lexer.Location);
+ }
+ ;
+
+interface_property_declaration
+ : PROPERTY IDENTIFIER
+ OPEN_PARENS
+ opt_formal_parameter_list
+ CLOSE_PARENS opt_type_spec EOL
+ {
+ // FIXME we MUST pass property parameters
+ $$ = new InterfaceProperty ((Expression) $6, (string) $2, false,
+ false, false, current_attributes,
+ lexer.Location);
+ }
+ ;
+
+interface_event_declaration
+ : opt_attributes opt_new EVENT type IDENTIFIER EOL
+ {
+ $$ = new InterfaceEvent ((Expression) $4, (string) $5, (bool) $2, (Attributes) $1,
+ lexer.Location);
+ }
+ ;
+
+property_declaration
+ : PROPERTY IDENTIFIER opt_property_parameters AS type EOL
+ {
+ get_implicit_value_parameter_type = (Expression) $5;
+ get_implicit_value_parameter_name = (string) $2;
+
+ current_local_parameters = (Parameters) $3;
+ if (current_local_parameters != Parameters.EmptyReadOnlyParameters) {
+ get_parameters = current_local_parameters.Copy (lexer.Location);
+ set_parameters = current_local_parameters.Copy (lexer.Location);
+ }
+ else
+ {
+ get_parameters = Parameters.EmptyReadOnlyParameters;
+ set_parameters = new Parameters (null, null ,lexer.Location);
+ }
+ lexer.PropertyParsing = true;
+
+ $$ = lexer.Location;
+ }
+ accessor_declarations
+ END PROPERTY EOL
+ {
+ lexer.PropertyParsing = false;
+
+ Property prop;
+ Pair pair = (Pair) $8;
+ Accessor get_block = (Accessor) pair.First;
+ Accessor set_block = (Accessor) pair.Second;
+ Location loc = lexer.Location;
+
+ prop = new Property ((Expression) $5, (string) $2, current_modifiers, get_block, set_block,
+ current_attributes, loc, set_implicit_value_parameter_name,
+ get_parameters, set_parameters);
+
+ CheckDef (current_container.AddProperty (prop), prop.Name, loc);
+ get_implicit_value_parameter_type = null;
+ set_implicit_value_parameter_type = null;
+ get_parameters = null;
+ set_parameters = null;
+ current_local_parameters = null;
+ }
+ ;
+
+opt_property_parameters
+ : /* empty */
+ {
+ $$ = Parameters.EmptyReadOnlyParameters; ;
+ }
+ | OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ $$ = $2;
+ }
+ ;
+
+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 EOL
+ {
+ current_local_parameters = get_parameters;
+
+ lexer.PropertyParsing = false;
+
+ start_block();
+ // Add local var declaration
+ // for return value
+ ArrayList retval = new ArrayList ();
+ retval.Add (new VariableDeclaration (get_implicit_value_parameter_name, null, lexer.Location));
+ declare_local_variables (get_implicit_value_parameter_type, retval, lexer.Location);
+
+ }
+ opt_statement_list
+ END GET EOL
+ {
+ $$ = new Accessor ((Block) end_block(), (Attributes) $1);
+ current_local_parameters = null;
+ lexer.PropertyParsing = true;
+ }
+ ;
+
+set_accessor_declaration
+ : opt_attributes SET opt_set_parameter EOL
+ {
+
+ Parameter implicit_value_parameter = new Parameter (
+ set_implicit_value_parameter_type,
+ set_implicit_value_parameter_name,
+ Parameter.Modifier.NONE, null);
+
+ current_local_parameters = set_parameters;
+ current_local_parameters.AppendParameter (implicit_value_parameter);
+
+ start_block();
+ lexer.PropertyParsing = false;
+ }
+ opt_statement_list
+ END SET EOL
+ {
+ $$ = new Accessor ((Block) end_block(), (Attributes) $1);
+ current_local_parameters = null;
+ lexer.PropertyParsing = true;
+ }
+ ;
+
+opt_set_parameter
+ : /* empty */
+ {
+ set_implicit_value_parameter_type = (Expression) TypeManager.system_object_expr;
+ set_implicit_value_parameter_name = "Value";
+ }
+ | OPEN_PARENS opt_identifier opt_type_spec CLOSE_PARENS
+ {
+ /* FIXME: possible syntax error which must be caught
+ Set ( As <type>) is currently (and wrongly so) legal
+ */
+ set_implicit_value_parameter_type = (Expression) $3;
+ if ($2 != null)
+ set_implicit_value_parameter_name = (string) $2;
+ else
+ set_implicit_value_parameter_name = "Value";
+ }
+ ;
+
+field_declaration
+ : opt_dim_stmt
+ variable_declarators EOL
+ {
+ int mod = (int) current_modifiers;
+
+
+ VariableDeclaration.FixupTypes ((ArrayList) $2);
+ VariableDeclaration.FixupArrayTypes ((ArrayList) $2);
+
+ if (current_container is Module)
+ mod = mod | Modifiers.STATIC;
+
+ foreach (VariableDeclaration var in (ArrayList) $2){
+ Location l = var.Location;
+
+ Field field = new Field (var.type, mod, var.identifier,
+ var.expression_or_array_initializer,
+ (Attributes) null, l);
+
+ CheckDef (current_container.AddField (field), field.Name, l);
+ }
+ }
+ ;
+
+withevents_declaration
+ : WITHEVENTS variable_declarators EOL
+ {
+ /* WithEvents Fields must be resolved into properties
+ with a bit of magic behind the scenes */
+
+ VariableDeclaration.FixupTypes ((ArrayList) $2);
+
+ foreach (VariableDeclaration var in (ArrayList) $2) {
+ // 1 - We create a private field
+ Location l = var.Location;
+ Property prop;
+ if ((current_modifiers & Modifiers.STATIC) > 0)
+ Report.Error (30234, l, "'Static' is not valid on a WithEvents declaration.");
+
+ Field field = new Field (var.type, Modifiers.PRIVATE, "_" + var.identifier,
+ var.expression_or_array_initializer,
+ (Attributes) null, l);
+
+ CheckDef (current_container.AddField (field), field.Name, l);
+
+ // 2 - Public property
+
+ prop = BuildSimpleProperty (var.type, (string) var.identifier,
+ field, (int) current_modifiers,
+ (Attributes) current_attributes, l);
+
+ CheckDef (current_container.AddProperty (prop), prop.Name, l);
+ }
+ }
+ ;
+
+opt_dim_stmt
+ : /* empty */
+ | DIM
+ ;
+
+delegate_declaration
+ : DELEGATE SUB
+ IDENTIFIER OPEN_PARENS
+ opt_formal_parameter_list
+ CLOSE_PARENS
+ EOL
+ {
+ Location l = lexer.Location;
+ Mono.CSharp.Delegate del = new Mono.CSharp.Delegate (current_container, TypeManager.system_void_expr,
+ (int) current_modifiers,
+ MakeName ((string) $3), (Parameters) $5,
+ (Attributes) current_attributes, l);
+
+ del.Namespace = current_namespace;
+ CheckDef (current_container.AddDelegate (del), del.Name, l);
+ }
+ | DELEGATE FUNCTION
+ IDENTIFIER OPEN_PARENS
+ opt_formal_parameter_list
+ CLOSE_PARENS AS type
+ {
+ Location l = lexer.Location;
+ Mono.CSharp.Delegate del = new Mono.CSharp.Delegate (
+ current_container,
+ (Expression) $8, (int) current_modifiers, MakeName ((string) $3),
+ (Parameters) $5, (Attributes) current_attributes, l);
+
+ del.Namespace = current_namespace;
+ CheckDef (current_container.AddDelegate (del), del.Name, l);
+ }
+ ;
+
+opt_evt_handler
+ : /* empty */
+ { $$ = null; }
+ | HANDLES qualified_identifier
+ {
+ $$ = (Expression) DecomposeQI ((string)$2, lexer.Location);
+ }
+ ;
+
+constructor_declaration
+ : constructor_declarator
+ opt_local_declarations
+ opt_statement_list
+ {
+ Constructor c = (Constructor) $1;
+ c.Block = (Block) end_block();
+ c.ModFlags = (int) current_modifiers;
+ c.OptAttributes = (Attributes) null;
+
+ CheckDef (current_container.AddConstructor (c), c.Name, c.Location);
+ current_local_parameters = null;
+ }
+ END SUB EOL
+ ;
+
+constructor_declarator
+ : SUB NEW OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS EOL
+ {
+ current_local_parameters = (Parameters) $4;
+ start_block();
+ oob_stack.Push (lexer.Location);
+
+ Location l = (Location) oob_stack.Pop ();
+ $$ = new Constructor ((string) "New", (Parameters) $4, (ConstructorInitializer) null, l);
+ }
+ ;
+
+
+opt_formal_parameter_list
+ : /* empty */
+ {
+ $$ = Parameters.EmptyReadOnlyParameters;
+ }
+ | formal_parameter_list
+ {
+ $$ = $1;
+ //Parameter p = ((Parameters) $1).FixedParameters[0];
+ }
+ ;
+
+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 ();
+
+ pars.Add ($1);
+ $$ = pars;
+ }
+ | fixed_parameters COMMA fixed_parameter
+ {
+ ArrayList pars = (ArrayList) $1;
+
+ pars.Add ($3);
+ $$ = $1;
+ }
+ ;
+
+fixed_parameter
+ : opt_attributes
+ opt_parameter_modifier
+ IDENTIFIER opt_type_spec opt_variable_initializer
+ {
+ Parameter.Modifier pm = (Parameter.Modifier)$2;
+ bool opt_parm = ((pm & Parameter.Modifier.OPTIONAL) != 0);
+
+ if (opt_parm && ($5 == null))
+ Report.Error (999, "Optional parameters must have a default value");
+
+ if (opt_parm)
+ pm = Parameter.Modifier.NONE; //FIXME: should take into account BYREF
+
+ $$ = new Parameter ((Expression) $4, (string) $3,
+ pm, (Attributes) $1, (Expression) $5, opt_parm);
+ }
+ ;
+
+parameter_array
+ : PARAM_ARRAY IDENTIFIER opt_parens AS type
+ {
+ $$ = new Parameter ((Expression) $5, (string) $2, Parameter.Modifier.PARAMS, null);
+ // note ("type must be a single-dimension array type");
+ }
+ ;
+
+opt_parens
+ : /* empty */
+ | OPEN_PARENS CLOSE_PARENS
+ ;
+
+opt_type_spec
+ : /* empty */ { $$ = (Expression) TypeManager.system_object_expr; }
+ | AS type { $$ = (Expression) $2; };
+ ;
+
+opt_parameter_modifier
+ : /* empty */ { $$ = Parameter.Modifier.VAL; }
+ | parameter_modifiers { $$ = $1; }
+ ;
+
+parameter_modifiers
+ : parameter_modifiers parameter_modifier { $$ = (Parameter.Modifier)$1 | (Parameter.Modifier)$2; }
+ | parameter_modifier { $$ = $1; }
+ ;
+
+parameter_modifier
+ : BYREF { $$ = Parameter.Modifier.REF | Parameter.Modifier.ISBYREF; }
+ | BYVAL { $$ = Parameter.Modifier.VAL; }
+ | OPTIONAL { $$ = Parameter.Modifier.OPTIONAL; }
+ ;
+
+opt_actual_parameters
+ : /* empty */
+ | qualified_identifier
+ | LITERAL_STRING
+ ;
+
+opt_statement_list
+ : /* empty */
+ | statement_list EOL
+ ;
+
+statement_list
+ : statement
+ | statement_list EOL statement
+ ;
+
+statement : embedded_statement
+ {
+ Statement s = (Statement) $1;
+
+ current_block.AddStatement ((Statement) $1);
+ }
+ | labeled_statement EOL
+ | ADDHANDLER prefixed_unary_expression COMMA ADDRESSOF qualified_identifier
+ {
+ AddHandler ((Expression) $2, (string) $5);
+ }
+ ;
+
+
+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
+ ;
+
+embedded_statement
+ : expression_statement
+ | selection_statement
+ | iteration_statement
+ | try_statement
+ | jump_statement
+ ;
+
+jump_statement
+ : /*break_statement
+ | continue_statement
+ | goto_statement
+ | throw_statement
+ | */return_statement
+ | exit_statement
+ ;
+
+exit_statement
+ : EXIT exit_type
+ {
+ $$ = new Exit ((ExitType)$2, lexer.Location);
+ }
+ ;
+
+exit_type
+ : DO { $$ = ExitType.DO; }
+ | FOR { $$ = ExitType.FOR; }
+ | WHILE { $$ = ExitType.WHILE; }
+ | SELECT { $$ = ExitType.SELECT; }
+ | SUB { $$ = ExitType.SUB; }
+ | FUNCTION { $$ = ExitType.FUNCTION; }
+ | PROPERTY { $$ = ExitType.PROPERTY; }
+ | TRY { $$ = ExitType.TRY; }
+ ;
+return_statement
+ : RETURN opt_expression
+ {
+ $$ = new Return ((Expression) $2, lexer.Location);
+ }
+ ;
+
+iteration_statement
+ : while_statement
+ | do_statement
+ | for_statement
+ /*| foreach_statement*/
+ ;
+
+try_statement
+ : try_catch
+ | try_catch_finally
+ ;
+
+try_catch
+ : try_header
+ END TRY
+ {
+ Catch g = null;
+ ArrayList s = new ArrayList ();
+
+ foreach (Catch cc in (ArrayList) tmp_catch_clauses) {
+ if (cc.IsGeneral)
+ g = cc;
+ else
+ s.Add (cc);
+ }
+
+ // Now s contains the list of specific catch clauses
+ // and g contains the general one.
+ Block b = end_block();
+
+ $$ = new Try ((Block) b, s, g, null, lexer.Location);
+ }
+ ;
+
+try_catch_finally
+ : try_header
+ {
+ tmp_block = end_block();
+ }
+ FINALLY EOL
+ {
+ start_block();
+ }
+ opt_statement_list
+ END TRY
+ {
+ Catch g = null;
+ ArrayList s = new ArrayList ();
+ ArrayList catch_list = (ArrayList) tmp_catch_clauses;
+
+ if (catch_list != null){
+ foreach (Catch cc in catch_list) {
+ if (cc.IsGeneral)
+ g = cc;
+ else
+ s.Add (cc);
+ }
+ }
+
+ $$ = new Try ((Block) tmp_block, s, g, (Block) end_block(), lexer.Location);
+
+ }
+ ;
+
+try_header
+ : TRY EOL
+ { Console.WriteLine ("try_header");
+ start_block();
+ }
+ opt_statement_list
+ opt_catch_clauses
+ {
+ tmp_catch_clauses = (ArrayList) $5;
+ }
+ ;
+
+opt_catch_clauses
+ : /* empty */ { $$ = null; }
+ | catch_clauses
+ ;
+
+catch_clauses
+ : catch_clause
+ {
+ ArrayList l = new ArrayList ();
+
+ 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 EOL
+ {
+ 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 ();
+ 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;
+ }
+ }
+
+ }
+ opt_statement_list {
+ Expression type = null;
+ string id = null;
+ Block b_catch = current_block;
+
+ 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)b_catch, lexer.Location);
+ }
+ ;
+
+opt_catch_args
+ : /* empty */ { $$ = null; }
+ | catch_args
+ ;
+
+catch_args
+ : IDENTIFIER AS type
+ {
+ $$ = new DictionaryEntry ($3, $1);
+ }
+ ;
+
+
+do_statement
+ : DO opt_do_construct EOL
+ {
+ start_block();
+ oob_stack.Push (lexer.Location);
+ }
+ opt_statement_list
+ LOOP opt_do_construct
+ {
+ Expression t_before = (Expression) $2;
+ Expression t_after = (Expression) $7;
+ Expression t;
+
+ if ((t_before != null) && (t_after != null))
+ Report.Error (30238, "'Loop' cannot have a condition if matching 'Do' has one.");
+
+ if ((t_before == null) && (t_after == null))
+ t = new BoolLiteral (true);
+ else
+ t = (t_before != null) ? t_before : t_after;
+
+ DoOptions test_type = (t_before != null) ? DoOptions.TEST_BEFORE : DoOptions.TEST_AFTER;
+
+ if (((do_type == DoOptions.WHILE) && (test_type == DoOptions.TEST_BEFORE)) ||
+ ((do_type == DoOptions.UNTIL) && (test_type == DoOptions.TEST_AFTER)))
+ t = new Unary (Unary.Operator.LogicalNot, (Expression) t, lexer.Location);
+
+ $$ = new Do ((Statement) end_block(), (Expression) t, test_type, lexer.Location);
+ }
+ ;
+
+opt_do_construct
+ : /* empty */ { $$ = null; }
+ | while_or_until boolean_expression
+ {
+ do_type = (DoOptions)$1;
+ $$ = (Expression) $2;
+ }
+ ;
+
+while_or_until
+ : WHILE { $$ = DoOptions.WHILE; }
+ | UNTIL { $$ = DoOptions.UNTIL; }
+ ;
+
+while_statement
+ : WHILE
+ {
+ start_block();
+ oob_stack.Push (lexer.Location);
+ }
+ boolean_expression EOL
+ opt_statement_list
+ END WHILE
+ {
+ Location l = (Location) oob_stack.Pop ();
+ Block b = end_block();
+ Expression e = (Expression) $3;
+ $$ = new While ((Expression) e, (Statement) b, l);
+ }
+ ;
+
+
+for_statement
+ : FOR qualified_identifier ASSIGN expression TO expression opt_step EOL
+ {
+ start_block();
+ }
+ opt_statement_list
+ NEXT opt_next_identifier
+ {
+ Block statement = end_block();
+ Expression for_var = (Expression) DecomposeQI ((string)$2, lexer.Location);;
+
+ Expression assign_expr = new Assign (for_var, (Expression) $4, lexer.Location);
+ Expression test_expr = new Binary (Binary.Operator.LessThanOrEqual,
+ for_var, (Expression) $6, lexer.Location);
+ Expression step_expr = new Assign (for_var, (Expression) new Binary (Binary.Operator.Addition,
+ for_var, (Expression) $7, lexer.Location), lexer.Location);
+
+ Statement assign_stmt = new StatementExpression ((ExpressionStatement) assign_expr, lexer.Location);
+ Statement step_stmt = new StatementExpression ((ExpressionStatement) step_expr, lexer.Location);
+
+ $$ = new For (assign_stmt, test_expr, step_stmt, statement, lexer.Location);
+ }
+ ;
+
+opt_step
+ : /* empty */ { $$ = new IntLiteral ((Int32) 1); }
+ | STEP expression { $$ = $2; }
+ ;
+
+opt_next_identifier
+ : /* empty */
+ | qualified_identifier
+ ;
+
+selection_statement
+ : if_statement
+ | select_statement
+ ;
+
+if_statement
+ : if_statement_open if_statement_rest
+ {
+ $$ = $2;
+ }
+ ;
+
+if_statement_open
+ : IF boolean_expression THEN EOL
+ {
+ oob_stack.Push (lexer.Location);
+ start_block();
+ tmp_expr = (Expression) $2;
+ }
+ ;
+
+if_statement_rest
+ :
+ opt_statement_list
+ END IF
+ {
+ Location l = (Location) oob_stack.Pop ();
+
+ $$ = new If ((Expression) tmp_expr, (Statement) end_block(), l);
+
+ }
+ |
+ opt_statement_list
+ ELSE EOL
+ {
+ tmp_block = end_block();
+ start_block();
+ }
+ opt_statement_list
+ END IF
+ {
+ Location l = (Location) oob_stack.Pop ();
+
+ $$ = new If ((Expression) tmp_expr, (Statement) tmp_block, (Statement) end_block(), l);
+ }
+ ;
+
+select_statement
+ : SELECT opt_case expression EOL
+ {
+ oob_stack.Push (lexer.Location);
+ switch_stack.Push (current_block);
+ }
+ opt_case_sections
+ END SELECT
+ {
+ $$ = new Switch ((Expression) $3, (ArrayList) $6, (Location) oob_stack.Pop ());
+ current_block = (Block) switch_stack.Pop ();
+ }
+ ;
+
+opt_case_sections
+ : /* empty */ { $$ = null; }
+ | case_sections { $$ = $1; }
+ ;
+
+case_sections
+ : case_sections case_section
+ {
+ ArrayList sections = (ArrayList) $1;
+
+ sections.Add ($2);
+ $$ = sections;
+ }
+ | case_section
+ {
+ ArrayList sections = new ArrayList ();
+
+ sections.Add ($1);
+ $$ = sections;
+ }
+ ;
+
+case_section
+ : CASE case_clauses EOL
+ {
+ start_block();
+ }
+ opt_statement_list
+ {
+ Block topmost = current_block;
+
+ while (topmost.Implicit)
+ topmost = topmost.Parent;
+
+ // FIXME: This is a horrible hack which MUST go
+ topmost.statements.Add (new Break (lexer.Location));
+ $$ = new SwitchSection ((ArrayList) $2, topmost);
+ }
+ | CASE ELSE EOL
+ /* FIXME: we should somehow flag an error
+ (BC30321 'Case' cannot follow a 'Case Else'
+ in the same 'Select' statement.)
+ if Case Else is not the last of the Case clauses
+ */
+ {
+ start_block();
+ }
+ opt_statement_list
+ {
+ Block topmost = current_block;
+
+ while (topmost.Implicit)
+ topmost = topmost.Parent;
+
+ // FIXME: This is a horrible hack which MUST go
+ topmost.statements.Add (new Break (lexer.Location));
+
+ ArrayList a = new ArrayList();
+ a.Add (new SwitchLabel (null, lexer.Location));
+ $$ = new SwitchSection ((ArrayList) a, topmost);
+ }
+ ;
+
+case_clauses
+ : case_clause
+ {
+ ArrayList labels = new ArrayList ();
+
+ labels.Add ($1);
+ $$ = labels;
+ }
+ | case_clauses COMMA case_clause
+ {
+ ArrayList labels = (ArrayList) ($1);
+ labels.Add ($2);
+
+ $$ = labels;
+ }
+ ;
+
+case_clause
+ : opt_is comparison_operator expression
+ | expression
+ {
+ $$ = new SwitchLabel ((Expression) $1, lexer.Location);
+ }
+ ;
+
+opt_is
+ : /* empty */
+ | IS
+ ;
+
+comparison_operator
+ : OP_LT
+ | OP_GT
+ | OP_LT
+ | OP_LE
+ | OP_NE
+ | OP_EQ
+ ;
+
+opt_case
+ : /* empty */
+ | CASE
+ ;
+
+expression_statement
+ : statement_expression
+ {
+ $$ = $1;
+ }
+ ;
+
+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); }
+ ;
+
+object_creation_expression
+ : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS
+ {
+ $$ = new New ((Expression) $2, (ArrayList) $4, lexer.Location);
+ }
+ ;
+
+new_expression
+ : object_creation_expression
+ /* | array_creation_expression */
+ ;
+
+assignment_expression
+ : prefixed_unary_expression ASSIGN expression
+ {
+ $$ = new Assign ((Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+opt_local_declarations
+ : /* empty */
+ | local_declarations
+ { if ($1 != null && (Block) $1 != current_block){
+ current_block.AddStatement ((Statement) $1);
+ current_block = (Block) $1;
+ }
+ }
+ ;
+
+local_declarations
+ : local_declaration EOL
+ | local_declaration EOL local_declarations
+ ;
+
+local_declaration
+ : local_variable_declaration
+ {
+ if ($1 != null){
+ DictionaryEntry de = (DictionaryEntry) $1;
+
+ $$ = declare_local_variables ((Expression) de.Key, (ArrayList) de.Value, lexer.Location);
+ }
+ }
+
+ | local_constant_declaration
+ {
+ if ($1 != null){
+ DictionaryEntry de = (DictionaryEntry) $1;
+
+ $$ = declare_local_constant ((Expression) de.Key, (VariableDeclaration) de.Value);
+ }
+ }
+ ;
+
+local_variable_declaration
+ : DIM variable_declarators
+ {
+ $$ = new DictionaryEntry (DecomposeQI("_local_vars_", lexer.Location), $2);
+ }
+ | DIM variable_declarators
+ {
+ $$ = new DictionaryEntry (TypeManager.system_object_expr, $2);
+ }
+ /*| DIM variable_declarators AS object_creation_expression
+ {
+ if ($4 != null)
+ $$ = new DictionaryEntry ($4, $2);
+ else
+ $$ = null;
+
+ } */
+ ;
+
+
+local_constant_declaration
+ : CONST constant_declarator
+ {
+ if ($2 != null)
+ $$ = new DictionaryEntry ($1, $2);
+ else
+ $$ = null;
+ }
+ ;
+
+constant_declarator
+ : IDENTIFIER ASSIGN constant_expression
+ {
+ $$ = new VariableDeclaration ((string) $1, $3, lexer.Location);
+ }
+ ;
+
+variable_declarators
+ : variable_declarator
+ {
+ ArrayList decl = new ArrayList ();
+ decl.Add ($1);
+ $$ = decl;
+ }
+ | variable_declarators COMMA variable_declarator
+ {
+ ArrayList decls = (ArrayList) $1;
+ decls.Add ($3);
+ $$ = $1;
+ }
+ ;
+
+variable_declarator
+ : variable_identifier opt_type_decl opt_variable_initializer
+ {
+ string varname = (string)$1;
+ string dims = "";
+ Expression vartype = (Expression) $2;
+ Expression varinit = (Expression) $3;
+ /*
+ Check for a declaration like Dim a(2) or Dim a(2,3)
+ If this is the case, we must generate an ArrayCreationExpression
+ and, in case, add the initializer after the array has been created.
+ */
+ if (VariableDeclaration.IsArrayDecl (varname)) {
+ if (VariableDeclaration.HasDimBounds(varname)) {
+ varname = VariableDeclaration.StripDims (varname, ref dims);
+ ArrayList a_dims = VariableDeclaration.ParseDims(dims);
+ varinit = new ArrayCreation (vartype, a_dims,"", null, lexer.Location);
+ }
+ vartype = DecomposeQI (vartype.ToString() + VariableDeclaration.GetRank (dims), lexer.Location);
+ }
+
+ $$ = new VariableDeclaration (varname, vartype, varinit, lexer.Location, null);
+ }
+ ;
+
+variable_identifier
+ : IDENTIFIER opt_array_name_modifier
+ {
+ $$ = $1;
+ if ($2 != null)
+ $$ = (string)$$ + (string)$2;
+ }
+ ;
+
+opt_type_decl
+ : /* empty */
+ {
+ $$ = null;
+ }
+ | AS type opt_argument_list /* FIXME must handle argument list*/
+ {
+ $$ = $2;
+ }
+ | AS NEW type opt_argument_list /* FIXME must handle NEW clause + argument list */
+ {
+ $$ = $3;
+ }
+ ;
+
+opt_array_name_modifier
+ : /* empty */ { $$ = null; }
+ | array_type_modifier { $$ = $1; }
+ | array_initialization_modifier
+ ;
+
+array_type_modifier
+ : rank_specifiers { $$ = $1; }
+ ;
+
+opt_dim_separators
+ : /* empty */
+ {
+ $$ = "";
+ }
+ | dim_separators
+ {
+ $$ = $1;
+ }
+ ;
+
+dim_separators
+ : COMMA
+ {
+ $$ = ",";
+ }
+ | dim_separators COMMA
+ {
+ $$ = (string) $1 + ",";
+ }
+ ;
+
+opt_variable_initializer
+ : /* empty */ { $$ = null; }
+ | ASSIGN variable_initializer { $$ = $2; }
+ ;
+
+array_initialization_modifier
+ : /* empty */ { $$ = null; }
+ ;
+
+variable_initializer
+ : expression
+ {
+ $$ = $1;
+ }
+ /*| array_initializer
+ {
+ $$ = $1;
+ }
+ */
+ ;
+
+/*
+ * 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)) {
+ 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);
+ }
+ ;
+
+rank_specifiers
+ : rank_specifier
+ {
+ $$ = $1;
+ }
+ | rank_specifiers rank_specifier
+ {
+ $$ = (string) $2 + (string) $1;
+ }
+ ;
+
+rank_specifier
+ : OPEN_PARENS opt_dim_separators CLOSE_PARENS
+ {
+ $$ = "[" + (string) $2 + "]";
+ }
+ ;
+
+opt_rank_specifier
+ : /* empty */
+ {
+ $$ = "";
+ }
+ | rank_specifiers
+ {
+ $$ = $1;
+ }
+ ;
+
+opt_dim_separators
+ : /* empty */
+ {
+ $$ = "";
+ }
+ | dim_separators
+ {
+ $$ = $1;
+ }
+ | dim_specifiers
+ {
+ $$ = $1;
+ }
+ ;
+
+dim_separators
+ : COMMA
+ {
+ $$ = ",";
+ }
+ | dim_separators COMMA
+ {
+ $$ = (string) $1 + ",";
+ }
+ ;
+
+dim_specifiers
+ : integer_literal { $$ = ((IntLiteral)$1).AsString(); }
+ | dim_specifiers COMMA integer_literal { $$ = $1 + "," + ((IntLiteral)$3).AsString(); }
+ ;
+
+/* Expressions */
+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
+ | new_expression
+ ;
+
+literal
+ : boolean_literal
+ | integer_literal
+ | real_literal
+ | LITERAL_CHARACTER { $$ = new CharLiteral ((char) lexer.Value); }
+ | LITERAL_STRING { $$ = new StringLiteral ((string) lexer.Value); }
+ | NOTHING { $$ = NullLiteral.Null; }
+ ;
+
+real_literal
+ : LITERAL_SINGLE { $$ = 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, "THIS IS CRAZY");
+ }
+ $$ = new Invocation ((Expression) $1, (ArrayList) $3, lexer.Location);
+ }
+ ;
+
+opt_argument_list
+ : /* empty */ { $$ = null; }
+ | argument_list
+ ;
+
+argument_list
+ : argument
+ {
+ ArrayList list = new ArrayList ();
+ 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);
+ }
+ | BYREF variable_reference
+ {
+ $$ = new Argument ((Expression) $2, Argument.AType.Ref);
+ }
+ | /* empty */
+ {
+ $$ = new Argument (new EmptyExpression (), Argument.AType.NoArg);
+ }
+ ;
+
+variable_reference
+ : expression {/* note ("section 5.4"); */ $$ = $1; }
+ ;
+
+element_access
+ : primary_expression OPEN_PARENS expression_list CLOSE_PARENS
+ {
+ $$ = 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 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 SimpleName (GetQualifiedIdentifier (expr) + (string) $2, lexer.Location);
+ }
+ }*/
+ ;
+
+opt_expression
+ : /* empty */
+ | expression
+ ;
+
+expression_list
+ : expression
+ {
+ ArrayList list = new ArrayList ();
+ list.Add ($1);
+ $$ = list;
+ }
+ | expression_list COMMA expression
+ {
+ ArrayList list = (ArrayList) $1;
+ list.Add ($3);
+ $$ = list;
+ }
+ ;
+
+this_access
+ : ME
+ {
+ $$ = new This (current_block, lexer.Location);
+ }
+ ;
+
+base_access
+ : MYBASE DOT IDENTIFIER
+ {
+ $$ = new BaseAccess ((string) $3, lexer.Location);
+ }
+ | MYBASE 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);
+ }
+ ;
+
+unary_expression
+ : primary_expression
+ | NOT prefixed_unary_expression
+ {
+ $$ = new Unary (Unary.Operator.LogicalNot, (Expression) $2, 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);
+ }
+ | ADDRESSOF prefixed_unary_expression
+ {
+ // FIXME: We should generate an error if AddressOf is NOT used
+ // during delegate creation
+ $$ = $2;
+ }
+ ;
+
+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 OP_MODULUS 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);
+ }
+ ;
+
+relational_expression
+ : additive_expression
+ | relational_expression OP_LT additive_expression
+ {
+ $$ = new Binary (Binary.Operator.LessThan,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression OP_GT additive_expression
+ {
+ $$ = new Binary (Binary.Operator.GreaterThan,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression OP_LE additive_expression
+ {
+ $$ = new Binary (Binary.Operator.LessThanOrEqual,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ | relational_expression OP_GE additive_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 OP_AND equality_expression
+ {
+ $$ = new Binary (Binary.Operator.BitwiseAnd,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression OP_XOR and_expression
+ {
+ $$ = new Binary (Binary.Operator.ExclusiveOr,
+ (Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+conditional_and_expression
+ : exclusive_or_expression
+ | conditional_and_expression OP_AND exclusive_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
+ ;
+
+assignment_expression
+ : prefixed_unary_expression ASSIGN expression
+ {
+ $$ = new Assign ((Expression) $1, (Expression) $3, lexer.Location);
+ }
+ ;
+
+expression
+ : conditional_expression
+ | assignment_expression
+ ;
+
+constant_expression
+ : expression
+ ;
+
+boolean_expression
+ : expression
+ ;
+
+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 */
+ ;
+
+type_list
+ : type
+ {
+ ArrayList types = new ArrayList ();
+
+ types.Add ($1);
+ $$ = types;
+ }
+ | type_list COMMA type
+ {
+ ArrayList types = (ArrayList) $1;
+
+ types.Add ($3);
+ $$ = types;
+ }
+ ;
+
+type_name
+ : namespace_or_type_name
+ ;
+
+namespace_or_type_name
+ : qualified_identifier
+ ;
+
+array_type
+ : type rank_specifiers
+ {
+ $$ = new ComposedCast ((Expression) $1, (string) $2, lexer.Location);
+ }
+ ;
+
+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 + ",";
+ }
+ ;
+/* Built-in / Integral types */
+builtin_types
+ : OBJECT { $$ = TypeManager.system_object_expr; }
+ | STRING { $$ = TypeManager.system_string_expr; }
+ | BOOLEAN { $$ = TypeManager.system_boolean_expr; }
+ | DECIMAL { $$ = TypeManager.system_decimal_expr; }
+ | SINGLE { $$ = 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; }
+ | */ INTEGER { $$ = 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
+ ;
+%%
+
+
+Tokenizer lexer;
+
+public Tokenizer Lexer {
+ get {
+ return lexer;
+ }
+}
+
+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);
+ }
+}
+
+Block declare_local_variables (Expression dummy_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;
+ //
+
+ VariableDeclaration.FixupTypes (variable_declarators);
+
+ if (current_block.Used) {
+ implicit_block = new Block (current_block, true, loc, Location.Null);
+ implicit_block.AddChildVariableNames (current_block);
+ } else
+ implicit_block = current_block;
+
+ foreach (VariableDeclaration decl in variable_declarators){
+ Expression type = decl.type;
+ 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 ();
+ inits.Add (decl);
+ }
+ }
+ }
+
+ if (inits == null)
+ return implicit_block;
+
+ foreach (VariableDeclaration decl in inits){
+ Assign assign;
+ Expression expr;
+ Expression type = decl.type;
+
+ 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, true);
+ 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;
+}
+
+// <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 Expression type;
+ public ArrayList dims;
+
+ public VariableDeclaration (string id, object eoai, Location l, Attributes opt_attrs) : this
+ (id, TypeManager.system_object_expr, eoai, l, opt_attrs)
+ {
+ }
+
+ public VariableDeclaration (string id, Expression t, object eoai, Location l, Attributes opt_attrs)
+ {
+ this.identifier = id;
+ this.expression_or_array_initializer = eoai;
+ this.Location = l;
+ this.OptAttributes = opt_attrs;
+ this.type = t;
+ this.dims = null;
+ }
+
+ public VariableDeclaration (string id, object eoai, Location l) : this (id, eoai, l, null)
+ {
+ }
+
+ public static void FixupTypes (ArrayList vars)
+ {
+ int varcount = vars.Count;
+ VariableDeclaration lf = (VariableDeclaration) vars[varcount - 1];
+
+ if (lf.type == null)
+ lf.type = TypeManager.system_object_expr;
+
+ Expression cur_type = lf.type;
+ int n = varcount - 1;
+
+ while (n >= 0) {
+ VariableDeclaration var = (VariableDeclaration) vars[n--];
+ if (var.type == null)
+ var.type = cur_type;
+ else
+ cur_type = var.type;
+ }
+ }
+
+ public static bool HasDimBounds (string varname)
+ {
+ bool res = false;
+
+ if (varname.IndexOf("[") >= 0) {
+ char[] ds = {'1','2','3','4','5','6','7','8','9'};
+
+ string dimpart = varname.Substring(varname.IndexOf("["), (varname.LastIndexOf("]") - varname.IndexOf("["))+1);
+ if (dimpart.IndexOfAny (ds) >= 0)
+ res = true;
+ }
+ return (res);
+ }
+
+ public static string StripDims (string varname, ref string d)
+ {
+ string res = varname;
+ string dres = "";
+
+ if (varname.IndexOf("[") >= 0) {
+ dres = varname.Substring(varname.IndexOf("["), (varname.LastIndexOf("]") - varname.IndexOf("["))+1);
+ res = varname.Substring(0, varname.IndexOf("["));
+ }
+ d = dres;
+ return (res);
+ }
+
+ public static string GetRank (string dims)
+ {
+ string res = "";
+ int x;
+
+ for (x = 0; x < dims.Length; x++) {
+ if (dims[x] == '[' || dims[x] == ']' || dims[x] == ',')
+ res = res + dims[x];
+ }
+ return (res);
+ }
+
+ public static ArrayList ParseDims (string dims)
+ {
+ ArrayList res = new ArrayList();
+ string d = dims.Substring (1, dims.Length -2);
+ Array a = d.Split (',');
+
+ if (a.GetLength(0) > 32) {
+ Report.Error (999, "Arrays cannot have more than 32 dimensions");
+ }
+
+ foreach (string s in a)
+ res.Add (new IntLiteral ((Int32) Convert.ToInt32(s)));
+
+ return (res);
+ }
+
+ public static bool IsArrayDecl (string varname)
+ {
+ return (varname.IndexOf("[") >= 0);
+ }
+
+ public static void FixupArrayTypes (ArrayList vars)
+ {
+ int varcount = vars.Count;
+ string dims;
+
+ foreach (VariableDeclaration var in vars) {
+ if (var.identifier.EndsWith(",")) {
+ dims = "[" + var.identifier.Substring(var.identifier.IndexOf (","),
+ var.identifier.LastIndexOf(",")) + "]";
+ var.identifier = var.identifier.Substring (0, var.identifier.IndexOf (","));
+ var.type = new ComposedCast (var.type, (string) dims, var.Location);
+ }
+ }
+ }
+}
+
+public Property BuildSimpleProperty (Expression p_type, string name,
+ Field p_fld, int mod_flags,
+ Attributes attrs, Location loc)
+{
+ Property p;
+ Block get_block, set_block;
+ Accessor acc_set, acc_get;
+ StatementExpression a_set;
+ Statement a_get;
+ Parameter [] args;
+
+ // Build SET Block
+ Parameter implicit_value_parameter = new Parameter (p_type, "value", Parameter.Modifier.NONE, null);
+ args = new Parameter [1];
+ args [0] = implicit_value_parameter;
+
+ Parameters set_params = new Parameters (args, null, loc);
+ a_set = new StatementExpression ((ExpressionStatement) new Assign ((Expression) DecomposeQI(p_fld.Name, loc),
+ (Expression) new SimpleName("value", loc), loc), loc);
+
+ set_block = new Block (current_block, set_params, loc, Location.Null);
+ set_block.AddStatement ((Statement) a_set);
+ acc_set = new Accessor (set_block, attrs);
+
+ // Build GET Block
+ a_get = (Statement) new Return ((Expression) DecomposeQI(p_fld.Name, loc), loc);
+ get_block = new Block (current_block, null, loc, Location.Null);
+ get_block.AddStatement ((Statement) a_get);
+ acc_get = new Accessor (get_block, attrs);
+
+ p = new Property (p_type, name, mod_flags, (Accessor) acc_get, (Accessor) acc_set, attrs, loc);
+
+ return (p);
+}
+
+void start_block ()
+{
+ current_block = new Block (current_block, current_local_parameters,
+ lexer.Location, Location.Null);
+}
+
+Block end_block ()
+{
+ Block res;
+
+ while (current_block.Implicit)
+ current_block = current_block.Parent;
+
+ res = current_block;
+
+ current_block.SetEndLocation (lexer.Location);
+ current_block = current_block.Parent;
+
+ return (res);
+}
+
+private void AddHandler (Expression evt_definition, string handler_name)
+{
+ AddHandler (current_block, evt_definition, handler_name);
+}
+
+private void AddHandler (Block b, Expression evt_definition, string handler_name)
+{
+ Location loc = lexer.Location;
+ ArrayList neh_args = new ArrayList();
+ neh_args.Add (new Argument (DecomposeQI(handler_name, loc), Argument.AType.Expression));
+
+ ExpressionStatement se = (ExpressionStatement)new New (DecomposeQI("System.EventHandler", loc), neh_args, loc);
+
+ CompoundAssign ca = new CompoundAssign (
+ Binary.Operator.Addition, evt_definition, (Expression) se, loc);
+
+ Statement s = (Statement)(new StatementExpression ((ExpressionStatement) ca, loc));
+ b.AddStatement (s);
+}
+
+// FIXME: THIS DOES NOT WORK!!!
+private void RemoveHandler (Block b, Expression evt_definition, string handler_name)
+{
+ Location loc = lexer.Location;
+ ArrayList neh_args = new ArrayList();
+ neh_args.Add (new Argument (DecomposeQI(handler_name, loc), Argument.AType.Expression));
+
+ ExpressionStatement se = (ExpressionStatement)new New (DecomposeQI("System.EventHandler", loc), neh_args, loc);
+
+ CompoundAssign ca = new CompoundAssign (
+ Binary.Operator.Subtraction, evt_definition, (Expression) se, loc);
+
+ Statement s = (Statement)(new StatementExpression ((ExpressionStatement) ca, loc));
+ b.AddStatement (s);
+}
+
+// <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>
+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 + ")");
+
+}
+
+private void RemoveHandler (Expression evt_definition, string handler_name)
+{
+ RemoveHandler (current_block, evt_definition, handler_name);
+}
+
+
+
+void Error_ExpectingTypeName (Location l, Expression expr)
+{
+ if (expr is Invocation){
+ Report.Error (1002, l, "; expected");
+ } else {
+ Report.Error (-1, l, "Invalid Type definition");
+ }
+}
+
+static bool AlwaysAccept (MemberInfo m, object filterCriteria) {
+ return true;
+}
+
+public override int parse ()
+{
+ current_namespace = new Namespace (null, "");
+ current_container = RootContext.Tree.Types;
+ current_container.Namespace = current_namespace;
+ oob_stack = new Stack ();
+ switch_stack = new Stack ();
+
+ UseExtendedSyntax = name.EndsWith(".mbs");
+
+ lexer = new Tokenizer (input, name, defines);
+ StringBuilder value = new StringBuilder ();
+ //yacc_verbose_flag=true;
+ try
+ {
+ if (yacc_verbose_flag)
+ yyparse (lexer, new yydebug.yyDebugSimple ());
+ else
+ yyparse (lexer);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine (lexer.location + " : Parsing error in " + lexer.ref_name);
+ Report.Error (9999, lexer.Location, "");
+ Console.WriteLine (e);
+ }
+
+ return Report.Errors;
+}
+
+/* end end end */
+}
diff --git a/mcs/mbas/mb-tokenizer.cs b/mcs/mbas/mb-tokenizer.cs
new file mode 100644
index 00000000000..028c16cceb3
--- /dev/null
+++ b/mcs/mbas/mb-tokenizer.cs
@@ -0,0 +1,888 @@
+//
+// Mono.MonoBASIC.Tokenizer.cs: The Tokenizer for the MonoBASIC compiler
+//
+// Author: A Rafael D Teixeira (rafaelteixeirabr@hotmail.com)
+//
+// Based on cs-tokenizer.cs by Miguel de Icaza (miguel@gnu.org)
+//
+// Licensed under the terms of the GNU GPL
+//
+// Copyright (C) 2001 A Rafael D Teixeira
+//
+
+namespace Mono.MonoBASIC
+{
+ using System;
+ using System.Text;
+ using System.Collections;
+ using System.IO;
+ using System.Globalization;
+ using Mono.Languages;
+ using Mono.CSharp;
+
+ /// <summary>
+ /// Tokenizer for MonoBASIC source code.
+ /// </summary>
+
+ public class Tokenizer : yyParser.yyInput
+ {
+ TextReader reader;
+ public string ref_name;
+ public int ref_line = 1;
+ public int line = 1;
+ public int col = 1;
+ public int current_token;
+ bool handle_get_set = false;
+
+ public int ExpandedTabsSize = 4;
+
+ public string location {
+ get {
+ string det;
+
+ if (current_token == Token.ERROR)
+ det = "detail: " + error_details;
+ else
+ det = "";
+
+ return "Line: "+line+" Col: "+col + "\n" +
+ "VirtLine: "+ref_line +
+ " Token: "+current_token + " " + det;
+ }
+ }
+
+ public bool properties {
+ get {
+ return handle_get_set;
+ }
+
+ set {
+ handle_get_set = value;
+ }
+ }
+
+ //
+ // Class variables
+ //
+ static Hashtable keywords;
+ static NumberStyles styles;
+ static NumberFormatInfo csharp_format_info;
+
+ //
+ // Values for the associated token returned
+ //
+ System.Text.StringBuilder number;
+ int putback_char;
+ Object val;
+
+ //
+ // Details about the error encoutered by the tokenizer
+ //
+ string error_details;
+
+ public string error {
+ get {
+ return error_details;
+ }
+ }
+
+ public int Line {
+ get {
+ return line;
+ }
+ }
+
+ public int Col {
+ get {
+ return col;
+ }
+ }
+
+ static void initTokens ()
+ {
+ keywords = new Hashtable ();
+
+ keywords.Add ("addhandler", Token.ADDHANDLER);
+ keywords.Add ("addressof", Token.ADDRESSOF);
+ keywords.Add ("alias", Token.ALIAS);
+ keywords.Add ("and", Token.AND);
+ keywords.Add ("andalso", Token.ANDALSO);
+ keywords.Add ("ansi", Token.ANSI);
+ keywords.Add ("as", Token.AS);
+ keywords.Add ("assembly", Token.ASSEMBLY);
+ keywords.Add ("auto", Token.AUTO);
+ keywords.Add ("boolean", Token.BOOLEAN);
+ keywords.Add ("byref", Token.BYREF);
+ keywords.Add ("byte", Token.BYTE);
+ keywords.Add ("byval", Token.BYVAL);
+ keywords.Add ("call", Token.CALL);
+ keywords.Add ("case", Token.CASE);
+ keywords.Add ("catch", Token.CATCH);
+ keywords.Add ("cbool", Token.CBOOL);
+ keywords.Add ("cbyte", Token.CBYTE);
+ keywords.Add ("cchar", Token.CCHAR);
+ keywords.Add ("cdate", Token.CDATE);
+ keywords.Add ("cdec", Token.CDEC);
+ keywords.Add ("cdbl", Token.CDBL);
+ keywords.Add ("char", Token.CHAR);
+ keywords.Add ("cint", Token.CINT);
+ keywords.Add ("class", Token.CLASS);
+ keywords.Add ("clng", Token.CLNG);
+ keywords.Add ("cobj", Token.COBJ);
+ //keywords.Add ("compare", Token.COMPARE);
+ keywords.Add ("const", Token.CONST);
+ keywords.Add ("cshort", Token.CSHORT);
+ keywords.Add ("csng", Token.CSNG);
+ keywords.Add ("cstr", Token.CSTR);
+ keywords.Add ("ctype", Token.CTYPE);
+ keywords.Add ("date", Token.DATE);
+ keywords.Add ("decimal", Token.DECIMAL);
+ keywords.Add ("declare", Token.DECLARE);
+ keywords.Add ("default", Token.DEFAULT);
+ keywords.Add ("delegate", Token.DELEGATE);
+ keywords.Add ("dim", Token.DIM);
+ keywords.Add ("do", Token.DO);
+ keywords.Add ("double", Token.DOUBLE);
+ keywords.Add ("each", Token.EACH);
+ keywords.Add ("else", Token.ELSE);
+ keywords.Add ("elseif", Token.ELSEIF);
+ keywords.Add ("end", Token.END);
+ keywords.Add ("enum", Token.ENUM);
+ keywords.Add ("erase", Token.ERASE);
+ keywords.Add ("error", Token.ERROR);
+ keywords.Add ("event", Token.EVENT);
+ keywords.Add ("exit", Token.EXIT);
+ //keywords.Add ("explicit", Token.EXPLICIT);
+ keywords.Add ("false", Token.FALSE);
+ keywords.Add ("finally", Token.FINALLY);
+ keywords.Add ("for", Token.FOR);
+ keywords.Add ("friend", Token.FRIEND);
+ keywords.Add ("function", Token.FUNCTION);
+ keywords.Add ("get", Token.GET);
+ keywords.Add ("gettype", Token.GETTYPE);
+ keywords.Add ("goto", Token.GOTO);
+ keywords.Add ("handles", Token.HANDLES);
+ keywords.Add ("if", Token.IF);
+ keywords.Add ("implements", Token.IMPLEMENTS);
+ keywords.Add ("imports", Token.IMPORTS);
+ keywords.Add ("in", Token.IN);
+ keywords.Add ("inherits", Token.INHERITS);
+ keywords.Add ("integer", Token.INTEGER);
+ keywords.Add ("interface", Token.INTERFACE);
+ keywords.Add ("is", Token.IS);
+ keywords.Add ("let ", Token.LET );
+ keywords.Add ("lib ", Token.LIB );
+ keywords.Add ("like ", Token.LIKE );
+ keywords.Add ("long", Token.LONG);
+ keywords.Add ("loop", Token.LOOP);
+ keywords.Add ("me", Token.ME);
+ keywords.Add ("mod", Token.MOD);
+ keywords.Add ("module", Token.MODULE);
+ keywords.Add ("mustinherit", Token.MUSTINHERIT);
+ keywords.Add ("mustoverride", Token.MUSTOVERRIDE);
+ keywords.Add ("mybase", Token.MYBASE);
+ keywords.Add ("myclass", Token.MYCLASS);
+ keywords.Add ("namespace", Token.NAMESPACE);
+ keywords.Add ("new", Token.NEW);
+ keywords.Add ("next", Token.NEXT);
+ keywords.Add ("not", Token.NOT);
+ keywords.Add ("nothing", Token.NOTHING);
+ keywords.Add ("notinheritable", Token.NOTINHERITABLE);
+ keywords.Add ("notoverridable", Token.NOTOVERRIDABLE);
+ keywords.Add ("object", Token.OBJECT);
+ keywords.Add ("on", Token.ON);
+ keywords.Add ("option", Token.OPTION);
+ keywords.Add ("optional", Token.OPTIONAL);
+ keywords.Add ("or", Token.OR);
+ keywords.Add ("orelse", Token.ORELSE);
+ keywords.Add ("overloads", Token.OVERLOADS);
+ keywords.Add ("overridable", Token.OVERRIDABLE);
+ keywords.Add ("overrides", Token.OVERRIDES);
+ keywords.Add ("paramarray", Token.PARAM_ARRAY);
+ keywords.Add ("preserve", Token.PRESERVE);
+ keywords.Add ("private", Token.PRIVATE);
+ keywords.Add ("property", Token.PROPERTY);
+ keywords.Add ("protected", Token.PROTECTED);
+ keywords.Add ("public", Token.PUBLIC);
+ keywords.Add ("raiseevent", Token.RAISEEVENT);
+ keywords.Add ("readonly", Token.READONLY);
+ keywords.Add ("redim", Token.REDIM);
+ keywords.Add ("rem", Token.REM);
+ keywords.Add ("removehandler", Token.REMOVEHANDLER);
+ keywords.Add ("resume", Token.RESUME);
+ keywords.Add ("return", Token.RETURN);
+ keywords.Add ("select", Token.SELECT);
+ keywords.Add ("set", Token.SET);
+ keywords.Add ("shadows", Token.SHADOWS);
+ keywords.Add ("shared", Token.SHARED);
+ keywords.Add ("short", Token.SHORT);
+ keywords.Add ("single", Token.SINGLE);
+ keywords.Add ("sizeof", Token.SIZEOF);
+ keywords.Add ("static", Token.STATIC);
+ keywords.Add ("step", Token.STEP);
+ keywords.Add ("stop", Token.STOP);
+ keywords.Add ("string", Token.STRING);
+ keywords.Add ("structure", Token.STRUCTURE);
+ keywords.Add ("sub", Token.SUB);
+ keywords.Add ("synclock", Token.SYNCLOCK);
+ keywords.Add ("then", Token.THEN);
+ keywords.Add ("throw", Token.THROW);
+ keywords.Add ("to", Token.TO);
+ keywords.Add ("true", Token.TRUE);
+ keywords.Add ("try", Token.TRY);
+ keywords.Add ("typeof", Token.TYPEOF);
+ keywords.Add ("unicode", Token.UNICODE);
+ keywords.Add ("until", Token.UNTIL);
+ keywords.Add ("variant", Token.VARIANT);
+ keywords.Add ("when", Token.WHEN);
+ keywords.Add ("while", Token.WHILE);
+ keywords.Add ("with", Token.WITH);
+ keywords.Add ("withevents", Token.WITHEVENTS);
+ keywords.Add ("writeonly", Token.WRITEONLY);
+ keywords.Add ("xor", Token.XOR);
+ }
+
+ //
+ // Class initializer
+ //
+ static Tokenizer ()
+ {
+ initTokens ();
+ csharp_format_info = new NumberFormatInfo ();
+ csharp_format_info.CurrencyDecimalSeparator = ".";
+ styles = NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint;
+ }
+
+ bool is_keyword (string name)
+ {
+ bool res;
+
+ res = keywords.Contains(name.ToLower());
+ if ((name == "get" || name == "set") && handle_get_set == false)
+ return false;
+ return res;
+ }
+
+ int getKeyword (string name)
+ {
+ return (int) (keywords [name.ToLower()]);
+ }
+
+ public Location Location {
+ get {
+ return new Location (ref_line);
+ }
+ }
+
+ public bool PropertyParsing {
+ get {
+ return handle_get_set;
+ }
+
+ set {
+ handle_get_set = value;
+ }
+ }
+
+ bool is_identifier_start_character (char c)
+ {
+ return Char.IsLetter (c) || c == '_' ;
+ }
+
+ bool is_identifier_part_character (char c)
+ {
+ return (Char.IsLetter (c) || Char.IsDigit (c) || c == '_');
+ }
+
+ int is_punct (char c, ref bool doread)
+ {
+ int idx = "{}[](),:;~+-*/%&|^!=<>?".IndexOf (c);
+ int d;
+ int t;
+
+ doread = false;
+
+ switch (c){
+// case '[':
+// return Token.OPEN_BRACKET;
+// case ']':
+// return Token.CLOSE_BRACKET;
+ case '(':
+ return Token.OPEN_PARENS;
+ case ')':
+ return Token.CLOSE_PARENS;
+ case ',':
+ return Token.COMMA;
+ case ':':
+ return Token.COLON;
+ case '?':
+ return Token.INTERR;
+ }
+
+ d = peekChar ();
+ if (c == '+'){
+
+ if (d == '+')
+ t = Token.OP_INC;
+ else if (d == '=')
+ t = Token.OP_ADD_ASSIGN;
+ else
+ return Token.PLUS;
+ doread = true;
+ return t;
+ }
+ if (c == '-'){
+ if (d == '=')
+ t = Token.OP_SUB_ASSIGN;
+ else
+ return Token.MINUS;
+ doread = true;
+ return t;
+ }
+
+ if (c == '='){
+ /*if (d == '='){
+ doread = true;
+ return Token.OP_EQ;
+ }*/
+ return Token.ASSIGN;
+ }
+
+ if (c == '*'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_MULT_ASSIGN;
+ }
+ return Token.STAR;
+ }
+
+ if (c == '/'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_DIV_ASSIGN;
+ }
+ return Token.DIV;
+ }
+
+ if (c == '\\'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_IDIV_ASSIGN;
+ }
+ return Token.OP_IDIV;
+ }
+
+ if (c == '^'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_EXP_ASSIGN;
+ }
+ return Token.OP_EXP;
+ }
+
+ if (c == '<'){
+ if (d == '>')
+ {
+ doread = true;
+ return Token.OP_NE;
+ }
+ if (d == '='){
+ doread = true;
+ return Token.OP_LE;
+ }
+ return Token.OP_LT;
+ }
+
+ if (c == '>'){
+ if (d == '='){
+ doread = true;
+ return Token.OP_GE;
+ }
+ return Token.OP_GT;
+ }
+ return Token.ERROR;
+ }
+
+ bool decimal_digits (int c)
+ {
+ int d;
+ bool seen_digits = false;
+
+ if (c != -1)
+ number.Append ((char) c);
+
+ while ((d = peekChar ()) != -1){
+ if (Char.IsDigit ((char)d)){
+ number.Append ((char) d);
+ getChar ();
+ seen_digits = true;
+ } else
+ break;
+ }
+ return seen_digits;
+ }
+
+ void hex_digits (int c)
+ {
+ int d;
+
+ if (c != -1)
+ number.Append ((char) c);
+ while ((d = peekChar ()) != -1){
+ char e = Char.ToUpper ((char) d);
+
+ if (Char.IsDigit (e) ||
+ (e >= 'A' && e <= 'F')){
+ number.Append ((char) e);
+ getChar ();
+ } else
+ break;
+ }
+ }
+
+ int real_type_suffix (int c)
+ {
+ int t;
+
+ switch (c){
+ case 'F': case 'f':
+ t = Token.LITERAL_SINGLE;
+ break;
+ case 'D': case 'd':
+ t = Token.LITERAL_DOUBLE;
+ break;
+ case 'M': case 'm':
+ t= Token.LITERAL_DECIMAL;
+ break;
+ default:
+ return Token.NONE;
+ }
+ getChar ();
+ return t;
+ }
+
+ int integer_type_suffix (int c)
+ {
+ // FIXME: Handle U and L suffixes.
+ // We also need to see in which kind of
+ // Int the thing fits better according to the spec.
+ return Token.LITERAL_INTEGER;
+ }
+
+ void adjust_int (int t)
+ {
+ val = new System.Int32();
+ val = System.Int32.Parse (number.ToString (), 0);
+ }
+
+ int adjust_real (int t)
+ {
+ string s = number.ToString ();
+
+ Console.WriteLine (s);
+ switch (t){
+ case Token.LITERAL_DECIMAL:
+ val = new System.Decimal ();
+ val = System.Decimal.Parse (
+ s, styles, csharp_format_info);
+ break;
+ case Token.LITERAL_DOUBLE:
+ val = new System.Double ();
+ val = System.Double.Parse (
+ s, styles, csharp_format_info);
+ break;
+ case Token.LITERAL_SINGLE:
+ val = new System.Double ();
+ val = (float) System.Double.Parse (
+ s, styles, csharp_format_info);
+ break;
+
+ case Token.NONE:
+ val = new System.Double ();
+ val = System.Double.Parse (
+ s, styles, csharp_format_info);
+ t = Token.LITERAL_DOUBLE;
+ break;
+ }
+ return t;
+ }
+
+ //
+ // Invoked if we know we have .digits or digits
+ //
+ int is_number (int c)
+ {
+ bool is_real = false;
+ number = new System.Text.StringBuilder ();
+ int type;
+
+ number.Length = 0;
+
+ if (Char.IsDigit ((char)c)){
+ if (c == '0' && peekChar () == 'x' || peekChar () == 'X'){
+ getChar ();
+ hex_digits (-1);
+ val = new System.Int32 ();
+ val = System.Int32.Parse (number.ToString (), NumberStyles.HexNumber);
+ return integer_type_suffix (peekChar ());
+ }
+ decimal_digits (c);
+ c = getChar ();
+ }
+
+ //
+ // We need to handle the case of
+ // "1.1" vs "1.string" (LITERAL_SINGLE vs NUMBER DOT IDENTIFIER)
+ //
+ if (c == '.'){
+ if (decimal_digits ('.')){
+ is_real = true;
+ c = peekChar ();
+ } else {
+ putback ('.');
+ number.Length -= 1;
+ adjust_int (Token.LITERAL_INTEGER);
+ return Token.LITERAL_INTEGER;
+ }
+ }
+
+ if (c == 'e' || c == 'E'){
+ is_real = true;
+ number.Append ("e");
+ getChar ();
+
+ c = peekChar ();
+ if (c == '+'){
+ number.Append ((char) c);
+ getChar ();
+ c = peekChar ();
+ } else if (c == '-'){
+ number.Append ((char) c);
+ getChar ();
+ c = peekChar ();
+ }
+ decimal_digits (-1);
+ c = peekChar ();
+ }
+
+ type = real_type_suffix (c);
+ if (type == Token.NONE && !is_real){
+ type = integer_type_suffix (c);
+ adjust_int (type);
+ putback (c);
+ return type;
+ } else
+ is_real = true;
+
+ if (is_real)
+ return adjust_real (type);
+
+ Console.WriteLine ("This should not be reached");
+ throw new Exception ("Is Number should never reach this point");
+ }
+
+ int escape (int c)
+ {
+ int d;
+ int v;
+
+ d = peekChar ();
+ if (c != '\\')
+ return c;
+
+ switch (d){
+ case 'a':
+ v = '\a'; break;
+ case 'b':
+ v = '\b'; break;
+ case 'n':
+ v = '\n'; break;
+ case 't':
+ v = '\t'; break;
+ case 'v':
+ v = '\v'; break;
+ case 'r':
+ v = 'c'; break;
+ case '\\':
+ v = '\\'; break;
+ case 'f':
+ v = '\f'; break;
+ case '0':
+ v = 0; break;
+ case '"':
+ v = '"'; break;
+ case '\'':
+ v = '\''; break;
+ default:
+ error_details = "cs1009: Unrecognized escape sequence " + (char)d;
+ return -1;
+ }
+ getChar ();
+ return v;
+ }
+
+ int getChar ()
+ {
+ if (putback_char != -1){
+ int x = putback_char;
+ putback_char = -1;
+
+ return x;
+ }
+ return reader.Read ();
+ }
+
+ int peekChar ()
+ {
+ if (putback_char != -1)
+ return putback_char;
+ return reader.Peek ();
+ }
+
+ void putback (int c)
+ {
+ if (putback_char != -1)
+ throw new Exception ("This should not happen putback on putback");
+ putback_char = c;
+ }
+
+ public bool advance ()
+ {
+ return current_token != Token.EOF ;
+ }
+
+ public Object Value {
+ get {
+ return val;
+ }
+ }
+
+ public Object value ()
+ {
+ return val;
+ }
+
+ private bool IsEOL(int currentChar)
+ {
+ if (currentChar == 0x0D)
+ {
+ if (peekChar() == 0x0A) // if it is a CR-LF pair consume LF also
+ getChar();
+
+ return true;
+ }
+ return (currentChar == -1 || currentChar == 0x0A || currentChar == 0x2028 || currentChar == 0x2029);
+ }
+
+ private int DropComments()
+ {
+ int d;
+ while (!IsEOL(d = getChar ()))
+ col++;
+ line++;
+ ref_line++;
+ col = 0;
+
+ return Token.EOL;
+ }
+
+ public int token ()
+ {
+ int lastToken = current_token;
+ do
+ {
+ current_token = xtoken ();
+ if (current_token == 0)
+ return Token.EOF;
+ if (current_token == Token.REM)
+ current_token = DropComments();
+ } while (lastToken == Token.EOL && current_token == Token.EOL);
+
+ return current_token;
+ }
+
+ private string GetIdentifier()
+ {
+ int c = getChar();
+ if (is_identifier_start_character ((char) c))
+ return GetIdentifier(c);
+ else
+ return null;
+ }
+
+ private string GetIdentifier(int c)
+ {
+ System.Text.StringBuilder id = new System.Text.StringBuilder ();
+
+ id.Append ((char) c);
+
+ while ((c = peekChar ()) != -1)
+ {
+ if (is_identifier_part_character ((char) c))
+ {
+ id.Append ((char)getChar ());
+ col++;
+ }
+ else
+ break;
+ }
+
+ return id.ToString ();
+ }
+
+ public int xtoken ()
+ {
+ int t;
+ bool doread = false;
+ int c;
+
+ val = null;
+ for (;(c = getChar ()) != -1; col++) {
+
+ // Handle line comments.
+ if (c == '\'')
+ return Token.REM;
+
+ // Handle EOL.
+ if (IsEOL(c))
+ {
+ line++;
+ ref_line++;
+ col = 0;
+ if (current_token == Token.EOL) // if last token was also EOL keep skipping
+ continue;
+ return Token.EOL;
+ }
+
+ // Handle escaped identifiers
+ if (c == '[')
+ {
+ if ((val = GetIdentifier()) == null)
+ break;
+ if ((c = getChar()) != ']')
+ break;
+ return Token.IDENTIFIER;
+ }
+
+ // Handle unescaped identifiers
+ if (is_identifier_start_character ((char) c))
+ {
+ string id;
+ if ((id = GetIdentifier(c)) == null)
+ break;
+ if (is_keyword(id))
+ return getKeyword(id);
+ val = id;
+ return Token.IDENTIFIER;
+ }
+
+ // handle numeric literals
+ if (c == '.'){
+ if (Char.IsDigit ((char) peekChar ()))
+ return is_number (c);
+ return Token.DOT;
+ }
+
+ if (Char.IsDigit ((char) c))
+ return is_number (c);
+
+ /* For now, limited support for pre-processor commands */
+ if (col == 1 && c == '#'){
+ System.Text.StringBuilder s = new System.Text.StringBuilder ();
+
+ while ((c = getChar ()) != -1 && (c != '\n')){
+ s.Append ((char) c);
+ }
+ if (String.Compare (s.ToString (), 0, "line", 0, 4) == 0){
+ string arg = s.ToString ().Substring (5);
+ int pos;
+
+ if ((pos = arg.IndexOf (' ')) != -1 && pos != 0){
+ ref_line = System.Int32.Parse (arg.Substring (0, pos));
+ pos++;
+
+ char [] quotes = { '\"' };
+
+ ref_name = arg.Substring (pos);
+ ref_name.TrimStart (quotes);
+ ref_name.TrimEnd (quotes);
+ } else
+ ref_line = System.Int32.Parse (arg);
+ }
+ line++;
+ ref_line++;
+ continue;
+ }
+
+ if ((t = is_punct ((char)c, ref doread)) != Token.ERROR){
+ if (doread){
+ getChar ();
+ col++;
+ }
+ return t;
+ }
+
+ // Treat string literals
+ if (c == '"'){
+ System.Text.StringBuilder s = new System.Text.StringBuilder ();
+
+ while ((c = getChar ()) != -1){
+ if (c == '"'){ // TODO: treat double-doublequotes
+ val = s.ToString ();
+ return Token.LITERAL_STRING;
+ }
+
+ c = escape (c);
+ if (c == -1)
+ return Token.ERROR;
+ s.Append ((char) c);
+ }
+ }
+
+ // expand tabs for location and ignore it as whitespace
+ if (c == '\t')
+ {
+ col = (((col + ExpandedTabsSize) / ExpandedTabsSize) * ExpandedTabsSize) - 1;
+ continue;
+ }
+
+ // white space
+ if (c == ' ' || c == '\f' || c == '\v')
+ continue;
+
+ error_details = ((char)c).ToString ();
+
+ return Token.ERROR;
+ }
+
+ if (current_token != Token.EOL) // if last token wasn´t EOL send it before EOF
+ return Token.EOL;
+
+ return Token.EOF;
+ }
+
+ public void cleanup ()
+ {
+/* borrowed from mcs - have to work it to have preprocessing in mbas
+
+ if (ifstack != null && ifstack.Count >= 1) {
+ int state = (int) ifstack.Pop ();
+ if ((state & REGION) != 0)
+ Report.Error (1038, "#endregion directive expected");
+ else
+ Report.Error (1027, "#endif directive expected");
+ }
+*/
+ }
+
+ public Tokenizer (System.IO.TextReader input, string fname, ArrayList defines)
+ {
+ this.ref_name = fname;
+ reader = input;
+ putback_char = -1;
+
+ Location.Push (fname);
+ }
+
+ }
+}
diff --git a/mcs/mbas/mbas.csproj b/mcs/mbas/mbas.csproj
new file mode 100644
index 00000000000..38360bcd2f1
--- /dev/null
+++ b/mcs/mbas/mbas.csproj
@@ -0,0 +1,264 @@
+<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.0.9466"
+ SchemaVersion = "1.0"
+ ProjectGuid = "{D9868C8B-B8C9-43E0-8702-F33AD49F1CC3}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = "mbas.ico"
+ AssemblyKeyContainerName = ""
+ AssemblyName = "mbas"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Exe"
+ RootNamespace = "Mono.Languages"
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "true"
+ Optimize = "false"
+ OutputPath = ".\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "false"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ Optimize = "true"
+ OutputPath = "bin\Release\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References>
+ <Reference
+ Name = "System"
+ AssemblyName = "System"
+ HintPath = "..\..\..\..\WINNT\Microsoft.NET\Framework\v1.0.3705\System.dll"
+ />
+ <Reference
+ Name = "System.Data"
+ AssemblyName = "System.Data"
+ HintPath = "..\..\..\..\WINNT\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+ />
+ <Reference
+ Name = "System.XML"
+ AssemblyName = "System.Xml"
+ HintPath = "..\..\..\..\WINNT\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+ />
+ <Reference
+ Name = "Mono.GetOptions"
+ Project = "{8D3008AB-7C0F-4DBE-A305-752926C366A7}"
+ Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "AssemblyInfo.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "assign.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "attribute.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "cfold.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ChangeLog"
+ BuildAction = "None"
+ />
+ <File
+ RelPath = "class.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "codegen.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "const.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "constant.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "decl.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "delegate.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "driver.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ecore.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "enum.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "expression.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "genericparser.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "interface.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "literal.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "location.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "mbas.ico"
+ BuildAction = "Content"
+ />
+ <File
+ RelPath = "mb-parser.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "mb-parser.jay"
+ BuildAction = "None"
+ />
+ <File
+ RelPath = "mb-tokenizer.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "modifiers.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "module.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "namespace.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "parameter.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "pending.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "report.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "rootcontext.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "statement.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "statementCollection.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "support.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "tree.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "typemanager.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "testmbas\filelist"
+ BuildAction = "Content"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+
diff --git a/mcs/mbas/mbas.ico b/mcs/mbas/mbas.ico
new file mode 100644
index 00000000000..e134617dd82
--- /dev/null
+++ b/mcs/mbas/mbas.ico
Binary files differ
diff --git a/mcs/mbas/mbas.sln b/mcs/mbas/mbas.sln
new file mode 100644
index 00000000000..95f0b4a015e
--- /dev/null
+++ b/mcs/mbas/mbas.sln
@@ -0,0 +1,33 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mbas", "mbas.csproj", "{D9868C8B-B8C9-43E0-8702-F33AD49F1CC3}"
+EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "testmbas", "testmbas\testmbas.vbproj", "{64A40514-2574-4F75-B967-855531F2F01D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.GetOptions", "..\class\Mono.GetOptions\Mono.GetOptions.csproj", "{8D3008AB-7C0F-4DBE-A305-752926C366A7}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {D9868C8B-B8C9-43E0-8702-F33AD49F1CC3}.Debug.ActiveCfg = Debug|.NET
+ {D9868C8B-B8C9-43E0-8702-F33AD49F1CC3}.Debug.Build.0 = Debug|.NET
+ {D9868C8B-B8C9-43E0-8702-F33AD49F1CC3}.Release.ActiveCfg = Release|.NET
+ {D9868C8B-B8C9-43E0-8702-F33AD49F1CC3}.Release.Build.0 = Release|.NET
+ {64A40514-2574-4F75-B967-855531F2F01D}.Debug.ActiveCfg = Debug|.NET
+ {64A40514-2574-4F75-B967-855531F2F01D}.Debug.Build.0 = Debug|.NET
+ {64A40514-2574-4F75-B967-855531F2F01D}.Release.ActiveCfg = Release|.NET
+ {64A40514-2574-4F75-B967-855531F2F01D}.Release.Build.0 = Release|.NET
+ {8D3008AB-7C0F-4DBE-A305-752926C366A7}.Debug.ActiveCfg = Debug|.NET
+ {8D3008AB-7C0F-4DBE-A305-752926C366A7}.Debug.Build.0 = Debug|.NET
+ {8D3008AB-7C0F-4DBE-A305-752926C366A7}.Release.ActiveCfg = Release|.NET
+ {8D3008AB-7C0F-4DBE-A305-752926C366A7}.Release.Build.0 = Release|.NET
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/mcs/mbas/modifiers.cs b/mcs/mbas/modifiers.cs
new file mode 100644
index 00000000000..a5cf6f62c03
--- /dev/null
+++ b/mcs/mbas/modifiers.cs
@@ -0,0 +1,241 @@
+//
+// 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;
+
+ 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");
+ }
+ }
+}
diff --git a/mcs/mbas/module.cs b/mcs/mbas/module.cs
new file mode 100644
index 00000000000..ec9982d7e02
--- /dev/null
+++ b/mcs/mbas/module.cs
@@ -0,0 +1,74 @@
+//
+// module.cs: Module handler
+//
+// Author: Rafael Teixeira (rafaelteixeirabr@hotmail.com)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2002 Rafael Teixeira
+//
+using System;
+using System.Collections;
+using System.Diagnostics.SymbolStore;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
+using Mono.CSharp ;
+
+namespace Mono.MonoBASIC
+{
+ public class Utils
+ {
+ public static void AddSpecializedAttribute(ref Attributes attrs, string attributeName, ArrayList args, Location loc)
+ {
+ Mono.CSharp.Attribute specialAttr = new Mono.CSharp.Attribute(attributeName, args, loc);
+ ArrayList al = new ArrayList();
+ al.Add(specialAttr);
+ AttributeSection asec = new AttributeSection(null, al);
+ if (attrs == null)
+ attrs = new Attributes(asec, loc);
+ else
+ attrs.AddAttribute(asec);
+ }
+ }
+
+ /// <summary>
+ /// Summary description for module.
+ /// </summary>
+ public class Module : Mono.CSharp.Class
+ {
+ // <summary>
+ // Modifiers allowed in a class declaration
+ // </summary>
+ public new const int AllowedModifiers =
+ Modifiers.PUBLIC |
+ Modifiers.INTERNAL;
+
+ public Module(TypeContainer parent, string name, int mod, Attributes attrs, Location l)
+ : base (parent, name, 0, null, l)
+ {
+ if (parent.Parent != null)
+ Report.Error (30617, l,
+ "'Module' statements can occur only at file or namespace level");
+
+ // overwrite ModFlags
+ this.ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.INTERNAL, l);
+
+ // add specialized attribute
+ Utils.AddSpecializedAttribute(ref attrs, "Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute", null, 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 | TypeAttributes.Sealed;
+ }
+ }
+ }
+}
diff --git a/mcs/mbas/namespace.cs b/mcs/mbas/namespace.cs
new file mode 100644
index 00000000000..a173b903620
--- /dev/null
+++ b/mcs/mbas/namespace.cs
@@ -0,0 +1,179 @@
+//
+// 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;
+ ArrayList using_clauses;
+ Hashtable aliases;
+ 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 string Name;
+ public bool Used;
+ public Location Location;
+
+ public UsingEntry (string name, Location loc)
+ {
+ Name = name;
+ Location = loc;
+ Used = false;
+ }
+ }
+
+ /// <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;
+
+ all_namespaces.Add (this);
+ }
+
+ /// <summary>
+ /// The qualified name of the current namespace
+ /// </summary>
+ public string Name {
+ get {
+ string pname = parent != null ? parent.Name : "";
+
+ if (pname == "")
+ return name;
+ else
+ return parent.Name + "." + name;
+ }
+ }
+
+ /// <summary>
+ /// The parent of this namespace, used by the parser to "Pop"
+ /// the current namespace declaration
+ /// </summary>
+ public Namespace Parent {
+ get {
+ return 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 (using_clauses == null)
+ using_clauses = new ArrayList ();
+
+ UsingEntry ue = new UsingEntry (ns, loc);
+ using_clauses.Add (ue);
+ }
+
+ public ArrayList UsingTable {
+ get {
+ return using_clauses;
+ }
+ }
+
+ 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] = namespace_or_type;
+ }
+
+ public string LookupAlias (string alias)
+ {
+ string value = null;
+
+ // System.Console.WriteLine ("Lookup " + alias + " in " + name);
+
+ if (aliases != null)
+ value = (string) (aliases [alias]);
+ if (value == null && Parent != null)
+ value = Parent.LookupAlias (alias);
+
+ return value;
+ }
+
+ /// <summary>
+ /// Used to validate that all the using clauses are correct
+ /// after we are finished parsing all the files.
+ /// </summary>
+ public static bool VerifyUsing ()
+ {
+ ArrayList unused = new ArrayList ();
+ int errors = 0;
+
+ foreach (Namespace ns in all_namespaces){
+ ArrayList uses = ns.UsingTable;
+ if (uses == null)
+ continue;
+
+ foreach (UsingEntry ue in uses){
+ if (ue.Used)
+ continue;
+ unused.Add (ue);
+ }
+ }
+
+ //
+ // If we have unused using aliases, load all namespaces and check
+ // whether it is unused, or it was missing
+ //
+ if (unused.Count > 0){
+ Hashtable namespaces = TypeManager.GetNamespaces ();
+
+ foreach (UsingEntry ue in unused){
+ if (namespaces.Contains (ue.Name)){
+ Report.Warning (6024, ue.Location, "Unused namespace in `using' declaration");
+ continue;
+ }
+
+ errors++;
+ Report.Error (246, ue.Location, "The namespace `" + ue.Name +
+ "' can not be found (missing assembly reference?)");
+ }
+ }
+
+ return errors == 0;
+ }
+
+ }
+}
diff --git a/mcs/mbas/parameter.cs b/mcs/mbas/parameter.cs
new file mode 100644
index 00000000000..d0eac31da32
--- /dev/null
+++ b/mcs/mbas/parameter.cs
@@ -0,0 +1,537 @@
+//
+// 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,
+ VAL = 0,
+ REF = 1,
+ OUT = 2,
+ PARAMS = 4,
+ // This is a flag which says that it's either REF or OUT.
+ ISBYREF = 8,
+ OPTIONAL = 16
+ }
+
+ public readonly Expression TypeName;
+ public readonly Modifier ModFlags;
+ public Attributes OptAttributes;
+ public readonly string Name;
+ public Type parameter_type;
+ public readonly Expression ParameterInitializer;
+ public readonly bool IsOptional;
+
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
+ {
+ Name = name;
+ ModFlags = mod;
+ TypeName = type;
+ OptAttributes = attrs;
+ ParameterInitializer = null;
+ IsOptional = false;
+ }
+
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi)
+ {
+ Name = name;
+ ModFlags = mod;
+ TypeName = type;
+ OptAttributes = attrs;
+ ParameterInitializer = pi;
+ IsOptional = false;
+ }
+
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi, bool opt)
+ {
+ Name = name;
+ ModFlags = mod;
+ TypeName = type;
+ OptAttributes = attrs;
+ ParameterInitializer = pi;
+ IsOptional = opt;
+ }
+
+
+ // <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 (DeclSpace ds, Location l)
+ {
+ if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
+ string n = parameter_type.FullName + "&";
+
+ Type t = RootContext.LookupType (ds, n, false, l);
+
+ return t;
+ }
+
+ 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 (ds, loc).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 HasOptional()
+ {
+ bool res = false;
+
+ foreach (Parameter p in FixedParameters)
+ {
+ if (p.IsOptional)
+ {
+ res = true;
+ break;
+ }
+ }
+ return (res);
+ }
+
+ /// <summary>
+ /// Returns the number of standard (i.e. non-optional) parameters
+ /// </summary>
+ public int CountStandardParams()
+ {
+ int res = 0;
+ if (FixedParameters == null)
+ return 0;
+
+ foreach (Parameter p in FixedParameters) {
+ if (!p.IsOptional)
+ res++;
+ }
+ return (res);
+ }
+
+ /// <summary>
+ /// Returns the number of optional parameters
+ /// </summary>
+ public int CountOptionalParams()
+ {
+ int res = 0;
+ if (FixedParameters == null)
+ return 0;
+
+ foreach (Parameter p in FixedParameters) {
+ if (p.IsOptional)
+ res++;
+ }
+ return (res);
+ }
+
+ public Expression GetDefaultValue (int i)
+ {
+ Parameter p = FixedParameters[i];
+ if (p.IsOptional)
+ return p.ParameterInitializer;
+ else
+ return null;
+ }
+
+ public void AppendParameter (Parameter p)
+ {
+ if (FixedParameters != null)
+ {
+ Parameter [] pa = new Parameter [FixedParameters.Length+1];
+ FixedParameters.CopyTo (pa, 0);
+ pa[FixedParameters.Length] = p;
+ FixedParameters = pa;
+ }
+ else
+ {
+ FixedParameters = new Parameter [1];
+ FixedParameters[0] = p;
+ }
+ }
+
+ public void PrependParameter (Parameter p)
+ {
+ Parameter [] pa = new Parameter [FixedParameters.Length+1];
+ FixedParameters.CopyTo (pa, 1);
+ pa[0] = p;
+ FixedParameters = pa;
+ }
+
+ public Parameters Copy (Location l)
+ {
+ Parameters p = new Parameters (null, null, l);
+ p.FixedParameters = new Parameter[this.FixedParameters.Length];
+ this.FixedParameters.CopyTo (p.FixedParameters, 0);
+
+ return (p);
+
+ }
+
+ 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 (ds, loc);
+ else
+ failed = true;
+
+ types [i] = t;
+ i++;
+ }
+ }
+
+ if (extra > 0){
+ if (ArrayParameter.Resolve (ds, loc))
+ types [i] = ArrayParameter.ExternalType (ds, loc);
+ 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 (ds, loc);
+ else
+ ok_flag = false;
+
+ types [i] = t;
+ i++;
+ }
+ }
+
+ if (extra > 0){
+ if (ArrayParameter.Resolve (ds, loc))
+ types [i] = ArrayParameter.ExternalType (ds, loc);
+ 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;
+ }
+ }
+}
+
+
+
diff --git a/mcs/mbas/pending.cs b/mcs/mbas/pending.cs
new file mode 100644
index 00000000000..5f01b009548
--- /dev/null
+++ b/mcs/mbas/pending.cs
@@ -0,0 +1,514 @@
+//
+// 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;
+
+ // 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, Type [] ifaces, ArrayList abstract_methods, int total)
+ {
+ TypeBuilder type_builder = container.TypeBuilder;
+
+ this.container = container;
+ pending_implementations = new TypeAndMethods [total];
+
+ int i = 0;
+ if (ifaces != null){
+ foreach (Type t in ifaces){
+ MethodInfo [] mi;
+
+ 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 = t;
+ 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++;
+ }
+ }
+ }
+
+ //
+ // 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;
+ Type [] ifaces;
+ Type b = type_builder.BaseType;
+ int icount = 0;
+
+ //
+ // 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.
+ //
+ ifaces = type_builder.GetInterfaces ();
+
+#if DEBUG
+ {
+ Type x = type_builder;
+
+ while (x != null){
+ Type [] iff = x.GetInterfaces ();
+ Console.WriteLine ("Type: " + x.Name);
+
+ foreach (Type tt in iff){
+ Console.WriteLine (" Iface: " + tt.Name);
+ }
+ x = x.BaseType;
+ }
+ }
+#endif
+
+ icount = ifaces.Length;
+
+ //
+ // 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 = icount + (implementing_abstract ? 1 : 0);
+ if (total == 0)
+ return null;
+
+ return new PendingImplementation (container, ifaces, 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 i = 0;
+ foreach (MethodInfo m in tm.methods){
+ if (m == null){
+ i++;
+ 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)){
+ i++;
+ continue;
+ }
+
+ if (ret_type != m.ReturnType){
+ if (!((ret_type == null && m.ReturnType == TypeManager.void_type) ||
+ (m.ReturnType == null && ret_type == TypeManager.void_type)))
+ {
+ i++;
+ continue;
+ }
+ }
+
+ //
+ // Check if we have the same parameters
+ //
+ if (tm.args [i].Length != arg_len){
+ i++;
+ 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){
+ i++;
+ 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;
+
+ DefineProxy (iface_type, (MethodInfo) list [0], 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;
+
+ string extra = "";
+
+ if (pending_implementations [i].found [j])
+ extra = ". (method might be private 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 */
+}
diff --git a/mcs/mbas/report.cs b/mcs/mbas/report.cs
new file mode 100644
index 00000000000..946355815ec
--- /dev/null
+++ b/mcs/mbas/report.cs
@@ -0,0 +1,359 @@
+//
+// 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)
+ {
+ string msg = String.Format (
+ "{0}({1}) error BC{2:0000}: {3}", l.Name, l.Row, code, text);
+// "{0}({1}) error BC{2}: {3}", l.Name, l.Row, code, text);
+
+ RealError (msg);
+ Check (code);
+ }
+
+ static public void Warning (int code, Location l, string text)
+ {
+ 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 BC{2:0000}: {3}",
+// "{0}({1}) warning BC{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)
+ {
+ string msg = String.Format ("error BC{0:0000}: {1}", code, text);
+// string msg = String.Format ("error BC{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)
+ {
+ }
+ }
+}
diff --git a/mcs/mbas/rootcontext.cs b/mcs/mbas/rootcontext.cs
new file mode 100644
index 00000000000..5505d95d8cc
--- /dev/null
+++ b/mcs/mbas/rootcontext.cs
@@ -0,0 +1,840 @@
+//
+// 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 TypeBuilder impl_details_class;
+
+ public static int WarningLevel = 2;
+
+ //
+ // 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)
+ {
+ string prefix = (nsn == "" ? "" : nsn + ".");
+
+ return prefix + 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",
+ };
+
+ // 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 (impl_details_class != null){
+ impl_details_class.CreateType ();
+ }
+ }
+
+ //
+ // 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 (Namespace curr_ns, string name, Location loc)
+ {
+ Type t;
+
+ //
+ // Try in the current namespace and all its implicit parents
+ //
+ for (string ns = curr_ns.Name; ns != null; ns = ImplicitParent (ns)) {
+ t = TypeManager.LookupType (MakeFQN (ns, name));
+ 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 = curr_ns.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 (Namespace ns = curr_ns; ns != null; ns = ns.Parent) {
+ //
+ // Look in the namespace ns
+ //
+ t = TypeManager.LookupType (MakeFQN (ns.Name, name));
+ if (t != null)
+ return t;
+
+ //
+ // Then try with the using clauses
+ //
+ ArrayList using_list = ns.UsingTable;
+
+ if (using_list == null)
+ continue;
+
+ Type match = null;
+ foreach (Namespace.UsingEntry ue in using_list) {
+ match = TypeManager.LookupType (MakeFQN (ue.Name, name));
+ if (match != null){
+ if (t != null){
+ DeclSpace.Error_AmbiguousTypeReference (loc, name, t, match);
+ return null;
+ }
+
+ t = match;
+ ue.Used = true;
+ }
+ }
+ 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.Namespace, 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){
+ 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.DefineMembers (root);
+ else
+ Report1530 (tc.Location);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ 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){
+ Namespace ns = (Namespace) de.Key;
+ Attributes attrs = (Attributes) de.Value;
+
+ dummy.Namespace = ns;
+ Attribute.ApplyAttributes (temp_ec, ab, ab, attrs, attrs.Location);
+ }
+ }
+
+ if (attribute_types != null)
+ foreach (TypeContainer tc in attribute_types)
+ tc.Emit ();
+
+ 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 ();
+ }
+
+ 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);
+
+ 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 AddGlobalAttribute (TypeContainer container,
+ AttributeSection attr, Location loc)
+ {
+ Namespace ns = container.Namespace;
+ Attributes a = (Attributes) global_attributes [ns];
+
+ if (a == null)
+ global_attributes [ns] = new Attributes (attr, loc);
+ else
+ a.AddAttribute (attr);
+ }
+ }
+}
+
+
diff --git a/mcs/mbas/statement.cs b/mcs/mbas/statement.cs
new file mode 100644
index 00000000000..25bd4c45cd7
--- /dev/null
+++ b/mcs/mbas/statement.cs
@@ -0,0 +1,5416 @@
+//
+// statement.cs: Statement representation for the IL tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+// Martin Baulig (martin@gnome.org)
+//
+// (C) 2001, 2002 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);
+ Report.Debug (8, "MARK", this, loc);
+ return DoEmit (ec);
+ }
+
+ public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
+ {
+ e = e.Resolve (ec);
+ if (e == null)
+ return null;
+
+ if (e.Type != TypeManager.bool_type){
+ e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
+ new Location (-1));
+ }
+
+ if (e == null){
+ Report.Error (
+ 31, loc, "Can not convert the expression to a boolean");
+ }
+
+ ec.Mark (loc);
+
+ return e;
+ }
+
+ /// <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 = 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 enum DoOptions {
+ WHILE,
+ UNTIL,
+ TEST_BEFORE,
+ TEST_AFTER
+ };
+
+ public class Do : Statement {
+ public Expression expr;
+ public readonly Statement EmbeddedStatement;
+ //public DoOptions type;
+ public DoOptions test;
+ bool infinite, may_return;
+
+
+ public Do (Statement statement, Expression boolExpr, DoOptions do_test, Location l)
+ {
+ expr = boolExpr;
+ EmbeddedStatement = statement;
+// type = do_type;
+ test = do_test;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = true;
+
+ ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+
+ if (!EmbeddedStatement.Resolve (ec))
+ ok = false;
+
+ expr = 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;
+
+ if (test == DoOptions.TEST_AFTER) {
+ 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);
+ }
+ else
+ {
+ ig.MarkLabel (loop);
+ ig.MarkLabel (ec.LoopBegin);
+
+ //
+ // Dead code elimination
+ //
+ if (expr is BoolConstant){
+ bool res = ((BoolConstant) expr).Value;
+
+ if (res)
+ ec.ig.Emit (OpCodes.Br, ec.LoopEnd);
+ } else
+ EmitBoolExpression (ec, expr, ec.LoopEnd, true);
+
+ EmbeddedStatement.Emit (ec);
+ ec.ig.Emit (OpCodes.Br, loop);
+ 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 = 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 = 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;
+
+ if (Increment != null){
+ if (!Increment.Resolve (ec))
+ ok = false;
+ }
+
+ ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+ if (!infinite)
+ 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;
+ 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)
+ 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 {
+ Expression expr;
+
+ public StatementExpression (ExpressionStatement expr, Location l)
+ {
+ this.expr = expr;
+ loc = l;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ expr = (Expression) expr.Resolve (ec);
+ return expr != null;
+ }
+
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (expr is ExpressionStatement)
+ ((ExpressionStatement) expr).EmitStatement (ec);
+ else {
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Pop);
+ }
+
+ 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;
+ }
+
+ 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 = Expression.ConvertImplicitRequired (
+ 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);
+
+ 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;
+
+ 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.UNREACHABLE;
+ 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");
+ }
+
+ label = sl.ILLabelCode;
+
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
+ 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.Error118 ("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 enum ExitType {
+ DO,
+ FOR,
+ WHILE,
+ SELECT,
+ SUB,
+ FUNCTION,
+ PROPERTY,
+ TRY
+ };
+
+ public class Exit : Statement {
+ public readonly ExitType type;
+ public Exit (ExitType t, Location l)
+ {
+ loc = l;
+ type = t;
+ }
+
+ 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 ArrayList 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
+ //
+ InternalParameters param_info;
+ int[] param_map;
+ MyStructInfo[] struct_params;
+ int num_params;
+ 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;
+ }
+
+ //
+ // State of parameter `number'.
+ //
+ public bool this [int number]
+ {
+ get {
+ if (number == -1)
+ return true;
+ else if (number == 0)
+ throw new ArgumentException ();
+
+ return parameters [number - 1];
+ }
+
+ set {
+ if (number == -1)
+ return;
+ else if (number == 0)
+ throw new ArgumentException ();
+
+ parameters [number - 1] = value;
+ }
+ }
+
+ //
+ // State of the local variable `vi'.
+ // If the local variable is a struct, use a non-zero `field_idx'
+ // to check an individual field in it.
+ //
+ public bool this [VariableInfo vi, int field_idx]
+ {
+ get {
+ if (vi.Number == -1)
+ return true;
+ else if (vi.Number == 0)
+ throw new ArgumentException ();
+
+ return locals [vi.Number + field_idx - 1];
+ }
+
+ set {
+ if (vi.Number == -1)
+ return;
+ else if (vi.Number == 0)
+ throw new ArgumentException ();
+
+ locals [vi.Number + field_idx - 1] = value;
+ }
+ }
+
+ // <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, ICollection 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.Count);
+
+ 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.Count == 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) {
+ if (child.Breaks != FlowReturns.EXCEPTION) {
+ if (new_params != null)
+ new_params.And (child.parameters);
+ else {
+ new_params = parameters.Clone ();
+ new_params.Or (child.parameters);
+ }
+ } else if (children.Count == 1) {
+ 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.Count == 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;
+ }
+ }
+
+ 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.Siblings = new ArrayList ();
+ 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, InternalParameters ip, Location loc)
+ : this (FlowBranchingType.BLOCK, loc)
+ {
+ Block = block;
+ Parent = null;
+
+ int count = (ip != null) ? ip.Count : 0;
+
+ param_info = ip;
+ param_map = new int [count];
+ struct_params = new MyStructInfo [count];
+ num_params = 0;
+
+ for (int i = 0; i < count; i++) {
+ Parameter.Modifier mod = param_info.ParameterModifier (i);
+
+ if ((mod & Parameter.Modifier.OUT) == 0)
+ continue;
+
+ param_map [i] = ++num_params;
+
+ Type param_type = param_info.ParameterType (i);
+
+ struct_params [i] = MyStructInfo.GetStructInfo (param_type);
+ if (struct_params [i] != null)
+ num_params += struct_params [i].Count;
+ }
+
+ Siblings = new ArrayList ();
+ Siblings.Add (new UsageVector (null, num_params, block.CountVariables));
+ }
+
+ // <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;
+
+ if (parent != null) {
+ param_info = parent.param_info;
+ param_map = parent.param_map;
+ struct_params = parent.struct_params;
+ num_params = parent.num_params;
+ }
+
+ UsageVector vector;
+ if (Block != null)
+ vector = new UsageVector (parent.CurrentUsageVector, num_params,
+ Block.CountVariables);
+ else
+ vector = new UsageVector (Parent.CurrentUsageVector);
+
+ Siblings.Add (vector);
+
+ switch (Type) {
+ case FlowBranchingType.EXCEPTION:
+ finally_vectors = new ArrayList ();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // <summary>
+ // Returns the branching's current usage vector.
+ // </summary>
+ public UsageVector CurrentUsageVector
+ {
+ get {
+ return (UsageVector) Siblings [Siblings.Count - 1];
+ }
+ }
+
+ // <summary>
+ // Creates a sibling of the current usage vector.
+ // </summary>
+ public void CreateSibling ()
+ {
+ Siblings.Add (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.Length; i++) {
+ int index = param_map [i];
+
+ if (index == 0)
+ continue;
+
+ if (parameters [index - 1])
+ continue;
+
+ // If it's a struct, we must ensure that all its fields have
+ // been assigned. If the struct has any non-public fields, this
+ // can only be done by assigning the whole struct.
+
+ MyStructInfo struct_info = struct_params [index - 1];
+ if ((struct_info == null) || struct_info.HasNonPublicFields) {
+ Report.Error (
+ 177, loc, "The out parameter `" +
+ param_info.ParameterName (i) + "' must be " +
+ "assigned before control leave the current method.");
+ param_map [i] = 0;
+ continue;
+ }
+
+
+ for (int j = 0; j < struct_info.Count; j++) {
+ if (!parameters [index + j]) {
+ Report.Error (
+ 177, loc, "The out parameter `" +
+ param_info.ParameterName (i) + "' must be " +
+ "assigned before control leave the current method.");
+ param_map [i] = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ // <summary>
+ // Merge a child branching.
+ // </summary>
+ public FlowReturns MergeChild (FlowBranching child)
+ {
+ FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings);
+
+ if (child.Type != FlowBranchingType.LOOP_BLOCK)
+ MayLeaveLoop |= child.MayLeaveLoop;
+ else
+ MayLeaveLoop = false;
+
+ 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, num_params, Block.CountVariables);
+
+ Report.Debug (1, "MERGING TOP BLOCK", Location, vector);
+
+ vector.MergeChildren (this, Siblings);
+
+ Siblings.Clear ();
+ Siblings.Add (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 IsVariableAssigned (VariableInfo vi)
+ {
+ if (CurrentUsageVector.AlwaysBreaks)
+ return true;
+ else
+ return CurrentUsageVector [vi, 0];
+ }
+
+ public bool IsVariableAssigned (VariableInfo vi, int field_idx)
+ {
+ if (CurrentUsageVector.AlwaysBreaks)
+ return true;
+ else
+ return CurrentUsageVector [vi, field_idx];
+ }
+
+ public void SetVariableAssigned (VariableInfo vi)
+ {
+ if (CurrentUsageVector.AlwaysBreaks)
+ return;
+
+ CurrentUsageVector [vi, 0] = true;
+ }
+
+ public void SetVariableAssigned (VariableInfo vi, int field_idx)
+ {
+ if (CurrentUsageVector.AlwaysBreaks)
+ return;
+
+ CurrentUsageVector [vi, field_idx] = true;
+ }
+
+ public bool IsParameterAssigned (int number)
+ {
+ int index = param_map [number];
+
+ if (index == 0)
+ return true;
+
+ if (CurrentUsageVector [index])
+ return true;
+
+ // Parameter is not assigned, so check whether it's a struct.
+ // If it's either not a struct or a struct which non-public
+ // fields, return false.
+ MyStructInfo struct_info = struct_params [number];
+ if ((struct_info == null) || struct_info.HasNonPublicFields)
+ return false;
+
+ // Ok, so each field must be assigned.
+ for (int i = 0; i < struct_info.Count; i++)
+ if (!CurrentUsageVector [index + i])
+ return false;
+
+ return true;
+ }
+
+ public bool IsParameterAssigned (int number, string field_name)
+ {
+ int index = param_map [number];
+
+ if (index == 0)
+ return true;
+
+ MyStructInfo info = (MyStructInfo) struct_params [number];
+ if (info == null)
+ return true;
+
+ int field_idx = info [field_name];
+
+ return CurrentUsageVector [index + field_idx];
+ }
+
+ public void SetParameterAssigned (int number)
+ {
+ if (param_map [number] == 0)
+ return;
+
+ if (!CurrentUsageVector.AlwaysBreaks)
+ CurrentUsageVector [param_map [number]] = true;
+ }
+
+ public void SetParameterAssigned (int number, string field_name)
+ {
+ int index = param_map [number];
+
+ if (index == 0)
+ return;
+
+ MyStructInfo info = (MyStructInfo) struct_params [number];
+ if (info == null)
+ return;
+
+ int field_idx = info [field_name];
+
+ if (!CurrentUsageVector.AlwaysBreaks)
+ CurrentUsageVector [index + field_idx] = true;
+ }
+
+ 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.
+ reachable = !CurrentUsageVector.AlwaysBreaks &&
+ !CurrentUsageVector.AlwaysReturns;
+ break;
+ }
+
+ Report.Debug (1, "REACHABLE", Type, CurrentUsageVector.Returns,
+ CurrentUsageVector.Breaks, CurrentUsageVector, 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.Count);
+ sb.Append (" - ");
+ sb.Append (CurrentUsageVector);
+ sb.Append (")");
+ return sb.ToString ();
+ }
+ }
+
+ public class MyStructInfo {
+ public readonly Type Type;
+ public readonly FieldInfo[] Fields;
+ public readonly FieldInfo[] NonPublicFields;
+ public readonly int Count;
+ public readonly int CountNonPublic;
+ public readonly bool HasNonPublicFields;
+
+ private static Hashtable field_type_hash = new Hashtable ();
+ private Hashtable field_hash;
+
+ // Private constructor. To save memory usage, we only need to create one instance
+ // of this class per struct type.
+ private MyStructInfo (Type type)
+ {
+ this.Type = type;
+
+ if (type is TypeBuilder) {
+ TypeContainer tc = TypeManager.LookupTypeContainer (type);
+
+ ArrayList fields = tc.Fields;
+ if (fields != null) {
+ foreach (Field field in fields) {
+ if ((field.ModFlags & Modifiers.STATIC) != 0)
+ continue;
+ if ((field.ModFlags & Modifiers.PUBLIC) != 0)
+ ++Count;
+ else
+ ++CountNonPublic;
+ }
+ }
+
+ Fields = new FieldInfo [Count];
+ NonPublicFields = new FieldInfo [CountNonPublic];
+
+ Count = CountNonPublic = 0;
+ if (fields != null) {
+ foreach (Field field in fields) {
+ if ((field.ModFlags & Modifiers.STATIC) != 0)
+ continue;
+ if ((field.ModFlags & Modifiers.PUBLIC) != 0)
+ Fields [Count++] = field.FieldBuilder;
+ else
+ NonPublicFields [CountNonPublic++] =
+ field.FieldBuilder;
+ }
+ }
+
+ } else {
+ Fields = type.GetFields (BindingFlags.Instance|BindingFlags.Public);
+ Count = Fields.Length;
+
+ NonPublicFields = type.GetFields (BindingFlags.Instance|BindingFlags.NonPublic);
+ CountNonPublic = NonPublicFields.Length;
+ }
+
+ Count += NonPublicFields.Length;
+
+ int number = 0;
+ field_hash = new Hashtable ();
+ foreach (FieldInfo field in Fields)
+ field_hash.Add (field.Name, ++number);
+
+ if (NonPublicFields.Length != 0)
+ HasNonPublicFields = true;
+
+ foreach (FieldInfo field in NonPublicFields)
+ field_hash.Add (field.Name, ++number);
+ }
+
+ public int this [string name] {
+ get {
+ if (field_hash.Contains (name))
+ return (int) field_hash [name];
+ else
+ return 0;
+ }
+ }
+
+ public FieldInfo this [int index] {
+ get {
+ if (index >= Fields.Length)
+ return NonPublicFields [index - Fields.Length];
+ else
+ return Fields [index];
+ }
+ }
+
+ public static MyStructInfo GetStructInfo (Type type)
+ {
+ if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type))
+ return null;
+
+ if (!(type is TypeBuilder) && TypeManager.IsBuiltinType (type))
+ return null;
+
+ MyStructInfo info = (MyStructInfo) field_type_hash [type];
+ if (info != null)
+ return info;
+
+ info = new MyStructInfo (type);
+ field_type_hash.Add (type, info);
+ return info;
+ }
+
+ public static MyStructInfo GetStructInfo (TypeContainer tc)
+ {
+ MyStructInfo info = (MyStructInfo) field_type_hash [tc.TypeBuilder];
+ if (info != null)
+ return info;
+
+ info = new MyStructInfo (tc.TypeBuilder);
+ field_type_hash.Add (tc.TypeBuilder, info);
+ return info;
+ }
+ }
+
+ public class VariableInfo : IVariable {
+ public Expression Type;
+ public LocalBuilder LocalBuilder;
+ public Type VariableType;
+ public readonly string Name;
+ public readonly Location Location;
+ public readonly int Block;
+
+ public int Number;
+
+ public bool Used;
+ public bool Assigned;
+ public bool ReadOnly;
+
+ public VariableInfo (Expression type, string name, int block, Location l)
+ {
+ Type = type;
+ Name = name;
+ Block = block;
+ LocalBuilder = null;
+ Location = l;
+ }
+
+ public VariableInfo (TypeContainer tc, int block, Location l)
+ {
+ VariableType = tc.TypeBuilder;
+ struct_info = MyStructInfo.GetStructInfo (tc);
+ Block = block;
+ LocalBuilder = null;
+ Location = l;
+ }
+
+ MyStructInfo struct_info;
+ public MyStructInfo StructInfo {
+ get {
+ return struct_info;
+ }
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this))
+ return true;
+
+ MyStructInfo struct_info = StructInfo;
+ if ((struct_info == null) || (struct_info.HasNonPublicFields && (Name != null))) {
+ Report.Error (165, loc, "Use of unassigned local variable `" + Name + "'");
+ ec.CurrentBranching.SetVariableAssigned (this);
+ return false;
+ }
+
+ int count = struct_info.Count;
+
+ for (int i = 0; i < count; i++) {
+ if (!ec.CurrentBranching.IsVariableAssigned (this, i+1)) {
+ if (Name != null) {
+ Report.Error (165, loc,
+ "Use of unassigned local variable `" +
+ Name + "'");
+ ec.CurrentBranching.SetVariableAssigned (this);
+ return false;
+ }
+
+ FieldInfo field = struct_info [i];
+ Report.Error (171, loc,
+ "Field `" + TypeManager.CSharpName (VariableType) +
+ "." + field.Name + "' must be fully initialized " +
+ "before control leaves the constructor");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
+ {
+ if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this) ||
+ (struct_info == null))
+ return true;
+
+ int field_idx = StructInfo [name];
+ if (field_idx == 0)
+ return true;
+
+ if (!ec.CurrentBranching.IsVariableAssigned (this, field_idx)) {
+ Report.Error (170, loc,
+ "Use of possibly unassigned field `" + name + "'");
+ ec.CurrentBranching.SetVariableAssigned (this, field_idx);
+ return false;
+ }
+
+ return true;
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetVariableAssigned (this);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string name)
+ {
+ if (ec.DoFlowAnalysis && (struct_info != null))
+ ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
+ }
+
+ public bool Resolve (DeclSpace decl)
+ {
+ if (struct_info != null)
+ return true;
+
+ if (VariableType == null)
+ VariableType = decl.ResolveType (Type, false, Location);
+
+ if (VariableType == null)
+ return false;
+
+ struct_info = MyStructInfo.GetStructInfo (VariableType);
+
+ return true;
+ }
+
+ public void MakePinned ()
+ {
+ TypeManager.MakePinned (LocalBuilder);
+ }
+
+ public override string ToString ()
+ {
+ return "VariableInfo (" + Number + "," + Type + "," + 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 bool Implicit;
+ public readonly Location StartLocation;
+ public Location EndLocation;
+
+ //
+ // The statements in this block
+ //
+ public 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;
+
+ //
+ // Maps variable names to ILGenerator.LocalBuilders
+ //
+ Hashtable local_builders;
+
+ bool used = false;
+
+ static int id;
+
+ int this_id;
+
+ public Block (Block parent)
+ : this (parent, false, Location.Null, Location.Null)
+ { }
+
+ public Block (Block parent, bool implicit_block)
+ : this (parent, implicit_block, Location.Null, Location.Null)
+ { }
+
+ public Block (Block parent, bool implicit_block, Parameters parameters)
+ : this (parent, implicit_block, parameters, Location.Null, Location.Null)
+ { }
+
+ public Block (Block parent, Location start, Location end)
+ : this (parent, false, start, end)
+ { }
+
+ public Block (Block parent, Parameters parameters, Location start, Location end)
+ : this (parent, false, parameters, start, end)
+ { }
+
+ public Block (Block parent, bool implicit_block, Location start, Location end)
+ : this (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
+ start, end)
+ { }
+
+ public Block (Block parent, bool implicit_block, Parameters parameters,
+ Location start, Location end)
+ {
+ if (parent != null)
+ parent.AddChild (this);
+
+ this.Parent = parent;
+ this.Implicit = implicit_block;
+ this.parameters = parameters;
+ this.StartLocation = start;
+ this.EndLocation = end;
+ this.loc = start;
+ this_id = id++;
+ statements = new ArrayList ();
+ }
+
+ 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 (labels == null)
+ labels = new Hashtable ();
+ if (labels.Contains (name))
+ return false;
+
+ labels.Add (name, target);
+ return true;
+ }
+
+ public LabeledStatement LookupLabel (string name)
+ {
+ if (labels != null){
+ if (labels.Contains (name))
+ return ((LabeledStatement) labels [name]);
+ }
+
+ if (Parent != null)
+ return Parent.LookupLabel (name);
+
+ return null;
+ }
+
+ VariableInfo this_variable = null;
+
+ // <summary>
+ // Returns the "this" instance variable of this block.
+ // See AddThisVariable() for more information.
+ // </summary>
+ public VariableInfo 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);
+ }
+
+ foreach (Block child in block.children) {
+ if (child.Variables != null) {
+ foreach (string name in child.Variables.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 VariableInfo AddThisVariable (TypeContainer tc, Location l)
+ {
+ if (this_variable != null)
+ return this_variable;
+
+ this_variable = new VariableInfo (tc, ID, l);
+
+ if (variables == null)
+ variables = new Hashtable ();
+ variables.Add ("this", this_variable);
+
+ return this_variable;
+ }
+
+ public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
+ {
+ if (variables == null)
+ variables = new Hashtable ();
+
+ VariableInfo vi = GetVariableInfo (name);
+ if (vi != null) {
+ if (vi.Block != ID)
+ 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 VariableInfo (type, name, ID, 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 VariableInfo GetVariableInfo (string name)
+ {
+ if (variables != null) {
+ object temp;
+ temp = variables [name];
+
+ if (temp != null){
+ return (VariableInfo) temp;
+ }
+ }
+
+ if (Parent != null)
+ return Parent.GetVariableInfo (name);
+
+ return null;
+ }
+
+ public Expression GetVariableType (string name)
+ {
+ VariableInfo vi = GetVariableInfo (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 has been defined
+ /// in this block
+ /// </summary>
+ public bool IsVariableDefined (string name)
+ {
+ // Console.WriteLine ("Looking up {0} in {1}", name, ID);
+ if (variables != null) {
+ if (variables.Contains (name))
+ return true;
+ }
+
+ if (Parent != null)
+ return Parent.IsVariableDefined (name);
+
+ return false;
+ }
+
+ /// <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;
+ }
+
+ bool variables_initialized = false;
+ int count_variables = 0, first_variable = 0;
+
+ void UpdateVariableInfo (EmitContext ec)
+ {
+ DeclSpace ds = ec.DeclSpace;
+
+ first_variable = 0;
+
+ if (Parent != null)
+ first_variable += Parent.CountVariables;
+
+ count_variables = first_variable;
+ if (variables != null) {
+ foreach (VariableInfo vi in variables.Values) {
+ if (!vi.Resolve (ds)) {
+ vi.Number = -1;
+ continue;
+ }
+
+ vi.Number = ++count_variables;
+
+ if (vi.StructInfo != null)
+ count_variables += vi.StructInfo.Count;
+ }
+ }
+
+ variables_initialized = true;
+ }
+
+ //
+ // <returns>
+ // The number of local variables in this block
+ // </returns>
+ public int CountVariables
+ {
+ get {
+ if (!variables_initialized)
+ throw new Exception ();
+
+ return count_variables;
+ }
+ }
+
+ /// <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, Block toplevel)
+ {
+ DeclSpace ds = ec.DeclSpace;
+ ILGenerator ig = ec.ig;
+
+ if (!variables_initialized)
+ UpdateVariableInfo (ec);
+
+ //
+ // Process this block variables
+ //
+ if (variables != null){
+ local_builders = new Hashtable ();
+
+ foreach (DictionaryEntry de in variables){
+ string name = (string) de.Key;
+ VariableInfo vi = (VariableInfo) de.Value;
+
+ if (vi.VariableType == null)
+ continue;
+
+ vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
+
+ if (CodeGen.SymbolWriter != null)
+ vi.LocalBuilder.SetLocalSymInfo (name);
+
+ if (constants == null)
+ continue;
+
+ Expression cv = (Expression) constants [name];
+ if (cv == null)
+ continue;
+
+ 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);
+ }
+ }
+
+ //
+ // Now, handle the children
+ //
+ if (children != null){
+ foreach (Block b in children)
+ b.EmitMeta (ec, toplevel);
+ }
+ }
+
+ public void UsageWarning ()
+ {
+ string name;
+
+ if (variables != null){
+ foreach (DictionaryEntry de in variables){
+ VariableInfo vi = (VariableInfo) 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);
+
+ if (!variables_initialized)
+ UpdateVariableInfo (ec);
+
+ 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.IsAssigned (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)
+ {
+ Block prev_block = ec.CurrentBlock;
+
+ ec.CurrentBlock = this;
+
+ ec.Mark (StartLocation);
+ foreach (Statement s in statements)
+ s.Emit (ec);
+ ec.Mark (EndLocation);
+
+ ec.CurrentBlock = prev_block;
+ return has_ret;
+ }
+ }
+
+ 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)){
+ Console.WriteLine ("Value is: " + label);
+ Report.Error (150, loc, "A constant value is expected");
+ 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 = Expression.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 (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 : 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, Convert.ChangeType (kb.nFirst, typeKeys));
+ ig.Emit (OpCodes.Blt, lblDefault);
+ ig.Emit (OpCodes.Ldloc, val);
+ EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
+ ig.Emit (OpCodes.Bgt, lblDefault);
+
+ // normalize range
+ ig.Emit (OpCodes.Ldloc, val);
+ if (kb.nFirst != 0)
+ {
+ EmitObjectInteger (ig, 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 (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 is_string = false;
+ bool null_found;
+
+ //
+ // Special processing for strings: we cant compare
+ // against null.
+ //
+ if (SwitchType == TypeManager.string_type){
+ ig.Emit (OpCodes.Ldloc, val);
+ is_string = true;
+
+ 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);
+ }
+
+ foreach (SwitchSection ss in Sections){
+ 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;
+ foreach (SwitchLabel sl in ss.Labels){
+ 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;
+
+ }
+ if (is_string){
+ 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
+ ig.Emit (OpCodes.Beq, sec_begin);
+ } else {
+ ig.Emit (OpCodes.Ldloc, val);
+ EmitObjectInteger (ig, lit);
+ ig.Emit (OpCodes.Ceq);
+ if (label_count == 1)
+ ig.Emit (OpCodes.Brfalse, next_test);
+ else
+ ig.Emit (OpCodes.Brtrue, sec_begin);
+ }
+ }
+ }
+ if (label_count != 1)
+ ig.Emit (OpCodes.Br, next_test);
+
+ 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;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ return Block.Resolve (ec);
+ }
+
+ 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;
+ }
+
+ 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 VariableInfo 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)
+ {
+ expr_type = ec.DeclSpace.ResolveType (type, false, loc);
+ if (expr_type == null)
+ return false;
+
+ data = new FixedData [declarators.Count];
+
+ int i = 0;
+ foreach (Pair p in declarators){
+ VariableInfo vi = (VariableInfo) p.First;
+ Expression e = (Expression) p.Second;
+
+ vi.Number = -1;
+
+ //
+ // 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;
+ }
+
+ e = e.Resolve (ec);
+ 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;
+ }
+
+ e = e.Resolve (ec);
+ if (e == null)
+ return false;
+
+ //
+ // Case 2: Array
+ //
+ if (e.Type.IsArray){
+ Type array_type = e.Type.GetElementType ();
+
+ 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 = Expression.ConvertImplicitRequired (
+ 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;
+
+ for (int i = 0; i < data.Length; i++) {
+ VariableInfo 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);
+
+ is_ret = statement.Emit (ec);
+
+ // Clear the pinned variable.
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Conv_U);
+ ig.Emit (OpCodes.Stloc, 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);
+
+ is_ret = statement.Emit (ec);
+
+ // Clear the pinned variable.
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Conv_U);
+ ig.Emit (OpCodes.Stloc, 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);
+
+ data [i].expr.Emit (ec);
+ ig.Emit (OpCodes.Stloc, pinned_string);
+
+ Expression sptr = new StringPtr (pinned_string, loc);
+ Expression converted = Expression.ConvertImplicitRequired (
+ ec, sptr, vi.VariableType, loc);
+
+ if (converted == null)
+ continue;
+
+ converted.Emit (ec);
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+
+ is_ret = statement.Emit (ec);
+
+ // Clear the pinned variable
+ ig.Emit (OpCodes.Ldnull);
+ ig.Emit (OpCodes.Stloc, pinned_string);
+ }
+ }
+
+ 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) {
+ VariableInfo vi = c.Block.GetVariableInfo (c.Name);
+ if (vi == null)
+ throw new Exception ();
+
+ vi.Number = -1;
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
+
+ if (Fini != null) {
+ 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);
+
+ 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){
+ VariableInfo vi;
+
+ ig.BeginCatchBlock (c.CatchType);
+
+ if (c.Name != null){
+ vi = c.Block.GetVariableInfo (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--;
+
+ if (!returns || ec.InTry || ec.InCatch)
+ return returns;
+
+ // 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.
+
+ if (ec.ReturnType != null)
+ ec.ig.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
+ ec.ig.Emit (OpCodes.Ret);
+
+ return true;
+ }
+ }
+
+ 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] = Expression.ConvertImplicitRequired (
+ 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 = Expression.ConvertImplicitRequired (
+ 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 = array_type.GetElementType ();
+
+ 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 = Expression.ConvertExplicit (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;
+ }
+
+ //
+ // 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))) {
+ 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 = 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);
+ ArrayAccess.EmitLoadOpcode (ig, var_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;
+ }
+ }
+}
diff --git a/mcs/mbas/statementCollection.cs b/mcs/mbas/statementCollection.cs
new file mode 100644
index 00000000000..9e5141dfdc6
--- /dev/null
+++ b/mcs/mbas/statementCollection.cs
@@ -0,0 +1,166 @@
+//
+// 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;
+ }
+ }
+ }
+}
diff --git a/mcs/mbas/support.cs b/mcs/mbas/support.cs
new file mode 100644
index 00000000000..3db32ac9da6
--- /dev/null
+++ b/mcs/mbas/support.cs
@@ -0,0 +1,258 @@
+//
+// 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
+ return pi [pos].ParameterType;
+ }
+
+ 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].IsOut)
+ sb.Append ("out ");
+
+ if (pi [pos].IsIn)
+ sb.Append ("in ");
+
+ if (pos >= pi.Length - 1 && last_arg_is_params)
+ sb.Append ("params ");
+
+ sb.Append (TypeManager.CSharpName (ParameterType (pos)));
+
+ 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)
+ return Parameter.Modifier.ISBYREF;
+
+ 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;
+ }
+ }
+
+ public Type ParameterType (int pos)
+ {
+ if (param_types == null)
+ return null;
+
+ Parameter [] fixed_pars = Parameters.FixedParameters;
+ if (fixed_pars != null){
+ int len = fixed_pars.Length;
+ if (pos < len)
+ return Parameters.FixedParameters [pos].ParameterType;
+ else
+ return Parameters.ArrayParameter.ParameterType;
+ } else
+ return Parameters.ArrayParameter.ParameterType;
+ }
+
+ public string ParameterName (int pos)
+ {
+ Parameter p;
+
+ if (pos >= Parameters.FixedParameters.Length)
+ p = Parameters.ArrayParameter;
+ else
+ p = Parameters.FixedParameters [pos];
+
+ return p.Name;
+ }
+
+ public string ParameterDesc (int pos)
+ {
+ string tmp = String.Empty;
+ Parameter p;
+
+ if (pos >= Parameters.FixedParameters.Length)
+ p = Parameters.ArrayParameter;
+ else
+ p = Parameters.FixedParameters [pos];
+
+ if (p.ModFlags == Parameter.Modifier.REF)
+ tmp = "ref ";
+ else if (p.ModFlags == Parameter.Modifier.OUT)
+ 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;
+
+ if (Parameters.FixedParameters == null) {
+ if (Parameters.ArrayParameter != null)
+ mod = Parameters.ArrayParameter.ModFlags;
+ else
+ mod = Parameter.Modifier.NONE;
+ } else if (pos >= Parameters.FixedParameters.Length)
+ mod = Parameters.ArrayParameter.ModFlags;
+ else
+ mod = Parameters.FixedParameters [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;
+ }
+ }
+}
diff --git a/mcs/mbas/testmbas/.cvsignore b/mcs/mbas/testmbas/.cvsignore
new file mode 100644
index 00000000000..656158779db
--- /dev/null
+++ b/mcs/mbas/testmbas/.cvsignore
@@ -0,0 +1,6 @@
+*.exe
+*.pdb
+*.vbproj
+*.vbproj.user
+*~
+.*~
diff --git a/mcs/mbas/testmbas/AssemblyInfo.vb b/mcs/mbas/testmbas/AssemblyInfo.vb
new file mode 100644
index 00000000000..f600c94bc01
--- /dev/null
+++ b/mcs/mbas/testmbas/AssemblyInfo.vb
@@ -0,0 +1,31 @@
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' General Information about an assembly is controlled through the following
+' set of attributes. Change these attribute values to modify the information
+' associated with an assembly.
+
+' Review the values of the assembly attributes
+
+<Assembly: AssemblyTitle("")>
+<Assembly: AssemblyDescription("")>
+<Assembly: AssemblyCompany("")>
+<Assembly: AssemblyProduct("")>
+<Assembly: AssemblyCopyright("")>
+<Assembly: AssemblyTrademark("")>
+<Assembly: CLSCompliant(True)>
+
+'The following GUID is for the ID of the typelib if this project is exposed to COM
+<Assembly: Guid("EA89BB68-1010-427C-A8B5-917940328A4B")>
+
+' Version information for an assembly consists of the following four values:
+'
+' Major Version
+' Minor Version
+' Build Number
+' Revision
+'
+' You can specify all the values or you can default the Build and Revision Numbers
+' by using the '*' as shown below:
+
+<Assembly: AssemblyVersion("1.0.*")>
diff --git a/mcs/mbas/testmbas/WriteOK.vb b/mcs/mbas/testmbas/WriteOK.vb
new file mode 100644
index 00000000000..ee17f11069e
--- /dev/null
+++ b/mcs/mbas/testmbas/WriteOK.vb
@@ -0,0 +1,19 @@
+Imports System
+
+Module WriteOK
+
+ Sub Main()
+ REM Testing old-fashioned comments
+ Console.WriteLine("OK!") ' Simple comments
+ End Sub
+
+End Module
+
+Module WriteOK2
+
+ Sub [Sub]() ' Escaped identifier
+ Console.WriteLine("Sub:OK!")
+ End Sub
+
+End Module
+
diff --git a/mcs/mbas/testmbas/ctest.vb b/mcs/mbas/testmbas/ctest.vb
new file mode 100644
index 00000000000..e3457f4cb08
--- /dev/null
+++ b/mcs/mbas/testmbas/ctest.vb
@@ -0,0 +1,33 @@
+Imports System.Windows.Forms
+Imports System.Drawing
+
+Delegate Sub d_b1_onClick (s, evt)
+
+Public Class TestClass
+ Inherits Form
+
+Public button1 as Button
+
+Public Sub PutButtonOnForm()
+
+End Sub
+
+Public Sub b1_onClick_handler (a,b) Handles button1.Click
+
+End Sub
+
+Public Sub New(ctest_a as string)
+ Dim b1_onClick as d_b1_onClick
+
+ b1_onClick = New d_b1_onClick(AddressOf Me.b1_onClick_handler)
+
+ Me.button1 = New Button()
+ Me.button1.Text = "Click Me"
+ Me.button1.Location = New Point(100, 10)
+ 'Me.Click = b1_onClick
+ Me.Controls.Add(Me.button1)
+
+ System.Console.WriteLine (ctest_a)
+End Sub
+
+End Class
diff --git a/mcs/mbas/testmbas/filelist b/mcs/mbas/testmbas/filelist
new file mode 100644
index 00000000000..d4d01a17442
--- /dev/null
+++ b/mcs/mbas/testmbas/filelist
@@ -0,0 +1 @@
+--main WriteOK testmbas\WriteOk.vb \ No newline at end of file
diff --git a/mcs/mbas/testmbas/gtk.vb b/mcs/mbas/testmbas/gtk.vb
new file mode 100644
index 00000000000..9196053df67
--- /dev/null
+++ b/mcs/mbas/testmbas/gtk.vb
@@ -0,0 +1,19 @@
+Imports System
+Imports Gtk
+
+Module GtkTest
+
+ Sub Main()
+ DIM Win as Window
+ DIM Btn as Button
+
+ Application.Init ()
+ Win = new Window ("VB Gtk+ Hello World")
+ Btn = new Button ("Click Me!")
+ Win.Add (Btn)
+ Win.ShowAll()
+ Application.Run ()
+ End Sub
+
+End Module
+
diff --git a/mcs/mbas/testmbas/test.vb b/mcs/mbas/testmbas/test.vb
new file mode 100644
index 00000000000..a2cd4e2dfdf
--- /dev/null
+++ b/mcs/mbas/testmbas/test.vb
@@ -0,0 +1,43 @@
+Imports System.Windows.Forms
+
+Module Test
+
+Sub MySub(b)
+ System.Console.WriteLine (b)
+End Sub
+
+Sub Main()
+ Dim a as Integer
+ Dim fgh as Integer
+ Dim btn as Button
+ Dim frm as TestClass
+
+ System.Console.WriteLine ("This var ")
+ System.Console.WriteLine ("contains ")
+ a = (1 + 2) * 144
+
+ System.Console.WriteLine (a)
+ a = 1
+ If (a > 2) Then
+ System.Console.WriteLine ("Greater than 2")
+ Else
+ System.Console.WriteLine ("Less than 2")
+ End If
+
+ a = 3
+ If (a > 2) Then
+ System.Console.WriteLine ("Greater than 2")
+ Else
+ System.Console.WriteLine ("Less than 2")
+ End If
+
+ frm = new TestClass("a")
+ frm.Width = 300
+ frm.Height = 80
+ frm.PutButtonOnForm()
+ frm.button1.Text = "AAA"
+ frm.ShowDialog()
+ MySub("parameter!!!!!!")
+End Sub
+
+End Module
diff --git a/mcs/mbas/testmbas/test2.vb b/mcs/mbas/testmbas/test2.vb
new file mode 100644
index 00000000000..ba84bbb471b
--- /dev/null
+++ b/mcs/mbas/testmbas/test2.vb
@@ -0,0 +1,14 @@
+Module Test
+
+Sub Main()
+ Dim a, b as Object
+ Dim t as Boolean
+
+ a = "abc"
+ b = "def"
+ t = (a < b)
+ System.Console.Write ("a < b : ")
+ System.Console.WriteLine (t)
+End Sub
+
+End Module
diff --git a/mcs/mbas/testmbas/test3.vb b/mcs/mbas/testmbas/test3.vb
new file mode 100644
index 00000000000..a0f9e388ff5
--- /dev/null
+++ b/mcs/mbas/testmbas/test3.vb
@@ -0,0 +1,51 @@
+Imports System.Windows.Forms
+Imports System.Drawing
+
+Module Test
+
+Sub Main()
+ ' Create a new instance of the form.
+ Dim form1 As Form
+ Dim button1 As Button
+ Dim button2 As Button
+
+ form1 = New Form()
+ button1 = New Button()
+ button2 = New Button()
+
+ ' Set the text of button1 to "OK".
+ button1.Text = "OK"
+ ' Set the position of the button on the form.
+ button1.Location = New Point(10, 10)
+ ' Set the text of button2 to "Cancel".
+ button2.Text = "Cancel"
+ ' Set the position of the button based on the location of button1.
+ button2.Location = New Point(button1.Left, button1.Height + button1.Top + 10)
+ ' Set the caption bar text of the form.
+ form1.Text = "My Dialog Box"
+ ' Display a help button on the form.
+ form1.HelpButton = True
+
+ ' Define the border style of the form to a dialog box.
+ form1.FormBorderStyle = FormBorderStyle.FixedDialog
+ ' Set the MaximizeBox to false to remove the maximize box.
+ form1.MaximizeBox = False
+ ' Set the MinimizeBox to false to remove the minimize box.
+ form1.MinimizeBox = False
+ ' Set the accept button of the form to button1.
+ form1.AcceptButton = button1
+ ' Set the cancel button of the form to button2.
+ form1.CancelButton = button2
+ ' Set the start position of the form to the center of the screen.
+ form1.StartPosition = FormStartPosition.CenterScreen
+
+ ' Add button1 to the form.
+ form1.Controls.Add(button1)
+ ' Add button2 to the form.
+ form1.Controls.Add(button2)
+
+ ' Display the form as a modal dialog box.
+ form1.ShowDialog()
+End Sub
+
+End Module
diff --git a/mcs/mbas/testmbas/test4.vb b/mcs/mbas/testmbas/test4.vb
new file mode 100644
index 00000000000..926a3d7c586
--- /dev/null
+++ b/mcs/mbas/testmbas/test4.vb
@@ -0,0 +1,16 @@
+Delegate Sub SubDelegate()
+
+Module Test
+
+Sub MySub()
+ System.Console.WriteLine ("In MySub")
+End Sub
+
+Sub Main()
+ Dim dsub as SubDelegate
+
+ dsub = New SubDelegate (AddressOf MySub)
+ dsub()
+End Sub
+
+End Module
diff --git a/mcs/mbas/testmbas/test5.vb b/mcs/mbas/testmbas/test5.vb
new file mode 100644
index 00000000000..34f8d53bd29
--- /dev/null
+++ b/mcs/mbas/testmbas/test5.vb
@@ -0,0 +1,32 @@
+Imports System.Windows.Forms
+Imports System.Drawing
+Imports System
+
+Public Class Form1
+ Inherits Form
+
+Public WithEvents b1 As Button
+Public WithEvents b2 As Button
+
+Public Sub b1_onClick (sender As Object, e as System.EventArgs)
+ Console.WriteLine ("b1 clicked")
+End Sub
+
+Public Sub b2_onClick (sender As Object, e as System.EventArgs)
+ Console.WriteLine ("b2 clicked")
+End Sub
+
+Public Sub New()
+ b1 = New Button()
+ b1.Location = New Point(100, 10)
+ Controls.Add (b1)
+ AddHandler b1.Click, AddressOf b1_onClick
+
+ b2 = New Button()
+ b2.Location = New Point(100, 60)
+ Controls.Add (b2)
+ AddHandler b2.Click, AddressOf b2_onClick
+End Sub
+
+End Class
+
diff --git a/mcs/mbas/testmbas/testm.vb b/mcs/mbas/testmbas/testm.vb
new file mode 100644
index 00000000000..99a6d8b588d
--- /dev/null
+++ b/mcs/mbas/testmbas/testm.vb
@@ -0,0 +1,11 @@
+Module Pippo
+
+Public Sub Main()
+ Dim c as Form1
+
+ c = new Form1()
+ c.ShowDialog()
+
+End Sub
+
+End Module
diff --git a/mcs/mbas/tree.cs b/mcs/mbas/tree.cs
new file mode 100644
index 00000000000..2cf5be8ca5c
--- /dev/null
+++ b/mcs/mbas/tree.cs
@@ -0,0 +1,109 @@
+//
+// 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 Namespace RecordNamespace (Namespace parent, string file, string name)
+ {
+ Namespace ns = new Namespace (parent, name);
+
+ if (namespaces.Contains (file)){
+ Hashtable ns_ns = (Hashtable) namespaces [file];
+
+ if (ns_ns.Contains (ns.Name))
+ return (Namespace) 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;
+ }
+ }
+ }
+}
diff --git a/mcs/mbas/typemanager.cs b/mcs/mbas/typemanager.cs
new file mode 100644
index 00000000000..b144bce45cf
--- /dev/null
+++ b/mcs/mbas/typemanager.cs
@@ -0,0 +1,2355 @@
+//
+// 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)
+//
+//
+using System;
+using System.Globalization;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+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 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 void_ptr_type;
+ static public Type indexer_name_type;
+ static public Type exception_type;
+ static public object obsolete_attribute_type;
+ static public object conditional_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;
+ static public MethodInfo system_void_set_corlib_type_builders;
+
+
+ //
+ // 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_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 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 cons_param_array_attribute;
+ static public ConstructorInfo void_decimal_ctor_five_args;
+ static public ConstructorInfo unverifiable_code_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 AddUserType (string name, TypeBuilder t, Type [] ifaces)
+ {
+ try {
+ types.Add (name, t);
+ } catch {
+ 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;
+ }
+
+ tc = builder_to_declspace [t] as TypeContainer;
+
+ Report.Warning (
+ 1595, "The type `" + name + "' is defined in an existing assembly;"+
+ " Using the new definition from: " + tc.Location);
+ Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
+
+ types.Remove (name);
+ types.Add (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)
+ {
+ types.Add (name, t);
+ builder_to_declspace.Add (t, del);
+ }
+
+ public static void AddEnumType (string name, TypeBuilder t, Enum en)
+ {
+ types.Add (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 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;
+ }
+
+ //
+ // Low-level lookup, cache-less
+ //
+ static Type LookupTypeReflection (string name)
+ {
+ Type t;
+
+ foreach (Assembly a in assemblies){
+ t = a.GetType (name);
+ if (t != null)
+ return t;
+ }
+
+ foreach (ModuleBuilder mb in modules) {
+ t = mb.GetType (name);
+ if (t != null){
+ return t;
+ }
+ }
+ return null;
+ }
+
+ //
+ // 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;
+
+ //
+ // Optimization: ComposedCast will work with an existing type, and might already have the
+ // full name of the type, so the full system lookup can probably be avoided.
+ //
+
+ string [] elements = name.Split ('.');
+ int count = elements.Length;
+
+ for (int n = 1; n <= count; n++){
+ string top_level_type = String.Join (".", elements, 0, n);
+
+ t = (Type) types [top_level_type];
+ if (t == null){
+ t = LookupTypeReflection (top_level_type);
+ if (t == null)
+ continue;
+ }
+
+ if (count == n){
+ types [name] = t;
+ return t;
+ }
+
+ string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
+ t = LookupTypeDirect (newt);
+ if (t != null)
+ types [newt] = t;
+ return t;
+ }
+ return null;
+ }
+
+ //
+ // Returns a list of all namespaces in the assemblies and types loaded.
+ //
+ public static Hashtable GetNamespaces ()
+ {
+ Hashtable namespaces = new Hashtable ();
+
+ foreach (Assembly a in assemblies){
+ foreach (Type t in a.GetTypes ()){
+ string ns = t.Namespace;
+
+ if (namespaces.Contains (ns))
+ continue;
+ namespaces [ns] = ns;
+ }
+ }
+
+ foreach (ModuleBuilder mb in modules){
+ foreach (Type t in mb.GetTypes ()){
+ string ns = t.Namespace;
+
+ if (namespaces.Contains (ns))
+ continue;
+ namespaces [ns] = ns;
+ }
+ }
+ return namespaces;
+ }
+
+ /// <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 = LookupType (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)
+ {
+ 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) {
+ Report.Error (-19, "Can not find the core function `" + name + "'");
+ return null;
+ }
+
+ MethodInfo mi = list [0] as MethodInfo;
+ if (mi == null) {
+ Report.Error (-19, "Can not find the core function `" + name + "'");
+ return null;
+ }
+
+ return mi;
+ }
+
+ /// <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");
+ 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");
+
+ 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");
+
+ //
+ // 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_type_type_arg = { system_type_type, system_type_type, system_type_type };
+
+ try {
+ system_void_set_corlib_type_builders = GetMethod (
+ system_assemblybuilder_type, "SetCorlibTypeBuilders",
+ system_type_type_arg);
+
+ object[] args = new object [3];
+ args [0] = object_type;
+ args [1] = value_type;
+ args [2] = enum_type;
+
+ system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
+ } catch {
+ Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
+ }
+ }
+ }
+
+ //
+ // 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 [] 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_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);
+
+ //
+ // 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);
+
+ }
+
+ 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)
+ {
+ //
+ // 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)) {
+ 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;
+ }
+
+ 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.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))
+ 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) || type.IsSubclassOf (parent))
+ return false;
+ else
+ return IsSubclassOrNestedChildOf (type, parent);
+ }
+
+ /// <summary>
+ /// Returns the User Defined Types
+ /// </summary>
+ public static ArrayList UserTypes {
+ get {
+ return user_types;
+ }
+ }
+
+ public static Hashtable TypeContainers {
+ get {
+ return typecontainers;
+ }
+ }
+
+ 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.GetAddMethod ();
+ }
+
+ 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)
+ {
+ 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;
+ }
+
+ static public MethodInfo GetPropertyGetter (PropertyInfo pi)
+ {
+ if (pi is PropertyBuilder){
+ Pair de = (Pair) properties [pi];
+
+ return (MethodInfo) de.Second;
+ } else
+ return pi.GetSetMethod ();
+ }
+
+ static public MethodInfo GetPropertySetter (PropertyInfo pi)
+ {
+ if (pi is PropertyBuilder){
+ Pair de = (Pair) properties [pi];
+
+ return (MethodInfo) de.First;
+ } else
+ return pi.GetGetMethod ();
+ }
+
+ /// <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)
+ {
+ if (!(value is IConvertible))
+ throw new ArgumentException ();
+
+ 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.
+ //
+ 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
+ throw new InvalidCastException ();
+ }
+
+ //
+ // 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_start_type;
+
+ //
+ // The assembly that defines the type is that is calling us
+ //
+ static Assembly closure_invocation_assembly;
+
+ //
+ // 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_start_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);
+
+ //
+ // 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;
+
+ 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);
+
+ //
+ // 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 ((closure_invocation_type != closure_start_type) &&
+ closure_invocation_type.IsSubclassOf (closure_start_type))
+ return false;
+
+ return true;
+ }
+
+ // Public.
+ return true;
+ }
+
+ //
+ // EventInfos and PropertyInfos, return true
+ //
+ return true;
+ }
+
+ static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
+
+ //
+ // 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'.
+ //
+ // The binding flags are `bf' and the kind of members being looked up are `mt'
+ //
+ // 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 queried_type,
+ MemberTypes mt, BindingFlags original_bf, string name)
+ {
+ Timer.StartTimer (TimerType.MemberLookup);
+
+ MemberInfo[] retval = RealMemberLookup (invocation_type, queried_type,
+ mt, original_bf, name);
+
+ Timer.StopTimer (TimerType.MemberLookup);
+
+ return retval;
+ }
+
+ static MemberInfo [] RealMemberLookup (Type invocation_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 private_ok;
+ bool always_ok_flag = false;
+ bool skip_iface_check = true, used_cache = false;
+
+ closure_name = name;
+ closure_invocation_type = invocation_type;
+ closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
+ closure_start_type = queried_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){
+ if (invocation_type == current_type){
+ private_ok = (bf & BindingFlags.NonPublic) != 0;
+ } else
+ private_ok = always_ok_flag;
+
+ if (invocation_type.IsSubclassOf (current_type))
+ private_ok = true;
+
+ if (private_ok)
+ bf = original_bf | BindingFlags.NonPublic;
+ } else {
+ private_ok = false;
+ bf = original_bf & ~BindingFlags.NonPublic;
+ }
+
+ closure_private_ok = private_ok;
+ 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 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, itype, mt, bf, name);
+ if (x != null)
+ return x;
+ }
+
+ return null;
+ }
+#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 + ")";
+ }
+}
+
+}