dict splatterns first draft
This commit is contained in:
parent
4dd4b8ff7e
commit
442532ecd3
|
@ -55,6 +55,8 @@ pub enum Op {
|
|||
ConcatDict,
|
||||
LoadDictValue,
|
||||
MatchDict,
|
||||
MatchSplattedDict,
|
||||
DropDictEntry,
|
||||
PushBox,
|
||||
GetKey,
|
||||
PanicNoWhen,
|
||||
|
@ -179,6 +181,8 @@ impl std::fmt::Display for Op {
|
|||
ConcatDict => "concat_dict",
|
||||
LoadDictValue => "load_dict_value",
|
||||
MatchDict => "match_dict",
|
||||
MatchSplattedDict => "match_splatted_dict",
|
||||
DropDictEntry => "drop_dict_entry",
|
||||
PushBox => "push_box",
|
||||
GetKey => "get_key",
|
||||
PanicNoWhen => "panic_no_when",
|
||||
|
@ -269,9 +273,9 @@ impl Chunk {
|
|||
*i += 1;
|
||||
}
|
||||
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | MatchList
|
||||
| MatchSplattedList | LoadSplattedList | MatchDict | LoadDictValue | PushTuple
|
||||
| PushBox | MatchDepth | PopN | StoreAt | Call | SetUpvalue | GetUpvalue | Partial
|
||||
| MatchString | PushStringMatches => {
|
||||
| MatchSplattedList | LoadSplattedList | MatchDict | MatchSplattedDict
|
||||
| DropDictEntry | 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;
|
||||
|
@ -853,13 +857,28 @@ impl<'a> Compiler<'a> {
|
|||
// then, match against all the values
|
||||
// then push the dict itself as last value
|
||||
// and then emit an opcode and constant/keyword to OMIT that key from the dict
|
||||
self.emit_op(Op::MatchDict);
|
||||
let mut is_splatted = false;
|
||||
if let Some((Splattern(_), _)) = pairs.last() {
|
||||
is_splatted = true;
|
||||
self.emit_op(Op::MatchSplattedDict);
|
||||
} else {
|
||||
self.emit_op(Op::MatchDict);
|
||||
}
|
||||
self.emit_byte(pairs.len());
|
||||
let before_load_dict_idx = self.stub_jump(Op::JumpIfNoMatch);
|
||||
|
||||
let mut jump_idxes = vec![];
|
||||
let dict_stack_pos = self.stack_depth - 1;
|
||||
for pair in pairs {
|
||||
let dict_stack_pos = self.stack_depth - self.match_depth - 1;
|
||||
let mut splattern = None;
|
||||
let mut pairs_len = pairs.len();
|
||||
if is_splatted {
|
||||
splattern = pairs.last();
|
||||
pairs_len -= 1;
|
||||
}
|
||||
|
||||
let mut match_depth = self.match_depth;
|
||||
self.match_depth = 0;
|
||||
for pair in pairs.iter().take(pairs_len) {
|
||||
let (PairPattern(key, pattern), _) = pair else {
|
||||
unreachable!()
|
||||
};
|
||||
|
@ -869,6 +888,28 @@ impl<'a> Compiler<'a> {
|
|||
self.visit(pattern);
|
||||
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
|
||||
}
|
||||
|
||||
if is_splatted {
|
||||
// pull the dict out of the stack
|
||||
// drop every value in the pattern
|
||||
self.emit_op(Op::PushBinding);
|
||||
self.emit_byte(dict_stack_pos);
|
||||
|
||||
for pair in pairs.iter().take(pairs_len) {
|
||||
let (PairPattern(key, _), _) = pair else {
|
||||
unreachable!()
|
||||
};
|
||||
self.emit_constant(Value::Keyword(key));
|
||||
self.emit_op(Op::DropDictEntry);
|
||||
}
|
||||
|
||||
if let Some(splatt) = splattern {
|
||||
self.visit(splatt);
|
||||
}
|
||||
}
|
||||
|
||||
self.match_depth = match_depth + pairs.len();
|
||||
|
||||
let jump_idx = self.stub_jump(Op::Jump);
|
||||
|
||||
for idx in jump_idxes {
|
||||
|
|
|
@ -75,8 +75,8 @@ pub fn run(src: &'static str) {
|
|||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
let (...y) = (1, 2, 3, 4, 5)
|
||||
y
|
||||
let (#{a, ...}, d, (e)) = (#{:a 1, :b 2}, :foo, (:bar))
|
||||
(a, d, e)
|
||||
";
|
||||
run(src);
|
||||
}
|
||||
|
|
21
src/vm.rs
21
src/vm.rs
|
@ -594,6 +594,27 @@ impl Vm {
|
|||
};
|
||||
self.ip += 2;
|
||||
}
|
||||
MatchSplattedDict => {
|
||||
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::Dict(members) => self.matches = members.len() >= patt_len as usize,
|
||||
_ => self.matches = false,
|
||||
}
|
||||
self.ip += 2;
|
||||
}
|
||||
DropDictEntry => {
|
||||
let Value::Keyword(key_to_drop) = self.pop() else {
|
||||
unreachable!()
|
||||
};
|
||||
let Value::Dict(mut dict) = self.pop() else {
|
||||
unreachable!()
|
||||
};
|
||||
dict.remove(key_to_drop);
|
||||
self.push(Value::Dict(dict));
|
||||
self.ip += 1;
|
||||
}
|
||||
PushBox => {
|
||||
let val = self.pop();
|
||||
self.push(Value::Box(Rc::new(RefCell::new(val))));
|
||||
|
|
Loading…
Reference in New Issue
Block a user