rough, not yet working, draft of dict patterns
This commit is contained in:
parent
cf51822128
commit
45d2e7e742
|
@ -35,6 +35,8 @@ pub enum Op {
|
||||||
LoadList,
|
LoadList,
|
||||||
PushList,
|
PushList,
|
||||||
PushDict,
|
PushDict,
|
||||||
|
LoadDictValue,
|
||||||
|
MatchDict,
|
||||||
PushBox,
|
PushBox,
|
||||||
GetKey,
|
GetKey,
|
||||||
PanicNoWhen,
|
PanicNoWhen,
|
||||||
|
@ -80,6 +82,8 @@ impl std::fmt::Display for Op {
|
||||||
LoadList => "load_list",
|
LoadList => "load_list",
|
||||||
PushList => "push_list",
|
PushList => "push_list",
|
||||||
PushDict => "push_dict",
|
PushDict => "push_dict",
|
||||||
|
LoadDictValue => "load_dict_value",
|
||||||
|
MatchDict => "match_dict",
|
||||||
PushBox => "push_box",
|
PushBox => "push_box",
|
||||||
GetKey => "get_key",
|
GetKey => "get_key",
|
||||||
PanicNoWhen => "panic_no_when",
|
PanicNoWhen => "panic_no_when",
|
||||||
|
@ -128,9 +132,9 @@ impl Chunk {
|
||||||
let value = &self.constants[next as usize].show(self);
|
let value = &self.constants[next as usize].show(self);
|
||||||
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
|
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchList | PushTuple | PushDict | PushList | PushBox
|
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||||
| Jump | JumpIfFalse | JumpIfNoMatch | JumpIfMatch | JumpBack | JumpIfZero
|
| PushDict | PushList | PushBox | Jump | JumpIfFalse | JumpIfNoMatch | JumpIfMatch
|
||||||
| MatchDepth | PopN => {
|
| JumpBack | JumpIfZero | MatchDepth | PopN => {
|
||||||
let next = self.bytecode[i + 1];
|
let next = self.bytecode[i + 1];
|
||||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
println!("{i:04}: {:16} {next:04}", op.to_string());
|
||||||
}
|
}
|
||||||
|
@ -229,6 +233,18 @@ impl Compiler {
|
||||||
self.span = root_span;
|
self.span = root_span;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_keyword(&mut self, s: &'static str) {
|
||||||
|
let existing_kw = self.chunk.keywords.iter().position(|kw| *kw == s);
|
||||||
|
let kw_index = match existing_kw {
|
||||||
|
Some(index) => index,
|
||||||
|
None => self.chunk.keywords.len(),
|
||||||
|
};
|
||||||
|
if kw_index == self.chunk.keywords.len() {
|
||||||
|
self.chunk.keywords.push(s);
|
||||||
|
}
|
||||||
|
self.emit_constant(Value::Keyword(kw_index));
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_constant(&mut self, val: Value) {
|
fn emit_constant(&mut self, val: Value) {
|
||||||
let constant_index = self.chunk.constants.len();
|
let constant_index = self.chunk.constants.len();
|
||||||
if constant_index > u8::MAX as usize {
|
if constant_index > u8::MAX as usize {
|
||||||
|
@ -344,17 +360,7 @@ impl Compiler {
|
||||||
self.chunk.strings.push(s);
|
self.chunk.strings.push(s);
|
||||||
self.emit_constant(Value::Interned(str_index));
|
self.emit_constant(Value::Interned(str_index));
|
||||||
}
|
}
|
||||||
Keyword(s) => {
|
Keyword(s) => self.emit_keyword(s),
|
||||||
let existing_kw = self.chunk.keywords.iter().position(|kw| kw == s);
|
|
||||||
let kw_index = match existing_kw {
|
|
||||||
Some(index) => index,
|
|
||||||
None => self.chunk.keywords.len(),
|
|
||||||
};
|
|
||||||
if kw_index == self.chunk.keywords.len() {
|
|
||||||
self.chunk.keywords.push(s);
|
|
||||||
}
|
|
||||||
self.emit_constant(Value::Keyword(kw_index));
|
|
||||||
}
|
|
||||||
Block(lines) => {
|
Block(lines) => {
|
||||||
self.scope_depth += 1;
|
self.scope_depth += 1;
|
||||||
let stack_depth = self.stack_depth;
|
let stack_depth = self.stack_depth;
|
||||||
|
@ -546,6 +552,45 @@ impl Compiler {
|
||||||
self.len() as u8 - before_load_list_idx as u8 - 1;
|
self.len() as u8 - before_load_list_idx as u8 - 1;
|
||||||
self.chunk.bytecode[jump_idx] = self.len() as u8 - jump_idx as u8 - 1;
|
self.chunk.bytecode[jump_idx] = self.len() as u8 - jump_idx as u8 - 1;
|
||||||
}
|
}
|
||||||
|
DictPattern(pairs) => {
|
||||||
|
self.emit_op(Op::MatchDict);
|
||||||
|
self.emit_byte(pairs.len());
|
||||||
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
let before_load_dict_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
|
let mut jump_idxes = vec![];
|
||||||
|
let dict_stack_pos = self.stack_depth;
|
||||||
|
for pair in pairs {
|
||||||
|
let (PairPattern(key, pattern), _) = pair else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
// algo:
|
||||||
|
// push the keyword onto the stack
|
||||||
|
self.emit_keyword(key);
|
||||||
|
// pull the value out of the dict
|
||||||
|
self.emit_op(Op::LoadDictValue);
|
||||||
|
self.emit_byte(dict_stack_pos);
|
||||||
|
// visit the pattern
|
||||||
|
self.visit(pattern);
|
||||||
|
// jump if no match
|
||||||
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
|
}
|
||||||
|
self.emit_op(Op::Jump);
|
||||||
|
let jump_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
|
for idx in jump_idxes {
|
||||||
|
self.chunk.bytecode[idx] = self.len() as u8 - idx as u8 - 1;
|
||||||
|
}
|
||||||
|
for _ in 0..pairs.len() {
|
||||||
|
self.emit_op(Op::Pop);
|
||||||
|
}
|
||||||
|
self.chunk.bytecode[before_load_dict_idx] =
|
||||||
|
self.len() as u8 - before_load_dict_idx as u8 - 1;
|
||||||
|
self.chunk.bytecode[jump_idx] = self.len() as u8 - jump_idx as u8 - 1;
|
||||||
|
}
|
||||||
|
PairPattern(_, _) => unreachable!(),
|
||||||
Tuple(members) => {
|
Tuple(members) => {
|
||||||
for member in members {
|
for member in members {
|
||||||
self.visit(member);
|
self.visit(member);
|
||||||
|
@ -840,9 +885,7 @@ impl Compiler {
|
||||||
| Splat(..)
|
| Splat(..)
|
||||||
| InterpolatedPattern(..)
|
| InterpolatedPattern(..)
|
||||||
| AsPattern(..)
|
| AsPattern(..)
|
||||||
| Splattern(..)
|
| Splattern(..) => todo!(),
|
||||||
| PairPattern(..)
|
|
||||||
| DictPattern(..) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,8 +909,8 @@ impl Compiler {
|
||||||
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
|
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchList | PushTuple | PushDict | PushList
|
PushBinding | MatchTuple | MatchList | PushTuple | PushDict | PushList
|
||||||
| PushBox | Jump | JumpIfFalse | JumpIfNoMatch | JumpIfMatch | JumpBack
|
| MatchDict | LoadDictValue | PushBox | Jump | JumpIfFalse | JumpIfNoMatch
|
||||||
| JumpIfZero | MatchDepth | PopN => {
|
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN => {
|
||||||
let (_, next) = codes.next().unwrap();
|
let (_, next) = codes.next().unwrap();
|
||||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
println!("{i:04}: {:16} {next:04}", op.to_string());
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,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 = "
|
||||||
#{:a 1, :b 2, :c 3}
|
let #{:a x} = #{:a 1}
|
||||||
|
x
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
}
|
}
|
||||||
|
|
21
src/vm.rs
21
src/vm.rs
|
@ -303,6 +303,27 @@ impl<'a> Vm<'a> {
|
||||||
self.stack.push(Value::Dict(Box::new(dict)));
|
self.stack.push(Value::Dict(Box::new(dict)));
|
||||||
self.ip += 2;
|
self.ip += 2;
|
||||||
}
|
}
|
||||||
|
LoadDictValue => {
|
||||||
|
let dict_idx = self.chunk.bytecode[self.ip + 1] as usize;
|
||||||
|
let Value::Dict(dict) = self.stack[dict_idx].clone() else {
|
||||||
|
unreachable!("expected dict, got something else")
|
||||||
|
};
|
||||||
|
let Value::Keyword(key) = self.pop() else {
|
||||||
|
unreachable!("expected keyword, got something else")
|
||||||
|
};
|
||||||
|
let value = dict.get(&key).unwrap_or(&Value::Nil);
|
||||||
|
self.push(value.clone());
|
||||||
|
}
|
||||||
|
MatchDict => {
|
||||||
|
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
|
let dict_len = self.chunk.bytecode[self.ip + 1];
|
||||||
|
let scrutinee = self.stack[idx].clone();
|
||||||
|
match scrutinee {
|
||||||
|
Value::Dict(members) => self.matches = members.len() == dict_len as usize,
|
||||||
|
_ => self.matches = false,
|
||||||
|
};
|
||||||
|
self.ip += 2;
|
||||||
|
}
|
||||||
PushBox => {
|
PushBox => {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
self.stack.push(Value::Box(Rc::new(RefCell::new(val))));
|
self.stack.push(Value::Box(Rc::new(RefCell::new(val))));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user