-//instantiate :: Scheme -> Infer Type
-//instantiate (Forall as t) = mapM (const fresh) as
-
-lookupEnv :: String -> Infer Type
-lookupEnv ident = asks ('Map'.get ident)
- >>= \m->case m of
- Nothing = liftT $ Left $ UndeclaredVariableError zero ident
- Just (Forall as t) = pure t //instantiate ???
-
-class infer a :: a -> Infer Type
-instance infer Expr where
- infer (VarExpr _ (VarDef ident fs)) = lookupEnv ident
- infer (Op2Expr _ e1 op e2) =
- infer e1 >>= \t1 ->
- infer e2 >>= \t2 ->
- fresh >>= \frsh ->
- let given = t1 ->> (t2 ->> frsh) in
- op2Type op >>= \expected ->
- unify expected given >>|
- return frsh
- infer (Op1Expr _ op e) =
- infer e >>= \t1 ->
- fresh >>= \frsh ->
- let given = t1 ->> frsh in
- op1Type op >>= \expected ->
- unify expected given >>|
- pure frsh
- infer (IntExpr _ _) = pure IntType
- infer (CharExpr _ _) = pure CharType
- infer (BoolExpr _ _) = pure BoolType
- infer (FunExpr _ f args sels) = //todo, iets met field selectors
- lookupEnv f >>= \expected ->
- fresh >>= \frsh ->
- mapM infer args >>= \argTypes ->
- let given = foldr (->>) frsh argTypes in
- unify expected given >>|
- pure frsh
- infer (EmptyListExpr _) = ListType <$> fresh
- infer (TupleExpr _ (e1, e2)) =
- infer e1 >>= \et1->infer e2 >>= \et2->pure $ TupleType (et1, et2)
-
-//:: VarDef = VarDef String [FieldSelector]
-//:: FieldSelector = FieldHd | FieldTl | FieldFst | FieldSnd
-//:: Op1 = UnNegation | UnMinus
-//:: Op2 = BiPlus | BiMinus | BiTimes | BiDivide | BiMod | BiEquals | BiLesser |
-// BiGreater | BiLesserEq | BiGreaterEq | BiUnEqual | BiAnd | BiOr | BiCons
-//:: FunDecl = FunDecl Pos String [String] (Maybe Type) [VarDecl] [Stmt]
-//:: FunCall = FunCall String [Expr]
-//:: Stmt
-// = IfStmt Expr [Stmt] [Stmt]
-// | WhileStmt Expr [Stmt]
-// | AssStmt VarDef Expr
-// | FunStmt FunCall
-// | ReturnStmt (Maybe Expr)
-//:: Pos = {line :: Int, col :: Int}
-//:: AST = AST [VarDecl] [FunDecl]
-//:: VarDecl = VarDecl Pos Type String Expr
-//:: Type
-// = TupleType (Type, Type)
-// | ListType Type
-// | IdType String
-// | IntType
-// | BoolType
-// | CharType
-// | VarType
-// | VoidType
-// | (->>) infixl 7 Type Type
+////----- Inference for Statements -----
+applySubst :: Substitution -> Typing Gamma
+applySubst s = changeGamma (subst s)
+
+instance infer Stmt where
+ infer s = case s of
+ IfStmt e th el =
+ infer e >>= \(s1, et)->
+ lift (unify et BoolType) >>= \s2 ->
+ applySubst (compose s2 s1) >>|
+ infer th >>= \(s3, tht)->
+ applySubst s3 >>|
+ infer el >>= \(s4, elt)->
+ applySubst s4 >>|
+ lift (unify tht elt) >>= \s5->
+ pure (compose s5 $ compose s4 $ compose s3 $ compose s2 s1, subst s5 tht)
+
+ WhileStmt e wh =
+ infer e >>= \(s1, et)->
+ lift (unify et BoolType) >>= \s2 ->
+ applySubst (compose s2 s1) >>|
+ infer wh >>= \(s3, wht)->
+ pure (compose s3 $ compose s2 s1, subst s3 wht)
+
+ AssStmt (VarDef k fs) e =
+ lookup k >>= \expected ->
+ infer e >>= \(s1, given)->
+ lift (unify expected given) >>= \s2->
+ let s = compose s2 s1 in
+ applySubst s >>|
+ changeGamma (extend k (Forall [] given)) >>| //todo: fieldselectors
+ pure (s, VoidType)
+
+ FunStmt f es = undef //what is this?
+
+ ReturnStmt Nothing = pure (zero, VoidType)
+ ReturnStmt (Just e) = infer e
+
+//The type of a list of statements is either an encountered
+//return, or VoidType
+instance infer [a] | infer a where
+ infer [] = pure (zero, VoidType)
+ infer [stmt:ss] =
+ infer stmt >>= \(s1, t1) ->
+ applySubst s1 >>|
+ infer ss >>= \(s2, t2) ->
+ applySubst s2 >>|
+ case t1 of
+ VoidType = pure (compose s2 s1, t2)
+ _ = case t2 of
+ VoidType = pure (compose s2 s1, t1)
+ _ = lift (unify t1 t2) >>= \s3 ->
+ pure (compose s3 $ compose s2 s1, t1)
+
+//the type class inferes the type of an AST element (VarDecl or FunDecl)
+//and adds it to the AST element
+class type a :: a -> Typing (Substitution, a)
+
+instance type VarDecl where
+ type (VarDecl p expected k e) =
+ infer e >>= \(s1, given) ->
+ applySubst s1 >>|
+ case expected of
+ Nothing = pure zero
+ Just expected_ = lift (unify expected_ given)
+ >>= \s2->
+ applySubst s2 >>|
+ let vtype = subst (compose s2 s1) given in
+ generalize vtype >>= \t ->
+ changeGamma (extend k t) >>|
+ pure (compose s2 s1, VarDecl p (Just vtype) k e)
+
+instance type FunDecl where
+ type (FunDecl p f args expected vds stmts) =
+ gamma >>= \outerScope-> //functions are infered in their own scopde
+ introduce f >>|
+ mapM introduce args >>= \argTs->
+ type vds >>= \(s1, tVds)->
+ applySubst s1 >>|
+ infer stmts >>= \(s2, result)->
+ applySubst s1 >>|
+ let argTs_ = map (subst $ compose s2 s1) argTs in
+ //abort (concat $ intersperse "\n" $ map toString argTs_) >>|
+ let given = foldr (->>) result argTs_ in
+ (case expected of
+ Nothing = pure zero
+ Just expected_ = lift (unify expected_ given))
+ >>= \s3 ->
+ let ftype = subst (compose s3 $ compose s2 s1) given in
+ generalize ftype >>= \t->
+ putGamma outerScope >>|
+ changeGamma (extend f t) >>|
+ pure (compose s3 $ compose s2 s1, FunDecl p f args (Just ftype) tVds stmts)
+
+instance type [a] | type a where
+ type [] = pure (zero, [])
+ type [v:vs] =
+ type v >>= \(s1, v_)->
+ applySubst s1 >>|
+ type vs >>= \(s2, vs_)->
+ applySubst (compose s2 s1) >>|
+ pure (compose s2 s1, [v_:vs_])
+
+introduce :: String -> Typing Type
+introduce k =
+ fresh >>= \tv ->
+ changeGamma (extend k (Forall [] tv)) >>|
+ pure tv
+
+instance toString Scheme where
+ toString (Forall x t) =
+ concat ["Forall ": intersperse "," x] +++ concat [". ", toString t];
+
+instance toString Gamma where
+ toString mp =
+ concat [concat [k, ": ", toString v, "\n"]\\(k, v)<-'Map'.toList mp]
+
+instance toString Substitution where
+ toString subs =
+ concat [concat [k, ": ", toString t, "\n"]\\(k, t)<-'Map'.toList subs]
+
+instance toString SemError where
+ toString (SanityError p e) = concat [toString p,
+ "SemError: SanityError: ", e]
+ toString (ParseError p s) = concat [toString p,
+ "ParseError: ", s]
+ toString (UnifyError p t1 t2) = concat [toString p,
+ "Can not unify types, expected|given:\n", toString t1,
+ "\n", toString t2]
+ toString (InfiniteTypeError p t) = concat [toString p,
+ "Infinite type: ", toString t]
+ toString (FieldSelectorError p t fs) = concat [toString p,
+ "Can not run fieldselector '", toString fs, "' on type: ",
+ toString t]
+ toString (OperatorError p op t) = concat [toString p,
+ "Operator error, operator '", toString op, "' can not be",
+ "used on type: ", toString t]
+ toString (UndeclaredVariableError p k) = concat [toString p,
+ "Undeclared identifier: ", k]
+ toString (ArgumentMisMatchError p str) = concat [toString p,
+ "Argument mismatch: ", str]
+ toString (Error e) = concat ["Unknown error during semantical",
+ "analysis: ", e]
+
+instance toString (Maybe a) | toString a where
+ toString Nothing = "Nothing"
+ toString (Just e) = concat ["Just ", toString e]
+
+instance MonadTrans (StateT (Gamma, [TVar])) where
+ liftT m = StateT \s-> m >>= \a-> return (a, s)
+
+Mapmap :: (a->b) ('Map'.Map k a) -> ('Map'.Map k b)
+Mapmap _ 'Map'.Tip = 'Map'.Tip
+Mapmap f ('Map'.Bin sz k v ml mr) = 'Map'.Bin sz k (f v)
+ (Mapmap f ml)
+ (Mapmap f mr)