finished generator for basic types, enums and functions.

Functions still need to print a body
This commit is contained in:
macocianradu
2021-11-12 03:05:34 +01:00
parent 045ae7049e
commit 40f6fb24b7
20 changed files with 224 additions and 63 deletions

1
.gitignore vendored
View File

@@ -22,3 +22,4 @@ cabal.project.local~
.HTF/
.ghc.environment.*
.idea/
/resources/Generated/

View File

@@ -27,6 +27,7 @@ library
exposed-modules:
Model.Enum
Model.Function
Model.RosettaObject
Model.Type
Parser.Enum
Parser.Expression
@@ -36,6 +37,7 @@ library
PrettyPrinter.Enum
PrettyPrinter.Function
PrettyPrinter.General
PrettyPrinter.RosettaObject
PrettyPrinter.Type
Semantic.ExpressionChecker
Semantic.TypeChecker

View File

@@ -7,6 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.stack-work" />
<excludeFolder url="file://$MODULE_DIR$/resources/Generated" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View File

@@ -3,28 +3,84 @@ module Main where
import Parser.Enum
import Parser.Type
import Parser.Function
import Parser.General
import Model.RosettaObject
import qualified Data.Text as Text
import Text.Megaparsec
import PrettyPrinter.Enum
import PrettyPrinter.Type
import PrettyPrinter.Function
import Semantic.TypeChecker
import Semantic.ExpressionChecker
import Model.Function
import Model.Type
import System.Environment.Blank (getArgs)
import Model.Enum
import Data.Either
-- :set args resources/testAll.rosetta resources/Generated/testAll.hs
main :: IO ()
main = do
rosettaString <- readFile "app/testFile.rosetta"
putStrLn "rosetta String: "
putStrLn rosettaString
putStrLn "\nFinal enum: \n"
case parse enumParser "" (Text.pack rosettaString) of
args <- getArgs
rosettaString <- readFile $ head args
case parse rosettaParser "" (Text.pack rosettaString) of
Left errorBundle -> print (errorBundlePretty errorBundle)
Right enum -> putStrLn $ printEnum enum
Right objs -> do
putStrLn $ printObjects (definedTypes, definedFunctions) objs
where
definedFunctions = addNewFunctions (definedTypes, defaultMap) objs
definedTypes = addNewTypes [] objs
printObjects :: ([Type], [Symbol]) -> [RosettaObject] -> String
printObjects (t, s) objs
| null (lefts finalString) = concat $ rights finalString
| otherwise = error $ show $ lefts finalString
where finalString = map (printObject (t, s)) objs
printObject :: ([Type], [Symbol]) -> RosettaObject -> Either [TypeCheckError] String
printObject (definedTypes, _) (TypeObject t)
| isRight checked = Right $ printType t
| otherwise = Left $ fromLeftUnsafe checked
where checked = checkType definedTypes t
printObject _ (EnumObject e) = Right $ printEnum e
printObject (_, definedFunctions) (FunctionObject (MakeFunction name desc inp out ex))
| isRight checked = Right $ printFunction (MakeFunction name desc inp out ex)
| otherwise = Left [fromLeftUnsafe checked]
where
checked = checkExpression definedFunctions ex
addNewFunctions :: ([Type], [Symbol]) -> [RosettaObject] -> [Symbol]
addNewFunctions (_, s) [] = s
addNewFunctions (t, s) ((FunctionObject f):os)
| isRight definedFunctions = fromRightUnsafe definedFunctions
| otherwise = error $ show $ fromLeftUnsafe definedFunctions
where definedFunctions = addFunction (t, addNewFunctions (t, s) os) f
addNewFunctions (t, s) (_:os) = addNewFunctions (t, s) os
addNewTypes :: [Type] -> [RosettaObject] -> [Type]
addNewTypes l [] = l
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 (_ :os) = addNewTypes defined os
rosettaParser :: Parser [RosettaObject]
rosettaParser = many (try parseEnum <|> try parseType <|> try parseFunction) <* eof
parseEnum :: Parser RosettaObject
parseEnum = do
EnumObject <$> enumParser
parseType :: Parser RosettaObject
parseType = do
TypeObject <$> typeParser
parseFunction :: Parser RosettaObject
parseFunction = do
FunctionObject <$> functionParser
testEnum :: IO()
testEnum = do
rosettaString <- readFile "resources/Enums/testEnum5.rosetta"
rosettaString <- readFile "resources/Enums/testEnum1.rosetta"
case parse enumParser "" (Text.pack rosettaString) of
Left errorBundle -> print errorBundle
Right enum ->
@@ -61,5 +117,5 @@ testFunc = do
Right fun ->
do
print $ printFunctionSignature fun
print (assignments fun)
print (assignment fun)
writeFile "resources/Generated/generatedFunction.hs" (show $ printFunctionSignature fun)

