From 64270e2217fa56eba69f893866a60c9705219f18 Mon Sep 17 00:00:00 2001 From: Macocian Adrian Radu <34056556+macocianradu@users.noreply.github.com> Date: Sun, 5 Jun 2022 00:14:02 +0200 Subject: [PATCH] randomsave --- .gitignore | 3 + app/Main.hs | 4 +- .../Rosetta/Contracts/contractDSL.rosetta | 6 +- .../Rosetta/Contracts/imports-types.rosetta | 2 +- src/Model/Type.hs | 13 ++- src/Parser/Expression.hs | 16 +-- src/PrettyPrinter/Expression.hs | 97 +++++++++++++++---- src/PrettyPrinter/Function.hs | 2 +- src/PrettyPrinter/Header.hs | 4 + src/PrettyPrinter/Type.hs | 1 + src/Semantic/ExpressionChecker.hs | 88 ++++++++++------- src/Semantic/FunctionChecker.hs | 4 +- src/Semantic/TypeChecker.hs | 1 + 13 files changed, 163 insertions(+), 78 deletions(-) diff --git a/.gitignore b/.gitignore index b5c99b8..3ae5126 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ cabal.project.local~ .idea/ /resources/Generated/ .vscode/ +/resources/Rosetta/Try/ +/resources/fxspot.json +/resources/european contract.json \ No newline at end of file diff --git a/app/Main.hs b/app/Main.hs index 9e74ca6..d6fb519 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -29,8 +29,8 @@ import Parser.Expression (expressionParser) -- :l resources/Generated/ContractDSL.hs resources/Generated/ImportsTypes.hs resources/Generated/ImportsEnums.hs -- :set args resources/Rosetta/Contracts/contractDSL.rosetta --- :set args resources/Rosetta/test-all.rosetta --- :l resources/Generated/testAll.hs resources/Generated/testPeriod.hs +-- :l resources/Generated/ContractDSL.hs resources/Generated/ImportsTypes.hs +-- :set args resources/Rosetta/Try/contractDSL.rosetta -- |Reads a rosetta string from the first input argument and writes a haskell output to the file given as a second argument main :: IO () diff --git a/resources/Rosetta/Contracts/contractDSL.rosetta b/resources/Rosetta/Contracts/contractDSL.rosetta index ba8d0ab..c048a61 100644 --- a/resources/Rosetta/Contracts/contractDSL.rosetta +++ b/resources/Rosetta/Contracts/contractDSL.rosetta @@ -259,7 +259,7 @@ func ResolveQuantity: assign-output resolvedQuantity -> unitOfAmount: resolvedValue -> unitOfAmount - +/* func CashflowPayoutToContract: inputs: cashflow Cashflow (1..1) @@ -288,13 +288,13 @@ func CashflowPayoutToContract: PayoutParty1 ( cashflow , MkScale - ( Konst (quantity -> multiplier) + ( Konst (quantity -> multiplier only-element) , if fixingDate exists then MkGet ( MkTruncate ( fixingDate , MkScale - ( ExchangeRate(quantity -> unitOfAmount -> currency, settlementTerms -> settlementCurrency) + ( ExchangeRateFunc(quantity -> unitOfAmount, settlementTerms -> settlementCurrency) , MkGet ( MkTruncate ( settlementTerms -> settlementDate -> valueDate diff --git a/resources/Rosetta/Contracts/imports-types.rosetta b/resources/Rosetta/Contracts/imports-types.rosetta index efd2d6f..e5ac344 100644 --- a/resources/Rosetta/Contracts/imports-types.rosetta +++ b/resources/Rosetta/Contracts/imports-types.rosetta @@ -63,7 +63,7 @@ type AdjustableOrRelativeDate: adjustableDate AdjustableDate (0..1) type AdjustableDate: - unadjastableDate string (0..1) //date + unadjustedDate string (0..1) //date type ForeignExchange: exchangedCurrency1 Cashflow (1..1) diff --git a/src/Model/Type.hs b/src/Model/Type.hs index b173f35..a2528b5 100644 --- a/src/Model/Type.hs +++ b/src/Model/Type.hs @@ -64,6 +64,7 @@ data ExplicitExpression = ExplicitEmpty | ExplicitFunction {name :: String, args :: [(ExplicitExpression, Coercion)], returnCoercion :: Coercion} | ExplicitIfSimple {cond :: (ExplicitExpression, Coercion), block1 :: (ExplicitExpression, Coercion), returnCoercion :: Coercion} | ExplicitIfElse {cond :: (ExplicitExpression, Coercion), block1 :: (ExplicitExpression, Coercion), block2 :: (ExplicitExpression, Coercion), returnCoercion :: Coercion} + deriving (Eq) changeCoercion :: ExplicitExpression -> Coercion -> ExplicitExpression changeCoercion ExplicitEmpty _ = ExplicitEmpty @@ -99,7 +100,7 @@ data TypeCoercion = MakeIdCoercion {toType :: Type} | MakeSuperCoercion {fromType :: Type, toType :: Type} | MakeTypeCoercion {fromType :: Type, toType :: Type, transformType :: String} - deriving (Show) + deriving (Eq, Show) data CardinalityCoercion = MakeCardinalityIdCoercion {toCardinality :: Cardinality} @@ -109,11 +110,10 @@ data CardinalityCoercion = | MakeMaybe2ListCoercion {fromCardinality :: Cardinality, toCardinality :: Cardinality} | MakeObject2MaybeCoercion {fromCardinality :: Cardinality, toCardinality :: Cardinality} | MakeObject2ListCoercion {fromCardinality :: Cardinality, toCardinality :: Cardinality} - deriving (Show) + deriving (Eq, Show) -- |Used to handle polymorphism in Rosetta -data Coercion = MakeCoercion {typeCoercion :: [TypeCoercion], cardinalityCoercion :: CardinalityCoercion} deriving(Show) - +data Coercion = MakeCoercion {typeCoercion :: [TypeCoercion], cardinalityCoercion :: CardinalityCoercion} deriving(Eq, Show) -- |The representation of an attribute of a data type data TypeAttribute = MakeTypeAttribute { @@ -191,4 +191,7 @@ createCoercion :: (Type, Cardinality) -> Coercion createCoercion (t, c) = MakeCoercion [MakeIdCoercion t] (MakeCardinalityIdCoercion c) anyListCoercion :: Coercion -anyListCoercion = MakeCoercion [MakeIdCoercion (BasicType "Any")] (MakeCardinalityIdCoercion (OneBound 0)) \ No newline at end of file +anyListCoercion = MakeCoercion [MakeIdCoercion (BasicType "Any")] (MakeCardinalityIdCoercion (OneBound 0)) + +typeFromExpression :: ExplicitExpression -> Type +typeFromExpression = coercionType . typeCoercion . returnCoercion \ No newline at end of file diff --git a/src/Parser/Expression.hs b/src/Parser/Expression.hs index d989142..7c57b11 100644 --- a/src/Parser/Expression.hs +++ b/src/Parser/Expression.hs @@ -200,7 +200,7 @@ powerParser = boolOpParser :: Parser Expression boolOpParser = do - p <- pathExpressionParser + p <- postfixParser op <- lexeme $ observing (string "or" <|> string "and") case op of Left _ -> return p @@ -210,12 +210,16 @@ boolOpParser = postfixParser :: Parser Expression postfixParser = do - t <- listUnaryOpParser + t <- pathExpressionParser op <- lexeme $ observing $ choice $ fmap (try . string . Text.pack) postfixFunctions case op of Left _ -> return t Right o -> return $ PostfixExp (Text.unpack o) t +-- |The list of existing postfix Rosetta functions +postfixFunctions :: [String] +postfixFunctions = ["exists", "is absent", "count", "only-element", "single exists", "multiple exists"] + listUnaryOperations :: [String] listUnaryOperations = ["sum", "max", "flatten", "min", "join", "only-element", "count", "first", "last", "sort", "distinct"] @@ -277,16 +281,12 @@ nestedListOp ex = pathExpressionParser :: Parser Expression pathExpressionParser = do - var <- postfixParser + var <- listUnaryOpParser op <- lexeme $ observing $ string "->" case op of Left _ -> return var Right _ -> pathExpressionParser >>= \ex -> return $ reverseExpression $ PathExpression var ex --- |The list of existing postfix Rosetta functions -postfixFunctions :: [String] -postfixFunctions = ["exists", "is absent", "count", "only-element", "single exists", "multiple exists"] - -------------------------------------------- -- Auxiliary ------------------------------ -------------------------------------------- @@ -297,7 +297,7 @@ reverseExpression (InfixExp op t1 (InfixExp op2 t2 e)) | precedence op == precedence op2 = InfixExp op2 (reverseExpression (InfixExp op t1 t2)) e | otherwise = InfixExp op t1 (InfixExp op2 t2 e) reverseExpression (PathExpression e1 (PathExpression e2 e3)) = PathExpression (reverseExpression (PathExpression e1 e2)) e3 -reverseExpression (PathExpression e1 (ListOp op ex2 cond)) = ListOp op cond (reverseExpression (PathExpression e1 ex2)) +reverseExpression (PathExpression e1 (ListOp op ex2 cond)) = ListOp op (reverseExpression (PathExpression e1 ex2)) cond reverseExpression (PathExpression e1 (ListUnaryOp op ex2)) = ListUnaryOp op (reverseExpression (PathExpression e1 ex2)) reverseExpression (ListOp op1 (ListOp op2 ex2 con2) con1) = ListOp op2 (reverseExpression (ListOp op1 ex2 con1)) con2 reverseExpression (ListOp op1 (ListUnaryOp op2 ex2) con1) = ListUnaryOp op2 (reverseExpression (ListOp op1 ex2 con1)) diff --git a/src/PrettyPrinter/Expression.hs b/src/PrettyPrinter/Expression.hs index 13a8978..0d337dc 100644 --- a/src/PrettyPrinter/Expression.hs +++ b/src/PrettyPrinter/Expression.hs @@ -13,6 +13,7 @@ printExpression ExplicitEmpty = "[]" printExpression (ExplicitVariable name coer) | "item" `isPrefixOf` name = printCoercion coer $ pretty (replacePrefix "item" name "x") | otherwise = printCoercion coer $ pretty name +printExpression (Value "empty" coer) = printCoercion coer "[]" printExpression (Value s coer) = printCoercion coer $ pretty s printExpression (ExplicitKeyword k) = pretty k printExpression (ExplicitEnumCall name val coer) = printCoercion coer $ pretty name <> pretty val @@ -24,11 +25,13 @@ printExpression (ExplicitListOp op lst cond coer) = pretty op <+> nest 4 (vsep [ printExpression (ExplicitListUnaryOp "only-element" lst coer) = "head" <+> enclose "(" ")" (nest 4 (line <> printExpression lst)) printExpression (ExplicitListUnaryOp "flatten" lst coer) = "concat" <+> enclose "(" ")" (nest 4 (line <> printExpression lst)) printExpression (ExplicitListUnaryOp op lst coer) = pretty op <+> nest 4 (printExpression lst) -printExpression (ExplicitPath ex1 (ExplicitVariable var ret) returnCoerce) = - pretty (uncapitalize $ typeName $ coercionType $ typeCoercion $ returnCoercion ex1) <> pretty (capitalize var) <+> - enclose "(" ")" (printExpression ex1) +printExpression (ExplicitPath ex1 (ExplicitVariable var ret) returnCoerce)= + pretty (uncapitalize $ typeName $ typeFromExpression ex1) <> pretty (capitalize var) <+> nest 4 (line <> + enclose "(" ")" (printCoercion (returnCoercion ex1) (printExpression (ex1{returnCoercion = MakeCoercion [MakeIdCoercion (typeFromExpression ex1)] (MakeCardinalityIdCoercion (Bounds (1,1)))})))) printExpression ExplicitPath {} = error "This should never happen. Path Expression 2nd argument is not variable" -printExpression (ExplicitFunction "exists" args returnCoerce) = printCoercion returnCoerce "isJust" <+> printCoercion (snd $ head args) (printExpression (fst $ head args)) +printExpression (ExplicitFunction "exists" args returnCoerce) + | toCardinality (cardinalityCoercion (snd (head args))) == Bounds (0, 1) = printCoercion returnCoerce "isJust" <+> enclose "(" ")" (printCoercion (snd $ head args) (printExpression (fst $ head args))) + | otherwise = printCoercion returnCoerce "length" <+> enclose "(" ")" (printCoercion (snd $ head args) (printExpression (fst $ head args))) <+> ">=" <+> "1" printExpression (ExplicitFunction "is absent" args returnCoerce) = printCoercion returnCoerce "isNothing" <+> printCoercion (snd $ head args) (printExpression (fst $ head args)) printExpression (ExplicitFunction "single exists" args returnCoerce) = printCoercion returnCoerce "length" <+> printCoercion (snd $ head args) (printExpression (fst $ head args)) <+> "==" <+> "1" printExpression (ExplicitFunction "multiple exists" args returnCoerce) = printCoercion returnCoerce "length" <+> printCoercion (snd $ head args) (printExpression (fst $ head args)) <+> ">" <+> "1" @@ -45,38 +48,90 @@ printExpression (ExplicitFunction "and" args returnCoerce) = printCoercion (snd printExpression (ExplicitFunction "or" args returnCoerce) = printCoercion (snd $ head args) (printExpression (fst $ head args)) <+> "||" <+> printCoercion (snd $ head $ tail args) (printExpression (fst $ head $ tail args)) printExpression (ExplicitFunction name args returnCoerce) = if null printedArgs then pretty (uncapitalize name) - else "(" <> pretty (uncapitalize name) <+> printCoercion returnCoerce (hsep printedArgs) <> ")" + else pretty (uncapitalize name) <+> printCoercion returnCoerce (hsep (map (enclose "(" ")") printedArgs)) where printedArgs = zipWith printCoercion [c | (e,c) <- args] [printExpression e | (e, c) <- args] -printExpression (ExplicitIfSimple cond thenBlock returnCoercion) = - "if" <+> printCoercion (snd cond) (printExpression (fst cond)) <+> - "then" <+> printCoercion (snd thenBlock) (printExpression (fst thenBlock)) <+> - "else" <+> case MakeCoercion [MakeIdCoercion $ coercionType $ typeCoercion returnCoercion] (MakeCardinalityIdCoercion (Bounds (0, 0))) `coercionIncluded` returnCoercion of - Left err -> error $ show err - Right c -> printCoercion c emptyDoc -printExpression (ExplicitIfElse cond thenBlock elseBlock returnCoercion) = - "if" <+> printCoercion (snd cond) (printExpression (fst cond)) <+> - "then" <+> printCoercion (snd thenBlock) (printExpression (fst thenBlock)) <+> - "else" <+> printCoercion (snd elseBlock) (printExpression (fst elseBlock)) +printExpression (ExplicitIfSimple cond thenBlock returnCoercion) = + printIf + (printCoercion (snd cond) (printExpression (fst cond))) + (printCoercion (snd thenBlock) (printExpression (fst thenBlock))) + (case MakeCoercion [MakeIdCoercion $ coercionType $ typeCoercion returnCoercion] (MakeCardinalityIdCoercion (Bounds (0, 0))) `coercionIncluded` returnCoercion of + Left err -> error $ show err + Right c -> printCoercion c emptyDoc) + +printExpression (ExplicitIfElse (ExplicitFunction op e rc, c) thenBlock elseBlock _) + | op `elem` ["exists", "only exists"] = case isOneOf (fst (head e)) of + Nothing -> printIf + (printCoercion c (printExpression (ExplicitFunction op e rc))) + (printCoercion (snd thenBlock) (printExpression (fst thenBlock))) + (printCoercion (snd elseBlock) (printExpression (fst elseBlock))) + Just ex -> "case" <+> printExpression (fst ex) <+> "of" <+> nest 4 + (line <> pretty (typeName (typeFromExpression (fst ex))) <> pretty (typeName (typeFromExpression (snd ex))) <+> "x" <+> "->" + <+> printCoercion (snd thenBlock) (printExpression (replace (fst (head e)) (fst thenBlock) "x")) <> line <> + getCases elseBlock) + + | otherwise = + printIf (printCoercion c (printExpression (ExplicitFunction op e rc))) + (printCoercion (snd thenBlock) (printExpression (fst thenBlock))) + (printCoercion (snd elseBlock) (printExpression (fst elseBlock))) + +printExpression (ExplicitIfElse cond thenBlock elseBlock _) = + printIf + (printCoercion (snd cond) (printExpression (fst cond))) + (printCoercion (snd thenBlock) (printExpression (fst thenBlock))) + (printCoercion (snd elseBlock) (printExpression (fst elseBlock))) + +printIf :: Doc a -> Doc a -> Doc a -> Doc a +printIf cond thenBlock elseBlock = "if" <+> cond <+> nest 4 ( line <> + "then" <+> thenBlock <+> line <> + "else" <+> elseBlock) -- |Converts a coercion into a haskell string printCoercion :: Coercion -> Doc a -> Doc a printCoercion (MakeCoercion [] crd) d = printCardinalityCoercion crd d -printCoercion (MakeCoercion (t: ts) crd) d = printTypeCoercion t <> printCoercion (MakeCoercion ts crd) d +printCoercion (MakeCoercion (t: ts) crd) d = printCoercion (MakeCoercion ts crd) d <> printTypeCoercion t printCardinalityCoercion :: CardinalityCoercion -> Doc a -> Doc a printCardinalityCoercion (MakeCardinalityIdCoercion _) d = d printCardinalityCoercion (MakeListCardinalityCoercion _ _) d = d printCardinalityCoercion (MakeNothing2MaybeCoercion _ _) d = "Nothing" printCardinalityCoercion (MakeNothing2ListCoercion _ _) d = "[]" -printCardinalityCoercion (MakeMaybe2ListCoercion _ _) d = "maybeToList" <+> d -printCardinalityCoercion (MakeObject2MaybeCoercion _ _) d = "Just" <+> d +printCardinalityCoercion (MakeMaybe2ListCoercion _ _) d = "maybeToList" <+> enclose "(" ")" d +printCardinalityCoercion (MakeObject2MaybeCoercion _ _) d = "fromJust" <+> enclose "(" ")" d printCardinalityCoercion (MakeObject2ListCoercion _ _) d = "[" <> d <> "]" printTypeCoercion :: TypeCoercion -> Doc a printTypeCoercion (MakeIdCoercion _) = emptyDoc -printTypeCoercion (MakeSuperCoercion _ _) = "super" <+> emptyDoc -printTypeCoercion (MakeTypeCoercion _ _ t) = pretty t <+> emptyDoc +printTypeCoercion (MakeSuperCoercion _ _) = "Super" +printTypeCoercion (MakeTypeCoercion _ _ t) = pretty t -- |Converts a list of type attributes to a Doc with a list of variable names printVariableNames :: [TypeAttribute] -> Doc a -printVariableNames vars = foldl (<+>) emptyDoc (map (pretty . attributeName) vars) \ No newline at end of file +printVariableNames vars = foldl (<+>) emptyDoc (map (pretty . attributeName) vars) + +isOneOf :: ExplicitExpression -> Maybe (ExplicitExpression, ExplicitExpression) +isOneOf (ExplicitPath e1 e2 c) + | not (null (conditions (typeFromExpression e1))) && + MakeCondition Nothing (Keyword "one-of") `elem` conditions (typeFromExpression e1) = Just (e1, e2) + | otherwise = Nothing +isOneOf _ = Nothing + +getCases :: (ExplicitExpression, Coercion) -> Doc a +getCases (ExplicitIfElse (ExplicitFunction op e rc, c) thn els coer, retCoer) + | op `elem` ["exists", "only exists"] = case isOneOf (fst (head e)) of + Nothing -> "_" <+> "->" <+> printExpression (ExplicitIfElse (ExplicitFunction op e rc, c) thn els coer) + Just ex -> pretty (typeName (typeFromExpression (fst ex))) <> pretty (typeName (typeFromExpression (snd ex))) <+> "x" <+> "->" + <+> printCoercion (snd thn) (printExpression (replace (fst (head e)) (fst thn) "x")) <> line <> + getCases els +getCases (e, c) = "_" <+> "->" <+> printCoercion c (printExpression e) + +replace :: ExplicitExpression -> ExplicitExpression -> String -> ExplicitExpression +replace e1 (ExplicitPath pe1 pe2 c) x + | e1 == ExplicitPath pe1 pe2 c = ExplicitVariable x c + | otherwise = ExplicitPath (replace e1 pe1 x) pe2 c +replace e1 (ExplicitListUnaryOp op e2 c) x = ExplicitListUnaryOp op (replace e1 e2 x) c +replace e1 (ExplicitListOp op e2 cond c) x = ExplicitListOp op (replace e1 e2 x) (replace e1 cond x) c +replace e1 (ExplicitParens e2 c) x = ExplicitParens (replace e1 e2 x) c +replace e1 (ExplicitFunction op e2 c) x = ExplicitFunction op [(replace e1 (fst e) x, snd e) | e <- e2] c +replace e1 (ExplicitIfSimple cond e2 c) x = ExplicitIfSimple (replace e1 (fst cond) x, snd cond) (replace e1 (fst e2) x, snd e2) c +replace e1 (ExplicitIfElse cond thn els c) x = ExplicitIfElse (replace e1 (fst cond) x, snd cond) (replace e1 (fst thn) x, snd thn) (replace e1 (fst els) x, snd els) c +replace _ e _ = e \ No newline at end of file diff --git a/src/PrettyPrinter/Function.hs b/src/PrettyPrinter/Function.hs index 438f574..a5322c3 100644 --- a/src/PrettyPrinter/Function.hs +++ b/src/PrettyPrinter/Function.hs @@ -40,7 +40,7 @@ printFunction f = show $ vcat [printFunctionSignature (sign f), printFunctionBod -- |Converts the body of a Function into a haskell valid Doc printFunctionBody :: ExplicitFunction -> Doc a -printFunctionBody (MakeExplicitFunction (MakeFunctionSignature name _ inp out) alias ex) = +printFunctionBody (MakeExplicitFunction (MakeFunctionSignature name _ inp out) alias ex) = pretty name <+> printVariableNames inp <+> "=" <+> nest 4 (vsep (map printAlias alias ++ [printAssignmentTree (head $ mergeAssignmentTrees [convertToAssignmentTree (fst exp) (AssignmentLeaf (snd exp)) | exp <- ex])])) diff --git a/src/PrettyPrinter/Header.hs b/src/PrettyPrinter/Header.hs index 5c04737..aa5df2d 100644 --- a/src/PrettyPrinter/Header.hs +++ b/src/PrettyPrinter/Header.hs @@ -14,11 +14,15 @@ printHeader (MakeHeader name (Just description) _ imports) = show $ vcat ["module" <+> pretty (removePeriods name) <+> "where", enclose "{-" "-}" (pretty description), emptyDoc, + "import" <+> "Data.List", + "import" <+> "Data.Maybe", vcat (map printImport imports), emptyDoc] printHeader (MakeHeader name Nothing _ imports) = show $ vcat ["module" <+> pretty (removePeriods name) <+> "where", emptyDoc, + "import" <+> "Data.List", + "import" <+> "Data.Maybe", vcat (map printImport imports), emptyDoc] diff --git a/src/PrettyPrinter/Type.hs b/src/PrettyPrinter/Type.hs index a27ff01..7b8920a 100644 --- a/src/PrettyPrinter/Type.hs +++ b/src/PrettyPrinter/Type.hs @@ -33,6 +33,7 @@ printAttributes :: String -> [Condition] -> [TypeAttribute] -> Doc a printAttributes objName conditions ats | MakeCondition Nothing (Keyword "one-of") `elem` conditions = vcat [nest 4 $ vcat $ zipWith (<>) ("" : repeat "| ") (map (printSumType objName) (increaseBound ats)) ++ map printCondition conditions, " deriving (Eq)"] + | null ats = emptyDoc | length ats < 2 = vcat [nest 4 $ vcat $ zipWith (<>) ("" : repeat "| ") (map (printSumType objName) ats) ++ map printCondition conditions, " deriving (Eq)", printDefault objName (objName ++ capitalize (attributeName (head ats))) ats] | otherwise = vcat [nest 4 $ vcat ("Make" <> pretty objName <+> "{" : diff --git a/src/Semantic/ExpressionChecker.hs b/src/Semantic/ExpressionChecker.hs index 9393d92..d727a78 100644 --- a/src/Semantic/ExpressionChecker.hs +++ b/src/Semantic/ExpressionChecker.hs @@ -34,7 +34,7 @@ defaultMap :: [Symbol] defaultMap = [ Func "or" [(BasicType "Boolean", Bounds (1, 1)), (BasicType "Boolean", Bounds (1, 1))] (BasicType "Boolean", Bounds (1, 1)), Func "and" [(BasicType "Boolean", Bounds (1, 1)), (BasicType "Boolean", Bounds (1, 1))] (BasicType "Boolean", Bounds (1, 1)), - Func "exists" [(BasicType "Any", Bounds (0, 1))] (BasicType "Boolean", Bounds(1, 1)), + Func "exists" [(BasicType "Any", OneBound 0)] (BasicType "Boolean", Bounds(1, 1)), Func "is absent" [(BasicType "Any", Bounds (0, 1))] (BasicType "Boolean", Bounds (1, 1)), Func "single exists" [(BasicType "Any", OneBound 0)] (BasicType "Boolean", Bounds (1, 1)), Func "multiple exists" [(BasicType "Any", OneBound 0)] (BasicType "Boolean", Bounds (1, 1)), @@ -80,8 +80,15 @@ listFunctionTypes :: Coercion -> Coercion -> [(String, Coercion, Coercion)] listFunctionTypes inp ex = [ -- The function given to a filter must be boolean and it can return anything ("filter", MakeCoercion [MakeIdCoercion (BasicType "Boolean")] (MakeCardinalityIdCoercion (OneBound 0)), inp), - ("map", MakeCoercion [MakeIdCoercion (BasicType "Any")] (MakeCardinalityIdCoercion (OneBound 0)), ex) - ] + ("map", MakeCoercion [MakeIdCoercion (BasicType "Any")] (MakeCardinalityIdCoercion (OneBound 0)), MakeCoercion (typeCoercion ex) (cardinalityCoercion inp)), + ("reduce", MakeCoercion [MakeIdCoercion (BasicType "Any")] (MakeCardinalityIdCoercion (Bounds (1, 1))), ex) + ] + +listUnaryFunctionTypes :: Coercion -> [(String, Coercion)] +listUnaryFunctionTypes inp = [ + ("only-element", MakeCoercion (typeCoercion inp) (MakeCardinalityIdCoercion (Bounds (1, 1)))), + ("flatten", inp) + ] -- |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] @@ -104,7 +111,7 @@ addVariables s ((MakeTypeAttribute name typ crd _) : vars) = Var name (toHaskel -- |Checks the type of a given expression checkExpression :: [Type] -> [Symbol] -> Expression -> Either TypeCheckError ExplicitExpression --checkExpression sym _ = error $ show sym -checkExpression defT symbolMap (Variable var) = findVarType var symbolMap +checkExpression _ symbolMap (Variable var) = findVarType var symbolMap checkExpression _ _ (Int val) = Right $ Value val $ MakeCoercion [MakeIdCoercion (BasicType "Integer")] (MakeCardinalityIdCoercion (Bounds (1, 1))) checkExpression _ _ (Real val) = Right $ Value val $ MakeCoercion [MakeIdCoercion (BasicType "Double")] (MakeCardinalityIdCoercion (Bounds (1, 1))) checkExpression _ _ (Boolean val) = Right $ Value val $ MakeCoercion [MakeIdCoercion (BasicType "Boolean")] (MakeCardinalityIdCoercion (Bounds (1, 1))) @@ -116,16 +123,16 @@ checkExpression defT symbolMap (Enum enum val) = case getType enum defT of else Left $ UndefinedVariable val checkExpression defT symbolMap (ListOp op lst cond) = case checkExpression defT symbolMap lst of - Left err -> Left err + Left err -> Left $ ErrorInsideFunction $ op ++ ": " ++ show err Right checkedLst -> if toCardinality (cardinalityCoercion (returnCoercion checkedLst)) == Bounds(1, 1) - then Left $ ListOperationNotOnList $ show lst + then Left $ ListOperationNotOnList $ show op ++ ": " ++ show lst else let it = getNextItem symbolMap in case checkExpression defT - (addVariables symbolMap [MakeTypeAttribute it (coercionType $ typeCoercion $ returnCoercion checkedLst) (toCardinality $ cardinalityCoercion $ returnCoercion checkedLst) Nothing]) + (addVariables symbolMap [MakeTypeAttribute it (typeFromExpression checkedLst) (Bounds (1,1)) Nothing]) (replaceVar cond it) of - Left err -> Left err + Left err -> Left $ ErrorInsideFunction $ op ++ ": " ++ show err Right condType -> case returnCoercion condType `coercionIncluded` head [snd3 x | x <- listOps, fst3 x == op] of - Left err -> Left err + Left err -> Left $ ErrorInsideFunction $ op ++ ": " ++ show err Right checkedCond -> Right $ ExplicitListOp op checkedLst (changeCoercion condType checkedCond) (head [trd3 x | x <- listOps, fst3 x == op]) where listOps = listFunctionTypes (returnCoercion checkedLst) (returnCoercion condType) @@ -133,17 +140,22 @@ checkExpression defT symbolMap (ListUnaryOp op lst) = case checkExpression defT symbolMap lst of Left err -> Left $ ErrorInsideFunction $ op ++ ": " ++ show err Right checkedLst -> if toCardinality (cardinalityCoercion (returnCoercion checkedLst)) == Bounds(1, 1) - then Left $ ListOperationNotOnList $ show lst - else Right $ ExplicitListUnaryOp op checkedLst (returnCoercion checkedLst) + then Left $ ListOperationNotOnList $ show op ++ ": " ++ show lst + else if op `elem` map fst (listUnaryFunctionTypes (returnCoercion checkedLst)) + then Right $ ExplicitListUnaryOp op checkedLst (head [snd x | x <- listUnaryFunctionTypes (returnCoercion checkedLst), fst x == op]) + else Left $ UndefinedFunction op checkExpression _ _ (Keyword k) = Right $ ExplicitKeyword k -checkExpression defT symbolMap (PathExpression ex1 (Variable b)) = +checkExpression defT symbolMap (PathExpression ex1 (Variable b)) = case checkExpression defT symbolMap ex1 of Left err -> Left err Right exp1 -> case findAttributeTypeRec defT b type1 of Left err -> Left $ UndefinedVariable $ show (typeName type1) ++ " -> " ++ b - Right exp2 -> Right $ ExplicitPath exp1 exp2 (returnCoercion exp2) + Right exp2 -> case Bounds(1, 1) `cardinalityIncluded` crd1 of + Left err -> Left $ PathExpressionOnList (show ex1) + Right c -> Right $ ExplicitPath (changeCoercion exp1 ((returnCoercion exp1){cardinalityCoercion = c})) exp2 (returnCoercion exp2) where - type1 = coercionType $ typeCoercion $ returnCoercion exp1 + type1 = typeFromExpression exp1 + crd1 = toCardinality $ cardinalityCoercion $ returnCoercion exp1 -- |Getting here means that an expression is used inside a path expression and this is not supported checkExpression _ _ (PathExpression _ ex) = Left $ UnsupportedExpressionInPathExpression $ show ex --checkExpression symbolMap (PathExpression ex1 (PathExpression )) @@ -161,17 +173,17 @@ checkExpression defT symbolMap (IfSimple cond ex) = case checkExpression defT symbolMap cond of Left err -> Left $ IfConditionNotBoolean $ show err Right condType -> case returnCoercion condType `coercionIncluded` MakeCoercion [MakeIdCoercion (BasicType "Boolean")] (MakeCardinalityIdCoercion (Bounds (1, 1))) of - Left err -> Left $ IfConditionNotBoolean $ show cond ++ " :: " ++ show (coercionType $ typeCoercion $ returnCoercion condType) + Left err -> Left $ IfConditionNotBoolean $ show cond ++ " :: " ++ show (typeFromExpression condType) Right condCoerce -> case checkExpression defT symbolMap ex of Left err -> Left err Right thenExp -> Right $ ExplicitIfSimple (condType, condCoerce) (thenExp, thenCoercion) - (MakeCoercion [MakeIdCoercion $ coercionType $ typeCoercion $ returnCoercion thenExp] + (MakeCoercion [MakeIdCoercion $ typeFromExpression thenExp] (MakeCardinalityIdCoercion $ smallestBound (Bounds (0, 0)) (toCardinality $ cardinalityCoercion $ returnCoercion thenExp))) where - thenCoercion = MakeCoercion [MakeIdCoercion $ coercionType $ typeCoercion $ returnCoercion thenExp] + thenCoercion = MakeCoercion [MakeIdCoercion $ typeFromExpression thenExp] (MakeCardinalityIdCoercion $ toCardinality $ cardinalityCoercion $ returnCoercion thenExp) -- |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 @@ -179,7 +191,7 @@ checkExpression defT symbolMap (IfElse cond ex1 ex2) = case checkExpression defT symbolMap cond of Left err -> Left $ IfConditionNotBoolean $ show err Right condType -> case returnCoercion condType `coercionIncluded` MakeCoercion [MakeIdCoercion (BasicType "Boolean")] (MakeCardinalityIdCoercion (Bounds (1, 1))) of - Left err -> Left $ IfConditionNotBoolean $ show cond ++ " :: " ++ show (coercionType $ typeCoercion $ returnCoercion condType) + Left err -> Left $ IfConditionNotBoolean $ show cond ++ " :: " ++ show (typeFromExpression condType) Right condCoerce -> case checkExpression defT symbolMap ex1 of Left err -> Left $ ErrorInsideFunction $ show err @@ -187,9 +199,9 @@ checkExpression defT symbolMap (IfElse cond ex1 ex2) = Left err -> Left $ ErrorInsideFunction $ show err Right elseExp -> Right $ ExplicitIfElse (condType, condCoerce) - (thenExp, MakeCoercion [MakeIdCoercion $ coercionType $ typeCoercion $ returnCoercion thenExp] + (thenExp, MakeCoercion [MakeIdCoercion $ typeFromExpression thenExp] (MakeCardinalityIdCoercion $ toCardinality $ cardinalityCoercion $ returnCoercion thenExp)) - (elseExp, MakeCoercion [MakeIdCoercion $ coercionType $ typeCoercion $ returnCoercion elseExp] + (elseExp, MakeCoercion [MakeIdCoercion $ typeFromExpression elseExp] (MakeCardinalityIdCoercion $ toCardinality $ cardinalityCoercion $ returnCoercion elseExp)) (returnCoercion thenExp) --(typeMatch ex1Type ex2Type, smallestBound ex1Card ex2Type) @@ -201,7 +213,7 @@ checkList defT symbs (ex : exps) = case checkExpression defT symbs ex of Left err -> Left err Right x -> - case checkList1 defT symbs exps (coercionType $ typeCoercion $ returnCoercion x, toCardinality $ cardinalityCoercion $ returnCoercion x) of + case checkList1 defT symbs exps (typeFromExpression x, toCardinality $ cardinalityCoercion $ returnCoercion x) of Left err -> Left err Right exp -> Right $ ExplicitList exp @@ -219,12 +231,13 @@ checkList1 defT symbs (ex : exps) typ = Left err -> Left err Right explicitEx -> Right [ExplicitList explicitEx] where - exTyp = coercionType $ typeCoercion $ returnCoercion exCo + exTyp = typeFromExpression exCo exCard = toCardinality $ cardinalityCoercion $ returnCoercion exCo -- |Checks whether the function that is called is already defined with the same argument types checkFunctionCall :: [Symbol] -> String -> [Either TypeCheckError ExplicitExpression ] -> Either TypeCheckError ExplicitExpression -checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: " ++ fun ++ " [" ++ show (rights args) ++ "]" +checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: " ++ fun ++ " [" + ++ show [(typeName $ typeFromExpression x, toCardinality $ cardinalityCoercion $ returnCoercion x) | x <- rights args] ++ "]" checkFunctionCall ((Func n a r):symbolMap) name args | not $ null $ lefts args = Left $ ErrorInsideFunction (name ++ ": " ++ show (lefts args)) | name == n = if all isRight coerce then Right $ ExplicitFunction name (zip (rights args) (rights coerce)) (MakeCoercion [MakeIdCoercion (fst r)] (MakeCardinalityIdCoercion (snd r))) @@ -282,8 +295,8 @@ findVarType x (_:symbols) = findVarType x symbols -- |Look for a type attribute in a given type and its super types findAttributeTypeRec :: [Type] -> String -> Type -> Either TypeCheckError ExplicitExpression findAttributeTypeRec _ var (BasicType _) = Left $ UndefinedVariable var -findAttributeTypeRec sTable var t = case findAttributeType var (getTypeAttributes sTable t) of - Left err -> case findAttributeTypeRec sTable var (superType t) of +findAttributeTypeRec defT var t = case findAttributeType var (getTypeAttributes defT t) of + Left err -> case findAttributeTypeRec defT var (superType t) of Left err -> Left err Right (ExplicitVariable n (MakeCoercion tc cc)) -> Right $ ExplicitVariable n @@ -316,6 +329,7 @@ replaceVar e _ = e -- |Checks whether the first argument is a subtype of the second argument isSubType :: Type -> Type -> Either TypeCheckError [TypeCoercion] +isSubType (BasicType "Empty") _ = Right [MakeIdCoercion (BasicType "Empty")] isSubType (BasicType "Integer") (BasicType "Double") = Right [MakeTypeCoercion (BasicType "Integer") (BasicType "Double") "fromInteger"] isSubType t (BasicType "Any") = Right [MakeIdCoercion t] isSubType (BasicType x) y @@ -335,14 +349,16 @@ getNextItem symbs -- |Finds the type attributes from a type in the symbol table getTypeAttributes :: [Type] -> Type -> [TypeAttribute] getTypeAttributes [] t = [] -getTypeAttributes (defT : ts) t - | typeName defT == typeName t = +getTypeAttributes defT t + | t `elem` defT = let typ = head [x | x <- defT, x == t] in [MakeTypeAttribute {attributeName = attributeName attr, - attributeType = toHaskell (attributeType attr), - Model.Type.cardinality = if MakeCondition Nothing (Keyword "one-of") `elem` conditions defT then Bounds (1,1) else Model.Type.cardinality attr, + attributeType = case getType (typeName $ attributeType attr) defT of + Left _ -> toHaskell (attributeType attr) + Right atTyp -> atTyp, + Model.Type.cardinality = Model.Type.cardinality attr, attributeDescription = attributeDescription attr} - | attr <- typeAttributes defT] - | otherwise = getTypeAttributes ts t + | attr <- typeAttributes typ] + | otherwise = [] -- |Checks whether the first cardinality is included into the second one cardinalityIncluded :: Cardinality -> Cardinality -> Either TypeCheckError CardinalityCoercion @@ -354,18 +370,20 @@ cardinalityIncluded (Bounds (0, 0)) (OneBound 0) = Right $ MakeNothing2ListCoerc -- |Transform maybe into list cardinalityIncluded (Bounds (0, 1)) (OneBound 0) = Right $ MakeMaybe2ListCoercion (Bounds (0, 1)) (OneBound 0) -- |Transform object into maybe -cardinalityIncluded (Bounds (1, 1)) (Bounds (0, 1)) = Right $ MakeObject2MaybeCoercion (Bounds (0, 1)) (Bounds (0, 1)) +cardinalityIncluded (Bounds (1, 1)) (Bounds (0, 1)) = Right $ MakeObject2MaybeCoercion (Bounds (1, 1)) (Bounds (0, 1)) -- |Transform object into list -cardinalityIncluded (Bounds (1, 1)) (OneBound 1) = Right $ MakeObject2ListCoercion (Bounds (0, 1)) (OneBound 1) -cardinalityIncluded (Bounds (1, 1)) (OneBound 0) = Right $ MakeObject2ListCoercion (Bounds (0, 1)) (OneBound 1) +cardinalityIncluded (Bounds (1, 1)) (OneBound 1) = Right $ MakeObject2ListCoercion (Bounds (1, 1)) (OneBound 1) +cardinalityIncluded (Bounds (1, 1)) (OneBound 0) = Right $ MakeObject2ListCoercion (Bounds (1, 1)) (OneBound 1) -- |General cardinalityIncluded (OneBound x) (OneBound y) - | x >= y = Right $ MakeListCardinalityCoercion (OneBound x) (OneBound y) + | x == y = Right $ MakeCardinalityIdCoercion (OneBound x) + | x > y = Right $ MakeListCardinalityCoercion (OneBound x) (OneBound y) | otherwise = Left $ CardinalityMismatch (OneBound x) (OneBound y) cardinalityIncluded (Bounds (x1, y1)) (OneBound y) | x1 >= y = Right $ MakeListCardinalityCoercion (Bounds (x1, y1)) (OneBound y) | otherwise = Left $ CardinalityMismatch (Bounds (x1, y1)) (OneBound y) cardinalityIncluded (OneBound x) (Bounds (x2, y2)) = Left $ CardinalityMismatch (OneBound x) (Bounds (x2, y2)) cardinalityIncluded (Bounds (x1, x2)) (Bounds (y1, y2)) + | x1 == y1 && x2 == y2 = Right $ MakeCardinalityIdCoercion (Bounds (x1, x2)) | x1 >= y1 && x2 <= y2 = Right $ MakeListCardinalityCoercion (Bounds (x1, x2)) (Bounds (y1, y2)) | otherwise = Left $ CardinalityMismatch (Bounds (x1, x2)) (Bounds (y1, y2)) diff --git a/src/Semantic/FunctionChecker.hs b/src/Semantic/FunctionChecker.hs index 256cebc..6a00b1d 100644 --- a/src/Semantic/FunctionChecker.hs +++ b/src/Semantic/FunctionChecker.hs @@ -42,10 +42,10 @@ checkAssignment defT symbs ((assign, ex): assigns) = addAliases :: [Type] -> [Symbol] -> [(String, Expression)] -> Either TypeCheckError ([Symbol], [(String, ExplicitExpression)]) addAliases definedTypes symbolMap [] = Right (symbolMap, []) -addAliases definedTypes symbolMap (alias : aliases) = +addAliases definedTypes symbolMap (alias : aliases) = case checkExpression definedTypes symbolMap (snd alias) of Left err -> Left err Right ex -> case add of Left err -> Left err Right added -> Right (fst added, (fst alias, ex) : snd added) - where add = addAliases definedTypes (addVariables symbolMap [MakeTypeAttribute (fst alias) (coercionType $ typeCoercion $ returnCoercion ex) (toCardinality $ cardinalityCoercion $ returnCoercion ex) Nothing]) aliases \ No newline at end of file + where add = addAliases definedTypes (addVariables symbolMap [MakeTypeAttribute (fst alias) (typeFromExpression ex) (toCardinality $ cardinalityCoercion $ returnCoercion ex) Nothing]) aliases \ No newline at end of file diff --git a/src/Semantic/TypeChecker.hs b/src/Semantic/TypeChecker.hs index d0772eb..12f7594 100644 --- a/src/Semantic/TypeChecker.hs +++ b/src/Semantic/TypeChecker.hs @@ -18,6 +18,7 @@ data TypeCheckError = | TypeNameReserved String | UnsupportedExpressionInPathExpression String | ListOperationNotOnList String + | PathExpressionOnList String deriving (Show) -- |Checks whether a data type is valid