aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs51
-rw-r--r--src/lib.rs38
2 files changed, 71 insertions, 18 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index cd4ffda..26c70de 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -255,8 +255,12 @@ pub(crate) struct Compiler {
unknown: HashMap<String, (usize, usize)>,
functions: HashMap<String, (usize, RustFunction)>,
- constants: Vec<Value>,
+
strings: Vec<String>,
+
+ constants: Vec<Value>,
+ values: HashMap<Value, usize>,
+
}
macro_rules! push_frame {
@@ -353,19 +357,11 @@ impl Compiler {
functions: HashMap::new(),
- constants: vec![Value::Nil],
strings: Vec::new(),
- }
- }
- fn nil_value(&self) -> usize {
- self.constants.iter()
- .enumerate()
- .find_map(|(i, x)|
- match x {
- Value::Nil => Some(i),
- _ => None,
- }).unwrap()
+ constants: vec![],
+ values: HashMap::new(),
+ }
}
fn new_blob_id(&mut self) -> usize {
@@ -375,8 +371,25 @@ impl Compiler {
}
fn add_constant(&mut self, value: Value) -> usize {
- self.constants.push(value);
- self.constants.len() - 1
+ if matches!(value, Value::Float(_)
+ | Value::Int(_)
+ | Value::Bool(_)
+ | Value::String(_)
+ | Value::Tuple(_)
+ | Value::Nil) {
+ let entry = self.values.entry(value.clone());
+ if let Entry::Occupied(entry) = entry {
+ *entry.get()
+ } else {
+ let slot = self.constants.len();
+ self.constants.push(value);
+ entry.or_insert(slot);
+ slot
+ }
+ } else {
+ self.constants.push(value);
+ self.constants.len() - 1
+ }
}
fn intern_string(&mut self, string: String) -> usize {
@@ -710,7 +723,7 @@ impl Compiler {
if let Some(res) = res {
return res;
}
- let constant = self.add_constant(Value::Nil);
+ let constant = self.add_constant(Value::Unknown);
let line = self.line();
let entry = self.unknown.entry(name.to_string());
entry.or_insert((constant, line)).0
@@ -847,12 +860,13 @@ impl Compiler {
}
});
+ let nil = self.add_constant(Value::Nil);
for op in function_block.ops.iter().rev() {
match op {
Op::Pop | Op::PopUpvalue => {}
Op::Return => { break; } ,
_ => {
- add_op(self, &mut function_block, Op::Constant(self.nil_value()));
+ add_op(self, &mut function_block, Op::Constant(nil));
add_op(self, &mut function_block, Op::Return);
break;
}
@@ -860,7 +874,7 @@ impl Compiler {
}
if function_block.ops.is_empty() {
- add_op(self, &mut function_block, Op::Constant(self.nil_value()));
+ add_op(self, &mut function_block, Op::Constant(nil));
add_op(self, &mut function_block, Op::Return);
}
@@ -1440,7 +1454,8 @@ impl Compiler {
expect!(self, Token::Newline | Token::EOF,
"Expect newline or EOF after expression.");
}
- add_op(self, &mut block, Op::Constant(self.nil_value()));
+ let tmp = self.add_constant(Value::Unknown);
+ add_op(self, &mut block, Op::Constant(tmp));
add_op(self, &mut block, Op::Return);
block.ty = Type::Function(Vec::new(), Box::new(Type::Void));
diff --git a/src/lib.rs b/src/lib.rs
index 91938f1..5908fa4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,6 +4,7 @@ use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::path::{Path, PathBuf};
use std::rc::Rc;
+use std::hash::{Hash, Hasher};
use owo_colors::OwoColorize;
@@ -198,6 +199,43 @@ impl Debug for Value {
}
}
+impl PartialEq<Value> for Value {
+ fn eq(&self, other: &Value) -> bool {
+ match (self, other) {
+ (Value::Float(a), Value::Float(b)) => a == b,
+ (Value::Int(a), Value::Int(b)) => a == b,
+ (Value::Bool(a), Value::Bool(b)) => a == b,
+ (Value::String(a), Value::String(b)) => a == b,
+ (Value::Tuple(a), Value::Tuple(b)) => {
+ a.len() == b.len() && a.iter().zip(b.iter()).all(|(a, b)| a == b)
+ }
+ (Value::Nil, Value::Nil) => true,
+ _ => false,
+ }
+ }
+}
+
+impl Eq for Value {}
+
+impl Hash for Value {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ match self {
+ Value::Float(a) => {
+ // We have to limit the values, because
+ // floats are wierd.
+ assert!(a.is_finite());
+ a.to_bits().hash(state);
+ },
+ Value::Int(a) => a.hash(state),
+ Value::Bool(a) => a.hash(state),
+ Value::String(a) => a.hash(state),
+ Value::Tuple(a) => a.hash(state),
+ Value::Nil => state.write_i8(0),
+ _ => {},
+ };
+ }
+}
+
impl Value {
fn identity(self) -> Self {
match self {