Compare commits
4 Commits
fb2488c850
...
a4d68fa02e
Author | SHA1 | Date | |
---|---|---|---|
|
a4d68fa02e | ||
|
2b95094eca | ||
|
4871dbd048 | ||
|
647f3d4463 |
|
@ -240,11 +240,16 @@ println!("{a} // {b_high}/{b_low} // {c}");
|
|||
```
|
||||
|
||||
To reiterate the punch list that *I would have needed for Computer Class 1*:
|
||||
* [ ] jump instructions need 16 bits of operand
|
||||
* [x] jump instructions need 16 bits of operand
|
||||
- Whew, that took longer than I expected
|
||||
* [ ] splatterns
|
||||
- [ ] validator should ensure splatterns are the longest patterns in a form
|
||||
* [ ] add guards to loop forms
|
||||
* [ ] check loop forms against function calls: do they still work the way we want them to?
|
||||
* [ ] improve validator
|
||||
- [ ] Tuples may not be longer than n members
|
||||
- [ ] Loops may not have splatterns
|
||||
- [ ] Identify others
|
||||
* [x] add guards to loop forms
|
||||
* [x] check loop forms against function calls: do they still work the way we want them to?
|
||||
* [ ] tail call elimination
|
||||
* [ ] stack traces in panics
|
||||
* [ ] actually good error messages
|
||||
|
|
|
@ -42,7 +42,9 @@ pub enum Op {
|
|||
PushTuple,
|
||||
LoadTuple,
|
||||
MatchList,
|
||||
MatchSplattedList,
|
||||
LoadList,
|
||||
LoadSplattedList,
|
||||
PushList,
|
||||
AppendList,
|
||||
ConcatList,
|
||||
|
@ -162,7 +164,9 @@ impl std::fmt::Display for Op {
|
|||
PushTuple => "push_tuple",
|
||||
LoadTuple => "load_tuple",
|
||||
MatchList => "match_list",
|
||||
MatchSplattedList => "match_splatted_list",
|
||||
LoadList => "load_list",
|
||||
LoadSplattedList => "load_splatted_list",
|
||||
PushList => "push_list",
|
||||
AppendList => "append_list",
|
||||
ConcatList => "concat_list",
|
||||
|
@ -260,9 +264,9 @@ impl Chunk {
|
|||
println!("{i:04}: {:16} {next:03}: {value}", op.to_string());
|
||||
*i += 1;
|
||||
}
|
||||
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||
| PushBox | MatchDepth | PopN | StoreAt | Call | SetUpvalue | GetUpvalue | Partial
|
||||
| MatchString | PushStringMatches => {
|
||||
PushBinding | MatchTuple | 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;
|
||||
|
@ -778,7 +782,14 @@ impl<'a> Compiler<'a> {
|
|||
self.match_depth = match_depth + members.len();
|
||||
}
|
||||
ListPattern(members) => {
|
||||
let mut is_splatted = false;
|
||||
if let Some((Splattern(_), _)) = members.last() {
|
||||
is_splatted = true;
|
||||
self.emit_op(Op::MatchSplattedList)
|
||||
} else {
|
||||
self.emit_op(Op::MatchList);
|
||||
}
|
||||
// TODO: lists must be able to be longer than 256 elements; fix this
|
||||
self.emit_byte(members.len());
|
||||
let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch);
|
||||
|
||||
|
@ -786,7 +797,12 @@ impl<'a> Compiler<'a> {
|
|||
let match_depth = self.match_depth;
|
||||
self.match_depth = members.len();
|
||||
|
||||
if is_splatted {
|
||||
self.emit_op(Op::LoadSplattedList);
|
||||
self.emit_byte(members.len());
|
||||
} else {
|
||||
self.emit_op(Op::LoadList);
|
||||
}
|
||||
self.stack_depth += members.len();
|
||||
|
||||
for member in members {
|
||||
|
@ -841,8 +857,8 @@ impl<'a> Compiler<'a> {
|
|||
self.patch_jump(before_load_dict_idx, self.len() - before_load_dict_idx - 3);
|
||||
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
|
||||
}
|
||||
Splattern(..) => {
|
||||
todo!()
|
||||
Splattern(patt) => {
|
||||
self.visit(patt);
|
||||
}
|
||||
InterpolatedPattern(parts, _) => {
|
||||
println!("An interpolated pattern of {} parts", parts.len());
|
||||
|
|
|
@ -75,10 +75,8 @@ pub fn run(src: &'static str) {
|
|||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
loop (1) with {
|
||||
(0) -> :done
|
||||
(1) -> recur (0)
|
||||
}
|
||||
let [x, ...y] = [1, 2, 3, 4, 5]
|
||||
y
|
||||
";
|
||||
run(src);
|
||||
}
|
||||
|
|
34
src/vm.rs
34
src/vm.rs
|
@ -458,27 +458,51 @@ impl Vm {
|
|||
}
|
||||
MatchList => {
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
||||
let list_len = self.chunk().bytecode[self.ip + 1];
|
||||
let scrutinee = self.stack[idx].clone();
|
||||
match scrutinee {
|
||||
Value::List(members) => self.matches = members.len() == tuple_len as usize,
|
||||
Value::List(members) => self.matches = members.len() == list_len as usize,
|
||||
_ => self.matches = false,
|
||||
};
|
||||
self.ip += 2;
|
||||
}
|
||||
MatchSplattedList => {
|
||||
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::List(members) => self.matches = members.len() >= patt_len as usize,
|
||||
_ => self.matches = false,
|
||||
}
|
||||
self.ip += 2;
|
||||
}
|
||||
LoadList => {
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let tuple = self.stack[idx].clone();
|
||||
match tuple {
|
||||
let list = self.stack[idx].clone();
|
||||
match list {
|
||||
Value::List(members) => {
|
||||
for member in members.iter() {
|
||||
self.push(member.clone());
|
||||
}
|
||||
}
|
||||
_ => return self.panic("internal error: expected tuple"),
|
||||
_ => return self.panic("internal error: expected list"),
|
||||
};
|
||||
self.ip += 1;
|
||||
}
|
||||
LoadSplattedList => {
|
||||
let loaded_len = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let list = self.stack[idx].clone();
|
||||
let Value::List(members) = list else {
|
||||
return self.panic("internal error: expected list");
|
||||
};
|
||||
for i in 0..loaded_len - 1 {
|
||||
self.push(members[i].clone());
|
||||
}
|
||||
let splatted = Value::List(Box::new(members.skip(loaded_len - 1)));
|
||||
self.push(splatted);
|
||||
self.ip += 2;
|
||||
}
|
||||
// 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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user