first draft of tuple splatterns
This commit is contained in:
parent
a4d68fa02e
commit
35d7d3b1c8
|
@ -39,8 +39,10 @@ pub enum Op {
|
|||
PushStringMatches,
|
||||
MatchType,
|
||||
MatchTuple,
|
||||
MatchSplattedTuple,
|
||||
PushTuple,
|
||||
LoadTuple,
|
||||
LoadSplattedTuple,
|
||||
MatchList,
|
||||
MatchSplattedList,
|
||||
LoadList,
|
||||
|
@ -161,8 +163,10 @@ impl std::fmt::Display for Op {
|
|||
PushStringMatches => "push_string_matches",
|
||||
MatchType => "match_type",
|
||||
MatchTuple => "match_tuple",
|
||||
MatchSplattedTuple => "match_splatted_tuple",
|
||||
PushTuple => "push_tuple",
|
||||
LoadTuple => "load_tuple",
|
||||
LoadSplattedTuple => "load_splatted_tuple",
|
||||
MatchList => "match_list",
|
||||
MatchSplattedList => "match_splatted_list",
|
||||
LoadList => "load_list",
|
||||
|
@ -264,9 +268,10 @@ impl Chunk {
|
|||
println!("{i:04}: {:16} {next:03}: {value}", op.to_string());
|
||||
*i += 1;
|
||||
}
|
||||
PushBinding | MatchTuple | MatchList | MatchSplattedList | LoadSplattedList
|
||||
| MatchDict | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreAt
|
||||
| Call | SetUpvalue | GetUpvalue | Partial | MatchString | PushStringMatches => {
|
||||
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | 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;
|
||||
|
@ -729,7 +734,16 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
TuplePattern(members) => {
|
||||
// first, test the tuple against length
|
||||
// check if we're splatted
|
||||
// different opcodes w/ splats, but same logic
|
||||
let mut is_splatted = false;
|
||||
if let Some((Splattern(_), _)) = members.last() {
|
||||
is_splatted = true;
|
||||
self.emit_op(Op::MatchSplattedTuple);
|
||||
} else {
|
||||
self.emit_op(Op::MatchTuple);
|
||||
}
|
||||
|
||||
self.emit_byte(members.len());
|
||||
// skip everything if tuple lengths don't match
|
||||
let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch);
|
||||
|
@ -741,7 +755,12 @@ impl<'a> Compiler<'a> {
|
|||
self.match_depth = members.len();
|
||||
|
||||
// load the tuple and update the stack len
|
||||
if is_splatted {
|
||||
self.emit_op(Op::LoadSplattedTuple);
|
||||
self.emit_byte(members.len());
|
||||
} else {
|
||||
self.emit_op(Op::LoadTuple);
|
||||
}
|
||||
self.stack_depth += members.len();
|
||||
|
||||
// visit each member
|
||||
|
|
|
@ -75,7 +75,7 @@ pub fn run(src: &'static str) {
|
|||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
let [x, ...y] = [1, 2, 3, 4, 5]
|
||||
let (...y) = (1, 2)
|
||||
y
|
||||
";
|
||||
run(src);
|
||||
|
|
27
src/vm.rs
27
src/vm.rs
|
@ -409,6 +409,16 @@ impl Vm {
|
|||
};
|
||||
self.ip += 2;
|
||||
}
|
||||
MatchSplattedTuple => {
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let patt_len = self.chunk().bytecode[self.ip + 1];
|
||||
let scrutinee = self.stack[idx].clone();
|
||||
match scrutinee {
|
||||
Value::Tuple(members) => self.matches = members.len() >= patt_len as usize,
|
||||
_ => self.matches = false,
|
||||
}
|
||||
self.ip += 2;
|
||||
}
|
||||
PushTuple => {
|
||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
||||
let tuple_members = self.stack.split_off(self.stack.len() - tuple_len as usize);
|
||||
|
@ -429,6 +439,23 @@ impl Vm {
|
|||
};
|
||||
self.ip += 1;
|
||||
}
|
||||
LoadSplattedTuple => {
|
||||
let load_len = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let tuple = self.stack[idx].clone();
|
||||
let Value::Tuple(members) = tuple else {
|
||||
return self.panic("internal error: expected tuple");
|
||||
};
|
||||
for i in 0..load_len - 1 {
|
||||
self.push(members[i].clone());
|
||||
}
|
||||
let mut splatted = Vector::new();
|
||||
for i in load_len - 1..members.len() {
|
||||
splatted.push_back(members[i].clone());
|
||||
}
|
||||
self.push(Value::List(Box::new(splatted)));
|
||||
self.ip += 2;
|
||||
}
|
||||
PushList => {
|
||||
self.push(Value::List(Box::new(Vector::new())));
|
||||
self.ip += 1;
|
||||
|
|
Loading…
Reference in New Issue
Block a user