|
|
|
@ -3,10 +3,32 @@ use pest::Parser as PestParser;
|
|
|
|
|
use pest::prec_climber::{Assoc, PrecClimber, Operator};
|
|
|
|
|
use crate::parser::Parser;
|
|
|
|
|
use crate::parser::Rule;
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
use crate::ast::Expr::Const;
|
|
|
|
|
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<Rule>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
@ -37,85 +59,87 @@ pub enum Expr<'a> {
|
|
|
|
|
Const(Value<'a>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_expr_infix<'a>(lhs: Result<Expr<'a>>, op: Pair<Rule>, rhs: Result<Expr<'a>>) -> Result<Expr<'a>> {
|
|
|
|
|
fn parse_expr_infix<'a>(lhs: Result<Expr<'a>, CozoError>, op: Pair<Rule>, rhs: Result<Expr<'a>, CozoError>) -> Result<Expr<'a>, CozoError> {
|
|
|
|
|
let lhs = lhs?;
|
|
|
|
|
let rhs = rhs?;
|
|
|
|
|
if let (Const(a), Const(b)) = (lhs, rhs) {
|
|
|
|
|
match op.as_rule() {
|
|
|
|
|
let rule = op.as_rule();
|
|
|
|
|
return match rule {
|
|
|
|
|
Rule::op_add => {
|
|
|
|
|
match (a, b) {
|
|
|
|
|
(Value::Null, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Int(va + vb))),
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va + vb as f64))),
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 + vb))),
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va + vb))),
|
|
|
|
|
(Value::OwnString(va), Value::OwnString(vb)) => return Ok(Const(Value::OwnString(Box::new(*va + &*vb)))),
|
|
|
|
|
(Value::OwnString(va), Value::RefString(vb)) => return Ok(Const(Value::OwnString(Box::new(*va + &*vb)))),
|
|
|
|
|
(Value::RefString(va), Value::OwnString(vb)) => return Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))),
|
|
|
|
|
(Value::RefString(va), Value::RefString(vb)) => return Ok(Const(Value::OwnString(Box::new(va.to_string() + &*vb)))),
|
|
|
|
|
_ => panic!()
|
|
|
|
|
(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, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Int(va - vb))),
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va - vb as f64))),
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 - vb))),
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va - vb))),
|
|
|
|
|
_ => panic!()
|
|
|
|
|
(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, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Int(va * vb))),
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va * vb as f64))),
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 * vb))),
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va * vb))),
|
|
|
|
|
_ => panic!()
|
|
|
|
|
(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, _) => return Ok(Const(Value::Null)),
|
|
|
|
|
(_, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Int(va), Value::Int(vb)) => return Ok(Const(Value::Float(va as f64 / vb as f64))),
|
|
|
|
|
(Value::Float(va), Value::Int(vb)) => return Ok(Const(Value::Float(va / vb as f64))),
|
|
|
|
|
(Value::Int(va), Value::Float(vb)) => return Ok(Const(Value::Float(va as f64 / vb))),
|
|
|
|
|
(Value::Float(va), Value::Float(vb)) => return Ok(Const(Value::Float(va / vb))),
|
|
|
|
|
_ => panic!()
|
|
|
|
|
(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 => return Ok(Const(Value::Bool(a == b))),
|
|
|
|
|
Rule::op_ne => return Ok(Const(Value::Bool(a != b))),
|
|
|
|
|
Rule::op_eq => Ok(Const(Value::Bool(a == b))),
|
|
|
|
|
Rule::op_ne => Ok(Const(Value::Bool(a != b))),
|
|
|
|
|
Rule::op_or => {
|
|
|
|
|
match (a, b) {
|
|
|
|
|
(Value::Null, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Null, Value::Bool(b)) => return Ok(Const(Value::Bool(b))),
|
|
|
|
|
(Value::Bool(b), Value::Null) => return Ok(Const(Value::Bool(b))),
|
|
|
|
|
(Value::Bool(a), Value::Bool(b)) => return Ok(Const(Value::Bool(a || b))),
|
|
|
|
|
_ => panic!()
|
|
|
|
|
(Value::Null, Value::Null) => Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Null, Value::Bool(b)) => Ok(Const(Value::Bool(b))),
|
|
|
|
|
(Value::Bool(b), Value::Null) => Ok(Const(Value::Bool(b))),
|
|
|
|
|
(Value::Bool(a), Value::Bool(b)) => Ok(Const(Value::Bool(a || b))),
|
|
|
|
|
(a, b) => Err(CozoError::InfixTypeMismatch { op: rule, lhs: a.into_owned(), rhs: b.into_owned() })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Rule::op_and => {
|
|
|
|
|
match (a, b) {
|
|
|
|
|
(Value::Null, Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Null, Value::Bool(_)) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Bool(_), Value::Null) => return Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Bool(a), Value::Bool(b)) => return Ok(Const(Value::Bool(a && b))),
|
|
|
|
|
_ => panic!()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Rule::op_coalesce => return Ok(if a == Value::Null { Const(b) } else { Const(a) }),
|
|
|
|
|
_ => {}
|
|
|
|
|
(Value::Null, Value::Null) => Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Null, Value::Bool(_)) => Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Bool(_), Value::Null) => Ok(Const(Value::Null)),
|
|
|
|
|
(Value::Bool(a), Value::Bool(b)) => Ok(Const(Value::Bool(a && b))),
|
|
|
|
|
(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]
|
|
|
|
|
fn parse_int(s: &str, radix: u32) -> i64 {
|
|
|
|
@ -123,7 +147,7 @@ fn parse_int(s: &str, radix: u32) -> i64 {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
|
fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
|
|
|
|
|
let mut ret = String::new();
|
|
|
|
|
for pair in pairs {
|
|
|
|
|
let s = pair.as_str();
|
|
|
|
@ -138,11 +162,8 @@ fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
|
r"\t" => ret.push('\t'),
|
|
|
|
|
s if s.starts_with(r"\u") => {
|
|
|
|
|
let code = parse_int(s, 16) as u32;
|
|
|
|
|
let ch = char::from_u32(code);
|
|
|
|
|
match ch {
|
|
|
|
|
Some(c) => ret.push(c),
|
|
|
|
|
None => panic!()
|
|
|
|
|
}
|
|
|
|
|
let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?;
|
|
|
|
|
ret.push(ch);
|
|
|
|
|
}
|
|
|
|
|
s => ret.push_str(s)
|
|
|
|
|
}
|
|
|
|
@ -152,7 +173,7 @@ fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
|
fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
|
|
|
|
|
let mut ret = String::new();
|
|
|
|
|
for pair in pairs {
|
|
|
|
|
let s = pair.as_str();
|
|
|
|
@ -167,11 +188,8 @@ fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
|
r"\t" => ret.push('\t'),
|
|
|
|
|
s if s.starts_with(r"\u") => {
|
|
|
|
|
let code = parse_int(s, 16) as u32;
|
|
|
|
|
let ch = char::from_u32(code);
|
|
|
|
|
match ch {
|
|
|
|
|
Some(c) => ret.push(c),
|
|
|
|
|
None => panic!()
|
|
|
|
|
}
|
|
|
|
|
let ch = char::from_u32(code).ok_or(CozoError::InvalidUtfCode)?;
|
|
|
|
|
ret.push(ch);
|
|
|
|
|
}
|
|
|
|
|
s => ret.push_str(s)
|
|
|
|
|
}
|
|
|
|
@ -179,7 +197,7 @@ fn parse_s_quoted_string(pairs: Pairs<Rule>) -> Result<String> {
|
|
|
|
|
Ok(ret)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
|
|
|
|
|
fn parse_expr_primary(pair: Pair<Rule>) -> Result<Expr, CozoError> {
|
|
|
|
|
match pair.as_rule() {
|
|
|
|
|
Rule::expr => parse_expr_primary(pair.into_inner().next().unwrap()),
|
|
|
|
|
Rule::term => parse_expr_primary(pair.into_inner().next().unwrap()),
|
|
|
|
@ -200,11 +218,11 @@ fn parse_expr_primary(pair: Pair<Rule>) -> Result<Expr> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_expr(pair: Pair<Rule>) -> Result<Expr> {
|
|
|
|
|
fn parse_expr(pair: Pair<Rule>) -> Result<Expr, CozoError> {
|
|
|
|
|
PREC_CLIMBER.climb(pair.into_inner(), parse_expr_primary, parse_expr_infix)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn parse_expr_from_str(inp: &str) -> Result<Expr> {
|
|
|
|
|
pub fn parse_expr_from_str(inp: &str) -> Result<Expr, CozoError> {
|
|
|
|
|
let expr_tree = Parser::parse(Rule::expr, inp)?.next().unwrap();
|
|
|
|
|
parse_expr(expr_tree)
|
|
|
|
|
}
|
|
|
|
|