mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
Merge pull request #6 from storybored379/pr/expr-runtime-stack-leak
Expressions: keep the runtime usable after errors and property reads
This commit is contained in:
3 files changed
+30
-2
No files matched your search
@@ -34,6 +34,15 @@ function __begin(t, v, c, l, path, uid, idx, fd, ti, tt, sv) {
|
||||
}
|
||||
|
||||
function __finish(r) {
|
||||
// Rethrow from this frame so the runtime's stack unwinds (see `Runtime::script`).
|
||||
try {
|
||||
return __result(r);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function __result(r) {
|
||||
r = __v(r);
|
||||
if (r !== null && typeof r === 'object' && r.__isLayer) return r.index;
|
||||
if (r !== null && typeof r === 'object' && r.__isTextStyle) return r.__out();
|
||||
|
||||
@@ -238,8 +238,11 @@ impl Runtime {
|
||||
self.scripts.clear();
|
||||
}
|
||||
// A block keeps `let`/`const` local to one evaluation; `{` shares line 1 with the code so
|
||||
// error line numbers match the user's text.
|
||||
let src = format!("{{{}\n}}", crate::rewrite::rewrite(text));
|
||||
// error line numbers match the user's text. Errors are rethrown from the script's own
|
||||
// frame: boa leaves the stack of the inner frames behind when an exception leaves the
|
||||
// script from a nested call (every host request does), and the thread's runtime would
|
||||
// fail every expression with "reached the maximum stack size" after a few hundred.
|
||||
let src = format!("try{{{}\n}}catch(__e){{throw __e}}", crate::rewrite::rewrite(text));
|
||||
let s = Script::parse(Source::from_bytes(src.as_bytes()), None, &mut self.ctx).map_err(|e| format_error(&e.to_string(), line_count(text)));
|
||||
self.scripts.insert(text.to_string(), s.clone());
|
||||
s
|
||||
|
||||
@@ -388,6 +388,22 @@ fn circular_references_terminate() {
|
||||
assert!(matches!(r, Ok(Value::Scalar(_))) || r.is_err(), "{r:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn errors_and_property_reads_keep_the_runtime_usable() {
|
||||
// Errors thrown inside helpers, and the aborts every property read makes until the host
|
||||
// answers, must not use up the thread's runtime (it used to fail every expression after a
|
||||
// few hundred with "reached the maximum stack size").
|
||||
let f = fx();
|
||||
for _ in 0..3000 {
|
||||
assert!(f.ev(f.b, ROT, "thisComp.layer('Ghost').position", 0.0).is_err());
|
||||
}
|
||||
for i in 0..1000 {
|
||||
let t = i as f64 / 1000.0;
|
||||
assert_close!(f.ev(f.b, ROT, "thisComp.layer('A').transform.rotation", t).unwrap().as_f64(), 90.0 * t);
|
||||
}
|
||||
assert_close!(f.num("time * 2", 1.0), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effect_slider_reference() {
|
||||
let f = fx();
|
||||
|
||||
Reference in new issue
Block a user