Added haddock documentation

This commit is contained in:
macocianradu
2021-11-30 22:33:44 +01:00
parent 70baa17a4e
commit ff25395b68
18 changed files with 136 additions and 73 deletions

View File

@@ -13,43 +13,53 @@ import PrettyPrinter.Function
import Semantic.TypeChecker import Semantic.TypeChecker
import Semantic.ExpressionChecker import Semantic.ExpressionChecker
import Semantic.FunctionChecker import Semantic.FunctionChecker
import Model.Function
import Model.Type import Model.Type
import System.Environment.Blank (getArgs) import System.Environment.Blank (getArgs)
import Model.Enum import Model.Enum
import Data.Either import Data.Either
-- :set args resources/testAll.rosetta resources/Generated/testAll.hs -- :set args resources/testAll.rosetta resources/Generated/testAll.hs
-- |Reads a rosetta string from the first input argument and writes a haskell output to the file given as a second argument
main :: IO () main :: IO ()
main = do main = do
args <- getArgs args <- getArgs
rosettaString <- readFile $ head args rosettaString <- readFile $ head args
-- |Parse the string read from the input file
case parse rosettaParser "" (Text.pack rosettaString) of case parse rosettaParser "" (Text.pack rosettaString) of
Left errorBundle -> print (errorBundlePretty errorBundle) Left errorBundle -> print (errorBundlePretty errorBundle)
Right objs -> do Right objs -> do
-- |Write the haskell string into the second argument
writeFile (args !! 1) (printObjects (definedTypes, definedFunctions) objs) writeFile (args !! 1) (printObjects (definedTypes, definedFunctions) objs)
where where
-- |Adds all the function definitions from the file into the symbol table
definedFunctions = addNewFunctions (definedTypes, defaultMap) objs definedFunctions = addNewFunctions (definedTypes, defaultMap) objs
-- |Adds all the new data types into the symbol table
definedTypes = addNewTypes [] objs definedTypes = addNewTypes [] objs
-- |Reads a rosetta string from the first input argument, parses that string and then writes a haskell output to the file given as a second argument
printObjects :: ([Type], [Symbol]) -> [RosettaObject] -> String printObjects :: ([Type], [Symbol]) -> [RosettaObject] -> String
printObjects (t, s) objs printObjects (t, s) objs
| null (lefts finalString) = concat $ rights finalString | null (lefts finalString) = concat $ rights finalString
| otherwise = error $ show $ lefts finalString | otherwise = error $ show $ lefts finalString
where finalString = map (printObject (t, s)) objs where finalString = map (printObject (t, s)) objs
-- |Checks the RosettaObject for type errors and then converts it into a haskell string
printObject :: ([Type], [Symbol]) -> RosettaObject -> Either [TypeCheckError] String printObject :: ([Type], [Symbol]) -> RosettaObject -> Either [TypeCheckError] String
-- |Checks the type and attributes of a type and then converts it
printObject (definedTypes, _) (TypeObject t) printObject (definedTypes, _) (TypeObject t)
| isRight checked = Right $ printType $ fromRightUnsafe checked | isRight checked = Right $ printType $ fromRightUnsafe checked
| otherwise = Left $ fromLeftUnsafe checked | otherwise = Left $ fromLeftUnsafe checked
where checked = checkType definedTypes t where checked = checkType definedTypes t
-- |Enum is converted directly since no type checks are necessary
printObject _ (EnumObject e) = Right $ printEnum e printObject _ (EnumObject e) = Right $ printEnum e
-- |Checks the function inputs, output and assignment and converts it
printObject (definedTypes, definedFunctions) (FunctionObject fun) printObject (definedTypes, definedFunctions) (FunctionObject fun)
| isRight checked = Right $ printFunction $ fromRightUnsafe checked | isRight checked = Right $ printFunction $ fromRightUnsafe checked
| otherwise = Left $ fromLeftUnsafe checked | otherwise = Left $ fromLeftUnsafe checked
where where
checked = checkFunction (definedTypes, definedFunctions) fun checked = checkFunction (definedTypes, definedFunctions) fun
-- |Adds new defined functions into the symbol table
addNewFunctions :: ([Type], [Symbol]) -> [RosettaObject] -> [Symbol] addNewFunctions :: ([Type], [Symbol]) -> [RosettaObject] -> [Symbol]
addNewFunctions (_, s) [] = s addNewFunctions (_, s) [] = s
addNewFunctions (t, s) ((FunctionObject f):os) addNewFunctions (t, s) ((FunctionObject f):os)
@@ -58,65 +68,28 @@ addNewFunctions (t, s) ((FunctionObject f):os)
where definedFunctions = addFunction (t, addNewFunctions (t, s) os) f where definedFunctions = addFunction (t, addNewFunctions (t, s) os) f
addNewFunctions (t, s) (_:os) = addNewFunctions (t, s) os addNewFunctions (t, s) (_:os) = addNewFunctions (t, s) os
-- |Adds new defined types into the symbol table
addNewTypes :: [Type] -> [RosettaObject] -> [Type] addNewTypes :: [Type] -> [RosettaObject] -> [Type]
addNewTypes l [] = l addNewTypes l [] = l
addNewTypes defined (TypeObject o: os) = addDefinedTypes (addNewTypes defined os) [o] addNewTypes defined (TypeObject o: os) = addDefinedTypes (addNewTypes defined os) [o]
addNewTypes defined (EnumObject (MakeEnum name _ _): os) = addDefinedTypes (addNewTypes defined os) [MakeType name Nothing Nothing []] addNewTypes defined (EnumObject (MakeEnum name _ _): os) = addDefinedTypes (addNewTypes defined os) [MakeType name Nothing Nothing []]
addNewTypes defined (_ :os) = addNewTypes defined os addNewTypes defined (_ :os) = addNewTypes defined os
-- |Parses any supported Rosetta types into a list of RosettaObject
rosettaParser :: Parser [RosettaObject] rosettaParser :: Parser [RosettaObject]
rosettaParser = many (try parseEnum <|> try parseType <|> try parseFunction) <* eof rosettaParser = many (try parseEnum <|> try parseType <|> try parseFunction) <* eof
-- |Reads an enum into a RosettaObject
parseEnum :: Parser RosettaObject parseEnum :: Parser RosettaObject
parseEnum = do parseEnum = do
EnumObject <$> enumParser EnumObject <$> enumParser
-- |Parse a type into a RosettaObject
parseType :: Parser RosettaObject parseType :: Parser RosettaObject
parseType = do parseType = do
TypeObject <$> typeParser TypeObject <$> typeParser
-- |Parse a function into a RosettaObject
parseFunction :: Parser RosettaObject parseFunction :: Parser RosettaObject
parseFunction = do parseFunction = do
FunctionObject <$> functionParser FunctionObject <$> functionParser
testEnum :: IO()
testEnum = do
rosettaString <- readFile "resources/Enums/testEnum1.rosetta"
case parse enumParser "" (Text.pack rosettaString) of
Left errorBundle -> print errorBundle
Right enum ->
do
putStrLn $ printEnum enum
writeFile "resources/Generated/generatedEnum.hs" (printEnum enum)
testTypeParser :: IO()
testTypeParser = do
rosettaString <- readFile "resources/Types/testType1.rosetta"
case parse typeParser "" (Text.pack rosettaString) of
Left errorBundle -> print (errorBundlePretty errorBundle)
Right typ ->
do
putStrLn $ printType typ
print typ
writeFile "resources/Generated/generatedType.hs" (printType typ)
testTypeChecker :: IO ()
testTypeChecker = do
rosettaString <- readFile "src/TestFiles/testType.rosetta"
case parse (many typeParser) "" (Text.pack rosettaString) of
Left errorBundle -> print (errorBundlePretty errorBundle)
Right typ ->
do
print $ map (checkAttributes definedTypes . typeAttributes) typ
where definedTypes = addDefinedTypes [] typ
testFunc :: IO()
testFunc = do
rosettaString <- readFile "resources/testFunction.rosetta"
case parse functionParser "" (Text.pack rosettaString) of
Left errorBundle -> print (errorBundlePretty errorBundle)
Right fun ->
do
print $ printFunctionSignature fun
print (assignment fun)
writeFile "resources/Generated/generatedFunction.hs" (show $ printFunctionSignature fun)

