/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs
408 строк
16 KB
Cyrus Najmabadi
Remove unused usings
18 июн 2025, 22:17
18 июн 2025, 22:17
481c36c
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #pragma warning disable 436 // The type 'RelativePathResolver' conflicts with imported type using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection.PortableExecutable; using System.Text; using System.Threading; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Scripting.Hosting { internal sealed class CommandLineRunner { private readonly ScriptCompiler _scriptCompiler; private readonly ObjectFormatter _objectFormatter; private readonly Func<string, PEStreamOptions, MetadataReferenceProperties, MetadataImageReference> _createFromFileFunc; internal CommandLineRunner( ConsoleIO console, CommonCompiler compiler, ScriptCompiler scriptCompiler, ObjectFormatter objectFormatter, Func<string, PEStreamOptions, MetadataReferenceProperties, MetadataImageReference>? createFromFileFunc = null) { Debug.Assert(console != null); Debug.Assert(compiler != null); Debug.Assert(scriptCompiler != null); Debug.Assert(objectFormatter != null); Console = console; Compiler = compiler; _scriptCompiler = scriptCompiler; _objectFormatter = objectFormatter; _createFromFileFunc = createFromFileFunc ?? Script.CreateFromFile; } // for testing: internal ConsoleIO Console { get; } internal CommonCompiler Compiler { get; } /// <summary> /// csi.exe and vbi.exe entry point. /// </summary> internal int RunInteractive() { SarifErrorLogger? errorLogger = null; if (Compiler.Arguments.ErrorLogOptions?.Path != null) { errorLogger = Compiler.GetErrorLogger(Console.Error); if (errorLogger == null) { return CommonCompiler.Failed; } } using (errorLogger) { return RunInteractiveCore(errorLogger); } } /// <summary> /// csi.exe and vbi.exe entry point. /// </summary> private int RunInteractiveCore(ErrorLogger? errorLogger) { Debug.Assert(Compiler.Arguments.IsScriptRunner); var sourceFiles = Compiler.Arguments.SourceFiles; if (Compiler.Arguments.DisplayVersion) { Compiler.PrintVersion(Console.Out); return 0; } if (Compiler.Arguments.DisplayLangVersions) { Compiler.PrintLangVersions(Console.Out); return 0; } if (sourceFiles.IsEmpty && Compiler.Arguments.DisplayLogo) { Compiler.PrintLogo(Console.Out); if (!Compiler.Arguments.DisplayHelp) { Console.Out.WriteLine(ScriptingResources.HelpPrompt); } } if (Compiler.Arguments.DisplayHelp) { Compiler.PrintHelp(Console.Out); return 0; } SourceText? code = null; var diagnosticsInfos = new List<DiagnosticInfo>(); if (!sourceFiles.IsEmpty) { if (sourceFiles.Length > 1 || !sourceFiles[0].IsScript) { diagnosticsInfos.Add(new DiagnosticInfo(Compiler.MessageProvider, Compiler.MessageProvider.ERR_ExpectedSingleScript)); } else { code = Compiler.TryReadFileContent(sourceFiles[0], diagnosticsInfos); } } // only emit symbols for non-interactive mode, var emitDebugInformation = !Compiler.Arguments.InteractiveMode; var scriptPathOpt = sourceFiles.IsEmpty ? null : sourceFiles[0].Path; var scriptOptions = GetScriptOptions(Compiler.Arguments, scriptPathOpt, Compiler.MessageProvider, diagnosticsInfos, emitDebugInformation); var errors = Compiler.Arguments.Errors.Concat(diagnosticsInfos.Select(Diagnostic.Create)); if (Compiler.ReportDiagnostics(errors, Console.Error, errorLogger, compilation: null)) { return CommonCompiler.Failed; } var cancellationToken = new CancellationToken(); Debug.Assert(scriptOptions is not null); if (Compiler.Arguments.InteractiveMode) { RunInteractiveLoop(scriptOptions, code?.ToString(), cancellationToken); return CommonCompiler.Succeeded; } else { return RunScript(scriptOptions, code, errorLogger, cancellationToken); } } private ScriptOptions? GetScriptOptions(CommandLineArguments arguments, string? scriptPathOpt, CommonMessageProvider messageProvider, List<DiagnosticInfo> diagnostics, bool emitDebugInformation) { var touchedFilesLoggerOpt = (arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; var metadataResolver = GetMetadataReferenceResolver(arguments, touchedFilesLoggerOpt, _createFromFileFunc); var sourceResolver = GetSourceReferenceResolver(arguments, touchedFilesLoggerOpt); var resolvedReferences = new List<MetadataReference>(); if (!arguments.ResolveMetadataReferences(metadataResolver, diagnostics, messageProvider, resolvedReferences)) { // can't resolve some references return null; } return new ScriptOptions( filePath: scriptPathOpt ?? "", references: ImmutableArray.CreateRange(resolvedReferences), namespaces: CommandLineHelpers.GetImports(arguments), metadataResolver: metadataResolver, sourceResolver: sourceResolver, emitDebugInformation: emitDebugInformation, fileEncoding: null, optimizationLevel: OptimizationLevel.Debug, allowUnsafe: true, checkOverflow: false, warningLevel: 4, parseOptions: arguments.ParseOptions, createFromFileFunc: _createFromFileFunc); } internal static MetadataReferenceResolver GetMetadataReferenceResolver( CommandLineArguments arguments, TouchedFileLogger? loggerOpt, Func<string, PEStreamOptions, MetadataReferenceProperties, MetadataImageReference> createFromFileFunc) { return RuntimeMetadataReferenceResolver.CreateCurrentPlatformResolver( arguments.ReferencePaths, arguments.BaseDirectory, createFromFileFunc: (path, properties) => { loggerOpt?.AddRead(path); return createFromFileFunc(path, PEStreamOptions.PrefetchEntireImage, properties); }); } internal static SourceReferenceResolver GetSourceReferenceResolver(CommandLineArguments arguments, TouchedFileLogger? loggerOpt) { return new CommonCompiler.LoggingSourceFileResolver(arguments.SourcePaths, arguments.BaseDirectory, ImmutableArray<KeyValuePair<string, string>>.Empty, loggerOpt); } private int RunScript(ScriptOptions? options, SourceText? code, ErrorLogger? errorLogger, CancellationToken cancellationToken) { var globals = new CommandLineScriptGlobals(Console.Out, _objectFormatter); globals.Args.AddRange(Compiler.Arguments.ScriptArguments); var script = Script.CreateInitialScript<int>(_scriptCompiler, code, options, globals.GetType(), assemblyLoaderOpt: null); try { return script.RunAsync(globals, cancellationToken).GetAwaiter().GetResult().ReturnValue; } catch (CompilationErrorException e) { Compiler.ReportDiagnostics(e.Diagnostics, Console.Error, errorLogger, compilation: null); return CommonCompiler.Failed; } catch (Exception e) { DisplayException(e); return e.HResult; } } private void RunInteractiveLoop(ScriptOptions options, string? initialScriptCodeOpt, CancellationToken cancellationToken) { var globals = new InteractiveScriptGlobals(Console.Out, _objectFormatter); globals.Args.AddRange(Compiler.Arguments.ScriptArguments); ScriptState<object>? state = null; if (initialScriptCodeOpt != null) { var script = Script.CreateInitialScript<object>(_scriptCompiler, SourceText.From(initialScriptCodeOpt), options, globals.GetType(), assemblyLoaderOpt: null); BuildAndRun(script, globals, ref state, ref options, displayResult: false, cancellationToken: cancellationToken); } while (true) { Console.Out.Write("> "); var input = new StringBuilder(); string? line; bool cancelSubmission = false; while (true) { line = Console.In.ReadLine(); if (line == null) { if (input.Length == 0) { return; } cancelSubmission = true; break; } input.AppendLine(line); var tree = _scriptCompiler.ParseSubmission(SourceText.From(input.ToString()), options.ParseOptions, cancellationToken); if (_scriptCompiler.IsCompleteSubmission(tree)) { break; } Console.Out.Write(". "); } if (cancelSubmission) { continue; } string code = input.ToString(); if (IsHelpCommand(code)) { DisplayHelpText(); continue; } Script<object> newScript; if (state == null) { newScript = Script.CreateInitialScript<object>(_scriptCompiler, SourceText.From(code ?? string.Empty), options, globals.GetType(), assemblyLoaderOpt: null); } else { newScript = state.Script.ContinueWith(code, options); } BuildAndRun(newScript, globals, ref state, ref options, displayResult: true, cancellationToken: cancellationToken); } } private void BuildAndRun(Script<object> newScript, InteractiveScriptGlobals globals, ref ScriptState<object>? state, ref ScriptOptions options, bool displayResult, CancellationToken cancellationToken) { var diagnostics = newScript.Compile(cancellationToken); DisplayDiagnostics(diagnostics); if (diagnostics.HasAnyErrors()) { return; } var task = (state == null) ? newScript.RunAsync(globals, catchException: e => true, cancellationToken: cancellationToken) : newScript.RunFromAsync(state, catchException: e => true, cancellationToken: cancellationToken); state = task.GetAwaiter().GetResult(); if (state.Exception != null) { DisplayException(state.Exception); } else if (displayResult && newScript.HasReturnValue()) { globals.Print(state.ReturnValue); } options = UpdateOptions(options, globals); } private static ScriptOptions UpdateOptions(ScriptOptions options, InteractiveScriptGlobals globals) { var currentMetadataResolver = (RuntimeMetadataReferenceResolver)options.MetadataResolver; var currentSourceResolver = (CommonCompiler.LoggingSourceFileResolver)options.SourceResolver; string newWorkingDirectory = Directory.GetCurrentDirectory(); var newReferenceSearchPaths = ImmutableArray.CreateRange(globals.ReferencePaths); var newSourceSearchPaths = ImmutableArray.CreateRange(globals.SourcePaths); // remove references and imports from the options, they have been applied and will be inherited from now on: return options. RemoveImportsAndReferences(). WithMetadataResolver(currentMetadataResolver. WithRelativePathResolver( currentMetadataResolver.PathResolver. WithBaseDirectory(newWorkingDirectory). WithSearchPaths(newReferenceSearchPaths))). WithSourceResolver(currentSourceResolver. WithBaseDirectory(newWorkingDirectory). WithSearchPaths(newSourceSearchPaths)); } private void DisplayException(Exception e) { try { Console.SetForegroundColor(ConsoleColor.Red); if (e is FileLoadException && e.InnerException is InteractiveAssemblyLoaderException) { Console.Error.WriteLine(e.InnerException.Message); } else { Console.Error.Write(_objectFormatter.FormatException(e)); } } finally { Console.ResetColor(); } } private static bool IsHelpCommand(string text) { const string helpCommand = "#help"; Debug.Assert(text != null); return text.Trim() == helpCommand; } private void DisplayHelpText() { Console.Out.Write(ScriptingResources.HelpText); Console.Out.WriteLine(); } private void DisplayDiagnostics(ImmutableArray<Diagnostic> diagnostics) { const int MaxDisplayCount = 5; // by severity, then by location var ordered = diagnostics.OrderBy((d1, d2) => { int delta = (int)d2.Severity - (int)d1.Severity; return (delta != 0) ? delta : d1.Location.SourceSpan.Start - d2.Location.SourceSpan.Start; }); try { foreach (var diagnostic in ordered.Take(MaxDisplayCount)) { Console.SetForegroundColor(diagnostic.Severity == DiagnosticSeverity.Error ? ConsoleColor.Red : ConsoleColor.Yellow); Console.Error.WriteLine(diagnostic.ToString()); } if (diagnostics.Length > MaxDisplayCount) { int notShown = diagnostics.Length - MaxDisplayCount; Console.SetForegroundColor(ConsoleColor.DarkRed); Console.Error.WriteLine(string.Format(ScriptingResources.PlusAdditionalError, notShown)); } } finally { Console.ResetColor(); } } } }