make progress, I guess

This commit is contained in:
Scott Richmond 2025-06-27 20:41:29 -04:00
parent db52bc2687
commit 48342ba4ea
9 changed files with 127 additions and 44 deletions

View File

@ -1261,13 +1261,11 @@ fn sleep! {
#{ #{
self self
send send
msgs
spawn! spawn!
yield! yield!
sleep! sleep!
alive? alive?
flush! flush!
flush_i!
link! link!

View File

@ -1065,3 +1065,13 @@ yield! ()
fn id (x) -> x fn id (x) -> x
receive(id) receive(id)
``` ```
#### some time later
I've started work on `receive`.
I've got all the stuff wired up, and it seems to all work (and was pretty straightforward!).
EXCEPT: I've got a difficult off-by-one error.
The problem is being in a receive in a tight loop/tail call, where the ip doesn't advance past the tail call back to the top of the function.
Jumping back to the beginning of the loop advances the message counter by one.
Basically, after the first time we've matched, we keep skipping item 0.
So: what I need to do is to figure out the right order of operations for.
This is just stepwise logic, and some titchy state management.

View File

@ -1,35 +1,25 @@
fn receive (receiver) -> { fn foo (val) -> receive {
print! ("receiving in", self (), "with msgs", msgs())
if empty? (msgs ())
then {yield! (); receive (receiver)}
else do msgs () > first > receiver
}
fn foo? (val) -> receive (fn (msg) -> match report!("scrutinee is", msg) with {
(:report) -> { (:report) -> {
print! ("LUDUS SAYS ==> value is {val}") print! ("LUDUS SAYS ==> value is {val}")
flush! () foo (val)
foo? (val)
} }
(:set, x) -> { (:set, x) -> {
print! ("LUDUS SAYS ==> foo! was {val}, now is {x}") print! ("LUDUS SAYS ==> foo! was {val}, now is {x}")
flush! () foo (x)
foo? (x)
} }
(:get, pid) -> { (:get, pid) -> {
print! ("LUDUS SAYS ==> value is {val}") print! ("LUDUS SAYS ==> value is {val}")
send (pid, (:response, val)) send (pid, (:response, val))
flush! () foo (val)
foo? (val)
} }
x -> print! ("LUDUS SAYS ==> no match, got {x}") }
})
let foo = spawn! (fn () -> foo? (42)) let fooer = spawn! (fn () -> foo (42))
print! (foo) print! (fooer)
send (foo, (:set, 23)) send (fooer, (:set, 23))
yield! () yield! ()
send (foo, (:get, self ())) send (fooer, (:get, self ()))
yield! () yield! ()
fn id (x) -> x
receive(id) flush! ()

View File

@ -1,4 +1,3 @@
use crate::parser::StringMatcher;
use crate::spans::*; use crate::spans::*;
use std::fmt; use std::fmt;
@ -164,7 +163,7 @@ impl Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(" ") .join(" ")
), ),
When(clauses) => format!( When(clauses) | Receive(clauses) => format!(
"when {{\n {}\n}}", "when {{\n {}\n}}",
clauses clauses
.iter() .iter()
@ -321,7 +320,7 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
When(clauses) => write!( When(clauses) | Receive(clauses) => write!(
f, f,
"When: [{}]", "When: [{}]",
clauses clauses

View File

@ -37,7 +37,7 @@ impl Chunk {
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString | Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
| ConcatStrings | Stringify | MatchType | Return | UnconditionalMatch | Print | ConcatStrings | Stringify | MatchType | Return | UnconditionalMatch | Print
| AppendList | ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing | AppendList | ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing
| PushGlobal | SetUpvalue => { | PushGlobal | SetUpvalue | LoadMessage | NextMessage | MatchMessage => {
println!("{i:04}: {op}") println!("{i:04}: {op}")
} }
Constant | MatchConstant => { Constant | MatchConstant => {

View File

@ -750,7 +750,7 @@ impl Compiler {
self.patch_jump(jump_idx, self.len() - jump_idx - 3); self.patch_jump(jump_idx, self.len() - jump_idx - 3);
} }
Splattern(patt) => self.visit(patt), Splattern(patt) => self.visit(patt),
InterpolatedPattern(parts, _) => { InterpolatedPattern(parts) => {
// println!("An interpolated pattern of {} parts", parts.len()); // println!("An interpolated pattern of {} parts", parts.len());
let mut pattern = "".to_string(); let mut pattern = "".to_string();
let mut words = vec![]; let mut words = vec![];
@ -1038,6 +1038,52 @@ impl Compiler {
self.emit_op(Op::Load); self.emit_op(Op::Load);
self.stack_depth += 1; self.stack_depth += 1;
} }
Receive(clauses) => {
let tail_pos = self.tail_pos;
let receive_begin = self.len();
self.emit_op(Op::LoadMessage);
self.stack_depth += 1;
let stack_depth = self.stack_depth;
let mut jump_idxes = vec![];
let mut clauses = clauses.iter();
while let Some((MatchClause(pattern, guard, body), _)) = clauses.next() {
self.tail_pos = false;
let mut no_match_jumps = vec![];
self.enter_scope();
// TODO: should this be self.reset_match()?
self.match_depth = 0;
self.visit(pattern);
no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch));
if guard.is_some() {
let guard_expr: &'static Spanned<Ast> =
Box::leak(Box::new(guard.clone().unwrap()));
self.visit(guard_expr);
no_match_jumps.push(self.stub_jump(Op::JumpIfFalse));
}
self.tail_pos = tail_pos;
self.emit_op(Op::MatchMessage);
self.visit(body);
self.store();
self.leave_scope();
self.pop_n(self.stack_depth - stack_depth);
jump_idxes.push(self.stub_jump(Op::Jump));
for idx in no_match_jumps {
self.patch_jump(idx, self.len() - idx - 3);
}
}
// TODO: get the next message
self.emit_op(Op::NextMessage);
// TODO: jump back to the "get a message" instruction
let jump_back = self.stub_jump(Op::JumpBack);
self.patch_jump(jump_back, self.len() - receive_begin - 3);
for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 3);
}
self.pop_n(self.stack_depth - stack_depth);
self.emit_op(Op::Load);
self.stack_depth += 1;
}
MatchClause(..) => unreachable!(), MatchClause(..) => unreachable!(),
Fn(name, body, doc) => { Fn(name, body, doc) => {
let is_anon = name.is_empty(); let is_anon = name.is_empty();
@ -1258,7 +1304,7 @@ impl Compiler {
let jump_back = self.stub_jump(Op::JumpBack); let jump_back = self.stub_jump(Op::JumpBack);
// set jump points // set jump points
self.patch_jump(jump_back, self.len() - repeat_begin - 2); self.patch_jump(jump_back, self.len() - repeat_begin - 2);
self.patch_jump(jiz_idx, self.len() - repeat_begin - 4); self.patch_jump(jiz_idx, self.len() - jiz_idx - 3);
self.pop(); self.pop();
self.emit_constant(Value::Nil); self.emit_constant(Value::Nil);
self.tail_pos = tail_pos; self.tail_pos = tail_pos;

View File

@ -89,6 +89,10 @@ pub enum Op {
GetUpvalue, GetUpvalue,
Msg, Msg,
LoadMessage,
NextMessage,
MatchMessage,
// Inc, // Inc,
// Dec, // Dec,
// Gt, // Gt,
@ -220,6 +224,10 @@ impl std::fmt::Display for Op {
SetUpvalue => "set_upvalue", SetUpvalue => "set_upvalue",
GetUpvalue => "get_upvalue", GetUpvalue => "get_upvalue",
LoadMessage => "load_message",
NextMessage => "next_message",
MatchMessage => "clear_message",
}; };
write!(f, "{rep}") write!(f, "{rep}")
} }

View File

@ -364,6 +364,11 @@ impl<'a> Validator<'a> {
self.visit(clause); self.visit(clause);
} }
} }
Receive(clauses) => {
for clause in clauses {
self.visit(clause);
}
}
FnDeclaration(name) => { FnDeclaration(name) => {
let tailpos = self.status.tail_position; let tailpos = self.status.tail_position;
self.status.tail_position = false; self.status.tail_position = false;
@ -520,7 +525,7 @@ impl<'a> Validator<'a> {
self.bind(name.to_string()); self.bind(name.to_string());
} }
}, },
InterpolatedPattern(parts, _) => { InterpolatedPattern(parts) => {
for (part, span) in parts { for (part, span) in parts {
if let StringPart::Word(name) = part { if let StringPart::Word(name) = part {
self.span = span; self.span = span;

View File

@ -93,6 +93,7 @@ pub struct Creature {
last_code: usize, last_code: usize,
pub pid: &'static str, pub pid: &'static str,
pub mbx: VecDeque<Value>, pub mbx: VecDeque<Value>,
msg_idx: usize,
pub reductions: usize, pub reductions: usize,
pub zoo: Rc<RefCell<Zoo>>, pub zoo: Rc<RefCell<Zoo>>,
pub r#yield: bool, pub r#yield: bool,
@ -141,6 +142,7 @@ impl Creature {
mbx: VecDeque::new(), mbx: VecDeque::new(),
reductions: 0, reductions: 0,
r#yield: false, r#yield: false,
msg_idx: 0,
} }
} }
@ -274,18 +276,6 @@ impl Creature {
}; };
match *msg { match *msg {
"self" => self.push(Value::Keyword(self.pid)), "self" => self.push(Value::Keyword(self.pid)),
"msgs" => {
let msgs = self.mbx.iter().cloned().collect::<Vec<_>>();
let msgs = Vector::from(msgs);
println!(
"delivering messages: {}",
msgs.iter()
.map(|x| x.show())
.collect::<Vec<_>>()
.join(" | ")
);
self.push(Value::List(Box::new(msgs)));
}
"send" => { "send" => {
let Value::Keyword(pid) = args[1] else { let Value::Keyword(pid) = args[1] else {
return self.panic("malformed pid"); return self.panic("malformed pid");
@ -331,9 +321,18 @@ impl Creature {
} }
"link" => todo!(), "link" => todo!(),
"flush" => { "flush" => {
let msgs = self.mbx.iter().cloned().collect::<Vec<_>>();
let msgs = Vector::from(msgs);
println!(
"delivering messages: {}",
msgs.iter()
.map(|x| x.show())
.collect::<Vec<_>>()
.join(" | ")
);
self.mbx = VecDeque::new(); self.mbx = VecDeque::new();
println!("flushing messages in {}", self.pid); println!("flushing messages in {}", self.pid);
self.push(Value::Keyword("ok")); self.push(Value::List(Box::new(msgs)));
} }
"sleep" => { "sleep" => {
println!("sleeping {} for {}", self.pid, args[1]); println!("sleeping {} for {}", self.pid, args[1]);
@ -1220,6 +1219,34 @@ impl Creature {
unreachable!(); unreachable!();
} }
} }
NextMessage => {
self.msg_idx += 1;
}
LoadMessage => {
println!("loading message {} in {}", self.msg_idx, self.pid);
match self.mbx.get(self.msg_idx) {
Some(msg) => {
println!("loaded message: {msg}");
self.push(msg.clone())
}
None => {
println!("no more messages in {}", self.pid);
self.msg_idx = 0;
self.r#yield = true;
}
}
}
MatchMessage => {
self.msg_idx = 0;
let matched = self.mbx.remove(self.msg_idx).unwrap();
println!(
"matched in {}: @idx {}, msg {matched}",
self.pid, self.msg_idx
);
}
ClearMessage => {
self.msg_idx = 0;
}
} }
} }
} }