another round of refactoring

main
Ziyang Hu 2 years ago
parent bb1eeacc71
commit 304ea38e29

@ -15,4 +15,6 @@ chrono = "0.4"
anyhow = "1.0"
lazy_static = "1.4.0"
thiserror = "1.0.30"
log = "0.4.16"
env_logger = "0.9.0"
cozorocks = { path = "cozorocks" }

@ -0,0 +1,6 @@
pub(crate) mod expr;
pub(crate) mod op;
pub(crate) mod tuple;
pub(crate) mod tuple_set;
pub(crate) mod typing;
pub(crate) mod value;

@ -0,0 +1,21 @@
use crate::data::op::Op;
use crate::data::tuple_set::{ColId, TableId, TupleSetIdx};
use crate::data::value::Value;
use std::collections::BTreeMap;
use std::sync::Arc;
pub(crate) enum Expr<'a> {
Const(Value<'a>),
List(Vec<Expr<'a>>),
Dict(BTreeMap<String, Expr<'a>>),
Variable(String),
TableCol(TableId, ColId),
TupleSetIdx(TupleSetIdx),
Apply(Arc<Op>, Vec<Expr<'a>>),
FieldAcc(String, Box<Expr<'a>>),
IdxAcc(usize, Box<Expr<'a>>),
}
pub(crate) type StaticExpr = Expr<'static>;
// TODO serde expr into value

@ -0,0 +1 @@
pub(crate) struct Op;

@ -0,0 +1,47 @@
#[repr(u8)]
#[derive(Ord, PartialOrd, Eq, PartialEq)]
pub(crate) enum Tag {
BoolFalse = 1,
Null = 2,
BoolTrue = 3,
Int = 4,
Float = 5,
Text = 6,
Uuid = 7,
Bytes = 64,
List = 128,
Dict = 129,
DescVal = 192,
Max = 255,
}
impl TryFrom<u8> for Tag {
type Error = u8;
#[inline]
fn try_from(u: u8) -> std::result::Result<Tag, u8> {
use self::Tag::*;
Ok(match u {
1 => BoolFalse,
2 => Null,
3 => BoolTrue,
4 => Int,
5 => Float,
6 => Text,
7 => Uuid,
64 => Bytes,
128 => List,
129 => Dict,
192 => DescVal,
255 => Max,
v => return Err(v),
})
}
}

@ -0,0 +1,3 @@
pub(crate) struct TableId;
pub(crate) struct ColId;
pub(crate) struct TupleSetIdx;

@ -0,0 +1,207 @@
use crate::data::value::{StaticValue, Value};
use std::fmt::{Display, Formatter};
use std::result;
use pest::{Parser};
use pest::iterators::Pair;
use crate::parser::{CozoParser, Rule};
use crate::parser::text_identifier::build_name_in_def;
#[derive(thiserror::Error, Debug)]
pub(crate) enum TypingError {
#[error("Not null constraint violated for {0}")]
NotNullViolated(Typing),
#[error("Type mismatch: {1} cannot be interpreted as {0}")]
TypeMismatch(Typing, StaticValue),
#[error("Undefined type '{0}'")]
UndefinedType(String),
#[error(transparent)]
Parse(#[from] pest::error::Error<Rule>),
#[error(transparent)]
TextParse(#[from] crate::parser::text_identifier::TextParseError)
}
type Result<T> = result::Result<T, TypingError>;
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
pub(crate) enum Typing {
Any,
Bool,
Int,
Float,
Text,
Uuid,
Nullable(Box<Typing>),
Homogeneous(Box<Typing>),
UnnamedTuple(Vec<Typing>),
NamedTuple(Vec<(String, Typing)>),
}
impl Display for Typing {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Typing::Any => write!(f, "Any"),
Typing::Bool => write!(f, "Bool"),
Typing::Int => write!(f, "Int"),
Typing::Float => write!(f, "Float"),
Typing::Text => write!(f, "Text"),
Typing::Uuid => write!(f, "Uuid"),
Typing::Nullable(t) => write!(f, "?{}", t),
Typing::Homogeneous(h) => write!(f, "[{}]", h),
Typing::UnnamedTuple(u) => {
let collected = u.iter().map(|v| v.to_string()).collect::<Vec<_>>();
let joined = collected.join(",");
write!(f, "({})", joined)
}
Typing::NamedTuple(n) => {
let collected = n
.iter()
.map(|(k, v)| format!(r##""{}":{}"##, k, v))
.collect::<Vec<_>>();
let joined = collected.join(",");
write!(f, "{{")?;
write!(f, "{}", joined)?;
write!(f, "}}")
}
}
}
}
impl Typing {
pub(crate) fn coerce<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
if *self == Typing::Any {
return Ok(v);
}
if v == Value::Null {
return if matches!(self, Typing::Nullable(_)) {
Ok(Value::Null)
} else {
Err(TypingError::NotNullViolated(self.clone()))
};
}
if let Typing::Nullable(t) = self {
return t.coerce(v);
}
match self {
Typing::Bool => self.coerce_bool(v),
Typing::Int => self.coerce_int(v),
Typing::Float => self.coerce_float(v),
Typing::Text => self.coerce_text(v),
Typing::Uuid => self.coerce_uuid(v),
Typing::Homogeneous(t) => match v {
Value::List(vs) => Ok(Value::List(
vs.into_iter()
.map(|v| t.coerce(v))
.collect::<Result<Vec<_>>>()?,
)),
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
},
Typing::UnnamedTuple(_ut) => {
todo!()
}
Typing::NamedTuple(_nt) => {
todo!()
}
Typing::Any => unreachable!(),
Typing::Nullable(_) => unreachable!(),
}
}
fn coerce_bool<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Bool(_) => Ok(v),
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
}
}
fn coerce_int<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Int(_) => Ok(v),
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
}
}
fn coerce_float<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Float(_) => Ok(v),
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
}
}
fn coerce_text<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Text(_) => Ok(v),
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
}
}
fn coerce_uuid<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
match v {
v @ Value::Uuid(_) => Ok(v),
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
}
}
}
impl TryFrom<&str> for Typing {
type Error = TypingError;
fn try_from(value: &str) -> Result<Self> {
let pair = CozoParser::parse(Rule::typing, value)?.next().unwrap();
Typing::from_pair(pair)
}
}
impl<'a> TryFrom<Value<'a>> for Typing {
type Error = TypingError;
fn try_from(value: Value<'a>) -> result::Result<Self, Self::Error> {
todo!()
}
}
impl Typing {
pub fn from_pair<'a>(pair: Pair<Rule>) -> Result<Self> {
Ok(match pair.as_rule() {
Rule::simple_type => match pair.as_str() {
"Any" => Typing::Any,
"Bool" => Typing::Bool,
"Int" => Typing::Int,
"Float" => Typing::Float,
"Text" => Typing::Text,
"Uuid" => Typing::Uuid,
t => return Err(TypingError::UndefinedType(t.to_string())),
},
Rule::nullable_type => Typing::Nullable(Box::new(Typing::from_pair(
pair.into_inner().next().unwrap()
)?)),
Rule::homogeneous_list_type => Typing::Homogeneous(Box::new(Typing::from_pair(
pair.into_inner().next().unwrap()
)?)),
Rule::unnamed_tuple_type => {
let types = pair
.into_inner()
.map(|p| Typing::from_pair(p))
.collect::<Result<Vec<Typing>>>()?;
Typing::UnnamedTuple(types)
}
Rule::named_tuple_type => {
let types = pair
.into_inner()
.map(|p| -> Result<(String, Typing)> {
let mut ps = p.into_inner();
let name_pair = ps.next().unwrap();
let name = build_name_in_def(name_pair, true)?;
let typ_pair = ps.next().unwrap();
let typ = Typing::from_pair(typ_pair)?;
Ok((name, typ))
})
.collect::<Result<Vec<(String, Typing)>>>()?;
Typing::NamedTuple(types)
}
_ => unreachable!(),
})
}
}

