module Transform.Canonicalize.Variable where
import Control.Monad.Error
import qualified Data.List as List
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import AST.Helpers as Help
import qualified AST.Type as Type
import qualified AST.Variable as Var
import Transform.Canonicalize.Environment as Env
variable :: Environment -> String -> Canonicalizer String Var.Canonical
variable env var =
case modul of
Just ms@(m:_)
| m == "Native" -> Env.using (Var.Canonical home name)
where
home = Var.Module (List.intercalate "." ms)
_ ->
case Map.lookup var (_values env) of
Just [v] -> Env.using v
Just vs -> preferLocals env "variable" vs var
Nothing -> notFound "variable" (Map.keys (_values env)) var
where
(modul, name) =
case Help.splitDots var of
[x] -> (Nothing, x)
xs -> (Just (init xs), last xs)
tvar :: Environment -> String
-> Canonicalizer String (Either Var.Canonical (Var.Canonical, [String], Type.CanonicalType))
tvar env var =
case adts ++ aliases of
[] -> notFound "type" (Map.keys (_adts env) ++ Map.keys (_aliases env)) var
[v] -> found extract v
vs -> preferLocals' env extract "type" vs var
where
adts = map Left . fromMaybe [] $ Map.lookup var (_adts env)
aliases = map Right . fromMaybe [] $ Map.lookup var (_aliases env)
extract value =
case value of
Left v -> v
Right (v,_,_) -> v
pvar :: Environment -> String -> Canonicalizer String Var.Canonical
pvar env var =
case Map.lookup var (_patterns env) of
Just [v] -> Env.using v
Just vs -> preferLocals env "pattern" vs var
Nothing -> notFound "pattern" (Map.keys (_patterns env)) var
found :: (a -> Var.Canonical) -> a -> Canonicalizer String a
found extract v = do
_ <- Env.using (extract v)
return v
notFound :: String -> [String] -> String -> Canonicalizer String a
notFound kind possibilities var =
throwError $ "Could not find " ++ kind ++ " '" ++ var ++ "'." ++ msg
where
matches = filter (List.isInfixOf var) possibilities
msg = if null matches then "" else
"\nClose matches include: " ++ List.intercalate ", " matches
preferLocals :: Environment -> String -> [Var.Canonical] -> String
-> Canonicalizer String Var.Canonical
preferLocals env = preferLocals' env id
preferLocals' :: Environment -> (a -> Var.Canonical) -> String -> [a] -> String
-> Canonicalizer String a
preferLocals' env extract kind possibilities var =
case filter (isLocal . extract) possibilities of
[] -> ambiguous possibilities
[v] -> found extract v
locals -> ambiguous locals
where
isLocal :: Var.Canonical -> Bool
isLocal (Var.Canonical home _) =
case home of
Var.Local -> True
Var.BuiltIn -> False
Var.Module name -> name == Env._home env
ambiguous possibleVars =
throwError msg
where
vars = map (Var.toString . extract) possibleVars
msg = "Ambiguous usage of " ++ kind ++ " '" ++ var ++ "'.\n" ++
" Disambiguate between: " ++ List.intercalate ", " vars