make progress, I guess
This commit is contained in:
parent
db52bc2687
commit
48342ba4ea
|
@ -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!
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
34
sandbox.ld
34
sandbox.ld
|
@ -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! ()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
53
src/vm.rs
53
src/vm.rs
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user