add list splats

This commit is contained in:
Scott Richmond 2025-06-05 13:05:07 -04:00
parent b8b720b877
commit b557c487cc
3 changed files with 53 additions and 19 deletions

View File

@ -41,6 +41,8 @@ pub enum Op {
MatchList,
LoadList,
PushList,
AppendList,
ConcatList,
PushDict,
LoadDictValue,
MatchDict,
@ -153,6 +155,8 @@ impl std::fmt::Display for Op {
MatchList => "match_list",
LoadList => "load_list",
PushList => "push_list",
AppendList => "append_list",
ConcatList => "concat_list",
PushDict => "push_dict",
LoadDictValue => "load_dict_value",
MatchDict => "match_dict",
@ -228,7 +232,8 @@ impl Chunk {
| PanicIfNoMatch | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch | TypeOf
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
| ConcatStrings | Stringify | MatchType | Return | Match | Print => {
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
| ConcatList | PushList => {
println!("{i:04}: {op}")
}
Constant | MatchConstant => {
@ -238,7 +243,7 @@ impl Chunk {
*i += 1;
}
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
| PushDict | PushList | PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch
| PushDict | PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt | Call
| SetUpvalue | GetUpvalue => {
let next = self.bytecode[*i + 1];
@ -590,7 +595,7 @@ impl<'a> Compiler<'a> {
self.emit_op(Op::Match);
self.bind(name);
}
Word(name) => match self.resolve_local(name) {
Word(name) | Splat(name) => match self.resolve_local(name) {
Some(position) => {
self.emit_op(Op::PushBinding);
self.emit_byte(position);
@ -757,12 +762,17 @@ impl<'a> Compiler<'a> {
self.stack_depth = self.stack_depth + 1 - members.len();
}
List(members) => {
self.emit_op(Op::PushList);
self.stack_depth += 1;
for member in members {
self.visit(member);
if matches!(member, (Splat(..), _)) {
self.emit_op(Op::ConcatList);
} else {
self.emit_op(Op::AppendList);
}
self.stack_depth -= 1;
}
self.emit_op(Op::PushList);
self.emit_byte(members.len());
self.stack_depth = self.stack_depth + 1 - members.len();
}
LBox(name, expr) => {
self.visit(expr);
@ -1273,7 +1283,7 @@ impl<'a> Compiler<'a> {
self.stack_depth -= 1;
}
}
Arguments(..) | Placeholder | Splat(..) | InterpolatedPattern(..) | Splattern(..) => {
Arguments(..) | Placeholder | InterpolatedPattern(..) | Splattern(..) => {
todo!()
}
And | Or => unreachable!(),

View File

@ -76,14 +76,11 @@ pub fn run(src: &'static str) {
pub fn main() {
env::set_var("RUST_BACKTRACE", "1");
let src = "
fn increase (x) -> add (x, 1)
fn double (x) -> mult (x, 2)
fn halve (x) -> div (x, 2)
do 1 > increase > double > increase > halve
let x = []
let y = [1, 2, 3]
let z = [...y, 4, ...x]
z
";
run(src);

View File

@ -368,12 +368,39 @@ impl Vm {
};
self.ip += 1;
}
// PushList => {
// let list_len = self.chunk().bytecode[self.ip + 1];
// let list_members = self.stack.split_off(self.stack.len() - list_len as usize);
// let list = Value::List(Box::new(Vector::from(list_members)));
// self.push(list);
// self.ip += 2;
// }
PushList => {
let list_len = self.chunk().bytecode[self.ip + 1];
let list_members = self.stack.split_off(self.stack.len() - list_len as usize);
let list = Value::List(Box::new(Vector::from(list_members)));
self.push(list);
self.ip += 2;
self.push(Value::List(Box::new(Vector::new())));
self.ip += 1;
}
AppendList => {
let value = self.pop();
let list = self.pop();
let Value::List(mut list) = list else {
return self.panic("only lists may be splatted into lists");
};
list.push_back(value);
self.push(Value::List(list));
self.ip += 1;
}
ConcatList => {
let splatted = self.pop();
let target = self.pop();
let Value::List(mut target) = target else {
unreachable!()
};
let Value::List(splatted) = splatted else {
return self.panic("only lists may be splatted into lists");
};
target.append(*splatted);
self.push(Value::List(target));
self.ip += 1;
}
MatchList => {
let idx = self.stack.len() - self.match_depth as usize - 1;