diff options
author | Camil Staps | 2017-07-19 21:59:47 +0000 |
---|---|---|
committer | Camil Staps | 2017-07-19 21:59:47 +0000 |
commit | f76f972a9d4b0db0b021225e70638f5cb7af0a8e (patch) | |
tree | 101a54ad70931ed824c88e2e64d81e7bd3dbae22 | |
parent | Fix testing code (diff) |
Add checks: no main, duplicate function, duplicate local
-rw-r--r-- | Sil/Check.dcl | 5 | ||||
-rw-r--r-- | Sil/Check.icl | 79 | ||||
-rw-r--r-- | examples/errors.sil | 18 |
3 files changed, 82 insertions, 20 deletions
diff --git a/Sil/Check.dcl b/Sil/Check.dcl index b222079..1d5929d 100644 --- a/Sil/Check.dcl +++ b/Sil/Check.dcl @@ -7,7 +7,10 @@ from Data.Maybe import :: Maybe from Sil.Syntax import :: Program, :: Name :: CheckError - = ReturnExpressionFromVoidError Name + = NoMainFunction + | DuplicateFunctionName Name + | DuplicateLocalName Name Name + | ReturnExpressionFromVoidError Name | NoReturnFromNonVoidError Name instance toString CheckError 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 <?< e) diff --git a/examples/errors.sil b/examples/errors.sil new file mode 100644 index 0000000..4507097 --- /dev/null +++ b/examples/errors.sil @@ -0,0 +1,18 @@ +Int noReturnFromNonVoid() { + Int a; + a := 5; +} + +Void returnFromVoid() { + return 5; +} + +Void duplicateFunction() { +} + +Void duplicateFunction() { +} + +Void duplicateLocals(Int a) { + Int a; +} |