PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Hosting/Shell/ConsoleHost.cs

https://bitbucket.org/stefanrusek/xronos
C# | 453 lines | 334 code | 84 blank | 35 comment | 56 complexity | 4a8e8cd0e65a7f353a10f5eb9e4d424e MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. using System.Diagnostics;
  22. using System.IO;
  23. using System.Reflection;
  24. using System.Runtime.CompilerServices;
  25. #if !CODEPLEX_40
  26. using Microsoft.Runtime.CompilerServices;
  27. #endif
  28. using System.Text;
  29. using System.Threading;
  30. using Microsoft.Scripting.Generation;
  31. using Microsoft.Scripting.Runtime;
  32. using Microsoft.Scripting.Utils;
  33. namespace Microsoft.Scripting.Hosting.Shell {
  34. /// <summary>
  35. /// Core functionality to implement an interactive console. This should be derived for concrete implementations
  36. /// </summary>
  37. public abstract class ConsoleHost {
  38. private int _exitCode;
  39. private ConsoleHostOptionsParser _optionsParser;
  40. private ScriptRuntime _runtime;
  41. private ScriptEngine _engine;
  42. internal OptionsParser _languageOptionsParser;
  43. private IConsole _console;
  44. private CommandLine _commandLine;
  45. public ConsoleHostOptions Options { get { return _optionsParser.Options; } }
  46. public ScriptRuntimeSetup RuntimeSetup { get { return _optionsParser.RuntimeSetup; } }
  47. public ScriptEngine Engine { get { return _engine; } protected set { _engine = value; } }
  48. public ScriptRuntime Runtime { get { return _runtime; } protected set { _runtime = value; } }
  49. protected int ExitCode { get { return _exitCode; } set { _exitCode = value; } }
  50. protected ConsoleHostOptionsParser ConsoleHostOptionsParser { get { return _optionsParser; } set { _optionsParser = value; } }
  51. protected IConsole ConsoleIO { get { return _console; } set { _console = value; } }
  52. protected CommandLine CommandLine { get { return _commandLine; } }
  53. protected ConsoleHost() {
  54. }
  55. /// <summary>
  56. /// Console Host entry-point .exe name.
  57. /// </summary>
  58. protected virtual string ExeName {
  59. get {
  60. #if !SILVERLIGHT
  61. Assembly entryAssembly = Assembly.GetEntryAssembly();
  62. //Can be null if called from unmanaged code (VS integration scenario)
  63. return entryAssembly != null ? entryAssembly.GetName().Name : "ConsoleHost";
  64. #else
  65. return "ConsoleHost";
  66. #endif
  67. }
  68. }
  69. #region Customization
  70. protected virtual void ParseHostOptions(string[] args) {
  71. _optionsParser.Parse(args);
  72. }
  73. protected virtual ScriptRuntimeSetup CreateRuntimeSetup() {
  74. var setup = ScriptRuntimeSetup.ReadConfiguration();
  75. string provider = Provider.AssemblyQualifiedName;
  76. if (!setup.LanguageSetups.Any(s => s.TypeName == provider)) {
  77. var languageSetup = CreateLanguageSetup();
  78. if (languageSetup != null) {
  79. setup.LanguageSetups.Add(languageSetup);
  80. }
  81. }
  82. return setup;
  83. }
  84. protected virtual LanguageSetup CreateLanguageSetup() {
  85. return null;
  86. }
  87. protected virtual PlatformAdaptationLayer PlatformAdaptationLayer {
  88. get { return PlatformAdaptationLayer.Default; }
  89. }
  90. protected virtual Type Provider {
  91. get { return null; }
  92. }
  93. private string GetLanguageProvider(ScriptRuntimeSetup setup) {
  94. var providerType = Provider;
  95. if (providerType != null) {
  96. return providerType.AssemblyQualifiedName;
  97. }
  98. if (Options.HasLanguageProvider) {
  99. return Options.LanguageProvider;
  100. }
  101. if (Options.RunFile != null) {
  102. string ext = Path.GetExtension(Options.RunFile);
  103. foreach (var lang in setup.LanguageSetups) {
  104. if (lang.FileExtensions.Any(e => DlrConfiguration.FileExtensionComparer.Equals(e, ext))) {
  105. return lang.TypeName;
  106. }
  107. }
  108. }
  109. throw new InvalidOptionException("No language specified.");
  110. }
  111. protected virtual CommandLine CreateCommandLine() {
  112. return new CommandLine();
  113. }
  114. protected virtual OptionsParser CreateOptionsParser() {
  115. return new OptionsParser<ConsoleOptions>();
  116. }
  117. protected virtual IConsole CreateConsole(ScriptEngine engine, CommandLine commandLine, ConsoleOptions options) {
  118. ContractUtils.RequiresNotNull(options, "options");
  119. if (options.TabCompletion) {
  120. return CreateSuperConsole(commandLine, options.ColorfulConsole);
  121. } else {
  122. return new BasicConsole(options.ColorfulConsole);
  123. }
  124. }
  125. // The advanced console functions are in a special non-inlined function so that
  126. // dependencies are pulled in only if necessary.
  127. [MethodImplAttribute(MethodImplOptions.NoInlining)]
  128. private static IConsole CreateSuperConsole(CommandLine commandLine, bool isColorful) {
  129. return new SuperConsole(commandLine, isColorful);
  130. }
  131. #endregion
  132. /// <summary>
  133. /// Request (from another thread) the console REPL loop to terminate
  134. /// </summary>
  135. /// <param name="exitCode">The caller can specify the exitCode corresponding to the event triggering
  136. /// the termination. This will be returned from CommandLine.Run</param>
  137. public virtual void Terminate(int exitCode) {
  138. _commandLine.Terminate(exitCode);
  139. }
  140. /// <summary>
  141. /// To be called from entry point.
  142. /// </summary>
  143. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  144. public virtual int Run(string[] args) {
  145. var runtimeSetup = CreateRuntimeSetup();
  146. var options = new ConsoleHostOptions();
  147. _optionsParser = new ConsoleHostOptionsParser(options, runtimeSetup);
  148. try {
  149. ParseHostOptions(args);
  150. } catch (InvalidOptionException e) {
  151. Console.Error.WriteLine("Invalid argument: " + e.Message);
  152. return _exitCode = 1;
  153. }
  154. SetEnvironment();
  155. string provider = GetLanguageProvider(runtimeSetup);
  156. LanguageSetup languageSetup = null;
  157. foreach (var language in runtimeSetup.LanguageSetups) {
  158. if (language.TypeName == provider) {
  159. languageSetup = language;
  160. }
  161. }
  162. if (languageSetup == null) {
  163. // the language doesn't have a setup -> create a default one:
  164. languageSetup = new LanguageSetup(Provider.AssemblyQualifiedName, Provider.Name);
  165. runtimeSetup.LanguageSetups.Add(languageSetup);
  166. }
  167. // inserts search paths for all languages (/paths option):
  168. InsertSearchPaths(runtimeSetup.Options, Options.SourceUnitSearchPaths);
  169. _languageOptionsParser = CreateOptionsParser();
  170. try {
  171. _languageOptionsParser.Parse(Options.IgnoredArgs.ToArray(), runtimeSetup, languageSetup, PlatformAdaptationLayer);
  172. } catch (InvalidOptionException e) {
  173. Console.Error.WriteLine(e.Message);
  174. return _exitCode = -1;
  175. }
  176. _runtime = new ScriptRuntime(runtimeSetup);
  177. try {
  178. _engine = _runtime.GetEngineByTypeName(provider);
  179. } catch (Exception e) {
  180. Console.Error.WriteLine(e.Message);
  181. return _exitCode = 1;
  182. }
  183. Execute();
  184. return _exitCode;
  185. }
  186. private static void InsertSearchPaths(IDictionary<string, object> options, ICollection<string> paths) {
  187. if (options != null && paths != null && paths.Count > 0) {
  188. var existingPaths = new List<string>(LanguageOptions.GetSearchPathsOption(options) ?? (IEnumerable<string>)ArrayUtils.EmptyStrings);
  189. existingPaths.InsertRange(0, paths);
  190. options["SearchPaths"] = existingPaths;
  191. }
  192. }
  193. #region Printing help
  194. protected virtual void PrintHelp() {
  195. Console.WriteLine(GetHelp());
  196. }
  197. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  198. protected virtual string GetHelp() {
  199. StringBuilder sb = new StringBuilder();
  200. string[,] optionsHelp = Options.GetHelp();
  201. sb.AppendLine(String.Format("Usage: {0}.exe [<dlr-options>] [--] [<language-specific-command-line>]", ExeName));
  202. sb.AppendLine();
  203. sb.AppendLine("DLR options (both slash or dash could be used to prefix options):");
  204. ArrayUtils.PrintTable(sb, optionsHelp);
  205. sb.AppendLine();
  206. sb.AppendLine("Language specific command line:");
  207. PrintLanguageHelp(sb);
  208. sb.AppendLine();
  209. return sb.ToString();
  210. }
  211. public void PrintLanguageHelp(StringBuilder output) {
  212. ContractUtils.RequiresNotNull(output, "output");
  213. string commandLine, comments;
  214. string[,] options, environmentVariables;
  215. CreateOptionsParser().GetHelp(out commandLine, out options, out environmentVariables, out comments);
  216. // only display language specific options if one or more optinos exists.
  217. if (commandLine != null || options != null || environmentVariables != null || comments != null) {
  218. if (commandLine != null) {
  219. output.AppendLine(commandLine);
  220. output.AppendLine();
  221. }
  222. if (options != null) {
  223. output.AppendLine("Options:");
  224. ArrayUtils.PrintTable(output, options);
  225. output.AppendLine();
  226. }
  227. if (environmentVariables != null) {
  228. output.AppendLine("Environment variables:");
  229. ArrayUtils.PrintTable(output, environmentVariables);
  230. output.AppendLine();
  231. }
  232. if (comments != null) {
  233. output.Append(comments);
  234. output.AppendLine();
  235. }
  236. output.AppendLine();
  237. }
  238. }
  239. #endregion
  240. private void Execute() {
  241. #if !SILVERLIGHT
  242. if (_languageOptionsParser.CommonConsoleOptions.IsMta) {
  243. Thread thread = new Thread(ExecuteInternal);
  244. thread.SetApartmentState(ApartmentState.MTA);
  245. thread.Start();
  246. thread.Join();
  247. return;
  248. }
  249. #endif
  250. ExecuteInternal();
  251. }
  252. protected virtual void ExecuteInternal() {
  253. Debug.Assert(_engine != null);
  254. ConsoleOptions consoleOptions = _languageOptionsParser.CommonConsoleOptions;
  255. if (consoleOptions.PrintVersion){
  256. PrintVersion();
  257. }
  258. if (consoleOptions.PrintUsage){
  259. PrintUsage();
  260. }
  261. if (consoleOptions.Exit){
  262. _exitCode = 0;
  263. return;
  264. }
  265. switch (Options.RunAction) {
  266. case ConsoleHostOptions.Action.None:
  267. case ConsoleHostOptions.Action.RunConsole:
  268. _exitCode = RunCommandLine();
  269. break;
  270. case ConsoleHostOptions.Action.RunFile:
  271. _exitCode = RunFile();
  272. break;
  273. default:
  274. throw Assert.Unreachable;
  275. }
  276. }
  277. private void SetEnvironment() {
  278. Debug.Assert(Options.EnvironmentVars != null);
  279. #if !SILVERLIGHT
  280. foreach (string env in Options.EnvironmentVars) {
  281. if (!String.IsNullOrEmpty(env)) {
  282. string[] var_def = env.Split('=');
  283. System.Environment.SetEnvironmentVariable(var_def[0], (var_def.Length > 1) ? var_def[1] : "");
  284. }
  285. }
  286. #endif
  287. }
  288. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  289. private int RunFile() {
  290. Debug.Assert(_engine != null);
  291. int result = 0;
  292. try {
  293. return _engine.CreateScriptSourceFromFile(Options.RunFile).ExecuteProgram();
  294. #if SILVERLIGHT
  295. } catch (ExitProcessException e) {
  296. result = e.ExitCode;
  297. #endif
  298. } catch (Exception e) {
  299. UnhandledException(Engine, e);
  300. result = 1;
  301. } finally {
  302. try {
  303. Snippets.SaveAndVerifyAssemblies();
  304. } catch (Exception) {
  305. result = 1;
  306. }
  307. }
  308. return result;
  309. }
  310. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  311. private int RunCommandLine() {
  312. Debug.Assert(_engine != null);
  313. _commandLine = CreateCommandLine();
  314. ConsoleOptions consoleOptions = _languageOptionsParser.CommonConsoleOptions;
  315. if (_console == null) {
  316. _console = CreateConsole(Engine, _commandLine, consoleOptions);
  317. }
  318. int exitCode = 0;
  319. try {
  320. if (consoleOptions.HandleExceptions) {
  321. try {
  322. exitCode = _commandLine.Run(Engine, _console, consoleOptions);
  323. } catch (Exception e) {
  324. if (CommandLine.IsFatalException(e)) {
  325. // Some exceptions are too dangerous to try to catch
  326. throw;
  327. }
  328. UnhandledException(Engine, e);
  329. exitCode = 1;
  330. }
  331. } else {
  332. exitCode = _commandLine.Run(Engine, _console, consoleOptions);
  333. }
  334. } finally {
  335. try {
  336. Snippets.SaveAndVerifyAssemblies();
  337. } catch (Exception) {
  338. exitCode = 1;
  339. }
  340. }
  341. return exitCode;
  342. }
  343. private void PrintUsage()
  344. {
  345. StringBuilder sb = new StringBuilder();
  346. sb.AppendFormat("Usage: {0}.exe ", ExeName);
  347. PrintLanguageHelp(sb);
  348. Console.Write(sb.ToString());
  349. }
  350. protected void PrintVersion()
  351. {
  352. Console.WriteLine("{0} {1} on .NET {2}", Engine.Setup.DisplayName, Engine.LanguageVersion, typeof(String).Assembly.GetName().Version);
  353. }
  354. protected virtual void UnhandledException(ScriptEngine engine, Exception e) {
  355. Console.Error.Write("Unhandled exception");
  356. Console.Error.WriteLine(':');
  357. ExceptionOperations es = engine.GetService<ExceptionOperations>();
  358. Console.Error.WriteLine(es.FormatException(e));
  359. }
  360. protected static void PrintException(TextWriter output, Exception e) {
  361. Debug.Assert(output != null);
  362. ContractUtils.RequiresNotNull(e, "e");
  363. while (e != null) {
  364. output.WriteLine(e);
  365. e = e.InnerException;
  366. }
  367. }
  368. }
  369. }