mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Upgrade wasm deps + fix demo
This commit is contained in:
22
Lib/_dummy_os.py
vendored
22
Lib/_dummy_os.py
vendored
@@ -5,22 +5,30 @@ A shim of the os module containing only simple path-related utilities
|
||||
try:
|
||||
from os import *
|
||||
except ImportError:
|
||||
import abc
|
||||
import abc, sys
|
||||
|
||||
def __getattr__(name):
|
||||
raise OSError("no os specific module found")
|
||||
if name in {"_path_normpath", "__path__"}:
|
||||
raise AttributeError(name)
|
||||
if name.isupper():
|
||||
return 0
|
||||
def dummy(*args, **kwargs):
|
||||
import io
|
||||
return io.UnsupportedOperation(f"{name}: no os specific module found")
|
||||
dummy.__name__ = f"dummy_{name}"
|
||||
return dummy
|
||||
|
||||
def _shim():
|
||||
import _dummy_os, sys
|
||||
sys.modules['os'] = _dummy_os
|
||||
sys.modules['os.path'] = _dummy_os.path
|
||||
sys.modules['os'] = sys.modules['posix'] = sys.modules[__name__]
|
||||
|
||||
import posixpath as path
|
||||
import sys
|
||||
sys.modules['os.path'] = path
|
||||
del sys
|
||||
|
||||
sep = path.sep
|
||||
supports_dir_fd = set()
|
||||
supports_effective_ids = set()
|
||||
supports_fd = set()
|
||||
supports_follow_symlinks = set()
|
||||
|
||||
|
||||
def fspath(path):
|
||||
|
||||
12
Lib/io.py
vendored
12
Lib/io.py
vendored
@@ -55,10 +55,15 @@ import _io
|
||||
import abc
|
||||
|
||||
from _io import (DEFAULT_BUFFER_SIZE, BlockingIOError, UnsupportedOperation,
|
||||
open, open_code, FileIO, BytesIO, StringIO, BufferedReader,
|
||||
open, open_code, BytesIO, StringIO, BufferedReader,
|
||||
BufferedWriter, BufferedRWPair, BufferedRandom,
|
||||
IncrementalNewlineDecoder, text_encoding, TextIOWrapper)
|
||||
|
||||
try:
|
||||
from _io import FileIO
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Pretend this exception was created here.
|
||||
UnsupportedOperation.__module__ = "io"
|
||||
|
||||
@@ -82,7 +87,10 @@ class BufferedIOBase(_io._BufferedIOBase, IOBase):
|
||||
class TextIOBase(_io._TextIOBase, IOBase):
|
||||
__doc__ = _io._TextIOBase.__doc__
|
||||
|
||||
RawIOBase.register(FileIO)
|
||||
try:
|
||||
RawIOBase.register(FileIO)
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
for klass in (BytesIO, BufferedReader, BufferedWriter, BufferedRandom,
|
||||
BufferedRWPair):
|
||||
|
||||
@@ -4,24 +4,25 @@
|
||||
"description": "Bindings to the RustPython library for WebAssembly",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"codemirror": "^5.42.0",
|
||||
"local-echo": "^0.2.0",
|
||||
"xterm": "^3.8.0"
|
||||
"@codemirror/lang-python": "^6.1.6",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.3.0",
|
||||
"codemirror": "^6.0.1",
|
||||
"upgrade": "^1.1.0",
|
||||
"xterm-readline": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wasm-tool/wasm-pack-plugin": "^1.1.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"css-loader": "^3.4.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"raw-loader": "^4.0.0",
|
||||
"serve": "^11.0.2",
|
||||
"webpack": "^4.16.3",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-dev-server": "^3.1.5"
|
||||
"@wasm-tool/wasm-pack-plugin": "^1.7.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"html-webpack-plugin": "^5.6.3",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"serve": "^14.2.4",
|
||||
"webpack": "^5.97.1",
|
||||
"webpack-cli": "^6.0.1",
|
||||
"webpack-dev-server": "^5.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server -d",
|
||||
"dev": "webpack serve",
|
||||
"build": "webpack",
|
||||
"dist": "webpack --mode production",
|
||||
"test": "webpack --mode production && cd ../tests && pytest"
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import asyncweb
|
||||
import whlimport
|
||||
|
||||
whlimport.setup()
|
||||
|
||||
# make sys.modules['os'] a dumb version of the os module, which has posixpath
|
||||
# available as os.path as well as a few other utilities, but will raise an
|
||||
# OSError for anything that actually requires an OS
|
||||
import _dummy_os
|
||||
_dummy_os._shim()
|
||||
|
||||
import asyncweb
|
||||
import whlimport
|
||||
|
||||
whlimport.setup()
|
||||
|
||||
@asyncweb.main
|
||||
async def main():
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
browser's devtools and play with <code>rp.pyEval('1 + 1')</code>
|
||||
</p>
|
||||
<div id="code-wrapper">
|
||||
<textarea id="code"><%= defaultSnippet %></textarea>
|
||||
<select id="snippets">
|
||||
<% for (const name of snippets) { %>
|
||||
<option
|
||||
@@ -77,7 +76,7 @@
|
||||
<a href="https://github.com/RustPython/RustPython">
|
||||
<img
|
||||
style="position: absolute; top: 0; right: 0; border: 0;"
|
||||
src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png"
|
||||
src="https://github.blog/wp-content/uploads/2008/12/forkme_right_green_007200.png"
|
||||
alt="Fork me on GitHub"
|
||||
/>
|
||||
</a>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import './style.css';
|
||||
import 'xterm/lib/xterm.css';
|
||||
import CodeMirror from 'codemirror';
|
||||
import 'codemirror/mode/python/python';
|
||||
import 'codemirror/addon/comment/comment';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
import { Terminal } from 'xterm';
|
||||
import LocalEchoController from 'local-echo';
|
||||
import '@xterm/xterm/css/xterm.css';
|
||||
import { EditorView, basicSetup } from 'codemirror';
|
||||
import { keymap } from '@codemirror/view';
|
||||
import { indentUnit } from '@codemirror/language';
|
||||
import { indentWithTab } from '@codemirror/commands';
|
||||
import { python } from '@codemirror/lang-python';
|
||||
import { Terminal } from '@xterm/xterm';
|
||||
import { FitAddon } from '@xterm/addon-fit';
|
||||
import { Readline } from 'xterm-readline';
|
||||
|
||||
let rp;
|
||||
|
||||
@@ -22,23 +24,24 @@ import('rustpython')
|
||||
document.getElementById('error').textContent = e;
|
||||
});
|
||||
|
||||
const editor = CodeMirror.fromTextArea(document.getElementById('code'), {
|
||||
extraKeys: {
|
||||
'Ctrl-Enter': runCodeFromTextarea,
|
||||
'Cmd-Enter': runCodeFromTextarea,
|
||||
'Shift-Tab': 'indentLess',
|
||||
'Ctrl-/': 'toggleComment',
|
||||
'Cmd-/': 'toggleComment',
|
||||
Tab: (editor) => {
|
||||
var spaces = Array(editor.getOption('indentUnit') + 1).join(' ');
|
||||
editor.replaceSelection(spaces);
|
||||
},
|
||||
},
|
||||
lineNumbers: true,
|
||||
mode: 'text/x-python',
|
||||
indentUnit: 4,
|
||||
autofocus: true,
|
||||
const fixedHeightEditor = EditorView.theme({
|
||||
'&': { height: '100%' },
|
||||
'.cm-scroller': { overflow: 'auto' },
|
||||
});
|
||||
const editor = new EditorView({
|
||||
parent: document.getElementById('code-wrapper'),
|
||||
extensions: [
|
||||
basicSetup,
|
||||
python(),
|
||||
keymap.of(
|
||||
{ key: 'Ctrl-Enter', mac: 'Cmd-Enter', run: runCodeFromTextarea },
|
||||
indentWithTab,
|
||||
),
|
||||
indentUnit.of(' '),
|
||||
fixedHeightEditor,
|
||||
],
|
||||
});
|
||||
editor.focus();
|
||||
|
||||
const consoleElement = document.getElementById('console');
|
||||
const errorElement = document.getElementById('error');
|
||||
@@ -48,7 +51,7 @@ function runCodeFromTextarea() {
|
||||
consoleElement.value = '';
|
||||
errorElement.textContent = '';
|
||||
|
||||
const code = editor.getValue();
|
||||
const code = editor.state.doc.toString();
|
||||
try {
|
||||
rp.pyExec(code, {
|
||||
stdout: (output) => {
|
||||
@@ -78,18 +81,25 @@ function updateSnippet() {
|
||||
// the require here creates a webpack context; it's fine to use it
|
||||
// dynamically.
|
||||
// https://webpack.js.org/guides/dependency-management/
|
||||
const { default: snippet } = require(
|
||||
`raw-loader!../snippets/${selected}.py`,
|
||||
);
|
||||
const snippet = require(`../snippets/${selected}.py?raw`);
|
||||
|
||||
editor.setValue(snippet);
|
||||
runCodeFromTextarea();
|
||||
editor.dispatch({
|
||||
changes: { from: 0, to: editor.state.doc.length, insert: snippet },
|
||||
});
|
||||
}
|
||||
function updateSnippetAndRun() {
|
||||
updateSnippet();
|
||||
requestAnimationFrame(runCodeFromTextarea);
|
||||
}
|
||||
updateSnippet();
|
||||
|
||||
const term = new Terminal();
|
||||
const readline = new Readline();
|
||||
const fitAddon = new FitAddon();
|
||||
term.loadAddon(readline);
|
||||
term.loadAddon(fitAddon);
|
||||
term.open(document.getElementById('terminal'));
|
||||
|
||||
const localEcho = new LocalEchoController(term);
|
||||
fitAddon.fit();
|
||||
|
||||
let terminalVM;
|
||||
|
||||
@@ -107,40 +117,33 @@ finally:
|
||||
}
|
||||
|
||||
async function readPrompts() {
|
||||
let continuing = false;
|
||||
let continuing = '';
|
||||
|
||||
while (true) {
|
||||
const ps1 = getPrompt('ps1');
|
||||
const ps2 = getPrompt('ps2');
|
||||
let input;
|
||||
let input = await readline.read(getPrompt(continuing ? 'ps2' : 'ps1'));
|
||||
if (input.endsWith('\n')) input = input.slice(0, -1);
|
||||
if (continuing) {
|
||||
const prom = localEcho.read(ps2, ps2);
|
||||
localEcho._activePrompt.prompt = ps1;
|
||||
localEcho._input = localEcho.history.entries.pop() + '\n';
|
||||
localEcho._cursor = localEcho._input.length;
|
||||
localEcho._active = true;
|
||||
input = await prom;
|
||||
if (!input.endsWith('\n')) continue;
|
||||
} else {
|
||||
input = await localEcho.read(ps1, ps2);
|
||||
input = continuing += '\n' + input;
|
||||
if (!continuing.endsWith('\n')) continue;
|
||||
}
|
||||
try {
|
||||
console.log([input]);
|
||||
terminalVM.execSingle(input);
|
||||
} catch (err) {
|
||||
if (err.canContinue) {
|
||||
continuing = true;
|
||||
continuing = input;
|
||||
continue;
|
||||
} else if (err instanceof WebAssembly.RuntimeError) {
|
||||
err = window.__RUSTPYTHON_ERROR || err;
|
||||
}
|
||||
localEcho.println(err);
|
||||
readline.print('' + err);
|
||||
}
|
||||
continuing = false;
|
||||
continuing = '';
|
||||
}
|
||||
}
|
||||
|
||||
function onReady() {
|
||||
snippets.addEventListener('change', updateSnippet);
|
||||
snippets.addEventListener('change', updateSnippetAndRun);
|
||||
document
|
||||
.getElementById('run-btn')
|
||||
.addEventListener('click', runCodeFromTextarea);
|
||||
@@ -148,7 +151,7 @@ function onReady() {
|
||||
runCodeFromTextarea();
|
||||
|
||||
terminalVM = rp.vmStore.init('term_vm');
|
||||
terminalVM.setStdout((data) => localEcho.print(data));
|
||||
terminalVM.setStdout((data) => readline.print(data));
|
||||
readPrompts().catch((err) => console.error(err));
|
||||
|
||||
// so that the test knows that we're ready
|
||||
|
||||
@@ -3,7 +3,7 @@ textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
#code,
|
||||
#code-wrapper,
|
||||
#console {
|
||||
height: 30vh;
|
||||
width: calc(100% - 3px);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const WasmPackPlugin = require('@wasm-tool/wasm-pack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
@@ -12,6 +11,7 @@ module.exports = (env = {}) => {
|
||||
output: {
|
||||
path: path.join(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
clean: true,
|
||||
},
|
||||
mode: 'development',
|
||||
resolve: {
|
||||
@@ -28,10 +28,17 @@ module.exports = (env = {}) => {
|
||||
test: /\.css$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||
},
|
||||
{
|
||||
resourceQuery: '?raw',
|
||||
type: 'asset/source',
|
||||
},
|
||||
{
|
||||
test: /\.wasm$/,
|
||||
type: 'webassembly/async',
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: 'src/index.ejs',
|
||||
@@ -51,6 +58,9 @@ module.exports = (env = {}) => {
|
||||
filename: 'styles.css',
|
||||
}),
|
||||
],
|
||||
experiments: {
|
||||
asyncWebAssembly: true,
|
||||
},
|
||||
};
|
||||
if (!env.noWasmPack) {
|
||||
config.plugins.push(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use crate::js_module;
|
||||
use crate::vm_class::{stored_vm_from_wasm, WASMVirtualMachine};
|
||||
use js_sys::{Array, ArrayBuffer, Object, Promise, Reflect, SyntaxError, Uint8Array};
|
||||
use rustpython_parser::ParseErrorType;
|
||||
use rustpython_parser::{lexer::LexicalErrorType, ParseErrorType};
|
||||
use rustpython_vm::{
|
||||
builtins::PyBaseExceptionRef,
|
||||
compiler::{CompileError, CompileErrorType},
|
||||
@@ -258,7 +258,15 @@ pub fn syntax_err(err: CompileError) -> SyntaxError {
|
||||
&"col".into(),
|
||||
&(err.location.unwrap().column.get()).into(),
|
||||
);
|
||||
let can_continue = matches!(&err.error, CompileErrorType::Parse(ParseErrorType::Eof));
|
||||
let can_continue = matches!(
|
||||
&err.error,
|
||||
CompileErrorType::Parse(
|
||||
ParseErrorType::Eof
|
||||
| ParseErrorType::Lexical(LexicalErrorType::Eof)
|
||||
| ParseErrorType::Lexical(LexicalErrorType::IndentationError)
|
||||
| ParseErrorType::UnrecognizedToken(rustpython_parser::Tok::Dedent, _)
|
||||
)
|
||||
);
|
||||
let _ = Reflect::set(&js_err, &"canContinue".into(), &can_continue.into());
|
||||
js_err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user