From f76f972a9d4b0db0b021225e70638f5cb7af0a8e Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Wed, 19 Jul 2017 21:59:47 +0000 Subject: Add checks: no main, duplicate function, duplicate local --- Sil/Check.icl | 79 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 19 deletions(-) (limited to 'Sil/Check.icl') diff --git a/Sil/Check.icl b/Sil/Check.icl index c4ab5f0..fc80324 100644 --- a/Sil/Check.icl +++ b/Sil/Check.icl @@ -1,5 +1,6 @@ implementation module Sil.Check +import StdBool import StdFile from StdFunc import flip, o import StdList @@ -8,6 +9,7 @@ import StdString import StdTuple from Data.Func import $, mapSt, seqSt +import Data.List import Data.Maybe import Data.Tuple from Text import <+ @@ -16,6 +18,12 @@ import Sil.Syntax instance toString CheckError where + toString NoMainFunction + = "Error: no main function." + toString (DuplicateFunctionName n) + = "Error: multiply defined: '" <+ n <+ "'." + toString (DuplicateLocalName f arg) + = "Error: multiply defined: '" <+ arg <+ "' in '" <+ f <+ "'." toString (ReturnExpressionFromVoidError f) = "Type error: an expression was returned from void function '" <+ f <+ "'." toString (NoReturnFromNonVoidError f) @@ -24,30 +32,63 @@ where instance <<< CheckError where <<< f e = f <<< toString e <<< "\r\n" checkProgram :: *(Maybe *File) Program -> *([CheckError], *Maybe *File) -checkProgram err prog = appFst flatten $ mapSt (flip checkFunction) prog.p_funs err +checkProgram err prog + = checkErrors [checkFunctionNames, checkMainFunction] prog + $ appFst flatten $ mapSt (flip checkFunction) prog.p_funs err +where + checkMainFunction :: Program -> [CheckError] + checkMainFunction p = case [f \\ f <- p.p_funs | f.f_name == "main"] of + [] -> [NoMainFunction] + _ -> [] + + checkFunctionNames :: Program -> [CheckError] + checkFunctionNames p = + [ DuplicateFunctionName $ hd fs + \\ fs <- tails [f.f_name \\ f <- p.p_funs] + | not (isEmpty fs) && isMember (hd fs) (tl fs)] checkFunction :: *(Maybe *File) Function -> *([CheckError], *Maybe *File) -checkFunction err f = checkErrors [checkReturnAndVoid] f err +checkFunction err f = checkErrors [checkLocals, checkReturnAndVoid] f $ noErrors err where - checkReturnAndVoid :: Function -> Maybe CheckError + checkReturnAndVoid :: Function -> [CheckError] checkReturnAndVoid f = case f.f_type of TVoid -> case [st \\ st=:(Return (Just _)) <- allStatements f] of - [] -> Nothing - _ -> Just $ ReturnExpressionFromVoidError f.f_name - _ -> if (sureToReturn f.f_code) Nothing (Just $ NoReturnFromNonVoidError f.f_name) - - 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 Nothing -> all (sureToReturn o snd) bs - _ -> False - -checkErrors :: [(a -> Maybe CheckError)] a *(Maybe *File) -> *([CheckError], *Maybe *File) -checkErrors cks x err = seqSt error (catMaybes $ map (flip ($) x) cks) $ noErrors err + [] -> [] + _ -> [ReturnExpressionFromVoidError f.f_name] + _ -> if (sureToReturn f.f_code) [] [NoReturnFromNonVoidError 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 Nothing -> all (sureToReturn o snd) bs + _ -> False + + checkLocals :: Function -> [CheckError] + checkLocals f = check [a.arg_name \\ a <- f.f_args] f.f_code + where + check :: [Name] CodeBlock -> [CheckError] + check defined cb = + [DuplicateLocalName f.f_name l \\ l <- defined | isMember l locals] ++ + concatMap (check (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 Nothing) = map snd bs + findCBs (While _ cb) = [cb] + findCBs (MachineStm _) = [] + +checkErrors :: [(a -> [CheckError])] a *([CheckError], Maybe *File) -> *([CheckError], *Maybe *File) +checkErrors cks x st = seqSt error (concatMap (flip ($) x) cks) st error :: CheckError *([CheckError], *Maybe *File) -> *([CheckError], *Maybe *File) error e (es, err) = ([e:es], err