2019-06-30 08:57:18 -05:00
|
|
|
// Copyright 2019 Jeremy Wall
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
|
|
|
pub mod pointer;
|
|
|
|
use pointer::OpPointer;
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum Primitive {
|
|
|
|
// Primitive Types
|
|
|
|
Int(i64),
|
|
|
|
Float(f64),
|
|
|
|
Str(String),
|
|
|
|
Bool(bool),
|
|
|
|
Empty,
|
|
|
|
}
|
|
|
|
|
2019-06-30 23:43:33 -05:00
|
|
|
use Primitive::{Bool, Float, Int, Str};
|
2019-06-30 22:51:47 -05:00
|
|
|
|
2019-06-30 08:57:18 -05:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum Composite {
|
|
|
|
List(Vec<Value>),
|
|
|
|
Tuple(Vec<(String, Value)>),
|
|
|
|
}
|
|
|
|
|
2019-06-30 17:31:49 -05:00
|
|
|
use Composite::{List, Tuple};
|
|
|
|
|
2019-06-30 08:57:18 -05:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum Value {
|
|
|
|
// Binding names.
|
|
|
|
S(String),
|
|
|
|
// Primitive Types
|
|
|
|
P(Primitive),
|
|
|
|
// Composite Types.
|
|
|
|
C(Composite),
|
|
|
|
// Program Pointer
|
|
|
|
T(usize),
|
|
|
|
}
|
2019-06-30 22:51:47 -05:00
|
|
|
use Value::{C, P, S, T};
|
2019-06-30 08:57:18 -05:00
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum Op {
|
|
|
|
// Stack and Name manipulation.
|
|
|
|
Bind, // Bind a Val to a name in the heap
|
|
|
|
Pop, // Pop a Value off the value stack and discard it.
|
|
|
|
// Math ops
|
|
|
|
Add,
|
|
|
|
Sub,
|
|
|
|
Div,
|
|
|
|
Mul,
|
2019-06-30 22:51:47 -05:00
|
|
|
// Comparison Ops
|
|
|
|
Equal,
|
|
|
|
Gt,
|
|
|
|
Lt,
|
|
|
|
GtEq,
|
|
|
|
LtEq,
|
2019-06-30 08:57:18 -05:00
|
|
|
// Primitive Types ops
|
|
|
|
Val(Primitive),
|
|
|
|
// A bareword for use in bindings or lookups
|
|
|
|
Sym(String),
|
|
|
|
// Complex Type ops
|
|
|
|
InitTuple,
|
2019-06-30 22:21:28 -05:00
|
|
|
Field,
|
2019-06-30 08:57:18 -05:00
|
|
|
InitList,
|
|
|
|
Element,
|
|
|
|
// Operations
|
|
|
|
Cp,
|
2019-06-30 22:21:28 -05:00
|
|
|
// Control Flow
|
|
|
|
Bang,
|
|
|
|
Jump(usize),
|
2019-06-30 23:17:49 -05:00
|
|
|
JumpIfTrue(usize),
|
2019-06-30 22:21:28 -05:00
|
|
|
Noop,
|
|
|
|
// Pending Computation
|
|
|
|
InitThunk(usize),
|
2019-06-30 08:57:18 -05:00
|
|
|
Return,
|
|
|
|
// - Call
|
|
|
|
// Runtime hooks
|
|
|
|
// - Map
|
|
|
|
// - Filter
|
|
|
|
// - Reduce
|
|
|
|
// - Import
|
|
|
|
// - Out
|
|
|
|
// - Assert
|
|
|
|
// - Print
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Error {}
|
|
|
|
|
|
|
|
pub struct VM {
|
|
|
|
stack: Vec<Value>,
|
2019-06-30 22:21:28 -05:00
|
|
|
// TODO(jwall): We may want to preserve order on these.
|
2019-06-30 08:57:18 -05:00
|
|
|
symbols: BTreeMap<String, Value>,
|
|
|
|
ops: OpPointer,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VM {
|
|
|
|
pub fn new(ops: Vec<Op>) -> Self {
|
|
|
|
Self {
|
|
|
|
stack: Vec::new(),
|
|
|
|
symbols: BTreeMap::new(),
|
|
|
|
ops: OpPointer::new(ops),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn run(&mut self) -> Result<(), Error> {
|
|
|
|
while self.ops.next().is_some() {
|
|
|
|
let idx = self.ops.ptr.unwrap();
|
|
|
|
match self.ops.op().unwrap() {
|
2019-06-30 23:43:33 -05:00
|
|
|
Op::Val(p) => self.push(P(p.clone()))?,
|
|
|
|
Op::Sym(s) => self.push(S(s.clone()))?,
|
2019-06-30 08:57:18 -05:00
|
|
|
Op::Add => self.op_add()?,
|
|
|
|
Op::Sub => self.op_sub()?,
|
|
|
|
Op::Mul => self.op_mul()?,
|
|
|
|
Op::Div => self.op_div()?,
|
|
|
|
Op::Bind => self.op_bind()?,
|
2019-06-30 22:51:47 -05:00
|
|
|
Op::Equal => self.op_equal()?,
|
|
|
|
Op::Gt => self.op_gt()?,
|
|
|
|
Op::Lt => self.op_lt()?,
|
|
|
|
Op::GtEq => self.op_gteq()?,
|
|
|
|
Op::LtEq => self.op_lteq()?,
|
2019-06-30 08:57:18 -05:00
|
|
|
// Add a Composite list value to the stack
|
2019-06-30 23:43:33 -05:00
|
|
|
Op::InitList => self.push(C(List(Vec::new())))?,
|
2019-06-30 08:57:18 -05:00
|
|
|
// Add a composite tuple value to the stack
|
2019-06-30 23:43:33 -05:00
|
|
|
Op::InitTuple => self.push(C(Tuple(Vec::new())))?,
|
2019-06-30 22:21:28 -05:00
|
|
|
Op::Field => self.op_field()?,
|
2019-06-30 08:57:18 -05:00
|
|
|
Op::Element => self.op_element()?,
|
|
|
|
Op::Cp => self.op_copy()?,
|
2019-06-30 22:21:28 -05:00
|
|
|
Op::Bang => return Err(Error {}),
|
|
|
|
Op::InitThunk(jp) => self.op_thunk(idx, *jp)?,
|
|
|
|
Op::Noop => {
|
|
|
|
// Do nothing
|
|
|
|
}
|
2019-06-30 08:57:18 -05:00
|
|
|
Op::Return => {
|
|
|
|
// TODO(jwall): This means we return back to the start of the frame.
|
|
|
|
}
|
2019-06-30 23:17:49 -05:00
|
|
|
Op::Jump(jp) => self.op_jump(*jp)?,
|
|
|
|
Op::JumpIfTrue(jp) => self.op_jump_if_true(*jp)?,
|
2019-06-30 08:57:18 -05:00
|
|
|
Op::Pop => {
|
|
|
|
self.pop()?;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2019-06-30 23:43:33 -05:00
|
|
|
|
2019-06-30 23:17:49 -05:00
|
|
|
fn op_jump(&mut self, jp: usize) -> Result<(), Error> {
|
|
|
|
self.ops.jump(self.ops.ptr.map(|v| v + jp).unwrap_or(jp))?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_jump_if_true(&mut self, jp: usize) -> Result<(), Error> {
|
|
|
|
if let P(Bool(cond)) = self.pop()? {
|
|
|
|
if cond {
|
|
|
|
self.op_jump(jp)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2019-06-30 08:57:18 -05:00
|
|
|
|
2019-06-30 22:21:28 -05:00
|
|
|
fn op_thunk(&mut self, idx: usize, jp: usize) -> Result<(), Error> {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(T(idx))?;
|
2019-06-30 23:17:49 -05:00
|
|
|
self.op_jump(jp)
|
2019-06-30 22:21:28 -05:00
|
|
|
}
|
|
|
|
|
2019-06-30 22:51:47 -05:00
|
|
|
fn op_equal(&mut self) -> Result<(), Error> {
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(left == right)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_gt(&mut self) -> Result<(), Error> {
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
match (left, right) {
|
|
|
|
(P(Int(i)), P(Int(ii))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(i > ii)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
(P(Float(f)), P(Float(ff))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(f > ff)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
_ => return Err(Error {}),
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_lt(&mut self) -> Result<(), Error> {
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
match (left, right) {
|
|
|
|
(P(Int(i)), P(Int(ii))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(i < ii)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
(P(Float(f)), P(Float(ff))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(f < ff)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
_ => return Err(Error {}),
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_lteq(&mut self) -> Result<(), Error> {
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
match (left, right) {
|
|
|
|
(P(Int(i)), P(Int(ii))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(i <= ii)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
(P(Float(f)), P(Float(ff))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(f <= ff)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
_ => return Err(Error {}),
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_gteq(&mut self) -> Result<(), Error> {
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
match (left, right) {
|
|
|
|
(P(Int(i)), P(Int(ii))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(i >= ii)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
(P(Float(f)), P(Float(ff))) => {
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(Bool(f >= ff)))?;
|
2019-06-30 22:51:47 -05:00
|
|
|
}
|
|
|
|
_ => return Err(Error {}),
|
|
|
|
}
|
2019-06-30 08:57:18 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_add(&mut self) -> Result<(), Error> {
|
|
|
|
// Adds the previous two items in the stack.
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
// Then pushes the result onto the stack.
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(self.add(left, right)?))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_sub(&mut self) -> Result<(), Error> {
|
|
|
|
// Subtracts the previous two items in the stack.
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
// Then pushes the result onto the stack.
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(self.sub(left, right)?))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_mul(&mut self) -> Result<(), Error> {
|
|
|
|
// Multiplies the previous two items in the stack.
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
// Then pushes the result onto the stack.
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(self.mul(left, right)?))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_div(&mut self) -> Result<(), Error> {
|
|
|
|
// Divides the previous two items in the stack.
|
|
|
|
let left = self.pop()?;
|
|
|
|
let right = self.pop()?;
|
|
|
|
// Then pushes the result onto the stack.
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(P(self.div(left, right)?))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_bind(&mut self) -> Result<(), Error> {
|
|
|
|
// pop val off stack.
|
|
|
|
let val = self.pop()?;
|
|
|
|
// pop name off stack.
|
|
|
|
let name = self.pop()?;
|
2019-06-30 23:43:33 -05:00
|
|
|
if let S(name) = name {
|
2019-06-30 08:57:18 -05:00
|
|
|
self.binding_push(name, val)?;
|
|
|
|
} else {
|
|
|
|
return Err(Error {});
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_field(&mut self) -> Result<(), Error> {
|
|
|
|
// Add a Composite field value to a tuple on the stack
|
|
|
|
// get value from stack
|
|
|
|
let val = self.pop()?;
|
|
|
|
// get name from stack.
|
2019-06-30 23:43:33 -05:00
|
|
|
let name = if let S(s) | P(Str(s)) = self.pop()? {
|
2019-06-30 08:57:18 -05:00
|
|
|
s
|
|
|
|
} else {
|
|
|
|
return Err(Error {});
|
|
|
|
};
|
|
|
|
// get composite tuple from stack
|
|
|
|
let tpl = self.pop()?;
|
2019-06-30 23:43:33 -05:00
|
|
|
if let C(Tuple(mut flds)) = tpl {
|
2019-06-30 08:57:18 -05:00
|
|
|
// add name and value to tuple
|
|
|
|
self.merge_field_into_tuple(&mut flds, name, val)?;
|
|
|
|
// place composite tuple back on stack
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(C(Tuple(flds)))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
} else {
|
|
|
|
return Err(Error {});
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_element(&mut self) -> Result<(), Error> {
|
|
|
|
// get element from stack.
|
|
|
|
let val = self.pop()?;
|
|
|
|
// get next value. It should be a Composite list.
|
|
|
|
let tpl = self.pop()?;
|
2019-06-30 23:43:33 -05:00
|
|
|
if let C(List(mut elems)) = tpl {
|
2019-06-30 08:57:18 -05:00
|
|
|
// add value to list
|
|
|
|
elems.push(val);
|
|
|
|
// Add that value to the list and put list back on stack.
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(C(List(elems)))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
} else {
|
|
|
|
return Err(Error {});
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_copy(&mut self) -> Result<(), Error> {
|
|
|
|
// TODO Use Cow pointers for this?
|
|
|
|
// get next value. It should be a Composite Tuple.
|
2019-06-30 23:43:33 -05:00
|
|
|
if let C(Tuple(flds)) = self.pop()? {
|
2019-06-30 08:57:18 -05:00
|
|
|
// Make a copy of the original
|
2019-06-30 17:31:49 -05:00
|
|
|
let original = Tuple(flds.clone());
|
|
|
|
let copy = Tuple(flds);
|
2019-06-30 08:57:18 -05:00
|
|
|
// Put the original on the Stack as well as the copy
|
2019-06-30 23:43:33 -05:00
|
|
|
self.push(C(original))?;
|
|
|
|
self.push(C(copy))?;
|
2019-06-30 08:57:18 -05:00
|
|
|
} else {
|
|
|
|
return Err(Error {});
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn merge_field_into_tuple(
|
|
|
|
&self,
|
|
|
|
src_fields: &mut Vec<(String, Value)>,
|
|
|
|
name: String,
|
|
|
|
value: Value,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
for fld in src_fields.iter_mut() {
|
|
|
|
if fld.0 == name {
|
|
|
|
fld.1 = value;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
src_fields.push((name, value));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push(&mut self, p: Value) -> Result<(), Error> {
|
|
|
|
self.stack.push(p);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn binding_push(&mut self, name: String, val: Value) -> Result<(), Error> {
|
|
|
|
// FIXME(jwall): Error if the symbol already exists.
|
|
|
|
self.symbols.insert(name, val);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_binding(&mut self, name: &str) -> Result<&Value, Error> {
|
|
|
|
match self.symbols.get(name) {
|
|
|
|
Some(v) => Ok(v),
|
|
|
|
None => Err(Error {}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop(&mut self) -> Result<Value, Error> {
|
|
|
|
match self.stack.pop() {
|
|
|
|
Some(v) => Ok(v),
|
|
|
|
None => Err(Error {}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mul(&self, left: Value, right: Value) -> Result<Primitive, Error> {
|
|
|
|
Ok(match (left, right) {
|
2019-06-30 23:43:33 -05:00
|
|
|
(P(Int(i)), P(Int(ii))) => Int(i * ii),
|
|
|
|
(P(Float(f)), P(Float(ff))) => Float(f * ff),
|
2019-06-30 08:57:18 -05:00
|
|
|
_ => return Err(Error {}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn div(&self, left: Value, right: Value) -> Result<Primitive, Error> {
|
|
|
|
Ok(match (left, right) {
|
2019-06-30 23:43:33 -05:00
|
|
|
(P(Int(i)), P(Int(ii))) => Int(i / ii),
|
|
|
|
(P(Float(f)), P(Float(ff))) => Float(f / ff),
|
2019-06-30 08:57:18 -05:00
|
|
|
_ => return Err(Error {}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sub(&self, left: Value, right: Value) -> Result<Primitive, Error> {
|
|
|
|
Ok(match (left, right) {
|
2019-06-30 23:43:33 -05:00
|
|
|
(P(Int(i)), Value::P(Int(ii))) => Int(i - ii),
|
|
|
|
(P(Float(f)), Value::P(Float(ff))) => Float(f - ff),
|
2019-06-30 08:57:18 -05:00
|
|
|
_ => return Err(Error {}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add(&self, left: Value, right: Value) -> Result<Primitive, Error> {
|
|
|
|
Ok(match (left, right) {
|
2019-06-30 23:43:33 -05:00
|
|
|
(P(Int(i)), Value::P(Int(ii))) => Int(i + ii),
|
|
|
|
(P(Float(f)), Value::P(Float(ff))) => Float(f + ff),
|
|
|
|
(P(Str(s)), Value::P(Str(ss))) => {
|
2019-06-30 08:57:18 -05:00
|
|
|
let mut ns = String::new();
|
|
|
|
ns.push_str(&s);
|
|
|
|
ns.push_str(&ss);
|
2019-06-30 23:43:33 -05:00
|
|
|
Str(ns)
|
2019-06-30 08:57:18 -05:00
|
|
|
}
|
|
|
|
_ => return Err(Error {}),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test;
|