mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 21:14:18 +00:00
Scripts: $.stack names a declared function after its declaring function returns
The compiler now keeps a function declaration's name with its code, so $.stack no longer shows [anonymous] for a declared function that is called after the function that declared it has returned. The member test expects "Web" for $.os in the wasm build, as the engine gives there.
This commit is contained in:
@@ -30,7 +30,9 @@ fn thrown(s: &mut Session, statement: &str) -> String {
|
||||
fn each_member_has_its_value() {
|
||||
let mut s = Session::new();
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let os = if cfg!(windows) {
|
||||
let os = if cfg!(target_arch = "wasm32") {
|
||||
"Web"
|
||||
} else if cfg!(windows) {
|
||||
"Windows"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
"macOS"
|
||||
|
||||
@@ -381,7 +381,7 @@ fn stack(interp: &mut Interp, _: Value, _: &[Value], _: bool) -> JsResult<Value>
|
||||
}
|
||||
for (code, pc, function) in frames.iter().skip(skip) {
|
||||
interp.use_fuel()?;
|
||||
let name = if *function { function_name(&frames, code) } else { "[global]".to_string() };
|
||||
let name = if *function { function_name(code) } else { "[global]".to_string() };
|
||||
let line = code.line_column(pc.saturating_sub(1)).0;
|
||||
text.push_str(&format!("{name}:{line}\n"));
|
||||
}
|
||||
@@ -390,14 +390,11 @@ fn stack(interp: &mut Interp, _: Value, _: &[Value], _: bool) -> JsResult<Value>
|
||||
Ok(out.finish(interp))
|
||||
}
|
||||
|
||||
/// The name `code` has: its own as a function expression's, or the one a function declaration of
|
||||
/// a frame's code gives it, cut to [`STACK_NAME_UNITS`]; `[anonymous]` without one.
|
||||
fn function_name(frames: &[(Rc<Code>, usize, bool)], code: &Rc<Code>) -> String {
|
||||
let declared = frames.iter().find_map(|(outer, ..)| {
|
||||
outer.fun_decls.iter().find(|(_, i)| outer.functions.get(*i as usize).is_some_and(|f| Rc::ptr_eq(f, code))).map(|(name, _)| name.clone())
|
||||
});
|
||||
match code.self_name.clone().or(declared) {
|
||||
Some(name) => String::from_utf16_lossy(name.get(..STACK_NAME_UNITS).unwrap_or(&*name)),
|
||||
/// The name `code` has: its own as a function expression's, or its declaration's, cut to
|
||||
/// [`STACK_NAME_UNITS`]; `[anonymous]` without one.
|
||||
fn function_name(code: &Code) -> String {
|
||||
match code.self_name.as_ref().or(code.decl_name.as_ref()) {
|
||||
Some(name) => String::from_utf16_lossy(name.get(..STACK_NAME_UNITS).unwrap_or(&**name)),
|
||||
None => "[anonymous]".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,8 @@ pub(crate) struct Code {
|
||||
pub(crate) strict: bool,
|
||||
/// A function expression's own name, bound inside it.
|
||||
pub(crate) self_name: Option<Key>,
|
||||
/// A function declaration's name, which `$.stack` shows.
|
||||
pub(crate) decl_name: Option<Key>,
|
||||
pub(crate) params: Vec<Key>,
|
||||
pub(crate) vars: Vec<Key>,
|
||||
/// Function declarations to instantiate on entry: their names and indices in `functions`.
|
||||
|
||||
@@ -1193,6 +1193,7 @@ impl<'a> FnCompiler<'a> {
|
||||
max_stack: 0,
|
||||
strict: self.strict,
|
||||
self_name: meta.self_name,
|
||||
decl_name: meta.decl_name,
|
||||
params: meta.params,
|
||||
vars: hoisted.vars,
|
||||
fun_decls: hoisted.fun_decls,
|
||||
@@ -1209,6 +1210,7 @@ impl<'a> FnCompiler<'a> {
|
||||
#[derive(Default)]
|
||||
struct Meta {
|
||||
self_name: Option<Key>,
|
||||
decl_name: Option<Key>,
|
||||
params: Vec<Key>,
|
||||
span: (u32, u32),
|
||||
}
|
||||
@@ -1231,6 +1233,7 @@ pub(crate) fn compile_function(ast: &Ast, fid: FunctionId, source: &Rc<Source>,
|
||||
c.emit(Op::Return);
|
||||
let name = f.name.as_ref().map(|n| key_of(&n.name));
|
||||
let meta = Meta {
|
||||
decl_name: if f.kind == FunctionKind::Declaration { name.clone() } else { None },
|
||||
self_name: if bind_name && f.kind == FunctionKind::Expression { name } else { None },
|
||||
params: f.params.iter().map(|p| key_of(&p.name)).collect(),
|
||||
span: (f.span.start, f.span.end),
|
||||
|
||||
@@ -163,6 +163,8 @@ fn script_items_read_the_global_object_the_last_error_the_line_and_the_stack() {
|
||||
assert_eq!(r.run("\n\n h.line").unwrap(), JsValue::Number(3.0));
|
||||
let source = "function outer() {\n return inner();\n}\nfunction inner() {\n return h.stack;\n}\nvar f = function () { return outer(); };\nf()";
|
||||
assert_eq!(text(&mut r, source), "[global]:8\n[anonymous]:7\nouter:2\ninner:5\n");
|
||||
let source = "function maker() {\n function named() {\n return h.stack;\n }\n return named;\n}\nvar later = maker();\nlater()";
|
||||
assert_eq!(text(&mut r, source), "[global]:8\nnamed:3\n", "a declared function keeps its name after its declaring function returns");
|
||||
let deep = "function d(n) { return n ? d(n - 1) : h.stack; } var s = d(100).split('\\n'); s.length + ',' + s[0]";
|
||||
let lines = text(&mut r, deep);
|
||||
assert_eq!(lines, "66,…", "64 frames, the line that some are left out, and the last line's end");
|
||||
|
||||
@@ -529,7 +529,7 @@ fn mark_code(code: &Code, strings: &mut StringSizes) {
|
||||
strings.add(flags);
|
||||
}
|
||||
let keys = code.names.iter().chain(&code.params).chain(&code.vars).chain(code.fun_decls.iter().map(|(k, _)| k));
|
||||
for k in keys.chain(&code.self_name) {
|
||||
for k in keys.chain(&code.self_name).chain(&code.decl_name) {
|
||||
strings.add_key(k);
|
||||
}
|
||||
stack.extend(code.functions.iter().map(|f| &**f));
|
||||
|
||||
@@ -843,6 +843,7 @@ fn code(ops: Vec<Op>) -> Code {
|
||||
max_stack: 0,
|
||||
strict: false,
|
||||
self_name: None,
|
||||
decl_name: None,
|
||||
params: Vec::new(),
|
||||
vars: Vec::new(),
|
||||
fun_decls: Vec::new(),
|
||||
|
||||
Reference in New Issue
Block a user