
There's obviously some overlap with the Rain typechecker here. I've tried to cover everything in the AST that could potentially be bound into occam at some point in the future, even if the occam parser doesn't support it yet (so this'll do checks for Concat and mobile allocation, for example).
164 lines
6.0 KiB
Haskell
164 lines
6.0 KiB
Haskell
{-
|
|
Tock: a compiler for parallel languages
|
|
Copyright (C) 2008 University of Kent
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
-}
|
|
|
|
-- | The occam-specific frontend passes.
|
|
module OccamPasses (occamPasses, foldConstants, checkConstants,
|
|
checkRetypes) where
|
|
|
|
import Control.Monad.State
|
|
import Data.Generics
|
|
|
|
import qualified AST as A
|
|
import CompState
|
|
import Errors
|
|
import EvalConstants
|
|
import EvalLiterals
|
|
import Metadata
|
|
import OccamTypes
|
|
import Pass
|
|
import qualified Properties as Prop
|
|
import ShowCode
|
|
import Types
|
|
|
|
-- | Occam-specific frontend passes.
|
|
occamPasses :: [Pass]
|
|
occamPasses = makePassesDep' ((== FrontendOccam) . csFrontend)
|
|
[ ("Fold constants", foldConstants,
|
|
[],
|
|
[Prop.constantsFolded])
|
|
, ("Fix the types of array constructors", fixConstructorTypes,
|
|
[Prop.constantsFolded],
|
|
[Prop.arrayConstructorTypesDone])
|
|
, ("Check mandatory constants", checkConstants,
|
|
[Prop.constantsFolded, Prop.arrayConstructorTypesDone],
|
|
[Prop.constantsChecked])
|
|
, ("Check types", checkTypes,
|
|
[],
|
|
[Prop.expressionTypesChecked, Prop.processTypesChecked])
|
|
, ("Check retyping", checkRetypes,
|
|
[],
|
|
[Prop.retypesChecked])
|
|
, ("Dummy occam pass", dummyOccamPass,
|
|
[],
|
|
Prop.agg_namesDone ++ [Prop.expressionTypesChecked,
|
|
Prop.inferredTypesRecorded, Prop.mainTagged,
|
|
Prop.processTypesChecked])
|
|
]
|
|
|
|
-- | Fixed the types of array constructors according to the replicator count
|
|
fixConstructorTypes :: Data t => t -> PassM t
|
|
fixConstructorTypes = applyDepthM doExpression
|
|
where
|
|
doExpression :: A.Expression -> PassM A.Expression
|
|
doExpression (A.ExprConstr m (A.RepConstr m' _ rep expr))
|
|
= do t <- typeOfExpression expr
|
|
let count = countReplicator rep
|
|
t' = A.Array [A.Dimension count] t
|
|
return $ A.ExprConstr m $ A.RepConstr m' t' rep expr
|
|
doExpression e = return e
|
|
|
|
-- | Fold constant expressions.
|
|
foldConstants :: Data t => t -> PassM t
|
|
foldConstants = applyDepthM2 doExpression doSpecification
|
|
where
|
|
-- Try to fold all expressions we encounter. Since we've recursed into the
|
|
-- expression first, this'll also fold subexpressions of non-constant
|
|
-- expressions.
|
|
doExpression :: A.Expression -> PassM A.Expression
|
|
doExpression e
|
|
= do (e', _, _) <- constantFold e
|
|
return e'
|
|
|
|
-- When an expression is abbreviated, update its definition so that it can
|
|
-- be used when folding later expressions.
|
|
doSpecification :: A.Specification -> PassM A.Specification
|
|
doSpecification s@(A.Specification _ n st@(A.IsExpr _ _ _ _))
|
|
= do modifyName n (\nd -> nd { A.ndType = st })
|
|
return s
|
|
doSpecification s = return s
|
|
|
|
|
|
-- | Check that things that must be constant are.
|
|
checkConstants :: Data t => t -> PassM t
|
|
checkConstants = applyDepthM2 doDimension doOption
|
|
where
|
|
-- Check array dimensions are constant.
|
|
doDimension :: A.Dimension -> PassM A.Dimension
|
|
doDimension d@(A.Dimension e)
|
|
= do when (not $ isConstant e) $
|
|
diePC (findMeta e) $ formatCode "Array dimension must be constant: %" e
|
|
return d
|
|
doDimension d = return d
|
|
|
|
-- Check case options are constant.
|
|
doOption :: A.Option -> PassM A.Option
|
|
doOption o@(A.Option _ es _)
|
|
= do sequence_ [when (not $ isConstant e) $
|
|
diePC (findMeta e) $ formatCode "Case option must be constant: %" e
|
|
| e <- es]
|
|
return o
|
|
doOption o = return o
|
|
|
|
-- | Check that retyping is safe.
|
|
checkRetypes :: Data t => t -> PassM t
|
|
checkRetypes = applyDepthM doSpecType
|
|
where
|
|
doSpecType :: A.SpecType -> PassM A.SpecType
|
|
doSpecType st@(A.Retypes m _ t v)
|
|
= do fromT <- typeOfVariable v
|
|
checkRetypes m fromT t
|
|
return st
|
|
doSpecType st@(A.RetypesExpr m _ t e)
|
|
= do fromT <- typeOfExpression e
|
|
checkRetypes m fromT t
|
|
return st
|
|
doSpecType st = return st
|
|
|
|
checkRetypes :: Meta -> A.Type -> A.Type -> PassM ()
|
|
checkRetypes m fromT toT
|
|
= do (fromBI, fromN) <- evalBytesInType fromT
|
|
(toBI, toN) <- evalBytesInType toT
|
|
case (fromBI, toBI, fromN, toN) of
|
|
(_, BIManyFree, _, _) ->
|
|
dieP m "Multiple free dimensions in retype destination type"
|
|
(BIJust _, BIJust _, Just a, Just b) ->
|
|
when (a /= b) $
|
|
dieP m "Sizes do not match in retype"
|
|
(BIJust _, BIOneFree _ _, Just a, Just b) ->
|
|
when (not ((b <= a) && (a `mod` b == 0))) $
|
|
dieP m "Sizes do not match in retype"
|
|
(BIOneFree _ _, BIJust _, Just a, Just b) ->
|
|
when (not ((a <= b) && (b `mod` a == 0))) $
|
|
dieP m "Sizes do not match in retype"
|
|
-- Otherwise we must do a runtime check.
|
|
_ -> return ()
|
|
|
|
evalBytesInType :: A.Type -> PassM (BytesInResult, Maybe Int)
|
|
evalBytesInType t
|
|
= do bi <- bytesInType t
|
|
n <- case bi of
|
|
BIJust e -> maybeEvalIntExpression e
|
|
BIOneFree e _ -> maybeEvalIntExpression e
|
|
_ -> return Nothing
|
|
return (bi, n)
|
|
|
|
-- | A dummy pass for things that haven't been separated out into passes yet.
|
|
dummyOccamPass :: Data t => t -> PassM t
|
|
dummyOccamPass = return
|
|
|