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

View File

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

View File

@ -368,12 +368,39 @@ impl Vm {
}; };
self.ip += 1; 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 => { PushList => {
let list_len = self.chunk().bytecode[self.ip + 1]; self.push(Value::List(Box::new(Vector::new())));
let list_members = self.stack.split_off(self.stack.len() - list_len as usize); self.ip += 1;
let list = Value::List(Box::new(Vector::from(list_members))); }
self.push(list); AppendList => {
self.ip += 2; 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 => { MatchList => {
let idx = self.stack.len() - self.match_depth as usize - 1; let idx = self.stack.len() - self.match_depth as usize - 1;