@@ -21,7 +21,7 @@ import Prelude hiding (lookup, EQ, LT, GT)
2121import Data.Map (insert )
2222import qualified Data.Map as M
2323import Data.Maybe (maybeToList )
24- import Data.List (find )
24+ import Data.List (find , foldl' )
2525import Control.Monad.State.Strict
2626import Data.Generics.Uniplate.Data
2727import Data.Data
@@ -41,13 +41,18 @@ type TypeEnv = M.Map Name IDType
4141-- | Information about a detected type error.
4242type TypeError = (String , SrcSpan )
4343
44+ -- | Mapping of structures to field types
45+ type StructTypeEnv = M. Map Name StructMemberTypeEnv
46+ type StructMemberTypeEnv = M. Map Name IDType
47+
4448--------------------------------------------------
4549
4650-- Monad for type inference work
4751type Infer a = State InferState a
4852data InferState = InferState { langVersion :: FortranVersion
4953 , intrinsics :: IntrinsicsTable
5054 , environ :: TypeEnv
55+ , structs :: StructTypeEnv
5156 , entryPoints :: M. Map Name (Name , Maybe Name )
5257 , typeErrors :: [TypeError ] }
5358 deriving Show
@@ -167,41 +172,68 @@ dimDeclarator ddAList = [ (lb, ub) | DimensionDeclarator _ _ lbExp ubExp <- aStr
167172 , let ub = do ExpValue _ _ (ValInteger i) <- ubExp
168173 return $ read i ]
169174
170- statement :: Data a => InferFunc (Statement (Analysis a ))
171-
172- statement (StDeclaration _ stmtSs ts@ (TypeSpec _ _ _ _) mAttrAList declAList)
175+ -- | Auxiliary function for getting semantic and construct type of a declaration.
176+ -- Used in standard declarations and structures
177+ handleDeclaration :: Data a => TypeEnv -> SrcSpan -> TypeSpec (Analysis a )
178+ -> Maybe (AList Attribute (Analysis a ))
179+ -> AList Declarator (Analysis a )
180+ -> Infer [(Name , SemType , ConstructType )]
181+ handleDeclaration env stmtSs ts mAttrAList declAList
173182 | mAttrs <- maybe [] aStrip mAttrAList
174183 , attrDim <- find isAttrDimension mAttrs
175184 , isParam <- any isAttrParameter mAttrs
176185 , isExtrn <- any isAttrExternal mAttrs
177- , decls <- aStrip declAList = do
178- env <- gets environ
186+ , decls <- aStrip declAList =
179187 let cType n | isExtrn = CTExternal
180188 | Just (AttrDimension _ _ ddAList) <- attrDim = CTArray (dimDeclarator ddAList)
181189 | isParam = CTParameter
182190 | Just (IDType _ (Just ct)) <- M. lookup n env
183191 , ct /= CTIntrinsic = ct
184192 | otherwise = CTVariable
185- forM_ decls $ \ decl -> case decl of
186- DeclArray _ declSs v ddAList mLenExpr _ -> do
187- let ct = CTArray $ dimDeclarator ddAList
193+ handler rs = \ case
194+ DeclArray _ declSs v ddAList mLenExpr _ -> do
188195 st <- deriveSemTypeFromDeclaration stmtSs declSs ts mLenExpr
189- recordType st ct (varName v)
190- DeclVariable _ declSs v mLenExpr _ -> do
196+ pure $ (varName v, st, CTArray $ dimDeclarator ddAList) : rs
197+ DeclVariable _ declSs v mLenExpr _ -> do
191198 st <- deriveSemTypeFromDeclaration stmtSs declSs ts mLenExpr
192- recordType st (cType n) n where n = varName v
199+ let n = varName v
200+ pure $ (n, st, cType n) : rs
201+ in foldM handler [] decls
202+
203+ handleStructureItem :: Data a => StructMemberTypeEnv -> StructureItem (Analysis a ) -> Infer StructMemberTypeEnv
204+ handleStructureItem mt (StructFields _ src ts mAttrAList declAList) = do
205+ env <- gets environ
206+ ds <- handleDeclaration env src ts mAttrAList declAList
207+ pure $ foldl' (\ m (n, s, c) -> M. insert n (IDType (Just s) (Just c)) m) mt ds
208+ -- TODO: These should eventually be implemented
209+ handleStructureItem mt StructUnion {} = pure mt
210+ handleStructureItem mt StructStructure {} = pure mt
211+
212+ -- | Create a structure env from the list of fields and add it to the InferState
213+ handleStructure :: Data a => Maybe String -> AList StructureItem (Analysis a ) -> Infer ()
214+ handleStructure mName itemAList = do
215+ case mName of
216+ Just n -> do
217+ structEnv <- foldM handleStructureItem M. empty (aStrip itemAList)
218+ recordStruct structEnv n
219+ Nothing -> pure ()
220+
221+ statement :: Data a => InferFunc (Statement (Analysis a ))
193222
223+ statement (StDeclaration _ stmtSs ts mAttrAList declAList) = do
224+ env <- gets environ
225+ decls <- handleDeclaration env stmtSs ts mAttrAList declAList
226+ forM_ decls $ \ (n, b, c) -> recordType b c n
194227statement (StExternal _ _ varAList) = do
195228 let vars = aStrip varAList
196229 mapM_ (recordCType CTExternal . varName) vars
197230statement (StExpressionAssign _ _ (ExpSubscript _ _ v ixAList) _)
198231 -- | any (not . isIxSingle) (aStrip ixAList) = recordCType CTArray (varName v) -- it's an array (or a string?) FIXME
199232 | all isIxSingle (aStrip ixAList) = do
200- let n = varName v
201- mIDType <- getRecordedType n
233+ mIDType <- getExprRecordedType v
202234 case mIDType of
203235 Just (IDType _ (Just CTArray {})) -> return () -- do nothing, it's already known to be an array
204- _ -> recordCType CTFunction n -- assume it's a function statement
236+ _ -> recordCType CTFunction (varName v) -- assume it's a function statement
205237
206238-- FIXME: if StFunctions can only be identified after types analysis
207239-- is complete and disambiguation is performed, then how do we get
@@ -216,6 +248,8 @@ statement (StDimension _ _ declAList) = do
216248 DeclArray _ _ v ddAList _ _ -> recordCType (CTArray $ dimDeclarator ddAList) (varName v)
217249 _ -> return ()
218250
251+ statement (StStructure _ _ mName itemAList) = handleStructure mName itemAList
252+
219253statement _ = return ()
220254
221255annotateExpression :: Data a => Expression (Analysis a ) -> Infer (Expression (Analysis a ))
@@ -417,7 +451,7 @@ isNumericType = \case
417451-- Monadic helper combinators.
418452
419453inferState0 :: FortranVersion -> InferState
420- inferState0 v = InferState { environ = M. empty, entryPoints = M. empty, langVersion = v
454+ inferState0 v = InferState { environ = M. empty, structs = M. empty, entryPoints = M. empty, langVersion = v
421455 , intrinsics = getVersionIntrinsics v, typeErrors = [] }
422456runInfer :: FortranVersion -> TypeEnv -> State InferState a -> (a , InferState )
423457runInfer v env = flip runState ((inferState0 v) { environ = env })
@@ -432,6 +466,9 @@ emptyType = IDType Nothing Nothing
432466recordType :: SemType -> ConstructType -> Name -> Infer ()
433467recordType st ct n = modify $ \ s -> s { environ = insert n (IDType (Just st) (Just ct)) (environ s) }
434468
469+ recordStruct :: StructMemberTypeEnv -> Name -> Infer ()
470+ recordStruct mt n = modify $ \ s -> s { structs = insert n mt (structs s) }
471+
435472-- Record the type (maybe) of the given name.
436473recordMType :: Maybe SemType -> Maybe ConstructType -> Name -> Infer ()
437474recordMType st ct n = modify $ \ s -> s { environ = insert n (IDType st ct) (environ s) }
@@ -452,6 +489,24 @@ recordEntryPoint fn en mRetName = modify $ \ s -> s { entryPoints = M.insert en
452489getRecordedType :: Name -> Infer (Maybe IDType )
453490getRecordedType n = gets (M. lookup n . environ)
454491
492+ getExprRecordedType :: Data a => Expression (Analysis a ) -> Infer (Maybe IDType )
493+ getExprRecordedType e@ (ExpValue _ _ (ValVariable _)) = getRecordedType $ varName e
494+ getExprRecordedType (ExpSubscript _ _ base _) = do
495+ mTy <- getExprRecordedType base
496+ case mTy of
497+ Just (IDType semTy (Just CTArray {})) -> pure . Just $ IDType semTy (Just CTVariable )
498+ _ -> pure Nothing
499+ getExprRecordedType (ExpDataRef _ _ base ref) = do
500+ mTy <- getExprRecordedType base
501+ case mTy of
502+ Just (IDType (Just (TCustom n)) _) -> do
503+ mStructEnv <- gets (M. lookup n . structs)
504+ case mStructEnv of
505+ Nothing -> pure Nothing
506+ Just env -> pure $ M. lookup (varName ref) env
507+ x -> pure x
508+ getExprRecordedType _ = pure Nothing
509+
455510-- Set the idType annotation
456511setIDType :: Annotated f => IDType -> f (Analysis a ) -> f (Analysis a )
457512setIDType ty x
0 commit comments