View File

@@ -1,4 +1,4 @@
type Period: <"description">
type Period extends Something: <"description">
periodMultiplier int (1..1) <"A time period multiplier, e.g. 1, 2 or 3 etc. A negative value can be used when specifying an offset relative to another date, e.g. -2 days.">
testMany TestType (0..*) <"Test many">
testSome TestSomeType (1..*) <"Test some">

34
resources/testAll.rosetta Normal file
View File

@@ -0,0 +1,34 @@
enum PeriodEnum: <"The enumerated values to specified the period, e.g. day, week.">
D displayName "day" <"Day">
M displayName "month" <"Month">
Y displayName "year" <"Year">
type Period extends Something: <"description">
periodMultiplier int (1..1) <"A time period multiplier, e.g. 1, 2 or 3 etc. A negative value can be used when specifying an offset relative to another date, e.g. -2 days.">
testMany TestType (0..*) <"Test many">
testSome TestSomeType (1..*) <"Test some">
testMaybeOne TestZeroOneType (0..1) <"Test zero or one">
type TestType:
periodMultiplier int (1..1)
type TestSomeType: <"description">
periodMultiplier int (1..1) <"A time period multiplier, e.g. 1, 2 or 3 etc. A negative value can be used when specifying an offset relative to another date, e.g. -2 days.">
type TestZeroOneType extends Period:
periodMultiplier int (1..1)
type ObservationPrimitive:
periodMultiplier int (1..1)
func EquityPriceObservation: <"Function specification for the observation of an equity price, based on the attributes of the 'EquityValuation' class.">
inputs:
equity int (1..1)
valuationDate int (1..1)
valuationTime int (0..1)
timeType TestType (0..1)
determinationMethod ObservationPrimitive (1..*)
output:
observation ObservationPrimitive (1..1)
assign-output: if equity exists then valuationDate

View File

@@ -8,5 +8,4 @@ func EquityPriceObservation: <"Function specification for the observation of an
output:
observation ObservationPrimitive (1..1)
assign-output
observation: if asd exists then var2
assign-output: if asd exists then var2

View File

@@ -8,7 +8,7 @@ data Function =
functionDescription :: Maybe String,
inputParameters :: [TypeAttribute],
outputParameter :: TypeAttribute,
assignments :: [(Expression, Expression)]
assignment :: Expression
}
deriving (Show)

View File

@@ -0,0 +1,10 @@
module Model.RosettaObject where
import Model.Enum
import Model.Function
import Model.Type
data RosettaObject =
EnumObject EnumType
| TypeObject Type
| FunctionObject Function

View File

@@ -29,7 +29,6 @@ data TypeAttribute = MakeTypeAttribute {
attributeDescription :: Maybe String
} deriving (Show)
--TODO use bounded class
data Cardinality = Bounds (Integer, Integer)
| OneBound Integer
| NoBounds

View File

@@ -10,7 +10,7 @@ import Model.Enum
enumParser :: Parser EnumType
enumParser =
do
eName <- enumNameParser
eName <- try enumNameParser
eDescription <- optional descriptionParser
values <- some enumValueParser
return (MakeEnum eName eDescription values)
@@ -18,7 +18,7 @@ enumParser =
enumValueParser :: Parser EnumValue
enumValueParser =
do
vName <- nameParser
vName <- try nameParser
dName <- optional enumValueDisplayNameParser
vDescription <- optional descriptionParser
return (MakeEnumValue vName vDescription dName)

