aboutsummaryrefslogblamecommitdiff
path: root/Sil/Check.icl
blob: b3ad1afddfd1d53ba70ab9662434f744d175e5db (plain) (tree)
1
2
3
4
5
6
7
8
9
                               
              
              
                           
              
               
                    
               
 
                 
                                     
                

                   
                
                 
                
                      
 
                                                           
                     

                            
                      
              
                                                                     
                                               
                                                                               
                                         
                        
                                                
                              
                                                                          
                                                   
                                                   
                                                                            
 
                                          
                        
                                                       
                                   
                                                    
 
                                                             


                                 
                      
     
                                                 
                                                                                                                          
                                                                                                   


                                                       
                                               




                                                                                                
 
                                                       
                    
                                                                                           
                               
 
                                          
                                                                      
             
                                                           
                                         
                                                                                                            
                                                                                       
                                                               
                                                         
                                                                  
                     

                                                        
                                                                    
                                                          
 
                                                    
                                                                  
                                         
                                                                              
                                                                  
 
                                                             
                                       
                                               
                    

                                                   
implementation module Sil.Check

import StdBool
import StdFile
from StdFunc import flip, o
import StdList
import StdMaybe
import StdOverloaded
import StdString
import StdTuple

import Data.Error
from Data.Func import $, mapSt, seqSt
import Data.List
import Data.Tuple
from Text import <+

import Sil.Error
import Sil.Syntax
import Sil.Types
import Sil.Util.Parser

checkProgram :: *(? *File) Program -> *([Error], * ? *File)
checkProgram err prog
	= checkErrors
	[ checkFunctionNames
	, checkMainFunction
	, checkGlobals
	] prog
	$ appFst flatten $ mapSt (flip checkFunction) prog.p_funs err
where
	checkMainFunction :: Program -> [Error]
	checkMainFunction p = case [f \\ f <- p.p_funs | f.f_name == "main"] of
		[] -> [Ck_NoMainFunction]
		_  -> []

	checkFunctionNames :: Program -> [Error]
	checkFunctionNames p =
		[ Ck_DuplicateFunctionName (errpos $ hd fs) (hd fs).f_name
		\\ fs <- tails [f \\ f <- p.p_funs]
		| let names = [f.f_name \\ f <- fs]
		  in  not (isEmpty names) && isMember (hd names) (tl names)]

	checkGlobals :: Program -> [Error]
	checkGlobals p =
		[ Ck_BasicGlobal (errpos g) g.init_name
		\\ g <- p.p_globals
		| (typeSize g.init_type).bsize <> 0]

checkFunction :: *(? *File) Function -> *([Error], * ? *File)
checkFunction err f = checkErrors
	[ checkLocals
	, checkReturnAndVoid
	, checkMainFunctionType
	] f
	$ noErrors err
where
	checkReturnAndVoid :: Function -> [Error]
	checkReturnAndVoid f = case f.f_type of
		TVoid -> [Ck_ReturnExpressionFromVoid (errpos st) f.f_name \\ st=:(Return _ (?Just _)) <- allStatements f]
		_     -> if (sureToReturn f.f_code) [] [Ck_NoReturnFromNonVoid (errpos f) f.f_name]
	where
		sureToReturn :: CodeBlock -> Bool
		sureToReturn cb = case cb.cb_content of
			[]  -> False
			sts -> case last sts of
				Return _ _        -> True
				While _ _ cb`     -> sureToReturn cb`
				If _ bs (?Just e) -> all sureToReturn [e:map snd bs]
				If _ bs ?None     -> all (sureToReturn o snd) bs
				MachineStm _ _    -> True // Let's assume the user is not stupid
				_                 -> False

	checkMainFunctionType :: Function -> [Error]
	checkMainFunctionType {f_name="main",f_args=[]}
		= []
	checkMainFunctionType f=:{f_name="main"}
		= [Ck_MainFunctionInvalidType (errpos f) $ fromOk $ fromJust $ type zero f]
	checkMainFunctionType _
		= []

	checkLocals :: Function -> [Error]
	checkLocals f =
		checkDupName [a.arg_name \\ a <- f.f_args] f.f_code ++
		concatMap checkVoid (allLocals f)
	where
		checkDupName :: [Name] CodeBlock -> [Error]
		checkDupName defined cb =
			[Ck_DuplicateLocalName (errpos f) f.f_name l \\ l <- defined | isMember l locals] ++
			concatMap (checkDupName (locals ++ defined)) (underlyingCBs cb)
		where locals = [i.init_name \\ i <- cb.cb_init]

		underlyingCBs :: CodeBlock -> [CodeBlock]
		underlyingCBs cb = concatMap findCBs cb.cb_content
		where
			findCBs (Declaration _ _ _) = []
			findCBs (Application _ _)   = []
			findCBs (Return _ _)        = []
			findCBs (If _ bs (?Just e)) = [e:map snd bs]
			findCBs (If _ bs ?None)     = map snd bs
			findCBs (While _ _ cb)      = [cb]
			findCBs (MachineStm _ _)    = []

		checkVoid :: (Type, Name) -> [Error]
		checkVoid (TVoid, n) = [Ck_LocalVoid (errpos f) n]
		checkVoid _          = []

checkErrors :: [(a -> [Error])] a *([Error], ? *File) -> *([Error], * ? *File)
checkErrors cks x st = seqSt error (concatMap (flip ($) x) cks) st

error :: Error *([Error], * ? *File) -> *([Error], * ? *File)
error e (es, err) = ([e:es], err <?< e)

noErrors :: *(? *File) -> *([Error], * ? *File)
noErrors f = ([], f)

(<?<) infixl :: !*(? *File) !a -> * ? *File | <<< a
(<?<) (?Just f) x = ?Just (f <<< x)
(<?<) ?None     _ = ?None