diff --git a/src/build/opcode/error.rs b/src/build/opcode/error.rs index 05476c0..65e7308 100644 --- a/src/build/opcode/error.rs +++ b/src/build/opcode/error.rs @@ -20,8 +20,8 @@ impl From for Error where E: std::error::Error + Sized, { - fn from(_e: E) -> Error { + fn from(_e: E) -> Self { // FIXME(jwall): This should really have more information for debugging Error {} } -} +} \ No newline at end of file diff --git a/src/build/opcode/mod.rs b/src/build/opcode/mod.rs index eb77eb5..dcf4960 100644 --- a/src/build/opcode/mod.rs +++ b/src/build/opcode/mod.rs @@ -40,6 +40,18 @@ pub enum Primitive { use Primitive::{Bool, Empty, Float, Int, Str}; +impl From<&Primitive> for String { + fn from(p: &Primitive) -> Self { + match p { + Int(i) => format!("{}", i), + Float(f) => format!("{}", f), + Str(s) => format!("{}", s), + Bool(b) => format!("{}", b), + Empty => "NULL".to_owned(), + } + } +} + #[derive(Debug, PartialEq, Clone)] pub enum Composite { List(Vec>), @@ -48,6 +60,35 @@ pub enum Composite { use Composite::{List, Tuple}; +impl From<&Composite> for String { + fn from(c: &Composite) -> Self { + let mut buf = String::new(); + match c { + &List(ref elems) => { + buf.push_str("["); + for e in elems.iter() { + let val: String = e.as_ref().into(); + buf.push_str(&val); + buf.push_str(","); + } + buf.push_str("]"); + } + &Tuple(ref flds) => { + buf.push_str("{"); + for &(ref k, ref v) in flds.iter() { + buf.push_str(&k); + buf.push_str(" = "); + let val: String = v.as_ref().into(); + buf.push_str(&val); + buf.push_str(","); + } + buf.push_str("}"); + } + } + buf + } +} + #[derive(Debug, PartialEq, Clone)] pub struct Func { ptr: OpPointer, @@ -78,6 +119,19 @@ pub enum Value { M(Module), } +impl From<&Value> for String { + fn from(v: &Value) -> Self { + match v { + &S(ref s) => s.clone(), + &P(ref p) => p.into(), + &C(ref c) => c.into(), + &T(_) => "".to_owned(), + &F(_) => "".to_owned(), + &M(_) => "".to_owned(), + } + } +} + use Value::{C, F, M, P, S, T}; #[derive(Debug, PartialEq, Clone)] @@ -148,6 +202,8 @@ pub enum Op { // Runtime hooks Runtime(Hook), // TODO(jwall): TRACE instruction + // TODO(jwall): Format instruction + Format, } use super::ir::Val; diff --git a/src/build/opcode/test.rs b/src/build/opcode/test.rs index b6e439c..b6f008d 100644 --- a/src/build/opcode/test.rs +++ b/src/build/opcode/test.rs @@ -16,7 +16,7 @@ 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, Index, InitList, + Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Format, Func, Index, InitList, InitThunk, InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Return, SelectJump, Sub, Sym, Typ, Val, }; @@ -632,3 +632,18 @@ fn simple_not_expr() { "not 1!=1;" => P(Bool(true)), ) } + +#[test] +fn simple_format_expr() { + assert_cases![ + vec![ + InitList, + Val(Int(1)), + Element, + Val(Int(2)), + Element, + Val(Str("@@".to_owned())), + Format, + ] => P(Str("12".to_owned())), + ]; +} diff --git a/src/build/opcode/translate.rs b/src/build/opcode/translate.rs index 559a8ca..b9eff95 100644 --- a/src/build/opcode/translate.rs +++ b/src/build/opcode/translate.rs @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use crate::ast::{BinaryExprType, Expression, Statement, Value}; +use crate::ast::{BinaryExprType, Expression, Statement, Value, FormatArgs}; use crate::build::opcode::Primitive; use crate::build::opcode::Value::{C, F, M, P, T}; use crate::build::opcode::{Hook, Op}; @@ -168,7 +168,24 @@ impl AST { Self::translate_expr(*expr, &mut ops); } Expression::Fail(_) => unimplemented!("Fail expressions are not implmented yet"), - Expression::Format(_) => unimplemented!("Format expressions are not implmented yet"), + Expression::Format(def) => { + match def.args { + FormatArgs::List(elems) => { + ops.push(Op::InitList); + for e in elems { + Self::translate_expr(e, &mut ops); + ops.push(Op::Element); + } + } + FormatArgs::Single(e) => { + ops.push(Op::InitList); + Self::translate_expr(*e, &mut ops); + ops.push(Op::Element); + } + } + ops.push(Op::Val(Primitive::Str(def.template))); + ops.push(Op::Format); + } Expression::Func(_) => unimplemented!("Func expressions are not implmented yet"), Expression::FuncOp(_) => unimplemented!("FuncOp expressions are not implmented yet"), Expression::Import(_) => unimplemented!("Import expressions are not implmented yet"), diff --git a/src/build/opcode/vm.rs b/src/build/opcode/vm.rs index 2eef372..9a26ae1 100644 --- a/src/build/opcode/vm.rs +++ b/src/build/opcode/vm.rs @@ -18,13 +18,14 @@ use std::rc::Rc; use super::pointer::OpPointer; use super::runtime; use super::scope::Stack; -use super::{Error, Op, Primitive, Value}; - use super::Composite::{List, Tuple}; use super::Hook; use super::Primitive::{Bool, Empty, Float, Int, Str}; use super::Value::{C, F, M, P, S, T}; +use super::{Error, Op, Primitive, Value}; use super::{Func, Module}; +use crate::ast::Position; +use crate::build::format::{ExpressionFormatter, FormatRenderer, SimpleFormatter}; pub struct VM { stack: Vec>, @@ -123,6 +124,7 @@ impl<'a> VM { } Op::Typ => self.op_typ()?, Op::Runtime(h) => self.op_runtime(h)?, + Op::Format => self.op_format()?, }; } Ok(()) @@ -719,4 +721,28 @@ impl<'a> VM { .borrow_mut() .handle(&self.path, h, &mut self.stack) } + + fn op_format(&mut self) -> Result<(), Error> { + let template = self.pop()?; + let template = match template.as_ref() { + &P(Str(ref s)) => s.clone(), + _ => return Err(dbg!(Error {})), + }; + let args = self.pop()?; + let args: Vec<&Value> = match args.as_ref() { + &C(List(ref elems)) => elems.iter().map(|v| v.as_ref()).collect(), + _ => return Err(dbg!(Error {})), + }; + let f = if args.len() == 1 { + unimplemented!("Expression formatters are not implemented yet"); + } else { + SimpleFormatter::new(template, args) + }; + // TODO(jwall): Position should be valid here. + match dbg!(f.render(&Position::new(0, 0, 0))) { + Err(_e) => return Err(dbg!(Error {})), + Ok(s) => self.push(Rc::new(P(Str(s))))?, + } + Ok(()) + } }