@ -0,0 +1,260 @@
use ordered_float::OrderedFloat;
use std::borrow::Cow;
use std::cmp::{min, Reverse};
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter, Write};
use uuid::Uuid;
#[derive(Clone, PartialEq, Ord, PartialOrd, Eq)]
pub enum Value<'a> {
Null,
Bool(bool),
Int(i64),
Float(OrderedFloat<f64>),
Uuid(Uuid),
Text(Cow<'a, str>),
Bytes(Cow<'a, [u8]>),
List(Vec<Value<'a>>),
Dict(BTreeMap<Cow<'a, str>, Value<'a>>),
DescVal(Reverse<Box<Value<'a>>>),
EndSentinel,
}
pub(crate) type StaticValue = Value<'static>;
impl<'a> Debug for Value<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Value {{ {} }}", self)
}
}
impl From<()> for StaticValue {
#[inline]
fn from(_: ()) -> Self {
Value::Null
}
}
impl From<bool> for StaticValue {
#[inline]
fn from(b: bool) -> Self {
Value::Bool(b)
}
}
impl From<i64> for StaticValue {
#[inline]
fn from(i: i64) -> Self {
Value::Int(i)
}
}
impl From<i32> for StaticValue {
#[inline]
fn from(i: i32) -> Self {
Value::Int(i as i64)
}
}
impl From<f64> for StaticValue {
#[inline]
fn from(f: f64) -> Self {
Value::Float(f.into())
}
}
impl From<OrderedFloat<f64>> for StaticValue {
#[inline]
fn from(f: OrderedFloat<f64>) -> Self {
Value::Float(f)
}
}
impl<'a> From<&'a str> for Value<'a> {
#[inline]
fn from(s: &'a str) -> Self {
Value::Text(Cow::Borrowed(s))
}
}
impl<'a> From<&'a [u8]> for Value<'a> {
#[inline]
fn from(v: &'a [u8]) -> Self {
Value::Bytes(Cow::Borrowed(v))
}
}
impl From<String> for StaticValue {
#[inline]
fn from(s: String) -> Self {
Value::Text(Cow::Owned(s))
}
}
impl From<Vec<u8>> for StaticValue {
#[inline]
fn from(v: Vec<u8>) -> Self {
Value::Bytes(Cow::Owned(v))
}
}
impl From<Uuid> for StaticValue {
#[inline]
fn from(u: Uuid) -> Self {
Value::Uuid(u)
}
}
impl<'a> From<Vec<Value<'a>>> for Value<'a> {
#[inline]
fn from(v: Vec<Value<'a>>) -> Self {
Value::List(v)
}
}
impl<'a> From<BTreeMap<Cow<'a, str>, Value<'a>>> for Value<'a> {
#[inline]
fn from(m: BTreeMap<Cow<'a, str>, Value<'a>>) -> Self {
Value::Dict(m)
}
}
impl<'a> Display for Value<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Value::Null => {
write!(f, "null")?;
}
Value::Bool(b) => {
write!(f, "{}", if *b { "true" } else { "false" })?;
}
Value::Int(i) => {
write!(f, "{}", i)?;
}
Value::Float(n) => {
write!(f, "{}", n.into_inner())?;
}
Value::Uuid(u) => {
write!(f, "{}", u)?;
}
Value::Bytes(b) => {
write!(f, "<{} bytes: {:?} ..>", b.len(), &b[..min(8, b.len())])?;
}
Value::Text(t) => {
f.write_char('"')?;
for char in t.chars() {
match char {
'"' => {
f.write_str("\\\"")?;
}
'\\' => {
f.write_str("\\\\")?;
}
'/' => {
f.write_str("\\/")?;
}
'\x08' => {
f.write_str("\\b")?;
}
'\x0c' => {
f.write_str("\\f")?;
}
'\n' => {
f.write_str("\\n")?;
}
'\r' => {
f.write_str("\\r")?;
}
'\t' => {
f.write_str("\\t")?;
}
c => {
f.write_char(c)?;
}
}
}
f.write_char('"')?;
}
Value::List(l) => {
f.write_char('[')?;
let mut first = true;
for v in l.iter() {
if !first {
f.write_char(',')?;
}
Display::fmt(v, f)?;
first = false;
}
f.write_char(']')?;
}
Value::Dict(d) => {
f.write_char('{')?;
let mut first = true;
for (k, v) in d.iter() {
if !first {
f.write_char(',')?;
}
Display::fmt(&Value::Text(k.clone()), f)?;
f.write_char(':')?;
Display::fmt(v, f)?;
first = false;
}
f.write_char('}')?;
}
Value::EndSentinel => write!(f, "Sentinel")?,
Value::DescVal(Reverse(v)) => {
write!(f, "~{}", v)?;
}
}
Ok(())
}
}
impl<'a> Value<'a> {
#[inline]
pub fn to_static(self) -> StaticValue {
match self {
Value::Null => Value::from(()),
Value::Bool(b) => Value::from(b),
Value::Int(i) => Value::from(i),
Value::Float(f) => Value::from(f),
Value::Uuid(u) => Value::from(u),
Value::Text(t) => Value::from(t.into_owned()),
Value::List(l) => l
.into_iter()
.map(|v| v.to_static())
.collect::<Vec<StaticValue>>()
.into(),
Value::Dict(d) => d
.into_iter()
.map(|(k, v)| (Cow::Owned(k.into_owned()), v.to_static()))
.collect::<BTreeMap<Cow<'static, str>, StaticValue>>()
.into(),
Value::EndSentinel => panic!("Cannot process sentinel value"),
Value::Bytes(t) => Value::from(t.into_owned()),
Value::DescVal(Reverse(val)) => Value::DescVal(Reverse(val.to_static().into())),
}
}
}
#[cfg(test)]
mod tests {
use crate::data::value::Value;
use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use std::mem::size_of;
use uuid::Uuid;
#[test]
fn print_sizes() {
dbg!(size_of::<usize>());
dbg!(size_of::<Uuid>());
dbg!(size_of::<Cow<str>>());
dbg!(size_of::<BTreeMap<(), ()>>());
dbg!(size_of::<HashMap<(), ()>>());
dbg!(size_of::<Value>());
}
}

