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
send
msgs
spawn!
yield!
sleep!
alive?
flush!
flush_i!
link!

View File

@ -1065,3 +1065,13 @@ yield! ()
fn id (x) -> x
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) -> {
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 {
fn foo (val) -> receive {
(:report) -> {
print! ("LUDUS SAYS ==> value is {val}")
flush! ()
foo? (val)
foo (val)
}
(:set, x) -> {
print! ("LUDUS SAYS ==> foo! was {val}, now is {x}")
flush! ()
foo? (x)
foo (x)
}
(:get, pid) -> {
print! ("LUDUS SAYS ==> value is {val}")
send (pid, (:response, val))
flush! ()
foo? (val)
foo (val)
}
x -> print! ("LUDUS SAYS ==> no match, got {x}")
})
}
let foo = spawn! (fn () -> foo? (42))
print! (foo)
send (foo, (:set, 23))
let fooer = spawn! (fn () -> foo (42))
print! (fooer)
send (fooer, (:set, 23))
yield! ()
send (foo, (:get, self ()))
send (fooer, (:get, self ()))
yield! ()
fn id (x) -> x
receive(id)
flush! ()

View File

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

View File

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

View File

@ -750,7 +750,7 @@ impl Compiler {
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
}
Splattern(patt) => self.visit(patt),
InterpolatedPattern(parts, _) => {
InterpolatedPattern(parts) => {
// println!("An interpolated pattern of {} parts", parts.len());
let mut pattern = "".to_string();
let mut words = vec![];
@ -1038,6 +1038,52 @@ impl Compiler {
self.emit_op(Op::Load);
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!(),
Fn(name, body, doc) => {
let is_anon = name.is_empty();
@ -1258,7 +1304,7 @@ impl Compiler {
let jump_back = self.stub_jump(Op::JumpBack);
// set jump points
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.emit_constant(Value::Nil);
self.tail_pos = tail_pos;

View File

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

View File

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

View File

@ -93,6 +93,7 @@ pub struct Creature {
last_code: usize,
pub pid: &'static str,
pub mbx: VecDeque<Value>,
msg_idx: usize,
pub reductions: usize,
pub zoo: Rc<RefCell<Zoo>>,
pub r#yield: bool,
@ -141,6 +142,7 @@ impl Creature {
mbx: VecDeque::new(),
reductions: 0,
r#yield: false,
msg_idx: 0,
}
}
@ -274,18 +276,6 @@ impl Creature {
};
match *msg {
"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" => {
let Value::Keyword(pid) = args[1] else {
return self.panic("malformed pid");
@ -331,9 +321,18 @@ impl Creature {
}
"link" => todo!(),
"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();
println!("flushing messages in {}", self.pid);
self.push(Value::Keyword("ok"));
self.push(Value::List(Box::new(msgs)));
}
"sleep" => {
println!("sleeping {} for {}", self.pid, args[1]);
@ -1220,6 +1219,34 @@ impl Creature {
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;
}
}
}
}