DEV: Indexing operation.

This commit is contained in:
Jeremy Wall 2019-07-11 19:28:55 -05:00
parent a50eb46c5e
commit 102f0f5ae1
2 changed files with 140 additions and 32 deletions

View File

@ -109,6 +109,7 @@ pub enum Op {
// - And(usize) // - And(usize)
// - Or(usize) // - Or(usize)
// Spacer operation, Does nothing. // Spacer operation, Does nothing.
Index, // indexing operation
Noop, Noop,
// Pending Computation // Pending Computation
InitThunk(i32), // Basically just used for module return expressions InitThunk(i32), // Basically just used for module return expressions
@ -167,7 +168,7 @@ impl<'a> VM {
let idx = self.ops.idx()?; let idx = self.ops.idx()?;
match op { match op {
Op::Val(p) => self.push(dbg!(P(p.clone())))?, Op::Val(p) => self.push(dbg!(P(p.clone())))?,
Op::Sym(s) => self.push(S(s.clone()))?, Op::Sym(s) => self.push(dbg!(S(s.clone())))?,
Op::DeRef(s) => self.op_deref(s.clone())?, Op::DeRef(s) => self.op_deref(s.clone())?,
Op::Add => self.op_add()?, Op::Add => self.op_add()?,
Op::Sub => self.op_sub()?, Op::Sub => self.op_sub()?,
@ -185,6 +186,7 @@ impl<'a> VM {
Op::InitTuple => self.push(C(Tuple(Vec::new())))?, Op::InitTuple => self.push(C(Tuple(Vec::new())))?,
Op::Field => self.op_field()?, Op::Field => self.op_field()?,
Op::Element => self.op_element()?, Op::Element => self.op_element()?,
Op::Index => self.op_index()?,
Op::Cp => self.op_copy()?, Op::Cp => self.op_copy()?,
//TODO(jwall): Should this take a user provided message? //TODO(jwall): Should this take a user provided message?
Op::Bang => return dbg!(Err(Error {})), Op::Bang => return dbg!(Err(Error {})),
@ -495,19 +497,73 @@ impl<'a> VM {
Ok(()) Ok(())
} }
fn find_in_list(&self, index: Value, elems: Vec<Value>) -> Result<Value, Error> {
let idx = match index {
P(Int(i)) => i,
_ => return dbg!(Err(Error {})),
};
match elems.get(idx as usize) {
Some(v) => Ok(v.clone()),
None => Err(Error {}),
}
}
fn find_in_flds(&self, index: Value, flds: Vec<(String, Value)>) -> Result<Value, Error> {
let idx = match index {
S(p) => p,
P(Str(p)) => p,
_ => return dbg!(Err(Error {})),
};
for f in flds.iter() {
if idx == f.0 {
return Ok(f.1.clone());
}
}
Err(Error {})
}
fn find_in_value(&self, index: Value, target: Value) -> Result<Value, Error> {
match target {
C(Tuple(flds)) => self.find_in_flds(index, flds),
C(List(elements)) => self.find_in_list(index, elements),
_ => return Err(Error {}),
}
}
fn op_index(&mut self) -> Result<(), Error> {
let path = if let C(List(elems)) = self.pop()? {
elems
} else {
return dbg!(Err(Error {}));
};
match self.pop()? {
P(_) | S(_) | T(_) | F(_) | M(_) => return dbg!(Err(Error {})),
val => {
let mut out = val;
for p in path {
let tgt = self.find_in_value(p, out)?;
out = tgt;
}
self.push(out)?;
}
};
Ok(())
}
fn op_copy(&mut self) -> Result<(), Error> { fn op_copy(&mut self) -> Result<(), Error> {
// TODO Use Cow pointers for this? // TODO Use Cow pointers for this?
// get next value. It should be a Module. // get next value. It should be a Module or Tuple.
let tgt = self.pop()?; let tgt = dbg!(self.pop())?;
// This value should always be a tuple
let overrides = if let C(Tuple(oflds)) = self.pop()? {
oflds
} else {
return dbg!(Err(Error {}));
};
match tgt { match tgt {
C(Tuple(mut flds)) => { C(Tuple(mut flds)) => {
let overrides = self.pop()?; for (name, val) in overrides {
if let C(Tuple(oflds)) = overrides { dbg!(self.merge_field_into_tuple(&mut flds, name, val))?;
for (name, val) in oflds {
self.merge_field_into_tuple(&mut flds, name, val)?;
}
} else {
return dbg!(Err(Error {}));
} }
// Put the copy on the Stack // Put the copy on the Stack
self.push(C(Tuple(flds)))?; self.push(C(Tuple(flds)))?;
@ -517,17 +573,19 @@ impl<'a> VM {
result_ptr, result_ptr,
mut flds, mut flds,
}) => { }) => {
let overrides = dbg!(self.pop()?); //let this = M(Module {
if let C(Tuple(oflds)) = overrides { // ptr: ptr.clone(),
for (name, val) in oflds { // result_ptr: result_ptr.clone(),
self.merge_field_into_tuple(&mut flds, name, val)?; // flds: flds.clone(),
} //});
} else { for (name, val) in overrides {
return dbg!(Err(Error {})); self.merge_field_into_tuple(&mut flds, name, val)?;
} }
// FIXME(jwall): We need to populate the pkg key for modules.
//self.merge_field_into_tuple(&mut flds, "this".to_owned(), this)?;
let mut vm = Self::with_pointer(ptr); let mut vm = Self::with_pointer(ptr);
vm.push(S("mod".to_owned()))?; vm.push(S("mod".to_owned()))?;
vm.push(C(Tuple(flds)))?; vm.push(C(Tuple(dbg!(flds))))?;
vm.run()?; vm.run()?;
let mut flds = Vec::new(); let mut flds = Vec::new();
if let Some(ptr) = dbg!(result_ptr) { if let Some(ptr) = dbg!(result_ptr) {

View File

@ -16,11 +16,11 @@ use std::rc::Rc;
use super::scope::Stack; use super::scope::Stack;
use super::Composite::{List, Tuple}; use super::Composite::{List, Tuple};
use super::Op::{ use super::Op::{
Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, InitList, InitThunk, Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, Index, InitList,
InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Return, SelectJump, Sub, Sym, InitThunk, InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Return,
Val, SelectJump, Sub, Sym, Val,
}; };
use super::Primitive::{Bool, Float, Int, Str}; use super::Primitive::{Bool, Empty, Float, Int, Str};
use super::Value::{C, P}; use super::Value::{C, P};
use super::VM; use super::VM;
@ -356,22 +356,24 @@ fn test_module_call() {
Sym("two".to_owned()), // 9 Sym("two".to_owned()), // 9
Val(Int(2)), // 10 Val(Int(2)), // 10
Field, // 11 Field, // 11
Module(17), // 12 // Module definition Module(17), // 12 // Module body definition
Bind, // 13 Bind, // 13 // bind the mod tuple
Sym("foo".to_owned()), // 14 Sym("foo".to_owned()), // 14
DeRef("mod".to_owned()), // 15 DeRef("mod".to_owned()), // 15
Bind, // 16 // bind mod tuple to foo Bind, // 16 // bind mod tuple to foo
Return, // 17 // end the module Return, // 17 // end the module
Bind, // 18 // bind module to the binding name Bind, // 18 // bind module to the binding name
DeRef("m".to_owned()), // 19 DeRef("m".to_owned()), // 19
Cp, // 20 Cp, // 20 // Call the module
] => C(Tuple(vec![( ] => C(Tuple(vec![
"foo".to_owned(), (
C(Tuple(vec![ "foo".to_owned(),
("one".to_owned(), P(Int(11))), C(Tuple(vec![
("two".to_owned(), P(Int(2))), ("one".to_owned(), P(Int(11))),
])), ("two".to_owned(), P(Int(2))),
)])), ]))
),
])),
vec![ vec![
InitTuple, // 0 // override tuple InitTuple, // 0 // override tuple
Sym("one".to_owned()), // 1 Sym("one".to_owned()), // 1
@ -433,6 +435,54 @@ fn test_select_short_circuit() {
]; ];
} }
#[test]
fn test_index_operation() {
assert_cases![
vec![
InitTuple,
Sym("foo".to_owned()),
InitTuple,
Sym("bar".to_owned()),
Val(Int(1)),
Field,
Field,
InitList,
Val(Str("foo".to_owned())),
Element,
Val(Str("bar".to_owned())),
Element,
Index,
] => P(Int(1)),
vec![
InitList,
Val(Str("foo".to_owned())),
Element,
Val(Str("bar".to_owned())),
Element,
InitList,
Val(Int(0)),
Element,
Index,
] => P(Str("foo".to_owned())),
vec![
InitTuple,
Sym("field".to_owned()),
InitList,
Val(Str("foo".to_owned())),
Element,
Val(Str("bar".to_owned())),
Element,
Field,
InitList,
Val(Str("field".to_owned())),
Element,
Val(Int(0)),
Element,
Index,
] => P(Str("foo".to_owned())),
];
}
#[test] #[test]
fn test_scope_stacks() { fn test_scope_stacks() {
let mut stack = Stack::new(); let mut stack = Stack::new();