X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Feval.cs;h=6782d573a406830981cd1b06a90daff32eae586c;hb=4a962f78ee88d1d617cee432bb74bf29885ed272;hp=bc36a672b3f50a107c47347cd0f4cd8a33909aab;hpb=0bd4004c832f6c5a02c35cada2b6fdbedd1563a2;p=mono.git diff --git a/mcs/mcs/eval.cs b/mcs/mcs/eval.cs index bc36a672b3f..6782d573a40 100644 --- a/mcs/mcs/eval.cs +++ b/mcs/mcs/eval.cs @@ -11,7 +11,7 @@ // using System; using System.Threading; -using System.Collections; +using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.IO; @@ -54,15 +54,19 @@ namespace Mono.CSharp { static string current_debug_name; static int count; static Thread invoke_thread; - - static ArrayList using_alias_list = new ArrayList (); - internal static ArrayList using_list = new ArrayList (); - static Hashtable fields = new Hashtable (); - static Type interactive_base_class = typeof (InteractiveBase); + static List using_alias_list = new List (); + internal static List using_list = new List (); + static Dictionary> fields = new Dictionary> (); + + static TypeSpec interactive_base_class; static Driver driver; static bool inited; + static CompilerContext ctx; + + public static TextWriter MessageOutput = Console.Out; + /// /// Optional initialization for the Evaluator. /// @@ -81,6 +85,10 @@ namespace Mono.CSharp { InitAndGetStartupFiles (args); } + internal static ReportPrinter SetPrinter (ReportPrinter report_printer) + { + return ctx.Report.SetPrinter (report_printer); + } /// /// Optional initialization for the Evaluator. @@ -105,22 +113,30 @@ namespace Mono.CSharp { if (inited) return new string [0]; - driver = Driver.Create (args, false); + driver = Driver.Create (args, false, new ConsoleReportPrinter ()); if (driver == null) throw new Exception ("Failed to create compiler driver with the given arguments"); + + RootContext.ToplevelTypes = new ModuleCompiled (ctx, true); driver.ProcessDefaultConfig (); - ArrayList startup_files = new ArrayList (); + var startup_files = new List (); foreach (CompilationUnit file in Location.SourceFiles) startup_files.Add (file.Path); CompilerCallableEntryPoint.Reset (); + RootContext.ToplevelTypes = new ModuleCompiled (ctx, true); + /*var ctypes = */TypeManager.InitCoreTypes (); + + Import.Initialize (); driver.LoadReferences (); + TypeManager.InitOptionalCoreTypes (ctx); + RootContext.EvalMode = true; inited = true; - return (string []) startup_files.ToArray (typeof (string)); + return startup_files.ToArray (); } } @@ -132,22 +148,35 @@ namespace Mono.CSharp { static void Reset () { CompilerCallableEntryPoint.PartialReset (); + RootContext.PartialReset (); + + // Workaround for API limitation where full message printer cannot be passed + ReportPrinter printer; + if (MessageOutput == Console.Out || MessageOutput == Console.Error){ + var console_reporter = new ConsoleReportPrinter (MessageOutput); + console_reporter.Fatal = driver.fatal_errors; + printer = console_reporter; + } else + printer = new StreamReportPrinter (MessageOutput); + + ctx = new CompilerContext (new Report (printer)); + RootContext.ToplevelTypes = new ModuleCompiled (ctx, true); // // PartialReset should not reset the core types, this is very redundant. // - if (!TypeManager.InitCoreTypes ()) - throw new Exception ("Failed to InitCoreTypes"); - TypeManager.InitOptionalCoreTypes (); +// if (!TypeManager.InitCoreTypes (ctx, null)) +// throw new Exception ("Failed to InitCoreTypes"); +// TypeManager.InitOptionalCoreTypes (ctx); - Location.AddFile ("{interactive}"); + Location.AddFile (null, "{interactive}"); Location.Initialize (); current_debug_name = "interactive" + (count++) + ".dll"; if (Environment.GetEnvironmentVariable ("SAVE") != null){ - CodeGen.Init (current_debug_name, current_debug_name, false); + CodeGen.Init (current_debug_name, current_debug_name, false, ctx); } else - CodeGen.InitDynamic (current_debug_name); + CodeGen.InitDynamic (ctx, current_debug_name); } /// @@ -164,18 +193,22 @@ namespace Mono.CSharp { /// base class and the static members that are /// available to your evaluated code. /// - static public Type InteractiveBaseClass { + static public TypeSpec InteractiveBaseClass { get { - return interactive_base_class; + if (interactive_base_class != null) + return interactive_base_class; + + return Import.ImportType (typeof (InteractiveBase)); } + } - set { - if (value == null) - throw new ArgumentNullException (); + public static void SetInteractiveBaseClass (Type type) + { + if (type == null) + throw new ArgumentNullException (); - lock (evaluator_lock) - interactive_base_class = value; - } + lock (evaluator_lock) + interactive_base_class = Import.ImportType (type); } /// @@ -244,14 +277,14 @@ namespace Mono.CSharp { object parser_result = parser.InteractiveResult; if (!(parser_result is Class)){ - int errors = Report.Errors; + int errors = ctx.Report.Errors; NamespaceEntry.VerifyAllUsing (); - if (errors == Report.Errors) + if (errors == ctx.Report.Errors) parser.CurrentNamespace.Extract (using_alias_list, using_list); } - compiled = CompileBlock (parser_result as Class, parser.undo); + compiled = CompileBlock (parser_result as Class, parser.undo, ctx.Report); } return null; @@ -289,7 +322,7 @@ namespace Mono.CSharp { // Either null (on error) or the compiled method. return compiled; } - + // // Todo: Should we handle errors, or expect the calling code to setup // the recording themselves? @@ -335,7 +368,7 @@ namespace Mono.CSharp { // The code execution does not need to keep the compiler lock // object retval = typeof (NoValueSet); - + try { invoke_thread = System.Threading.Thread.CurrentThread; invoking = true; @@ -387,11 +420,11 @@ namespace Mono.CSharp { try { RootContext.ResolveTree (); - if (Report.Errors != 0) + if (ctx.Report.Errors != 0) return null; RootContext.PopulateTypes (); - if (Report.Errors != 0) + if (ctx.Report.Errors != 0) return null; MethodOrOperator method = null; @@ -405,14 +438,14 @@ namespace Mono.CSharp { if (method == null) throw new InternalErrorException ("did not find the the Host method"); - EmitContext ec = method.CreateEmitContext (null); + BlockContext bc = new BlockContext (method, method.Block, method.ReturnType); try { - method.Block.Resolve (null, ec, method.ParameterInfo, method); + method.Block.Resolve (null, bc, method.ParameterInfo, method); } catch (CompletionResult cr){ prefix = cr.BaseText; return cr.Result; - } + } } finally { parser.undo.ExecuteUndo (); } @@ -487,7 +520,7 @@ namespace Mono.CSharp { // static InputKind ToplevelOrStatement (SeekableStreamReader seekable) { - Tokenizer tokenizer = new Tokenizer (seekable, (CompilationUnit) Location.SourceFiles [0]); + Tokenizer tokenizer = new Tokenizer (seekable, (CompilationUnit) Location.SourceFiles [0], ctx); int t = tokenizer.token (); switch (t){ @@ -594,6 +627,7 @@ namespace Mono.CSharp { partial_input = false; Reset (); queued_fields.Clear (); + Tokenizer.LocatedToken.Initialize (); Stream s = new MemoryStream (Encoding.Default.GetBytes (input)); SeekableStreamReader seekable = new SeekableStreamReader (s, Encoding.Default); @@ -601,7 +635,7 @@ namespace Mono.CSharp { InputKind kind = ToplevelOrStatement (seekable); if (kind == InputKind.Error){ if (mode == ParseMode.ReportErrors) - Report.Error (-25, "Detection Parsing Error"); + ctx.Report.Error (-25, "Detection Parsing Error"); partial_input = false; return null; } @@ -615,8 +649,7 @@ namespace Mono.CSharp { } seekable.Position = 0; - CSharpParser parser = new CSharpParser (seekable, (CompilationUnit) Location.SourceFiles [0]); - parser.ErrorOutput = Report.Stderr; + CSharpParser parser = new CSharpParser (seekable, (CompilationUnit) Location.SourceFiles [0], ctx); if (kind == InputKind.StatementOrExpression){ parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter; @@ -635,18 +668,14 @@ namespace Mono.CSharp { if (mode == ParseMode.GetCompletions) parser.Lexer.CompleteOnEOF = true; - bool disable_error_reporting; + ReportPrinter old_printer = null; if ((mode == ParseMode.Silent || mode == ParseMode.GetCompletions) && CSharpParser.yacc_verbose_flag == 0) - disable_error_reporting = true; - else - disable_error_reporting = false; - - if (disable_error_reporting) - Report.DisableReporting (); + old_printer = SetPrinter (new StreamReportPrinter (TextWriter.Null)); + try { parser.parse (); } finally { - if (Report.Errors != 0){ + if (ctx.Report.Errors != 0){ if (mode != ParseMode.ReportErrors && parser.UnexpectedEOF) partial_input = true; @@ -654,8 +683,8 @@ namespace Mono.CSharp { parser = null; } - if (disable_error_reporting) - Report.EnableReporting (); + if (old_printer != null) + SetPrinter (old_printer); } return parser; } @@ -665,13 +694,13 @@ namespace Mono.CSharp { // or reflection gets confused (it basically gets confused, and variables override each // other). // - static ArrayList queued_fields = new ArrayList (); + static List queued_fields = new List (); //static ArrayList types = new ArrayList (); static volatile bool invoking; - static CompiledMethod CompileBlock (Class host, Undo undo) + static CompiledMethod CompileBlock (Class host, Undo undo, Report Report) { RootContext.ResolveTree (); if (Report.Errors != 0){ @@ -706,13 +735,15 @@ namespace Mono.CSharp { } RootContext.EmitCode (); - if (Report.Errors != 0) + if (Report.Errors != 0){ + undo.ExecuteUndo (); return null; + } RootContext.CloseTypes (); if (Environment.GetEnvironmentVariable ("SAVE") != null) - CodeGen.Save (current_debug_name, false); + CodeGen.Save (current_debug_name, false, Report); if (host == null) return null; @@ -721,31 +752,33 @@ namespace Mono.CSharp { // Unlike Mono, .NET requires that the MethodInfo is fetched, it cant // work from MethodBuilders. Retarded, I know. // - Type tt = CodeGen.Assembly.Builder.GetType (tb.Name); + var tt = CodeGen.Assembly.Builder.GetType (tb.Name); MethodInfo mi = tt.GetMethod (mb.Name); // Pull the FieldInfos from the type, and keep track of them foreach (Field field in queued_fields){ FieldInfo fi = tt.GetField (field.Name); - - FieldInfo old = (FieldInfo) fields [field.Name]; + + Tuple old; // If a previous value was set, nullify it, so that we do // not leak memory - if (old != null){ - if (TypeManager.IsStruct (old.FieldType)){ + if (fields.TryGetValue (field.Name, out old)) { + if (old.Item1.MemberType.IsStruct) { // // TODO: Clear fields for structs // } else { try { - old.SetValue (null, null); + old.Item2.SetValue (null, null); } catch { } } + + fields [field.Name] = Tuple.Create (old.Item1, fi); + } else { + fields.Add (field.Name, Tuple.Create (field.Spec, fi)); } - - fields [field.Name] = fi; } //types.Add (tb); @@ -768,10 +801,10 @@ namespace Mono.CSharp { public class NoValueSet { } - static internal FieldInfo LookupField (string name) + static internal Tuple LookupField (string name) { - FieldInfo fi = (FieldInfo) fields [name]; - + Tuple fi; + fields.TryGetValue (name, out fi); return fi; } @@ -814,9 +847,9 @@ namespace Mono.CSharp { } } - static internal ICollection GetUsingList () + static internal ICollection GetUsingList () { - ArrayList res = new ArrayList (using_list.Count); + var res = new List (using_list.Count); foreach (object ue in using_list) res.Add (ue.ToString ()); return res; @@ -825,7 +858,7 @@ namespace Mono.CSharp { static internal string [] GetVarNames () { lock (evaluator_lock){ - return (string []) new ArrayList (fields.Keys).ToArray (typeof (string)); + return new List (fields.Keys).ToArray (); } } @@ -834,25 +867,19 @@ namespace Mono.CSharp { lock (evaluator_lock){ StringBuilder sb = new StringBuilder (); - foreach (DictionaryEntry de in fields){ - FieldInfo fi = LookupField ((string) de.Key); - object value = null; - bool error = false; - + foreach (var de in fields){ + var fi = LookupField (de.Key); + object value; try { - if (value == null) - value = "null"; - value = fi.GetValue (null); + value = fi.Item2.GetValue (null); if (value is string) value = Quote ((string)value); } catch { - error = true; + value = ""; } - - if (error) - sb.Append (String.Format ("{0} {1} ", TypeManager.CSharpName(fi.FieldType), de.Key)); - else - sb.Append (String.Format ("{0} {1} = {2}", TypeManager.CSharpName(fi.FieldType), de.Key, value)); + + sb.AppendFormat ("{0} {1} = {2}", fi.Item1.MemberType.GetSignatureForError (), de.Key, value); + sb.AppendLine (); } return sb.ToString (); @@ -865,8 +892,8 @@ namespace Mono.CSharp { static public void LoadAssembly (string file) { lock (evaluator_lock){ - Driver.LoadAssembly (file, false); - GlobalRootNamespace.Instance.ComputeNamespaces (); + driver.LoadAssembly (file, false); + GlobalRootNamespace.Instance.ComputeNamespaces (ctx); } } @@ -876,11 +903,17 @@ namespace Mono.CSharp { static public void ReferenceAssembly (Assembly a) { lock (evaluator_lock){ - GlobalRootNamespace.Instance.AddAssemblyReference (a); - GlobalRootNamespace.Instance.ComputeNamespaces (); +// GlobalRootNamespace.Instance.AddAssemblyReference (a); +// GlobalRootNamespace.Instance.ComputeNamespaces (ctx); + GlobalRootNamespace.Instance.ImportAssembly (a); } } - + + /// + /// If true, turns type expressions into valid expressions + /// and calls the describe method on it + /// + public static bool DescribeTypeExpressions; } @@ -980,7 +1013,7 @@ namespace Mono.CSharp { return; } - string pkgout = Driver.GetPackageFlags (pkg, false); + string pkgout = Driver.GetPackageFlags (pkg, false, RootContext.ToplevelTypes.Compiler.Report); if (pkgout == null) return; @@ -1017,17 +1050,17 @@ namespace Mono.CSharp { /// static public string help { get { - return "Static methods:\n"+ - " Describe(obj) - Describes the object's type\n" + - " LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)\n" + - " LoadAssembly (ass) - Loads the given assembly (like -r:ASS)\n" + - " ShowVars (); - Shows defined local variables.\n" + - " ShowUsing (); - Show active using decltions.\n" + - " Prompt - The prompt used by the C# shell\n" + - " ContinuationPrompt - The prompt for partial input\n" + - " Time(() -> { }) - Times the specified code\n" + - " quit;\n" + - " help;\n"; + return "Static methods:\n" + + " Describe (object) - Describes the object's type\n" + + " LoadPackage (package); - Loads the given Package (like -pkg:FILE)\n" + + " LoadAssembly (assembly) - Loads the given assembly (like -r:ASSEMBLY)\n" + + " ShowVars (); - Shows defined local variables.\n" + + " ShowUsing (); - Show active using declarations.\n" + + " Prompt - The prompt used by the C# shell\n" + + " ContinuationPrompt - The prompt for partial input\n" + + " Time(() -> { }) - Times the specified code\n" + + " quit; - You'll never believe it - this quits the repl!\n" + + " help; - This help text\n"; } } @@ -1055,14 +1088,12 @@ namespace Mono.CSharp { static public string Describe (object x) { if (x == null) - return ""; - - Type t = x as Type; - if (t == null) - t = x.GetType (); + return ""; + + var type = x as Type ?? x.GetType (); StringWriter sw = new StringWriter (); - new Outline (t, sw, true, false, false).OutlineType (); + new Outline (type, sw, true, false, false).OutlineType (); return sw.ToString (); } #endif @@ -1104,7 +1135,7 @@ namespace Mono.CSharp { return name.GetHashCode (); } - override public Expression DoResolveLValue (EmitContext ec, Expression right_side) + override public Expression DoResolveLValue (ResolveContext ec, Expression right_side) { Expression ret = base.DoResolveLValue (ec, right_side); if (ret == null) @@ -1133,15 +1164,39 @@ namespace Mono.CSharp { { } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { CloneContext cc = new CloneContext (); Expression clone = source.Clone (cc); - clone = clone.Resolve (ec); - if (clone == null) - return null; - + // + // A useful feature for the REPL: if we can resolve the expression + // as a type, Describe the type; + // + if (Evaluator.DescribeTypeExpressions){ + var old_printer = Evaluator.SetPrinter (new StreamReportPrinter (TextWriter.Null)); + clone = clone.Resolve (ec); + if (clone == null){ + clone = source.Clone (cc); + clone = clone.Resolve (ec, ResolveFlags.Type); + if (clone == null){ + Evaluator.SetPrinter (old_printer); + clone = source.Clone (cc); + clone = clone.Resolve (ec); + return null; + } + + Arguments args = new Arguments (1); + args.Add (new Argument (new TypeOf ((TypeExpr) clone, Location))); + source = new Invocation (new SimpleName ("Describe", Location), args).Resolve (ec); + } + Evaluator.SetPrinter (old_printer); + } else { + clone = clone.Resolve (ec); + if (clone == null) + return null; + } + // This means its really a statement. if (clone.Type == TypeManager.void_type){ source = source.Resolve (ec); @@ -1172,11 +1227,11 @@ namespace Mono.CSharp { } public class Undo { - ArrayList undo_types; + List> undo_types; public Undo () { - undo_types = new ArrayList (); + undo_types = new List> (); } public void AddTypeContainer (TypeContainer current_container, TypeContainer tc) @@ -1185,10 +1240,11 @@ namespace Mono.CSharp { Console.Error.WriteLine ("Internal error: inserting container into itself"); return; } - + if (undo_types == null) - undo_types = new ArrayList (); - undo_types.Add (new Pair (current_container, tc)); + undo_types = new List> (); + + undo_types.Add (new KeyValuePair (current_container, tc)); } public void ExecuteUndo () @@ -1196,10 +1252,10 @@ namespace Mono.CSharp { if (undo_types == null) return; - foreach (Pair p in undo_types){ - TypeContainer current_container = (TypeContainer) p.First; + foreach (var p in undo_types){ + TypeContainer current_container = p.Key; - current_container.RemoveTypeContainer ((TypeContainer) p.Second); + current_container.RemoveTypeContainer (p.Value); } undo_types = null; }