use ecow::EcoVec; use crate::engine::Engine; use crate::env::Env; use crate::error::{Error, Result}; use crate::ir::{self, DynAttr}; use crate::ty::common::Const; use crate::ty::internal::{AttrSet, List, Value}; use crate::ty::public::Symbol; pub mod jit; pub trait Evaluate { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result; } impl Evaluate for ir::Attrs { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let mut attrs = AttrSet::new( self.stcs .iter() .map(|(k, v)| { let eval_result = v.eval(engine, env); Ok((k.clone(), eval_result?)) }) .collect::>()?, ); for DynAttr(k, v) in self.dyns.iter() { let mut k = k.eval(engine, env)?; k.force(engine, env)?.coerce_to_string(); let v_eval_result = v.eval(engine, env)?; attrs.push_attr(k.unwrap_string(), v_eval_result); } let result = Value::AttrSet(attrs.into()).ok(); Ok(result.unwrap()) } } impl Evaluate for ir::List { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let items = self .items .iter() .map(|val| { let eval_result = val.eval(engine, env); eval_result }) .collect::>>()?; let result = Value::List(List::from(items)).ok(); Ok(result.unwrap()) } } impl Evaluate for ir::HasAttr { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { use ir::Attr::*; let mut val = self.lhs.eval(engine, env)?; val.force(engine, env)? .has_attr(self.rhs.iter().map(|attr| { Ok(match attr { Str(ident) => ident.clone(), Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Dynamic(expr) => { let mut val = expr.eval(engine, env)?; val.force(engine, env)?.coerce_to_string(); val.unwrap_string() } }) }))?; let result = val.ok(); Ok(result.unwrap()) } } impl Evaluate for ir::BinOp { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { use ir::BinOpKind::*; let mut lhs = self.lhs.eval(engine, env)?; let mut rhs = self.rhs.eval(engine, env)?; lhs.force(engine, env)?; rhs.force(engine, env)?; match self.kind { Add => lhs.add(rhs), Sub => { rhs.neg(); lhs.add(rhs); } Mul => lhs.mul(rhs), Div => lhs.div(rhs)?, Eq => Value::eq(&mut lhs, rhs), Neq => { Value::eq(&mut lhs, rhs); lhs.not(); } Lt => lhs.lt(rhs), Gt => { rhs.lt(lhs); lhs = rhs; } Leq => { rhs.lt(lhs); rhs.not(); lhs = rhs; } Geq => { lhs.lt(rhs); lhs.not(); } And => lhs.and(rhs), Or => lhs.or(rhs), Impl => { lhs.not(); lhs.or(rhs); } Con => lhs.concat(rhs), Upd => lhs.update(rhs), PipeL => lhs.call(vec![rhs], engine, env)?, PipeR => { rhs.call(vec![lhs], engine, env)?; lhs = rhs; } } Ok(lhs) } } impl Evaluate for ir::UnOp { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { use ir::UnOpKind::*; let mut rhs = self.rhs.eval(engine, env)?; rhs.force(engine, env)?; match self.kind { Neg => { rhs.neg(); } Not => { rhs.not(); } }; Ok(rhs) } } impl Evaluate for ir::Select { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { use ir::Attr::*; let mut val = self.expr.eval(engine, env)?; if let Some(default) = &self.default { let default = default.eval(engine, env)?; val.force(engine, env)?.select_with_default( self.attrpath.iter().map(|attr| { Ok(match attr { Str(ident) => ident.clone(), Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Dynamic(expr) => { let mut val = expr.eval(engine, env)?; val.force(engine, env)?.coerce_to_string(); val.unwrap_string() } }) }), default, )?; } else { val.force(engine, env)? .select(self.attrpath.iter().map(|attr| { Ok(match attr { Str(ident) => ident.clone(), Strs(expr) => expr.eval(engine, env)?.unwrap_string(), Dynamic(expr) => { let mut val = expr.eval(engine, env)?; val.force(engine, env)?.coerce_to_string(); val.unwrap_string() } }) }))?; } let result = val.ok(); Ok(result.unwrap()) } } impl Evaluate for ir::If { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { // TODO: Error Handling let mut cond = self.cond.eval(engine, env)?; cond.force(engine, env)?; let cond = cond.unwrap_bool(); let result = if cond { self.consq.eval(engine, env) } else { self.alter.eval(engine, env) }; result } } impl Evaluate for ir::LoadFunc { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let idx = engine.func_offset + self.idx; let result = Value::Func(idx).ok(); Ok(result.unwrap()) } } impl Evaluate for ir::Call { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let mut func = self.func.eval(engine, env)?; func.force(engine, env)?; let result = func.call( self.args .iter() .map(|arg| arg.eval(engine, env)) .collect::>()?, engine, env, ); Ok(func.ok().unwrap()) } } impl Evaluate for ir::Let { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { unreachable!() } } impl Evaluate for ir::With { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let mut namespace = self.namespace.eval(engine, env)?; namespace.force(engine, env)?; // TODO: Error Handling env.enter_with(namespace.unwrap_attr_set().into_inner()); let ret = self.expr.eval(engine, env); env.pop_with(); ret } } impl Evaluate for ir::Assert { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { todo!() } } impl Evaluate for ir::ConcatStrings { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let mut parts = self .parts .iter() .map(|part| { let mut part = part.eval(engine, env)?; part.force(engine, env)?.coerce_to_string(); part.ok() }) .collect::>>()? .into_iter(); let init = parts.next().unwrap(); let result = parts.fold(init, |mut a, b| { a.concat_string(b); a }); Ok(result.ok().unwrap()) } } impl Evaluate for ir::String { fn eval(&self, _: &mut Engine, _: &mut Env) -> Result { let result = Value::String(self.val.clone()).ok(); Ok(result.unwrap()) } } impl Evaluate for ir::Const { fn eval(&self, _: &mut Engine, _: &mut Env) -> Result { let result = match self.val { Const::Null => Value::Null, Const::Int(x) => Value::Int(x), Const::Float(x) => Value::Float(x), Const::Bool(x) => Value::Bool(x), } .ok(); Ok(result.unwrap()) } } impl Evaluate for ir::Var { fn eval(&self, _: &mut Engine, env: &mut Env) -> Result { let result = env.lookup_with(&self.sym).ok_or_else(|| { Error::EvalError(format!( "variable {} not found", Symbol::from(self.sym.clone()) )) }); result } } impl Evaluate for ir::Arg { fn eval(&self, _: &mut Engine, env: &mut Env) -> Result { let result = env.lookup_arg(self.level).clone().ok(); Ok(result.unwrap()) } } impl Evaluate for ir::LetVar { fn eval(&self, _: &mut Engine, env: &mut Env) -> Result { unreachable!() } } impl Evaluate for ir::Thunk { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { Value::Thunk(self.idx).ok() } } impl Evaluate for ir::MaybeThunk { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { let result = match self { ir::MaybeThunk::Const(cnst) => cnst.eval(engine, env), ir::MaybeThunk::String(string) => string.eval(engine, env), ir::MaybeThunk::Thunk(thunk) => thunk.eval(engine, env), }; result } } impl Evaluate for ir::Path { fn eval(&self, engine: &mut Engine, env: &mut Env) -> Result { todo!() } }