make progress, I guess
This commit is contained in:
parent
db52bc2687
commit
48342ba4ea
|
@ -1261,13 +1261,11 @@ fn sleep! {
|
|||
#{
|
||||
self
|
||||
send
|
||||
msgs
|
||||
spawn!
|
||||
yield!
|
||||
sleep!
|
||||
alive?
|
||||
flush!
|
||||
flush_i!
|
||||
|
||||
link!
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
34
sandbox.ld
34
sandbox.ld
|
@ -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! ()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}")
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
53
src/vm.rs
53
src/vm.rs
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user