mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-21 18:10:42 -04:00
DEV: List and Tuple construction.
This commit is contained in:
parent
d4b7bdcd46
commit
d7da091b83
@ -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
|
||||||
}
|
//}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user