diff --git a/Cargo.lock b/Cargo.lock index bec2a79cd0..a202bb76fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,13 +28,13 @@ dependencies = [ [[package]] name = "ammonia" -version = "4.0.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" +checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6" dependencies = [ + "cssparser", "html5ever", "maplit", - "once_cell", "tendril", "url", ] @@ -492,6 +492,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.90", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -550,6 +573,21 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "either" version = "1.13.0" @@ -841,16 +879,13 @@ checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "html5ever" -version = "0.27.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" dependencies = [ "log", - "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 2.0.90", + "match_token", ] [[package]] @@ -1318,16 +1353,24 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" dependencies = [ "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -1647,7 +1690,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "phf_shared 0.11.2", + "phf_macros", + "phf_shared", ] [[package]] @@ -1656,18 +1700,8 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand", + "phf_generator", + "phf_shared", ] [[package]] @@ -1676,17 +1710,21 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ - "phf_shared 0.11.2", + "phf_shared", "rand", ] [[package]] -name = "phf_shared" -version = "0.10.0" +name = "phf_macros" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ - "siphasher", + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -2259,26 +2297,25 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot 0.12.3", - "phf_shared 0.10.0", + "phf_shared", "precomputed-hash", "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -2817,6 +2854,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index 168cfbe0da..565ad6ed92 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -19,6 +19,7 @@ pub mod math; pub mod print; pub mod rand; pub mod string; +pub mod vm_inspect; pub const NOOP: &str = "noop"; diff --git a/builtins/src/print.rs b/builtins/src/print.rs index a0941de9d9..7aed6b2ed8 100644 --- a/builtins/src/print.rs +++ b/builtins/src/print.rs @@ -1,10 +1,10 @@ use crate::SloshVm; +use crate::vm_inspect::{disassemble_value, dump_call_stack, dump_regs, dump_stack}; use bridge_macros::sl_sh_fn; -use compile_state::state::{CompileState, SloshVmTrait}; -use sl_compiler::compile; -use sl_compiler::pass1::pass1; -use slvm::{Interned, VMError, VMResult, Value}; +use compile_state::state::SloshVmTrait; +use slvm::{Chunk, Interned, VMError, VMResult, Value}; use std::io::{Write, stderr, stdout}; +use std::sync::Arc; fn is_sym(vm: &SloshVm, name: &str, intern: Interned) -> bool { if let Some(i) = vm.get_if_interned(name) @@ -174,14 +174,22 @@ pub fn eprn(vm: &mut SloshVm, registers: &[Value]) -> VMResult { /// Section: core /// /// Example: -/// #t +/// ;;(dump-globals) ; prints all global variables and their values #[sl_sh_fn(fn_name = "dump-globals", takes_env = true)] pub fn dump_globals(environment: &mut SloshVm) -> VMResult { environment.dump_globals(); Ok(Value::Nil) } -/// TODO PC make the other builtins. +/// Usage: (dasm callable) +/// +/// Disassembles a callable (function, closure, or expression) and prints the bytecode. +/// Shows the compiled bytecode instructions, register usage, and constants. +/// +/// Section: core +/// +/// Example: +/// (dasm (fn (x) (+ x 1))) pub fn dasm(vm: &mut SloshVm, registers: &[Value]) -> VMResult { if registers.len() != 1 { return Err(VMError::new_compile( @@ -189,42 +197,244 @@ pub fn dasm(vm: &mut SloshVm, registers: &[Value]) -> VMResult { )); } let exp = registers[0].unref(vm); - match exp { - Value::Lambda(handle) => { - let l = vm.get_lambda(handle); - l.disassemble_chunk(vm, 0)?; - Ok(Value::Nil) - } - Value::Closure(handle) => { - let (l, _) = vm.get_closure(handle); - l.disassemble_chunk(vm, 0)?; - Ok(Value::Nil) - } - Value::List(_handle, _start_idx) => { - let mut state = CompileState::new_state("", 1, None); - pass1(vm, &mut state, exp)?; - compile(vm, &mut state, exp, 0)?; - state.chunk.disassemble_chunk(vm, 0)?; - Ok(Value::Nil) + disassemble_value(vm, exp)?; + Ok(Value::Nil) +} + +/// Usage: (dump-regs) +/// +/// Dump the registers for the current call frame. Shows register names (if debug info available) +/// and values. Heap-allocated values are marked with '^'. +/// +/// Section: core +/// +/// Example: +/// (def test-fn (fn (x y) +/// (dump-regs) ; shows x in R1, y in R2, plus any scratch registers +/// (+ x y))) +/// (test::assert-equal 5 (test-fn 2 3)) +#[sl_sh_fn(takes_env = true, fn_name = "dump-regs")] +pub fn builtin_dump_regs(environment: &mut SloshVm) -> VMResult { + if let Some(frame) = environment.call_frame() { + println!("Previous Call Frames Regs (NOTE: tail calls will be 'missing' Call Frames):"); + dump_regs(environment, frame); + println!(); + } + let lambda = if let Some(val) = environment.this_fn() { + match val { + Value::Lambda(h) => environment.get_lambda(h), + Value::Closure(h) => { + let (l, _) = environment.get_closure(h); + l + } + _ => Arc::new(Chunk::new("", 0)), } - Value::Pair(_handle) => { - let mut state = CompileState::new_state("", 1, None); - pass1(vm, &mut state, exp)?; - compile(vm, &mut state, exp, 0)?; - state.chunk.disassemble_chunk(vm, 0)?; - Ok(Value::Nil) + } else { + Arc::new(Chunk::new("", 0)) + }; + let mut reg_names = lambda.dbg_args.as_ref().map(|iargs| iargs.iter()); + let regs = environment.get_current_registers(); + for (i, r) in regs.iter().enumerate() { + let aname = if i == 0 { + "params/result" + } else if let Some(reg_names) = reg_names.as_mut() { + if let Some(n) = reg_names.next() { + environment.get_interned(*n) + } else { + "[SCRATCH]" + } + } else { + "[SCRATCH]" + }; + if let Value::Value(_) = r { + println!( + "{:#03} ^{:#20}: {:#12} {}", + i, + aname, + r.display_type(environment), + r.pretty_value(environment) + ); + } else { + println!( + "{:#03} {:#20}: {:#12} {}", + i, + aname, + r.display_type(environment), + r.pretty_value(environment) + ); } - _ => Err(VMError::new_vm("DASM: Not a callable.")), } + Ok(Value::Nil) +} + +/// Usage: (dump-stack) +/// +/// Dump the call stack frames. Shows each active call frame with file name, +/// line number, and instruction pointer. +/// +/// Section: core +/// +/// Example: +/// (dump-stack) +#[sl_sh_fn(takes_env = true, fn_name = "dump-stack")] +pub fn builtin_dump_stack(environment: &mut SloshVm) -> VMResult { + dump_call_stack(environment); + Ok(Value::Nil) +} + +/// Usage: (dump-regs-raw) +/// +/// Dump all registers in the VM stack. Shows raw stack contents without +/// interpreting call frame boundaries. +/// +/// Section: core +/// +/// Example: +/// (dump-regs-raw) +#[sl_sh_fn(takes_env = true, fn_name = "dump-regs-raw")] +pub fn dump_regs_raw(environment: &mut SloshVm) -> VMResult { + dump_stack(environment); + Ok(Value::Nil) } pub fn add_print_builtins(env: &mut SloshVm) { - env.set_global_builtin("pr", pr); - env.set_global_builtin("epr", epr); - env.set_global_builtin("prn", prn); - env.set_global_builtin("eprn", eprn); - env.set_global_builtin("dasm", dasm); - env.set_global_builtin("fpr", fpr); - env.set_global_builtin("fprn", fprn); + bridge_adapters::add_builtin( + env, + "pr", + pr, + r#"Usage: (pr value1 value2 ...) + +Print values to stdout without a newline. Values are printed in their "pretty" form, +meaning strings are printed without quotes and character values without delimiters. + +Section: core + +Example: +(pr "Hello" " " "World") ; prints: Hello World +(pr 'symbol :keyword 42) ; prints: symbol:keyword42 +"#, + ); + bridge_adapters::add_builtin( + env, + "epr", + epr, + r#"Usage: (epr value1 value2 ...) + +Print values to stderr without a newline. Values are printed in their "pretty" form, +meaning strings are printed without quotes and character values without delimiters. + +Section: core + +Example: +(epr "Error occurred!") ; prints to stderr: Error: +"#, + ); + bridge_adapters::add_builtin( + env, + "prn", + prn, + r#"Usage: (prn value1 value2 ...) + +Print values to stdout followed by a newline. Values are printed in their "pretty" form, +meaning strings are printed without quotes and character values without delimiters. + +Section: core + +Example: +(prn "Hello World") ; prints: Hello World\n +(prn "Line 1") +(prn "Line 2") ; prints each on separate lines +"#, + ); + bridge_adapters::add_builtin( + env, + "eprn", + eprn, + r#"Usage: (eprn value1 value2 ...) + +Print values to stderr followed by a newline. Values are printed in their "pretty" form, +meaning strings are printed without quotes and character values without delimiters. + +Section: core + +Example: +(eprn "Error occurred!") ; prints to stderr: Error occurred!\n +"#, + ); + bridge_adapters::add_builtin( + env, + "dasm", + dasm, + r#"Usage: (dasm callable) + +Disassemble a callable (function, closure, or expression) and print its bytecode. +Shows the compiled bytecode instructions, register usage, and constants. + +Section: core + +Example: +(dasm (fn (x) (+ x 1))) +; Output: +; INPUTS: 2 args/optional/rest 1/0/false +; EXTRA REGS: 1 +; 0x00000000 MOV(0x05) R(0x02) R(0x01) +; 0x00000003 REGI(0x11) R(0x03) 0x01 +; 0x00000006 ADD R(0x02) R(0x03) +; 0x00000009 SRET(0x03) R(0x02) + +(def my-func (fn (a b) (* a b))) +(dasm my-func) ; disassemble a named function +"#, + ); + bridge_adapters::add_builtin( + env, + "fpr", + fpr, + r#"Usage: (fpr file-handle value1 value2 ...) + +Print values to a file handle without a newline. The first argument must be +a writable IO object. Values are printed in their "pretty" form. + +Section: file + +Example: +(with-temp-file (fn (tmp-name) +(let (tmp-file (fopen tmp-name :create :truncate)) + (fpr tmp-file (str "Hello" " " "World")) + (fpr tmp-file "!") + (fclose tmp-file) + (let (tmp-file (fopen tmp-name :read)) + (defer (fclose tmp-file)) + (test::assert-equal "Hello World!" (read-line tmp-file)))))) +"#, + ); + bridge_adapters::add_builtin( + env, + "fprn", + fprn, + r#"Usage: (fprn file-handle value1 value2 ...) + +Print values to a file handle followed by a newline. The first argument must be +a writable IO object. Values are printed in their "pretty" form. + +Section: file + +Example: +(with-temp-file (fn (tmp-name) +(let (tmp-file (fopen tmp-name :create :truncate)) + (fprn tmp-file "Line 1") + (fprn tmp-file "Line 2") + (fclose tmp-file) + (let (tmp-file (fopen tmp-name :read)) + (defer (fclose tmp-file)) + (test::assert-equal "Line 1 +" (read-line tmp-file)) + (test::assert-equal "Line 2 +" (read-line tmp-file)))))) +"#, + ); + intern_builtin_dump_regs(env); + intern_builtin_dump_stack(env); + intern_dump_regs_raw(env); intern_dump_globals(env); } diff --git a/builtins/src/vm_inspect.rs b/builtins/src/vm_inspect.rs new file mode 100644 index 0000000000..69ebea2544 --- /dev/null +++ b/builtins/src/vm_inspect.rs @@ -0,0 +1,154 @@ +use crate::SloshVm; +use compile_state::state::CompileState; +use sl_compiler::compile; +use sl_compiler::pass1::pass1; +use slvm::{CallFrame, VMError, VMResult, Value}; +use std::collections::VecDeque; + +/// Common function to disassemble a value (lambda, closure, or expression) +pub fn disassemble_value(vm: &mut SloshVm, exp: Value) -> VMResult<()> { + match exp { + Value::Lambda(handle) => { + let l = vm.get_lambda(handle); + l.disassemble_chunk(vm, 0)?; + Ok(()) + } + Value::Closure(handle) => { + let (l, _) = vm.get_closure(handle); + l.disassemble_chunk(vm, 0)?; + Ok(()) + } + Value::List(_handle, _start_idx) => { + let mut state = CompileState::new_state("", 1, None); + pass1(vm, &mut state, exp)?; + compile(vm, &mut state, exp, 0)?; + state.chunk.disassemble_chunk(vm, 0)?; + Ok(()) + } + Value::Pair(_handle) => { + let mut state = CompileState::new_state("", 1, None); + pass1(vm, &mut state, exp)?; + compile(vm, &mut state, exp, 0)?; + state.chunk.disassemble_chunk(vm, 0)?; + Ok(()) + } + _ => Err(VMError::new_vm("DASM: Not a callable.")), + } +} + +/// Common function to dump registers for a call frame +pub fn dump_regs(vm: &SloshVm, frame: &CallFrame) { + let start = frame.stack_top; + let end = frame.stack_top + frame.chunk.input_regs + frame.chunk.extra_regs + 1; + let regs = vm.get_registers(start, end); + let mut reg_names = frame.chunk.dbg_args.as_ref().map(|iargs| iargs.iter()); + for (i, r) in regs.iter().enumerate() { + let aname = if i == 0 { + "params/result" + } else if let Some(reg_names) = reg_names.as_mut() { + if let Some(n) = reg_names.next() { + vm.get_interned(*n) + } else { + "[SCRATCH]" + } + } else { + "[SCRATCH]" + }; + if let Value::Value(_) = r { + println!( + "{:#03} ^{:#20}: {:#12} {}", + i, + aname, + r.display_type(vm), + r.pretty_value(vm) + ); + } else { + println!( + "{:#03} {:#20}: {:#12} {}", + i, + aname, + r.display_type(vm), + r.pretty_value(vm) + ); + } + } +} + +/// Common function to dump the entire stack +pub fn dump_stack(vm: &SloshVm) { + let mut reg_names = None; + let mut chunks = VecDeque::new(); + for i in 1..=vm.stack_max() { + let r = vm.get_stack(i); + if let Value::CallFrame(handle) = r { + let frame = vm.get_callframe(handle); + chunks.push_back(frame.chunk.clone()); + } + } + if let Some(err_frame) = vm.err_frame() { + chunks.push_back(err_frame.chunk.clone()); + } + + let mut chunk_own; + for i in 0..=vm.stack_max() { + let r = vm.get_stack(i); + let reg_name = if let Value::CallFrame(_) = r { + reg_names = if let Some(chunk) = chunks.pop_front() { + chunk_own = chunk; + chunk_own.dbg_args.as_ref().map(|iargs| iargs.iter()) + } else { + None + }; + "RESULT" + } else if let Some(reg_names) = reg_names.as_mut() { + if let Some(n) = reg_names.next() { + vm.get_interned(*n) + } else { + "[SCRATCH]" + } + } else { + "[SCRATCH]" + }; + if let Value::Value(handle) = r { + let han_str = format!("{}({})", reg_name, handle.idx()); + println!( + "{:#03} ^{:#20}: {:#12} {}", + i, + han_str, + r.display_type(vm), + r.pretty_value(vm) + ); + } else { + println!( + "{:#03} {:#20}: {:#12} {}", + i, + reg_name, + r.display_type(vm), + r.pretty_value(vm) + ); + } + } +} + +/// Dump the call stack +pub fn dump_call_stack(vm: &SloshVm) { + if let Some(frame) = vm.err_frame() { + let line = frame.current_line().unwrap_or(0); + println!( + "ERROR Frame: {} line: {} ip: {:#010x}", + frame.chunk.file_name, + line, + frame.current_offset() + ); + } + for frame in vm.get_call_stack() { + let line = frame.current_line().unwrap_or(0); + println!( + "ID: {} {} line: {} ip: {:#010x}", + frame.id, + frame.chunk.file_name, + line, + frame.current_offset() + ); + } +} diff --git a/doc/mdbook-slosh-eval/Cargo.lock b/doc/mdbook-slosh-eval/Cargo.lock index 164e633cad..e893c1b0e6 100644 --- a/doc/mdbook-slosh-eval/Cargo.lock +++ b/doc/mdbook-slosh-eval/Cargo.lock @@ -28,13 +28,13 @@ dependencies = [ [[package]] name = "ammonia" -version = "4.0.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" +checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6" dependencies = [ + "cssparser", "html5ever", "maplit", - "once_cell", "tendril", "url", ] @@ -233,9 +233,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" @@ -381,6 +381,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.98", +] + [[package]] name = "darling" version = "0.20.10" @@ -485,6 +508,21 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "elasticlunr-rs" version = "3.0.2" @@ -776,16 +814,13 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.27.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" dependencies = [ "log", - "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 2.0.98", + "match_token", ] [[package]] @@ -1203,16 +1238,24 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" dependencies = [ "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -1550,6 +1593,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ + "phf_macros", "phf_shared", ] @@ -1573,6 +1617,19 @@ dependencies = [ "rand", ] +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "phf_shared" version = "0.11.3" @@ -2042,9 +2099,9 @@ dependencies = [ [[package]] name = "string_cache_codegen" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244292f3441c89febe5b5bdfbb6863aeaf4f64da810ea3050fd927b27b8d92ce" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ "phf_generator", "phf_shared", @@ -2507,6 +2564,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web_atoms" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/slosh_lib/src/debug.rs b/slosh_lib/src/debug.rs index a8b520f118..3930b17f73 100644 --- a/slosh_lib/src/debug.rs +++ b/slosh_lib/src/debug.rs @@ -1,109 +1,14 @@ extern crate sl_liner; -use std::collections::VecDeque; use std::env; use std::io::ErrorKind; use std::path::PathBuf; -use std::sync::Arc; +use builtins::vm_inspect::{disassemble_value, dump_call_stack, dump_regs, dump_stack}; use compile_state::state::{SloshVm, SloshVmTrait}; use sl_compiler::Reader; use sl_liner::{Context, Prompt}; -use slvm::{CallFrame, Chunk, VMError, VMResult, Value}; - -fn dump_regs(vm: &SloshVm, frame: &CallFrame) { - let start = frame.stack_top; - let end = frame.stack_top + frame.chunk.input_regs + frame.chunk.extra_regs + 1; - let regs = vm.get_registers(start, end); - let mut reg_names = frame.chunk.dbg_args.as_ref().map(|iargs| iargs.iter()); - for (i, r) in regs.iter().enumerate() { - let aname = if i == 0 { - "params/result" - } else if let Some(reg_names) = reg_names.as_mut() { - if let Some(n) = reg_names.next() { - vm.get_interned(*n) - } else { - "[SCRATCH]" - } - } else { - "[SCRATCH]" - }; - if let Value::Value(_) = r { - println!( - "{:#03} ^{:#20}: {:#12} {}", - i, - aname, - r.display_type(vm), - r.pretty_value(vm) - ); - } else { - println!( - "{:#03} {:#20}: {:#12} {}", - i, - aname, - r.display_type(vm), - r.pretty_value(vm) - ); - } - } -} - -fn dump_stack(vm: &SloshVm) { - //println!("Stack from 0 to {}", vm.stack_max() - 1); - let mut reg_names = None; - let mut chunks = VecDeque::new(); - for i in 1..=vm.stack_max() { - let r = vm.get_stack(i); - if let Value::CallFrame(handle) = r { - let frame = vm.get_callframe(handle); - chunks.push_back(frame.chunk.clone()); - } - } - if let Some(err_frame) = vm.err_frame() { - chunks.push_back(err_frame.chunk.clone()); - } - - let mut chunk_own; - for i in 0..=vm.stack_max() { - let r = vm.get_stack(i); - let reg_name = if let Value::CallFrame(_) = r { - reg_names = if let Some(chunk) = chunks.pop_front() { - chunk_own = chunk; - chunk_own.dbg_args.as_ref().map(|iargs| iargs.iter()) - } else { - None - }; - "RESULT" - } else if let Some(reg_names) = reg_names.as_mut() { - if let Some(n) = reg_names.next() { - vm.get_interned(*n) - } else { - "[SCRATCH]" - } - } else { - "[SCRATCH]" - }; - //for (i, r) in vm.stack().iter().enumerate() { - if let Value::Value(handle) = r { - let han_str = format!("{}({})", reg_name, handle.idx()); - println!( - "{:#03} ^{:#20}: {:#12} {}", - i, - han_str, - r.display_type(vm), - r.pretty_value(vm) - ); - } else { - println!( - "{:#03} {:#20}: {:#12} {}", - i, - reg_name, - r.display_type(vm), - r.pretty_value(vm) - ); - } - } -} +use slvm::Value; pub fn debug(env: &mut SloshVm) { let abort = env.intern("abort"); @@ -172,8 +77,8 @@ pub fn debug(env: &mut SloshVm) { break; } } - } else { - println!("Param not an int."); + } else if let Err(e) = disassemble_value(env, parm) { + println!("Error in disassembly: {e}"); } } else if let Some(err_frame) = env.err_frame() { if let Err(e) = err_frame.chunk.disassemble_chunk(env, 0) { @@ -206,25 +111,7 @@ pub fn debug(env: &mut SloshVm) { dump_stack(env); } Some(Ok(Value::Keyword(k))) if k == stack => { - if let Some(frame) = env.err_frame() { - let line = frame.current_line().unwrap_or(0); - println!( - "ERROR Frame: {} line: {} ip: {:#010x}", - frame.chunk.file_name, - line, - frame.current_offset() - ); - } - for frame in env.get_call_stack() { - let line = frame.current_line().unwrap_or(0); - println!( - "ID: {} {} line: {} ip: {:#010x}", - frame.id, - frame.chunk.file_name, - line, - frame.current_offset() - ); - } + dump_call_stack(env); } Some(Err(err)) => println!("Reader error: {err}"), _ => {} @@ -235,62 +122,6 @@ pub fn debug(env: &mut SloshVm) { } } -pub fn builtin_dump_regs(vm: &mut SloshVm, registers: &[Value]) -> VMResult { - if !registers.is_empty() { - return Err(VMError::new_compile("dump-regs: takes no args")); - } - if let Some(frame) = vm.call_frame() { - println!("Previous Call Frames Regs (NOTE: tail calls will be 'missing' Call Frames):"); - dump_regs(vm, frame); - println!(); - } - let lambda = if let Some(val) = vm.this_fn() { - match val { - Value::Lambda(h) => vm.get_lambda(h), - Value::Closure(h) => { - let (l, _) = vm.get_closure(h); - l - } - _ => Arc::new(Chunk::new("", 0)), - } - } else { - Arc::new(Chunk::new("", 0)) - }; - let mut reg_names = lambda.dbg_args.as_ref().map(|iargs| iargs.iter()); - let regs = vm.get_current_registers(); - for (i, r) in regs.iter().enumerate() { - let aname = if i == 0 { - "params/result" - } else if let Some(reg_names) = reg_names.as_mut() { - if let Some(n) = reg_names.next() { - vm.get_interned(*n) - } else { - "[SCRATCH]" - } - } else { - "[SCRATCH]" - }; - if let Value::Value(_) = r { - println!( - "{:#03} ^{:#20}: {:#12} {}", - i, - aname, - r.display_type(vm), - r.pretty_value(vm) - ); - } else { - println!( - "{:#03} {:#20}: {:#12} {}", - i, - aname, - r.display_type(vm), - r.pretty_value(vm) - ); - } - } - Ok(Value::Nil) -} - pub fn get_temp_file_path(filename: &str) -> PathBuf { let temp_dir = env::temp_dir(); //let temp_dir = PathBuf::from("/tmp/"); diff --git a/slosh_lib/src/lib.rs b/slosh_lib/src/lib.rs index 4503990a66..916a6ba39c 100644 --- a/slosh_lib/src/lib.rs +++ b/slosh_lib/src/lib.rs @@ -523,14 +523,11 @@ pub fn set_builtins_and_shell_builtins(env: &mut SloshVm) { pub fn set_shell_builtins(env: &mut SloshVm) { set_environment(env); add_shell_builtins(env); - env.set_global_builtin("dump-regs", builtin_dump_regs); let uid = Sys::current_uid(); let euid = Sys::effective_uid(); unsafe { env::set_var("UID", format!("{uid}")); - } - unsafe { env::set_var("EUID", format!("{euid}")); } bridge_adapters::add_named_global_doc( diff --git a/slosh_test_lib/src/docs.rs b/slosh_test_lib/src/docs.rs index b753b7c3c8..430bff8a93 100644 --- a/slosh_test_lib/src/docs.rs +++ b/slosh_test_lib/src/docs.rs @@ -53,14 +53,6 @@ lazy_static! { exemption_set.insert("return"); exemption_set.insert("*int-min*"); exemption_set.insert("*int-max*"); - exemption_set.insert("prn"); - exemption_set.insert("pr"); - exemption_set.insert("fprn"); - exemption_set.insert("fpr"); - exemption_set.insert("eprn"); - exemption_set.insert("epr"); - exemption_set.insert("dump-regs"); - exemption_set.insert("dasm"); exemption_set.insert("*int-bits*"); exemption_set.insert("*stdout*"); exemption_set.insert("*prn*"); diff --git a/slosh_test_lib/src/docs/legacy.rs b/slosh_test_lib/src/docs/legacy.rs index 0a2849e74f..f5582c0420 100644 --- a/slosh_test_lib/src/docs/legacy.rs +++ b/slosh_test_lib/src/docs/legacy.rs @@ -107,7 +107,6 @@ pub(crate) fn unimplemented_report(vm: &mut SloshVm) -> VMResult { crate::vm_with_stdout_disabled(vm); slosh_lib::load_builtins_lisp_less_sloshrc(vm)?; - slosh_lib::load_test(vm); crate::vm_with_stdout_enabled(vm); // Add all global symbols for g in vm.globals().keys() { diff --git a/slosh_test_lib/src/lib.rs b/slosh_test_lib/src/lib.rs index 12a826b3c6..2a9a3477f0 100644 --- a/slosh_test_lib/src/lib.rs +++ b/slosh_test_lib/src/lib.rs @@ -12,6 +12,9 @@ pub fn do_to_vm_stdout_fcns(env: &mut SloshVm, noop_swap_type: NoopSwap) { let _ = noop_swap_internal(env, "prn".to_string(), noop_swap_type); let _ = noop_swap_internal(env, "dasm".to_string(), noop_swap_type); let _ = noop_swap_internal(env, "dump-globals".to_string(), noop_swap_type); + let _ = noop_swap_internal(env, "dump-regs-raw".to_string(), noop_swap_type); + let _ = noop_swap_internal(env, "dump-regs".to_string(), noop_swap_type); + let _ = noop_swap_internal(env, "dump-stack".to_string(), noop_swap_type); } /// pr/prn/dasm/dump-globals which write directly to stdout are mapped to noop