diff --git a/src/compiler.rs b/src/compiler.rs index 0470138..4539827 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -219,7 +219,7 @@ impl Chunk { } Constant | MatchConstant => { let next = self.bytecode[*i + 1]; - let value = &self.constants[next as usize].show(self); + let value = &self.constants[next as usize].show(); println!("{i:04}: {:16} {next:04}: {value}", op.to_string()); *i += 1; } @@ -242,9 +242,9 @@ impl Chunk { } } - pub fn kw_from(&self, kw: &str) -> Option { - self.kw_index_from(kw).map(Value::Keyword) - } + // pub fn kw_from(&self, kw: &str) -> Option { + // self.kw_index_from(kw).map(Value::Keyword) + // } pub fn kw_index_from(&self, kw: &str) -> Option { self.keywords.iter().position(|s| *s == kw) @@ -334,13 +334,13 @@ impl Compiler { } } - pub fn kw_from(&self, kw: &str) -> Option { - self.kw_index_from(kw).map(Value::Keyword) - } + // pub fn kw_from(&self, kw: &str) -> Option { + // self.kw_index_from(kw).map(Value::Keyword) + // } - pub fn kw_index_from(&self, kw: &str) -> Option { - self.chunk.keywords.iter().position(|s| *s == kw) - } + // pub fn kw_index_from(&self, kw: &str) -> Option { + // self.chunk.keywords.iter().position(|s| *s == kw) + // } pub fn visit(&mut self, node: &'static Spanned) { let root_node = self.ast; @@ -353,31 +353,36 @@ impl Compiler { 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_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(s)); + // } fn emit_constant(&mut self, val: Value) { - let constant_index = self.chunk.constants.len(); - if constant_index > u8::MAX as usize { + let const_idx = if let Some(idx) = self.chunk.constants.iter().position(|v| *v == val) { + idx + } else { + self.chunk.constants.push(val); + self.chunk.constants.len() - 1 + }; + + if const_idx > u8::MAX as usize { panic!( "internal Ludus compiler error: too many constants in chunk:{}:: {}", self.span, self.ast ) } - self.chunk.constants.push(val); self.emit_op(Op::Constant); // self.chunk.bytecode.push(Op::Constant as u8); // self.spans.push(self.span); - self.emit_byte(constant_index); + self.emit_byte(const_idx); // self.chunk.bytecode.push(constant_index as u8); // self.spans.push(self.span); self.stack_depth += 1; @@ -386,7 +391,10 @@ impl Compiler { fn match_constant(&mut self, val: Value) { let constant_index = match self.chunk.constants.iter().position(|v| *v == val) { Some(idx) => idx, - None => self.chunk.constants.len(), + None => { + self.chunk.constants.push(val); + self.chunk.constants.len() - 1 + } }; if constant_index > u8::MAX as usize { panic!( @@ -394,15 +402,8 @@ impl Compiler { self.span, self.ast ) } - if constant_index == self.chunk.constants.len() { - self.chunk.constants.push(val); - } 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) { @@ -476,15 +477,15 @@ impl Compiler { self.stack_depth += 1; } String(s) => { - let existing_str = self.chunk.strings.iter().position(|e| e == s); - let str_index = match existing_str { - Some(idx) => idx, - None => self.chunk.strings.len(), - }; - self.chunk.strings.push(s); - self.emit_constant(Value::Interned(str_index)); + // let existing_str = self.chunk.strings.iter().position(|e| e == s); + // let str_index = match existing_str { + // Some(idx) => idx, + // None => self.chunk.strings.len(), + // }; + // self.chunk.strings.push(s); + self.emit_constant(Value::Interned(s)); } - Keyword(s) => self.emit_keyword(s), + Keyword(s) => self.emit_constant(Value::Keyword(s)), Block(lines) => { self.scope_depth += 1; let stack_depth = self.stack_depth; @@ -589,24 +590,24 @@ impl Compiler { if kw_index == self.chunk.keywords.len() { self.chunk.keywords.push(s); } - self.match_constant(Value::Keyword(kw_index)); + self.match_constant(Value::Keyword(s)); } AsPattern(word, typ) => { - self.emit_constant(self.chunk.kw_from(typ).unwrap()); + self.emit_constant(Value::Keyword(typ)); 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 { - Some(idx) => idx, - None => self.chunk.strings.len(), - }; - if str_index == self.chunk.strings.len() { - self.chunk.strings.push(s) - } - self.match_constant(Value::Interned(str_index)); + // let existing_str = self.chunk.strings.iter().position(|e| e == s); + // let str_index = match existing_str { + // Some(idx) => idx, + // None => self.chunk.strings.len(), + // }; + // if str_index == self.chunk.strings.len() { + // self.chunk.strings.push(s) + // } + self.match_constant(Value::Interned(s)); } TuplePattern(members) => { self.emit_op(Op::MatchTuple); @@ -696,7 +697,7 @@ impl Compiler { }; // algo: // push the keyword onto the stack - self.emit_keyword(key); + self.emit_constant(Value::Keyword(key)); // pull the value out of the dict self.emit_op(Op::LoadDictValue); self.emit_byte(dict_stack_pos); @@ -759,15 +760,15 @@ impl Compiler { ); } Pair(key, value) => { - let existing_kw = self.chunk.keywords.iter().position(|kw| kw == key); - 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(key); - } - self.emit_constant(Value::Keyword(kw_index)); + // let existing_kw = self.chunk.keywords.iter().position(|kw| kw == key); + // 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(key); + // } + self.emit_constant(Value::Keyword(key)); self.visit(value); } Synthetic(first, second, rest) => { diff --git a/src/main.rs b/src/main.rs index c356c78..11573f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,14 +61,12 @@ pub fn run(src: &'static str) { println!("=== vm run: test ==="); } - // TODO: investigate lifeteims and remove this clone - let show_chunk = compiler.chunk.clone(); let vm_chunk = compiler.chunk; let mut vm = Vm::new(vm_chunk); let result = vm.run(); let output = match result { - Ok(val) => val.show(&show_chunk), + Ok(val) => val.show(), Err(panic) => format!("Ludus panicked! {panic}"), }; vm.print_stack(); @@ -78,9 +76,9 @@ pub fn run(src: &'static str) { pub fn main() { env::set_var("RUST_BACKTRACE", "1"); let src = " -fn foo (_) -> [1, 2, 3] +fn foo (_) -> :foo -foo (1) +foo (nil) "; run(src); } diff --git a/src/value.rs b/src/value.rs index caf3b6a..0a0258a 100644 --- a/src/value.rs +++ b/src/value.rs @@ -29,14 +29,13 @@ pub enum Value { Nil, True, False, - Keyword(usize), - Interned(usize), - FnDecl(usize), + Keyword(&'static str), + Interned(&'static str), String(Rc), Number(f64), Tuple(Rc>), List(Box>), - Dict(Box>), + Dict(Box>), Box(Rc>), Fn(Rc>), } @@ -49,8 +48,8 @@ impl std::fmt::Display for Value { Nil => write!(f, "nil"), True => write!(f, "true"), False => write!(f, "false"), - Keyword(idx) => write!(f, ":{idx}"), - Interned(idx) => write!(f, "\"@{idx}\""), + Keyword(str) => write!(f, ":{str}"), + Interned(str) => write!(f, "\"{str}\""), String(str) => write!(f, "\"{str}\""), Number(n) => write!(f, "{n}"), Tuple(members) => write!( @@ -82,76 +81,63 @@ impl std::fmt::Display for Value { ), Box(value) => write!(f, "box {}", value.as_ref().borrow()), Fn(lfn) => write!(f, "fn {}", lfn.get().unwrap().name), - _ => todo!(), } } } impl Value { - pub fn show(&self, ctx: &Chunk) -> String { + pub fn show(&self) -> String { use Value::*; match &self { Nil => "nil".to_string(), True => "true".to_string(), False => "false".to_string(), Number(n) => format!("{n}"), - Interned(i) => { - let str_str = ctx.strings[*i]; - format!("\"{str_str}\"") - } + Interned(str) => format!("\"{str}\""), String(str) => { let str_str = str.to_string(); format!("\"{str_str}\"") } - Keyword(i) => { - let kw_str = ctx.keywords[*i]; - format!(":{kw_str}") - } + Keyword(str) => format!(":{str}"), Tuple(t) => { - let members = t.iter().map(|e| e.show(ctx)).collect::>().join(", "); + let members = t.iter().map(|e| e.show()).collect::>().join(", "); format!("({members})") } List(l) => { - let members = l.iter().map(|e| e.show(ctx)).collect::>().join(", "); + let members = l.iter().map(|e| e.show()).collect::>().join(", "); format!("[{members}]") } Dict(d) => { let members = d .iter() .map(|(k, v)| { - let key_show = Value::Keyword(*k).show(ctx); - let value_show = v.show(ctx); + let key_show = Value::Keyword(k).show(); + let value_show = v.show(); format!("{key_show} {value_show}") }) .collect::>() .join(", "); format!("#{{{members}}}") } - Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show(ctx)), + Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()), Fn(lfn) => format!("fn {}", lfn.get().unwrap().name), _ => todo!(), } } - pub fn stringify(&self, ctx: &Chunk) -> String { + pub fn stringify(&self) -> String { use Value::*; match &self { Nil => "nil".to_string(), True => "true".to_string(), False => "false".to_string(), Number(n) => format!("{n}"), - Interned(i) => { - let str_str = ctx.strings[*i]; - str_str.to_string() - } - Keyword(i) => { - let kw_str = ctx.keywords[*i]; - format!(":{kw_str}") - } + Interned(str) => str.to_string(), + Keyword(str) => str.to_string(), Tuple(t) => { let members = t .iter() - .map(|e| e.stringify(ctx)) + .map(|e| e.stringify()) .collect::>() .join(", "); members.to_string() @@ -159,7 +145,7 @@ impl Value { List(l) => { let members = l .iter() - .map(|e| e.stringify(ctx)) + .map(|e| e.stringify()) .collect::>() .join(", "); members.to_string() @@ -168,8 +154,8 @@ impl Value { let members = d .iter() .map(|(k, v)| { - let key_show = Value::Keyword(*k).show(ctx); - let value_show = v.show(ctx); + let key_show = Value::Keyword(k).stringify(); + let value_show = v.stringify(); format!("{key_show} {value_show}") }) .collect::>() @@ -177,7 +163,7 @@ impl Value { members.to_string() } String(s) => s.as_ref().clone(), - Box(x) => x.as_ref().borrow().stringify(ctx), + Box(x) => x.as_ref().borrow().stringify(), Fn(lfn) => lfn.get().unwrap().name.to_string(), _ => todo!(), } @@ -192,7 +178,6 @@ impl Value { False => "bool", Keyword(..) => "keyword", Interned(..) => "string", - FnDecl(..) => "fn", String(..) => "string", Number(..) => "number", Tuple(..) => "tuple", diff --git a/src/vm.rs b/src/vm.rs index a3b9a70..f8a697f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -300,9 +300,11 @@ impl Vm { } MatchType => { let as_type = self.pop(); + let Value::Keyword(as_type) = as_type else { + unreachable!() + }; 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; } @@ -473,7 +475,7 @@ impl Vm { } TypeOf => { let val = self.pop(); - let type_of = self.chunk().kw_from(val.type_of()).unwrap(); + let type_of = Value::Keyword(val.type_of()); self.push(type_of); self.ip += 1; } @@ -626,7 +628,7 @@ impl Vm { self.ip += 1; } Panic => { - let msg = self.pop().show(self.chunk()); + let msg = self.pop().show(); return self.panic_with(msg); } EmptyString => { @@ -650,7 +652,7 @@ impl Vm { } Stringify => { let to_stringify = self.pop(); - let the_string = to_stringify.stringify(self.chunk()); + let the_string = to_stringify.stringify(); let stringified = Value::String(Rc::new(the_string)); self.push(stringified); self.ip += 1; @@ -661,8 +663,7 @@ impl Vm { let val = self.pop(); let Value::Fn(_) = val else { - return self - .panic_with(format!("{} is not a function", val.show(self.chunk()))); + return self.panic_with(format!("{} is not a function", val.show())); }; let mut frame = CallFrame { @@ -679,18 +680,12 @@ impl Vm { self.ip = 0; if crate::DEBUG_RUN { - println!( - "== calling into {} ==", - self.frame.function.show(self.chunk()) - ); + println!("== calling into {} ==", self.frame.function.show()); } } Return => { if crate::DEBUG_RUN { - println!( - "== returning from {} ==", - self.frame.function.show(self.chunk()) - ) + println!("== returning from {} ==", self.frame.function.show()) } self.frame = self.call_stack.pop().unwrap(); self.ip = self.frame.ip;