private int StepFlow(ActionBase action) { // function if (action is Actionfunction) { return(++m_IP); } // return if (action is Actionreturn) { m_IP = m_InstrStack.Pop(); m_CallStack.Pop(); m_variables.RemoveLocals(m_FnNameStack.Pop()); return(++m_IP); } // call if (action is Actioncall) { Actioncall call = (Actioncall)action; Debug.Assert(null != call); m_InstrStack.Push(m_IP); m_IP = m_script.GetFuncEntryIndex(call.FunctionName); m_CallStack.Push(m_IP); if (-1 == m_IP) { string errMsg = "Function: '" + call.FunctionName + "' NOT found."; m_Status = VMStatus.ERROR; m_ErrStack.Push(errMsg); host.MarkCurrentLine(m_IP, action.LineNumber, Color.Red, action.Path2Script); action.Result = EnumActionResult.ERROR; throw new Exception(errMsg); } Actionfunction fn = (Actionfunction)m_script.GetAction(m_IP); Debug.Assert(null != fn); Dictionary <string, string> vars = new Dictionary <string, string>(); if (call.Parameters.Count > 0) { for (int i = 0; i < call.Parameters.Count; ++i) { string key = fn.Parameters[i]; string value = m_variables.Get(call.Parameters[i]); vars.Add(key, value); } } m_variables.AddLocals(fn.Name, vars); // create a new scope as well m_FnNameStack.Push(fn.Name); return(m_IP); } // Label if (action is ActionLabel) { return(++m_IP); } // goto if (action is ActionGoto) { ActionGoto actGoto = (ActionGoto)action; int jump2Index = -1; int i = 0; foreach (ActionBase item in m_script.Actions) // locate position where to goto { if (item is ActionLabel) { ActionLabel actLabel = (ActionLabel)item; if (actLabel.GetLabel == actGoto.label) { jump2Index = i; break; } } ++i; } if (-1 == jump2Index) { throw new Exception("Error locating label '" + actGoto.label + "' for GOTO command."); } if ("0" != actGoto.jumpCount) // not a FOR-EVER kind of goto { if (!m_dicGotoCounts.ContainsKey(actGoto.label)) { m_dicGotoCounts.Add(actGoto.label, Convert.ToInt32(actGoto.jumpCount)); // init } if (m_dicGotoCounts[actGoto.label] > 0) { --m_dicGotoCounts[actGoto.label]; } else { m_dicGotoCounts.Remove(actGoto.label); m_script.Actions.IndexOf(actGoto); return(m_IP); } } m_IP = jump2Index; return(m_IP); } // foreach // for // while if (action is ActionFlowIterator) { ActionFlowIterator act = (ActionFlowIterator)action; Debug.Assert(null != act); if (0 == m_LoopStack.Count) { m_LoopStack.Push(m_IP); } else if (m_LoopStack.Peek() != m_IP) { m_LoopStack.Push(m_IP); } if (act.IsDone) { m_LoopStack.Pop(); m_IP = GetMatchingLoopStatement(m_IP); } return(++m_IP); } // break if (action is Actionbreak) { int ip = m_LoopStack.Pop(); ActionFlowIterator act = (ActionFlowIterator)m_script.Actions[ip]; act.Done(); // probably it will cleanup itself from the vm m_IP = GetClosestLoopStatement(m_IP); return(++m_IP); } // loop // continue if (action is Actionloop || action is Actioncontinue) { m_IP = m_LoopStack.Peek(); return(m_IP); } // if if (action is Actionif) { Actionif actIF = (Actionif)action; m_IfStack.Push(m_IP); if (actIF.result == true) { return(++m_IP); // go inside if block } else // bypass if block (find else or endif statement (matching! nested if satetement are skipped as well) { m_IP = GetMatchingIfStatement(m_IP); return(m_IP); } } // endif if (action is Actionendif) { m_IfStack.Pop(); return(++m_IP); } // else if (action is Actionelse) { int index = m_IfStack.Peek(); Actionif actIF = (Actionif)script.Actions[index]; if (actIF.result == true) // then skip the else part { m_IP = GetMatchingIfStatement(m_IP); return(m_IP); } else { return(++m_IP); } } // unknown command throw new Exception("Player::StepFlow Unknown FlowCommand [" + action.RawCmdLine.Trim() + "]"); }
private bool HandleError(ActionBase action) { if (null == m_actionError) { m_actionError = action; } m_variables.UpdateSystem("$ERROR", "True"); int tmpInstPtr = m_IP; ++tmpInstPtr; if (tmpInstPtr < script.Actions.Count) // peek ahead one instruction is it a if statement? { ActionBase actTmp = m_script.GetAction(tmpInstPtr);; if (actTmp is Actionif) { Actionif actIF = (Actionif)actTmp; Debug.Assert(null != actIF); if (actIF.Params[1] == "$ERROR" || actIF.Params[3] == "$ERROR") { return(true); // error is handled (do not let the playback to be stopped) } } } // unhandled error... if (!m_bErrorIsHandled && m_listOnError.Count > 0) { m_bErrorIsHandled = true; int pos = m_script.Actions.IndexOf(action) + 1; foreach (string funcName in m_listOnError) { if (m_FnNameStack.Count > 0) { string fn = m_FnNameStack.Peek(); if (fn == funcName) // do not insert calls inside our function { continue; } } Actioncall call = new Actioncall(); call.FunctionName = funcName; m_script.Actions.Insert(pos, call); ++pos; } ActionError err = new ActionError(); m_script.Actions.Insert(pos, err); return(true); // show must go on } else { m_Status = VMStatus.ERROR; return(false); // we stop the playback } }
public void Run() { m_ScreenshotCounter = 0; SaveScreenshotOnPlaybackBegin(); ActionBase action = null; int ip = 0; m_host.WriteLog("<steps>"); while (VMStatus.IN_PLAYBACK == m_Status) { ip = m_IP; action = m_script.GetAction(m_IP); Step(action); if (action is ActionFlow) // if, for, next, loop, foreach, return, function, call, expression, else, label, goto, endif etc. { StepFlow(action); } switch (action.Result) { case EnumActionResult.OK: m_variables.UpdateSystem("$ERROR", "False"); break; case EnumActionResult.ERROR: case EnumActionResult.TIMEOUT: case EnumActionResult.TEST_FAILED: { if (!HandleError(action)) // unhandled error will result is playback stop { SaveScreenshotOnPlaybackEnd(); return; } } break; case EnumActionResult.STOPPED: m_Status = VMStatus.STOPPED; SaveScreenshotOnPlaybackEnd(); return; } if (VMStatus.QUIT == m_Status) { HandleQuit(action); } if (ip == m_IP) // the IP is not set artifically (by a flow command) { ++m_IP; // go to the next command } if (IsFinished()) { SaveScreenshotOnPlaybackEnd(); return; } else { UtilSys.Wait(m_iSpeed); } } SaveScreenshotOnPlaybackEnd(); }
public bool Init() { m_Status = VMStatus.INITIALIZATION; string path = Path.Combine(host.StartupPath, @"data\log\" + Path.GetFileNameWithoutExtension(m_script.Path) + ".log"); host.SetLogFile(path, host.BigBrother); m_variables = new VariableManager(this, m_script); StringBuilder sb = new StringBuilder(); sb.Append("<Playback "); string[,] attributes = { { "script=", m_script.Path }, { "On=", UtilSys.GetDateTime() }, { "Autorun=", host.IsAutorun.ToString() }, }; for (int i = 0; i < attributes.GetLength(0); ++i) { sb.Append(" " + attributes[i, 0] + "\"" + attributes[i, 1] + "\""); } sb.Append(">"); string msg = sb.ToString(); host.WriteLog(msg); m_dtStartTime = DateTime.Now; m_actionError = null; // register events are using this m_bErrorIsHandled = false; m_bQuitIsHandled = false; m_utree = null; m_grid = null; m_dicControls.Clear(); m_dicCache.Clear(); m_dicGotoCounts.Clear(); m_InstrStack.Clear(); m_CallStack.Clear(); m_IfStack.Clear(); m_LoopStack.Clear(); // this stack is used by instructions like for, while, foreach m_FnNameStack.Clear(); m_ErrStack.Clear(); m_listAfterEachCommand.Clear(); m_listAfterCommands.Clear(); m_listOnError.Clear(); m_listOnQuit.Clear(); host.ReleaseSQLStuff(); m_FnNameStack.Push(VariableManager._GlobalScopeName); m_variables.Reset(); m_variables.AddSystem("$ERROR", "False"); m_variables.AddSystem("sys.speed", Speed.ToString()); m_variables.AddSystem("sys.SaveScreenshotOnError", m_bSaveScreenshotOnError.ToString()); m_variables.AddSystem("env.ScreenWidht", Screen.PrimaryScreen.Bounds.Width.ToString()); m_variables.AddSystem("env.ScreenHeight", Screen.PrimaryScreen.Bounds.Height.ToString()); foreach (KeyValuePair <string, string> kv in m_script.Scopes[0].Variables) { m_variables.Add(kv.Key, kv.Value); } foreach (KeyValuePair <string, string> kv in m_script.Scopes[0].Consts) { m_variables.AddConst(kv.Key, kv.Value); } foreach (KeyValuePair <string, string> kv in Data.Vars) { m_variables.AddExternal(kv.Key, kv.Value); } m_IP = m_script.EntryPoint; if (-1 == m_IP) { m_ErrStack.Push("No entry point in script.\r\nEdit script file and enter the [sys.start] command from which point you want playback to begin."); return(false); } m_Status = VMStatus.IN_PLAYBACK; return(true); }