Skip to content
Closed
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
18 changes: 18 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion crates/octoscript-capabilities/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ workspace = true
blake3 = { version = "1.8.5", features = ["pure"] }
getrandom = { version = "0.3.4", features = ["wasm_js"] }
keyring = { version = "3.6.3", default-features = false, features = ["apple-native", "windows-native"], optional = true }
makepad-script = { path = "../../vendor/makepad/platform/script" }
makepad-script = { git = "https://github.com/OctoSense-org/makepad.git", rev = "a4347332b38d0d511287006dc19f0c079604f78a" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.150"
octoscript-core = { path = "../octoscript-core" }
Expand Down
100 changes: 56 additions & 44 deletions crates/octoscript-capabilities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use std::time::{Duration, Instant};

use makepad_script::{
id, id_lut, script_args_def, script_err_not_allowed, script_err_unexpected, script_value,
LiveId, ScriptHandle, ScriptHandleGc, ScriptHandleType, ScriptIp, ScriptThreadId, ScriptValue,
NIL,
LiveId, ScriptHandle, ScriptHandleGc, ScriptHandleType, ScriptIp, ScriptStringSink,
ScriptThreadId, ScriptValue, NIL,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub use serde_json::{json, Value as JsonValue};
Expand Down Expand Up @@ -5793,7 +5793,7 @@ fn install_capability_module(
)
}
};
let output = match vm.host.downcast_mut::<CapabilityHost>() {
let output = match vm.host.as_any_mut().downcast_mut::<CapabilityHost>() {
Some(host) => host.call_json(&tool, &input),
None => {
return script_err_unexpected!(
Expand Down Expand Up @@ -5841,7 +5841,7 @@ fn install_capability_module(
)
}
};
let result = match vm.host.downcast_mut::<CapabilityHost>() {
let result = match vm.host.as_any_mut().downcast_mut::<CapabilityHost>() {
Some(host) => host.begin_async_json(&tool, &input, max_pending_tools),
None => {
return script_err_unexpected!(
Expand Down Expand Up @@ -5904,7 +5904,7 @@ fn install_tool_module(runtime: &mut Runtime<CapabilityHost, ()>, max_pending_to
)
}
};
let pending = match vm.host.downcast_ref::<CapabilityHost>() {
let pending = match vm.host.as_any().downcast_ref::<CapabilityHost>() {
Some(host) => host.pending(),
None => {
return script_err_unexpected!(
Expand Down Expand Up @@ -5951,7 +5951,9 @@ fn install_tool_module(runtime: &mut Runtime<CapabilityHost, ()>, max_pending_to
match ready {
Some(Ok(output)) => match promise_output {
ToolPromiseOutput::Text => {
vm.new_string_with(|_, destination| destination.push_str(&output))
vm.bx.heap.new_bounded_string_with(|_, destination| {
destination.append_str(&output)
})
}
ToolPromiseOutput::DecodedJson {
max_output_bytes,
Expand Down Expand Up @@ -5985,22 +5987,25 @@ fn install_tool_module(runtime: &mut Runtime<CapabilityHost, ()>, max_pending_to
let name = script_text(vm, script_value!(vm, args.name));
let input = script_text(vm, script_value!(vm, args.input));
let result = match (name, input) {
(Ok(name), Ok(input)) => match vm.host.downcast_mut::<CapabilityHost>() {
Some(host) => host.call(&name, &input),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
(Ok(name), Ok(input)) => {
match vm.host.as_any_mut().downcast_mut::<CapabilityHost>() {
Some(host) => host.call(&name, &input),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
}
}
},
}
(Err(error), _) | (_, Err(error)) => Err(error),
};

match result {
Ok(output) => {
vm.new_string_with(|_, destination| destination.push_str(&output))
}
Ok(output) => vm
.bx
.heap
.new_bounded_string_with(|_, destination| destination.append_str(&output)),
Err(error) => {
script_err_not_allowed!(vm.bx.threads.cur_ref().trap, "{}", error)
}
Expand All @@ -6016,22 +6021,25 @@ fn install_tool_module(runtime: &mut Runtime<CapabilityHost, ()>, max_pending_to
let name = script_text(vm, script_value!(vm, args.name));
let input = script_json(vm, script_value!(vm, args.input));
let result = match (name, input) {
(Ok(name), Ok(input)) => match vm.host.downcast_mut::<CapabilityHost>() {
Some(host) => host.call_json(&name, &input),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
(Ok(name), Ok(input)) => {
match vm.host.as_any_mut().downcast_mut::<CapabilityHost>() {
Some(host) => host.call_json(&name, &input),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
}
}
},
}
(Err(error), _) | (_, Err(error)) => Err(error),
};

match result {
Ok(output) => {
vm.new_string_with(|_, destination| destination.push_str(&output))
}
Ok(output) => vm
.bx
.heap
.new_bounded_string_with(|_, destination| destination.append_str(&output)),
Err(error) => {
script_err_not_allowed!(vm.bx.threads.cur_ref().trap, "{}", error)
}
Expand All @@ -6047,15 +6055,17 @@ fn install_tool_module(runtime: &mut Runtime<CapabilityHost, ()>, max_pending_to
let name = script_text(vm, script_value!(vm, args.name));
let input = script_text(vm, script_value!(vm, args.input));
let result = match (name, input) {
(Ok(name), Ok(input)) => match vm.host.downcast_mut::<CapabilityHost>() {
Some(host) => host.begin_async(&name, &input, max_pending_tools),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
(Ok(name), Ok(input)) => {
match vm.host.as_any_mut().downcast_mut::<CapabilityHost>() {
Some(host) => host.begin_async(&name, &input, max_pending_tools),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
}
}
},
}
(Err(error), _) | (_, Err(error)) => Err(error),
};

Expand Down Expand Up @@ -6084,15 +6094,17 @@ fn install_tool_module(runtime: &mut Runtime<CapabilityHost, ()>, max_pending_to
let name = script_text(vm, script_value!(vm, args.name));
let input = script_json(vm, script_value!(vm, args.input));
let result = match (name, input) {
(Ok(name), Ok(input)) => match vm.host.downcast_mut::<CapabilityHost>() {
Some(host) => host.begin_async_json(&name, &input, max_pending_tools),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
(Ok(name), Ok(input)) => {
match vm.host.as_any_mut().downcast_mut::<CapabilityHost>() {
Some(host) => host.begin_async_json(&name, &input, max_pending_tools),
None => {
return script_err_unexpected!(
vm.bx.threads.cur_ref().trap,
"invalid Octoscript capability host"
)
}
}
},
}
(Err(error), _) | (_, Err(error)) => Err(error),
};

Expand Down
2 changes: 1 addition & 1 deletion crates/octoscript-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ workspace = true

[dependencies]
octoscript-ui-l0 = { path = "../octoscript-ui-l0" }
makepad-script = { path = "../../vendor/makepad/platform/script" }
makepad-script = { git = "https://github.com/OctoSense-org/makepad.git", rev = "a4347332b38d0d511287006dc19f0c079604f78a" }
serde_json = "1.0.150"
29 changes: 15 additions & 14 deletions crates/octoscript-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,7 @@ impl Evaluation {
/// install native bindings through [`Runtime::configure`]; scripts only see
/// the bindings that configuration creates.
pub struct Runtime<H: Any = (), S: Any = ()> {
host: H,
std: S,
host: vm::ScriptVmHost<H, S>,
vm: Box<vm::ScriptVmBase>,
limits: ExecutionLimits,
json_method_limits: Rc<Cell<ScriptJsonMethodLimits>>,
Expand All @@ -818,8 +817,7 @@ impl<H: Any, S: Any> Runtime<H, S> {
)));
let installed_limits = json_method_limits.clone();
let mut runtime = Self {
host,
std,
host: vm::ScriptVmHost::new(host, std),
vm: Box::new(vm::ScriptVmBase::new()),
limits,
json_method_limits,
Expand Down Expand Up @@ -894,11 +892,11 @@ impl<H: Any, S: Any> Runtime<H, S> {
}

pub fn host(&self) -> &H {
&self.host
&self.host.host
}

pub fn host_mut(&mut self) -> &mut H {
&mut self.host
&mut self.host.host
}

/// Installs trusted native bindings. The standalone `std` module is frozen,
Expand Down Expand Up @@ -1215,7 +1213,6 @@ impl<H: Any, S: Any> Runtime<H, S> {
let previous_vm = std::mem::replace(&mut self.vm, Box::new(vm::ScriptVmBase::new()));
let mut vm = vm::ScriptVm {
host: &mut self.host,
std: &mut self.std,
bx: previous_vm,
};
let result = operation(&mut vm);
Expand Down Expand Up @@ -5499,13 +5496,15 @@ mod tests {

#[test]
fn canonical_newline_boundaries_are_lowered_for_vm_compatibility() {
// The inherited tokenizer sees the newline as whitespace and would
// otherwise parse `(42)` as a call on the imported module field.
// The ported VM (upstream makepad #1139) treats a `(` on a new line as
// the start of a new statement, so the inherited tokenizer no longer
// parses `(42)` as a call on the imported module field. Both the
// compatibility preflight and canonical lowering now agree.
let source = "use mod.std.a\n(42)\n";
let compatibility = check_vm_compatibility(source).unwrap();
let canonical = check_syntax(source).unwrap();

assert!(!compatibility.valid);
assert!(compatibility.valid, "{:?}", compatibility.diagnostics);
assert!(canonical.valid, "{:?}", canonical.diagnostics);
}

Expand Down Expand Up @@ -7720,10 +7719,12 @@ compute(outer, 2)
.iter()
.any(|diagnostic| diagnostic.contains("heap allocation limit")));

assert!(matches!(
runtime.eval("2"),
Err(RuntimeError::HeapLimitExceeded { maximum, .. }) if maximum == limits.max_heap_bytes
));
// The ported heap preflights the charge and never allocates the
// over-limit string, so the runtime is not left above its cap after
// the failure: the next evaluation runs, and stays within the limit.
let next = runtime.eval("2").unwrap();
assert!(next.completed(), "{:?}", next.diagnostics);
assert!(runtime.accounted_heap_bytes() <= limits.max_heap_bytes);
}

#[test]
Expand Down
Loading