refactor to have a world run a process

This commit is contained in:
Scott Richmond 2025-06-26 16:11:35 -04:00
parent b5528ced8f
commit b35657e698
4 changed files with 159 additions and 60 deletions

View File

@ -1,4 +1 @@
repeat 1 { :foobar
fd! (100)
rt! (0.25)
}

View File

@ -8,7 +8,9 @@ const DEBUG_PRELUDE_COMPILE: bool = false;
const DEBUG_PRELUDE_RUN: bool = false; const DEBUG_PRELUDE_RUN: bool = false;
mod base; mod base;
mod world; mod world;
use crate::world::World;
mod spans; mod spans;
use crate::spans::Spanned; use crate::spans::Spanned;
@ -144,8 +146,11 @@ pub fn ludus(src: String) -> String {
let vm_chunk = compiler.chunk; let vm_chunk = compiler.chunk;
let mut vm = Creature::new(vm_chunk, DEBUG_SCRIPT_RUN); let vm = Creature::new(vm_chunk, DEBUG_SCRIPT_RUN);
let result = vm.run(); let grip = World::new(vm);
grip.borrow_mut().run();
let world = grip.borrow();
let result = world.result.clone().unwrap();
let console = postlude.get("console").unwrap(); let console = postlude.get("console").unwrap();
let Value::Box(console) = console else { let Value::Box(console) = console else {
@ -165,7 +170,6 @@ pub fn ludus(src: String) -> String {
unreachable!() unreachable!()
}; };
let commands = commands.borrow(); let commands = commands.borrow();
dbg!(&commands);
let commands = commands.to_json().unwrap(); let commands = commands.to_json().unwrap();
let output = match result { let output = match result {
@ -176,7 +180,7 @@ pub fn ludus(src: String) -> String {
} }
}; };
if DEBUG_SCRIPT_RUN { if DEBUG_SCRIPT_RUN {
vm.print_stack(); // vm.print_stack();
} }
// TODO: use serde_json to make this more robust? // TODO: use serde_json to make this more robust?

View File

@ -4,13 +4,17 @@ use crate::op::Op;
use crate::parser::Ast; use crate::parser::Ast;
use crate::spans::Spanned; use crate::spans::Spanned;
use crate::value::{LFn, Value}; use crate::value::{LFn, Value};
use crate::world::Grasp;
use imbl::{HashMap, Vector}; use imbl::{HashMap, Vector};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::mem::swap; use std::mem::swap;
use std::rc::Rc; use std::rc::Rc;
const MAX_REDUCTIONS: usize = 100;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Panic { pub enum Panic {
Str(&'static str), Str(&'static str),
@ -86,6 +90,9 @@ pub struct Creature {
debug: bool, debug: bool,
last_code: usize, last_code: usize,
pub id: &'static str, pub id: &'static str,
pub world: Grasp,
pub mbx: VecDeque<Value>,
pub reductions: usize,
} }
impl Creature { impl Creature {
@ -117,9 +124,20 @@ impl Creature {
debug, debug,
last_code: 0, last_code: 0,
id: "", id: "",
world: None,
mbx: VecDeque::new(),
reductions: 0,
} }
} }
pub fn reduce(&mut self) {
self.reductions += 1;
}
pub fn receive(&mut self, value: Value) {
self.mbx.push_back(value);
}
pub fn chunk(&self) -> &Chunk { pub fn chunk(&self) -> &Chunk {
self.frame.chunk() self.frame.chunk()
} }
@ -225,6 +243,9 @@ impl Creature {
self.result = Some(Ok(self.stack.pop().unwrap())); self.result = Some(Ok(self.stack.pop().unwrap()));
return; return;
} }
if self.reductions >= MAX_REDUCTIONS {
return;
}
let code = self.read(); let code = self.read();
if self.debug { if self.debug {
self.last_code = self.ip - 1; self.last_code = self.ip - 1;

View File

@ -1,10 +1,11 @@
use crate::value::Value; use crate::value::Value;
use crate::vm::{Creature, Panic}; use crate::vm::{Creature, Panic};
use ran::ran_u8; use ran::ran_u8;
use std::collections::{HashMap, VecDeque}; use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
const ANIMALS: [&str; 24] = [ const ANIMALS: [&str; 24] = [
"turtle",
"tortoise", "tortoise",
"hare", "hare",
"squirrel", "squirrel",
@ -28,6 +29,7 @@ const ANIMALS: [&str; 24] = [
"giraffe", "giraffe",
"leopard", "leopard",
"lion", "lion",
"hippopotamus",
]; ];
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -43,6 +45,7 @@ struct Zoo {
empty: Vec<usize>, empty: Vec<usize>,
ids: HashMap<&'static str, usize>, ids: HashMap<&'static str, usize>,
dead: Vec<&'static str>, dead: Vec<&'static str>,
active: usize,
} }
impl Zoo { impl Zoo {
@ -52,14 +55,28 @@ impl Zoo {
empty: vec![], empty: vec![],
ids: HashMap::new(), ids: HashMap::new(),
dead: vec![], dead: vec![],
active: 0,
} }
} }
fn random_id(&self) -> String {
let rand = ran_u8() as usize % 24;
let idx = self.procs.len();
format!("{}_{idx}", ANIMALS[rand])
}
fn new_id(&self) -> &'static str {
let mut new = self.random_id();
while self.dead.iter().any(|old| *old == new) {
new = self.random_id();
}
new.leak()
}
pub fn put(&mut self, mut proc: Creature) -> &'static str { pub fn put(&mut self, mut proc: Creature) -> &'static str {
if self.empty.is_empty() { if self.empty.is_empty() {
let rand = ran_u8() as usize % 24; let id = self.new_id();
let idx = self.procs.len(); let idx = self.procs.len();
let id = format!("{}_{idx}", ANIMALS[rand]).leak();
proc.id = id; proc.id = id;
self.procs.push(Status::Nested(proc)); self.procs.push(Status::Nested(proc));
self.ids.insert(id, idx); self.ids.insert(id, idx);
@ -106,76 +123,136 @@ impl Zoo {
unreachable!("tried to return a process the world doesn't know about"); unreachable!("tried to return a process the world doesn't know about");
} }
} }
pub fn next(&mut self, curr_id: &'static str) -> &'static str {
let idx = self.ids.get(curr_id).unwrap();
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();
while self.procs[self.active] != Status::Empty {
self.active = (self.active + 1) % self.procs.len();
}
match &self.procs[self.active] {
Status::Empty => unreachable!(),
Status::Borrowed => panic!(
"encountered unexpectedly borrowed process at idx {}",
self.active
),
Status::Nested(proc) => proc.id,
}
}
} }
pub type Grasp = Option<Rc<RefCell<World>>>;
#[derive(Debug, Clone, PartialEq)]
pub struct World { pub struct World {
procs: Zoo, zoo: Zoo,
mbxes: HashMap<String, VecDeque<Value>>, active: Option<Creature>,
active: Creature,
// TODO: we need a lifetime here
main: &'static str, main: &'static str,
handle: Grasp,
pub result: Option<Result<Value, Panic>>,
} }
impl World { impl World {
pub fn new(proc: Creature) -> World { pub fn new(proc: Creature) -> Rc<RefCell<World>> {
let mut creatures = Zoo::new(); let mut zoo = Zoo::new();
let id = creatures.put(proc); let id = zoo.put(proc);
let caught = creatures.catch(id); let world = World {
World { zoo,
procs: creatures, active: None,
mbxes: HashMap::new(),
active: caught,
main: id, main: id,
} handle: None,
result: None,
};
let handle = Rc::new(RefCell::new(world));
let grasped = handle.clone();
let mut world = grasped.as_ref().borrow_mut();
world.handle = Some(grasped.clone());
let mut caught = world.zoo.catch(id);
caught.world = world.handle.clone();
world.zoo.release(caught);
handle
} }
pub fn spawn(&mut self, proc: Creature) -> Value { pub fn spawn(&mut self, proc: Creature) -> Value {
let id = self.procs.put(proc); let id = self.zoo.put(proc);
Value::Keyword(id) Value::Keyword(id)
} }
pub fn send_msg(&mut self, id: &'static str, msg: Value) { pub fn send_msg(&mut self, id: &'static str, msg: Value) {
let mbx = self.mbxes.get_mut(id).unwrap(); let mut proc = self.zoo.catch(id);
mbx.push_back(msg); proc.receive(msg);
self.zoo.release(proc);
} }
pub fn sleep(&mut self, id: &'static str) { fn next(&mut self) {
// check if the id is the actually active process let id = self.zoo.next(self.active.as_ref().unwrap().id);
// return it to the nursery let mut active = None;
// get the next process from the nursery std::mem::swap(&mut active, &mut self.active);
let mut holding_pen = self.zoo.catch(id);
let mut active = active.unwrap();
std::mem::swap(&mut active, &mut holding_pen);
self.zoo.release(holding_pen);
let mut active = Some(active);
std::mem::swap(&mut active, &mut self.active);
} }
pub fn get_msg(&self, id: &'static str) -> Option<(usize, Value)> { // pub fn sleep(&mut self, id: &'static str) {
// check if the id is of the active process // // check if the id is the actually active process
todo!() // if self.active.id != id {
} // panic!("attempted to sleep a process from outside that process: active = {}; to sleep: = {id}", self.active.id);
// }
// self.next(id);
// }
pub fn match_msg(&mut self, id: &'static str, idx: usize) { // pub fn panic(&mut self, id: &'static str, panic: Panic) {
// again, check for activity // // TODO: devise some way of linking processes (study the BEAM on this)
// delete the message at idx, which we gave along with the value as the tuple in get_msg // // check if the id is active
} // if self.active.id != id {
// panic!("attempted to panic from a process from outside that process: active = {}; panicking = {id}; panic = {panic}", self.active.id);
// }
// // check if the process is `main`, and crash the program if it is
// if self.main == id {
// self.result = self.active.result.clone();
// }
// // kill the process
// self.zoo.kill(id);
// self.next(id);
// }
pub fn r#yield(&mut self, id: &'static str) { // pub fn complete(&mut self) {
// check if the id is active // if self.main == self.active.id {
// swap out the currently active process for the next one // self.result = self.active.result.clone();
} // }
// self.next(id);
// }
pub fn panic(&mut self, id: &'static str) { pub fn run(&mut self) {
// TODO: devise some way of linking processes (study the BEAM on this) loop {
// check if the id is active if self.active.is_none() {
// check if the process is `main`, and crash the program if it is let main = self.zoo.catch(self.main);
// kill the process self.active = Some(main);
// swap out this process for the next one
} }
self.active.as_mut().unwrap().interpret();
pub fn complete(&mut self, id: &'static str, value: Value) { match self.active.as_ref().unwrap().result {
// check if the id is active None => (),
// check if the process is main Some(_) => {
// if it is: stash the value somehow and exit the program cleanly if self.active.as_ref().unwrap().id == self.main {
self.result = self.active.as_ref().unwrap().result.clone();
return;
}
self.zoo.kill(self.active.as_ref().unwrap().id);
}
}
self.next();
} }
pub fn run(&mut self) -> Result<Value, Panic> {
todo!()
} }
// TODO: // TODO: