skulpt with timeout

by sc549

HTML

<script src="https://cdn.jsdelivr.net/gh/skulpt/skulpt-dist/skulpt.js"></script>
<script src="https://cdn.jsdelivr.net/gh/skulpt/skulpt-dist/skulpt-stdlib.js"></script>

<textarea id="code" rows="24" cols="80">
from time import sleep
print('Ready')
sleep(.5)
print('Set')
sleep(.2)
i = 0
while True:
    sleep(.2)
    print(i, end=", ")
    i += 1
</textarea><br>
<button id="run" onclick="runit()" type="button">Run</button>
<button onclick="stopit()" type="button">Stop</button>
<pre id="output"></pre>

CSS

#code {
  max-height: 50vh;
  max-width: 60vw;
}

JavaScript

var StopExecution = false;

function outf(text) {
  const output = document.getElementById("output");
  text = text.replace(/</g, "&lt;");
  output.innerHTML += text;
}

function stopit() {
  StopExecution = true;
}


Sk.configure({
  output: outf,
  // here are some other related configurations for limits
  // yieldLimit: 100,
  // execLimit: 5000,
  // timeoutMsg: "your program timed out"
  killableWhile: true,
  // killableFor: true,


  inputTakesPrompt: true,
  // you can customise the input function - this can return a promise - the default is just to use window.prompt
  inputfun(args) {
    return new Promise((resolve, reject) => {
      setTimeout(function() {
        resolve(window.prompt(args))
      }, 250)
    })
  },
  __future__: Sk.python3
});


function runit() {
  StopExecution = false;
  const prog = document.getElementById("code").value;
  const output = document.getElementById("output");
  const run = document.getElementById("run");
  output.innerHTML = "";
  run.disabled = true;

  Sk.misceval.asyncToPromise(() =>
    Sk.importMainWithBody("<stdin>", false, prog, true), {
      // handle a suspension of the executing code
      // "*" says handle all types of suspensions
      "*": () => {
        if (StopExecution) throw "Execution interrupted"
      }
    },
  ).catch(err => {
    outf("\n" + err.toString());
  }).finally(() => {
    run.disabled = false;
  })
}