Skip to content
Open
66 changes: 43 additions & 23 deletions src/ScriptEngine.HostedScript/HostedScriptEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,35 +84,64 @@ public ICompilerFrontend GetCompilerService()
{
var compilerSvc = _engine.GetCompilerService();
compilerSvc.FillSymbols(typeof(UserScriptContextInstance));

DefineConstants(compilerSvc);
return compilerSvc;
}

/// <summary>
/// Создаёт процесс выполнения скрипта: инициализация, компиляция исходника, подготовка к запуску.
/// </summary>
/// <param name="host">Хост-приложение для взаимодействия со скриптом.</param>
/// <param name="src">Исходный код скрипта.</param>
/// <returns>Процесс, готовый к вызову <see cref="Process.Start"/>.</returns>
/// <remarks>
/// При ошибке компиляции или подготовки исключение пробрасывается вызывающему коду.
/// </remarks>
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);
}

/// <summary>
/// Создаёт и запускает процесс скрипта, возвращает код завершения.
/// </summary>
/// <param name="host">Хост-приложение для взаимодействия со скриптом.</param>
/// <param name="source">Исходный код скрипта.</param>
/// <returns>
/// Код завершения скрипта; при ошибке создания/выполнения — <c>1</c>
/// после вывода информации об исключении через <see cref="IHostApplication.ShowExceptionInfo"/>.
/// </returns>
/// <remarks>
/// Управляет сессией отладчика: старт и ожидание готовности перед созданием процесса,
/// уведомление о завершении при любом исходе.
/// Прерывание скрипта (<see cref="ScriptInterruptionException"/>) обрабатывается в <see cref="Process.Start"/>
/// и возвращается как штатный код выхода.
/// </remarks>
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)
Expand All @@ -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();
Expand Down
61 changes: 34 additions & 27 deletions src/ScriptEngine.HostedScript/Process.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/// <summary>
/// Скомпилированный процесс выполнения скрипта.
/// </summary>
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()
/// <summary>
/// Создаёт процесс: выделяет runtime-процесс, компилирует исходник, готовит к запуску.
/// </summary>
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);
}

/// <summary>
/// Запускает выполнение скрипта.
/// </summary>
/// <returns>
/// <c>0</c> при успешном завершении; код выхода при прерывании скрипта.
/// </returns>
/// <remarks>
/// Прочие исключения пробрасываются вызывающему коду.
/// </remarks>
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;
}

}
}
29 changes: 12 additions & 17 deletions src/TestApp/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -205,35 +205,23 @@ 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);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
sw.Stop();
if (returnCode != 0)
{
result.AppendText("\nError detected. Exit code = " + returnCode.ToString());
}
result.AppendText("\nScript completed: " + DateTime.Now.ToString());
result.AppendText("\nDuration: " + sw.Elapsed.ToString() + "\n");

}

private static string GetFileDialogFilter()
Expand Down Expand Up @@ -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)
Expand Down
22 changes: 3 additions & 19 deletions src/oscript/CgiBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IBinaryDataMemoryLimit>().MaxBytesInMemory);
using var engine = ConsoleHostBuilder.Build(builder);
using var request = new WebRequestContext(engine.Services.Resolve<IBinaryDataMemoryLimit>().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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/oscript/CheckSyntaxBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 1 addition & 13 deletions src/oscript/ConsoleApplicationHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
2 changes: 1 addition & 1 deletion src/oscript/ShowCompiledBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down