diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index c4bb49a..3a45866 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -453,11 +453,9 @@ fn index_operation() { Val(Int(1)), Field, Field, - InitList, Val(Str("foo".to_owned())), - Element, + Index, Val(Str("bar".to_owned())), - Element, Index, ] => P(Int(1)), vec![ @@ -466,9 +464,7 @@ fn index_operation() { Element, Val(Str("bar".to_owned())), Element, - InitList, Val(Int(0)), - Element, Index, ] => P(Str("foo".to_owned())), vec![ @@ -480,11 +476,9 @@ fn index_operation() { Val(Str("bar".to_owned())), Element, Field, - InitList, Val(Str("field".to_owned())), - Element, + Index, Val(Int(0)), - Element, Index, ] => P(Str("foo".to_owned())), ]; @@ -612,6 +606,27 @@ fn simple_binary_expr() { ) } +#[test] +fn dot_expressions() { + let mut ops = vec![ + Sym("foo".to_owned()), + InitList, + Val(Int(0)), + Element, + Val(Int(1)), + Element, + Val(Int(2)), + Element, + Bind, + ]; + + let stmts = parse(OffsetStrIter::from(dbg!("foo.0;")), None).unwrap(); + ops.append(&mut translate::AST::translate(stmts)); + let ops = Rc::new(ops); + let mut vm = VM::new("foo.ucg", ops.clone()); + vm.run().unwrap(); +} + #[test] fn simple_not_expr() { assert_parse_cases!( diff --git a/src/build/opcode/translate.rs b/src/build/opcode/translate.rs index 4d635f3..b120dd5 100644 --- a/src/build/opcode/translate.rs +++ b/src/build/opcode/translate.rs @@ -136,9 +136,26 @@ impl AST { Self::translate_expr(*def.left, &mut ops); ops.push(Op::Mod); } - BinaryExprType::IN | BinaryExprType::DOT => { + BinaryExprType::IN => { unimplemented!("Binary expressions are not implmented yet") - // TODO + } + BinaryExprType::DOT => { + // Dot expressions expect the left side to be pushed first + Self::translate_expr(*def.left, &mut ops); + // Symbols on the right side should be converted to strings to satisfy + // the Index operation contract. + match *def.right { + Expression::Simple(Value::Symbol(name)) => { + Self::translate_expr( + Expression::Simple(Value::Str(name)), + &mut ops, + ); + } + expr => { + Self::translate_expr(expr, &mut ops); + } + } + ops.push(Op::Index); } }; } @@ -171,7 +188,9 @@ impl AST { Value::Str(s) => ops.push(Op::Val(Primitive::Str(s.val))), Value::Empty(_pos) => ops.push(Op::Val(Primitive::Empty)), Value::Boolean(b) => ops.push(Op::Val(Primitive::Bool(b.val))), - Value::Symbol(s) => ops.push(Op::Sym(s.val)), + Value::Symbol(s) => { + ops.push(Op::DeRef(s.val)); + } Value::Tuple(_flds) => unimplemented!("Select expression are not implmented yet"), Value::List(_els) => unimplemented!("Select expression are not implmented yet"), } diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index 0c66f65..2eef372 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -541,25 +541,33 @@ impl<'a> VM { } fn op_index(&mut self) -> Result<(), Error> { - let path_val = self.pop()?; - let path = if let &C(List(ref elems)) = path_val.as_ref() { - elems.clone() - } else { - return Err(dbg!(Error {})); - }; - let target_val = self.pop()?; - match target_val.as_ref() { - &P(_) | &S(_) | &T(_) | &F(_) | &M(_) => return Err(dbg!(Error {})), - _ => { - let mut out = target_val.clone(); - for p in path { - let tgt = self.find_in_value(&p, &out)?; - out = tgt; + // left and then right + let right = dbg!(self.pop()?); + let left = dbg!(self.pop()?); + match right.as_ref() { + &P(Int(i)) => { + if let &C(List(ref elems)) = left.as_ref() { + if i < (elems.len() as i64) && i >= 0 { + self.push(elems[i as usize].clone())?; + return Ok(()); + } } - self.push(out)?; + } + &P(Str(ref s)) => { + if let &C(Tuple(ref flds)) = left.as_ref() { + for &(ref key, ref val) in flds.iter() { + if key == s { + self.push(val.clone())?; + return Ok(()); + } + } + } + } + _ => { + // noop } }; - Ok(()) + return Err(dbg!(Error {})); } fn op_copy(&mut self) -> Result<(), Error> {