DEV: List and Tuple construction.

This commit is contained in:
Jeremy Wall 2019-06-27 19:47:36 -05:00
parent d4b7bdcd46
commit d7da091b83
2 changed files with 122 additions and 31 deletions

View File

@ -11,12 +11,13 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::collections::BTreeMap; use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap};
use std::rc::Rc; use std::rc::Rc;
use crate::build::ir::Val; use crate::build::ir::Val;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum Primitive { pub enum Primitive {
// Primitive Types // Primitive Types
Int(i64), Int(i64),
@ -26,14 +27,14 @@ pub enum Primitive {
Empty, Empty,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum Composite { pub enum Composite {
List(Vec<Val>), List(Vec<Value>),
Tuple(Vec<(String, Val)>), Tuple(Vec<(String, Value)>),
Thunk(Frame), //Thunk(Frame),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum Value { pub enum Value {
// Binding names. // Binding names.
S(String), S(String),
@ -43,7 +44,7 @@ pub enum Value {
C(Composite), C(Composite),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum Op { pub enum Op {
// Stack and Name manipulation. // Stack and Name manipulation.
Bind, // Bind a Val to a name in the heap Bind, // Bind a Val to a name in the heap
@ -81,7 +82,7 @@ pub struct Heap {}
pub struct Error {} pub struct Error {}
/// The type of Frame environment this is /// The type of Frame environment this is
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum FrameType { pub enum FrameType {
Lib, Lib,
Func, Func,
@ -209,10 +210,8 @@ impl VM {
// get composite tuple from stack // get composite tuple from stack
let tpl = self.pop()?; let tpl = self.pop()?;
if let Value::C(Composite::Tuple(mut flds)) = tpl { if let Value::C(Composite::Tuple(mut flds)) = tpl {
// FIXME(jwall): We need to reuse the field merging logic
// from the ast walker version.
// add name and value to tuple // add name and value to tuple
flds.push((name, self.to_val(val)?)); self.merge_field_into_tuple(&mut flds, name, val)?;
// place composite tuple back on stack // place composite tuple back on stack
self.composite_push(Composite::Tuple(flds))?; self.composite_push(Composite::Tuple(flds))?;
} else { } else {
@ -223,10 +222,10 @@ impl VM {
// get element from stack. // get element from stack.
let val = self.pop()?; let val = self.pop()?;
// get next value. It should be a Composite list. // get next value. It should be a Composite list.
let lst = self.pop()?; let tpl = self.pop()?;
if let Value::C(Composite::List(mut elems)) = lst { if let Value::C(Composite::List(mut elems)) = tpl {
// add value to list // add value to list
elems.push(self.to_val(val)?); elems.push(val);
// Add that value to the list and put list back on stack. // Add that value to the list and put list back on stack.
self.composite_push(Composite::List(elems))?; self.composite_push(Composite::List(elems))?;
} else { } else {
@ -234,14 +233,13 @@ impl VM {
}; };
} }
Op::Cp => { Op::Cp => {
// TODO Use Cow pointers for this?
// get next value. It should be a Composite Tuple. // get next value. It should be a Composite Tuple.
if let Value::C(Composite::Tuple(flds)) = self.pop()? { if let Value::C(Composite::Tuple(flds)) = self.pop()? {
// Make a copy of the original // Make a copy of the original
let original = Composite::Tuple(flds.clone()); let original = Composite::Tuple(flds.clone());
// FIXME(jwall): We need to reuse the field merging logic
// from the ast walker version.
let copy = Composite::Tuple(flds); let copy = Composite::Tuple(flds);
// Put the original on the Stack as well as the original // Put the original on the Stack as well as the copy
self.composite_push(original)?; self.composite_push(original)?;
self.composite_push(copy)?; self.composite_push(copy)?;
} else { } else {
@ -267,6 +265,22 @@ impl VM {
Ok(()) 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_stack(&mut self, typ: FrameType) { fn push_stack(&mut self, typ: FrameType) {
self.stack.push(Frame { self.stack.push(Frame {
names: BTreeMap::new(), names: BTreeMap::new(),
@ -279,7 +293,7 @@ impl VM {
self.stack.pop() self.stack.pop()
} }
fn to_val(&self, p: Value) -> Result<Val, Error> { fn to_val(p: Value) -> Result<Val, Error> {
Ok(match p { Ok(match p {
Value::P(Primitive::Int(i)) => Val::Int(i), Value::P(Primitive::Int(i)) => Val::Int(i),
Value::P(Primitive::Float(f)) => Val::Float(f), Value::P(Primitive::Float(f)) => Val::Float(f),
@ -287,18 +301,24 @@ impl VM {
Value::P(Primitive::Bool(b)) => Val::Boolean(b), Value::P(Primitive::Bool(b)) => Val::Boolean(b),
Value::P(Primitive::Empty) => Val::Empty, Value::P(Primitive::Empty) => Val::Empty,
Value::C(Composite::List(mut elems)) => { Value::C(Composite::List(mut elems)) => {
Val::List(elems.drain(0..).map(|v| Rc::new(v)).collect()) let mut mapped = Vec::with_capacity(elems.len());
for val in elems.drain(0..) {
mapped.push(Rc::new(Self::to_val(val)?));
}
Val::List(mapped)
}
Value::C(Composite::Tuple(mut flds)) => {
let mut mapped = Vec::with_capacity(flds.len());
for (name, val) in flds.drain(0..) {
mapped.push((name, Rc::new(Self::to_val(val)?)));
}
Val::Tuple(mapped)
} }
Value::C(Composite::Tuple(mut flds)) => Val::Tuple(
flds.drain(0..)
.map(|(name, val)| (name, Rc::new(val)))
.collect(),
),
Value::S(_) => return Err(Error {}), Value::S(_) => return Err(Error {}),
Value::C(Composite::Thunk(_)) => { //Value::C(Composite::Thunk(_)) => {
// TODO(jwall): This is either a function or a Module // // TODO(jwall): This is either a function or a Module
Val::Empty // Val::Empty
} //}
}) })
} }

View File

@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::Op::{Add, Bind, Div, Mul, Sub, Sym, Val}; use super::Composite::{List, Tuple};
use super::Op::{Add, Bind, Cp, Div, Element, InitList, InitTuple, Mul, Sub, Sym, Val, FIELD};
use super::Primitive::{Float, Int, Str}; use super::Primitive::{Float, Int, Str};
use super::Value::P; use super::Value::{C, P};
use super::VM; use super::VM;
#[test] #[test]
@ -80,3 +81,73 @@ fn test_bind_op() {
assert_eq!(&result, v); assert_eq!(&result, v);
} }
} }
#[test]
fn test_list_ops() {
let mut cases = vec![
(vec![InitList], C(List(Vec::new()))),
(
vec![InitList, Val(Int(1)), Element],
C(List(vec![P(Int(1))])),
),
(
vec![InitList, Val(Int(2)), Element, Val(Int(1)), Element],
C(List(vec![P(Int(2)), P(Int(1))])),
),
];
let mut vm = VM::new();
for mut case in cases.drain(0..) {
vm.run(case.0.drain(0..)).unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
}
#[test]
fn test_tuple_ops() {
let mut cases = vec![
(vec![InitTuple], C(Tuple(Vec::new()))),
(
vec![InitTuple, Val(Str("foo".to_owned())), Val(Int(1)), FIELD],
C(Tuple(vec![("foo".to_owned(), P(Int(1)))])),
),
(
vec![
InitTuple,
Sym("bar".to_owned()),
Val(Str("quux".to_owned())),
FIELD,
Val(Str("foo".to_owned())),
Val(Int(1)),
FIELD,
],
C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))),
("foo".to_owned(), P(Int(1))),
])),
),
(
vec![
InitTuple,
Sym("bar".to_owned()),
Val(Str("quux".to_owned())),
FIELD,
Val(Str("foo".to_owned())),
Val(Int(1)),
FIELD,
Cp,
Val(Str("foo".to_owned())),
Val(Int(2)),
FIELD,
],
C(Tuple(vec![
("bar".to_owned(), P(Str("quux".to_owned()))),
("foo".to_owned(), P(Int(2))),
])),
),
];
let mut vm = VM::new();
for mut case in cases.drain(0..) {
vm.run(case.0.drain(0..)).unwrap();
assert_eq!(vm.pop().unwrap(), case.1);
}
}