Skip to content

Commit 1ad9406

Browse files
authored
Merge pull request #1492 from wapm-packages/wasi
WASI integration
2 parents ad8a182 + 32123b5 commit 1ad9406

6 files changed

Lines changed: 125 additions & 3 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ tests/snippets/resources
1414
flame-graph.html
1515
flame.txt
1616
flamescope.json
17+
/wapm.lock
18+
/wapm_packages

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ num-traits = "0.2.8"
3232
flame = { version = "0.2", optional = true }
3333
flamescope = { version = "0.1", optional = true }
3434

35+
[target.'cfg(not(target_os = "wasi"))'.dependencies]
3536
rustyline = "=5.0.1"
3637

3738

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ Or use the interactive shell:
3434
>>>>> 2+2
3535
4
3636

37+
### WASI
38+
39+
You can compile RustPython to a standalone WebAssembly WASI module so it can run anywhere.
40+
41+
```shell
42+
$ wapm install rustpython
43+
$ wapm run rustpython
44+
>>>>> 2+2
45+
4
46+
```
47+
48+
#### Building the WASI file
49+
50+
You can build the WebAssembly WASI file with:
51+
52+
```
53+
cargo build --release --target wasm32-wasi --features="freeze-stdlib"
54+
```
55+
56+
> Note: we use the `freeze-stdlib` to include the standard libarary inside the binary.
57+
3758
## Disclaimer
3859

3960
RustPython is in a development phase and should not be used in production or a

src/main.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,8 @@ fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>>
321321
}
322322

323323
fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> {
324-
import::init_importlib(&vm, true)?;
324+
// We only include the standard library bytecode in WASI
325+
import::init_importlib(&vm, cfg!(not(target_os = "wasi")))?;
325326

326327
if let Some(paths) = option_env!("BUILDTIME_RUSTPYTHONPATH") {
327328
let sys_path = vm.get_attribute(vm.sys_module.clone(), "path")?;
@@ -486,6 +487,7 @@ fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResul
486487
}
487488
}
488489

490+
#[cfg(not(target_os = "wasi"))]
489491
fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
490492
use rustyline::{error::ReadlineError, Editor};
491493

@@ -596,3 +598,79 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
596598

597599
Ok(())
598600
}
601+
602+
#[cfg(target_os = "wasi")]
603+
fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
604+
use std::io::prelude::*;
605+
use std::io::{self, BufRead};
606+
607+
println!(
608+
"Welcome to the magnificent Rust Python {} interpreter \u{1f631} \u{1f596}",
609+
crate_version!()
610+
);
611+
612+
// Read a single line:
613+
let mut input = String::new();
614+
let mut continuing = false;
615+
616+
loop {
617+
let prompt_name = if continuing { "ps2" } else { "ps1" };
618+
let prompt = vm
619+
.get_attribute(vm.sys_module.clone(), prompt_name)
620+
.and_then(|prompt| vm.to_str(&prompt));
621+
let prompt = match prompt {
622+
Ok(ref s) => s.as_str(),
623+
Err(_) => "",
624+
};
625+
print!("{}", prompt);
626+
io::stdout().flush().ok().expect("Could not flush stdout");
627+
628+
let stdin = io::stdin();
629+
630+
let result = match stdin.lock().lines().next().unwrap() {
631+
Ok(line) => {
632+
debug!("You entered {:?}", line);
633+
let stop_continuing = line.is_empty();
634+
635+
if input.is_empty() {
636+
input = line;
637+
} else {
638+
input.push_str(&line);
639+
}
640+
input.push_str("\n");
641+
642+
if continuing {
643+
if stop_continuing {
644+
continuing = false;
645+
} else {
646+
continue;
647+
}
648+
}
649+
650+
match shell_exec(vm, &input, scope.clone()) {
651+
ShellExecResult::Ok => {
652+
input.clear();
653+
Ok(())
654+
}
655+
ShellExecResult::Continue => {
656+
continuing = true;
657+
Ok(())
658+
}
659+
ShellExecResult::PyErr(err) => {
660+
input.clear();
661+
Err(err)
662+
}
663+
}
664+
}
665+
Err(err) => {
666+
eprintln!("Readline error: {:?}", err);
667+
break;
668+
}
669+
};
670+
671+
if let Err(exc) = result {
672+
print_exception(vm, &exc);
673+
}
674+
}
675+
Ok(())
676+
}

vm/src/stdlib/time_module.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ fn duration_to_f64(d: Duration) -> f64 {
5656
(d.as_secs() as f64) + (f64::from(d.subsec_nanos()) / 1e9)
5757
}
5858

59-
#[cfg(not(target_arch = "wasm32"))]
59+
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
6060
fn time_time(_vm: &VirtualMachine) -> f64 {
6161
match SystemTime::now().duration_since(UNIX_EPOCH) {
6262
Ok(v) => duration_to_f64(v),
6363
Err(err) => panic!("Time error: {:?}", err),
6464
}
6565
}
6666

67-
#[cfg(target_arch = "wasm32")]
67+
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
6868
fn time_time(_vm: &VirtualMachine) -> f64 {
6969
use wasm_bindgen::prelude::*;
7070
#[wasm_bindgen]

wapm.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name="rustpython"
3+
version="0.0.4"
4+
description="A Python-3 (CPython >= 3.5.0) Interpreter written in Rust 🐍 😱 🤘"
5+
license-file="LICENSE"
6+
readme = "README.md"
7+
repository = "https://github.com/RustPython/RustPython"
8+
9+
[[module]]
10+
name="rustpython"
11+
source="target/wasm32-wasi/release/rustpython.wasm"
12+
abi = "wasi"
13+
interfaces = {wasi= "0.0.0-unstable"}
14+
15+
[[command]]
16+
name="rustpython"
17+
module="rustpython"
18+
19+
# [fs]
20+
# "Lib"="Lib"

0 commit comments

Comments
 (0)