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