use middle::typing::ast::*;
use middle::analysis::ast::AGrammar;
pub use front::ast::FGrammar;
use partial::*;
pub mod analysis;
pub mod typing;
pub fn typecheck(fgrammar: FGrammar) -> TGrammar {
Partial::Value(fgrammar)
.and_then(|grammar| at_least_one_rule_declared(grammar))
.and_then(|grammar| analysis::analyse(grammar))
.ensure("aborting due to previous error (analysis phase).")
.and_then(|grammar| extract_stream_type(grammar))
.and_then(|grammar| typing::type_inference(grammar))
.expect("aborting due to previous error (typing phase).")
}
fn at_least_one_rule_declared(fgrammar: FGrammar) -> Partial<FGrammar> {
if fgrammar.rules.len() == 0 {
fgrammar.start_span.unstable()
.error("At least one rule must be declared.")
.emit();
Partial::Nothing
} else {
Partial::Value(fgrammar)
}
}
fn extract_stream_type(mut grammar: AGrammar)
-> Partial<AGrammar>
{
let mut stream_redefined = false;
{
let stream_alias =
grammar.rust_items.iter().find_map(|item| {
match item {
&syn::Item::Type(ref ty) => {
if ty.ident.to_string() == "Stream" {
Some(ty.clone())
}
else { None }
}
_ => None
}
});
if let Some(ty) = stream_alias {
grammar.stream_alias = ty;
stream_redefined = true;
}
}
if !stream_redefined {
grammar.rust_items.push(syn::Item::Type(grammar.stream_alias.clone()));
}
Partial::Value(grammar)
}