NO_INLINE JsVar *jspeStatementDoOrWhile(bool isWhile) {
#ifdef JSPARSE_MAX_LOOP_ITERATIONS
  int loopCount = JSPARSE_MAX_LOOP_ITERATIONS;
#endif
  JsVar *cond;
  bool loopCond = true; // true for do...while loops
  bool hasHadBreak = false;
  JslCharPos whileCondStart;
  // We do repetition by pulling out the string representing our statement
  // there's definitely some opportunity for optimisation here
  JSP_ASSERT_MATCH(isWhile ? LEX_R_WHILE : LEX_R_DO);
  bool wasInLoop = (execInfo.execute&EXEC_IN_LOOP)!=0;
  if (isWhile) { // while loop
    JSP_MATCH('(');
    whileCondStart = jslCharPosClone(&lex->tokenStart);
    cond = jspeAssignmentExpression();
    loopCond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(cond));
    jsvUnLock(cond);
    JSP_MATCH_WITH_CLEANUP_AND_RETURN(')',jslCharPosFree(&whileCondStart);,0);
  }
  JslCharPos whileBodyStart = jslCharPosClone(&lex->tokenStart);
  JSP_SAVE_EXECUTE();
  // actually try and execute first bit of while loop (we'll do the rest in the actual loop later)
  if (!loopCond) jspSetNoExecute();
  execInfo.execute |= EXEC_IN_LOOP;
  jsvUnLock(jspeBlockOrStatement());
  if (!wasInLoop) execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP;

  if (execInfo.execute & EXEC_CONTINUE)
    execInfo.execute = (execInfo.execute & ~EXEC_RUN_MASK) | EXEC_YES;
  else if (execInfo.execute & EXEC_BREAK) {
    execInfo.execute = (execInfo.execute & ~EXEC_RUN_MASK) | EXEC_YES;
    hasHadBreak = true; // fail loop condition, so we exit
  }
  if (!loopCond) JSP_RESTORE_EXECUTE();

  if (!isWhile) { // do..while loop
    JSP_MATCH_WITH_CLEANUP_AND_RETURN(LEX_R_WHILE,jslCharPosFree(&whileBodyStart);,0);
    JSP_MATCH_WITH_CLEANUP_AND_RETURN('(',jslCharPosFree(&whileBodyStart);if (isWhile)jslCharPosFree(&whileCondStart);,0);
    whileCondStart = jslCharPosClone(&lex->tokenStart);
    cond = jspeAssignmentExpression();
    loopCond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(cond));
    jsvUnLock(cond);
    JSP_MATCH_WITH_CLEANUP_AND_RETURN(')',jslCharPosFree(&whileBodyStart);jslCharPosFree(&whileCondStart);,0);
  }

  JslCharPos whileBodyEnd;
  whileBodyEnd = jslCharPosClone(&lex->tokenStart);

  while (!hasHadBreak && loopCond
#ifdef JSPARSE_MAX_LOOP_ITERATIONS
      && loopCount-->0
#endif
  ) {
    jslSeekToP(&whileCondStart);
    cond = jspeAssignmentExpression();
    loopCond = JSP_SHOULD_EXECUTE && jsvGetBoolAndUnLock(jsvSkipName(cond));
    jsvUnLock(cond);
    if (loopCond) {
      jslSeekToP(&whileBodyStart);
      execInfo.execute |= EXEC_IN_LOOP;
      jspDebuggerLoopIfCtrlC();
      jsvUnLock(jspeBlockOrStatement());
      if (!wasInLoop) execInfo.execute &= (JsExecFlags)~EXEC_IN_LOOP;
      if (execInfo.execute & EXEC_CONTINUE)
        execInfo.execute = (execInfo.execute & ~EXEC_RUN_MASK) | EXEC_YES;
      else if (execInfo.execute & EXEC_BREAK) {
        execInfo.execute = (execInfo.execute & ~EXEC_RUN_MASK) | EXEC_YES;
        hasHadBreak = true;
      }
    }
  }
  jslSeekToP(&whileBodyEnd);
  jslCharPosFree(&whileCondStart);
  jslCharPosFree(&whileBodyStart);
  jslCharPosFree(&whileBodyEnd);
#ifdef JSPARSE_MAX_LOOP_ITERATIONS
  if (loopCount<=0) {
    jsExceptionHere(JSET_ERROR, "WHILE Loop exceeded the maximum number of iterations (" STRINGIFY(JSPARSE_MAX_LOOP_ITERATIONS) ")");
  }
#endif
  return 0;
}