/// <summary> /// Change the state of the interpreter. /// </summary> /// <param name="source">The source from where we changed the state (an interpreter usually).</param> /// <param name="e">The new state.</param> internal void ChangeState(object source, BaZicInterpreterStateChangeEventArgs e) { if (e.State == BaZicInterpreterState.StoppedWithError || e.State == BaZicInterpreterState.Stopped) { ProgramInterpreter?.CloseUserInterface(); } lock (_stateChangedHistory) { var oldState = State; switch (e.State) { case BaZicInterpreterState.StoppedWithError: if (State != BaZicInterpreterState.StoppedWithError) { Error = e.Error; State = e.State; } break; case BaZicInterpreterState.Pause: case BaZicInterpreterState.Preparing: case BaZicInterpreterState.Ready: case BaZicInterpreterState.Running: case BaZicInterpreterState.Idle: case BaZicInterpreterState.Stopped: State = e.State; break; case BaZicInterpreterState.Log: Logger.Instance.Debug($"BaZic Interpreter : {e.LogMessage}"); break; default: throw new ArgumentOutOfRangeException(nameof(e.State)); } if (e.State == BaZicInterpreterState.Log || e.State == BaZicInterpreterState.Ready || State != oldState) { _stateChangedHistory.Add(e); StateChanged?.Invoke(this, e); _middleware.SendLog(this, e); } } }
/// <summary> /// Starts the interpreter in debug mode. The program will be interpreted and support the beakpoint and step by step debugging. /// </summary> /// <param name="callback">The cross-AppDomain task proxy.</param> /// <param name="verbose">Defines if the verbose mode must be enabled or not.</param> /// <param name="args">The arguments to pass to the entry point.</param> /// <returns>Returns an awaitable task that can wait the end of the program execution</returns> internal void StartDebug(MarshaledResultSetter callback, bool verbose, params object[] args) { Requires.NotNull(_middleware, nameof(_middleware)); if (_releaseModeForced) { throw new UnexpectedException(new Exception(L.BaZic.Runtime.BaZicInterpreter.CannotStartDebugAfterBuild)); } _forceStop = false; DebugMode = true; var action = new Action(() => { LoadAssemblies(); if (State == BaZicInterpreterState.Preparing) { if (ProgramInterpreter == null) { var executionFlowId = RunningStateManager.AddCallStackForUnwaitedMethodInvocation(); RunningStateManager.SetIsRunningMainFunction(true); ProgramInterpreter = new ProgramInterpreter(this, Program, executionFlowId); } ProgramInterpreter.Start(_programArguments); RunningStateManager.WaitUnwaitedMethodInvocation(ProgramInterpreter.ExecutionFlowId); if (State == BaZicInterpreterState.Running || State == BaZicInterpreterState.Idle) { ProgramResult = ProgramInterpreter.ProgramResult; FreePauseModeWaiter(); } } }); callback.ContinueWith(() => { RunningStateManager.SetIsRunningMainFunction(false); RunningStateManager.UpdateState(); }, null); Start(callback, action, verbose, args); }
/// <summary> /// Dispose the resources /// </summary> public void Dispose() { Stop(); if (ProgramInterpreter != null) { ProgramInterpreter.Dispose(); } if (_stateChangedHistory != null) { _stateChangedHistory.Clear(); } if (DebugInfo != null) { DebugInfo.CallStackService.StackTraceCallCount.Clear(); DebugInfo.CallStackService.CallStacks.Clear(); DebugInfo.CallStackService.CallCount = 0; DebugInfo = null; } Error = null; Program = null; ProgramInterpreter = null; }
/// <summary> /// Start the interpreter /// </summary> /// <param name="debugMode">Defines if the debug mode must be enabled or not</param> /// <returns>Returns an awaitable task that can wait the end of the program execution</returns> private Task RunAsync(bool debugMode) { InDebugMode = debugMode; return Task.Run(() => { RuntimeHelpers.EnsureSufficientExecutionStack(); GCSettings.LatencyMode = GCLatencyMode.LowLatency; ProgramInterpreter = new ProgramInterpreter(Program, debugMode); ProgramInterpreter.StateChanged += ChangeState; ProgramInterpreter.Start(); Stop(false); ProgramInterpreter.StateChanged -= ChangeState; ProgramInterpreter.Dispose(); GCSettings.LatencyMode = GCLatencyMode.Interactive; GC.Collect(); GC.WaitForPendingFinalizers(); }); }
/// <summary> /// Invoke a public method accessible from outside of the interpreter (EXTERN FUNCTION) in Debug mode. /// </summary> /// <param name="callback">The cross-AppDomain task proxy.</param> /// <param name="verbose">Defines if the verbose mode must be enabled or not.</param> /// <param name="methodName">The name of the method.</param> /// <param name="awaitIfAsync">Await if the method is maked as asynchronous.</param> /// <param name="args">The arguments to pass to the method.</param> /// <returns>Returns the result of the invocation (a <see cref="Task"/> in the case of a not awaited asynchronous method, or the value returned by the method).</returns> private async void InvokeMethodDebug(MarshaledResultSetter <object> callback, bool verbose, string methodName, bool awaitIfAsync, object[] args) { DebugMode = true; if (State == BaZicInterpreterState.Ready || State == BaZicInterpreterState.Stopped || State == BaZicInterpreterState.StoppedWithError) { // Creates a new ProgramInterpreter. var privateCallback = new MarshaledResultSetter(); var action = new Action(() => { LoadAssemblies(); if (State == BaZicInterpreterState.Preparing) { var executionFlowIdProgram = RunningStateManager.AddCallStackForUnwaitedMethodInvocation(); ProgramInterpreter = new ProgramInterpreter(this, Program, executionFlowIdProgram); ProgramInterpreter.InitializeGlobalState(); ChangeState(this, new BaZicInterpreterStateChangeEventArgs(BaZicInterpreterState.Idle)); } }); Start(privateCallback, action, verbose); await privateCallback.Task; } var currentCulture = LocalizationHelper.GetCurrentCulture(); var thread = Task.Run(() => { object result = null; try { LocalizationHelper.SetCurrentCulture(currentCulture, false, false); Task.Delay(500).ConfigureAwait(false).GetAwaiter().GetResult(); if (State == BaZicInterpreterState.Preparing) { // Wait for running. WaitForState(BaZicInterpreterState.Running, BaZicInterpreterState.Idle); } if (State == BaZicInterpreterState.Running) { // Wait for having being idle. WaitForState(BaZicInterpreterState.Idle, BaZicInterpreterState.Stopped, BaZicInterpreterState.StoppedWithError); if (_forceStop) { // The state is Stopped and it has been requested by the user (command await Stop()) or the interpreter is disposing. return(null); } } CheckState(BaZicInterpreterState.Idle, BaZicInterpreterState.Stopped, BaZicInterpreterState.StoppedWithError); var arguments = new List <PrimitiveExpression>(); if (args != null) { foreach (var argument in args) { arguments.Add(new PrimitiveExpression(argument)); } } RunningStateManager.StartsExternMethod(); var executionFlowId = RunningStateManager.AddCallStackForUnwaitedMethodInvocation(); result = ProgramInterpreter.InvokeMethod(executionFlowId, methodName, awaitIfAsync, arguments.ToArray()); } catch (Exception exception) { CoreHelper.ReportException(exception); if (!_ignoreException) { ChangeState(this, new UnexpectedException(exception)); } _ignoreException = false; } finally { RunningStateManager.StopsExternMethod(); RunningStateManager.UpdateState(); GC.Collect(); GC.WaitForPendingFinalizers(); } return(result); }); var t = thread.ContinueWith((task) => { callback.SetResult(task.Result); }); }