View File

@@ -193,7 +193,7 @@ reverseExpression e = e
precedence :: String -> Int
precedence "or" = 1
precedence "and" = 1
precedence "and" = 10
precedence "+" = 2
precedence "-" = 2
precedence "*" = 3

View File

@@ -14,22 +14,19 @@ functionParser :: Parser Function
functionParser =
do
_ <- lexeme $ string "func"
fName <- pascalNameParser
fName <- try pascalNameParser
_ <- lexeme $ char ':'
fDescription <- optional descriptionParser
fInput <- inputAttributesParser
fOutput <- outputAttributeParser
fAssignments <- many assignmentParser
return (MakeFunction fName fDescription fInput fOutput fAssignments)
MakeFunction fName fDescription fInput fOutput <$> assignmentParser
assignmentParser :: Parser (Expression, Expression)
assignmentParser :: Parser Expression
assignmentParser =
do
_ <- lexeme $ string "assign-output"
name <- expressionParser
_ <- lexeme $ char ':'
expr <- expressionParser
return (name, expr)
expressionParser
inputAttributesParser :: Parser [TypeAttribute]
inputAttributesParser =
@@ -46,8 +43,8 @@ outputAttributeParser =
attributeParser :: Parser TypeAttribute
attributeParser =
do
nam <- camelNameParser
typ <- pascalNameParser <|> camelNameParser
nam <- try camelNameParser
typ <- try (pascalNameParser <|> camelNameParser)
crd <- cardinalityParser
desc <- optional descriptionParser
return $ MakeTypeAttribute nam (MakeType typ Nothing Nothing []) crd desc

View File

@@ -27,19 +27,33 @@ pascalNameParser :: Parser String
pascalNameParser =
do
first <- upperChar
rest <- lexeme $ many (letterChar <|> digitChar <|> char '_')
return (first : rest)
rest <- lexeme $ many allowedChars
if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name")
camelNameParser :: Parser String
camelNameParser =
do
first <- lowerChar
rest <- lexeme $ many (letterChar <|> digitChar <|> char '_')
return (first : rest)
rest <- lexeme $ many allowedChars
if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name")
nameParser :: Parser String
nameParser =
do
first <- letterChar <|> char '_'
rest <- lexeme $ many (letterChar <|> digitChar <|> char '_')
return (first:rest)
rest <- lexeme $ many allowedChars
if first:rest `notElem` restrictedNames then return (first:rest) else fail ((first:rest) ++ " is a restricted name")
allowedChars :: Parser Char
allowedChars = letterChar <|> digitChar <|> char '_'
restrictedNames :: [String]
restrictedNames = [
"displayName",
"enum",
"func",
"type",
"extends",
"inputs",
"output"
]

View File

@@ -10,7 +10,7 @@ import Parser.General
typeParser :: Parser Type
typeParser =
do
tName <- typeNameParser
tName <- try typeNameParser
tSuper <- optional superTypeParser
_ <- lexeme $ char ':'
tDescription <- optional descriptionParser
@@ -27,8 +27,8 @@ superTypeParser =
typeAttributeParser :: Parser TypeAttribute
typeAttributeParser =
do
aName <- camelNameParser
aType <- nameParser
aName <- try camelNameParser
aType <- try nameParser
card <- cardinalityParser
desc <- optional descriptionParser
return (MakeTypeAttribute aName (MakeType aType Nothing Nothing []) card desc)

View File

@@ -9,6 +9,9 @@ import PrettyPrinter.Type
-- show printStatementTree
printFunction :: Function -> String
printFunction = show . printFunctionSignature
printFunctionSignature :: Function -> Doc a
printFunctionSignature (MakeFunction name description inputs output _) =
printDescription description (pretty name <+> prettyPrintType (Prelude.map printCardinality (inputs ++ [output])))

View File

