method syntax sugar achieved

This commit is contained in:
Scott Richmond 2025-07-02 19:29:49 -04:00
parent 12389ae371
commit 0cd682de21
10 changed files with 96 additions and 31 deletions

View File

@ -425,7 +425,7 @@ function __wbg_get_imports() {
_assertBoolean(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);
return ret;
}, arguments) };

Binary file not shown.

View File

@ -34,6 +34,7 @@ pub enum Ast {
Boolean(bool),
Number(f64),
Keyword(&'static str),
Method(&'static str, Box<Spanned<Self>>),
Word(&'static str),
String(&'static str),
Interpolated(Vec<Spanned<StringPart>>),
@ -103,6 +104,7 @@ impl Ast {
Boolean(b) | BooleanPattern(b) => b.to_string(),
Number(n) | NumberPattern(n) => n.to_string(),
Keyword(k) | KeywordPattern(k) => format!(":{k}"),
Method(m, args) => format!("::{m} {}", args.0),
Word(w) | WordPattern(w) => w.to_string(),
Block(lines) => {
let mut out = "{\n".to_string();
@ -260,6 +262,7 @@ impl fmt::Display for Ast {
Boolean(b) => write!(f, "Boolean: {}", b),
Number(n) => write!(f, "Number: {}", n),
Keyword(k) => write!(f, "Keyword: :{}", k),
Method(m, args) => write!(f, "Method: ::{m} ({})", args.0),
Word(w) => write!(f, "Word: {}", w),
Block(b) => write!(
f,

View File

@ -37,7 +37,8 @@ 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 | LoadMessage | NextMessage | MatchMessage | ClearMessage => {
| PushGlobal | SetUpvalue | LoadMessage | NextMessage | MatchMessage | ClearMessage
| SendMethod => {
println!("{i:04}: {op}")
}
Constant | MatchConstant => {

View File

@ -860,6 +860,14 @@ impl Compiler {
self.stack_depth -= 1;
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)) => {
self.visit(&args[0]);
self.visit(first);
@ -954,8 +962,16 @@ impl Compiler {
Keyword(str) => {
self.emit_constant(Value::Keyword(str));
self.emit_op(Op::GetKey);
// target, keyword -> value
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) => {
self.store();
let arity = args.len();
@ -1475,7 +1491,7 @@ impl Compiler {
Placeholder => {
self.emit_op(Op::Nothing);
}
And | Or | Arguments(..) => unreachable!(),
And | Or | Arguments(..) | Method(..) => unreachable!(),
}
}

View File

@ -13,6 +13,7 @@ pub enum Token {
// todo: hard code these types
Reserved(&'static str),
Punctuation(&'static str),
Method(&'static str),
}
impl fmt::Display for Token {
@ -26,6 +27,7 @@ impl fmt::Display for Token {
Token::Reserved(r) => write!(f, "[Reserved {}]", r),
Token::Nil => write!(f, "[nil]"),
Token::Punctuation(p) => write!(f, "[Punctuation {}]", p),
Token::Method(m) => write!(f, "[Method {m}]"),
}
}
}
@ -62,6 +64,8 @@ pub fn lexer(
_ => Token::Word(word),
});
let method = just("::").ignore_then(word).map(Token::Method);
let keyword = just(':').ignore_then(word).map(Token::Keyword);
let string = just('"')
@ -81,6 +85,7 @@ pub fn lexer(
let token = number
.or(reserved_or_word)
.or(keyword)
.or(method)
.or(string)
.or(punctuation);

View File

@ -94,6 +94,7 @@ pub enum Op {
NextMessage,
MatchMessage,
ClearMessage,
SendMethod,
// Inc,
// Dec,
// Gt,
@ -230,6 +231,7 @@ impl std::fmt::Display for Op {
NextMessage => "next_message",
MatchMessage => "match_message",
ClearMessage => "clear_message",
SendMethod => "send_method",
};
write!(f, "{rep}")
}

View File

@ -233,7 +233,7 @@ where
)
.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}
.then_ignore(just(Token::Reserved("as")))
@ -300,9 +300,13 @@ where
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_term = keyword.or(args);
let synth_term = keyword.or(args).or(method);
let synthetic = synth_root
.then(synth_term.clone())

View File

@ -284,6 +284,13 @@ impl<'a> Validator<'a> {
// check arity against fn info if first term is word and second term is args
Synthetic(first, second, rest) => {
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(_)) => {
self.visit(second.as_ref())
}
@ -587,7 +594,7 @@ impl<'a> Validator<'a> {
}
PairPattern(_, patt) => self.visit(patt.as_ref()),
// 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
NilPattern | BooleanPattern(..) | NumberPattern(..) | StringPattern(..)
| KeywordPattern(..) | PlaceholderPattern => (),

View File

@ -234,12 +234,14 @@ impl Creature {
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
println!("process {} panicked!\n{msg}", self.pid);
self.result = Some(Err(Panic::String(msg)));
self.r#yield = true;
}
pub fn panic_with(&mut self, msg: String) {
let msg = format!("{msg}\nPanic traceback:\n{}", self.call_stack());
println!("process {} panicked!\n{msg}", self.pid);
self.result = Some(Err(Panic::String(msg)));
self.r#yield = true;
}
fn get_value_at(&mut self, idx: u8) -> Value {
@ -269,6 +271,18 @@ impl Creature {
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>) {
println!("message received by {}: {}", self.pid, args[0]);
let Value::Keyword(msg) = args.first().unwrap() else {
@ -277,24 +291,25 @@ impl Creature {
match *msg {
"self" => self.push(Value::Keyword(self.pid)),
"send" => {
let Value::Keyword(pid) = args[1] else {
return self.panic("malformed pid");
};
println!(
"sending msg from {} to {} of {}",
self.pid,
pid,
args[2].show()
);
if self.pid == pid {
self.mbx.push_back(args[2].clone());
} else {
self.zoo
.as_ref()
.borrow_mut()
.send_msg(pid, args[2].clone());
}
self.push(Value::Keyword("ok"));
self.send_msg(args[1].clone(), args[2].clone())
// let Value::Keyword(pid) = args[1] else {
// return self.panic("malformed pid");
// };
// println!(
// "sending msg from {} to {} of {}",
// self.pid,
// pid,
// args[2].show()
// );
// if self.pid == pid {
// self.mbx.push_back(args[2].clone());
// } else {
// self.zoo
// .as_ref()
// .borrow_mut()
// .send_msg(pid, args[2].clone());
// }
// self.push(Value::Keyword("ok"));
}
"spawn" => {
let f = args[1].clone();
@ -376,19 +391,19 @@ impl Creature {
loop {
if self.at_end() {
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));
return;
}
if self.r#yield {
println!("process {} has explicitly yielded", self.pid);
// println!("process {} has explicitly yielded", self.pid);
return;
}
if self.reductions >= MAX_REDUCTIONS {
println!(
"process {} is yielding after {MAX_REDUCTIONS} reductions",
self.pid
);
// println!(
// "process {} is yielding after {MAX_REDUCTIONS} reductions",
// self.pid
// );
return;
}
let code = self.read();
@ -1231,11 +1246,23 @@ impl Creature {
}
},
MatchMessage => {
let matched = self.mbx.remove(self.msg_idx).unwrap();
self.mbx.remove(self.msg_idx).unwrap();
}
ClearMessage => {
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));
}
}
}
}