From 102f0f5ae1de31155494603911b5f0276fc6ab56 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Thu, 11 Jul 2019 19:28:55 -0500 Subject: [PATCH] DEV: Indexing operation. --- src/build/opcode/mod.rs | 94 ++++++++++++++++++++++++++++++++-------- src/build/opcode/test.rs | 78 +++++++++++++++++++++++++++------ 2 files changed, 140 insertions(+), 32 deletions(-) diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index e69d183..b516e31 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -109,6 +109,7 @@ pub enum Op { // - And(usize) // - Or(usize) // Spacer operation, Does nothing. + Index, // indexing operation Noop, // Pending Computation InitThunk(i32), // Basically just used for module return expressions @@ -167,7 +168,7 @@ impl<'a> VM { let idx = self.ops.idx()?; match op { 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::Add => self.op_add()?, Op::Sub => self.op_sub()?, @@ -185,6 +186,7 @@ impl<'a> VM { Op::InitTuple => self.push(C(Tuple(Vec::new())))?, Op::Field => self.op_field()?, Op::Element => self.op_element()?, + Op::Index => self.op_index()?, Op::Cp => self.op_copy()?, //TODO(jwall): Should this take a user provided message? Op::Bang => return dbg!(Err(Error {})), @@ -495,19 +497,73 @@ impl<'a> VM { Ok(()) } + fn find_in_list(&self, index: Value, elems: Vec) -> Result { + 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 { + 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 { + 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> { // TODO Use Cow pointers for this? - // get next value. It should be a Module. - let tgt = self.pop()?; + // get next value. It should be a Module or Tuple. + 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 { C(Tuple(mut flds)) => { - let overrides = self.pop()?; - if let C(Tuple(oflds)) = overrides { - for (name, val) in oflds { - self.merge_field_into_tuple(&mut flds, name, val)?; - } - } else { - return dbg!(Err(Error {})); + for (name, val) in overrides { + dbg!(self.merge_field_into_tuple(&mut flds, name, val))?; } // Put the copy on the Stack self.push(C(Tuple(flds)))?; @@ -517,17 +573,19 @@ impl<'a> VM { result_ptr, mut flds, }) => { - let overrides = dbg!(self.pop()?); - if let C(Tuple(oflds)) = overrides { - for (name, val) in oflds { - self.merge_field_into_tuple(&mut flds, name, val)?; - } - } else { - return dbg!(Err(Error {})); + //let this = M(Module { + // ptr: ptr.clone(), + // result_ptr: result_ptr.clone(), + // flds: flds.clone(), + //}); + for (name, val) in overrides { + 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); vm.push(S("mod".to_owned()))?; - vm.push(C(Tuple(flds)))?; + vm.push(C(Tuple(dbg!(flds))))?; vm.run()?; let mut flds = Vec::new(); if let Some(ptr) = dbg!(result_ptr) { diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index bd40c35..d6f2736 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -16,11 +16,11 @@ use std::rc::Rc; use super::scope::Stack; use super::Composite::{List, Tuple}; use super::Op::{ - Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, InitList, InitThunk, - InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Return, SelectJump, Sub, Sym, - Val, + Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, Index, InitList, + InitThunk, InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Return, + 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::VM; @@ -356,22 +356,24 @@ fn test_module_call() { Sym("two".to_owned()), // 9 Val(Int(2)), // 10 Field, // 11 - Module(17), // 12 // Module definition - Bind, // 13 + Module(17), // 12 // Module body definition + Bind, // 13 // bind the mod tuple Sym("foo".to_owned()), // 14 DeRef("mod".to_owned()), // 15 Bind, // 16 // bind mod tuple to foo Return, // 17 // end the module Bind, // 18 // bind module to the binding name DeRef("m".to_owned()), // 19 - Cp, // 20 - ] => C(Tuple(vec![( - "foo".to_owned(), - C(Tuple(vec![ - ("one".to_owned(), P(Int(11))), - ("two".to_owned(), P(Int(2))), - ])), - )])), + Cp, // 20 // Call the module + ] => C(Tuple(vec![ + ( + "foo".to_owned(), + C(Tuple(vec![ + ("one".to_owned(), P(Int(11))), + ("two".to_owned(), P(Int(2))), + ])) + ), + ])), vec![ InitTuple, // 0 // override tuple 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] fn test_scope_stacks() { let mut stack = Stack::new();