@@ -0,0 +1,11 @@
module PrettyPrinter.RosettaObject where
import Model.RosettaObject
import PrettyPrinter.Enum
import PrettyPrinter.Function
import PrettyPrinter.Type
printRosettaObject :: RosettaObject -> String
printRosettaObject (EnumObject a) = printEnum a
printRosettaObject (TypeObject a) = printType a
printRosettaObject (FunctionObject a) = printFunction a

View File

@@ -7,15 +7,24 @@ import PrettyPrinter.General
import Model.Type
printType :: Type -> String
printType (MakeType name _ description attributes) =
show $ printDescription description (vcat [nest 4 $ vcat ("data" <+> pretty name <+> "=" <+> "Make" <> pretty name <+> "{": map printAttribute 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 name Nothing description attributes) =
show $ printDescription description (vcat [nest 4 $ vcat ("data" <+> pretty name <+> "=" <+> "Make" <> pretty name <+> "{": printAttributes attributes), "}", ""])
printType (BasicType name) = show $ pretty name
--printSuperType :: Maybe Type -> Doc a
--printSuperType (Just (MakeType name _ _ _)) = "super" <+> "::" <+> pretty name
--printSuperType (Just (BasicType _)) = error "Can't extend basic types"
--printSuperType Nothing = emptyDoc
superToAttribute :: String -> TypeAttribute
superToAttribute name = MakeTypeAttribute "super" (MakeType name Nothing Nothing []) (Bounds (1, 1)) (Just "Pointer to super class")
printAttributes :: [TypeAttribute] -> [Doc a]
printAttributes [] = []
printAttributes [at] = [printAttribute at]
printAttributes (at : ats) = (printAttribute at <> ",") : printAttributes ats
printAttribute :: TypeAttribute -> Doc a
printAttribute (MakeTypeAttribute name typ crd description) =

View File

@@ -51,7 +51,21 @@ defaultMap = [
Func "count" [BasicType "Any"] (BasicType "Integer")
]
addFunction :: ([Type], [Symbol]) -> Function -> Either [TypeCheckError] [Symbol]
addFunction (definedTypes, definedSymbols) (MakeFunction name _ inps out _)
| null (lefts checkedInputs) && isRight checkedOutput = Right $ Func name (map attributeType (rights checkedInputs)) (attributeType $ fromRightUnsafe checkedOutput) : allSymbols
| isLeft checkedOutput = Left [fromLeftUnsafe checkedOutput]
| otherwise = Left $ lefts checkedInputs
where
checkedInputs = checkAttributes definedTypes inps
checkedOutput = head $ checkAttributes definedTypes [out]
allSymbols = addVariables definedSymbols inps
addVariables :: [Symbol] -> [TypeAttribute] -> [Symbol]
addVariables s [] = s
addVariables s ((MakeTypeAttribute name typ _ _) : vars) = Var name typ : addVariables s vars
checkExpression :: [Symbol] -> Expression -> Either TypeCheckError Type
checkExpression symbolMap (Variable var) = findVarType var symbolMap
checkExpression _ (Int _) = Right $ BasicType "Integer"
@@ -65,7 +79,7 @@ checkExpression symbolMap (Function name exps) = checkFunctionCall symbolMap nam
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 (IfSimple cond ex)
| isLeft condType && isLeft (typeMatch (fromRightUnsafe condType) (BasicType "Boolean")) = checkExpression symbolMap ex
| isRight condType && isRight (typeMatch (fromRightUnsafe condType) (BasicType "Boolean")) = checkExpression symbolMap ex
| otherwise = Left IfConditionNotBoolean
where condType = checkExpression symbolMap cond
checkExpression symbolMap (IfElse cond ex1 ex2)
@@ -95,7 +109,7 @@ checkList1 symbs (ex : exps) typ
checkFunctionCall :: [Symbol] -> String -> [Either TypeCheckError Type] -> Either TypeCheckError Type
checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: \"" ++ fun ++ "\" [" ++ concatMap typeName (rights args) ++ "]"
checkFunctionCall ((Func n a r):symbolMap) name args
| length right /= length args = Left ErrorInsideFunction
| length right /= length args = Left $ ErrorInsideFunction (name ++ ": " ++ show args)
| name == n && all isRight (zipWith typeMatch a right) = Right r
| otherwise = checkFunctionCall symbolMap name args
where right = rights args
@@ -118,14 +132,4 @@ findVarType var [] = Left $ UndefinedVariable var
findVarType x ((Var name typ):symbols)
| x == name = Right typ
| otherwise = findVarType x symbols
findVarType x (_:symbols) = findVarType x symbols
fromRightUnsafe :: Either a b -> b
fromRightUnsafe x = case x of
Left _ -> error "Value is Left"
Right b -> b
fromLeftUnsafe :: Either a b -> a
fromLeftUnsafe x = case x of
Left a -> a
Right _ -> error "Value is Right"
findVarType x (_:symbols) = findVarType x symbols

View File

@@ -1,32 +1,53 @@
module Semantic.TypeChecker where
import Model.Type
import Data.Either
data TypeCheckError =
UndefinedType String
| IfConditionNotBoolean
| IfExpressionsDifferentTypes
| UndefinedFunction String
| ErrorInsideFunction
| ErrorInsideFunction String
| UndefinedVariable String
| TypeMismatch String String
deriving (Show)
checkAttributes :: [Type] -> [TypeAttribute] -> [Either TypeCheckError Type]
checkAttributes _ [] = []
checkAttributes definedTypes ((MakeTypeAttribute _ name _ _):as) = checkType definedTypes name : checkAttributes definedTypes as
checkType :: [Type] -> Type -> Either [TypeCheckError] Type
checkType definedTypes (MakeType name super desc attr)
| null (lefts checkedAttr) = Right $ MakeType name super desc (rights checkedAttr)
| otherwise = Left $ lefts checkedAttr
where checkedAttr = checkAttributes definedTypes attr
checkType _ (BasicType b) = Right (BasicType b)
checkType :: [Type] -> Type -> Either TypeCheckError Type
checkType _ (MakeType "int" _ _ _) = Right $ BasicType "Integer"
checkType _ (MakeType "string" _ _ _) = Right $ BasicType "String"
checkType _ (MakeType "number" _ _ _) = Right $ BasicType "Double"
checkType _ (MakeType "boolean" _ _ _) = Right $ BasicType "Bool"
checkType _ (MakeType "time" _ _ _) = Right $ BasicType "Time"
checkType definedTypes name
checkAttributes :: [Type] -> [TypeAttribute] -> [Either TypeCheckError TypeAttribute]
checkAttributes _ [] = []
checkAttributes definedTypes ((MakeTypeAttribute name typ crd desc):as)
| isRight checked = Right (MakeTypeAttribute name (fromRightUnsafe checked) crd desc) : checkAttributes definedTypes as
| otherwise = Left (fromLeftUnsafe checked) : checkAttributes definedTypes as
where checked = checkAttributeType definedTypes typ
checkAttributeType :: [Type] -> Type -> Either TypeCheckError Type
checkAttributeType _ (MakeType "int" _ _ _) = Right $ BasicType "Integer"
checkAttributeType _ (MakeType "string" _ _ _) = Right $ BasicType "String"
checkAttributeType _ (MakeType "number" _ _ _) = Right $ BasicType "Double"
checkAttributeType _ (MakeType "boolean" _ _ _) = Right $ BasicType "Bool"
checkAttributeType _ (MakeType "time" _ _ _) = Right $ BasicType "Time"
checkAttributeType definedTypes name
| name `elem` definedTypes = Right name
| otherwise = Left $ UndefinedType (typeName name)
addDefinedTypes :: [Type] -> [Type] -> [Type]
addDefinedTypes l [] = l
addDefinedTypes l (BasicType _ : ts) = addDefinedTypes l ts
addDefinedTypes l (t:ts) = t : addDefinedTypes l ts
addDefinedTypes l (t:ts) = t : addDefinedTypes l ts
fromRightUnsafe :: (Show a) => Either a b -> b
fromRightUnsafe x = case x of
Left a -> error ("Value is Left" ++ show a)
Right b -> b
fromLeftUnsafe :: Either a b -> a
fromLeftUnsafe x = case x of
Left a -> a
Right _ -> error "Value is Right"