diff --git a/src/compiler.rs b/src/compiler.rs index 6d07bef..4df31e2 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -33,6 +33,7 @@ pub enum Op { MatchWord, PanicIfNoMatch, MatchConstant, + MatchType, MatchTuple, PushTuple, LoadTuple, @@ -140,6 +141,7 @@ impl std::fmt::Display for Op { ResetMatch => "reset_match", PanicIfNoMatch => "panic_if_no_match", MatchConstant => "match_constant", + MatchType => "match_type", MatchTuple => "match_tuple", PushTuple => "push_tuple", LoadTuple => "load_tuple", @@ -210,7 +212,7 @@ impl Chunk { | PanicIfNoMatch | MatchWord | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch | TypeOf | Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub | Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic - | EmptyString | ConcatStrings | Stringify => { + | EmptyString | ConcatStrings | Stringify | MatchType => { println!("{i:04}: {op}") } Constant | MatchConstant => { @@ -359,10 +361,12 @@ impl Compiler { ) } self.chunk.constants.push(val); - self.chunk.bytecode.push(Op::Constant as u8); - self.spans.push(self.span); - self.chunk.bytecode.push(constant_index as u8); - self.spans.push(self.span); + self.emit_op(Op::Constant); + // self.chunk.bytecode.push(Op::Constant as u8); + // self.spans.push(self.span); + self.emit_byte(constant_index); + // self.chunk.bytecode.push(constant_index as u8); + // self.spans.push(self.span); self.stack_depth += 1; } @@ -380,10 +384,12 @@ impl Compiler { if constant_index == self.chunk.constants.len() { self.chunk.constants.push(val); } - self.chunk.bytecode.push(Op::MatchConstant as u8); - self.spans.push(self.span); - self.chunk.bytecode.push(constant_index as u8); - self.spans.push(self.span); + self.emit_op(Op::MatchConstant); + self.emit_byte(constant_index); + // self.chunk.bytecode.push(Op::MatchConstant as u8); + // self.spans.push(self.span); + // self.chunk.bytecode.push(constant_index as u8); + // self.spans.push(self.span); } fn emit_op(&mut self, op: Op) { @@ -572,6 +578,12 @@ impl Compiler { } self.match_constant(Value::Keyword(kw_index)); } + AsPattern(word, typ) => { + self.emit_constant(self.chunk.kw_from(typ).unwrap()); + self.emit_op(Op::MatchType); + self.stack_depth -= 1; + self.bind(word); + } StringPattern(s) => { let existing_str = self.chunk.strings.iter().position(|e| e == s); let str_index = match existing_str { @@ -1142,7 +1154,6 @@ impl Compiler { | Do(..) | Splat(..) | InterpolatedPattern(..) - | AsPattern(..) | Splattern(..) => todo!(), And | Or => unreachable!(), } @@ -1160,7 +1171,7 @@ impl Compiler { | MatchFalse | MatchWord | ResetMatch | PanicIfNoMatch | GetKey | PanicNoWhen | PanicNoMatch | TypeOf | Duplicate | Truncate | Decrement | LoadTuple | LoadList | Eq | Add | Sub | Mult | Div | Unbox | BoxStore | Assert | Get | At - | Not | Panic | EmptyString | ConcatStrings | Stringify => { + | Not | Panic | EmptyString | ConcatStrings | Stringify | MatchType => { println!("{i:04}: {op}") } Constant | MatchConstant => { diff --git a/src/main.rs b/src/main.rs index 770a628..34bbed9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,10 +74,8 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " -let x = 42 -let y = :foo -let z = \"thing\" -\"{x} {y} {z}\" +let (x as :keyword, y as :number) = (:ok, 42) +[x, y] "; run(src); } diff --git a/src/vm.rs b/src/vm.rs index ca6088d..405ada7 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -249,6 +249,15 @@ impl<'a> Vm<'a> { self.matches = true; self.ip += 1; } + MatchType => { + let as_type = self.pop(); + let idx = self.stack.len() - self.match_depth as usize - 1; + let val_type = self.stack[idx].type_of(); + let val_type = self.chunk.kw_from(val_type).unwrap(); + self.matches = val_type == as_type; + self.ip += 1; + self.interpret() + } MatchNil => { let idx = self.stack.len() - self.match_depth as usize - 1; if self.stack[idx] == Value::Nil { @@ -579,14 +588,15 @@ impl<'a> Vm<'a> { self.push(Value::String(Rc::new("".to_string()))); self.ip += 1; } + //TODO: don't use the schlemiel's algo here ConcatStrings => { let second = self.pop(); let first = self.pop(); let combined = match (first, second) { (Value::String(first), Value::String(second)) => { - let mut newstr = first.as_ref().clone(); - newstr.push_str(second.as_str()); - Value::String(Rc::new(newstr)) + let mut new = first.as_ref().clone(); + new.push_str(second.as_str()); + Value::String(Rc::new(new)) } _ => unreachable!(), };