pub mod ast;
pub mod compiler;
pub mod error;
pub mod lexer;
pub mod parser;
use ast::DocumentItem;
use error::ParseError;
use fabula::pattern::Pattern;
use fabula_memory::{MemGraph, MemValue};
use std::collections::HashMap;
use std::fmt::Debug;
pub use compiler::{compile_pattern_body, compile_pattern_body_with, MemMapper, TypeMapper};
pub struct ParsedDocument<L = String, V = MemValue> {
pub patterns: Vec<Pattern<L, V>>,
pub graphs: Vec<MemGraph>,
}
impl<L: Debug, V: Debug> std::fmt::Debug for ParsedDocument<L, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ParsedDocument")
.field("patterns", &self.patterns.len())
.field("graphs", &self.graphs.len())
.finish()
}
}
pub fn parse_pattern(input: &str) -> Result<Pattern<String, MemValue>, ParseError> {
parse_pattern_with(input, &MemMapper)
}
pub fn parse_pattern_with<M: TypeMapper>(
input: &str,
mapper: &M,
) -> Result<Pattern<M::L, M::V>, ParseError> {
let tokens = lexer::Lexer::new(input).tokenize()?;
let ast = parser::Parser::new(tokens).parse_pattern_only()?;
compiler::compile_pattern_with(&ast, mapper)
}
pub fn parse_graph(input: &str) -> Result<MemGraph, ParseError> {
let tokens = lexer::Lexer::new(input).tokenize()?;
let ast = parser::Parser::new(tokens).parse_graph_only()?;
Ok(compiler::compile_graph(&ast))
}
pub fn parse_document(input: &str) -> Result<ParsedDocument, ParseError> {
parse_document_with(input, &MemMapper)
}
pub fn parse_document_with<M: TypeMapper>(
input: &str,
mapper: &M,
) -> Result<ParsedDocument<M::L, M::V>, ParseError> {
let tokens = lexer::Lexer::new(input).tokenize()?;
let doc = parser::Parser::new(tokens).parse_document()?;
let mut patterns = Vec::new();
let mut graphs = Vec::new();
let mut named: HashMap<String, Pattern<M::L, M::V>> = HashMap::new();
for item in &doc.items {
match item {
DocumentItem::Pattern(ast) => {
let pat = compiler::compile_pattern_with(ast, mapper)?;
named.insert(ast.name.clone(), pat.clone());
patterns.push(pat);
}
DocumentItem::Graph(ast) => {
graphs.push(compiler::compile_graph(ast));
}
DocumentItem::Compose(ast) => {
let composed = compiler::compile_compose_with(ast, &named, mapper)?;
for p in &composed {
named.insert(p.name.clone(), p.clone());
}
if composed.len() > 1 && !named.contains_key(&ast.name) {
named.insert(ast.name.clone(), composed[0].clone());
}
patterns.extend(composed);
}
}
}
Ok(ParsedDocument { patterns, graphs })
}