diff --git a/.idea/cozo.iml b/.idea/cozo.iml index 14c4f514..c1724834 100644 --- a/.idea/cozo.iml +++ b/.idea/cozo.iml @@ -4,8 +4,10 @@ + + diff --git a/src/ast/eval_op.rs b/src/ast/eval_op.rs new file mode 100644 index 00000000..4e47538c --- /dev/null +++ b/src/ast/eval_op.rs @@ -0,0 +1,451 @@ +use crate::ast::Expr; +use crate::ast::Expr::*; +use crate::ast::op::Op; +use crate::error::CozoError; +use crate::error::CozoError::*; +use crate::value::Value::*; + +pub fn add_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + Ok(Const(match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(va), Int(vb)) => Int(va + vb), + (Float(va), Int(vb)) => Float(va + vb as f64), + (Int(va), Float(vb)) => Float(va as f64 + vb), + (Float(va), Float(vb)) => Float(va + vb), + (OwnString(va), OwnString(vb)) => OwnString(Box::new(*va + &*vb)), + (OwnString(va), RefString(vb)) => OwnString(Box::new(*va + &*vb)), + (RefString(va), OwnString(vb)) => OwnString(Box::new(va.to_string() + &*vb)), + (RefString(va), RefString(vb)) => OwnString(Box::new(va.to_string() + &*vb)), + (_, _) => return Err(CozoError::TypeError) + } + } + (a, b) => return Ok(Apply(Op::Add, vec![a, b])) + })) + } + _ => unreachable!() + } +} + +pub fn sub_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + Ok(Const(match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(va), Int(vb)) => Int(va - vb), + (Float(va), Int(vb)) => Float(va - vb as f64), + (Int(va), Float(vb)) => Float(va as f64 - vb), + (Float(va), Float(vb)) => Float(va - vb), + (_, _) => return Err(CozoError::TypeError) + } + } + (a, b) => return Ok(Apply(Op::Sub, vec![a, b])) + })) + } + _ => unreachable!() + } +} + +pub fn mul_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + Ok(Const(match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(va), Int(vb)) => Int(va * vb), + (Float(va), Int(vb)) => Float(va * vb as f64), + (Int(va), Float(vb)) => Float(va as f64 * vb), + (Float(va), Float(vb)) => Float(va * vb), + (_, _) => return Err(CozoError::TypeError) + } + } + (a, b) => return Ok(Apply(Op::Mul, vec![a, b])) + })) + } + _ => unreachable!() + } +} + + +pub fn div_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + Ok(Const(match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(va), Int(vb)) => Float(va as f64 / vb as f64), + (Float(va), Int(vb)) => Float(va / vb as f64), + (Int(va), Float(vb)) => Float(va as f64 / vb), + (Float(va), Float(vb)) => Float(va / vb), + (_, _) => return Err(CozoError::TypeError) + } + } + (a, b) => return Ok(Apply(Op::Div, vec![a, b])) + })) + } + _ => unreachable!() + } +} + +pub fn mod_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + Ok(Const(match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(a), Int(b)) => Int(a % b), + (_, _) => return Err(CozoError::TypeError) + } + } + (a, b) => return Ok(Apply(Op::Mod, vec![a, b])) + })) + } + _ => unreachable!() + } +} + + +pub fn eq_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => Ok(Const(Bool(a == b))), + (a, b) => Ok(Apply(Op::Eq, vec![a, b])) + } + } + _ => unreachable!() + } +} + + +pub fn ne_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => Ok(Const(Bool(a == b))), + (a, b) => Ok(Apply(Op::Neq, vec![a, b])) + } + } + _ => unreachable!() + } +} + + +pub fn gt_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(a), Int(b)) => Ok(Const(Bool(a > b))), + (Float(a), Int(b)) => Ok(Const(Bool(a > b as f64))), + (Int(a), Float(b)) => Ok(Const(Bool(a as f64 > b))), + (Float(a), Float(b)) => Ok(Const(Bool(a > b))), + (_, _) => Err(CozoError::TypeError) + } + } + (a, b) => Ok(Apply(Op::Gt, vec![a, b])) + } + } + _ => unreachable!() + } +} + + +pub fn ge_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(a), Int(b)) => Ok(Const(Bool(a >= b))), + (Float(a), Int(b)) => Ok(Const(Bool(a >= b as f64))), + (Int(a), Float(b)) => Ok(Const(Bool(a as f64 >= b))), + (Float(a), Float(b)) => Ok(Const(Bool(a >= b))), + (_, _) => Err(CozoError::TypeError) + } + } + (a, b) => Ok(Apply(Op::Ge, vec![a, b])) + } + } + _ => unreachable!() + } +} + + +pub fn lt_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(a), Int(b)) => Ok(Const(Bool(a < b))), + (Float(a), Int(b)) => Ok(Const(Bool(a < b as f64))), + (Int(a), Float(b)) => Ok(Const(Bool((a as f64) < b))), + (Float(a), Float(b)) => Ok(Const(Bool(a < b))), + (_, _) => Err(CozoError::TypeError) + } + } + (a, b) => Ok(Apply(Op::Lt, vec![a, b])) + } + } + _ => unreachable!() + } +} + +pub fn le_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(a), Int(b)) => Ok(Const(Bool(a <= b))), + (Float(a), Int(b)) => Ok(Const(Bool(a <= b as f64))), + (Int(a), Float(b)) => Ok(Const(Bool((a as f64) <= b))), + (Float(a), Float(b)) => Ok(Const(Bool(a <= b))), + (_, _) => Err(CozoError::TypeError) + } + } + (a, b) => Ok(Apply(Op::Le, vec![a, b])) + } + } + _ => unreachable!() + } +} + + +pub fn pow_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) || b == Const(Null) { + return Ok(Const(Null)); + } + match (a, b) { + (Const(a), Const(b)) => { + match (a, b) { + (Int(a), Int(b)) => Ok(Const(Float((a as f64).powf(b as f64)))), + (Float(a), Int(b)) => Ok(Const(Float(a.powi(b as i32)))), + (Int(a), Float(b)) => Ok(Const(Float((a as f64).powf(b)))), + (Float(a), Float(b)) => Ok(Const(Float(a.powf(b)))), + (_, _) => Err(CozoError::TypeError) + } + } + (a, b) => Ok(Apply(Op::Pow, vec![a, b])) + } + } + _ => unreachable!() + } +} + +pub fn coalesce_exprs<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + match exprs { + [a, b] => { + let a = a.eval()?; + let b = b.eval()?; + if a == Const(Null) { + return Ok(b); + } + if b == Const(Null) { + return Ok(a); + } + if let a @ Const(_) = a { + return Ok(a); + } + return Ok(Apply(Op::Coalesce, vec![a, b])); + } + _ => unreachable!() + } +} + +pub fn negate_expr<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + Ok(match exprs { + [a] => { + match a.eval()? { + Const(Null) => Const(Null), + Const(Bool(b)) => Const(Bool(!b)), + Const(_) => return Err(TypeError), + Apply(Op::Neg, v) => v.into_iter().next().unwrap(), + Apply(Op::IsNull, v) => Apply(Op::NotNull, v), + Apply(Op::NotNull, v) => Apply(Op::IsNull, v), + Apply(Op::Eq, v) => Apply(Op::Neq, v), + Apply(Op::Neq, v) => Apply(Op::Eq, v), + Apply(Op::Gt, v) => Apply(Op::Le, v), + Apply(Op::Ge, v) => Apply(Op::Lt, v), + Apply(Op::Le, v) => Apply(Op::Gt, v), + Apply(Op::Lt, v) => Apply(Op::Ge, v), + v => Apply(Op::Neg, vec![v]) + } + } + _ => unreachable!() + }) +} + + +pub fn minus_expr<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + Ok(match exprs { + [a] => { + match a.eval()? { + Const(Null) => Const(Null), + Const(Int(i)) => Const(Int(-i)), + Const(Float(f)) => Const(Float(-f)), + Const(_) => return Err(TypeError), + Apply(Op::Minus, v) => v.into_iter().next().unwrap(), + v => Apply(Op::Minus, vec![v]) + } + } + _ => unreachable!() + }) +} + + +pub fn is_null_expr<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + Ok(match exprs { + [a] => { + match a.eval()? { + Const(Null) => Const(Bool(true)), + Const(_) => Const(Bool(false)), + v => Apply(Op::IsNull, vec![v]) + } + } + _ => unreachable!() + }) +} + +pub fn not_null_expr<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + Ok(match exprs { + [a] => { + match a.eval()? { + Const(Null) => Const(Bool(false)), + Const(_) => Const(Bool(true)), + v => Apply(Op::IsNull, vec![v]) + } + } + _ => unreachable!() + }) +} + +pub fn or_expr<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + let mut unevaluated = vec![]; + let mut has_null = false; + for expr in exprs { + match expr.eval()? { + Const(Bool(true)) => return Ok(Const(Bool(true))), + Const(Bool(false)) => {} + Const(Null) => { has_null = true}, + Const(_) => return Err(TypeError), + Apply(Op::Or, vs) => { + for el in vs { + match el { + Const(Null) => has_null = true, + Const(_) => unreachable!(), + v => unevaluated.push(v) + } + } + } + v => unevaluated.push(v) + } + } + match (has_null, unevaluated.len()) { + (true, 0) => Ok(Const(Null)), + (false, 0) => Ok(Const(Bool(false))), + (false, _) => Ok(Apply(Op::Or, unevaluated)), + (true, _) => { + unevaluated.push(Const(Null)); + Ok(Apply(Op::Or, unevaluated)) + } + } +} + + + +pub fn and_expr<'a>(exprs: &[Expr<'a>]) -> Result, CozoError> { + let mut unevaluated = vec![]; + let mut no_null = true; + for expr in exprs { + match expr.eval()? { + Const(Bool(false)) => return Ok(Const(Bool(false))), + Const(Bool(true)) => {}, + Const(Null) => no_null = false, + Const(_) => return Err(TypeError), + Apply(Op::Or, vs) => { + for el in vs { + match el { + Const(Null) => no_null = false, + Const(_) => unreachable!(), + v => unevaluated.push(v) + } + } + } + v => unevaluated.push(v) + } + } + match (no_null, unevaluated.len()) { + (true, 0) => Ok(Const(Bool(true))), + (false, 0) => Ok(Const(Null)), + (true, _) => Ok(Apply(Op::Add, unevaluated)), + (false, _) => { + unevaluated.push(Const(Null)); + Ok(Apply(Op::And, unevaluated)) + } + } +} \ No newline at end of file diff --git a/src/ast.rs b/src/ast/mod.rs similarity index 61% rename from src/ast.rs rename to src/ast/mod.rs index 07f89a0a..fcc831e0 100644 --- a/src/ast.rs +++ b/src/ast/mod.rs @@ -4,31 +4,14 @@ use pest::prec_climber::{Assoc, PrecClimber, Operator}; use crate::parser::Parser; use crate::parser::Rule; use lazy_static::lazy_static; -use crate::ast::Expr::Const; +use crate::ast::eval_op::*; +use crate::ast::Expr::{Apply, Const}; +use crate::ast::op::Op; +use crate::error::CozoError; use crate::value::Value; -use thiserror::Error; -#[derive(Error, Debug)] -pub enum CozoError { - #[error("Invalid UTF code")] - InvalidUtfCode, - - #[error("Type mismatch")] - InfixTypeMismatch { - op: Rule, - lhs: Value<'static>, - rhs: Value<'static>, - }, - - #[error(transparent)] - ParseInt(#[from] std::num::ParseIntError), - - #[error(transparent)] - ParseFloat(#[from] std::num::ParseFloatError), - - #[error(transparent)] - Parse(#[from] pest::error::Error), -} +mod eval_op; +mod op; lazy_static! { @@ -49,72 +32,69 @@ lazy_static! { }; } + #[derive(PartialEq, Debug)] pub enum Expr<'a> { - UnaryOp, - BinaryOp, - AssocOp, - Accessor, - FnCall, + Apply(Op, Vec>), Const(Value<'a>), } +impl<'a> Expr<'a> { + pub fn eval(&self) -> Result, CozoError> { + match self { + Apply(op, args) => { + match op { + Op::Add => add_exprs(args), + Op::Sub => sub_exprs(args), + Op::Mul => mul_exprs(args), + Op::Div => div_exprs(args), + Op::Eq => eq_exprs(args), + Op::Neq => ne_exprs(args), + Op::Gt => gt_exprs(args), + Op::Lt => lt_exprs(args), + Op::Ge => ge_exprs(args), + Op::Le => le_exprs(args), + Op::Neg => negate_expr(args), + Op::Minus => minus_expr(args), + Op::Mod => mod_exprs(args), + Op::Or => or_expr(args), + Op::And => and_expr(args), + Op::Coalesce => coalesce_exprs(args), + Op::Pow => pow_exprs(args), + Op::IsNull => is_null_expr(args), + Op::NotNull => not_null_expr(args), + Op::Call => unimplemented!(), + } + } + Const(v) => Ok(Const(v.clone())) + } + } +} + fn build_expr_infix<'a>(lhs: Result, CozoError>, op: Pair, rhs: Result, CozoError>) -> Result, CozoError> { let lhs = lhs?; let rhs = rhs?; - if let (Const(a), Const(b)) = (lhs, rhs) { - let rule = op.as_rule(); - return match rule { - Rule::op_add => { - match (a, b) { - (Value::Null, _) => Ok(Const(Value::Null)), - (_, Value::Null) => Ok(Const(Value::Null)), - (Value::Int(va), Value::Int(vb)) => Ok(Const(Value::Int(va + vb))), - (Value::Float(va), Value::Int(vb)) => Ok(Const(Value::Float(va + vb as f64))), - (Value::Int(va), Value::Float(vb)) => Ok(Const(Value::Float(va as f64 + vb))), - (Value::Float(va), Value::Float(vb)) => Ok(Const(Value::Float(va + vb))), - (Value::OwnString(va), Value::OwnString(vb)) => Ok(Const(Value::OwnString(Box::new(*va + &*vb)))), - (Value::OwnString(va), Value::RefString(vb)) => Ok(Const(Value::OwnString(Box::new(*va + &*vb)))), - (Value::RefString(va), Value::OwnString(vb)) => Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))), - (Value::RefString(va), Value::RefString(vb)) => Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))), - (a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) - } - } - Rule::op_sub => { - match (a, b) { - (Value::Null, _) => Ok(Const(Value::Null)), - (_, Value::Null) => Ok(Const(Value::Null)), - (Value::Int(va), Value::Int(vb)) => Ok(Const(Value::Int(va - vb))), - (Value::Float(va), Value::Int(vb)) => Ok(Const(Value::Float(va - vb as f64))), - (Value::Int(va), Value::Float(vb)) => Ok(Const(Value::Float(va as f64 - vb))), - (Value::Float(va), Value::Float(vb)) => Ok(Const(Value::Float(va - vb))), - (a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) - } - } - Rule::op_mul => { - match (a, b) { - (Value::Null, _) => Ok(Const(Value::Null)), - (_, Value::Null) => Ok(Const(Value::Null)), - (Value::Int(va), Value::Int(vb)) => Ok(Const(Value::Int(va * vb))), - (Value::Float(va), Value::Int(vb)) => Ok(Const(Value::Float(va * vb as f64))), - (Value::Int(va), Value::Float(vb)) => Ok(Const(Value::Float(va as f64 * vb))), - (Value::Float(va), Value::Float(vb)) => Ok(Const(Value::Float(va * vb))), - (a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) - } - } - Rule::op_div => { - match (a, b) { - (Value::Null, _) => Ok(Const(Value::Null)), - (_, Value::Null) => Ok(Const(Value::Null)), - (Value::Int(va), Value::Int(vb)) => Ok(Const(Value::Float(va as f64 / vb as f64))), - (Value::Float(va), Value::Int(vb)) => Ok(Const(Value::Float(va / vb as f64))), - (Value::Int(va), Value::Float(vb)) => Ok(Const(Value::Float(va as f64 / vb))), - (Value::Float(va), Value::Float(vb)) => Ok(Const(Value::Float(va / vb))), - (a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) - } - } - Rule::op_eq => Ok(Const(Value::Bool(a == b))), - Rule::op_ne => Ok(Const(Value::Bool(a != b))), + let op = match op.as_rule() { + Rule::op_add => Op::Add, + Rule::op_sub => Op::Sub, + Rule::op_mul => Op::Mul, + Rule::op_div => Op::Div, + Rule::op_eq => Op::Eq, + Rule::op_ne => Op::Neq, + Rule::op_or => Op::Or, + Rule::op_and => Op::And, + Rule::op_mod => Op::Mod, + Rule::op_gt => Op::Gt, + Rule::op_ge => Op::Ge, + Rule::op_lt => Op::Lt, + Rule::op_le => Op::Le, + Rule::op_pow => Op::Pow, + Rule::op_coalesce => Op::Coalesce, + _ => unreachable!() + }; + Ok(Apply(op, vec![lhs, rhs])) + /* + /* Rule::op_or => { match (a, b) { (Value::Null, Value::Null) => Ok(Const(Value::Null)), @@ -133,12 +113,8 @@ fn build_expr_infix<'a>(lhs: Result, CozoError>, op: Pair, rhs: R (a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) } } - Rule::op_coalesce => Ok(if a == Value::Null { Const(b) } else { Const(a) }), - _ => { unimplemented!() } - }; - } else { - unimplemented!() - } + */ + */ } #[inline] @@ -148,7 +124,7 @@ fn parse_int(s: &str, radix: u32) -> i64 { #[inline] fn parse_quoted_string(pairs: Pairs) -> Result { - let mut ret = String::new(); + let mut ret = String::with_capacity(pairs.as_str().len()); for pair in pairs { let s = pair.as_str(); match s { @@ -165,6 +141,7 @@ fn parse_quoted_string(pairs: Pairs) -> Result { let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?; ret.push(ch); } + s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence), s => ret.push_str(s) } } @@ -174,7 +151,7 @@ fn parse_quoted_string(pairs: Pairs) -> Result { #[inline] fn parse_s_quoted_string(pairs: Pairs) -> Result { - let mut ret = String::new(); + let mut ret = String::with_capacity(pairs.as_str().len()); for pair in pairs { let s = pair.as_str(); match s { @@ -191,6 +168,7 @@ fn parse_s_quoted_string(pairs: Pairs) -> Result { let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?; ret.push(ch); } + s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence), s => ret.push_str(s) } } @@ -201,6 +179,26 @@ fn build_expr_primary(pair: Pair) -> Result { match pair.as_rule() { Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()), Rule::term => build_expr_primary(pair.into_inner().next().unwrap()), + Rule::grouping => build_expr(pair.into_inner().next().unwrap()), + + Rule::unary => { + let mut inner = pair.into_inner(); + let op = inner.next().unwrap().as_rule(); + let term = build_expr_primary(inner.next().unwrap())?; + /* + match (op, term) { + (Rule::minus, Const(Value::Int(i))) => Ok(Const(Value::Int(-i))), + (Rule::minus, Const(Value::Float(f))) => Ok(Const(Value::Float(-f))), + (_, Const(term)) => Err(PrefixTypeMismatch { op, term: term.into_owned() }), + (_, _) => unimplemented!() + } + */ + Ok(Apply(match op { + Rule::negate => Op::Neg, + Rule::minus => Op::Minus, + _ => unreachable!() + }, vec![term])) + } Rule::pos_int => Ok(Const(Value::Int(pair.as_str().replace('_', "").parse::()?))), Rule::hex_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 16)))), @@ -255,6 +253,11 @@ mod tests { #[test] fn operators() { - println!("{:#?}", parse_expr_from_str("1/10+2+3*4").unwrap()); + println!("{:#?}", parse_expr_from_str("1/10+(-2+3)*4^5").unwrap().eval().unwrap()); + println!("{:#?}", parse_expr_from_str("true && false").unwrap().eval().unwrap()); + println!("{:#?}", parse_expr_from_str("true || false").unwrap().eval().unwrap()); + println!("{:#?}", parse_expr_from_str("true || null").unwrap().eval().unwrap()); + println!("{:#?}", parse_expr_from_str("null || true").unwrap().eval().unwrap()); + println!("{:#?}", parse_expr_from_str("true && null").unwrap().eval().unwrap()); } } \ No newline at end of file diff --git a/src/ast/op.rs b/src/ast/op.rs new file mode 100644 index 00000000..1de2cbc3 --- /dev/null +++ b/src/ast/op.rs @@ -0,0 +1,24 @@ + +#[derive(PartialEq, Debug)] +pub enum Op { + Add, + Sub, + Mul, + Div, + Eq, + Neq, + Gt, + Lt, + Ge, + Le, + Neg, + Minus, + Mod, + Or, + And, + Coalesce, + Pow, + Call, + IsNull, + NotNull +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..a44f5dd9 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,23 @@ +use thiserror::Error; +use crate::parser::Rule; + +#[derive(Error, Debug)] +pub enum CozoError { + #[error("Invalid UTF code")] + InvalidUtfCode, + + #[error("Invalid escape sequence")] + InvalidEscapeSequence, + + #[error("Type mismatch")] + TypeError, + + #[error(transparent)] + ParseInt(#[from] std::num::ParseIntError), + + #[error(transparent)] + ParseFloat(#[from] std::num::ParseFloatError), + + #[error(transparent)] + Parse(#[from] pest::error::Error), +} diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/function.rs b/src/function.rs new file mode 100644 index 00000000..fcd2b0f8 --- /dev/null +++ b/src/function.rs @@ -0,0 +1,73 @@ +use std::collections::BTreeMap; +use std::fmt::{Debug, Formatter}; +use crate::typing::{PrimitiveType, Typing}; +use crate::value::Value; +use lazy_static::lazy_static; + +#[derive(PartialEq, Debug)] +pub struct Function { + pub args: Vec, + pub var_arg: Option, + pub ret_type: Typing, + pub fn_impl: FunctionImpl, +} + +pub enum FunctionImpl { + Native(&'static str, for<'a> fn(&[Value<'a>]) -> Value<'a>), + UserDefined(()), +} + +impl Debug for FunctionImpl { + fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +impl PartialEq for FunctionImpl { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (FunctionImpl::Native(a,_), FunctionImpl::Native(b,_)) => a == b, + (FunctionImpl::UserDefined(a), FunctionImpl::UserDefined(b)) => a == b, + (_, _) => false + } + } +} + +#[derive(PartialEq, Debug)] +pub struct Arg { + pub typing: Typing, + pub default_val: Option>, + pub name: Option, +} + +lazy_static! { + static ref BUILT_IN_FUNCTIONS : BTreeMap<&'static str, Function> = { + let mut ret = BTreeMap::new(); + + fn add_int<'a>(_args: &[Value<'a>]) -> Value<'a> { + todo!() + } + + fn add_float<'a>(_args: &[Value<'a>]) -> Value<'a> { + todo!() + } + + ret.insert("_add_int", + Function { + args: vec![], + var_arg: Some(Typing::Primitive(PrimitiveType::Int)), + ret_type: Typing::Primitive(PrimitiveType::Int), + fn_impl: FunctionImpl::Native("_add_int", add_int) + }); + + ret.insert("_add_float", + Function { + args: vec![], + var_arg: Some(Typing::Primitive(PrimitiveType::Float)), + ret_type: Typing::Primitive(PrimitiveType::Float), + fn_impl: FunctionImpl::Native("_add_float", add_float) + }); + + ret + }; +} diff --git a/src/lib.rs b/src/lib.rs index 65a9eb03..890b5b1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,4 +3,6 @@ pub mod typing; pub mod env; pub mod ast; pub mod parser; - +pub mod eval; +pub mod function; +pub mod error; \ No newline at end of file