From b557c487cc2f1eed16ef36224d53313b161ea890 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Thu, 5 Jun 2025 13:05:07 -0400 Subject: [PATCH] add list splats --- src/compiler.rs | 24 +++++++++++++++++------- src/main.rs | 11 ++++------- src/vm.rs | 37 ++++++++++++++++++++++++++++++++----- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 81ef617..bbaa21d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -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!(), diff --git a/src/main.rs b/src/main.rs index 6366dc8..45f310c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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); diff --git a/src/vm.rs b/src/vm.rs index 4d3c34e..29604ac 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -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;