keywords and interned strings use &'static str instead of indexes into vecs
This commit is contained in:
parent
681176282c
commit
86992078e9
125
src/compiler.rs
125
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<Value> {
|
||||
self.kw_index_from(kw).map(Value::Keyword)
|
||||
}
|
||||
// pub fn kw_from(&self, kw: &str) -> Option<Value> {
|
||||
// self.kw_index_from(kw).map(Value::Keyword)
|
||||
// }
|
||||
|
||||
pub fn kw_index_from(&self, kw: &str) -> Option<usize> {
|
||||
self.keywords.iter().position(|s| *s == kw)
|
||||
|
@ -334,13 +334,13 @@ impl Compiler {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn kw_from(&self, kw: &str) -> Option<Value> {
|
||||
self.kw_index_from(kw).map(Value::Keyword)
|
||||
}
|
||||
// pub fn kw_from(&self, kw: &str) -> Option<Value> {
|
||||
// self.kw_index_from(kw).map(Value::Keyword)
|
||||
// }
|
||||
|
||||
pub fn kw_index_from(&self, kw: &str) -> Option<usize> {
|
||||
self.chunk.keywords.iter().position(|s| *s == kw)
|
||||
}
|
||||
// pub fn kw_index_from(&self, kw: &str) -> Option<usize> {
|
||||
// self.chunk.keywords.iter().position(|s| *s == kw)
|
||||
// }
|
||||
|
||||
pub fn visit(&mut self, node: &'static Spanned<Ast>) {
|
||||
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) => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
57
src/value.rs
57
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<String>),
|
||||
Number(f64),
|
||||
Tuple(Rc<Vec<Value>>),
|
||||
List(Box<Vector<Value>>),
|
||||
Dict(Box<HashMap<usize, Value>>),
|
||||
Dict(Box<HashMap<&'static str, Value>>),
|
||||
Box(Rc<RefCell<Value>>),
|
||||
Fn(Rc<OnceCell<LFn>>),
|
||||
}
|
||||
|
@ -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::<Vec<_>>().join(", ");
|
||||
let members = t.iter().map(|e| e.show()).collect::<Vec<_>>().join(", ");
|
||||
format!("({members})")
|
||||
}
|
||||
List(l) => {
|
||||
let members = l.iter().map(|e| e.show(ctx)).collect::<Vec<_>>().join(", ");
|
||||
let members = l.iter().map(|e| e.show()).collect::<Vec<_>>().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::<Vec<_>>()
|
||||
.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::<Vec<_>>()
|
||||
.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::<Vec<_>>()
|
||||
.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::<Vec<_>>()
|
||||
|
@ -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",
|
||||
|
|
23
src/vm.rs
23
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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user