use middle::typing::ast::*;
use middle::typing::ast::IType::*;
use middle::typing::type_rewriting::*;
use middle::typing::typing_printer::*;
pub struct Surface
{
pub grammar: IGrammar,
pub error: bool,
recursion_path: Vec<Ident>
}
impl Surface
{
pub fn new(grammar: IGrammar) -> Surface {
Surface {
grammar: grammar,
error: false,
recursion_path: vec![]
}
}
pub fn surface(&mut self) {
for rule in self.grammar.rules.clone() {
self.visit_rule(&rule.ident());
}
if self.grammar.attributes.print_typing.debug() {
println!("After applying Surface\n.");
print_debug(&self.grammar);
println!("");
}
}
fn visit_rule(&mut self, rule_name: &Ident) -> IType {
let expr_idx = self.grammar.expr_index_of_rule(rule_name);
let rule_ty = self.grammar.type_of(expr_idx);
if rule_ty == Infer {
if self.is_rec(rule_name) {
self.infer_rec_type(rule_name)
}
else {
self.recursion_path.push(rule_name.clone());
let ty = self.visit_expr(expr_idx);
self.recursion_path.pop();
let reduced_ty = TypeRewriting::reduce_rec_entry_point(&self.grammar, rule_name, ty);
self.type_expr(expr_idx, reduced_ty)
}
}
else {
rule_ty
}
}
fn is_rec(&self, rule: &Ident) -> bool {
self.recursion_path.iter().any(|r| r == rule)
}
pub fn type_of(&self, expr_idx: usize) -> IType {
self.grammar[expr_idx].ty()
}
pub fn type_expr(&mut self, expr_idx: usize, ty: IType) -> IType {
self.grammar[expr_idx].ty = ty.clone();
ty
}
fn infer_rec_type(&mut self, entry_rule: &Ident) -> IType {
let rec_path = self.recursion_path.clone();
let mut rec_shorter_path = vec![entry_rule.clone()];
rec_shorter_path.extend(
rec_path.into_iter()
.rev()
.take_while(|r| r != entry_rule));
IType::rec(RecKind::Unit, rec_shorter_path)
}
fn type_mismatch_branches(&mut self, rec_set: RecSet, sum_expr: usize, branches: Vec<usize>, tys: Vec<IType>) {
self.error = true;
let mut diagnostic = self.grammar[sum_expr].span().unstable().error(
format!("Type mismatch between branches of the choice operator."));
for i in 0..branches.len() {
diagnostic = diagnostic.span_note(self.grammar[branches[i]].span().unstable(),
format!("branch {} of type `{}`", i+1, tys[i].display(&self.grammar)));
}
if !rec_set.is_empty() {
let entry_point = self.grammar.find_rule_by_ident(&rec_set.entry_point());
diagnostic = diagnostic.span_note(entry_point.span().unstable(),
format!("Types annotated with `*` have been reduced to (^) because they are involved \
in one of the following rule cycle (generating recursive types):\n{}",
rec_set.display()));
}
diagnostic.emit();
}
}
impl ExprByIndex for Surface
{
fn expr_by_index(&self, index: usize) -> Expression {
self.grammar.expr_by_index(index)
}
}
impl Visitor<IType> for Surface
{
fn visit_expr(&mut self, this: usize) -> IType {
let mut this_ty = self.type_of(this);
if this_ty == Infer {
this_ty = walk_expr(self, this);
let reduced_ty = TypeRewriting::reduce(&self.grammar, this_ty);
self.type_expr(this, reduced_ty)
}
else {
this_ty
}
}
fn visit_str_literal(&mut self, _this: usize, _lit: String) -> IType {
IType::Invisible
}
fn visit_syntactic_predicate(&mut self, _this: usize, _child: usize) -> IType {
IType::Invisible
}
fn visit_type_ascription(&mut self, _this: usize, _child: usize, ty: IType) -> IType {
ty
}
fn visit_atom(&mut self, _this: usize) -> IType {
IType::Regular(Type::Atom)
}
fn visit_semantic_action(&mut self, this: usize, _child: usize, boxed: bool, action: syn::Expr) -> IType {
self.grammar.resolve_action_type(self.grammar[this].span(), boxed, action)
}
fn visit_non_terminal_symbol(&mut self, _this: usize, rule: &Ident) -> IType {
self.visit_rule(rule)
}
fn visit_external_non_terminal_symbol(&mut self, _this: usize, _rule: &syn::Path) -> IType {
IType::External
}
fn visit_repeat(&mut self, _this: usize, child: usize) -> IType {
self.visit_expr(child);
IType::Regular(Type::List(child))
}
fn visit_optional(&mut self, _this: usize, child: usize) -> IType {
self.visit_expr(child);
IType::Regular(Type::Optional(child))
}
fn visit_spanned_expr(&mut self, _this: usize, child: usize) -> IType {
self.visit_expr(child);
IType::Regular(Type::Tuple(vec![self.grammar.span_ty_idx(), child]))
}
fn visit_range_expr(&mut self, _this: usize, child: usize) -> IType {
self.visit_expr(child);
IType::Regular(Type::Rust(self.grammar.range_type()))
}
fn visit_sequence(&mut self, _this: usize, children: Vec<usize>) -> IType {
walk_exprs(self, children.clone());
IType::Regular(Type::Tuple(children))
}
fn visit_choice(&mut self, this: usize, children: Vec<usize>) -> IType {
let tys = walk_exprs(self, children.clone());
match TypeRewriting::reduce_sum(&self.grammar, tys.clone()) {
Ok(principal_type) => principal_type,
Err(rec_set) => {
self.type_mismatch_branches(rec_set, this, children, tys);
IType::Invisible
}
}
}
}