diff --git a/src/ScriptEngine.HostedScript/HostedScriptEngine.cs b/src/ScriptEngine.HostedScript/HostedScriptEngine.cs index 6ed02ed64..d2c6dfc5d 100644 --- a/src/ScriptEngine.HostedScript/HostedScriptEngine.cs +++ b/src/ScriptEngine.HostedScript/HostedScriptEngine.cs @@ -12,7 +12,6 @@ This Source Code Form is subject to the terms of the using OneScript.Compilation; using OneScript.Contexts; using OneScript.DependencyInjection; -using OneScript.Execution; using OneScript.StandardLibrary; using OneScript.StandardLibrary.Tasks; using ScriptEngine.Machine.Contexts; @@ -85,35 +84,64 @@ public ICompilerFrontend GetCompilerService() { var compilerSvc = _engine.GetCompilerService(); compilerSvc.FillSymbols(typeof(UserScriptContextInstance)); - + DefineConstants(compilerSvc); return compilerSvc; } + /// + /// Создаёт процесс выполнения скрипта: инициализация, компиляция исходника, подготовка к запуску. + /// + /// Хост-приложение для взаимодействия со скриптом. + /// Исходный код скрипта. + /// Процесс, готовый к вызову . + /// + /// При ошибке компиляции или подготовки исключение пробрасывается вызывающему коду. + /// public Process CreateProcess(IHostApplication host, SourceCode src) { Initialize(); SetGlobalEnvironment(host, src); - - if (_engine.Debugger.IsEnabled) - { - _engine.Debugger.Start(); - _engine.Debugger.GetSession().WaitReadyToRun(); - } var compilerSvc = GetCompilerService(); - DefineConstants(compilerSvc); - IExecutableModule module; - var bslProcess = _engine.NewProcess(); + return Process.Create(_engine, compilerSvc, src); + } + + /// + /// Создаёт и запускает процесс скрипта, возвращает код завершения. + /// + /// Хост-приложение для взаимодействия со скриптом. + /// Исходный код скрипта. + /// + /// Код завершения скрипта; при ошибке создания/выполнения — 1 + /// после вывода информации об исключении через . + /// + /// + /// Управляет сессией отладчика: старт и ожидание готовности перед созданием процесса, + /// уведомление о завершении при любом исходе. + /// Прерывание скрипта () обрабатывается в + /// и возвращается как штатный код выхода. + /// + public int RunProcess(IHostApplication host, SourceCode source) + { try { - module = compilerSvc.Compile(src, bslProcess); + if (_engine.Debugger.IsEnabled) + { + _engine.Debugger.Start(); + _engine.Debugger.GetSession().WaitReadyToRun(); + } + + var process = CreateProcess(host, source); + var exitCode = process.Start(); + _engine.Debugger.NotifyProcessExit(exitCode); + return exitCode; } - catch (CompilerException) + catch (Exception e) { _engine.Debugger.NotifyProcessExit(1); - throw; + host.ShowExceptionInfo(e); + return 1; } - return InitProcess(bslProcess, host, module); } private void DefineConstants(ICompilerFrontend compilerSvc) @@ -139,14 +167,6 @@ public void SetGlobalEnvironment(IHostApplication host, SourceCode src) _globalCtx.InitInstance(); } - private Process InitProcess(IBslProcess bslProcess, IHostApplication host, IExecutableModule module) - { - Initialize(); - - var process = new Process(bslProcess, host, module, _engine); - return process; - } - public void Dispose() { _engine?.Dispose(); diff --git a/src/ScriptEngine.HostedScript/Process.cs b/src/ScriptEngine.HostedScript/Process.cs index 39a36d266..5159a8c51 100644 --- a/src/ScriptEngine.HostedScript/Process.cs +++ b/src/ScriptEngine.HostedScript/Process.cs @@ -4,59 +4,66 @@ This Source Code Form is subject to the terms of the was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ -using System; + +using OneScript.Compilation; using OneScript.Execution; +using OneScript.Sources; using ScriptEngine.Machine; namespace ScriptEngine.HostedScript { + /// + /// Скомпилированный процесс выполнения скрипта. + /// public class Process { - ScriptingEngine _engine; - - readonly IHostApplication _host; - readonly IExecutableModule _module; - private IBslProcess _bslProcess; + private readonly ScriptingEngine _engine; + private readonly IExecutableModule _module; + private readonly IBslProcess _bslProcess; - internal Process( + private Process( IBslProcess process, - IHostApplication host, IExecutableModule src, ScriptingEngine runtime) { - _host = host; _engine = runtime; _module = src; _bslProcess = process; } - public int Start() + /// + /// Создаёт процесс: выделяет runtime-процесс, компилирует исходник, готовит к запуску. + /// + internal static Process Create( + ScriptingEngine engine, + ICompilerFrontend compiler, + SourceCode source) { - int exitCode = 0; + var bslProcess = engine.NewProcess(); + var module = compiler.Compile(source, bslProcess); + return new Process(bslProcess, module, engine); + } + /// + /// Запускает выполнение скрипта. + /// + /// + /// 0 при успешном завершении; код выхода при прерывании скрипта. + /// + /// + /// Прочие исключения пробрасываются вызывающему коду. + /// + public int Start() + { try { _engine.NewObject(_module, _bslProcess); - exitCode = 0; + return 0; } catch (ScriptInterruptionException e) { - exitCode = e.ExitCode; + return e.ExitCode; } - catch (Exception e) - { - _host.ShowExceptionInfo(e); - exitCode = 1; - } - finally - { - _engine.Debugger.NotifyProcessExit(exitCode); - _engine.Dispose(); - _engine = null; - } - - return exitCode; } - } } diff --git a/src/TestApp/MainWindow.xaml.cs b/src/TestApp/MainWindow.xaml.cs index 320401b17..d60cec9e5 100644 --- a/src/TestApp/MainWindow.xaml.cs +++ b/src/TestApp/MainWindow.xaml.cs @@ -159,7 +159,7 @@ private HostedScriptEngine CreateEngine() private void Button_Click(object sender, RoutedEventArgs e) { - var hostedScript = CreateEngine(); + using var hostedScript = CreateEngine(); hostedScript.Initialize(); var src = hostedScript.Loader.FromString(txtCode.Text); @@ -205,27 +205,16 @@ private void Button_Click_1(object sender, RoutedEventArgs e) var host = new Host(result, l_args.ToArray()); SystemLogger.SetWriter(host); - var hostedScript = CreateEngine(); + using var hostedScript = CreateEngine(); var src = SourceCodeBuilder.Create() .FromSource(new EditedFileSource(txtCode.Text, _currentDocPath)) .WithName(_currentDocPath) .Build(); - Process process = null; - try - { - process = hostedScript.CreateProcess(host, src); - } - catch (Exception exc) - { - host.Echo(exc.Message); - return; - } - result.AppendText("Script started: " + DateTime.Now.ToString() + "\n"); sw.Start(); - var returnCode = process.Start(); + var returnCode = hostedScript.RunProcess(host, src); sw.Stop(); if (returnCode != 0) { @@ -233,7 +222,6 @@ private void Button_Click_1(object sender, RoutedEventArgs e) } result.AppendText("\nScript completed: " + DateTime.Now.ToString()); result.AppendText("\nDuration: " + sw.Elapsed.ToString() + "\n"); - } private static string GetFileDialogFilter() @@ -422,11 +410,18 @@ public Host(TextBox output, string [] arguments = null) public void Echo(string str, MessageStatusEnum status = MessageStatusEnum.Ordinary) { - _output.Dispatcher.BeginInvoke(new Action(() => + void Append() { _output.AppendText(str + '\n'); _output.ScrollToEnd(); - })); + } + + // RunProcess вызывается с UI-потока: без синхронной записи + // ShowExceptionInfo оказывается после "Error detected" / "Script completed". + if (_output.Dispatcher.CheckAccess()) + Append(); + else + _output.Dispatcher.BeginInvoke(new Action(Append)); } public void ShowExceptionInfo(Exception exc) diff --git a/src/oscript/CgiBehavior.cs b/src/oscript/CgiBehavior.cs index 3354a0597..f0781bf9e 100644 --- a/src/oscript/CgiBehavior.cs +++ b/src/oscript/CgiBehavior.cs @@ -68,33 +68,17 @@ private int RunCGIMode(string scriptFile) e.AddAssembly(GetType().Assembly); }); - var engine = ConsoleHostBuilder.Build(builder); - - var request = new WebRequestContext(engine.Services.Resolve().MaxBytesInMemory); + using var engine = ConsoleHostBuilder.Build(builder); + using var request = new WebRequestContext(engine.Services.Resolve().MaxBytesInMemory); engine.InjectGlobalProperty("ВебЗапрос", "WebRequest", request, true); engine.InjectObject(this); var source = engine.Loader.FromFile(scriptFile); - - Process process; - - try - { - process = engine.CreateProcess(this, source); - } - catch (Exception e) - { - ShowExceptionInfo(e); - return 1; - } - - var exitCode = process.Start(); + var exitCode = engine.RunProcess(this, source); if (!_isContentEchoed) Echo(""); - request.Dispose(); - return exitCode; } diff --git a/src/oscript/CheckSyntaxBehavior.cs b/src/oscript/CheckSyntaxBehavior.cs index aa285ec6e..3148fd1e4 100644 --- a/src/oscript/CheckSyntaxBehavior.cs +++ b/src/oscript/CheckSyntaxBehavior.cs @@ -28,7 +28,7 @@ public CheckSyntaxBehavior(string path, string envFile, bool isCgi = false) public override int Execute() { var builder = ConsoleHostBuilder.Create(_path); - var hostedScript = ConsoleHostBuilder.Build(builder); + using var hostedScript = ConsoleHostBuilder.Build(builder); hostedScript.Initialize(); if (_isCgi) diff --git a/src/oscript/ConsoleApplicationHost.cs b/src/oscript/ConsoleApplicationHost.cs index 45b2bc11c..412ee0384 100644 --- a/src/oscript/ConsoleApplicationHost.cs +++ b/src/oscript/ConsoleApplicationHost.cs @@ -33,19 +33,7 @@ public void Write(string text) public int RunProcess(HostedScriptEngine engine, SourceCode source) { SystemLogger.SetWriter(this); - - Process process; - try - { - process = engine.CreateProcess(this, source); - } - catch (Exception e) - { - ShowExceptionInfo(e); - return 1; - } - - return process.Start(); + return engine.RunProcess(this, source); } } } diff --git a/src/oscript/ShowCompiledBehavior.cs b/src/oscript/ShowCompiledBehavior.cs index 5be120562..cf257d264 100644 --- a/src/oscript/ShowCompiledBehavior.cs +++ b/src/oscript/ShowCompiledBehavior.cs @@ -23,7 +23,7 @@ public ShowCompiledBehavior(string path) public override int Execute() { var builder = ConsoleHostBuilder.Create(_path); - var hostedScript = ConsoleHostBuilder.Build(builder); + using var hostedScript = ConsoleHostBuilder.Build(builder); hostedScript.Initialize(); var source = hostedScript.Loader.FromFile(_path);