defining nodes and edges
parent
4fb53e7037
commit
28e52242e0
@ -0,0 +1,241 @@
|
||||
use pest::Parser as PestParser;
|
||||
use pest::iterators::{Pair, Pairs};
|
||||
use crate::ast::parse_string;
|
||||
use crate::env::Env;
|
||||
use crate::error::CozoError;
|
||||
use crate::error::CozoError::*;
|
||||
use crate::parser::{Parser, Rule};
|
||||
use crate::typing::{BaseType, Col, Edge, Node, Structured, StructuredEnv, StructuredEnvItem, TableId, Typing};
|
||||
use crate::typing::Persistence::{Global, Local};
|
||||
use crate::typing::StorageStatus::Planned;
|
||||
use crate::value::Value;
|
||||
|
||||
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 | Rule::s_quoted_string | Rule::quoted_string => parse_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))
|
||||
}
|
||||
|
||||
|
||||
impl StructuredEnvItem {
|
||||
pub fn build_edge_def(&mut self, pair: Pair<Rule>, table_id: TableId) -> Result<(), CozoError> {
|
||||
let mut inner = pair.into_inner();
|
||||
let src_name = build_name_in_def(inner.next().unwrap(), true)?;
|
||||
let src = self.resolve(&src_name).ok_or(UndefinedType)?;
|
||||
let src_id = if let Structured::Node(n, _) = src {
|
||||
n.id
|
||||
} else {
|
||||
return Err(WrongType);
|
||||
};
|
||||
let name = build_name_in_def(inner.next().unwrap(), true)?;
|
||||
let dst_name = build_name_in_def(inner.next().unwrap(), true)?;
|
||||
let dst = self.resolve(&dst_name).ok_or(UndefinedType)?;
|
||||
let dst_id = if let Structured::Node(n, _) = dst {
|
||||
n.id
|
||||
} else {
|
||||
return Err(WrongType);
|
||||
};
|
||||
if table_id.0 == Global && (src_id.0 == Local || dst_id.0 == Local) {
|
||||
return Err(IncompatibleEdge);
|
||||
}
|
||||
let (keys, cols) = if let Some(p) = inner.next() {
|
||||
self.build_col_defs(p)?
|
||||
} else {
|
||||
(vec![], vec![])
|
||||
};
|
||||
let edge = Edge {
|
||||
src: src_id,
|
||||
dst: dst_id,
|
||||
id: table_id,
|
||||
keys,
|
||||
cols,
|
||||
};
|
||||
if self.define_new(name.to_string(), Structured::Edge(edge, Planned)) {
|
||||
if let Some(Structured::Node(src, _)) = self.resolve_mut(&src_name) {
|
||||
src.out_e.push(table_id);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
if let Some(Structured::Node(dst, _)) = self.resolve_mut(&dst_name) {
|
||||
dst.in_e.push(table_id);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(NameConflict)
|
||||
}
|
||||
}
|
||||
pub fn build_node_def(&mut self, pair: Pair<Rule>, table_id: TableId) -> Result<(), CozoError> {
|
||||
let mut inner = pair.into_inner();
|
||||
let name = build_name_in_def(inner.next().unwrap(), true)?;
|
||||
let (keys, cols) = self.build_col_defs(inner.next().unwrap())?;
|
||||
let node = Node {
|
||||
id: table_id,
|
||||
keys,
|
||||
cols,
|
||||
out_e: vec![],
|
||||
in_e: vec![],
|
||||
attached: vec![],
|
||||
};
|
||||
if self.define_new(name.to_string(), Structured::Node(node, Planned)) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(NameConflict)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_type(&self, pair: Pair<Rule>) -> Result<Typing, CozoError> {
|
||||
let mut pairs = pair.into_inner();
|
||||
let mut inner = pairs.next().unwrap();
|
||||
let nullable = if Rule::nullable_marker == inner.as_rule() {
|
||||
inner = pairs.next().unwrap();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let t = match inner.as_rule() {
|
||||
Rule::simple_type => {
|
||||
let name = parse_ident(inner.into_inner().next().unwrap());
|
||||
if let Some(Structured::Typing(t)) = self.resolve(&name) {
|
||||
t.clone()
|
||||
} else {
|
||||
return Err(UndefinedType);
|
||||
}
|
||||
}
|
||||
Rule::list_type => {
|
||||
let inner_t = self.build_type(inner.into_inner().next().unwrap())?;
|
||||
Typing::HList(Box::new(inner_t))
|
||||
}
|
||||
// Rule::tuple_type => {},
|
||||
_ => unreachable!()
|
||||
};
|
||||
Ok(if nullable {
|
||||
Typing::Nullable(Box::new(t))
|
||||
} else {
|
||||
t
|
||||
})
|
||||
}
|
||||
|
||||
fn build_default_value(&self, _pair: Pair<Rule>) -> Result<Value<'static>, CozoError> {
|
||||
// TODO: _pair is an expression, parse it and evaluate it to a constant value
|
||||
Ok(Value::Null)
|
||||
}
|
||||
|
||||
fn build_col_entry(&self, pair: Pair<Rule>) -> Result<(Col, bool), CozoError> {
|
||||
let mut pairs = pair.into_inner();
|
||||
let (name, is_key) = parse_col_name(pairs.next().unwrap())?;
|
||||
let typ = self.build_type(pairs.next().unwrap())?;
|
||||
let default = if let Some(p) = pairs.next() {
|
||||
// TODO: check value is suitable for the type
|
||||
Some(self.build_default_value(p)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok((Col {
|
||||
name,
|
||||
typ,
|
||||
default,
|
||||
}, is_key))
|
||||
}
|
||||
|
||||
fn build_col_defs(&self, 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) = self.build_col_entry(pair)?;
|
||||
if is_key {
|
||||
keys.push(col)
|
||||
} else {
|
||||
cols.push(col)
|
||||
}
|
||||
}
|
||||
|
||||
Ok((keys, cols))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructuredEnv {
|
||||
pub fn build_table(&mut self, pairs: Pairs<Rule>) -> Result<(), CozoError> {
|
||||
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;
|
||||
let next_id = self.get_next_table_id(is_local);
|
||||
let env_to_build = if is_local {
|
||||
self.root_mut()
|
||||
} else {
|
||||
self.cur_mut()
|
||||
};
|
||||
|
||||
// println!("{:?} {:?}", r, inner.as_rule());
|
||||
match inner.as_rule() {
|
||||
Rule::node_def => {
|
||||
env_to_build.build_node_def(inner, next_id)?;
|
||||
}
|
||||
Rule::edge_def => {
|
||||
env_to_build.build_edge_def(inner, next_id)?;
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
Rule::EOI => {}
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn definitions() {
|
||||
let s = r#"
|
||||
local node "Person" {
|
||||
*id: Int,
|
||||
name: String,
|
||||
email: ?String,
|
||||
habits: ?[?String]
|
||||
}
|
||||
|
||||
local edge (Person)-[Friend]->(Person) {
|
||||
relation: ?String
|
||||
}
|
||||
"#;
|
||||
let parsed = Parser::parse(Rule::file, s).unwrap();
|
||||
let mut env = StructuredEnv::new();
|
||||
env.build_table(parsed).unwrap();
|
||||
println!("{:#?}", env.resolve("Person"));
|
||||
println!("{:#?}", env.resolve("Friend"));
|
||||
}
|
||||
}
|
@ -1,5 +1,15 @@
|
||||
pub trait Env<V> {
|
||||
fn define(&mut self, name: &str, value: V) -> Option<V>;
|
||||
fn resolve(&self, name: &str) -> Option<V>;
|
||||
fn define(&mut self, name: String, value: V) -> Option<V>;
|
||||
fn define_new(&mut self, name: String, value: V) -> bool;
|
||||
fn resolve(&self, name: &str) -> Option<&V>;
|
||||
fn resolve_mut(&mut self, name: &str) -> Option<&mut V>;
|
||||
fn undef(&mut self, name: &str) -> Option<V>;
|
||||
}
|
||||
|
||||
pub trait LayeredEnv<V> : Env<V> {
|
||||
fn root_define(&mut self, name: String, value: V) -> Option<V>;
|
||||
fn root_define_new(&mut self, name: String, value: V) -> bool;
|
||||
fn root_resolve(&self, name: &str) -> Option<&V>;
|
||||
fn root_resolve_mut(&mut self, name: &str) -> Option<&mut V>;
|
||||
fn root_undef(&mut self, name: &str) -> Option<V>;
|
||||
}
|
Loading…
Reference in New Issue