From 2b95094eca78c1d5070d2c24d622b2a38704ebf6 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Thu, 19 Jun 2025 12:06:47 -0400 Subject: [PATCH] first stab at splatted lists --- src/compiler.rs | 16 ++++++++++++---- src/vm.rs | 21 ++++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 656de41..59ac133 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -44,6 +44,7 @@ pub enum Op { MatchList, MatchSplattedList, LoadList, + LoadSplattedList, PushList, AppendList, ConcatList, @@ -165,6 +166,7 @@ impl std::fmt::Display for Op { MatchList => "match_list", MatchSplattedList => "match_splatted_list", LoadList => "load_list", + LoadSplattedList => "load_splatted_list", PushList => "push_list", AppendList => "append_list", ConcatList => "concat_list", @@ -262,9 +264,9 @@ impl Chunk { println!("{i:04}: {:16} {next:03}: {value}", op.to_string()); *i += 1; } - PushBinding | MatchTuple | MatchList | MatchSplattedList | MatchDict - | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreAt | Call - | SetUpvalue | GetUpvalue | Partial | MatchString | PushStringMatches => { + PushBinding | MatchTuple | MatchList | MatchSplattedList | LoadSplattedList + | MatchDict | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreAt + | Call | SetUpvalue | GetUpvalue | Partial | MatchString | PushStringMatches => { let next = self.bytecode[*i + 1]; println!("{i:04}: {:16} {next:03}", op.to_string()); *i += 1; @@ -780,7 +782,9 @@ impl<'a> Compiler<'a> { self.match_depth = match_depth + members.len(); } ListPattern(members) => { + let mut is_splatted = false; if let Some((Splattern(patt), _)) = members.last() { + is_splatted = true; self.emit_op(Op::MatchSplattedList) } else { self.emit_op(Op::MatchList); @@ -793,7 +797,11 @@ impl<'a> Compiler<'a> { let match_depth = self.match_depth; self.match_depth = members.len(); - self.emit_op(Op::LoadList); + if is_splatted { + self.emit_op(Op::LoadSplattedList); + } else { + self.emit_op(Op::LoadList); + } self.stack_depth += members.len(); for member in members { diff --git a/src/vm.rs b/src/vm.rs index ad8c391..2552ac6 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -471,17 +471,32 @@ impl Vm { } LoadList => { let idx = self.stack.len() - self.match_depth as usize - 1; - let tuple = self.stack[idx].clone(); - match tuple { + let list = self.stack[idx].clone(); + match list { Value::List(members) => { for member in members.iter() { self.push(member.clone()); } } - _ => return self.panic("internal error: expected tuple"), + _ => return self.panic("internal error: expected list"), }; self.ip += 1; } + LoadSplattedList => { + let loaded_len = self.chunk().bytecode[self.ip + 1] as usize; + let idx = self.stack.len() - self.match_depth as usize - 1; + let list = self.stack[idx].clone(); + let Value::List(members) = list else { + return self.panic("internal error: expected list"); + }; + for i in 0..loaded_len - 1 { + self.push(members[i].clone()); + } + let splatted = Value::List(Box::new(members.skip(loaded_len - 1))); + self.push(splatted); + self.ip += 2; + todo!() + } // PushDict => { // let dict_len = self.chunk().bytecode[self.ip + 1] as usize * 2; // let dict_members = self.stack.split_off(self.stack.len() - dict_len);