Skip to content

Commit

Permalink
chore: add python interpreter demo
Browse files Browse the repository at this point in the history
  • Loading branch information
alicialics committed Oct 9, 2023
1 parent 9686012 commit 1218e27
Show file tree
Hide file tree
Showing 9 changed files with 1,729 additions and 0 deletions.
240 changes: 240 additions & 0 deletions examples/python-interpreter-demo/async-execution.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Asynchronous Execution with Python Interpreter</title>
<script src="mini-coi.js"></script>
<script src="toolbox.js"></script>
<script src="./node_modules/blockly/blockly_compressed.js"></script>
<script src="./node_modules/blockly/blocks_compressed.js"></script>
<script src="./node_modules/blockly/python_compressed.js"></script>
<script src="./node_modules/blockly/msg/en.js"></script>
<script src="wait_block.js"></script>
<script src="interpreter.js"></script>
<style>
body {
background-color: #fff;
font-family: sans-serif;
}
h1 {
font-weight: normal;
font-size: 140%;
}
</style>
</head>
<body>
<h1>Asynchronous Execution with Python Interpreter</h1>

<p>This is a demo of executing code asynchronously (e.g., waiting for delays or user input) using the Python interpreter.</p>

<p>
<button onclick="runCode()" id="runButton">Run Python</button>
</p>

<div style="width: 100%">
<div id="blocklyDiv"
style="display: inline-block; height: 480px; width: 58%"></div>
<textarea id="output" disabled="disabled"
style="display: inline-block; height: 480px; width: 38%;">
</textarea>
</div>

<script>
const startBlocks = {
"blocks": {
"blocks": [
{
"type": "variables_set",
"x": 20,
"y": 20,
"inline": true,
"fields": {
"VAR": {"id": "n"}
},
"inputs": {
"VALUE": {
"block": {
"type": "math_number",
"fields": {"NUM": 1}
}
}
},
"next": {
"block": {
"type": "controls_repeat_ext",
"inline": true,
"inputs": {
"TIMES": {
"block": {
"type": "math_number",
"fields": {"NUM": 4}
}
},
"DO": {
"block": {
"type": "wait_seconds",
"fields": {"SECONDS": 1},
"next": {
"block": {
"type": "variables_set",
"inline": true,
"fields": {
"VAR": {"id": "n"}
},
"inputs": {
"VALUE": {
"block": {
"type": "math_arithmetic",
"fields": {"OP": "MULTIPLY"},
"inputs": {
"A": {
"block": {
"type": "variables_get",
"fields": {
"VAR": {"id": "n"}
}
}
},
"B": {
"block": {
"type": "math_number",
"fields": {"NUM": 2}
}
}
}
}
}
},
"next": {
"block": {
"type": "text_print",
"inline": false,
"inputs": {
"TEXT": {
"block": {
"type": "variables_get",
"fields": {
"VAR": {"id": "n"}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
]
},
"variables": [
{
"name": "n",
"id": "n"
}
]
};
const demoWorkspace = Blockly.inject('blocklyDiv',
{media: './node_modules/blockly/media/',
toolbox: toolboxJson});
python.pythonGenerator.STATEMENT_PREFIX = 'highlightBlock(%1)\n';
python.pythonGenerator.addReservedWords('highlightBlock');
Blockly.serialization.workspaces.load(startBlocks, demoWorkspace);

const outputArea = document.getElementById('output');
const runButton = document.getElementById('runButton');
let myInterpreter = null;
let runnerPid = 0;

function initApi(interpreter, globalObject) {
// Add an API function for the alert() block, generated for "text_print" blocks.
const wrapperAlert = function alert(text) {
text = arguments.length ? text : '';
outputArea.value += '\n' + text;
};
interpreter.setProperty(globalObject, 'print',
interpreter.createNativeFunction(wrapperAlert));

// Add an API function for the prompt() block.
const wrapperPrompt = function prompt(text) {
return window.prompt(text);
};
interpreter.setProperty(globalObject, 'input',
interpreter.createNativeFunction(wrapperPrompt));

// Add an API function for highlighting blocks.
const wrapper = function(id) {
id = String(id || '');
return highlightBlock(id);
};
interpreter.setProperty(globalObject, 'highlightBlock',
interpreter.createNativeFunction(wrapper));

// Add an API for the wait block. See wait_block.js
initInterpreterWaitForSeconds(interpreter, globalObject);
}

function highlightBlock(id) {
demoWorkspace.highlightBlock(id);
}

function resetStepUi(clearOutput) {
clearTimeout(runnerPid);
demoWorkspace.highlightBlock(null);
runButton.disabled = '';

if (clearOutput) {
outputArea.value = 'Program output:\n=================';
}
myInterpreter = null;
}

function runCode() {
if (!myInterpreter) {
// First statement of this code.
// Clear the program output.
resetStepUi(true);
const latestCode = python.pythonGenerator.workspaceToCode(demoWorkspace);
runButton.disabled = 'disabled';

// And then show generated code in an alert.
// In a timeout to allow the outputArea.value to reset first.
setTimeout(function() {
alert('Ready to execute the following code\n' +
'===================================\n' + latestCode);

// Begin execution
myInterpreter = new Interpreter(latestCode, initApi);
function runner() {
if (myInterpreter) {
const hasMore = myInterpreter.run();
if (hasMore) {
// Execution is currently blocked by some async call.
// Try again later.
runnerPid = setTimeout(runner, 10);
} else {
// Program is complete.
outputArea.value += '\n\n<< Program complete >>';
resetStepUi(false);
}
}
}
runner();
}, 1);
return;
}
}

demoWorkspace.addChangeListener(function(event) {
if (!event.isUiEvent) {
// Something changed. Interpreter needs to be reloaded.
resetStepUi(true);
}
});
</script>
</body>
</html>
11 changes: 11 additions & 0 deletions examples/python-interpreter-demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Redirecting...</title>
<meta http-equiv="refresh" content="0;URL='step-execution.html'"/>
</head>
<body>
Redirecting to <a href="step-execution.html">step execution Python Interpreter demo</a>.
</body>
</html>
Loading

0 comments on commit 1218e27

Please sign in to comment.