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