add sleep, which was unexpectedly titchy!
This commit is contained in:
parent
90505f89fe
commit
8923581eed
|
@ -414,6 +414,7 @@ fn print! {
|
||||||
"Sends a text representation of Ludus values to the console."
|
"Sends a text representation of Ludus values to the console."
|
||||||
(...args) -> {
|
(...args) -> {
|
||||||
let line = do args > map (string, _) > join (_, " ")
|
let line = do args > map (string, _) > join (_, " ")
|
||||||
|
base :print! (args)
|
||||||
update! (console, append (_, line))
|
update! (console, append (_, line))
|
||||||
:ok
|
:ok
|
||||||
}
|
}
|
||||||
|
|
20
sandbox.ld
20
sandbox.ld
|
@ -1,16 +1,20 @@
|
||||||
fn simple_reporter () -> {
|
fn reporter () -> {
|
||||||
print! (self (), msgs ())
|
print! (self (), msgs ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hanger () -> hanger ()
|
fn printer () -> {
|
||||||
|
print!("LUDUS SAYS ==> hi")
|
||||||
|
sleep! (1)
|
||||||
|
printer ()
|
||||||
|
}
|
||||||
|
|
||||||
let foo = spawn! (hanger)
|
|
||||||
let bar = spawn! (simple_reporter)
|
|
||||||
let baz = spawn! (fn () -> panic! :oops)
|
|
||||||
|
|
||||||
send (foo, [:foo, :bar, :baz])
|
let foo = spawn! (printer)
|
||||||
send (bar, (1, 2, 3))
|
let bar = spawn! (reporter)
|
||||||
|
|
||||||
yield! ()
|
send (bar, [:foo, :bar, :baz])
|
||||||
|
|
||||||
|
& yield! ()
|
||||||
|
sleep! (5)
|
||||||
|
|
||||||
:done
|
:done
|
||||||
|
|
|
@ -3,7 +3,7 @@ use imbl::HashMap;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
const DEBUG_SCRIPT_COMPILE: bool = false;
|
const DEBUG_SCRIPT_COMPILE: bool = false;
|
||||||
const DEBUG_SCRIPT_RUN: bool = true;
|
const DEBUG_SCRIPT_RUN: bool = false;
|
||||||
const DEBUG_PRELUDE_COMPILE: bool = false;
|
const DEBUG_PRELUDE_COMPILE: bool = false;
|
||||||
const DEBUG_PRELUDE_RUN: bool = false;
|
const DEBUG_PRELUDE_RUN: bool = false;
|
||||||
|
|
||||||
|
|
13
src/vm.rs
13
src/vm.rs
|
@ -292,14 +292,15 @@ impl Creature {
|
||||||
self.push(Value::Keyword("ok"));
|
self.push(Value::Keyword("ok"));
|
||||||
}
|
}
|
||||||
"spawn" => {
|
"spawn" => {
|
||||||
println!("spawning new process!");
|
|
||||||
let f = args[1].clone();
|
let f = args[1].clone();
|
||||||
let proc = Creature::spawn(f, self.zoo.clone(), self.debug);
|
let proc = Creature::spawn(f, self.zoo.clone(), self.debug);
|
||||||
let id = self.zoo.as_ref().borrow_mut().put(proc);
|
let id = self.zoo.as_ref().borrow_mut().put(proc);
|
||||||
|
println!("spawning new process {id}!");
|
||||||
self.push(Value::Keyword(id));
|
self.push(Value::Keyword(id));
|
||||||
}
|
}
|
||||||
"yield" => {
|
"yield" => {
|
||||||
self.r#yield = true;
|
self.r#yield = true;
|
||||||
|
println!("yielding from {}", self.id);
|
||||||
self.push(Value::Keyword("ok"));
|
self.push(Value::Keyword("ok"));
|
||||||
}
|
}
|
||||||
"alive" => {
|
"alive" => {
|
||||||
|
@ -318,7 +319,15 @@ impl Creature {
|
||||||
self.mbx = VecDeque::new();
|
self.mbx = VecDeque::new();
|
||||||
self.push(Value::Keyword("ok"));
|
self.push(Value::Keyword("ok"));
|
||||||
}
|
}
|
||||||
"sleep" => {}
|
"sleep" => {
|
||||||
|
println!("sleeping {} for {}", self.id, args[1]);
|
||||||
|
let Value::Number(ms) = args[1] else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
self.zoo.as_ref().borrow_mut().sleep(self.id, ms as usize);
|
||||||
|
self.r#yield = true;
|
||||||
|
self.push(Value::Keyword("ok"));
|
||||||
|
}
|
||||||
msg => panic!("Process does not understand message: {msg}"),
|
msg => panic!("Process does not understand message: {msg}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
174
src/world.rs
174
src/world.rs
|
@ -4,7 +4,9 @@ use crate::vm::{Creature, Panic};
|
||||||
use ran::ran_u8;
|
use ran::ran_u8;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::mem::swap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
const ANIMALS: [&str; 24] = [
|
const ANIMALS: [&str; 24] = [
|
||||||
"tortoise",
|
"tortoise",
|
||||||
|
@ -67,7 +69,9 @@ pub struct Zoo {
|
||||||
ids: HashMap<&'static str, usize>,
|
ids: HashMap<&'static str, usize>,
|
||||||
dead: Vec<&'static str>,
|
dead: Vec<&'static str>,
|
||||||
kill_list: Vec<&'static str>,
|
kill_list: Vec<&'static str>,
|
||||||
active: usize,
|
sleeping: HashMap<&'static str, (Instant, Duration)>,
|
||||||
|
active_idx: usize,
|
||||||
|
active_id: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Zoo {
|
impl Zoo {
|
||||||
|
@ -78,7 +82,9 @@ impl Zoo {
|
||||||
ids: HashMap::new(),
|
ids: HashMap::new(),
|
||||||
kill_list: vec![],
|
kill_list: vec![],
|
||||||
dead: vec![],
|
dead: vec![],
|
||||||
active: 0,
|
sleeping: HashMap::new(),
|
||||||
|
active_idx: 0,
|
||||||
|
active_id: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,27 +125,63 @@ impl Zoo {
|
||||||
self.kill_list.push(id);
|
self.kill_list.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sleep(&mut self, id: &'static str, ms: usize) {
|
||||||
|
self.sleeping
|
||||||
|
.insert(id, (Instant::now(), Duration::from_millis(ms as u64)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_alive(&self, id: &'static str) -> bool {
|
||||||
|
if self.kill_list.contains(&id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let idx = self.ids.get(id);
|
||||||
|
match idx {
|
||||||
|
Some(idx) => match self.procs.get(*idx) {
|
||||||
|
Some(proc) => match proc {
|
||||||
|
Status::Empty => false,
|
||||||
|
Status::Borrowed => true,
|
||||||
|
Status::Nested(_) => true,
|
||||||
|
},
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clean_up(&mut self) {
|
pub fn clean_up(&mut self) {
|
||||||
while let Some(id) = self.kill_list.pop() {
|
while let Some(id) = self.kill_list.pop() {
|
||||||
if let Some(idx) = self.ids.get(id) {
|
if let Some(idx) = self.ids.get(id) {
|
||||||
|
println!("buried process {id}");
|
||||||
self.procs[*idx] = Status::Empty;
|
self.procs[*idx] = Status::Empty;
|
||||||
self.empty.push(*idx);
|
self.empty.push(*idx);
|
||||||
self.ids.remove(id);
|
self.ids.remove(id);
|
||||||
self.dead.push(id);
|
self.dead.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.sleeping
|
||||||
|
.retain(|_, (instant, duration)| instant.elapsed() < *duration);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"currently sleeping processes: {}",
|
||||||
|
self.sleeping
|
||||||
|
.keys()
|
||||||
|
.map(|id| id.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" | ")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn catch(&mut self, id: &'static str) -> Creature {
|
pub fn catch(&mut self, id: &'static str) -> Creature {
|
||||||
if let Some(idx) = self.ids.get(id) {
|
if let Some(idx) = self.ids.get(id) {
|
||||||
let mut proc = Status::Borrowed;
|
let mut proc = Status::Borrowed;
|
||||||
std::mem::swap(&mut proc, &mut self.procs[*idx]);
|
swap(&mut proc, &mut self.procs[*idx]);
|
||||||
let Status::Nested(proc) = proc else {
|
let Status::Nested(proc) = proc else {
|
||||||
unreachable!("tried to borrow an empty or already-borrowed process");
|
unreachable!("tried to borrow an empty or already-borrowed process {id}");
|
||||||
};
|
};
|
||||||
proc
|
proc
|
||||||
} else {
|
} else {
|
||||||
unreachable!("tried to borrow a non-existent process");
|
unreachable!("tried to borrow a non-existent process {id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,46 +189,36 @@ impl Zoo {
|
||||||
let id = proc.id;
|
let id = proc.id;
|
||||||
if let Some(idx) = self.ids.get(id) {
|
if let Some(idx) = self.ids.get(id) {
|
||||||
let mut proc = Status::Nested(proc);
|
let mut proc = Status::Nested(proc);
|
||||||
std::mem::swap(&mut proc, &mut self.procs[*idx]);
|
swap(&mut proc, &mut self.procs[*idx]);
|
||||||
} else {
|
}
|
||||||
unreachable!("tried to return a process the world doesn't know about");
|
// Removed because, well, we shouldn't have creatures we don't know about
|
||||||
|
// And since zoo.next now cleans (and thus kills) before the world releases its active process
|
||||||
|
// We'll die if we execute this check
|
||||||
|
// else {
|
||||||
|
// unreachable!("tried to return a process the world doesn't know about");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_available(&self) -> bool {
|
||||||
|
match &self.procs[self.active_idx] {
|
||||||
|
Status::Empty => false,
|
||||||
|
Status::Borrowed => false,
|
||||||
|
Status::Nested(proc) => !self.sleeping.contains_key(proc.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self, curr_id: &'static str) -> &'static str {
|
pub fn next(&mut self) -> &'static str {
|
||||||
println!("getting next process from {curr_id}");
|
self.active_idx = (self.active_idx + 1) % self.procs.len();
|
||||||
println!(
|
while !self.is_available() {
|
||||||
"current procs in zoo:\n{}",
|
self.clean_up();
|
||||||
self.procs
|
self.active_idx = (self.active_idx + 1) % self.procs.len();
|
||||||
.iter()
|
println!(
|
||||||
.map(|proc| proc.to_string())
|
"testing process availability: {}",
|
||||||
.collect::<Vec<_>>()
|
self.procs[self.active_idx]
|
||||||
.join("//")
|
|
||||||
);
|
|
||||||
println!("ids: {:?}", self.ids);
|
|
||||||
let idx = self.ids.get(curr_id).unwrap();
|
|
||||||
println!("current idx: {idx}");
|
|
||||||
if *idx != self.active {
|
|
||||||
panic!(
|
|
||||||
"tried to get next creature after {curr_id} while {} is active",
|
|
||||||
self.active
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.active = (self.active + 1) % self.procs.len();
|
match &self.procs[self.active_idx] {
|
||||||
println!("active idx is now: {}", self.active);
|
Status::Empty | Status::Borrowed => unreachable!(),
|
||||||
while self.procs[self.active] == Status::Empty {
|
|
||||||
let new_active_idx = (self.active + 1) % self.procs.len();
|
|
||||||
println!("new active idx: {new_active_idx}");
|
|
||||||
println!("new active process is: {}", self.procs[new_active_idx]);
|
|
||||||
self.active = (self.active + 1) % self.procs.len();
|
|
||||||
}
|
|
||||||
println!("found next proc: {}", &self.procs[self.active]);
|
|
||||||
match &self.procs[self.active] {
|
|
||||||
Status::Empty => unreachable!(),
|
|
||||||
Status::Borrowed => panic!(
|
|
||||||
"encountered unexpectedly borrowed process at idx {}",
|
|
||||||
self.active
|
|
||||||
),
|
|
||||||
Status::Nested(proc) => proc.id,
|
Status::Nested(proc) => proc.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,26 +263,42 @@ impl World {
|
||||||
// proc.receive(msg);
|
// proc.receive(msg);
|
||||||
// self.zoo.release(proc);
|
// self.zoo.release(proc);
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
fn next(&mut self) {
|
fn next(&mut self) {
|
||||||
let id = self
|
|
||||||
.zoo
|
|
||||||
.as_ref()
|
|
||||||
.borrow_mut()
|
|
||||||
.next(self.active.as_ref().unwrap().id);
|
|
||||||
println!("next id is {id}");
|
|
||||||
let mut active = None;
|
let mut active = None;
|
||||||
std::mem::swap(&mut active, &mut self.active);
|
swap(&mut active, &mut self.active);
|
||||||
let mut holding_pen = self.zoo.as_ref().borrow_mut().catch(id);
|
let mut zoo = self.zoo.as_ref().borrow_mut();
|
||||||
let mut active = active.unwrap();
|
zoo.release(active.unwrap());
|
||||||
std::mem::swap(&mut active, &mut holding_pen);
|
// at the moment, active is None, process is released.
|
||||||
println!("now in the holding pen: {}", holding_pen.id);
|
// zoo should NOT need an id--it has a representation of the current active process
|
||||||
holding_pen.reset_reductions();
|
// world has an active process for memory reasons
|
||||||
self.zoo.as_ref().borrow_mut().release(holding_pen);
|
// not for state-keeping reasons
|
||||||
let mut active = Some(active);
|
let new_active_id = zoo.next();
|
||||||
std::mem::swap(&mut active, &mut self.active);
|
let mut new_active_proc = zoo.catch(new_active_id);
|
||||||
|
new_active_proc.reset_reductions();
|
||||||
|
let mut new_active_opt = Some(new_active_proc);
|
||||||
|
swap(&mut new_active_opt, &mut self.active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn old_next(&mut self) {
|
||||||
|
// let id = self
|
||||||
|
// .zoo
|
||||||
|
// .as_ref()
|
||||||
|
// .borrow_mut()
|
||||||
|
// .next(self.active.as_ref().unwrap().id);
|
||||||
|
// println!("next id is {id}");
|
||||||
|
// let mut active = None;
|
||||||
|
// std::mem::swap(&mut active, &mut self.active);
|
||||||
|
// let mut holding_pen = self.zoo.as_ref().borrow_mut().catch(id);
|
||||||
|
// let mut active = active.unwrap();
|
||||||
|
// std::mem::swap(&mut active, &mut holding_pen);
|
||||||
|
// println!("now in the holding pen: {}", holding_pen.id);
|
||||||
|
// holding_pen.reset_reductions();
|
||||||
|
// self.zoo.as_ref().borrow_mut().release(holding_pen);
|
||||||
|
// let mut active = Some(active);
|
||||||
|
// std::mem::swap(&mut active, &mut self.active);
|
||||||
|
// }
|
||||||
|
|
||||||
// pub fn sleep(&mut self, id: &'static str) {
|
// pub fn sleep(&mut self, id: &'static str) {
|
||||||
// // check if the id is the actually active process
|
// // check if the id is the actually active process
|
||||||
// if self.active.id != id {
|
// if self.active.id != id {
|
||||||
|
@ -299,16 +347,15 @@ impl World {
|
||||||
&self.active.as_ref().unwrap().result
|
&self.active.as_ref().unwrap().result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean_up(&mut self) {
|
|
||||||
self.zoo.as_ref().borrow_mut().clean_up()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
self.activate_main();
|
self.activate_main();
|
||||||
loop {
|
loop {
|
||||||
println!("entering world loop");
|
println!(
|
||||||
|
"entering world loop; active process is {}",
|
||||||
|
self.active_id()
|
||||||
|
);
|
||||||
self.active.as_mut().unwrap().interpret();
|
self.active.as_mut().unwrap().interpret();
|
||||||
println!("interpreted loop");
|
println!("yielded from {}", self.active_id());
|
||||||
match self.active_result() {
|
match self.active_result() {
|
||||||
None => (),
|
None => (),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
|
@ -316,12 +363,13 @@ impl World {
|
||||||
self.result = self.active_result().clone();
|
self.result = self.active_result().clone();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
println!("process died: {}", self.active_id());
|
||||||
self.kill_active();
|
self.kill_active();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("getting next process");
|
println!("getting next process");
|
||||||
self.next();
|
self.next();
|
||||||
self.clean_up();
|
// self.clean_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user