use crate::{
command::Command,
lexer::{parse_stringish, Token},
query::{Clause, Predicate, Query, Value},
};
grammar<'src>;
U32: u32 = U32Tok =>? {
<>.1.parse().map_err(|e: std::num::ParseIntError| {
lalrpop_util::ParseError::User { error: e.to_string() }
})
};
String: String = StringTok => parse_stringish(<>.1);
Var: String = {
EscapedVar => parse_stringish(<>.1),
UnescapedVar => <>.1.to_string(),
};
pub Value: Value = {
String => Value::Str(<>),
Var => Value::Var(<>),
};
Values: Vec<Value> = {
")" => Vec::new(),
"," <head: Value> <tail: Values> => {
let mut tail = tail;
tail.push(head);
tail
},
};
pub Predicate: Predicate = {
<name: Var> "(" ")" => Predicate { name, args: Vec::new() },
<name: Var> "(" <head: Value> <tail: Values> => {
let mut args = tail;
args.push(head);
args.reverse();
Predicate { name, args }
},
};
Predicates: Vec<(bool, Predicate)> = {
"." => Vec::new(),
"," <head: Predicate> <tail: Predicates> => {
let mut tail = tail;
tail.push((false, head));
tail
},
"," "!" <head: Predicate> <tail: Predicates> => {
let mut tail = tail;
tail.push((true, head));
tail
},
};
pub Clause: Clause = {
<head: Predicate> "." => Clause { head, body: Vec::new() },
<head: Predicate> ":-" <head_body: Predicate> <tail_body: Predicates> => {
let mut body = tail_body;
body.push((false, head_body));
body.reverse();
Clause { head, body }
},
<head: Predicate> ":-" "!" <head_body: Predicate> <tail_body: Predicates> => {
let mut body = tail_body;
body.push((true, head_body));
body.reverse();
Clause { head, body }
},
};
Clauses: Vec<Clause> = {
=> Vec::new(),
<init: Clauses> <tail: Clause> => {
let mut body = init;
body.push(tail);
body
},
};
pub Query: Query = {
<clauses: Clauses> "?-" <goal: Predicate> "." => Query { clauses, goal },
};
pub Command: Command = {
<Clause> => Command::Clause(<>),
".create_atom" => Command::CreateAtom,
".delete_atom" <atom: String> => Command::DeleteAtom(atom),
".create_name" <atom: String> <ns: String> <title: String> => {
Command::CreateName(atom, ns, title, false)
},
".delete_name" <ns: String> <title: String> => Command::DeleteName(ns, title),
".upsert_name" <atom: String> <ns: String> <title: String> => {
Command::CreateName(atom, ns, title, true)
},
".create_edge" <from: String> <to: String> <label: String> => {
Command::CreateEdge(from, to, label)
},
".delete_edge" <from: String> <to: String> <label: String> => {
Command::DeleteEdge(from, to, label)
},
".create_tag" <atom: String> <key: String> <value: String> => {
Command::CreateTag(atom, key, value, false)
},
".delete_tag" <atom: String> <key: String> => {
Command::DeleteTag(atom, key)
},
".upsert_tag" <atom: String> <key: String> <value: String> => {
Command::CreateTag(atom, key, value, true)
},
".create_blob" <atom: String> <kind: String> <mime: String> <hash: String> => {
Command::CreateBlob(atom, kind, mime, hash, false)
},
".delete_blob" <atom: String> <kind: String> <mime: String> => {
Command::DeleteBlob(atom, kind, mime)
},
".upsert_blob" <atom: String> <kind: String> <mime: String> <hash: String> => {
Command::CreateBlob(atom, kind, mime, hash, true)
},
"?-" <Predicate> "." => Command::Query(<>),
".help" => Command::Help,
".list" => Command::List,
".quit" => Command::Quit,
".undefine" <name: Var> "/" <argn: U32> => Command::Undefine(name, argn),
};
extern {
type Error = String;
enum (Token, &'src str) {
")" => (Token::ParenClose, _),
"(" => (Token::ParenOpen, _),
"." => (Token::Period, _),
"," => (Token::Comma, _),
"/" => (Token::Slash, _),
"?-" => (Token::Query, _),
":-" => (Token::Turnstile, _),
"!" => (Token::Not, _),
".create_atom" => (Token::DotCreateAtom, _),
".delete_atom" => (Token::DotDeleteAtom, _),
".create_name" => (Token::DotCreateName, _),
".delete_name" => (Token::DotDeleteName, _),
".upsert_name" => (Token::DotUpsertName, _),
".create_edge" => (Token::DotCreateEdge, _),
".delete_edge" => (Token::DotDeleteEdge, _),
".create_tag" => (Token::DotCreateTag, _),
".delete_tag" => (Token::DotDeleteTag, _),
".upsert_tag" => (Token::DotUpsertTag, _),
".create_blob" => (Token::DotCreateBlob, _),
".delete_blob" => (Token::DotDeleteBlob, _),
".upsert_blob" => (Token::DotUpsertBlob, _),
".help" => (Token::DotHelp, _),
".list" => (Token::DotList, _),
".quit" => (Token::DotQuit, _),
".undefine" => (Token::DotUndefine, _),
U32Tok => (Token::U32, _),
StringTok => (Token::String, _),
EscapedVar => (Token::EscapedVar, _),
UnescapedVar => (Token::Var, _),
}
}