From fa9066725bae0010e67747a56a565c8c917ce94c Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Thu, 7 Apr 2022 22:48:53 +0800 Subject: [PATCH] error handling --- Cargo.toml | 3 +- src/ast.rs | 154 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 88 insertions(+), 69 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fdd5d0ec..6f95a78e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ uuid = "0.8" chrono = "0.4" rocksdb = "0.18.0" anyhow = "1.0" -lazy_static = "1.4.0" \ No newline at end of file +lazy_static = "1.4.0" +thiserror = "1.0.30" \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index eb71f5fa..7d31d286 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -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), +} lazy_static! { @@ -37,84 +59,86 @@ pub enum Expr<'a> { Const(Value<'a>), } -fn parse_expr_infix<'a>(lhs: Result>, op: Pair, rhs: Result>) -> Result> { +fn parse_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) { - 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!() + (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 => return Ok(if a == Value::Null { Const(b) } else { Const(a) }), - _ => {} - } + } + Rule::op_coalesce => Ok(if a == Value::Null { Const(b) } else { Const(a) }), + _ => { unimplemented!() } + }; + } else { + unimplemented!() } - unimplemented!() } #[inline] @@ -123,7 +147,7 @@ fn parse_int(s: &str, radix: u32) -> i64 { } #[inline] -fn parse_quoted_string(pairs: Pairs) -> Result { +fn parse_quoted_string(pairs: Pairs) -> Result { let mut ret = String::new(); for pair in pairs { let s = pair.as_str(); @@ -138,11 +162,8 @@ fn parse_quoted_string(pairs: Pairs) -> Result { 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) -> Result { #[inline] -fn parse_s_quoted_string(pairs: Pairs) -> Result { +fn parse_s_quoted_string(pairs: Pairs) -> Result { 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) -> Result { 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) -> Result { Ok(ret) } -fn parse_expr_primary(pair: Pair) -> Result { +fn parse_expr_primary(pair: Pair) -> Result { 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) -> Result { } } -fn parse_expr(pair: Pair) -> Result { +fn parse_expr(pair: Pair) -> Result { PREC_CLIMBER.climb(pair.into_inner(), parse_expr_primary, parse_expr_infix) } -pub fn parse_expr_from_str(inp: &str) -> Result { +pub fn parse_expr_from_str(inp: &str) -> Result { let expr_tree = Parser::parse(Rule::expr, inp)?.next().unwrap(); parse_expr(expr_tree) }