@ -1,28 +1,7 @@
extern crate core;
// pub mod value;
// pub mod typing;
// pub mod env;
// pub mod ast;
// pub mod parser;
// pub mod eval;
// pub mod function;
// pub mod definition;
// pub mod storage;
// pub mod mutation;
// pub mod plan;
pub mod db;
pub mod error;
pub mod parser;
pub mod relation;
pub(crate) mod eval;
#[cfg(test)]
mod tests {
#[test]
fn import() {
use cozorocks::*;
let _o = OptionsPtr::default();
println!("Hello");
}
}
// pub mod db;
// pub mod error;
// pub mod relation;
// pub(crate) mod eval;
pub(crate) mod parser;
pub(crate) mod data;
pub(crate) mod logger;

@ -0,0 +1,28 @@
#[cfg(test)]
mod tests {
fn init_logger() {
let _ = env_logger::builder()
// Include all events in tests
.filter_level(log::LevelFilter::max())
// Ensure events are captured by `cargo test`
.is_test(true)
// Ignore errors initializing the logger if tests race to configure it
.try_init();
}
#[test]
fn test_logger() {
use log::{debug, error, info, log_enabled, Level};
init_logger();
debug!("this is a debug {}", "message");
error!("this is printed by default");
if log_enabled!(Level::Info) {
let x = dbg!(3 * 4);
// expensive computation
info!("the answer was: {}", x);
}
}
}

