summaryrefslogtreecommitdiff
path: root/src/chomp/check/check.rs
blob: 87295656837ea362901e6265efe5a6ff1634730b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use super::{
    super::{
        ast::{Alt, Call, Cat, Epsilon, Fix, Literal, Parameter, Variable},
        context::Context,
        error::TypeError,
        typed::{self, TypedExpression},
        visit::{Folder, Visitable, Visitor},
    },
    TypeInfer,
};

#[derive(Debug)]
pub struct TypeCheck<'a> {
    pub context: &'a mut Context,
}

impl Folder for TypeCheck<'_> {
    type Out = Result<TypedExpression, TypeError>;

    fn fold_epsilon(&mut self, eps: Epsilon) -> Self::Out {
        Ok(typed::Epsilon::from(eps).into())
    }

    fn fold_literal(&mut self, lit: Literal) -> Self::Out {
        Ok(typed::Literal::from(lit).into())
    }

    fn fold_cat(&mut self, cat: Cat) -> Self::Out {
        let ty = TypeInfer {
            context: self.context,
        }
        .visit_cat(&cat)?;
        let fst = cat.fst.fold(self)?;
        let snd = cat.snd;
        let snd = self
            .context
            .with_unguard(|context| snd.fold(&mut TypeCheck { context }))?;

        Ok(typed::Cat::new(fst, cat.punct, snd, ty).into())
    }

    fn fold_alt(&mut self, alt: Alt) -> Self::Out {
        let ty = TypeInfer {
            context: self.context,
        }
        .visit_alt(&alt)?;
        let left = alt.left.fold(self)?;
        let right = alt.right.fold(self)?;

        Ok(typed::Alt::new(left, alt.punct, right, ty).into())
    }

    fn fold_fix(&mut self, fix: Fix) -> Self::Out {
        let ty = TypeInfer {
            context: self.context,
        }
        .visit_fix(&fix)?;
        let inner = fix.inner;
        let inner = self
            .context
            .with_variable_type(ty.clone(), |context| inner.fold(&mut TypeCheck { context }))?;

        Ok(typed::Fix::new(fix.arg, inner, fix.span, ty).into())
    }

    fn fold_variable(&mut self, var: Variable) -> Self::Out {
        let ty = TypeInfer {
            context: self.context,
        }
        .visit_variable(&var)?;
        Ok(typed::Variable::new(var, ty).into())
    }

    fn fold_parameter(&mut self, _param: Parameter) -> Self::Out {
        todo!()
    }

    fn fold_call(&mut self, _call: Call) -> Self::Out {
        todo!()
    }
}