aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs55
-rw-r--r--src/lib.rs17
-rw-r--r--src/vm.rs74
3 files changed, 109 insertions, 37 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index d12ee4b..193d16c 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -117,6 +117,8 @@ pub(crate) struct Compiler {
blobs: Vec<Blob>,
functions: HashMap<String, (usize, RustFunction)>,
+ constants: Vec<Value>,
+ strings: Vec<String>,
}
macro_rules! push_frame {
@@ -187,9 +189,32 @@ impl Compiler {
blobs: Vec::new(),
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()
+ }
+
+ fn add_constant(&mut self, value: Value) -> usize {
+ self.constants.push(value);
+ self.constants.len() - 1
+ }
+
+ fn intern_string(&mut self, string: String) -> usize {
+ self.strings.push(string);
+ self.strings.len() - 1
+ }
+
fn frame(&self) -> &Frame {
let last = self.frames.len() - 1;
&self.frames[last]
@@ -336,7 +361,8 @@ impl Compiler {
Token::String(s) => { Value::String(Rc::from(s)) }
_ => { error!(self, "Cannot parse value."); Value::Bool(false) }
};
- add_op(self, block, Op::Constant(value));
+ let constant = self.add_constant(value);
+ add_op(self, block, Op::Constant(constant));
}
fn grouping_or_tuple(&mut self, block: &mut Block) {
@@ -586,7 +612,7 @@ impl Compiler {
Op::Pop | Op::PopUpvalue => {}
Op::Return => { break; } ,
_ => {
- add_op(self, &mut function_block, Op::Constant(Value::Nil));
+ add_op(self, &mut function_block, Op::Constant(self.nil_value()));
add_op(self, &mut function_block, Op::Return);
break;
}
@@ -594,7 +620,7 @@ impl Compiler {
}
if function_block.ops.is_empty() {
- add_op(self, &mut function_block, Op::Constant(Value::Nil));
+ add_op(self, &mut function_block, Op::Constant(self.nil_value()));
add_op(self, &mut function_block, Op::Return);
}
@@ -602,9 +628,9 @@ impl Compiler {
let function_block = Rc::new(RefCell::new(function_block));
- let func = Op::Constant(Value::Function(Vec::new(), Rc::clone(&function_block)));
+ let constant = self.add_constant(Value::Function(Vec::new(), Rc::clone(&function_block)));
self.blocks[block_id] = function_block;
- add_op(self, block, func);
+ add_op(self, block, Op::Constant(constant));
}
fn variable_expression(&mut self, block: &mut Block) {
@@ -623,7 +649,8 @@ impl Compiler {
Token::Dot => {
self.eat();
if let Token::Identifier(field) = self.eat() {
- add_op(self, block, Op::Get(String::from(field)));
+ let string = self.intern_string(String::from(field));
+ add_op(self, block, Op::Get(string));
} else {
error!(self, "Expected fieldname after '.'.");
break;
@@ -636,12 +663,14 @@ impl Compiler {
}
}
} else if let Some(blob) = self.find_blob(&name) {
- add_op(self, block, Op::Constant(Value::Blob(blob)));
+ let string = self.add_constant(Value::Blob(blob));
+ add_op(self, block, Op::Constant(string));
if self.peek() == Token::LeftParen {
self.call(block);
}
} else if let Some(slot) = self.find_extern_function(&name) {
- add_op(self, block, Op::Constant(Value::ExternFunction(slot)));
+ let string = self.add_constant(Value::ExternFunction(slot));
+ add_op(self, block, Op::Constant(string));
self.call(block);
} else {
error!(self, format!("Using undefined variable {}.", name));
@@ -675,7 +704,8 @@ impl Compiler {
fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) {
let slot = self.define_variable(name, typ.clone(), block);
self.expression(block);
- add_op(self, block, Op::Define(typ));
+ let constant = self.add_constant(Value::Ty(typ));
+ add_op(self, block, Op::Define(constant));
if let Ok(slot) = slot {
self.stack_mut()[slot].active = true;
@@ -940,6 +970,7 @@ impl Compiler {
return Err(());
};
+ let field = self.intern_string(field);
let op = match self.peek() {
Token::Equal => {
self.eat();
@@ -959,7 +990,7 @@ impl Compiler {
}
};
add_op(self, block, Op::Copy);
- add_op(self, block, Op::Get(field.clone()));
+ add_op(self, block, Op::Get(field));
self.eat();
self.expression(block);
add_op(self, block, op);
@@ -1096,7 +1127,7 @@ impl Compiler {
self.statement(&mut block);
expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression.");
}
- add_op(self, &mut block, Op::Constant(Value::Nil));
+ add_op(self, &mut block, Op::Constant(self.nil_value()));
add_op(self, &mut block, Op::Return);
block.ty = Type::Function(Vec::new(), Box::new(Type::Void));
@@ -1107,6 +1138,8 @@ impl Compiler {
blocks: self.blocks.clone(),
blobs: self.blobs.iter().map(|x| Rc::new(x.clone())).collect(),
functions: functions.iter().map(|(_, f)| *f).collect(),
+ constants: self.constants.clone(),
+ strings: self.strings.clone(),
})
} else {
Err(self.errors.clone())
diff --git a/src/lib.rs b/src/lib.rs
index cca1a58..e49e653 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -162,6 +162,7 @@ impl From<Type> for Value {
#[derive(Clone)]
pub enum Value {
+ Ty(Type),
Blob(usize),
BlobInstance(usize, Rc<RefCell<Vec<Value>>>),
Tuple(Rc<Vec<Value>>),
@@ -178,6 +179,7 @@ pub enum Value {
impl Debug for Value {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
+ Value::Ty(ty) => write!(fmt, "(type {:?})", ty),
Value::Blob(i) => write!(fmt, "(blob {})", i),
Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v),
Value::Float(f) => write!(fmt, "(float {})", f),
@@ -307,11 +309,11 @@ pub enum Op {
///
/// {A, B} - Copy - {A, B, B}
Copy,
- /// Adds the given value to the top of the stack.
+ /// Adds the value indexed in the `constants-vector` to the top of the stack.
/// Also links upvalues if the value is a function.
///
/// {A} - Constant(B) - {A, B}
- Constant(Value),
+ Constant(usize),
/// Creates a new [Tuple] with the given size and place it on the top
/// of the stack.
///
@@ -326,15 +328,17 @@ pub enum Op {
/// Looks up a field by the given name
/// and replaces the parent with it.
/// Currently only expects [Value::Blob].
+ /// (name is looked up in the internal string-list)
///
/// {O} - Get(F) - {O.F}
- Get(String),
+ Get(usize),
/// Looks up a field by the given name
/// and replaces the current value in the object.
/// Currently only expects [Value::Blob].
+ /// (name is looked up in the internal string-list)
///
/// {O} - Set(F) - {}
- Set(String),
+ Set(usize),
/// Adds the two top elements on the stack,
/// using the function [op::add]. The result
@@ -452,9 +456,10 @@ pub enum Op {
/// makes sure the top value on the stack
/// is of the given type, and is ment to signal
/// that the "variable" is added.
+ /// (The type is looked up in the constants vector)
///
/// Does not affect the stack.
- Define(Type),
+ Define(usize),
/// Calls "something" with the given number
/// of arguments. The callable value is
@@ -702,6 +707,8 @@ pub struct Prog {
pub blocks: Vec<Rc<RefCell<Block>>>,
pub blobs: Vec<Rc<Blob>>,
pub functions: Vec<RustFunction>,
+ pub constants: Vec<Value>,
+ pub strings: Vec<String>,
}
#[cfg(test)]
diff --git a/src/vm.rs b/src/vm.rs
index 5a7b471..cb2c40d 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -58,6 +58,8 @@ pub struct VM {
frames: Vec<Frame>,
blobs: Vec<Rc<Blob>>,
+ constants: Vec<Value>,
+ strings: Vec<String>,
pub print_blocks: bool,
pub print_ops: bool,
@@ -83,7 +85,11 @@ impl VM {
stack: Vec::new(),
frames: Vec::new(),
+
blobs: Vec::new(),
+ constants: Vec::new(),
+ strings: Vec::new(),
+
print_blocks: false,
print_ops: false,
@@ -132,6 +138,21 @@ impl VM {
&mut self.frames[last]
}
+ fn constant(&self, slot: usize) -> &Value {
+ &self.constants[slot]
+ }
+
+ fn ty(&self, slot: usize) -> &Type {
+ match &self.constants[slot] {
+ Value::Ty(ty) => ty,
+ _ => self.crash_and_burn(),
+ }
+ }
+
+ fn string(&self, slot: usize) -> &String {
+ &self.strings[slot]
+ }
+
fn op(&self) -> Op {
let ip = self.frame().ip;
self.frame().block.borrow().ops[ip].clone()
@@ -197,7 +218,8 @@ impl VM {
Op::Constant(value) => {
let offset = self.frame().stack_offset;
- let value = match value {
+ let constant = self.constant(value).clone();
+ let value = match constant {
Value::Function(_, block) => {
let mut ups = Vec::new();
for (slot, is_up, _) in block.borrow().upvalues.iter() {
@@ -215,7 +237,7 @@ impl VM {
}
Value::Function(ups, block)
},
- _ => value.clone(),
+ value => value,
};
self.push(value);
}
@@ -240,23 +262,25 @@ impl VM {
}
}
- Op::Get(field) => {
+ Op::Get(field_ident) => {
let inst = self.pop();
+ let field = self.string(field_ident);
if let Value::BlobInstance(ty, values) = inst {
- let slot = self.blobs[ty].fields.get(&field).unwrap().0;
+ let slot = self.blobs[ty].fields.get(field).unwrap().0;
self.push(values.borrow()[slot].clone());
} else {
- error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst]));
+ error!(self, ErrorKind::RuntimeTypeError(Op::Get(field_ident), vec![inst]));
}
}
- Op::Set(field) => {
+ Op::Set(field_ident) => {
let (inst, value) = self.poppop();
+ let field = self.string(field_ident);
if let Value::BlobInstance(ty, values) = inst {
- let slot = self.blobs[ty].fields.get(&field).unwrap().0;
+ let slot = self.blobs[ty].fields.get(field).unwrap().0;
values.borrow_mut()[slot] = value;
} else {
- error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst]));
+ error!(self, ErrorKind::RuntimeTypeError(Op::Get(field_ident), vec![inst]));
}
}
@@ -428,6 +452,9 @@ impl VM {
pub(crate) fn init(&mut self, prog: &Prog) {
let block = Rc::clone(&prog.blocks[0]);
self.blobs = prog.blobs.clone();
+ self.constants = prog.constants.clone();
+ self.strings = prog.strings.clone();
+
self.extern_functions = prog.functions.clone();
self.stack.clear();
self.frames.clear();
@@ -469,8 +496,8 @@ impl VM {
Op::Yield => {}
- Op::Constant(ref value) => {
- match value.clone() {
+ Op::Constant(value) => {
+ match self.constant(value).clone() {
Value::Function(_, block) => {
self.push(Value::Function(Vec::new(), block.clone()));
@@ -500,34 +527,35 @@ impl VM {
}
};
},
- _ => {
+ value => {
self.push(value.clone());
}
}
}
- Op::Get(field) => {
+ Op::Get(field_ident) => {
let inst = self.pop();
+ let field = self.string(field_ident);
if let Value::BlobInstance(ty, _) = inst {
- let value = Value::from(&self.blobs[ty].fields.get(&field).unwrap().1);
+ let value = Value::from(&self.blobs[ty].fields.get(field).unwrap().1);
self.push(value);
} else {
self.push(Value::Nil);
- error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst]));
+ error!(self, ErrorKind::RuntimeTypeError(Op::Get(field_ident), vec![inst]));
}
}
- Op::Set(field) => {
- let value = self.pop();
- let inst = self.pop();
+ Op::Set(field_ident) => {
+ let (inst, value) = self.poppop();
+ let field = self.string(field_ident);
if let Value::BlobInstance(ty, _) = inst {
- let ty = &self.blobs[ty].fields.get(&field).unwrap().1;
+ let ty = &self.blobs[ty].fields.get(field).unwrap().1;
if ty != &Type::from(&value) {
- error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst]));
+ error!(self, ErrorKind::RuntimeTypeError(Op::Set(field_ident), vec![inst]));
}
} else {
- error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst]));
+ error!(self, ErrorKind::RuntimeTypeError(Op::Set(field_ident), vec![inst]));
}
}
@@ -564,7 +592,8 @@ impl VM {
self.pop();
}
- Op::Define(ref ty) => {
+ Op::Define(ty) => {
+ let ty = self.ty(ty);
let top_type = self.stack.last().unwrap().into();
match (ty, top_type) {
(Type::Unknown, top_type)
@@ -707,6 +736,9 @@ impl VM {
let mut errors = Vec::new();
self.blobs = prog.blobs.clone();
+ self.constants = prog.constants.clone();
+ self.strings = prog.strings.clone();
+
self.extern_functions = prog.functions.clone();
for block in prog.blocks.iter() {
errors.append(&mut self.typecheck_block(Rc::clone(block)));