elm/compiler/Types/Alias.hs

139 lines
4.8 KiB
Haskell
Raw Normal View History

2013-04-05 16:55:30 +00:00
module Types.Alias (dealias, get, mistakes) where
import Ast
import Control.Arrow (second)
import Data.List (group,sort)
import qualified Data.Map as Map
import qualified Data.Set as Set
import Types.Substitutions (subst)
import Types.Types
builtins :: [(String,([X],Type))]
2013-05-05 01:58:10 +00:00
builtins =
let touch = ("t0", time) : map (flip (,) int) ["x","y","x0","y0","id"]
state = [("string", string), ("selectionStart", int), ("selectionEnd", int)]
line = [("color", tipe "Color"), ("width", float),
("cap", tipe "LineCap"), ("join", tipe "LineJoin"),
("miterLimit", float), ("dashing", listOf int),
("dashOffset", int)]
makeRecord fields =
RecordT (Map.fromList $ map (second (:[])) fields) EmptyRecord
in [ ("String", ([], listOf char)),
("Time", ([], float)),
("KeyCode", ([], int)),
("Touch", ([], makeRecord touch)),
2013-05-06 09:30:11 +00:00
("FieldState", ([], makeRecord state)),
("LineStyle", ([], makeRecord line))
2013-05-05 01:58:10 +00:00
]
2013-04-05 16:55:30 +00:00
get :: [Statement] -> Map.Map String ([X],Type)
get stmts = Map.fromList (builtins ++ concatMap getAlias stmts)
where getAlias stmt = case stmt of
TypeAlias alias xs t -> [(alias, (xs,t))]
_ -> []
2013-04-05 16:55:30 +00:00
dealias :: Map.Map String ([X],Type) -> Type -> Type
dealias aliases t =
let f = dealias aliases in
case t of
ADT name ts -> case Map.lookup name aliases of
Just (xs,t) -> f (subst (zip xs ts) t)
Nothing -> ADT name (map f ts)
LambdaT t u -> LambdaT (f t) (f u)
RecordT r t -> RecordT (Map.map (map f) r) (f t)
_ -> t
mistakes :: [Statement] -> [String]
mistakes stmts = badKinds stmts ++ dups stmts ++ badOrder stmts
badKinds :: [Statement] -> [String]
badKinds stmts = map msg (concatMap badS stmts)
where
msg x = "Type Error: Type alias '" ++ x ++
"' was given the wrong number of arguments."
badT :: Type -> [String]
badT t =
case t of
ADT name ts ->
2013-04-05 16:55:30 +00:00
case Map.lookup name (get stmts) of
Just (xs,t) | length xs == length ts -> []
| otherwise -> [name]
Nothing -> concatMap badT ts
LambdaT t u -> badT t ++ badT u
RecordT r t -> badT t ++ concatMap badT (concat (Map.elems r))
_ -> []
badS :: Statement -> [String]
badS s =
case s of
Datatype _ _ tcs -> concatMap badT (concatMap snd tcs)
ExportEvent _ _ tipe -> badT tipe
ImportEvent _ _ _ tipe -> badT tipe
TypeAnnotation _ tipe -> badT tipe
TypeAlias _ _ tipe -> badT tipe
Definition _ -> []
annotation :: Statement -> [String]
annotation s =
case s of
TypeAnnotation name _ -> [name]
_ -> []
definition :: Statement -> [String]
definition s =
case s of
Definition d -> [defName d]
_ -> []
defName :: Def -> String
defName d =
case d of
FnDef n _ _ -> n
OpDef n _ _ _ -> n
dups :: [Statement] -> [String]
dups stmts = map defMsg (dup definition) ++ map annMsg (dup annotation)
where
dup :: (Statement -> [String]) -> [String]
dup f = map head . filter ((>1) . length) . group . sort $ concatMap f stmts
msg = "Syntax Error: There can only be one "
defMsg x = msg ++ "top-level definition of '" ++ x ++ "'."
annMsg x = msg ++ "type annotation for '" ++ x ++ "'."
badOrder :: [Statement] -> [String]
badOrder stmts = map msg $ missings (sort $ expectedPairs as ds) (sort $ actualPairs stmts)
where
msg x = "Syntax Error: The type annotation for '" ++ x ++
"' must be directly above its definition."
as = sort $ concatMap annotation stmts
ds = sort $ concatMap definition stmts
expectedPairs :: [String] -> [String] -> [String]
expectedPairs as ds =
case (as,ds) of
(x:xs, y:ys) -> case compare x y of
LT -> expectedPairs xs (y:ys)
EQ -> x : expectedPairs xs ys
GT -> expectedPairs (x:xs) ys
( _ , _ ) -> []
actualPairs :: [Statement] -> [String]
actualPairs stmts =
case stmts of
TypeAnnotation n _ : Definition d : rest ->
(if n == defName d then [n] else []) ++ actualPairs rest
t:s:rest -> actualPairs (s:rest)
_ -> []
missings :: [String] -> [String] -> [String]
missings expected actual =
case (expected, actual) of
(e:es, a:as) -> case compare e a of
LT -> e : missings es (a:as)
EQ -> missings es as
GT -> a : missings (e:es) as
( [] , _ ) -> actual
( _ , [] ) -> expected