improve panic message, slightly
This commit is contained in:
parent
728614879c
commit
e4e32bb308
|
@ -1035,7 +1035,7 @@ fn spawn! {
|
|||
}
|
||||
|
||||
fn yield! {
|
||||
"Forces a process to yield."
|
||||
"Forces a process to yield, allowing other processes to execute."
|
||||
() -> base :process (:yield)
|
||||
}
|
||||
|
||||
|
@ -1045,10 +1045,13 @@ fn alive? {
|
|||
}
|
||||
|
||||
fn link! {
|
||||
"Creates a link between two processes. There are two types of links: `:report`, which sends a message to pid1 when pid2 dies; and `:panic`, which causes a panic in one when the other dies. The default is `:report`."
|
||||
(pid1 as :keyword, pid2 as :keyword) -> link! (pid1, pid2, :report)
|
||||
(pid1 as :keyword, pid2 as :keyword, :report) -> base :process (:link_report, pid1, pid2)
|
||||
(pid1 as :keyword, pid2 as :keyword, :panic) -> base :process (:link_panic, pid1, pid2)
|
||||
"Links this process to another process. When either one dies--panics or returns--both are shut down."
|
||||
(pid as :keyword) -> base :process (:link, pid)
|
||||
}
|
||||
|
||||
fn monitor! {
|
||||
"Subscribes this process to another process's exit signals. There are two possibilities: a panic or a return. Exit signals are in the form of `(:exit, pid, (:ok, value)/(:err, msg))`."
|
||||
(pid as :keyword) -> base :process (:monitor, pid)
|
||||
}
|
||||
|
||||
fn flush! {
|
||||
|
@ -1061,6 +1064,25 @@ fn sleep! {
|
|||
(ms as :number) -> base :process (:sleep, ms)
|
||||
}
|
||||
|
||||
fn await! {
|
||||
"Parks the current process until it receives an exit signal from the passed process. Returns the result of a successful execution or panics if the awaited process panics."
|
||||
(pid as :keyword) -> {
|
||||
monitor! (pid)
|
||||
receive {
|
||||
(:exit, _, (:ok, result)) -> result
|
||||
(:exit, _, (:err, msg)) -> {
|
||||
panic! "Monitored process {pid} panicked with {msg}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn heed! {
|
||||
"Parks the current process until it receives a reply, and returns whatever is replied. Causes a panic if it gets anything other than a `(:reply, result)` tuple."
|
||||
() -> receive {
|
||||
(:reply, result) -> result
|
||||
}
|
||||
}
|
||||
|
||||
& TODO: make this more robust, to handle multiple pending requests w/o data races
|
||||
fn request_fetch! {
|
||||
(pid as :keyword, url as :string) -> {
|
||||
|
@ -1427,7 +1449,11 @@ fn llist {
|
|||
flush!
|
||||
|
||||
& wip actor functions
|
||||
& link!
|
||||
link!
|
||||
monitor!
|
||||
await!
|
||||
heed!
|
||||
|
||||
spawn_turtle!
|
||||
|
||||
& shared memory w/ rust
|
||||
|
|
|
@ -1249,5 +1249,6 @@ And now, we build capacity for building projects.
|
|||
|
||||
* [ ] allow for multiple turtles
|
||||
- [x] rework p5 function in `ludus.js` to properly parse commands targeted at different turtles
|
||||
- [ ] write ludus code to spawn & manipulate turtle actors
|
||||
- [x] write ludus code to spawn & manipulate turtle actors
|
||||
- [ ] write linking logic so we can `await` turtles
|
||||
* [ ] do some sample multiturtle sketches
|
||||
|
|
|
@ -403,7 +403,7 @@ function __wbg_get_imports() {
|
|||
_assertBoolean(ret);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper8094 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
imports.wbg.__wbindgen_closure_wrapper8073 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 354, __wbg_adapter_20);
|
||||
return ret;
|
||||
}, arguments) };
|
||||
|
|
Binary file not shown.
|
@ -97,7 +97,7 @@ pub fn panic(panic: Panic) -> String {
|
|||
// console_log!("Ludus panicked!: {panic}");
|
||||
// panic.call_stack.last().unwrap().chunk().dissasemble();
|
||||
// console_log!("{:?}", panic.call_stack.last().unwrap().chunk().spans);
|
||||
let mut msgs = vec!["Ludus panicked!".to_string()];
|
||||
let mut msgs = vec![];
|
||||
let msg = match panic.msg {
|
||||
PanicMsg::Generic(ref s) => s,
|
||||
_ => &"no match".to_string(),
|
||||
|
|
|
@ -163,14 +163,14 @@ pub async fn ludus(src: String) {
|
|||
compiler.compile();
|
||||
|
||||
if DEBUG_SCRIPT_COMPILE {
|
||||
println!("=== source code ===");
|
||||
println!("{src}");
|
||||
console_log!("=== source code ===");
|
||||
console_log!("{src}");
|
||||
compiler.disassemble();
|
||||
println!("\n\n")
|
||||
console_log!("\n\n")
|
||||
}
|
||||
|
||||
if DEBUG_SCRIPT_RUN {
|
||||
println!("=== vm run ===");
|
||||
console_log!("=== vm run ===");
|
||||
}
|
||||
|
||||
let vm_chunk = compiler.chunk;
|
||||
|
|
166
src/vm.rs
166
src/vm.rs
|
@ -178,9 +178,10 @@ impl Creature {
|
|||
.map(|val| val.show())
|
||||
.collect::<Vec<_>>()
|
||||
.join("/");
|
||||
println!(
|
||||
console_log!(
|
||||
"{:04}: [{inner}] ({register}) {} {{{mbx}}}",
|
||||
self.last_code, self.pid
|
||||
self.last_code,
|
||||
self.pid
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -197,14 +198,6 @@ impl Creature {
|
|||
// add it to our cloned stack
|
||||
let mut call_stack = self.call_stack.clone();
|
||||
call_stack.push(frame);
|
||||
// console_log!(
|
||||
// "{}",
|
||||
// call_stack
|
||||
// .iter()
|
||||
// .map(|s| s.to_string())
|
||||
// .collect::<Vec<_>>()
|
||||
// .join("\n")
|
||||
// );
|
||||
//make a panic
|
||||
let panic = Panic {
|
||||
msg,
|
||||
|
@ -214,9 +207,10 @@ impl Creature {
|
|||
// and gtfo
|
||||
self.result = Some(Err(panic));
|
||||
self.r#yield = true;
|
||||
self.broadcast_panic();
|
||||
}
|
||||
|
||||
fn panic_with(&mut self, msg: String) {
|
||||
pub fn panic_with(&mut self, msg: String) {
|
||||
self.panic(PanicMsg::Generic(msg));
|
||||
}
|
||||
|
||||
|
@ -254,52 +248,84 @@ impl Creature {
|
|||
if self.pid == pid {
|
||||
self.mbx.push_back(msg.clone());
|
||||
} else {
|
||||
self.zoo.as_ref().borrow_mut().send_msg(pid, msg);
|
||||
self.zoo.borrow_mut().send_msg(pid, msg);
|
||||
}
|
||||
self.push(Value::Keyword("ok"));
|
||||
}
|
||||
|
||||
// TODO: fix these based on what I decide about `link` & `monitor`
|
||||
fn link_report(&mut self, parent: Value, child: Value) {
|
||||
let (Value::Keyword(parent), Value::Keyword(child)) = (parent, child) else {
|
||||
unreachable!("expected keyword pids in link_report");
|
||||
fn broadcast_panic(&mut self) {
|
||||
console_log!("broadcasting panic in {}", self.pid);
|
||||
let Err(panic) = self.result.clone().unwrap() else {
|
||||
unreachable!("expected panic in broadcast panic");
|
||||
};
|
||||
let child = if child == self.pid {
|
||||
self
|
||||
} else {
|
||||
&mut self.zoo.borrow_mut().catch(child)
|
||||
};
|
||||
child.parents.push(parent);
|
||||
let msg = Rc::new(crate::errors::panic(panic));
|
||||
for pid in self.parents.clone() {
|
||||
self.send_msg(
|
||||
Value::Keyword(pid),
|
||||
Value::tuple(vec![
|
||||
Value::Keyword("exit"),
|
||||
Value::Keyword(self.pid),
|
||||
Value::tuple(vec![Value::Keyword("err"), Value::String(msg.clone())]),
|
||||
]),
|
||||
)
|
||||
}
|
||||
for pid in self.siblings.clone() {
|
||||
self.zoo.borrow_mut().kill_linked(pid);
|
||||
}
|
||||
}
|
||||
|
||||
fn link_panic(&mut self, left_pid: Value, right_pid: Value) {
|
||||
let (Value::Keyword(left_id), Value::Keyword(right_id)) = (left_pid, right_pid) else {
|
||||
unreachable!("expected keyword pids in link_panic");
|
||||
fn broadcast_return(&mut self) {
|
||||
// console_log!("broadcasting return from {}", self.pid);
|
||||
//TODO: work around this clone?
|
||||
for pid in self.parents.clone() {
|
||||
let result_tuple = Value::tuple(vec![
|
||||
Value::Keyword("ok"),
|
||||
self.result.clone().unwrap().unwrap(),
|
||||
]);
|
||||
let exit_signal = Value::tuple(vec![
|
||||
Value::Keyword("exit"),
|
||||
Value::Keyword(self.pid),
|
||||
result_tuple,
|
||||
]);
|
||||
// console_log!("sending exit signal {exit_signal}");
|
||||
self.send_msg(Value::Keyword(pid), exit_signal);
|
||||
}
|
||||
for pid in self.siblings.clone() {
|
||||
self.zoo.borrow_mut().kill(pid);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fix these based on what I decide about `link` & `monitor`
|
||||
fn monitor(&mut self, other: Value) {
|
||||
// console_log!("monitoring {other}");
|
||||
let Value::Keyword(other) = other else {
|
||||
unreachable!("expected keyword pid in monitor");
|
||||
};
|
||||
if other != self.pid {
|
||||
let mut other = self.zoo.borrow_mut().catch(other);
|
||||
other.parents.push(self.pid);
|
||||
self.zoo.borrow_mut().release(other);
|
||||
// console_log!("{} added to parents", self.pid);
|
||||
}
|
||||
self.push(Value::Keyword("ok"));
|
||||
}
|
||||
|
||||
fn link(&mut self, other: Value) {
|
||||
let Value::Keyword(other) = other else {
|
||||
unreachable!("expected keyword pid in link");
|
||||
};
|
||||
// if we're linking to ourselves, we don't need to do anything
|
||||
if left_id == self.pid && right_id == self.pid {
|
||||
return;
|
||||
}
|
||||
let mut zoo = self.zoo.borrow_mut();
|
||||
// fancy footwork w/ cases: we can't catch ourselves in the zoo
|
||||
if left_id == self.pid {
|
||||
self.siblings.push(right_id);
|
||||
let mut right = zoo.catch(right_id);
|
||||
right.siblings.push(self.pid);
|
||||
} else if right_id == self.pid {
|
||||
self.siblings.push(left_id);
|
||||
let mut left = zoo.catch(left_id);
|
||||
left.siblings.push(self.pid);
|
||||
} else {
|
||||
let mut left = zoo.catch(left_id);
|
||||
let mut right = zoo.catch(right_id);
|
||||
left.siblings.push(right_id);
|
||||
right.siblings.push(left_id);
|
||||
if other != self.pid {
|
||||
self.siblings.push(other);
|
||||
let mut other = self.zoo.borrow_mut().catch(other);
|
||||
other.siblings.push(self.pid);
|
||||
self.zoo.borrow_mut().release(other);
|
||||
}
|
||||
self.push(Value::Keyword("ok"));
|
||||
}
|
||||
|
||||
fn handle_msg(&mut self, args: Vec<Value>) {
|
||||
println!("message received by {}: {}", self.pid, args[0]);
|
||||
// console_log!("message received by {}: {}", self.pid, args[0]);
|
||||
let Value::Keyword(msg) = args.first().unwrap() else {
|
||||
return self.panic_with("malformed message to Process".to_string());
|
||||
};
|
||||
|
@ -310,12 +336,12 @@ impl Creature {
|
|||
let f = args[1].clone();
|
||||
let proc = Creature::spawn(f, self.zoo.clone(), self.debug);
|
||||
let id = self.zoo.as_ref().borrow_mut().put(proc);
|
||||
console_log!("spawning new process {id}!");
|
||||
// console_log!("spawning new process {id}!");
|
||||
self.push(Value::Keyword(id));
|
||||
}
|
||||
"yield" => {
|
||||
self.r#yield = true;
|
||||
println!("yielding from {}", self.pid);
|
||||
console_log!("yielding from {}", self.pid);
|
||||
self.push(Value::Keyword("ok"));
|
||||
}
|
||||
"alive" => {
|
||||
|
@ -329,12 +355,12 @@ impl Creature {
|
|||
self.push(Value::False)
|
||||
}
|
||||
}
|
||||
"link_panic" => self.link_panic(args[1].clone(), args[2].clone()),
|
||||
"link_report" => self.link_report(args[1].clone(), args[2].clone()),
|
||||
"link" => self.link(args[1].clone()),
|
||||
"monitor" => self.monitor(args[1].clone()),
|
||||
"flush" => {
|
||||
let msgs = self.mbx.iter().cloned().collect::<Vec<_>>();
|
||||
let msgs = Vector::from(msgs);
|
||||
println!(
|
||||
console_log!(
|
||||
"delivering messages: {}",
|
||||
msgs.iter()
|
||||
.map(|x| x.show())
|
||||
|
@ -342,11 +368,11 @@ impl Creature {
|
|||
.join(" | ")
|
||||
);
|
||||
self.mbx = VecDeque::new();
|
||||
println!("flushing messages in {}", self.pid);
|
||||
console_log!("flushing messages in {}", self.pid);
|
||||
self.push(Value::List(Box::new(msgs)));
|
||||
}
|
||||
"sleep" => {
|
||||
println!("sleeping {} for {}", self.pid, args[1]);
|
||||
console_log!("sleeping {} for {}", self.pid, args[1]);
|
||||
let Value::Number(ms) = args[1] else {
|
||||
unreachable!()
|
||||
};
|
||||
|
@ -359,28 +385,29 @@ impl Creature {
|
|||
}
|
||||
|
||||
pub fn interpret(&mut self) {
|
||||
console_log!("starting process {}", self.pid);
|
||||
console_log!(
|
||||
"mbx: {}",
|
||||
self.mbx
|
||||
.iter()
|
||||
.map(|x| x.show())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | ")
|
||||
);
|
||||
// console_log!("starting process {}", self.pid);
|
||||
// console_log!(
|
||||
// "mbx: {}",
|
||||
// self.mbx
|
||||
// .iter()
|
||||
// .map(|x| x.show())
|
||||
// .collect::<Vec<_>>()
|
||||
// .join(" | ")
|
||||
// );
|
||||
loop {
|
||||
if self.at_end() {
|
||||
let result = self.stack.pop().unwrap();
|
||||
// println!("process {} has returned {result}", self.pid);
|
||||
self.broadcast_return();
|
||||
// console_log!("process :{} has returned {result}", self.pid);
|
||||
self.result = Some(Ok(result));
|
||||
return;
|
||||
}
|
||||
if self.r#yield {
|
||||
console_log!("yielding from {}", self.pid);
|
||||
// console_log!("yielding from {}", self.pid);
|
||||
return;
|
||||
}
|
||||
if self.reductions >= MAX_REDUCTIONS {
|
||||
// println!(
|
||||
// console_log!(
|
||||
// "process {} is yielding after {MAX_REDUCTIONS} reductions",
|
||||
// self.pid
|
||||
// );
|
||||
|
@ -730,7 +757,7 @@ impl Creature {
|
|||
let dict = match self.get_value_at(dict_idx) {
|
||||
Value::Dict(dict) => dict,
|
||||
value => {
|
||||
println!(
|
||||
console_log!(
|
||||
"internal Ludus error in function {}",
|
||||
self.frame.function.as_fn().name()
|
||||
);
|
||||
|
@ -1003,7 +1030,7 @@ impl Creature {
|
|||
let called = self.pop();
|
||||
|
||||
if self.debug {
|
||||
println!(
|
||||
console_log!(
|
||||
"=== tail call into {called}/{arity} from {} ===",
|
||||
self.frame.function.as_fn().name()
|
||||
);
|
||||
|
@ -1142,7 +1169,7 @@ impl Creature {
|
|||
let called = self.pop();
|
||||
|
||||
if self.debug {
|
||||
println!("=== calling into {called}/{arity} ===");
|
||||
console_log!("=== calling into {called}/{arity} ===");
|
||||
}
|
||||
|
||||
match called {
|
||||
|
@ -1263,7 +1290,7 @@ impl Creature {
|
|||
}
|
||||
Return => {
|
||||
if self.debug {
|
||||
println!("== returning from {} ==", self.frame.function.show())
|
||||
console_log!("== returning from {} ==", self.frame.function.show())
|
||||
}
|
||||
let mut value = Value::Nothing;
|
||||
swap(&mut self.register[0], &mut value);
|
||||
|
@ -1274,14 +1301,15 @@ impl Creature {
|
|||
self.push(value);
|
||||
}
|
||||
None => {
|
||||
println!("process {} has returned with {}", self.pid, value);
|
||||
// console_log!("process {} has returned with {}", self.pid, value);
|
||||
self.result = Some(Ok(value));
|
||||
self.broadcast_return();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Print => {
|
||||
println!("{}", self.pop().show());
|
||||
console_log!("{}", self.pop().show());
|
||||
self.push(Value::Keyword("ok"));
|
||||
}
|
||||
SetUpvalue => {
|
||||
|
|
60
src/world.rs
60
src/world.rs
|
@ -1,9 +1,11 @@
|
|||
use chumsky::primitive::NoneOf;
|
||||
|
||||
use crate::chunk::Chunk;
|
||||
use crate::value::{Value, Key};
|
||||
use crate::vm::Creature;
|
||||
use crate::panic::Panic;
|
||||
use crate::errors::panic;
|
||||
use crate::js::{random, now};
|
||||
use crate::js::*;
|
||||
use crate::io::{MsgOut, MsgIn, do_io};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
@ -82,6 +84,7 @@ pub struct Zoo {
|
|||
sleeping: HashMap<&'static str, f64>,
|
||||
active_idx: usize,
|
||||
active_id: &'static str,
|
||||
msgs: Vec<String>,
|
||||
}
|
||||
|
||||
impl Zoo {
|
||||
|
@ -95,6 +98,7 @@ impl Zoo {
|
|||
sleeping: HashMap::new(),
|
||||
active_idx: 0,
|
||||
active_id: "",
|
||||
msgs: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +135,11 @@ impl Zoo {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn kill_linked(&mut self, id: &'static str) {
|
||||
self.msgs.push(format!("process :{id} terminated by linked process"));
|
||||
self.kill_list.push(id);
|
||||
}
|
||||
|
||||
pub fn kill(&mut self, id: &'static str) {
|
||||
self.kill_list.push(id);
|
||||
}
|
||||
|
@ -161,7 +170,7 @@ impl Zoo {
|
|||
pub fn clean_up(&mut self) {
|
||||
while let Some(id) = self.kill_list.pop() {
|
||||
if let Some(idx) = self.ids.get(id) {
|
||||
println!("buried process {id}");
|
||||
console_log!("process :{id} terminated");
|
||||
self.procs[*idx] = Status::Empty;
|
||||
self.empty.push(*idx);
|
||||
self.ids.remove(id);
|
||||
|
@ -172,14 +181,14 @@ impl Zoo {
|
|||
self.sleeping
|
||||
.retain(|_, wakeup_time| now() < *wakeup_time);
|
||||
|
||||
println!(
|
||||
"currently sleeping processes: {}",
|
||||
self.sleeping
|
||||
.keys()
|
||||
.map(|id| id.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | ")
|
||||
);
|
||||
// console_log!(
|
||||
// "currently sleeping processes: {}",
|
||||
// self.sleeping
|
||||
// .keys()
|
||||
// .map(|id| id.to_string())
|
||||
// .collect::<Vec<_>>()
|
||||
// .join(" | ")
|
||||
// );
|
||||
}
|
||||
|
||||
pub fn catch(&mut self, id: &'static str) -> Creature {
|
||||
|
@ -362,9 +371,24 @@ impl World {
|
|||
if let Some(fetch) = self.make_fetch_happen() {
|
||||
outbox.push(fetch);
|
||||
}
|
||||
if let Some(msgs) = self.flush_zoo() {
|
||||
outbox.push(msgs);
|
||||
}
|
||||
outbox
|
||||
}
|
||||
|
||||
fn flush_zoo(&mut self) -> Option<MsgOut> {
|
||||
let mut zoo_msgs = vec![];
|
||||
let mut zoo = self.zoo.borrow_mut();
|
||||
swap(&mut zoo_msgs, &mut zoo.msgs);
|
||||
if zoo_msgs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let inner = zoo_msgs.into_iter().map(Value::string).collect::<imbl::Vector<_>>();
|
||||
Some(MsgOut::Console(Value::list(inner)))
|
||||
}
|
||||
}
|
||||
|
||||
fn make_fetch_happen(&self) -> Option<MsgOut> {
|
||||
let out = self.buffers.fetch_out();
|
||||
let working = RefCell::new(Value::Interned(""));
|
||||
|
@ -406,11 +430,13 @@ impl World {
|
|||
// TODO: if we have a panic, actually add the panic message to the console
|
||||
let result = self.active_result().clone().unwrap();
|
||||
self.result = Some(result.clone());
|
||||
let result_msg = match result {
|
||||
Ok(value) => MsgOut::Complete(Value::string(value.show())),
|
||||
Err(p) => MsgOut::Error(panic(p))
|
||||
};
|
||||
outbox.push(result_msg);
|
||||
match result {
|
||||
Ok(value) => outbox.push(MsgOut::Complete(Value::string(value.show()))),
|
||||
Err(p) => {
|
||||
outbox.push(MsgOut::Console(Value::list(imbl::vector!(Value::string("Ludus panicked!".to_string())))));
|
||||
outbox.push(MsgOut::Error(panic(p)))
|
||||
}
|
||||
}
|
||||
outbox
|
||||
}
|
||||
|
||||
|
@ -466,8 +492,8 @@ impl World {
|
|||
fn report_process_end(&mut self) {
|
||||
let result = self.active_result().clone().unwrap();
|
||||
let msg = match result {
|
||||
Ok(value) => format!("process {} returned with {}", self.active_id().unwrap(), value.show()),
|
||||
Err(panic) => format!("process {} panicked with {}", self.active_id().unwrap(), crate::errors::panic(panic))
|
||||
Ok(value) => format!("Process {} returned with {}", self.active_id().unwrap(), value.show()),
|
||||
Err(panic) => format!("Process {} panicked with {}", self.active_id().unwrap(), crate::errors::panic(panic))
|
||||
};
|
||||
self.send_ludus_msg(msg);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user