rail-compiler-editor-0.3.0.0: src/RailCompiler/SemanticalAnalysis.hs
{- |
Module : SemanticalAnalysis.hs
Description : .
Maintainer : Christopher Pockrandt
License : MIT
There is no need for a semantical analysis at this time, therefore the function
`process` equals the identity function
-}
module SemanticalAnalysis (
process -- main function of the module "SemanticalAnalysis"
)
where
-- imports --
import InterfaceDT as IDT
import ErrorHandling as EH
import Data.List
-- functions --
process :: IDT.SynAna2SemAna -> IDT.SemAna2InterCode
process (IDT.ISS input)
| null input = error EH.strEmptyProgram
| duplicatefunctions input = error EH.strDuplicateFunctions
| nomain input = error EH.strMainMissing
| not (all validfollowers input) = error EH.strUnknownNode
| otherwise = IDT.ISI (concatMap splitlambda $ map check input)
-- splits lambdas into own functions
splitlambda :: IDT.AST -> [IDT.AST]
splitlambda func@(funcname, paths) = func : lambdafuncs 1
where
lambdafuncs offset
| offset > maximum (fst (getids func)) = []
| islambda offset = (funcname ++ "!" ++ show offset, (1, [NOP], offset):tail paths):lambdafuncs (offset + 1)
| otherwise = lambdafuncs (offset + 1)
islambda x = any (\(_, lex, _) -> Lambda x `elem` lex) paths
-- checks if there are unknown followers
validfollowers :: IDT.AST -> Bool
validfollowers ast = null subset
where
(ids, followers) = getids ast
subset = nub followers \\ ids
-- gets a tuple of (ids, followers) to check if there are unknown followers
getids :: IDT.AST -> ([Int], [Int])
getids (_, nodes) = unzip (getnodeids nodes)
where
getnodeids [] = []
getnodeids ((id, nodes, follow):xs) = (0, junctionattribute nodes):(id, follow):getnodeids xs
junctionattribute nodes = case last nodes of
(Junction attribute) -> attribute
_ -> 0
-- looking for a main function
nomain :: [IDT.AST] -> Bool
nomain input = "main" `notElem` allfunctions input
-- checking if there are two or more functions with the same name
duplicatefunctions :: [IDT.AST] -> Bool
duplicatefunctions input = length functions > length (nub functions)
where functions = allfunctions input
-- getting a list of every function
allfunctions :: [IDT.AST] -> [String]
allfunctions [] = []
allfunctions ((name, _):xs) = name:allfunctions xs
-- this will return the exact same input if it's valid and will error otherwise
check :: IDT.AST -> IDT.AST
check (name, nodes) = (name, map checknode nodes)
-- this will return the exact same input if it's valid and will error otherwise
checknode :: (Int, [Lexeme], Int) -> (Int, [Lexeme], Int)
checknode (id, lexeme, following)
| following == 0 && not (last lexeme `elem` [Finish, Boom] || isinvalidjunction (last lexeme)) = error EH.strInvalidMovement
| otherwise = (id, map checklexeme lexeme, following)
where
isinvalidjunction (Junction x) = x == 0
isinvalidjunction _ = False
-- this will return the exact same input if it's valid and will error otherwise
checklexeme :: Lexeme -> Lexeme
checklexeme (Junction 0) = error EH.strInvalidMovement
checklexeme (Push "") = error EH.strInvalidVarName
checklexeme (Pop "") = error EH.strInvalidVarName
checklexeme lexeme = lexeme