separate expression evaluator

main
Ziyang Hu 2 years ago
parent bd2d61d91b
commit 20cf83d2bf

@ -4,8 +4,10 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/cozo_parser/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/cozo_parser/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/ast/op/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
<excludeFolder url="file://$MODULE_DIR$/cozo_parser/target" /> <excludeFolder url="file://$MODULE_DIR$/cozo_parser/target" />
<excludeFolder url="file://$MODULE_DIR$/src/ast/op/target" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />

@ -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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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<Expr<'a>, 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))
}
}
}

@ -4,31 +4,14 @@ use pest::prec_climber::{Assoc, PrecClimber, Operator};
use crate::parser::Parser; use crate::parser::Parser;
use crate::parser::Rule; use crate::parser::Rule;
use lazy_static::lazy_static; 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 crate::value::Value;
use thiserror::Error;
#[derive(Error, Debug)] mod eval_op;
pub enum CozoError { mod op;
#[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<Rule>),
}
lazy_static! { lazy_static! {
@ -49,72 +32,69 @@ lazy_static! {
}; };
} }
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum Expr<'a> { pub enum Expr<'a> {
UnaryOp, Apply(Op, Vec<Expr<'a>>),
BinaryOp,
AssocOp,
Accessor,
FnCall,
Const(Value<'a>), Const(Value<'a>),
} }
impl<'a> Expr<'a> {
pub fn eval(&self) -> Result<Expr<'a>, 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<Expr<'a>, CozoError>, op: Pair<Rule>, rhs: Result<Expr<'a>, CozoError>) -> Result<Expr<'a>, CozoError> { fn build_expr_infix<'a>(lhs: Result<Expr<'a>, CozoError>, op: Pair<Rule>, rhs: Result<Expr<'a>, CozoError>) -> Result<Expr<'a>, CozoError> {
let lhs = lhs?; let lhs = lhs?;
let rhs = rhs?; let rhs = rhs?;
if let (Const(a), Const(b)) = (lhs, rhs) { let op = match op.as_rule() {
let rule = op.as_rule(); Rule::op_add => Op::Add,
return match rule { Rule::op_sub => Op::Sub,
Rule::op_add => { Rule::op_mul => Op::Mul,
match (a, b) { Rule::op_div => Op::Div,
(Value::Null, _) => Ok(Const(Value::Null)), Rule::op_eq => Op::Eq,
(_, Value::Null) => Ok(Const(Value::Null)), Rule::op_ne => Op::Neq,
(Value::Int(va), Value::Int(vb)) => Ok(Const(Value::Int(va + vb))), Rule::op_or => Op::Or,
(Value::Float(va), Value::Int(vb)) => Ok(Const(Value::Float(va + vb as f64))), Rule::op_and => Op::And,
(Value::Int(va), Value::Float(vb)) => Ok(Const(Value::Float(va as f64 + vb))), Rule::op_mod => Op::Mod,
(Value::Float(va), Value::Float(vb)) => Ok(Const(Value::Float(va + vb))), Rule::op_gt => Op::Gt,
(Value::OwnString(va), Value::OwnString(vb)) => Ok(Const(Value::OwnString(Box::new(*va + &*vb)))), Rule::op_ge => Op::Ge,
(Value::OwnString(va), Value::RefString(vb)) => Ok(Const(Value::OwnString(Box::new(*va + &*vb)))), Rule::op_lt => Op::Lt,
(Value::RefString(va), Value::OwnString(vb)) => Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))), Rule::op_le => Op::Le,
(Value::RefString(va), Value::RefString(vb)) => Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))), Rule::op_pow => Op::Pow,
(a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) Rule::op_coalesce => Op::Coalesce,
} _ => unreachable!()
} };
Rule::op_sub => { Ok(Apply(op, vec![lhs, rhs]))
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))),
Rule::op_or => { Rule::op_or => {
match (a, b) { match (a, b) {
(Value::Null, Value::Null) => Ok(Const(Value::Null)), (Value::Null, Value::Null) => Ok(Const(Value::Null)),
@ -133,12 +113,8 @@ fn build_expr_infix<'a>(lhs: Result<Expr<'a>, CozoError>, op: Pair<Rule>, rhs: R
(a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() }) (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] #[inline]
@ -148,7 +124,7 @@ fn parse_int(s: &str, radix: u32) -> i64 {
#[inline] #[inline]
fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> { fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
let mut ret = String::new(); let mut ret = String::with_capacity(pairs.as_str().len());
for pair in pairs { for pair in pairs {
let s = pair.as_str(); let s = pair.as_str();
match s { match s {
@ -165,6 +141,7 @@ fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?; let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?;
ret.push(ch); ret.push(ch);
} }
s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence),
s => ret.push_str(s) s => ret.push_str(s)
} }
} }
@ -174,7 +151,7 @@ fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
#[inline] #[inline]
fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> { fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
let mut ret = String::new(); let mut ret = String::with_capacity(pairs.as_str().len());
for pair in pairs { for pair in pairs {
let s = pair.as_str(); let s = pair.as_str();
match s { match s {
@ -191,6 +168,7 @@ fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?; let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?;
ret.push(ch); ret.push(ch);
} }
s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence),
s => ret.push_str(s) s => ret.push_str(s)
} }
} }
@ -201,6 +179,26 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Expr, CozoError> {
match pair.as_rule() { match pair.as_rule() {
Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()), Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()),
Rule::term => 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::<i64>()?))), Rule::pos_int => Ok(Const(Value::Int(pair.as_str().replace('_', "").parse::<i64>()?))),
Rule::hex_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 16)))), Rule::hex_pos_int => Ok(Const(Value::Int(parse_int(pair.as_str(), 16)))),
@ -255,6 +253,11 @@ mod tests {
#[test] #[test]
fn operators() { 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());
} }
} }

@ -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
}

@ -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<Rule>),
}

@ -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<Arg>,
pub var_arg: Option<Typing>,
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<Value<'static>>,
pub name: Option<String>,
}
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
};
}

@ -3,4 +3,6 @@ pub mod typing;
pub mod env; pub mod env;
pub mod ast; pub mod ast;
pub mod parser; pub mod parser;
pub mod eval;
pub mod function;
pub mod error;
Loading…
Cancel
Save