@ -4,7 +4,7 @@ use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct Parser;
pub struct CozoParser;
#[cfg(test)]
mod tests {
@ -13,55 +13,55 @@ mod tests {
#[test]
fn identifiers() {
assert_eq!(Parser::parse(Rule::ident, "x").unwrap().as_str(), "x");
assert_eq!(Parser::parse(Rule::ident, "x2").unwrap().as_str(), "x2");
assert_eq!(Parser::parse(Rule::ident, "x_y").unwrap().as_str(), "x_y");
assert_eq!(Parser::parse(Rule::ident, "x_").unwrap().as_str(), "x_");
assert_eq!(Parser::parse(Rule::ident, "你好").unwrap().as_str(), "你好");
assert_eq!(CozoParser::parse(Rule::ident, "x").unwrap().as_str(), "x");
assert_eq!(CozoParser::parse(Rule::ident, "x2").unwrap().as_str(), "x2");
assert_eq!(CozoParser::parse(Rule::ident, "x_y").unwrap().as_str(), "x_y");
assert_eq!(CozoParser::parse(Rule::ident, "x_").unwrap().as_str(), "x_");
assert_eq!(CozoParser::parse(Rule::ident, "你好").unwrap().as_str(), "你好");
assert_eq!(
Parser::parse(Rule::ident, "你好123").unwrap().as_str(),
CozoParser::parse(Rule::ident, "你好123").unwrap().as_str(),
"你好123"
);
assert_ne!(Parser::parse(Rule::ident, "x$y").unwrap().as_str(), "x$y");
assert_ne!(CozoParser::parse(Rule::ident, "x$y").unwrap().as_str(), "x$y");
assert_eq!(Parser::parse(Rule::ident, "_x").unwrap().as_str(), "_x");
assert_eq!(Parser::parse(Rule::ident, "_").unwrap().as_str(), "_");
assert_eq!(CozoParser::parse(Rule::ident, "_x").unwrap().as_str(), "_x");
assert_eq!(CozoParser::parse(Rule::ident, "_").unwrap().as_str(), "_");
assert!(Parser::parse(Rule::ident, "$x").is_err());
assert!(Parser::parse(Rule::ident, "$").is_err());
assert_eq!(Parser::parse(Rule::param, "$x").unwrap().as_str(), "$x");
assert!(CozoParser::parse(Rule::ident, "$x").is_err());
assert!(CozoParser::parse(Rule::ident, "$").is_err());
assert_eq!(CozoParser::parse(Rule::param, "$x").unwrap().as_str(), "$x");
assert!(Parser::parse(Rule::ident, "123x").is_err());
assert!(Parser::parse(Rule::ident, ".x").is_err());
assert_ne!(Parser::parse(Rule::ident, "x.x").unwrap().as_str(), "x.x");
assert_ne!(Parser::parse(Rule::ident, "x~x").unwrap().as_str(), "x~x");
assert!(CozoParser::parse(Rule::ident, "123x").is_err());
assert!(CozoParser::parse(Rule::ident, ".x").is_err());
assert_ne!(CozoParser::parse(Rule::ident, "x.x").unwrap().as_str(), "x.x");
assert_ne!(CozoParser::parse(Rule::ident, "x~x").unwrap().as_str(), "x~x");
}
#[test]
fn strings() {
assert_eq!(
Parser::parse(Rule::string, r#""""#).unwrap().as_str(),
CozoParser::parse(Rule::string, r#""""#).unwrap().as_str(),
r#""""#
);
assert_eq!(
Parser::parse(Rule::string, r#"" b a c""#).unwrap().as_str(),
CozoParser::parse(Rule::string, r#"" b a c""#).unwrap().as_str(),
r#"" b a c""#
);
assert_eq!(
Parser::parse(Rule::string, r#""你好👋""#).unwrap().as_str(),
CozoParser::parse(Rule::string, r#""你好👋""#).unwrap().as_str(),
r#""你好👋""#
);
assert_eq!(
Parser::parse(Rule::string, r#""\n""#).unwrap().as_str(),
CozoParser::parse(Rule::string, r#""\n""#).unwrap().as_str(),
r#""\n""#
);
assert_eq!(
Parser::parse(Rule::string, r#""\u5678""#).unwrap().as_str(),
CozoParser::parse(Rule::string, r#""\u5678""#).unwrap().as_str(),
r#""\u5678""#
);
assert!(Parser::parse(Rule::string, r#""\ux""#).is_err());
assert!(CozoParser::parse(Rule::string, r#""\ux""#).is_err());
assert_eq!(
Parser::parse(Rule::string, r###"r#"a"#"###)
CozoParser::parse(Rule::string, r###"r#"a"#"###)
.unwrap()
.as_str(),
r##"r#"a"#"##
@ -70,60 +70,60 @@ mod tests {
#[test]
fn numbers() {
assert_eq!(Parser::parse(Rule::number, "123").unwrap().as_str(), "123");
assert_eq!(Parser::parse(Rule::number, "0").unwrap().as_str(), "0");
assert_eq!(CozoParser::parse(Rule::number, "123").unwrap().as_str(), "123");
assert_eq!(CozoParser::parse(Rule::number, "0").unwrap().as_str(), "0");
assert_eq!(
Parser::parse(Rule::number, "0123").unwrap().as_str(),
CozoParser::parse(Rule::number, "0123").unwrap().as_str(),
"0123"
);
assert_eq!(
Parser::parse(Rule::number, "000_1").unwrap().as_str(),
CozoParser::parse(Rule::number, "000_1").unwrap().as_str(),
"000_1"
);
assert!(Parser::parse(Rule::number, "_000_1").is_err());
assert!(CozoParser::parse(Rule::number, "_000_1").is_err());
assert_eq!(
Parser::parse(Rule::number, "0xAf03").unwrap().as_str(),
CozoParser::parse(Rule::number, "0xAf03").unwrap().as_str(),
"0xAf03"
);
assert_eq!(
Parser::parse(Rule::number, "0o0_7067").unwrap().as_str(),
CozoParser::parse(Rule::number, "0o0_7067").unwrap().as_str(),
"0o0_7067"
);
assert_ne!(
Parser::parse(Rule::number, "0o0_7068").unwrap().as_str(),
CozoParser::parse(Rule::number, "0o0_7068").unwrap().as_str(),
"0o0_7068"
);
assert_eq!(
Parser::parse(Rule::number, "0b0000_0000_1111")
CozoParser::parse(Rule::number, "0b0000_0000_1111")
.unwrap()
.as_str(),
"0b0000_0000_1111"
);
assert_ne!(
Parser::parse(Rule::number, "0b0000_0000_1112")
CozoParser::parse(Rule::number, "0b0000_0000_1112")
.unwrap()
.as_str(),
"0b0000_0000_1112"
);
assert_eq!(
Parser::parse(Rule::number, "123.45").unwrap().as_str(),
CozoParser::parse(Rule::number, "123.45").unwrap().as_str(),
"123.45"
);
assert_eq!(
Parser::parse(Rule::number, "1_23.4_5_").unwrap().as_str(),
CozoParser::parse(Rule::number, "1_23.4_5_").unwrap().as_str(),
"1_23.4_5_"
);
assert_ne!(
Parser::parse(Rule::number, "123.").unwrap().as_str(),
CozoParser::parse(Rule::number, "123.").unwrap().as_str(),
"123."
);
assert_eq!(
Parser::parse(Rule::number, "123.333e456").unwrap().as_str(),
CozoParser::parse(Rule::number, "123.333e456").unwrap().as_str(),
"123.333e456"
);
assert_eq!(
Parser::parse(Rule::number, "1_23.33_3e45_6")
CozoParser::parse(Rule::number, "1_23.33_3e45_6")
.unwrap()
.as_str(),
"1_23.33_3e45_6"
@ -132,6 +132,6 @@ mod tests {
#[test]
fn expressions() {
assert!(Parser::parse(Rule::expr, r"(a + b) ~ [] + c.d.e(1,2,x=3).f").is_ok());
assert!(CozoParser::parse(Rule::expr, r"(a + b) ~ [] + c.d.e(1,2,x=3).f").is_ok());
}
}

@ -1,8 +1,23 @@
use crate::error::{CozoError, Result};
use std::result;
use crate::parser::number::parse_int;
use crate::parser::Rule;
use pest::iterators::Pair;
#[derive(thiserror::Error, Debug)]
pub(crate) enum TextParseError {
#[error("Invalid UTF code {0}")]
InvalidUtfCode(u32),
#[error("Invalid escape sequence {0}")]
InvalidEscapeSequence(String),
#[error("Reserved identifier: {0}")]
ReservedIdent(String),
}
type Result<T> = result::Result<T, TextParseError>;
#[inline]
fn parse_raw_string(pair: Pair<Rule>) -> Result<String> {
Ok(pair
@ -31,10 +46,10 @@ fn parse_quoted_string(pair: Pair<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).ok_or(CozoError::InvalidUtfCode)?;
let ch = char::from_u32(code).ok_or_else(|| TextParseError::InvalidUtfCode(code))?;
ret.push(ch);
}
s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence),
s if s.starts_with('\\') => return Err(TextParseError::InvalidEscapeSequence(s.to_string())),
s => ret.push_str(s),
}
}
@ -58,10 +73,10 @@ fn parse_s_quoted_string(pair: Pair<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).ok_or(CozoError::InvalidUtfCode)?;
let ch = char::from_u32(code).ok_or_else(|| TextParseError::InvalidUtfCode(code))?;
ret.push(ch);
}
s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence),
s if s.starts_with('\\') => return Err(TextParseError::InvalidEscapeSequence(s.to_string())),
s => ret.push_str(s),
}
}
@ -69,7 +84,7 @@ fn parse_s_quoted_string(pair: Pair<Rule>) -> Result<String> {
}
#[inline]
pub fn parse_string(pair: Pair<Rule>) -> Result<String> {
pub(crate) fn parse_string(pair: Pair<Rule>) -> Result<String> {
match pair.as_rule() {
Rule::quoted_string => Ok(parse_quoted_string(pair)?),
Rule::s_quoted_string => Ok(parse_s_quoted_string(pair)?),
@ -79,11 +94,11 @@ pub fn parse_string(pair: Pair<Rule>) -> Result<String> {
}
}
pub fn parse_ident(pair: Pair<Rule>) -> String {
pub(crate) fn parse_ident(pair: Pair<Rule>) -> String {
pair.as_str().to_string()
}
pub fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Result<String> {
pub(crate) fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Result<String> {
let inner = pair.into_inner().next().unwrap();
let name = match inner.as_rule() {
Rule::ident => parse_ident(inner),
@ -91,13 +106,13 @@ pub fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Result<St
_ => unreachable!(),
};
if forbid_underscore && name.starts_with('_') {
Err(CozoError::ReservedIdent)
Err(TextParseError::ReservedIdent(name))
} else {
Ok(name)
}
}
pub fn parse_col_name(pair: Pair<Rule>) -> Result<(String, bool)> {
pub(crate) fn parse_col_name(pair: Pair<Rule>) -> Result<(String, bool)> {
let mut pairs = pair.into_inner();
let mut is_key = false;
let mut nxt_pair = pairs.next().unwrap();

Loading…
Cancel
Save