|
|
@ -8,7 +8,8 @@ use crate::ast::eval_op::*;
|
|
|
|
use crate::ast::Expr::{Apply, Const};
|
|
|
|
use crate::ast::Expr::{Apply, Const};
|
|
|
|
use crate::ast::op::Op;
|
|
|
|
use crate::ast::op::Op;
|
|
|
|
use crate::error::CozoError;
|
|
|
|
use crate::error::CozoError;
|
|
|
|
use crate::typing::Typing;
|
|
|
|
use crate::error::CozoError::ReservedIdent;
|
|
|
|
|
|
|
|
use crate::typing::{PrimitiveType, Typing};
|
|
|
|
use crate::value::Value;
|
|
|
|
use crate::value::Value;
|
|
|
|
|
|
|
|
|
|
|
|
mod eval_op;
|
|
|
|
mod eval_op;
|
|
|
@ -33,19 +34,23 @@ lazy_static! {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct Col {
|
|
|
|
pub struct Col {
|
|
|
|
pub name: String,
|
|
|
|
pub name: String,
|
|
|
|
pub typ: Typing,
|
|
|
|
pub typ: Typing,
|
|
|
|
pub default: Option<Value<'static>>,
|
|
|
|
pub default: Option<Value<'static>>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum TableDef {
|
|
|
|
pub enum TableDef {
|
|
|
|
Node {
|
|
|
|
Node {
|
|
|
|
|
|
|
|
is_local: bool,
|
|
|
|
name: String,
|
|
|
|
name: String,
|
|
|
|
keys: Vec<Col>,
|
|
|
|
keys: Vec<Col>,
|
|
|
|
cols: Vec<Col>,
|
|
|
|
cols: Vec<Col>,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Edge {
|
|
|
|
Edge {
|
|
|
|
|
|
|
|
is_local: bool,
|
|
|
|
src: String,
|
|
|
|
src: String,
|
|
|
|
dst: String,
|
|
|
|
dst: String,
|
|
|
|
name: String,
|
|
|
|
name: String,
|
|
|
@ -53,10 +58,17 @@ pub enum TableDef {
|
|
|
|
cols: Vec<Col>,
|
|
|
|
cols: Vec<Col>,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Columns {
|
|
|
|
Columns {
|
|
|
|
|
|
|
|
is_local: bool,
|
|
|
|
attached: String,
|
|
|
|
attached: String,
|
|
|
|
name: String,
|
|
|
|
name: String,
|
|
|
|
cols: Vec<Col>,
|
|
|
|
cols: Vec<Col>,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
Index {
|
|
|
|
|
|
|
|
is_local: bool,
|
|
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
|
|
attached: String,
|
|
|
|
|
|
|
|
cols: Vec<String>,
|
|
|
|
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -128,12 +140,13 @@ fn parse_int(s: &str, radix: u32) -> i64 {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
fn parse_raw_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
|
|
|
|
fn parse_raw_string(pair: Pair<Rule>) -> Result<String, CozoError> {
|
|
|
|
Ok(pairs.into_iter().next().unwrap().as_str().to_string())
|
|
|
|
Ok(pair.into_inner().into_iter().next().unwrap().as_str().to_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
fn parse_quoted_string(pairs: Pairs<Rule>) -> Result<String, CozoError> {
|
|
|
|
fn parse_quoted_string(pair: Pair<Rule>) -> Result<String, CozoError> {
|
|
|
|
|
|
|
|
let pairs = pair.into_inner().next().unwrap().into_inner();
|
|
|
|
let mut ret = String::with_capacity(pairs.as_str().len());
|
|
|
|
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();
|
|
|
@ -160,7 +173,8 @@ 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(pair: Pair<Rule>) -> Result<String, CozoError> {
|
|
|
|
|
|
|
|
let pairs = pair.into_inner().next().unwrap().into_inner();
|
|
|
|
let mut ret = String::with_capacity(pairs.as_str().len());
|
|
|
|
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();
|
|
|
@ -209,9 +223,9 @@ fn build_expr_primary(pair: Pair<Rule>) -> Result<Expr, CozoError> {
|
|
|
|
Rule::dot_float | Rule::sci_float => Ok(Const(Value::Float(pair.as_str().replace('_', "").parse::<f64>()?))),
|
|
|
|
Rule::dot_float | Rule::sci_float => Ok(Const(Value::Float(pair.as_str().replace('_', "").parse::<f64>()?))),
|
|
|
|
Rule::null => Ok(Const(Value::Null)),
|
|
|
|
Rule::null => Ok(Const(Value::Null)),
|
|
|
|
Rule::boolean => Ok(Const(Value::Bool(pair.as_str() == "true"))),
|
|
|
|
Rule::boolean => Ok(Const(Value::Bool(pair.as_str() == "true"))),
|
|
|
|
Rule::quoted_string => Ok(Const(Value::OwnString(Box::new(parse_quoted_string(pair.into_inner().next().unwrap().into_inner())?)))),
|
|
|
|
Rule::quoted_string => Ok(Const(Value::OwnString(Box::new(parse_quoted_string(pair)?)))),
|
|
|
|
Rule::s_quoted_string => Ok(Const(Value::OwnString(Box::new(parse_s_quoted_string(pair.into_inner().next().unwrap().into_inner())?)))),
|
|
|
|
Rule::s_quoted_string => Ok(Const(Value::OwnString(Box::new(parse_s_quoted_string(pair)?)))),
|
|
|
|
Rule::raw_string => Ok(Const(Value::OwnString(Box::new(parse_raw_string(pair.into_inner())?)))),
|
|
|
|
Rule::raw_string => Ok(Const(Value::OwnString(Box::new(parse_raw_string(pair)?)))),
|
|
|
|
_ => {
|
|
|
|
_ => {
|
|
|
|
println!("{:#?}", pair);
|
|
|
|
println!("{:#?}", pair);
|
|
|
|
unimplemented!()
|
|
|
|
unimplemented!()
|
|
|
@ -228,6 +242,102 @@ pub fn parse_expr_from_str(inp: &str) -> Result<Expr, CozoError> {
|
|
|
|
build_expr(expr_tree)
|
|
|
|
build_expr(expr_tree)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_ident(pair: Pair<Rule>) -> String {
|
|
|
|
|
|
|
|
pair.as_str().to_string()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn build_name_in_def(pair: Pair<Rule>, forbid_underscore: bool) -> Result<String, CozoError> {
|
|
|
|
|
|
|
|
let inner = pair.into_inner().next().unwrap();
|
|
|
|
|
|
|
|
let name = match inner.as_rule() {
|
|
|
|
|
|
|
|
Rule::ident => parse_ident(inner),
|
|
|
|
|
|
|
|
Rule::raw_string => parse_raw_string(inner)?,
|
|
|
|
|
|
|
|
Rule::s_quoted_string => parse_s_quoted_string(inner)?,
|
|
|
|
|
|
|
|
Rule::quoted_string => parse_quoted_string(inner)?,
|
|
|
|
|
|
|
|
_ => unreachable!()
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
if forbid_underscore && name.starts_with('_') {
|
|
|
|
|
|
|
|
Err(ReservedIdent)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Ok(name)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_col_name(pair: Pair<Rule>) -> Result<(String, bool), CozoError> {
|
|
|
|
|
|
|
|
let mut pairs = pair.into_inner();
|
|
|
|
|
|
|
|
let mut is_key = false;
|
|
|
|
|
|
|
|
let mut nxt_pair = pairs.next().unwrap();
|
|
|
|
|
|
|
|
if nxt_pair.as_rule() == Rule::key_marker {
|
|
|
|
|
|
|
|
is_key = true;
|
|
|
|
|
|
|
|
nxt_pair = pairs.next().unwrap();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok((build_name_in_def(nxt_pair, true)?, is_key))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn build_col_entry(pair: Pair<Rule>) -> Result<(Col, bool), CozoError> {
|
|
|
|
|
|
|
|
let mut pairs = pair.into_inner();
|
|
|
|
|
|
|
|
let (name, is_key) = parse_col_name(pairs.next().unwrap())?;
|
|
|
|
|
|
|
|
Ok((Col {
|
|
|
|
|
|
|
|
name,
|
|
|
|
|
|
|
|
typ: Typing::Primitive(PrimitiveType::Int),
|
|
|
|
|
|
|
|
default: None
|
|
|
|
|
|
|
|
}, is_key))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn build_col_defs(pair: Pair<Rule>) -> Result<(Vec<Col>, Vec<Col>), CozoError> {
|
|
|
|
|
|
|
|
let mut keys = vec![];
|
|
|
|
|
|
|
|
let mut cols = vec![];
|
|
|
|
|
|
|
|
for pair in pair.into_inner() {
|
|
|
|
|
|
|
|
let (col, is_key) = build_col_entry(pair)?;
|
|
|
|
|
|
|
|
if is_key {
|
|
|
|
|
|
|
|
keys.push(col)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
cols.push(col)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok((keys, cols))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn build_node_def(pair: Pair<Rule>, is_local: bool) -> Result<TableDef, CozoError> {
|
|
|
|
|
|
|
|
let mut inner = pair.into_inner();
|
|
|
|
|
|
|
|
let name = build_name_in_def(inner.next().unwrap(), true)?;
|
|
|
|
|
|
|
|
let (keys, cols) = build_col_defs(inner.next().unwrap())?;
|
|
|
|
|
|
|
|
Ok(TableDef::Node {
|
|
|
|
|
|
|
|
is_local,
|
|
|
|
|
|
|
|
name,
|
|
|
|
|
|
|
|
keys,
|
|
|
|
|
|
|
|
cols,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn build_statements(pairs: Pairs<Rule>) -> Result<Vec<TableDef>, CozoError> {
|
|
|
|
|
|
|
|
let mut ret = vec![];
|
|
|
|
|
|
|
|
for pair in pairs {
|
|
|
|
|
|
|
|
match pair.as_rule() {
|
|
|
|
|
|
|
|
r @ (Rule::global_def | Rule::local_def) => {
|
|
|
|
|
|
|
|
let inner = pair.into_inner().next().unwrap();
|
|
|
|
|
|
|
|
let is_local = r == Rule::local_def;
|
|
|
|
|
|
|
|
// println!("{:?} {:?}", r, inner.as_rule());
|
|
|
|
|
|
|
|
match inner.as_rule() {
|
|
|
|
|
|
|
|
Rule::node_def => {
|
|
|
|
|
|
|
|
ret.push(build_node_def(inner, is_local)?);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => todo!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Rule::EOI => {}
|
|
|
|
|
|
|
|
_ => unreachable!()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(ret)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn build_statements_from_str(inp: &str) -> Result<Vec<TableDef>, CozoError> {
|
|
|
|
|
|
|
|
let expr_tree = Parser::parse(Rule::file, inp)?;
|
|
|
|
|
|
|
|
build_statements(expr_tree)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use super::*;
|
|
|
@ -269,4 +379,16 @@ mod tests {
|
|
|
|
println!("{:#?}", parse_expr_from_str("null || true").unwrap().eval().unwrap());
|
|
|
|
println!("{:#?}", parse_expr_from_str("null || true").unwrap().eval().unwrap());
|
|
|
|
println!("{:#?}", parse_expr_from_str("true && null").unwrap().eval().unwrap());
|
|
|
|
println!("{:#?}", parse_expr_from_str("true && null").unwrap().eval().unwrap());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn definitions() {
|
|
|
|
|
|
|
|
println!("{:#?}", build_statements_from_str(r#"
|
|
|
|
|
|
|
|
local node "Person" {
|
|
|
|
|
|
|
|
*id: Int,
|
|
|
|
|
|
|
|
name: String,
|
|
|
|
|
|
|
|
email: ?String,
|
|
|
|
|
|
|
|
habits: [String]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
"#).unwrap());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|