Start
[mono.git] / mcs / mbas / codegen.cs
index a8a09a721300334ad6ffe9dce48cde4d126eb722..0ece01942c1f1f45d48a6dce6968b80eedc79609 100644 (file)
@@ -8,12 +8,13 @@
 //
 
 using System;
+using System.IO;
 using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
 using System.Diagnostics.SymbolStore;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
 
        /// <summary>
        ///    Code generator class.
@@ -65,41 +66,47 @@ namespace Mono.CSharp {
                //
                // This routine initializes the Mono runtime SymbolWriter.
                //
-               static void InitMonoSymbolWriter (string basename, string[] debug_args)
+               static bool InitMonoSymbolWriter (string basename, string symbol_output,
+                                                 string exe_output_file, string[] debug_args)
                {
-                       string symbol_output = basename + "-debug.s";
-
                        Type itype = SymbolWriter.GetType ();
                        if (itype == null)
-                               return;
+                               return false;
 
-                       Type[] arg_types = new Type [2];
+                       Type[] arg_types = new Type [3];
                        arg_types [0] = typeof (string);
-                       arg_types [1] = typeof (string[]);
+                       arg_types [1] = typeof (string);
+                       arg_types [2] = typeof (string[]);
 
                        MethodInfo initialize = itype.GetMethod ("Initialize", arg_types);
                        if (initialize == null)
-                               return;
+                               return false;
 
-                       object[] args = new object [2];
-                       args [0] = symbol_output;
-                       args [1] = debug_args;
+                       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[] args)
+               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)
+                       if (SymbolWriter == null) {
+                               Report.Warning (
+                                       -18, "Cannot find any symbol writer");
                                return;
+                       }
                        
                        //
                        // Due to lacking documentation about the first argument of the
@@ -115,11 +122,14 @@ namespace Mono.CSharp {
                        
                        switch (sym_type.Name){
                        case "MonoSymbolWriter":
-                               InitMonoSymbolWriter (basename, args);
+                               if (!InitMonoSymbolWriter (basename, symbol_output,
+                                                          exe_output_file, args))
+                                       Report.Warning (
+                                               -18, "Cannot initialize the symbol writer");
                                break;
 
                        default:
-                               Report.Error (
+                               Report.Warning (
                                        -18, "Cannot generate debugging information on this platform");
                                break;
                        }
@@ -151,8 +161,25 @@ namespace Mono.CSharp {
                        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 (an.Name, debug_args);
+                               InitializeSymbolWriter (basename, symbol_output, output, debug_args);
+                       else {
+                               try {
+                                       File.Delete (symbol_output);
+                               } catch {
+                                       // Ignore errors.
+                               }
+                       }
                }
 
                static public void Save (string name)
@@ -212,6 +239,11 @@ namespace Mono.CSharp {
                /// </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.
@@ -278,23 +310,16 @@ namespace Mono.CSharp {
                ///  Whether we are inside an unsafe block
                /// </summary>
                public bool InUnsafe;
-
-               /// <summary>
-               ///   Whether we break from a loop or not
-               /// </summary>
-               public bool Breaks;
                
                /// <summary>
-               ///   Location for this EmitContext
+               ///  Whether we are inside an unsafe block
                /// </summary>
-               public Location loc;
+               public bool InvokingOwnOverload;                
 
                /// <summary>
-               ///   Used to "flag" the resolution process to only lookup types,
-               ///   and nothing else.  This is an out-of-band communication
-               ///   path to SimpleName from the cast operation.
+               ///   Location for this EmitContext
                /// </summary>
-               public bool OnlyLookupTypes;
+               public Location loc;
 
                /// <summary>
                ///   Used to flag that it is ok to define types recursively, as the
@@ -312,6 +337,8 @@ namespace Mono.CSharp {
                ///   we relax the rules
                /// </summary>
                public bool InEnumContext;
+               
+               public string BlockName;
 
                protected Stack FlowStack;
                
@@ -329,13 +356,17 @@ namespace Mono.CSharp {
                        ReturnType = return_type;
                        IsConstructor = is_constructor;
                        CurrentBlock = null;
+                       BlockName = "";
+                       InvokingOwnOverload = false;
                        
                        if (parent != null){
                                // Can only be null for the ResolveType contexts.
-                       ContainerType = parent.TypeBuilder;
-                       InUnsafe = ((parent.ModFlags | code_flags) & Modifiers.UNSAFE) != 0;
+                               ContainerType = parent.TypeBuilder;
+                               if (parent.UnsafeContext)
+                                       InUnsafe = true;
+                               else
+                                       InUnsafe = (code_flags & Modifiers.UNSAFE) != 0;
                        }
-                       OnlyLookupTypes = false;
                        loc = l;
 
                        FlowStack = new Stack ();
@@ -465,12 +496,22 @@ namespace Mono.CSharp {
                                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)
                {
-                       bool has_ret = false;
+                       EmitTopBlock (block, "", ip, loc);
+               }
 
-//                     Console.WriteLine ("Emitting: " + loc);
+               public void EmitTopBlock (Block block, string bname, InternalParameters ip, Location loc)
+               {
+                       bool has_ret = false;
 
+                       //Console.WriteLine ("Emitting: '{0}", bname);
+                       BlockName = bname;
                        if (CodeGen.SymbolWriter != null)
                                Mark (loc);
 
@@ -493,12 +534,17 @@ namespace Mono.CSharp {
                                        }
 
                                        cfb = (FlowBranching) FlowStack.Pop ();
-                                       cfb.MergeTopBlock ();
+                                       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 ();
@@ -508,11 +554,18 @@ namespace Mono.CSharp {
 
                        if (ReturnType != null && !has_ret){
                                //
-                               // FIXME: we need full flow analysis to implement this
-                               // correctly and emit an error instead of a warning.
-                               //
+                               // mcs here would report an error (and justly so), but functions without
+                               // an explicit return value are perfectly legal in MonoBasic
                                //
-                               Report.Error (161, loc, "Not all code paths return a value");
+                               
+                               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;
                        }
 
@@ -535,13 +588,13 @@ namespace Mono.CSharp {
                /// </summary>
                public void Mark (Location loc)
                {
-                       if (!Location.IsNull (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 
@@ -623,8 +676,14 @@ namespace Mono.CSharp {
                public Expression my_this;
                public Expression This {
                        get {
-                               if (my_this == null)
-                                       my_this = new This (loc).Resolve (this);
+                               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;
                        }