Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ name = "vm"
[features]
default = ["runtime", "cli", "cranelift-jit"]
runtime = []
http-client = ["dep:reqwest", "dep:url", "dep:tokio", "dep:futures-util"]
http-client = ["runtime", "dep:reqwest", "dep:url", "dep:tokio", "dep:futures-util"]
sqlite = ["runtime", "dep:rusqlite"]
edge-abi = [
"dep:edge_abi",
"edge_abi/console",
Expand Down Expand Up @@ -62,9 +63,10 @@ cranelift-module = { version = "0.129.1", optional = true }
cranelift-native = { version = "0.129.1", optional = true }
pd-host-function = { path = "./pd-host-function", version = "0.1.0" }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "stream"], optional = true }
rusqlite = { version = "0.32", default-features = false, features = ["bundled", "hooks", "limits"], optional = true }
url = { version = "2", optional = true }
futures-util = { version = "0.3", optional = true }
tokio = { version = "1", features = ["rt", "net", "time"], optional = true }
tokio = { version = "1", features = ["rt-multi-thread", "net", "time", "sync"], optional = true }
edge_abi = { package = "pd-edge-abi", version = "0.1.1", default-features = false, optional = true }
futures-channel = "0.3"
paste = "1"
Expand All @@ -82,6 +84,7 @@ windows-sys = { version = "0.59", features = ["Win32_System_Diagnostics_Debug",
libc = "0.2"

[dev-dependencies]
futures-util = "0.3"
syn = { version = "2", features = ["full"] }
tokio = { version = "1", features = ["macros", "rt", "time", "sync"] }

Expand All @@ -93,7 +96,12 @@ required-features = ["cranelift-jit"]
[[test]]
name = "http_host_tests"
path = "tests/vm/http_host_tests.rs"
required-features = ["http-client"]
required-features = ["runtime", "http-client"]

[[test]]
name = "sqlite_host_tests"
path = "tests/vm/sqlite_host_tests.rs"
required-features = ["sqlite"]

[build-dependencies]
syn = { version = "2", features = ["full"] }
56 changes: 55 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ fn main() {
println!("cargo:rerun-if-changed={}", catalog_path.display());
let catalog = parse_catalog(&catalog_path);

let host_sources = [
let mut host_sources = vec![
SourceSpec {
path: "src/builtins/runtime/host.rs".to_string(),
module: "host".to_string(),
Expand All @@ -160,7 +160,19 @@ fn main() {
module: "http".to_string(),
category: SourceCategory::DefaultHost,
},
SourceSpec {
path: "src/builtins/runtime/context_host.rs".to_string(),
module: "context_host".to_string(),
category: SourceCategory::DefaultHost,
},
];
if env::var_os("CARGO_FEATURE_SQLITE").is_some() {
host_sources.push(SourceSpec {
path: "src/builtins/runtime/sqlite.rs".to_string(),
module: "sqlite".to_string(),
category: SourceCategory::DefaultHost,
});
}
let builtin_sources = builtin_source_specs(&namespaces);
let core_sources = [SourceSpec {
path: "src/builtins/runtime/core.rs".to_string(),
Expand Down Expand Up @@ -941,6 +953,7 @@ fn render_builtin_catalog(

writeln!(&mut out, "impl BuiltinFunction {{").unwrap();
render_builtin_name_method(&mut out, &builtin_variant_order, &actual_builtin_by_variant);
render_builtin_capability_method(&mut out, builtin_callables);
render_builtin_arity_method(&mut out, &builtin_variant_order, &actual_builtin_by_variant);
render_builtin_accepts_arity_method(
&mut out,
Expand Down Expand Up @@ -1082,6 +1095,12 @@ fn render_builtin_runtime_dispatch(
)
.unwrap();
}
writeln!(
&mut out,
" registry.mark_runtime_owned_pending({:?});",
callable.name
)
.unwrap();
}
writeln!(&mut out, "}}").unwrap();
writeln!(&mut out).unwrap();
Expand All @@ -1098,6 +1117,12 @@ fn render_builtin_runtime_dispatch(
.render_bind_static_call(&callable.name, &host_wrapper_adapter_name(callable));
writeln!(&mut out, " {:?} => {{", callable.name).unwrap();
writeln!(&mut out, " {bind_call}").unwrap();
writeln!(
&mut out,
" vm.mark_runtime_owned_pending_binding({:?});",
callable.name
)
.unwrap();
writeln!(&mut out, " true").unwrap();
writeln!(&mut out, " }}").unwrap();
}
Expand Down Expand Up @@ -1415,6 +1440,35 @@ fn render_builtin_name_method(
writeln!(out).unwrap();
}

fn render_builtin_capability_method(out: &mut String, builtin_callables: &[CallableDecl]) {
let mut capability_variants = Vec::new();
for callable in builtin_callables {
let variant = builtin_variant_name(&callable.name);
if !capability_variants.contains(&variant) {
capability_variants.push(variant);
}
}
capability_variants.sort();
writeln!(out, " #[cfg(feature = \"runtime\")]").unwrap();
writeln!(
out,
" pub(crate) const fn requires_explicit_host_capability(self) -> bool {{"
)
.unwrap();
if capability_variants.is_empty() {
writeln!(out, " false").unwrap();
} else {
let patterns = capability_variants
.iter()
.map(|variant| format!("BuiltinFunction::{variant}"))
.collect::<Vec<_>>()
.join(" | ");
writeln!(out, " matches!(self, {patterns})").unwrap();
}
writeln!(out, " }}").unwrap();
writeln!(out).unwrap();
}

fn render_builtin_arity_method(
out: &mut String,
builtin_variant_order: &[String],
Expand Down
4 changes: 3 additions & 1 deletion crates/rustscript/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ runtime = ["pd_vm_crate/runtime"]
edge-abi = ["pd_vm_crate/edge-abi"]
cli = ["pd_vm_crate/cli"]
cranelift-jit = ["pd_vm_crate/cranelift-jit"]
http-client = ["runtime", "pd_vm_crate/http-client"]
sqlite = ["pd_vm_crate/sqlite"]

[dependencies]
pd_vm_crate = { package = "pd-vm", path = "../..", version = ">=0.1.0, <1.0.0" }
pd_vm_crate = { package = "pd-vm", path = "../..", version = "=0.1.0", default-features = false }
35 changes: 35 additions & 0 deletions crates/rustscript/tests/alias_smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,38 @@ fn alias_exports_op_code() {
let _ = rustscript::OpCode::Nop;
let _ = rustscript::OpCode::Add;
}

#[cfg(feature = "runtime")]
#[test]
fn alias_exports_public_runtime_event_contract() {
fn accept_sink<S: rustscript::EventSink>(_sink: S) {}

struct Sink;
impl rustscript::EventSink for Sink {
fn emit(&mut self, _payload: rustscript::EventPayload) -> rustscript::RuntimeResult<()> {
Ok(())
}
}

accept_sink(Sink);
}

#[cfg(feature = "http-client")]
#[test]
fn alias_http_client_includes_runtime_contract() {
fn accept_runtime_result(_result: rustscript::RuntimeResult<()>) {}

accept_runtime_result(Ok(()));
}

#[cfg(feature = "sqlite")]
#[test]
fn alias_exports_public_sqlite_configuration() {
let program = rustscript::compile_source("0;")
.expect("minimal alias SQLite program should compile")
.program;
let mut vm = rustscript::Vm::new(program);
vm.configure_sqlite(rustscript::SqlitePolicy::default());
let _limits = rustscript::SqliteLimits::default();
vm.clear_sqlite_configuration();
}
2 changes: 1 addition & 1 deletion docs/callable-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RustScript bytecode format version 11 (VMBC v11) introduces runtime script call
- callable environments are bound through the internal builtin call path; callable creation adds no bytecode opcode.
- `ret` completes the active script frame. A nested frame leaves exactly one result at the caller segment base, using `null` when the body produced no value. Root `ret` keeps the historical program-result stack behavior.

VMBC v11 is a hard format boundary. Decoders reject all earlier versions (v10 and below) with a deterministic unsupported-version error; there is no compatibility decoder and no old-ID alias. The stream includes script-function entry ranges, callable prototypes, function regions, root callable bindings, and call indices drawn from the static builtin catalog. PDRC v6 recordings and AOT artifacts (format 7, ABI 6) use their corresponding bumped versions and include callable metadata in cache identity.
VMBC v11 is a hard format boundary. Decoders reject all earlier versions (v10 and below) with a deterministic unsupported-version error; there is no compatibility decoder and no old-ID alias. The stream includes script-function entry ranges, callable prototypes, function regions, root callable bindings, and call indices drawn from the static builtin catalog. PDRC v6 recordings and AOT artifacts (format 7, ABI 7) use their corresponding bumped versions and include callable metadata in cache identity.

## Static builtin IDs

Expand Down
Loading
Loading