/
EvilBeaver
/
OneScript
Обзор
Документация
Войти
/
EvilBeaver
/
OneScript
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
v2.0.1
src/ScriptEngine/Machine/MachineStopManager.cs
162 строки
6 KB
EvilBeaver
Лишняя остановка отладчиком на заголовке цикла Для Каждого
19 дек 2025, 22:50
19 дек 2025, 22:50
3cadb89
Код
Авторство
О чём код?
/*---------------------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v.2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ using System; using System.Linq; using ScriptEngine.Machine.Debugger; namespace ScriptEngine.Machine { internal enum DebugState { Running, SteppingOver, SteppingIn, SteppingOut } internal class MachineStopManager { private struct StopPoint { public ExecutionFrame frame; public int line; } private DebugState _currentState = DebugState.Running; private readonly IBreakpointManager _breakpoints; private readonly MachineInstance _machine; private readonly IThreadEventsListener _threadManager; private ExecutionFrame[] _stopFrames; private StopPoint _lastStopPoint; public MachineStopManager(MachineInstance runner, IThreadEventsListener threadManager, IBreakpointManager breakpoints) { _machine = runner ?? throw new ArgumentNullException(nameof(runner)); _threadManager = threadManager; _breakpoints = breakpoints ?? throw new ArgumentNullException(nameof(runner)); } public IBreakpointManager Breakpoints => _breakpoints; public MachineStopReason LastStopReason { get; internal set; } public string LastStopErrorMessage { get; internal set; } public DebugState CurrentState => _currentState; public void NotifyStop(MachineStopReason reason, string errMessage) { _threadManager.ThreadStopped(_machine.Process.VirtualThreadId, reason, errMessage); } public void NotifyStop() { _threadManager.ThreadStopped(_machine.Process.VirtualThreadId, LastStopReason, LastStopErrorMessage); } public bool ShouldStopAtThisLine(string module, ExecutionFrame currentFrame) { bool mustStop = false; switch (_currentState) { case DebugState.Running: mustStop = HitBreakpointOnLine(module, currentFrame); break; case DebugState.SteppingIn: mustStop = true; break; case DebugState.SteppingOut: case DebugState.SteppingOver: mustStop = FrameIsInStopList(currentFrame); // по пути следования все равно может встретиться breakpoint if (!mustStop && HitBreakpointOnLine(module, currentFrame)) { _currentState = DebugState.Running; //для правильной причины останова (см. ниже) mustStop = true; } break; } if (mustStop) { // здесь мы уже останавливались? if (_lastStopPoint.frame != currentFrame || _lastStopPoint.line != currentFrame.LineNumber) { if (_currentState == DebugState.Running) { LastStopReason = MachineStopReason.Breakpoint; // Проверим существование условия остановки var condition = Breakpoints.GetCondition(module, currentFrame.LineNumber); if (!string.IsNullOrEmpty(condition)) { try { mustStop = _machine.EvaluateInFrame(condition, currentFrame).AsBoolean(); } catch (Exception ex) { // Остановим и сообщим, что остановка произошла не по условию, а в результате ошибки вычисления mustStop = true; LastStopReason = MachineStopReason.BreakpointConditionError; LastStopErrorMessage = $"Не удалось выполнить условие точки останова: {ex.Message}"; } } } else { LastStopReason = MachineStopReason.Step; } _lastStopPoint = new StopPoint() { frame = currentFrame, line = currentFrame.LineNumber }; _currentState = DebugState.Running; } else { mustStop = false; } } return mustStop; } private bool HitBreakpointOnLine(string module, ExecutionFrame currentFrame) { return _breakpoints.FindBreakpoint(module, currentFrame.LineNumber); } private bool FrameIsInStopList(ExecutionFrame currentFrame) { return _stopFrames != null && _stopFrames.Contains(currentFrame); } public void StepOver() { _currentState = DebugState.SteppingOver; _stopFrames = _machine.GetExecutionFrames().Select(x => x.FrameObject).ToArray(); } public void StepIn() { _currentState = DebugState.SteppingIn; } internal void StepOut() { _currentState = DebugState.SteppingOut; _stopFrames = _machine.GetExecutionFrames().Select(x => x.FrameObject).Skip(1).ToArray(); } } }