View File

@@ -1,11 +1,13 @@
module Model.Enum where module Model.Enum where
-- |The representation of a Rosetta enum data type
data EnumType = MakeEnum { data EnumType = MakeEnum {
enumName :: String, enumName :: String,
enumDescription :: Maybe String, enumDescription :: Maybe String,
enumValues :: [EnumValue] enumValues :: [EnumValue]
} deriving (Show, Eq) } deriving (Show, Eq)
-- |The representation of a Rosetta enum value type
data EnumValue = MakeEnumValue { data EnumValue = MakeEnumValue {
enumValueName :: String, enumValueName :: String,
enumValueDescription :: Maybe String, enumValueDescription :: Maybe String,

View File

@@ -2,6 +2,7 @@ module Model.Function where
import Model.Type (TypeAttribute) import Model.Type (TypeAttribute)
-- |The representation of a Rosetta function type
data Function = data Function =
MakeFunction { MakeFunction {
functionName :: String, functionName :: String,
@@ -11,18 +12,8 @@ data Function =
assignment :: Expression assignment :: Expression
} }
deriving (Show) deriving (Show)
--data Condition =
-- MakeCondition {
-- conditionDescription :: Maybe String,
-- conditionStatement :: Expression
-- }
-- | MakePostCondition {
-- conditionDescription :: Maybe String,
-- conditionStatement :: Expression
-- }
-- deriving (Show)
-- |The representation of an expression
data Expression = Variable String data Expression = Variable String
| Int String | Int String
| Real String | Real String

View File

@@ -4,6 +4,7 @@ import Model.Enum
import Model.Function import Model.Function
import Model.Type import Model.Type
-- |Any supported Rosetta object
data RosettaObject = data RosettaObject =
EnumObject EnumType EnumObject EnumType
| TypeObject Type | TypeObject Type

View File

@@ -2,6 +2,7 @@ module Model.Type where
import Data.Time.LocalTime() import Data.Time.LocalTime()
-- |The representation of a Rosetta data type
data Type = MakeType { data Type = MakeType {
typeName :: String, typeName :: String,
superType :: Maybe Type, superType :: Maybe Type,
@@ -22,6 +23,8 @@ instance Eq Type where
| otherwise = False | otherwise = False
(==) _ _ = False (==) _ _ = False
-- |The representation of an attribute of a data type
data TypeAttribute = MakeTypeAttribute { data TypeAttribute = MakeTypeAttribute {
attributeName :: String, attributeName :: String,
attributeType :: Type, attributeType :: Type,
@@ -29,7 +32,12 @@ data TypeAttribute = MakeTypeAttribute {
attributeDescription :: Maybe String attributeDescription :: Maybe String
} deriving (Show) } deriving (Show)
data Cardinality = Bounds (Integer, Integer) -- |The representation of cardinality
data Cardinality =
-- |The cardinality between two bounds (ex. 2 - 5)
Bounds (Integer, Integer)
-- |The cardinality starting from one bound until infinity (ex. 5 - *)
| OneBound Integer | OneBound Integer
-- |The cardinality of no bounds (ex. * - *)
| NoBounds | NoBounds
deriving Show deriving Show

View File

@@ -7,6 +7,8 @@ import Text.Megaparsec.Char
import Text.Megaparsec import Text.Megaparsec
import Model.Enum import Model.Enum
-- |Parses a complete Rosetta enum into a EnumType
enumParser :: Parser EnumType enumParser :: Parser EnumType
enumParser = enumParser =
do do
@@ -15,6 +17,8 @@ enumParser =
values <- some enumValueParser values <- some enumValueParser
return (MakeEnum eName eDescription values) return (MakeEnum eName eDescription values)
-- |Parses a Rosetta enum value into a EnumValue
enumValueParser :: Parser EnumValue enumValueParser :: Parser EnumValue
enumValueParser = enumValueParser =
do do
@@ -23,6 +27,8 @@ enumValueParser =
vDescription <- optional descriptionParser vDescription <- optional descriptionParser
return (MakeEnumValue vName vDescription dName) return (MakeEnumValue vName vDescription dName)
-- |Parses the display name of a Rosetta enum value into a String
enumValueDisplayNameParser :: Parser String enumValueDisplayNameParser :: Parser String
enumValueDisplayNameParser = enumValueDisplayNameParser =
do do
@@ -30,6 +36,8 @@ enumValueDisplayNameParser =
_ <- char '"' _ <- char '"'
lexeme $ anySingle `manyTill` char '"' lexeme $ anySingle `manyTill` char '"'
-- |Parses the name of a Rosetta enum into a String
enumNameParser :: Parser String enumNameParser :: Parser String
enumNameParser = enumNameParser =
do do

View File

@@ -8,6 +8,8 @@ import qualified Data.Text as Text
import Text.Megaparsec import Text.Megaparsec
import Text.Megaparsec.Char import Text.Megaparsec.Char
-- |Parses a complete Rosetta expression into an Expression type
expressionParser :: Parser Expression expressionParser :: Parser Expression
expressionParser = expressionParser =
choice [ ifParser, choice [ ifParser,
@@ -18,6 +20,7 @@ expressionParser =
-- Command Structures ---------------------- -- Command Structures ----------------------
-------------------------------------------- --------------------------------------------
-- |Parses a function call in Rosetta into an Expression
functionCallParser :: Parser Expression functionCallParser :: Parser Expression
functionCallParser = functionCallParser =
do do
@@ -30,6 +33,7 @@ functionCallParser =
Nothing -> return $ Function f [] Nothing -> return $ Function f []
Just at -> return $ Function f (ats ++ [at]) Just at -> return $ Function f (ats ++ [at])
-- |Parses an if statement in Rosetta into an Expression
ifParser :: Parser Expression ifParser :: Parser Expression
ifParser = ifParser =
do do
@@ -42,6 +46,7 @@ ifParser =
Left _ -> return (IfSimple condition expr) Left _ -> return (IfSimple condition expr)
Right _ -> expressionParser >>= \expr2 -> return (IfElse condition expr expr2) Right _ -> expressionParser >>= \expr2 -> return (IfElse condition expr expr2)
-- |Parses an expression between parentheses in Rosetta into an Expression
parens :: Parser a -> Parser a parens :: Parser a -> Parser a
parens = between (char '(') (char ')') parens = between (char '(') (char ')')
@@ -49,6 +54,7 @@ parens = between (char '(') (char ')')
-- Terminals ------------------------------- -- Terminals -------------------------------
-------------------------------------------- --------------------------------------------
-- |Parses a list in Rosetta into an Expression
listParser :: Parser Expression listParser :: Parser Expression
listParser = listParser =
do do
@@ -58,6 +64,7 @@ listParser =
_ <- lexeme $ char ']' _ <- lexeme $ char ']'
return $ List (expressions ++ [lastExpr]) return $ List (expressions ++ [lastExpr])
-- |Parses a variable in Rosetta into an Expression
variableParser :: Parser Expression variableParser :: Parser Expression
variableParser = variableParser =
do do
@@ -65,18 +72,21 @@ variableParser =
inner <- many innerVariableParser inner <- many innerVariableParser
return $ Variable (var ++ concatMap ("->" ++) inner) return $ Variable (var ++ concatMap ("->" ++) inner)
-- |Parses an inner variable (a -> b) in Rosetta into an Expression
innerVariableParser :: Parser String innerVariableParser :: Parser String
innerVariableParser = innerVariableParser =
do do
_ <- lexeme $ string "->" _ <- lexeme $ string "->"
camelNameParser camelNameParser
-- |Parses an integer in Rosetta into an Expression
integerParser :: Parser Expression integerParser :: Parser Expression
integerParser = integerParser =
do do
nr <- lexeme $ some digitChar nr <- lexeme $ some digitChar
return $ Int nr return $ Int nr
-- |Parses a real number in Rosetta into an Expression
decimalParser :: Parser Expression decimalParser :: Parser Expression
decimalParser = decimalParser =
do do
@@ -84,19 +94,22 @@ decimalParser =
_ <- char '.' _ <- char '.'
real <- lexeme $ many digitChar real <- lexeme $ many digitChar
return $ Real $ nr ++ "." ++ real return $ Real $ nr ++ "." ++ real
-- |Parses a boolean in Rosetta into an Expression
booleanParser :: Parser Expression booleanParser :: Parser Expression
booleanParser = booleanParser =
do do
bol <- lexeme (string "True" <|> string "False") bol <- lexeme (string "True" <|> string "False")
return $ Boolean $ Text.unpack bol return $ Boolean $ Text.unpack bol
-- |Parses the empty statement in Rosetta into an Expression
emptyParser :: Parser Expression emptyParser :: Parser Expression
emptyParser = emptyParser =
do do
_ <- lexeme $ string "empty" _ <- lexeme $ string "empty"
return Empty return Empty
-- |Parses any of the terminal statements in Rosetta into an Expression
terminalParser :: Parser Expression terminalParser :: Parser Expression
terminalParser = terminalParser =
do do
@@ -115,12 +128,18 @@ terminalParser =
-- Expressions ----------------------------- -- Expressions -----------------------------
-------------------------------------------- --------------------------------------------
-- |Parses an prefix function statement in Rosetta into an Expression
prefixParser :: Parser Expression prefixParser :: Parser Expression
prefixParser = prefixParser =
do do
op <- lexeme $ choice $ fmap (try . string . Text.pack) prefixOperators op <- lexeme $ choice $ fmap (try . string . Text.pack) prefixOperators
PrefixExp (Text.unpack op) <$> expressionParser PrefixExp (Text.unpack op) <$> expressionParser
-- |List of prefix operators
prefixOperators :: [String]
prefixOperators = ["-", "not"]
-- |Parses an equality statement in Rosetta into an Expression
eqParser :: Parser Expression eqParser :: Parser Expression
eqParser = eqParser =
do do
@@ -130,9 +149,11 @@ eqParser =
Left _ -> return s Left _ -> return s
Right o -> eqParser >>= \ex -> return $ InfixExp (Text.unpack o) s ex Right o -> eqParser >>= \ex -> return $ InfixExp (Text.unpack o) s ex
-- |The list of equality statements in Rosetta
eqFunctions :: [String] eqFunctions :: [String]
eqFunctions = ["=", "<", "<=", ">", ">=", "<>", "all =", "all <>", "any =", "any <>"] eqFunctions = ["=", "<", "<=", ">", ">=", "<>", "all =", "all <>", "any =", "any <>"]
-- |Parses a sum statement in Rosetta into an Expression
sumParser :: Parser Expression sumParser :: Parser Expression
sumParser = sumParser =
do do
@@ -142,6 +163,7 @@ sumParser =
Left _ -> return f Left _ -> return f
Right o -> sumParser >>= \ex -> return $ reverseExpression $ InfixExp [o] f ex Right o -> sumParser >>= \ex -> return $ reverseExpression $ InfixExp [o] f ex
-- |Parses a multiplication or division statement in Rosetta into an Expression
factorParser :: Parser Expression factorParser :: Parser Expression
factorParser = factorParser =
do do
@@ -151,6 +173,7 @@ factorParser =
Left _ -> return p Left _ -> return p
Right o -> factorParser >>= \ex -> return $ reverseExpression $ InfixExp [o] p ex Right o -> factorParser >>= \ex -> return $ reverseExpression $ InfixExp [o] p ex
-- |Parses a boolean statement in Rosetta into an Expression
boolOpParser :: Parser Expression boolOpParser :: Parser Expression
boolOpParser = boolOpParser =
do do
@@ -160,6 +183,7 @@ boolOpParser =
Left _ -> return p Left _ -> return p
Right o -> boolOpParser >>= \ex -> return $ InfixExp (Text.unpack o) p ex Right o -> boolOpParser >>= \ex -> return $ InfixExp (Text.unpack o) p ex
-- |Parses a power statement in Rosetta into an Expression
powerParser :: Parser Expression powerParser :: Parser Expression
powerParser = powerParser =
do do
@@ -168,7 +192,8 @@ powerParser =
case op of case op of
Left _ -> return p Left _ -> return p
Right _ -> powerParser >>= \ex -> return $ InfixExp "^" p ex Right _ -> powerParser >>= \ex -> return $ InfixExp "^" p ex
-- |Parses a postfix function in Rosetta into an Expression
postfixParser :: Parser Expression postfixParser :: Parser Expression
postfixParser = postfixParser =
do do
@@ -178,6 +203,7 @@ postfixParser =
Left _ -> return t Left _ -> return t
Right o -> return $ PostfixExp (Text.unpack o) t Right o -> return $ PostfixExp (Text.unpack o) t
-- |The list of existing postfix Rosetta functions
postfixFunctions :: [String] postfixFunctions :: [String]
postfixFunctions = ["exists", "is absent", "count", "only-element", "single exists", "multiple exists"] postfixFunctions = ["exists", "is absent", "count", "only-element", "single exists", "multiple exists"]
@@ -185,12 +211,15 @@ postfixFunctions = ["exists", "is absent", "count", "only-element", "single exis
-- Auxiliary ------------------------------ -- Auxiliary ------------------------------
-------------------------------------------- --------------------------------------------
-- |Reverses the order of operations for left-associative functions
reverseExpression :: Expression -> Expression reverseExpression :: Expression -> Expression
reverseExpression (InfixExp op t1 (InfixExp op2 t2 e)) reverseExpression (InfixExp op t1 (InfixExp op2 t2 e))
| precedence op == precedence op2 = InfixExp op2 (reverseExpression (InfixExp op t1 t2)) e | precedence op == precedence op2 = InfixExp op2 (reverseExpression (InfixExp op t1 t2)) e
| otherwise = InfixExp op t1 (InfixExp op2 t2 e) | otherwise = InfixExp op t1 (InfixExp op2 t2 e)
reverseExpression e = e reverseExpression e = e
-- |The precedence of existing infix functions (higher goes first)
precedence :: String -> Int precedence :: String -> Int
precedence "or" = 1 precedence "or" = 1
precedence "and" = 10 precedence "and" = 10
@@ -199,7 +228,4 @@ precedence "-" = 2
precedence "*" = 3 precedence "*" = 3
precedence "/" = 3 precedence "/" = 3
precedence "^" = 4 precedence "^" = 4
precedence _ = 100 precedence _ = 100
prefixOperators :: [String]
prefixOperators = ["-", "not"]

View File

@@ -10,6 +10,7 @@ import Text.Megaparsec
import Text.Megaparsec.Char import Text.Megaparsec.Char
import Parser.General import Parser.General
-- |Parses a function statement in Rosetta into a Function
functionParser :: Parser Function functionParser :: Parser Function
functionParser = functionParser =
do do
@@ -21,6 +22,7 @@ functionParser =
fOutput <- outputAttributeParser fOutput <- outputAttributeParser
MakeFunction fName fDescription fInput fOutput <$> assignmentParser MakeFunction fName fDescription fInput fOutput <$> assignmentParser
-- |Parses the output assignment statement from a function in Rosetta into an Expression
assignmentParser :: Parser Expression assignmentParser :: Parser Expression
assignmentParser = assignmentParser =
do do
@@ -28,18 +30,21 @@ assignmentParser =
_ <- lexeme $ char ':' _ <- lexeme $ char ':'
expressionParser expressionParser
-- |Parses the input attributes from a function statement in Rosetta into a list of TypeAttributes
inputAttributesParser :: Parser [TypeAttribute] inputAttributesParser :: Parser [TypeAttribute]
inputAttributesParser = inputAttributesParser =
do do
_ <- lexeme $ string "inputs:" _ <- lexeme $ string "inputs:"
many $ try attributeParser many $ try attributeParser
-- |Parses the output attribute of a function statement in Rosetta into a TypeAttribute
outputAttributeParser :: Parser TypeAttribute outputAttributeParser :: Parser TypeAttribute
outputAttributeParser = outputAttributeParser =
do do
_ <- lexeme $ string "output:" _ <- lexeme $ string "output:"
attributeParser attributeParser
-- |Auxiliary function that parses an attribute into a TypeAttribute
attributeParser :: Parser TypeAttribute attributeParser :: Parser TypeAttribute
attributeParser = attributeParser =
do do

View File

@@ -10,19 +10,22 @@ import Data.Text
type Parser = Parsec Void Text type Parser = Parsec Void Text
-- |Auxiliary parser that eliminates trailing white space
spaceConsumer :: Parser () spaceConsumer :: Parser ()
spaceConsumer = L.space space1 (L.skipLineComment "//") (L.skipBlockComment "/*" "*/") spaceConsumer = L.space space1 (L.skipLineComment "//") (L.skipBlockComment "/*" "*/")
-- |Auxiliary parser that runs a parser and eliminates trailing white space
lexeme :: Parser a -> Parser a lexeme :: Parser a -> Parser a
lexeme = L.lexeme spaceConsumer lexeme = L.lexeme spaceConsumer
-- |Parses a description in Rosetta into a String
descriptionParser :: Parser String descriptionParser :: Parser String
descriptionParser = descriptionParser =
do do
_ <- string "<\"" _ <- string "<\""
lexeme $ anySingle `manyTill` string "\">" lexeme $ anySingle `manyTill` string "\">"
-- |Parses a pascal case name into a String (PascalCase)
pascalNameParser :: Parser String pascalNameParser :: Parser String
pascalNameParser = pascalNameParser =
do do
@@ -30,6 +33,7 @@ pascalNameParser =
rest <- lexeme $ many allowedChars rest <- lexeme $ many allowedChars
if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name") if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name")
-- |Parses a camel case name into a String (camelCase)
camelNameParser :: Parser String camelNameParser :: Parser String
camelNameParser = camelNameParser =
do do
@@ -37,6 +41,7 @@ camelNameParser =
rest <- lexeme $ many allowedChars rest <- lexeme $ many allowedChars
if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name") if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name")
-- |Parses any name that starts with a letter or '_' into a String
nameParser :: Parser String nameParser :: Parser String
nameParser = nameParser =
do do
@@ -44,9 +49,12 @@ nameParser =
rest <- lexeme $ many allowedChars rest <- lexeme $ many allowedChars
if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name") if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name")
-- |Parses a character allowed in names in Rosetta into a Char
allowedChars :: Parser Char allowedChars :: Parser Char
allowedChars = letterChar <|> digitChar <|> char '_' allowedChars = letterChar <|> digitChar <|> char '_'
-- |List of restricted names used by Rosetta
restrictedNames :: [String] restrictedNames :: [String]
restrictedNames = [ restrictedNames = [
"displayName", "displayName",

View File

@@ -7,6 +7,7 @@ import Text.Megaparsec.Char
import Text.Megaparsec import Text.Megaparsec
import Parser.General import Parser.General
-- |Parses a type declaration statement in Rosetta into an Type
typeParser :: Parser Type typeParser :: Parser Type
typeParser = typeParser =
do do
@@ -17,6 +18,7 @@ typeParser =
tAttributes <- many $ try typeAttributeParser tAttributes <- many $ try typeAttributeParser
return (MakeType tName tSuper tDescription tAttributes) return (MakeType tName tSuper tDescription tAttributes)
-- |Parses the super class declaration statement in Rosetta into an Type
superTypeParser :: Parser Type superTypeParser :: Parser Type
superTypeParser = superTypeParser =
do do
@@ -24,6 +26,7 @@ superTypeParser =
name <- pascalNameParser name <- pascalNameParser
return $ MakeType name Nothing Nothing [] return $ MakeType name Nothing Nothing []
-- |Parses a declared type attribute in Rosetta into a TypeAttribute
typeAttributeParser :: Parser TypeAttribute typeAttributeParser :: Parser TypeAttribute
typeAttributeParser = typeAttributeParser =
do do
@@ -33,11 +36,13 @@ typeAttributeParser =
desc <- optional descriptionParser desc <- optional descriptionParser
return (MakeTypeAttribute aName (MakeType aType Nothing Nothing []) card desc) return (MakeTypeAttribute aName (MakeType aType Nothing Nothing []) card desc)
-- |Parses the cardinality of a type attribute in Rosetta into a Cardinality
cardinalityParser :: Parser Cardinality cardinalityParser :: Parser Cardinality
cardinalityParser = cardinalityParser =
do do
try parseBounded <|> try parseSemiBounded <|> try parseUnbounded try parseBounded <|> try parseSemiBounded <|> try parseUnbounded
-- |Parses a bounded cardinality statement in Rosetta into a Cardinality
parseBounded :: Parser Cardinality parseBounded :: Parser Cardinality
parseBounded = parseBounded =
do do
@@ -48,7 +53,7 @@ parseBounded =
_ <- lexeme $ char ')' _ <- lexeme $ char ')'
return $ Bounds (read low, read up) return $ Bounds (read low, read up)
-- |Parses a one bounded cardinality statement in Rosetta into a Cardinality
parseSemiBounded :: Parser Cardinality parseSemiBounded :: Parser Cardinality
parseSemiBounded = parseSemiBounded =
do do
@@ -57,13 +62,14 @@ parseSemiBounded =
_ <- lexeme $ string "..*)" _ <- lexeme $ string "..*)"
return $ OneBound $ read low return $ OneBound $ read low
-- |Parses an unbounded cardinality statement in Rosetta into a Cardinality
parseUnbounded :: Parser Cardinality parseUnbounded :: Parser Cardinality
parseUnbounded = parseUnbounded =
do do
_ <- lexeme $ string "(*..*)" _ <- lexeme $ string "(*..*)"
return NoBounds return NoBounds
-- |Parses the name of a type in Rosetta into a String
typeNameParser :: Parser String typeNameParser :: Parser String
typeNameParser = typeNameParser =
do do

View File

@@ -6,6 +6,7 @@ import Model.Enum
import PrettyPrinter.General import PrettyPrinter.General
import Prettyprinter import Prettyprinter
-- |Converts an EnumType into a haskell valid String
printEnum :: EnumType -> String printEnum :: EnumType -> String
printEnum (MakeEnum name description values) = printEnum (MakeEnum name description values) =
show $ printDescription description show $ printDescription description
@@ -14,22 +15,27 @@ printEnum (MakeEnum name description values) =
"", "",
printDisplayNames name values]) printDisplayNames name values])
-- |Converts a list of EnumValues into a haskell valid Doc
printEnumValues :: [EnumValue] -> Doc a printEnumValues :: [EnumValue] -> Doc a
printEnumValues [] = "" printEnumValues [] = ""
printEnumValues (x:xs) = vcat (printFirstEnumValue x: map printEnumValue xs) printEnumValues (x:xs) = vcat (printFirstEnumValue x: map printEnumValue xs)
-- |Converts the first EnumValue (in haskell without the '|') into a haskell valid Doc
printFirstEnumValue :: EnumValue -> Doc a printFirstEnumValue :: EnumValue -> Doc a
printFirstEnumValue (MakeEnumValue name description _) = printFirstEnumValue (MakeEnumValue name description _) =
printDescription description (pretty name) printDescription description (pretty name)
-- |Converts a non-first EnumValue (in haskell with the '|') into a haskell valid Doc
printEnumValue :: EnumValue -> Doc a printEnumValue :: EnumValue -> Doc a
printEnumValue (MakeEnumValue name description _) = printEnumValue (MakeEnumValue name description _) =
printDescription description ("|" <+> pretty name) printDescription description ("|" <+> pretty name)
-- |Converts the display names of an EnumType into a haskell valid Doc
printDisplayNames :: String -> [EnumValue] -> Doc a printDisplayNames :: String -> [EnumValue] -> Doc a
printDisplayNames name values = printDisplayNames name values =
nest 4 $ vcat ("instance Show" <+> pretty name <+> "where": map printDisplayName values) nest 4 $ vcat ("instance Show" <+> pretty name <+> "where": map printDisplayName values)
-- |Converts a single display name into a haskell valid Doc
printDisplayName :: EnumValue -> Doc a printDisplayName :: EnumValue -> Doc a
printDisplayName (MakeEnumValue name _ (Just display)) = printDisplayName (MakeEnumValue name _ (Just display)) =
"show" <+> pretty name <+> "= \"" <> pretty display <> "\"" "show" <+> pretty name <+> "= \"" <> pretty display <> "\""

View File

@@ -9,9 +9,11 @@ import PrettyPrinter.Type
-- show printStatementTree -- show printStatementTree
-- |Converts a Function into a haskell valid String
printFunction :: Function -> String printFunction :: Function -> String
printFunction f = show $ vcat [printFunctionSignature f, printFunctionBody f] printFunction f = show $ vcat [printFunctionSignature f, printFunctionBody f]
-- |Converts the body of a Function into a haskell valid Doc
printFunctionBody :: Function -> Doc a printFunctionBody :: Function -> Doc a
printFunctionBody (MakeFunction name _ _ _ ex) = pretty name <+> "=" <+> printExpression ex printFunctionBody (MakeFunction name _ _ _ ex) = pretty name <+> "=" <+> printExpression ex
printExpression :: Expression -> Doc a printExpression :: Expression -> Doc a
@@ -29,9 +31,11 @@ printExpression (InfixExp name ex1 ex2) = printExpression ex1 <+> pretty name <+
printExpression (IfSimple cond ex) = "if" <+> printExpression cond <+> "then" <+> printExpression ex <+> "else" <+> "pure ()" printExpression (IfSimple cond ex) = "if" <+> printExpression cond <+> "then" <+> printExpression ex <+> "else" <+> "pure ()"
printExpression (IfElse cond ex1 ex2) = "if" <+> printExpression cond <+> "then" <+> printExpression ex1 <+> "else" <+> printExpression ex2 printExpression (IfElse cond ex1 ex2) = "if" <+> printExpression cond <+> "then" <+> printExpression ex1 <+> "else" <+> printExpression ex2
-- |Converts a function into a haskell valid Doc representing the signature of the function
printFunctionSignature :: Function -> Doc a printFunctionSignature :: Function -> Doc a
printFunctionSignature (MakeFunction name description inputs output _) = printFunctionSignature (MakeFunction name description inputs output _) =
printDescription description (pretty name <+> prettyPrintType (Prelude.map printCardinality (inputs ++ [output]))) printDescription description (pretty name <+> prettyPrintType (Prelude.map printCardinality (inputs ++ [output])))
-- |Zips the signature with the needed characters ('::', '->')
prettyPrintType :: [Doc x] -> Doc x prettyPrintType :: [Doc x] -> Doc x
prettyPrintType = align . sep . Prelude.zipWith (<+>) ("::" : repeat "->") prettyPrintType = align . sep . Prelude.zipWith (<+>) ("::" : repeat "->")

View File

@@ -4,6 +4,7 @@ module PrettyPrinter.General where
import Prettyprinter import Prettyprinter
-- |Converts a description String into a haskell valid Doc
printDescription :: Maybe String -> Doc a -> Doc a printDescription :: Maybe String -> Doc a -> Doc a
printDescription (Just description) doc = printDescription (Just description) doc =
vcat [enclose "{-" "-}" (pretty description), doc] vcat [enclose "{-" "-}" (pretty description), doc]

View File

@@ -5,6 +5,7 @@ import PrettyPrinter.Enum
import PrettyPrinter.Function import PrettyPrinter.Function
import PrettyPrinter.Type import PrettyPrinter.Type
-- |Converts a supported Rosetta object into a haskell valid String
printRosettaObject :: RosettaObject -> String printRosettaObject :: RosettaObject -> String
printRosettaObject (EnumObject a) = printEnum a printRosettaObject (EnumObject a) = printEnum a
printRosettaObject (TypeObject a) = printType a printRosettaObject (TypeObject a) = printType a

View File

@@ -6,6 +6,7 @@ import Prettyprinter
import PrettyPrinter.General import PrettyPrinter.General
import Model.Type import Model.Type
-- |Converts an EnumType into a haskell valid String
printType :: Type -> String printType :: Type -> String
printType (MakeType name (Just (MakeType super _ _ _)) description attributes) = printType (MakeType name Nothing description (superToAttribute super:attributes)) printType (MakeType name (Just (MakeType super _ _ _)) description attributes) = printType (MakeType name Nothing description (superToAttribute super:attributes))
printType (MakeType _ (Just (BasicType _)) _ _) = error "Can't extend basic types" printType (MakeType _ (Just (BasicType _)) _ _) = error "Can't extend basic types"
@@ -13,24 +14,23 @@ printType (MakeType name Nothing description attributes) =
show $ printDescription description (vcat [nest 4 $ vcat ("data" <+> pretty name <+> "=" <+> "Make" <> pretty name <+> "{": printAttributes attributes), "}", ""]) show $ printDescription description (vcat [nest 4 $ vcat ("data" <+> pretty name <+> "=" <+> "Make" <> pretty name <+> "{": printAttributes attributes), "}", ""])
printType (BasicType name) = show $ pretty name printType (BasicType name) = show $ pretty name
--printSuperType :: Maybe Type -> Doc a -- |Creates an attribute that accesses the super type
--printSuperType (Just (MakeType name _ _ _)) = "super" <+> "::" <+> pretty name
--printSuperType (Just (BasicType _)) = error "Can't extend basic types"
--printSuperType Nothing = emptyDoc
superToAttribute :: String -> TypeAttribute superToAttribute :: String -> TypeAttribute
superToAttribute name = MakeTypeAttribute "super" (MakeType name Nothing Nothing []) (Bounds (1, 1)) (Just "Pointer to super class") superToAttribute name = MakeTypeAttribute "super" (MakeType name Nothing Nothing []) (Bounds (1, 1)) (Just "Pointer to super class")
-- |Converts a list of TypeAttributes into a list of haskell valid Docs
printAttributes :: [TypeAttribute] -> [Doc a] printAttributes :: [TypeAttribute] -> [Doc a]
printAttributes [] = [] printAttributes [] = []
printAttributes [at] = [printAttribute at] printAttributes [at] = [printAttribute at]
printAttributes (at : ats) = (printAttribute at <> ",") : printAttributes ats printAttributes (at : ats) = (printAttribute at <> ",") : printAttributes ats
-- |Converts a TypeAttribute into a haskell valid Doc
printAttribute :: TypeAttribute -> Doc a printAttribute :: TypeAttribute -> Doc a
printAttribute (MakeTypeAttribute name typ crd description) = printAttribute (MakeTypeAttribute name typ crd description) =
printDescription description printDescription description
(pretty name <+> "::" <+> printCardinality (MakeTypeAttribute name typ crd description)) (pretty name <+> "::" <+> printCardinality (MakeTypeAttribute name typ crd description))
-- |Converts a Cardinality into a haskell valid Doc
printCardinality :: TypeAttribute -> Doc a printCardinality :: TypeAttribute -> Doc a
printCardinality (MakeTypeAttribute _ typ (Bounds (x, y)) _) printCardinality (MakeTypeAttribute _ typ (Bounds (x, y)) _)
| x == 0 && y == 1 = "Maybe" <+> pretty (typeName typ) | x == 0 && y == 1 = "Maybe" <+> pretty (typeName typ)

View File

@@ -6,6 +6,7 @@ import Data.Maybe
import Model.Type import Model.Type
import Semantic.TypeChecker import Semantic.TypeChecker
-- |A declared variable or function
data Symbol = Var{ data Symbol = Var{
varName :: String, varName :: String,
declaredType :: Type declaredType :: Type
@@ -16,6 +17,7 @@ data Symbol = Var{
returnType :: Type returnType :: Type
} }
-- |A map of the predefined functions, their arguments and their return type
defaultMap :: [Symbol] defaultMap :: [Symbol]
defaultMap = [ defaultMap = [
Func "or" [BasicType "Boolean", BasicType "Boolean"] (BasicType "Boolean"), Func "or" [BasicType "Boolean", BasicType "Boolean"] (BasicType "Boolean"),
@@ -52,6 +54,7 @@ defaultMap = [
Func "count" [BasicType "Any"] (BasicType "Integer") Func "count" [BasicType "Any"] (BasicType "Integer")
] ]
-- |Checks whether a function is valid (inputs, outputs are of valid type and all variables are defined) and adds it to the symbol table
addFunction :: ([Type], [Symbol]) -> Function -> Either [TypeCheckError] [Symbol] addFunction :: ([Type], [Symbol]) -> Function -> Either [TypeCheckError] [Symbol]
addFunction (definedTypes, definedSymbols) (MakeFunction name _ inps out _) addFunction (definedTypes, definedSymbols) (MakeFunction name _ inps out _)
| null (lefts checkedInputs) && isRight checkedOutput = Right $ Func name (map attributeType (rights checkedInputs)) (attributeType $ fromRightUnsafe checkedOutput) : allSymbols | null (lefts checkedInputs) && isRight checkedOutput = Right $ Func name (map attributeType (rights checkedInputs)) (attributeType $ fromRightUnsafe checkedOutput) : allSymbols
@@ -62,10 +65,12 @@ addFunction (definedTypes, definedSymbols) (MakeFunction name _ inps out _)
checkedOutput = head $ checkAttributes definedTypes [out] checkedOutput = head $ checkAttributes definedTypes [out]
allSymbols = addVariables definedSymbols inps allSymbols = addVariables definedSymbols inps
-- |Adds a newly defined variable to the symbol table
addVariables :: [Symbol] -> [TypeAttribute] -> [Symbol] addVariables :: [Symbol] -> [TypeAttribute] -> [Symbol]
addVariables s [] = s addVariables s [] = s
addVariables s ((MakeTypeAttribute name typ _ _) : vars) = Var name typ : addVariables s vars addVariables s ((MakeTypeAttribute name typ _ _) : vars) = Var name typ : addVariables s vars
-- |Checks the type of a given expression
checkExpression :: [Symbol] -> Expression -> Either TypeCheckError Type checkExpression :: [Symbol] -> Expression -> Either TypeCheckError Type
checkExpression symbolMap (Variable var) = findVarType var symbolMap checkExpression symbolMap (Variable var) = findVarType var symbolMap
checkExpression _ (Int _) = Right $ BasicType "Integer" checkExpression _ (Int _) = Right $ BasicType "Integer"
@@ -78,10 +83,12 @@ checkExpression symbolMap (PrefixExp name ex) = checkFunctionCall symbolMap name
checkExpression symbolMap (Function name exps) = checkFunctionCall symbolMap name (map (checkExpression symbolMap) exps) checkExpression symbolMap (Function name exps) = checkFunctionCall symbolMap name (map (checkExpression symbolMap) exps)
checkExpression symbolMap (PostfixExp name ex) = checkFunctionCall symbolMap name [checkExpression symbolMap ex] checkExpression symbolMap (PostfixExp name ex) = checkFunctionCall symbolMap name [checkExpression symbolMap ex]
checkExpression symbolMap (InfixExp name ex1 ex2) = checkFunctionCall symbolMap name (checkExpression symbolMap ex1: [checkExpression symbolMap ex2]) checkExpression symbolMap (InfixExp name ex1 ex2) = checkFunctionCall symbolMap name (checkExpression symbolMap ex1: [checkExpression symbolMap ex2])
-- |Checks if the condition of an if expression is of type boolean, and then checks the expression of the then statement
checkExpression symbolMap (IfSimple cond ex) checkExpression symbolMap (IfSimple cond ex)
| isRight condType && isRight (typeMatch (fromRightUnsafe condType) (BasicType "Boolean")) = checkExpression symbolMap ex | isRight condType && isRight (typeMatch (fromRightUnsafe condType) (BasicType "Boolean")) = checkExpression symbolMap ex
| otherwise = Left IfConditionNotBoolean | otherwise = Left IfConditionNotBoolean
where condType = checkExpression symbolMap cond where condType = checkExpression symbolMap cond
-- |Checks if the condition of the if statement is of type boolean, and then checks that both the then and else statements have the same type
checkExpression symbolMap (IfElse cond ex1 ex2) checkExpression symbolMap (IfElse cond ex1 ex2)
| isRight condType || isRight (typeMatch (fromRightUnsafe condType) (BasicType "Boolean")) = Left IfConditionNotBoolean | isRight condType || isRight (typeMatch (fromRightUnsafe condType) (BasicType "Boolean")) = Left IfConditionNotBoolean
| isRight ex1Type || isRight ex2Type || isRight (typeMatch (fromRightUnsafe ex1Type) (fromRightUnsafe ex2Type)) = Left IfExpressionsDifferentTypes | isRight ex1Type || isRight ex2Type || isRight (typeMatch (fromRightUnsafe ex1Type) (fromRightUnsafe ex2Type)) = Left IfExpressionsDifferentTypes
@@ -90,12 +97,14 @@ checkExpression symbolMap (IfElse cond ex1 ex2)
ex1Type = checkExpression symbolMap ex1 ex1Type = checkExpression symbolMap ex1
ex2Type = checkExpression symbolMap ex2 ex2Type = checkExpression symbolMap ex2
-- |Checks that all the expressions in a list have compatible types
checkList :: [Symbol] -> [Expression] -> Either TypeCheckError Type checkList :: [Symbol] -> [Expression] -> Either TypeCheckError Type
checkList symbs exps checkList symbs exps
| isRight typ && fromRightUnsafe typ == BasicType "Any" = Right $ BasicType "Empty" | isRight typ && fromRightUnsafe typ == BasicType "Any" = Right $ BasicType "Empty"
| otherwise = typ | otherwise = typ
where typ = checkList1 symbs exps (BasicType "Any") where typ = checkList1 symbs exps (BasicType "Any")
-- |Auxiliary function for the check list function
checkList1 :: [Symbol] -> [Expression] -> Type -> Either TypeCheckError Type checkList1 :: [Symbol] -> [Expression] -> Type -> Either TypeCheckError Type
checkList1 _ [] typ = Right typ checkList1 _ [] typ = Right typ
checkList1 symbs (ex : exps) typ checkList1 symbs (ex : exps) typ
@@ -106,6 +115,7 @@ checkList1 symbs (ex : exps) typ
exTyp = checkExpression symbs ex exTyp = checkExpression symbs ex
match = typeMatch typ (fromRightUnsafe exTyp) match = typeMatch typ (fromRightUnsafe exTyp)
-- |Checks whether the function that is called is already defined with the same argument types
checkFunctionCall :: [Symbol] -> String -> [Either TypeCheckError Type] -> Either TypeCheckError Type checkFunctionCall :: [Symbol] -> String -> [Either TypeCheckError Type] -> Either TypeCheckError Type
checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: \"" ++ fun ++ "\" [" ++ concatMap typeName (rights args) ++ "]" checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: \"" ++ fun ++ "\" [" ++ concatMap typeName (rights args) ++ "]"
checkFunctionCall ((Func n a r):symbolMap) name args checkFunctionCall ((Func n a r):symbolMap) name args
@@ -116,6 +126,7 @@ checkFunctionCall ((Func n a r):symbolMap) name args
checkFunctionCall (_:symbolMap) name args = checkFunctionCall symbolMap name args checkFunctionCall (_:symbolMap) name args = checkFunctionCall symbolMap name args
--Try to match 2nd type to first type --Try to match 2nd type to first type
-- |Checks whether two types are compatible
typeMatch :: Type -> Type -> Either TypeCheckError Type typeMatch :: Type -> Type -> Either TypeCheckError Type
typeMatch (BasicType "Any") x = Right x typeMatch (BasicType "Any") x = Right x
typeMatch (BasicType "Double") (BasicType "Integer") = Right $ BasicType "Dobule" typeMatch (BasicType "Double") (BasicType "Integer") = Right $ BasicType "Dobule"
@@ -127,6 +138,7 @@ typeMatch s s2
| isJust $ superType s2 = typeMatch s (fromJust $ superType s2) | isJust $ superType s2 = typeMatch s (fromJust $ superType s2)
| otherwise = Left $ TypeMismatch (typeName s) (typeName s2) | otherwise = Left $ TypeMismatch (typeName s) (typeName s2)
-- |Looks in the symbol map for the type of a variable
findVarType :: String -> [Symbol] -> Either TypeCheckError Type findVarType :: String -> [Symbol] -> Either TypeCheckError Type
findVarType var [] = Left $ UndefinedVariable var findVarType var [] = Left $ UndefinedVariable var
findVarType x ((Var name typ):symbols) findVarType x ((Var name typ):symbols)

View File

@@ -6,6 +6,7 @@ import Semantic.ExpressionChecker
import Semantic.TypeChecker import Semantic.TypeChecker
import Data.Either import Data.Either
-- |Checks if all the inputs and the out of a function call have valid types, and then checks that the assign-output expression is valid
checkFunction :: ([Type], [Symbol]) -> Function -> Either [TypeCheckError] Function checkFunction :: ([Type], [Symbol]) -> Function -> Either [TypeCheckError] Function
checkFunction (definedTypes, definedFunctions) (MakeFunction name desc inp out ex) checkFunction (definedTypes, definedFunctions) (MakeFunction name desc inp out ex)
| isRight checkedEx && isRight checkedOut && null (lefts checkedIn) = Right $ MakeFunction name desc (rights checkedIn) (fromRightUnsafe checkedOut) ex | isRight checkedEx && isRight checkedOut && null (lefts checkedIn) = Right $ MakeFunction name desc (rights checkedIn) (fromRightUnsafe checkedOut) ex

View File

@@ -3,6 +3,7 @@ module Semantic.TypeChecker where
import Model.Type import Model.Type
import Data.Either import Data.Either
-- |A datatype for the different types of type check errors
data TypeCheckError = data TypeCheckError =
UndefinedType String UndefinedType String
| IfConditionNotBoolean | IfConditionNotBoolean
@@ -13,6 +14,7 @@ data TypeCheckError =
| TypeMismatch String String | TypeMismatch String String
deriving (Show) deriving (Show)
-- |Checks whether a data type is valid
checkType :: [Type] -> Type -> Either [TypeCheckError] Type checkType :: [Type] -> Type -> Either [TypeCheckError] Type
checkType definedTypes (MakeType name super desc attr) checkType definedTypes (MakeType name super desc attr)
| null (lefts checkedAttr) = Right $ MakeType name super desc (rights checkedAttr) | null (lefts checkedAttr) = Right $ MakeType name super desc (rights checkedAttr)
@@ -20,6 +22,8 @@ checkType definedTypes (MakeType name super desc attr)
where checkedAttr = checkAttributes definedTypes attr where checkedAttr = checkAttributes definedTypes attr
checkType _ (BasicType b) = Right (BasicType b) checkType _ (BasicType b) = Right (BasicType b)
-- |Checks whether all the types of the attributes of a data type are already defined
checkAttributes :: [Type] -> [TypeAttribute] -> [Either TypeCheckError TypeAttribute] checkAttributes :: [Type] -> [TypeAttribute] -> [Either TypeCheckError TypeAttribute]
checkAttributes _ [] = [] checkAttributes _ [] = []
checkAttributes definedTypes ((MakeTypeAttribute name typ crd desc):as) checkAttributes definedTypes ((MakeTypeAttribute name typ crd desc):as)
@@ -27,6 +31,7 @@ checkAttributes definedTypes ((MakeTypeAttribute name typ crd desc):as)
| otherwise = Left (fromLeftUnsafe checked) : checkAttributes definedTypes as | otherwise = Left (fromLeftUnsafe checked) : checkAttributes definedTypes as
where checked = checkAttributeType definedTypes typ where checked = checkAttributeType definedTypes typ
-- |Checks whether a type is predefined or in the symbol table
checkAttributeType :: [Type] -> Type -> Either TypeCheckError Type checkAttributeType :: [Type] -> Type -> Either TypeCheckError Type
checkAttributeType _ (MakeType "int" _ _ _) = Right $ BasicType "Integer" checkAttributeType _ (MakeType "int" _ _ _) = Right $ BasicType "Integer"
checkAttributeType _ (MakeType "string" _ _ _) = Right $ BasicType "String" checkAttributeType _ (MakeType "string" _ _ _) = Right $ BasicType "String"
@@ -37,16 +42,21 @@ checkAttributeType definedTypes name
| name `elem` definedTypes = Right name | name `elem` definedTypes = Right name
| otherwise = Left $ UndefinedType (typeName name) | otherwise = Left $ UndefinedType (typeName name)
-- |Add a list of defined types to the symbol table
addDefinedTypes :: [Type] -> [Type] -> [Type] addDefinedTypes :: [Type] -> [Type] -> [Type]
addDefinedTypes l [] = l addDefinedTypes l [] = l
addDefinedTypes l (BasicType _ : ts) = addDefinedTypes l ts addDefinedTypes l (BasicType _ : ts) = addDefinedTypes l ts
addDefinedTypes l (t:ts) = t : addDefinedTypes l ts addDefinedTypes l (t:ts) = t : addDefinedTypes l ts
-- |Auxiliary function to get the right value from an either that stops with an error if the value is left
-- used when it is certain that the value will be right
fromRightUnsafe :: (Show a) => Either a b -> b fromRightUnsafe :: (Show a) => Either a b -> b
fromRightUnsafe x = case x of fromRightUnsafe x = case x of
Left a -> error ("Value is Left" ++ show a) Left a -> error ("Value is Left" ++ show a)
Right b -> b Right b -> b
-- |Auxiliary function to get the left value from an either that stops with an error if the value is right
-- used when it is certain that the value will be left
fromLeftUnsafe :: Either a b -> a fromLeftUnsafe :: Either a b -> a
fromLeftUnsafe x = case x of fromLeftUnsafe x = case x of
Left a -> a Left a -> a