method syntax sugar achieved
This commit is contained in:
parent
12389ae371
commit
0cd682de21
|
@ -425,7 +425,7 @@ function __wbg_get_imports() {
|
||||||
_assertBoolean(ret);
|
_assertBoolean(ret);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper7701 = function() { return logError(function (arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper7779 = function() { return logError(function (arg0, arg1, arg2) {
|
||||||
const ret = makeMutClosure(arg0, arg1, 347, __wbg_adapter_22);
|
const ret = makeMutClosure(arg0, arg1, 347, __wbg_adapter_22);
|
||||||
return ret;
|
return ret;
|
||||||
}, arguments) };
|
}, arguments) };
|
||||||
|
|
Binary file not shown.
|
@ -34,6 +34,7 @@ pub enum Ast {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Number(f64),
|
Number(f64),
|
||||||
Keyword(&'static str),
|
Keyword(&'static str),
|
||||||
|
Method(&'static str, Box<Spanned<Self>>),
|
||||||
Word(&'static str),
|
Word(&'static str),
|
||||||
String(&'static str),
|
String(&'static str),
|
||||||
Interpolated(Vec<Spanned<StringPart>>),
|
Interpolated(Vec<Spanned<StringPart>>),
|
||||||
|
@ -103,6 +104,7 @@ impl Ast {
|
||||||
Boolean(b) | BooleanPattern(b) => b.to_string(),
|
Boolean(b) | BooleanPattern(b) => b.to_string(),
|
||||||
Number(n) | NumberPattern(n) => n.to_string(),
|
Number(n) | NumberPattern(n) => n.to_string(),
|
||||||
Keyword(k) | KeywordPattern(k) => format!(":{k}"),
|
Keyword(k) | KeywordPattern(k) => format!(":{k}"),
|
||||||
|
Method(m, args) => format!("::{m} {}", args.0),
|
||||||
Word(w) | WordPattern(w) => w.to_string(),
|
Word(w) | WordPattern(w) => w.to_string(),
|
||||||
Block(lines) => {
|
Block(lines) => {
|
||||||
let mut out = "{\n".to_string();
|
let mut out = "{\n".to_string();
|
||||||
|
@ -260,6 +262,7 @@ impl fmt::Display for Ast {
|
||||||
Boolean(b) => write!(f, "Boolean: {}", b),
|
Boolean(b) => write!(f, "Boolean: {}", b),
|
||||||
Number(n) => write!(f, "Number: {}", n),
|
Number(n) => write!(f, "Number: {}", n),
|
||||||
Keyword(k) => write!(f, "Keyword: :{}", k),
|
Keyword(k) => write!(f, "Keyword: :{}", k),
|
||||||
|
Method(m, args) => write!(f, "Method: ::{m} ({})", args.0),
|
||||||
Word(w) => write!(f, "Word: {}", w),
|
Word(w) => write!(f, "Word: {}", w),
|
||||||
Block(b) => write!(
|
Block(b) => write!(
|
||||||
f,
|
f,
|
||||||
|
|
|
@ -37,7 +37,8 @@ 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 | LoadMessage | NextMessage | MatchMessage | ClearMessage => {
|
| PushGlobal | SetUpvalue | LoadMessage | NextMessage | MatchMessage | ClearMessage
|
||||||
|
| SendMethod => {
|
||||||
println!("{i:04}: {op}")
|
println!("{i:04}: {op}")
|
||||||
}
|
}
|
||||||
Constant | MatchConstant => {
|
Constant | MatchConstant => {
|
||||||
|
|
|
@ -860,6 +860,14 @@ impl Compiler {
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
self.report_depth("after keyword access");
|
self.report_depth("after keyword access");
|
||||||
}
|
}
|
||||||
|
(Keyword(_), Method(str, args)) | (Word(_), Method(str, args)) => {
|
||||||
|
self.visit(first);
|
||||||
|
self.emit_constant(Value::Keyword(str));
|
||||||
|
self.visit(args);
|
||||||
|
self.emit_op(Op::SendMethod);
|
||||||
|
// target, method, args -> result
|
||||||
|
self.stack_depth -= 2;
|
||||||
|
}
|
||||||
(Keyword(_), Arguments(args)) => {
|
(Keyword(_), Arguments(args)) => {
|
||||||
self.visit(&args[0]);
|
self.visit(&args[0]);
|
||||||
self.visit(first);
|
self.visit(first);
|
||||||
|
@ -954,8 +962,16 @@ impl Compiler {
|
||||||
Keyword(str) => {
|
Keyword(str) => {
|
||||||
self.emit_constant(Value::Keyword(str));
|
self.emit_constant(Value::Keyword(str));
|
||||||
self.emit_op(Op::GetKey);
|
self.emit_op(Op::GetKey);
|
||||||
|
// target, keyword -> value
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
}
|
}
|
||||||
|
Method(str, args) => {
|
||||||
|
self.emit_constant(Value::Keyword(str));
|
||||||
|
self.visit(args);
|
||||||
|
self.emit_op(Op::SendMethod);
|
||||||
|
// target, method, args -> result
|
||||||
|
self.stack_depth -= 2;
|
||||||
|
}
|
||||||
Arguments(args) => {
|
Arguments(args) => {
|
||||||
self.store();
|
self.store();
|
||||||
let arity = args.len();
|
let arity = args.len();
|
||||||
|
@ -1475,7 +1491,7 @@ impl Compiler {
|
||||||
Placeholder => {
|
Placeholder => {
|
||||||
self.emit_op(Op::Nothing);
|
self.emit_op(Op::Nothing);
|
||||||
}
|
}
|
||||||
And | Or | Arguments(..) => unreachable!(),
|
And | Or | Arguments(..) | Method(..) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub enum Token {
|
||||||
// todo: hard code these types
|
// todo: hard code these types
|
||||||
Reserved(&'static str),
|
Reserved(&'static str),
|
||||||
Punctuation(&'static str),
|
Punctuation(&'static str),
|
||||||
|
Method(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Token {
|
impl fmt::Display for Token {
|
||||||
|
@ -26,6 +27,7 @@ impl fmt::Display for Token {
|
||||||
Token::Reserved(r) => write!(f, "[Reserved {}]", r),
|
Token::Reserved(r) => write!(f, "[Reserved {}]", r),
|
||||||
Token::Nil => write!(f, "[nil]"),
|
Token::Nil => write!(f, "[nil]"),
|
||||||
Token::Punctuation(p) => write!(f, "[Punctuation {}]", p),
|
Token::Punctuation(p) => write!(f, "[Punctuation {}]", p),
|
||||||
|
Token::Method(m) => write!(f, "[Method {m}]"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +64,8 @@ pub fn lexer(
|
||||||
_ => Token::Word(word),
|
_ => Token::Word(word),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let method = just("::").ignore_then(word).map(Token::Method);
|
||||||
|
|
||||||
let keyword = just(':').ignore_then(word).map(Token::Keyword);
|
let keyword = just(':').ignore_then(word).map(Token::Keyword);
|
||||||
|
|
||||||
let string = just('"')
|
let string = just('"')
|
||||||
|
@ -81,6 +85,7 @@ pub fn lexer(
|
||||||
let token = number
|
let token = number
|
||||||
.or(reserved_or_word)
|
.or(reserved_or_word)
|
||||||
.or(keyword)
|
.or(keyword)
|
||||||
|
.or(method)
|
||||||
.or(string)
|
.or(string)
|
||||||
.or(punctuation);
|
.or(punctuation);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,7 @@ pub enum Op {
|
||||||
NextMessage,
|
NextMessage,
|
||||||
MatchMessage,
|
MatchMessage,
|
||||||
ClearMessage,
|
ClearMessage,
|
||||||
|
SendMethod,
|
||||||
// Inc,
|
// Inc,
|
||||||
// Dec,
|
// Dec,
|
||||||
// Gt,
|
// Gt,
|
||||||
|
@ -230,6 +231,7 @@ impl std::fmt::Display for Op {
|
||||||
NextMessage => "next_message",
|
NextMessage => "next_message",
|
||||||
MatchMessage => "match_message",
|
MatchMessage => "match_message",
|
||||||
ClearMessage => "clear_message",
|
ClearMessage => "clear_message",
|
||||||
|
SendMethod => "send_method",
|
||||||
};
|
};
|
||||||
write!(f, "{rep}")
|
write!(f, "{rep}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,7 @@ where
|
||||||
)
|
)
|
||||||
.map_with(|dict, e| (DictPattern(dict), e.span()));
|
.map_with(|dict, e| (DictPattern(dict), e.span()));
|
||||||
|
|
||||||
let keyword = select! {Token::Keyword(k) => Keyword(k),}.map_with(|k, e| (k, e.span()));
|
let keyword = select! {Token::Keyword(k) => Keyword(k)}.map_with(|k, e| (k, e.span()));
|
||||||
|
|
||||||
let as_pattern = select! {Token::Word(w) => w}
|
let as_pattern = select! {Token::Word(w) => w}
|
||||||
.then_ignore(just(Token::Reserved("as")))
|
.then_ignore(just(Token::Reserved("as")))
|
||||||
|
@ -300,9 +300,13 @@ where
|
||||||
|
|
||||||
let and = just(Token::Reserved("and")).map_with(|_, e| (And, e.span()));
|
let and = just(Token::Reserved("and")).map_with(|_, e| (And, e.span()));
|
||||||
|
|
||||||
|
let method = select!(Token::Method(m) => m)
|
||||||
|
.then(tuple.clone())
|
||||||
|
.map_with(|(m, t), e| (Ast::Method(m, Box::new(t)), e.span()));
|
||||||
|
|
||||||
let synth_root = or.or(and).or(word).or(keyword);
|
let synth_root = or.or(and).or(word).or(keyword);
|
||||||
|
|
||||||
let synth_term = keyword.or(args);
|
let synth_term = keyword.or(args).or(method);
|
||||||
|
|
||||||
let synthetic = synth_root
|
let synthetic = synth_root
|
||||||
.then(synth_term.clone())
|
.then(synth_term.clone())
|
||||||
|
|
|
@ -284,6 +284,13 @@ impl<'a> Validator<'a> {
|
||||||
// check arity against fn info if first term is word and second term is args
|
// check arity against fn info if first term is word and second term is args
|
||||||
Synthetic(first, second, rest) => {
|
Synthetic(first, second, rest) => {
|
||||||
match (&first.0, &second.0) {
|
match (&first.0, &second.0) {
|
||||||
|
(Ast::Word(_), Ast::Method(_, args)) => {
|
||||||
|
self.visit(first.as_ref());
|
||||||
|
self.visit(args);
|
||||||
|
}
|
||||||
|
(Ast::Keyword(_), Ast::Method(_, args)) => {
|
||||||
|
self.visit(args);
|
||||||
|
}
|
||||||
(Ast::And, Ast::Arguments(_)) | (Ast::Or, Ast::Arguments(_)) => {
|
(Ast::And, Ast::Arguments(_)) | (Ast::Or, Ast::Arguments(_)) => {
|
||||||
self.visit(second.as_ref())
|
self.visit(second.as_ref())
|
||||||
}
|
}
|
||||||
|
@ -587,7 +594,7 @@ impl<'a> Validator<'a> {
|
||||||
}
|
}
|
||||||
PairPattern(_, patt) => self.visit(patt.as_ref()),
|
PairPattern(_, patt) => self.visit(patt.as_ref()),
|
||||||
// terminals can never be invalid
|
// terminals can never be invalid
|
||||||
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) | And | Or => (),
|
Nil | Boolean(_) | Number(_) | Keyword(_) | String(_) | And | Or | Method(..) => (),
|
||||||
// terminal patterns can never be invalid
|
// terminal patterns can never be invalid
|
||||||
NilPattern | BooleanPattern(..) | NumberPattern(..) | StringPattern(..)
|
NilPattern | BooleanPattern(..) | NumberPattern(..) | StringPattern(..)
|
||||||
| KeywordPattern(..) | PlaceholderPattern => (),
|
| KeywordPattern(..) | PlaceholderPattern => (),
|
||||||
|
|
77
src/vm.rs
77
src/vm.rs
|
@ -234,12 +234,14 @@ impl Creature {
|
||||||
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
|
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
|
||||||
println!("process {} panicked!\n{msg}", self.pid);
|
println!("process {} panicked!\n{msg}", self.pid);
|
||||||
self.result = Some(Err(Panic::String(msg)));
|
self.result = Some(Err(Panic::String(msg)));
|
||||||
|
self.r#yield = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn panic_with(&mut self, msg: String) {
|
pub fn panic_with(&mut self, msg: String) {
|
||||||
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
|
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
|
||||||
println!("process {} panicked!\n{msg}", self.pid);
|
println!("process {} panicked!\n{msg}", self.pid);
|
||||||
self.result = Some(Err(Panic::String(msg)));
|
self.result = Some(Err(Panic::String(msg)));
|
||||||
|
self.r#yield = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_value_at(&mut self, idx: u8) -> Value {
|
fn get_value_at(&mut self, idx: u8) -> Value {
|
||||||
|
@ -269,6 +271,18 @@ impl Creature {
|
||||||
self.ip >= self.chunk().bytecode.len()
|
self.ip >= self.chunk().bytecode.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_msg(&mut self, pid: Value, msg: Value) {
|
||||||
|
let Value::Keyword(pid) = pid else {
|
||||||
|
return self.panic_with(format!("Ludus expected pid keyword, and instead got {pid}"));
|
||||||
|
};
|
||||||
|
if self.pid == pid {
|
||||||
|
self.mbx.push_back(msg.clone());
|
||||||
|
} else {
|
||||||
|
self.zoo.as_ref().borrow_mut().send_msg(pid, msg);
|
||||||
|
}
|
||||||
|
self.push(Value::Keyword("ok"));
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_msg(&mut self, args: Vec<Value>) {
|
fn handle_msg(&mut self, args: Vec<Value>) {
|
||||||
println!("message received by {}: {}", self.pid, args[0]);
|
println!("message received by {}: {}", self.pid, args[0]);
|
||||||
let Value::Keyword(msg) = args.first().unwrap() else {
|
let Value::Keyword(msg) = args.first().unwrap() else {
|
||||||
|
@ -277,24 +291,25 @@ impl Creature {
|
||||||
match *msg {
|
match *msg {
|
||||||
"self" => self.push(Value::Keyword(self.pid)),
|
"self" => self.push(Value::Keyword(self.pid)),
|
||||||
"send" => {
|
"send" => {
|
||||||
let Value::Keyword(pid) = args[1] else {
|
self.send_msg(args[1].clone(), args[2].clone())
|
||||||
return self.panic("malformed pid");
|
// let Value::Keyword(pid) = args[1] else {
|
||||||
};
|
// return self.panic("malformed pid");
|
||||||
println!(
|
// };
|
||||||
"sending msg from {} to {} of {}",
|
// println!(
|
||||||
self.pid,
|
// "sending msg from {} to {} of {}",
|
||||||
pid,
|
// self.pid,
|
||||||
args[2].show()
|
// pid,
|
||||||
);
|
// args[2].show()
|
||||||
if self.pid == pid {
|
// );
|
||||||
self.mbx.push_back(args[2].clone());
|
// if self.pid == pid {
|
||||||
} else {
|
// self.mbx.push_back(args[2].clone());
|
||||||
self.zoo
|
// } else {
|
||||||
.as_ref()
|
// self.zoo
|
||||||
.borrow_mut()
|
// .as_ref()
|
||||||
.send_msg(pid, args[2].clone());
|
// .borrow_mut()
|
||||||
}
|
// .send_msg(pid, args[2].clone());
|
||||||
self.push(Value::Keyword("ok"));
|
// }
|
||||||
|
// self.push(Value::Keyword("ok"));
|
||||||
}
|
}
|
||||||
"spawn" => {
|
"spawn" => {
|
||||||
let f = args[1].clone();
|
let f = args[1].clone();
|
||||||
|
@ -376,19 +391,19 @@ impl Creature {
|
||||||
loop {
|
loop {
|
||||||
if self.at_end() {
|
if self.at_end() {
|
||||||
let result = self.stack.pop().unwrap();
|
let result = self.stack.pop().unwrap();
|
||||||
println!("process {} has returned {result}", self.pid);
|
// println!("process {} has returned {result}", self.pid);
|
||||||
self.result = Some(Ok(result));
|
self.result = Some(Ok(result));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.r#yield {
|
if self.r#yield {
|
||||||
println!("process {} has explicitly yielded", self.pid);
|
// println!("process {} has explicitly yielded", self.pid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.reductions >= MAX_REDUCTIONS {
|
if self.reductions >= MAX_REDUCTIONS {
|
||||||
println!(
|
// println!(
|
||||||
"process {} is yielding after {MAX_REDUCTIONS} reductions",
|
// "process {} is yielding after {MAX_REDUCTIONS} reductions",
|
||||||
self.pid
|
// self.pid
|
||||||
);
|
// );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let code = self.read();
|
let code = self.read();
|
||||||
|
@ -1231,11 +1246,23 @@ impl Creature {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MatchMessage => {
|
MatchMessage => {
|
||||||
let matched = self.mbx.remove(self.msg_idx).unwrap();
|
self.mbx.remove(self.msg_idx).unwrap();
|
||||||
}
|
}
|
||||||
ClearMessage => {
|
ClearMessage => {
|
||||||
self.msg_idx = 0;
|
self.msg_idx = 0;
|
||||||
}
|
}
|
||||||
|
SendMethod => {
|
||||||
|
let Value::Tuple(args) = self.pop() else {
|
||||||
|
unreachable!("method args should be a tuple");
|
||||||
|
};
|
||||||
|
let method = self.pop();
|
||||||
|
let target = self.pop();
|
||||||
|
let mut msg = vec![method];
|
||||||
|
for arg in args.as_ref() {
|
||||||
|
msg.push(arg.clone());
|
||||||
|
}
|
||||||
|
self.send_msg(target, Value::tuple(msg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user