private void DoExecute() // MAIN thread only.. { executing = true; System.Diagnostics.Stopwatch timetaken = new System.Diagnostics.Stopwatch(); timetaken.Start(); while (true) { if (progcurrent != null) { if (progcurrent.GetErrorList != null) // any errors pending, handle { actioncontroller.LogLine("Error: " + progcurrent.GetErrorList + Environment.NewLine + StackTrace()); TerminateToCloseAtEnd(); // terminate up to a close at end entry, which would have started this stack } else if (progcurrent.IsProgramFinished) // if current program ran out, cancel it { // this catches a LOOP without a statement at the end.. or a DO without a WHILE at the end.. if (progcurrent.ExecLevel > 0 && progcurrent.LevelUp(progcurrent.ExecLevel, null)) // see if we have any pending LOOP (or a DO without a while) and continue.. { continue; // errors or movement causes it to go back.. errors will be picked up above } TerminateCurrent(); } } while (progcurrent == null && progqueue.Count > 0) // if no program,but something in queue { progcurrent = progqueue[0]; progqueue.RemoveAt(0); if (progcurrent.variables != null) // if not null, its because its just been restarted after a call.. reset globals { progcurrent.Add(actioncontroller.Globals); // in case they have been updated... progcurrent.Add(progcurrent.ActionFile.FileVariables); // in case they have been updated... } else { progcurrent.PrepareToRun( new Variables(progcurrent.inputvariables, actioncontroller.Globals, progcurrent.ActionFile.FileVariables), new FunctionPersistentData(), new Dictionary <string, ExtendedControls.ConfigurableForm>(), true); // with new file handles and close at end.. } if (progcurrent.IsProgramFinished) // reject empty programs.. { TerminateCurrent(); continue; // and try again } } if (progcurrent == null) // Still nothing, game over { break; } ActionBase ac = progcurrent.GetNextStep(); // get the step. move PC on. // System.Diagnostics.Debug.WriteLine((Environment.TickCount % 10000).ToString("00000") + " " + timetaken.ElapsedMilliseconds + " @ " + progcurrent.Location + " Lv " + progcurrent.ExecLevel + " e " + (progcurrent.IsExecuteOn ? "1" : "0") + " up " + ac.LevelUp + " " + progcurrent.PushPos + " " + ac.Name); if (ac.LevelUp > 0 && progcurrent.LevelUp(ac.LevelUp, ac)) // level up.. { //System.Diagnostics.Debug.WriteLine((Environment.TickCount % 10000).ToString("00000") + " Abort Lv" + progcurrent.ExecLevel + " e " + (progcurrent.IsExecuteOn ? "1" : "0") + " up " + ac.LevelUp + ": " + progcurrent.StepNumber + " " + ac.Name + " " + ac.DisplayedUserData); continue; } if (logtologline || logger != null) { string t = (Environment.TickCount % 10000).ToString("00000") + " "; string index = string.Concat(Enumerable.Repeat(". ", progcurrent.ExecLevel)); string s = progcurrent.GetLastStep().LineNumber.ToString() + (progcurrent.IsExecuteOn ? "+" : "-") + ":" + index + ac.Name + " " + ac.DisplayedUserData; System.Diagnostics.Debug.WriteLine(t + s); if (logtologline) { actioncontroller.LogLine(t + s); } if (logger != null) { logger.WriteLine(s); } } if (progcurrent.DoExecute(ac)) // execute is on.. { if (ac.Type == ActionBase.ActionType.Call) // Call needs to pass info back up thru to us, need a different call { ActionCall acall = ac as ActionCall; string prog; Variables paravars; if (acall.ExecuteCallAction(progcurrent, out prog, out paravars)) // if execute ok { //System.Diagnostics.Debug.WriteLine("Call " + prog + " with " + paravars.ToString()); Tuple <ActionFile, ActionProgram> ap = actionfilelist.FindProgram(prog, progcurrent.ActionFile); // find program using this name, prefer this action file first if (ap != null) { Run(true, ap.Item1, ap.Item2, paravars, progcurrent.Functions.persistentdata, progcurrent.Dialogs, false); // run now with these para vars } else { progcurrent.ReportError("Call cannot find " + prog); } } } else if (ac.Type == ActionBase.ActionType.Return) // Return needs to pass info back up thru to us, need a different call { ActionReturn ar = ac as ActionReturn; string retstr; if (ar.ExecuteActionReturn(progcurrent, out retstr)) { TerminateCurrent(); // if a new program is queued, but not prepared, and this program returns to finish, make sure we don't // screw up since the variables are not preparred yet - they will be above in PrepareToRun if (progqueue.Count > 0 && progqueue[0].variables != null) // pass return value if program is there AND its prepared { progqueue[0]["ReturnValue"] = retstr; } continue; // back to top, next action from returned function. } } else if (!ac.ExecuteAction(progcurrent)) // if execute says, stop, i'm waiting for something { return; // exit, with executing set true. ResumeAfterPause will restart it. } } if (AsyncMode && timetaken.ElapsedMilliseconds > 150) // no more than ms per go to stop the main thread being blocked { System.Diagnostics.Debug.WriteLine((Environment.TickCount % 10000).ToString("00000") + " *** SUSPEND Actions at " + timetaken.ElapsedMilliseconds); restarttick.Start(); break; } } executing = false; }