add dict splats
This commit is contained in:
parent
b557c487cc
commit
f3bf55fe72
|
@ -44,6 +44,8 @@ pub enum Op {
|
||||||
AppendList,
|
AppendList,
|
||||||
ConcatList,
|
ConcatList,
|
||||||
PushDict,
|
PushDict,
|
||||||
|
AppendDict,
|
||||||
|
ConcatDict,
|
||||||
LoadDictValue,
|
LoadDictValue,
|
||||||
MatchDict,
|
MatchDict,
|
||||||
PushBox,
|
PushBox,
|
||||||
|
@ -158,6 +160,8 @@ impl std::fmt::Display for Op {
|
||||||
AppendList => "append_list",
|
AppendList => "append_list",
|
||||||
ConcatList => "concat_list",
|
ConcatList => "concat_list",
|
||||||
PushDict => "push_dict",
|
PushDict => "push_dict",
|
||||||
|
AppendDict => "append_dict",
|
||||||
|
ConcatDict => "concat_dict",
|
||||||
LoadDictValue => "load_dict_value",
|
LoadDictValue => "load_dict_value",
|
||||||
MatchDict => "match_dict",
|
MatchDict => "match_dict",
|
||||||
PushBox => "push_box",
|
PushBox => "push_box",
|
||||||
|
@ -233,7 +237,7 @@ impl Chunk {
|
||||||
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
||||||
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
||||||
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
||||||
| ConcatList | PushList => {
|
| ConcatList | PushList | PushDict | AppendDict | ConcatDict => {
|
||||||
println!("{i:04}: {op}")
|
println!("{i:04}: {op}")
|
||||||
}
|
}
|
||||||
Constant | MatchConstant => {
|
Constant | MatchConstant => {
|
||||||
|
@ -243,9 +247,9 @@ impl Chunk {
|
||||||
*i += 1;
|
*i += 1;
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||||
| PushDict | PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch
|
| PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch | JumpIfMatch
|
||||||
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt | Call
|
| JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt | Call | SetUpvalue
|
||||||
| SetUpvalue | GetUpvalue => {
|
| GetUpvalue => {
|
||||||
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());
|
||||||
*i += 1;
|
*i += 1;
|
||||||
|
@ -780,13 +784,27 @@ impl<'a> Compiler<'a> {
|
||||||
self.bind(name);
|
self.bind(name);
|
||||||
}
|
}
|
||||||
Dict(pairs) => {
|
Dict(pairs) => {
|
||||||
for pair in pairs {
|
|
||||||
self.visit(pair);
|
|
||||||
}
|
|
||||||
self.emit_op(Op::PushDict);
|
self.emit_op(Op::PushDict);
|
||||||
self.emit_byte(pairs.len());
|
self.stack_depth += 1;
|
||||||
self.stack_depth = self.stack_depth + 1 - (pairs.len() * 2);
|
for pair in pairs.iter().rev() {
|
||||||
|
self.visit(pair);
|
||||||
|
if matches!(pair, (Splat(..), _)) {
|
||||||
|
self.emit_op(Op::ConcatDict);
|
||||||
|
self.stack_depth -= 1;
|
||||||
|
} else {
|
||||||
|
self.emit_op(Op::AppendDict);
|
||||||
|
self.stack_depth -= 2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Dict(pairs) => {
|
||||||
|
// for pair in pairs {
|
||||||
|
// self.visit(pair);
|
||||||
|
// }
|
||||||
|
// self.emit_op(Op::PushDict);
|
||||||
|
// self.emit_byte(pairs.len());
|
||||||
|
// self.stack_depth = self.stack_depth + 1 - (pairs.len() * 2);
|
||||||
|
// }
|
||||||
Pair(key, value) => {
|
Pair(key, value) => {
|
||||||
self.emit_constant(Value::Keyword(key));
|
self.emit_constant(Value::Keyword(key));
|
||||||
self.visit(value);
|
self.visit(value);
|
||||||
|
|
|
@ -76,11 +76,10 @@ 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 x = []
|
let x = #{:a 1, :b 2}
|
||||||
let y = [1, 2, 3]
|
let y = #{x}
|
||||||
let z = [...y, 4, ...x]
|
let z = #{...x, y}
|
||||||
|
z :y :x :a
|
||||||
z
|
|
||||||
|
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
|
|
54
src/vm.rs
54
src/vm.rs
|
@ -368,13 +368,6 @@ impl Vm {
|
||||||
};
|
};
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
// PushList => {
|
|
||||||
// let list_len = self.chunk().bytecode[self.ip + 1];
|
|
||||||
// let list_members = self.stack.split_off(self.stack.len() - list_len as usize);
|
|
||||||
// let list = Value::List(Box::new(Vector::from(list_members)));
|
|
||||||
// self.push(list);
|
|
||||||
// self.ip += 2;
|
|
||||||
// }
|
|
||||||
PushList => {
|
PushList => {
|
||||||
self.push(Value::List(Box::new(Vector::new())));
|
self.push(Value::List(Box::new(Vector::new())));
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
|
@ -425,20 +418,47 @@ impl Vm {
|
||||||
};
|
};
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
|
// 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);
|
||||||
|
// let mut dict = HashMap::new();
|
||||||
|
// let mut dict_iter = dict_members.iter();
|
||||||
|
// while let Some(kw) = dict_iter.next() {
|
||||||
|
// let Value::Keyword(key) = kw else {
|
||||||
|
// unreachable!()
|
||||||
|
// };
|
||||||
|
// let value = dict_iter.next().unwrap();
|
||||||
|
// dict.insert(*key, value.clone());
|
||||||
|
// }
|
||||||
|
// self.push(Value::Dict(Box::new(dict)));
|
||||||
|
// self.ip += 2;
|
||||||
|
// }
|
||||||
PushDict => {
|
PushDict => {
|
||||||
let dict_len = self.chunk().bytecode[self.ip + 1] as usize * 2;
|
self.push(Value::Dict(Box::new(HashMap::new())));
|
||||||
let dict_members = self.stack.split_off(self.stack.len() - dict_len);
|
self.ip += 1;
|
||||||
let mut dict = HashMap::new();
|
}
|
||||||
let mut dict_iter = dict_members.iter();
|
AppendDict => {
|
||||||
while let Some(kw) = dict_iter.next() {
|
let value = self.pop();
|
||||||
let Value::Keyword(key) = kw else {
|
let Value::Keyword(key) = self.pop() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let value = dict_iter.next().unwrap();
|
let Value::Dict(mut dict) = self.pop() else {
|
||||||
dict.insert(*key, value.clone());
|
unreachable!()
|
||||||
|
};
|
||||||
|
dict.insert(key, value);
|
||||||
|
self.push(Value::Dict(dict));
|
||||||
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
self.push(Value::Dict(Box::new(dict)));
|
ConcatDict => {
|
||||||
self.ip += 2;
|
let Value::Dict(splatted) = self.pop() else {
|
||||||
|
return self.panic("only dicts may be splatted into dicts");
|
||||||
|
};
|
||||||
|
let Value::Dict(target) = self.pop() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let union = splatted.union(*target);
|
||||||
|
self.push(Value::Dict(Box::new(union)));
|
||||||
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
LoadDictValue => {
|
LoadDictValue => {
|
||||||
let dict_idx = self.chunk().bytecode[self.ip + 1] as usize;
|
let dict_idx = self.chunk().bytecode[self.ip + 1] as usize;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user