changed compiler to whole folder

This commit is contained in:
Radu Macocian
2022-08-08 03:06:47 +02:00
parent 18b7e778a2
commit 24bfeea014
17 changed files with 711 additions and 84 deletions

3
.gitignore vendored
View File

@@ -26,4 +26,5 @@ cabal.project.local~
.vscode/ .vscode/
/resources/Rosetta/Try/ /resources/Rosetta/Try/
/resources/fxspot.json /resources/fxspot.json
/resources/european contract.json /resources/european contract.json
/resources/CDM/

View File

@@ -53,6 +53,8 @@ library
src src
build-depends: build-depends:
base >=4.7 && <5 base >=4.7 && <5
, directory
, filepath
, megaparsec , megaparsec
, mtl , mtl
, parser-combinators , parser-combinators
@@ -69,6 +71,8 @@ executable RosettaParser-exe
build-depends: build-depends:
RosettaParser RosettaParser
, base >=4.7 && <5 , base >=4.7 && <5
, directory
, filepath
, megaparsec , megaparsec
, mtl , mtl
, parser-combinators , parser-combinators
@@ -93,6 +97,8 @@ test-suite RosettaParser-test
build-depends: build-depends:
RosettaParser RosettaParser
, base >=4.7 && <5 , base >=4.7 && <5
, directory
, filepath
, hspec , hspec
, hspec-megaparsec , hspec-megaparsec
, megaparsec , megaparsec

View File

@@ -1,3 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}
module Main where module Main where
import Parser.Enum import Parser.Enum
@@ -15,6 +17,7 @@ import Semantic.TypeChecker
import Semantic.ExpressionChecker import Semantic.ExpressionChecker
import Semantic.FunctionChecker import Semantic.FunctionChecker
import Model.Type import Model.Type
import Model.Function
import System.Environment.Blank (getArgs) import System.Environment.Blank (getArgs)
import Model.Enum import Model.Enum
import Data.Either import Data.Either
@@ -23,63 +26,125 @@ import Parser.Header
import PrettyPrinter.Header import PrettyPrinter.Header
import Data.Tuple (fst, snd) import Data.Tuple (fst, snd)
import Data.Void import Data.Void
import System.FilePath
import Utils.Utils import Utils.Utils
import System.Directory
import Data.List
import Data.Text (Text) import Data.Text (Text)
import Parser.Expression (expressionParser) import Parser.Expression (expressionParser)
-- :l resources/Generated/ContractDSL.hs resources/Generated/ImportsTypes.hs resources/Generated/ImportsEnums.hs -- :l resources/Generated/ContractDSL.hs resources/Generated/ImportsType.hs resources/Generated/ImportsEnum.hs
-- :set args resources/Rosetta/Contracts/contractDSL.rosetta -- :set args resources/Rosetta/Contracts/
-- :set args resources/CDM/
-- |Reads a rosetta string from the first input argument and writes a haskell output to the file given as a second argument -- |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
let mainFile = head args let mainFolder = head args
parseResult <- parseWithImport mainFile files <- getDirectoryContents mainFolder
let checked = checkObjects parseResult parseResult <- parseFolder [mainFolder ++ f | f <- files, f `notElem` [".", ".."]]
let completeFiles = [createSymbolTable f parseResult | f <- parseResult]
let checked = checkObjects completeFiles
let headers = fstlst checked let headers = fstlst checked
let objects = nestedRights $ sndlst checked let objects = nestedRights $ sndlst checked
--_ <- error $ show [(map typeName t, map symbolName s) | (path, t, s, (head, obj)) <- completeFiles, path == "resources/Rosetta/Contracts/contractDSL.rosetta"]
if null $ lefts $ concat $ sndlst checked if null $ lefts $ concat $ sndlst checked
then then
let input = pairRights checked in let input = pairRights checked in
mapM_ generateFile input mapM_ generateFile input
else error $ show $ lefts $ concat $ sndlst checked else error $ show $ lefts $ concat $ sndlst checked
{- |Recursively parse a file and all the imports into a list of headers and objects {- | Parse the contents of a folder, skip any files without the Rosetta extension
The first argument is the default directory, second argument is the file name Return a list of Header, Rosettaobject, filename pairs
-} -}
parseWithImport :: String -> IO [(([Type], [Symbol]), (Header, [RosettaObject]))] parseFolder :: [FilePath] -> IO [(FilePath, Header, [RosettaObject])]
parseWithImport file = parseFolder [] = return []
parseFolder (file : files) = do
plain <- readFile file
rest <- parseFolder files
case parseFile plain of
Left errorBundle -> error $ errorBundlePretty errorBundle ++ " on file " ++ file
Right (header, objs) ->
return ((file, header, objs) : rest)
-- | Create the symbol table for each file from the imported types enums and functions
createSymbolTable :: (FilePath, Header, [RosettaObject]) -> [(FilePath, Header, [RosettaObject])] -> (FilePath, [Type], [Symbol], (Header, [RosettaObject]))
createSymbolTable (file, MakeHeader name desc ver imp, objs) imps =
(file, concat (fstlst imports), concat (sndlst imports), (MakeHeader name desc ver actualImport, objs))
where
imports = [(getTypes imObjs, getFunctions imObjs) | (_, MakeHeader imName _ _ _, imObjs) <- imps, imName `elem` map getNamespace imp || imName == name]
actualImport =
[removeChar (takeFileName (dropExtension p)) '-' | (p, MakeHeader imName _ _ _, imObjs) <- imps, imName `elem` map getNamespace imp
|| (imName == name && p /= file && not ("enum.rosetta" `isSuffixOf` file) && not ("type.rosetta" `isSuffixOf` file && "func.rosetta" `isSuffixOf` p))]
-- |Get the defined data types from a list of rosetta objects
getTypes :: [RosettaObject] -> [Type]
getTypes [] = []
getTypes (TypeObject o : os) = o{typeAttributes = map convertAttributeType (typeAttributes o)} : getTypes os
getTypes (EnumObject o : os) = convertEnumToType o : getTypes os
getTypes (FunctionObject o : os) = getTypes os
convertAttributeType :: TypeAttribute -> TypeAttribute
convertAttributeType (MakeTypeAttribute n (MakeType "int" _ _ _ _) c d) = MakeTypeAttribute n (BasicType "Integer") c d
convertAttributeType (MakeTypeAttribute n (MakeType "string" _ _ _ _) c d) = MakeTypeAttribute n (BasicType "String") c d
convertAttributeType (MakeTypeAttribute n (MakeType "number" _ _ _ _) c d) = MakeTypeAttribute n (BasicType "Double") c d
convertAttributeType (MakeTypeAttribute n (MakeType "boolean" _ _ _ _) c d) = MakeTypeAttribute n (BasicType "Bool") c d
convertAttributeType (MakeTypeAttribute n (MakeType "time" _ _ _ _) c d) = MakeTypeAttribute n (BasicType "Time") c d
convertAttributeType t = t
getFunctions :: [RosettaObject] -> [Symbol]
getFunctions [] = []
getFunctions (FunctionObject o : os) = functionToSymbol o : getFunctions os
getFunctions (o : os) = getFunctions os
functionToSymbol :: Function -> Symbol
functionToSymbol (MakeFunction (MakeFunctionSignature name _ inp out) _ _) = Func name [(attributeType (convertAttributeType i), Model.Type.cardinality i)| i <- inp] (attributeType out, Model.Type.cardinality out)
{- |Recursively parse a file and all the imports into a list of headers and objects
The first argument is a list of files already parsed (to handle cyclic imports) and the second is the name of the file to be parsed
-}
parseWithImport :: [String] -> String -> IO [(([Type], [Symbol]), (Header, [RosettaObject]))]
parseWithImport files file
| file `elem` files = error $ "cyclic dependency on " ++ file
| otherwise =
do do
plain <- readFile file plain <- readFile file
case parseFile plain of case parseFile plain of
Left errorBundle -> error $ errorBundlePretty errorBundle ++ "on file" ++ file Left errorBundle -> error $ errorBundlePretty errorBundle ++ "on file" ++ file
Right (MakeHeader name desc vers imp, objs) -> Right (MakeHeader name desc vers imp, objs) ->
do do
let files = map ((++) (fileDirectory file) . namespaceToName) imp let modules = map namespaceToName imp
imports <- mapM parseWithImport files importFiles <- getFiles modules
imports <- mapM (parseWithImport (file : files)) importFiles
let importedSymbolTable = fstlst (concat imports) let importedSymbolTable = fstlst (concat imports)
let importedTypes = concat $ fstlst importedSymbolTable let importedTypes = concat $ fstlst importedSymbolTable
let importedFunctions = concat $ sndlst importedSymbolTable let importedFunctions = concat $ sndlst importedSymbolTable
case addNewTypes importedTypes objs of case addNewTypes importedTypes objs of
Left errors -> error $ show errors Left errors -> error $ show errors ++ "\n on file " ++ file
Right definedTypes -> case addNewFunctions (definedTypes, importedFunctions) objs of Right definedTypes -> case addNewFunctions (definedTypes, importedFunctions) objs of
Left errors -> error $ show errors Left errors -> error $ show errors ++ "\n on file " ++ file
Right definedFunctions -> return $ ((definedTypes, definedFunctions), (MakeHeader name desc vers imp, objs)) : concat imports Right definedFunctions -> return $ ((definedTypes, definedFunctions), (MakeHeader name desc vers imp, objs)) : concat imports
getFiles :: [String] -> IO [String]
getFiles [] = return []
getFiles (n : ns)
| ".*" `isSuffixOf` n = do
files <- getDirectoryContents $ takeDirectory n
rest <- getFiles ns
return $ [f | f <- files, dropExtension n `isPrefixOf` f] ++ rest
| otherwise = do
files <- getFiles ns
return (n : files)
-- |Parse a file into a list of RosettaObjects -- |Parse a file into a list of RosettaObjects
parseFile :: String -> Either (ParseErrorBundle Text Void) (Header, [RosettaObject]) parseFile :: String -> Either (ParseErrorBundle Text Void) (Header, [RosettaObject])
parseFile plainText = parse rosettaParser "" (Text.pack plainText) parseFile plainText = parse rosettaParser "" (Text.pack plainText)
-- |Converts a RosettaObject into a plain haskell string
-- printObject :: CheckedRosettaObject -> String
-- printObject (CheckedTypeObject t) = printType t
-- printObject (CheckedFunctionObject f) = printFunction f
-- printObject (CheckedEnumObject e) = printEnum e
-- |Checks all the objects from a list -- |Checks all the objects from a list
checkObjects :: [(([Type], [Symbol]), (Header, [RosettaObject]))] -> [(Header, [Either [TypeCheckError] CheckedRosettaObject])] checkObjects :: [(FilePath, [Type], [Symbol], (Header, [RosettaObject]))] -> [((FilePath, Header), [Either [TypeCheckError] CheckedRosettaObject])]
checkObjects [] = [] checkObjects [] = []
checkObjects (((definedTypes, definedSymbols), (header, objs)) : rest) = (header, checked) : checkObjects rest checkObjects ((file, definedTypes, definedSymbols, (header, objs)) : rest) = ((file, header), checked) : checkObjects rest
where where
checked = map (checkObject (definedTypes, definedSymbols)) objs checked = map (checkObject (definedTypes, definedSymbols)) objs
@@ -110,7 +175,7 @@ addNewFunctions (t, s) (_:os) = addNewFunctions (t, s) os
-- |Adds new defined types into the symbol table -- |Adds new defined types into the symbol table
addNewTypes :: [Type] -> [RosettaObject] -> Either [TypeCheckError] [Type] addNewTypes :: [Type] -> [RosettaObject] -> Either [TypeCheckError] [Type]
addNewTypes l [] = Right l addNewTypes l [] = Right l
addNewTypes defined (TypeObject o: os) = addNewTypes defined (TypeObject o: os) =
case addNewTypes defined os of case addNewTypes defined os of
Left errors -> Left errors Left errors -> Left errors
Right types -> addDefinedTypes types [o] Right types -> addDefinedTypes types [o]
@@ -140,5 +205,7 @@ parseFunction = do
FunctionObject <$> functionParser FunctionObject <$> functionParser
-- |Generate a new haskell file based on the rosetta objects and header -- |Generate a new haskell file based on the rosetta objects and header
generateFile :: (Header, [CheckedRosettaObject]) -> IO () generateFile :: ((FilePath, Header), [CheckedRosettaObject]) -> IO ()
generateFile (header, objects) = writeFile (haskellFileName $ namespace header) (printHeader header ++ concatMap printRosettaObject objects) generateFile ((path, header), objects) =
writeFile (haskellFileName $ dropExtension $ takeFileName path)
(printHeader (dropExtension $ takeFileName path) header ++ concatMap printRosettaObject objects)

View File

@@ -27,6 +27,8 @@ dependencies:
- prettyprinter - prettyprinter
- parser-combinators - parser-combinators
- text - text
- filepath
- directory
library: library:
source-dirs: src source-dirs: src

View File

@@ -1,8 +1,7 @@
namespace contractDSL : <"Generic product concepts: quantity, price, economic terms and payout, that are built using template features."> namespace contractDSL : <"Generic product concepts: quantity, price, economic terms and payout, that are built using template features.">
version "${project.version}" version "${project.version}"
import imports.types.* import imports.*
import imports.enums.*
type Obs: type Obs:

View File

@@ -0,0 +1,6 @@
namespace imports : <"Enums used for the contract dsl">
version "${version.ok}"
enum CounterpartyRoleEnum:
Party1
Party2

View File

@@ -0,0 +1,105 @@
namespace imports : <"Types used for the contract dsl">
version "${version.ok}"
type Product:
contractualProduct ContractualProduct (0..1)
foreignExchange ForeignExchange (0..1)
condition: one-of
type Trade:
tradableProduct TradableProduct (1..1)
type TradableProduct:
product Product (1..1)
tradeLot TradeLot (1..*)
type TradeLot:
priceQuantity PriceQuantity (1..*)
type PriceQuantity:
quantity Quantity (0..*)
type SettlementTerms:
settlementDate SettlementDate (0..1)
cashSettlementTerms CashSettlementTerms (0..*)
settlementCurrency string (0..1)
unitType UnitType (1..1)
type CashSettlementTerms:
valuationDate ValuationDate (1..1)
type ValuationDate:
fxFixingDate FxFixingDate (1..1)
type FxFixingDate:
fxFixingDate AdjustableOrRelativeDate (1..1)
type SettlementDate:
valueDate string (1..1)
type ContractualProduct:
economicTerms EconomicTerms (1..1)
type EconomicTerms:
payout Payout (1..1)
type Payout:
optionPayout OptionPayout (0..*)
forwardPayout ForwardPayout (0..*)
cashflow Cashflow (0..*)
type OptionPayout:
exerciseTerms OptionExercise (1..1)
underlier Product (1..1)
settlementTerms SettlementTerms (0..1)
type OptionExercise:
optionStyle OptionStyle (1..1)
type OptionStyle:
europeanExercise EuropeanExercise (0..1)
condition: one-of
type EuropeanExercise:
expirationDate AdjustableOrRelativeDate (1..*)
type AdjustableOrRelativeDate:
adjustableDate AdjustableDate (0..1)
type AdjustableDate:
adjustedDate string (0..1)
unadjustedDate string (0..1)
type ForwardPayout:
settlementTerms SettlementTerms (1..1)
underlier Product (1..1)
type ForeignExchange:
exchangedCurrency1 Cashflow (1..1)
exchangedCurrency2 Cashflow (1..1)
type Cashflow extends PayoutBase:
payoutQuantity ResolvablePayoutQuantity (1..1)
type ResolvablePayoutQuantity:
resolvedQuantity Quantity (1..1)
type Quantity:
multiplier number (0..1)
location Address (0..1)
unitOfAmount UnitType (0..1)
type Address:
street string (1..1)
type UnitType:
currency string (0..1)
type PayoutBase:
payerReceiver PayerReceiver (1..1)
type PayerReceiver:
payer CounterpartyRoleEnum (1..1)
receiver CounterpartyRoleEnum (1..1)

View File

@@ -0,0 +1,416 @@
namespace contractDSL : <"Generic product concepts: quantity, price, economic terms and payout, that are built using template features.">
version "${project.version}"
import imports.types.*
import imports.enums.*
type Obs:
constant number (0..1)
exchangeRate ExchangeRate (0..1)
condition: one-of
type ExchangeRate:
from UnitType (1..1)
to UnitType (1..1)
func Konst:
inputs:
constant number (1..1)
output:
observable Obs (1..1)
assign-output observable -> constant:
constant
func ExchangeRateFunc:
inputs:
from UnitType (1..1)
to UnitType (1..1)
output:
observable Obs (1..1)
assign-output observable -> exchangeRate -> from:
from
assign-output observable -> exchangeRate -> to:
to
type Contract:
zero Contract_Zero (0..1)
expired Contract_Expired (0..1)
one Contract_One (0..1)
orContract Contract_Or (0..1)
both Contract_Both (0..1)
give Contract_Give (0..1)
thereafter Contract_Thereafter (0..1)
truncate Contract_Truncate (0..1)
scale Contract_Scale (0..1)
get Contract_Get (0..1)
anytime Contract_Anytime (0..1)
condition: one-of
type Contract_Zero:
unit int (1..1)
type Contract_Expired:
unit int (1..1)
type Contract_One:
currency UnitType (1..1)
type Contract_Or:
left Contract (1..1)
right Contract (1..1)
type Contract_Both:
left Contract (1..1)
right Contract (1..1)
type Contract_Thereafter:
earlier Contract (1..1)
later Contract (1..1)
type Contract_Give:
contract Contract (1..1)
type Contract_Truncate:
expiryDate string (1..1)
contract Contract (1..1)
type Contract_Scale:
observable Obs (1..1)
contract Contract (1..1)
type Contract_Get:
contract Contract (1..1)
type Contract_Anytime:
contract Contract (1..1)
func MkZero:
output:
contract Contract (1..1)
assign-output contract -> zero -> unit:
1 // create the zero contract dummy value
func MkExpired:
output:
contract Contract (1..1)
assign-output contract -> expired -> unit:
1 // create the expired contract dummy value
func MkOne:
inputs:
currency UnitType (1..1)
output:
contract Contract (1..1)
assign-output contract -> one -> currency:
currency
func MkOr:
inputs:
left Contract (1..1)
right Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> orContract -> left:
left
assign-output contract -> orContract -> right:
right
func MkBoth:
inputs:
left Contract (1..1)
right Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> both -> left:
left
assign-output contract -> both -> right:
right
func MkThereafter:
inputs:
earlier Contract (1..1)
later Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> thereafter -> earlier:
earlier
assign-output contract -> thereafter -> later:
later
func MkGive:
inputs:
subContract Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> give -> contract:
subContract
func MkTruncate:
inputs:
truncateTo string (1..1)
subContract Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> truncate -> contract:
subContract
assign-output contract -> truncate -> expiryDate:
truncateTo
func MkScale:
inputs:
observable Obs (1..1)
subContract Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> scale -> contract:
subContract
assign-output contract -> scale -> observable:
observable
func MkGet:
inputs:
subContract Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> get -> contract:
subContract
func MkAnytime:
inputs:
subContract Contract (1..1)
output:
contract Contract (1..1)
assign-output contract -> anytime -> contract:
subContract
func MkAnd:
inputs:
left Contract (1..1)
right Contract (1..1)
output:
contract Contract (1..1)
assign-output contract:
MkThereafter(MkBoth(left,right),MkOr(left,right))
func ZeroCouponBond:
inputs:
maturesOn string (1..1) <"Date the bond matures on">
amount number (1..1) <"Amount of the bond is worth">
currency UnitType (1..1) <"Unit the bond is denoted in">
output:
contract Contract (1..1)
assign-output contract:
MkGet (MkTruncate(maturesOn, MkScale(Konst(amount),MkOne(currency))))
func Perhaps:
inputs:
endDate string (1..1)
contract Contract (1..1)
output:
perhaps Contract (1..1)
assign-output perhaps:
MkTruncate(endDate,MkOr(contract,MkZero()))
func EuropeanOption:
inputs:
endDate string (1..1)
contract Contract (1..1)
output:
option Contract (1..1)
assign-output option:
MkGet(Perhaps(endDate,contract))
func AmericanOption:
inputs:
startDate string (1..1)
endDate string (1..1)
contract Contract (1..1)
output:
option Contract (1..1)
alias opt: MkAnytime(Perhaps(endDate,contract))
assign-output option:
MkThereafter(MkGet (MkTruncate(startDate,opt)),opt)
/* Swap the parties of a contract based on the party of a payout. Assuming we are Party1 */
func PayoutParty1:
inputs:
payout PayoutBase (1..1)
contract Contract (1..1)
output:
contractOut Contract (1..1)
assign-output contractOut:
if (payout -> payerReceiver -> payer = CounterpartyRoleEnum -> Party1)
or (payout -> payerReceiver -> receiver = CounterpartyRoleEnum -> Party2) then
MkGive(contract)
else
contract
func ResolveQuantity:
inputs:
address Address (1..1)
tradeLot TradeLot (1..*)
output:
resolvedQuantity Quantity (1..1)
alias resolvedValue:
tradeLot
map [item -> priceQuantity]
flatten
map [item -> quantity]
flatten
filter [item -> location = address]
only-element
assign-output resolvedQuantity -> multiplier:
resolvedValue -> multiplier
assign-output resolvedQuantity -> unitOfAmount:
resolvedValue -> unitOfAmount
func CashflowPayoutToContract:
inputs:
cashflow Cashflow (1..1)
tradeLot TradeLot (1..*)
settlementTerms SettlementTerms (0..1)
output:
zcb Contract (1..1)
alias quantity:
ResolveQuantity(cashflow -> payoutQuantity -> resolvedQuantity -> location only-element, tradeLot)
alias fixingDate:
if settlementTerms -> cashSettlementTerms exists then
settlementTerms
-> cashSettlementTerms
only-element
-> valuationDate
-> fxFixingDate
-> fxFixingDate
-> adjustableDate
-> unadjustedDate
else
empty
assign-output zcb:
PayoutParty1
( cashflow
, MkScale
( Konst (quantity -> multiplier only-element)
, if fixingDate exists then
MkGet
( MkTruncate
( fixingDate only-element
, MkScale
( ExchangeRateFunc(quantity -> unitOfAmount only-element, settlementTerms -> unitType)
, MkGet
( MkTruncate
( settlementTerms -> settlementDate -> valueDate
, MkOne (settlementTerms -> unitType)
)
)
)
)
)
else
MkOne(quantity -> unitOfAmount only-element))
)
func ForeignExchangeToContract:
inputs:
foreignExchange ForeignExchange (1..1)
tradeLot TradeLot (1..*)
settlementTerms SettlementTerms (0..1)
output:
contract Contract (1..1)
assign-output contract:
MkBoth
( CashflowPayoutToContract(foreignExchange -> exchangedCurrency1, tradeLot, settlementTerms)
, CashflowPayoutToContract(foreignExchange -> exchangedCurrency2, tradeLot, settlementTerms)
)
func ForwardPayoutToContract:
inputs:
fx ForwardPayout (1..1)
tradeLot TradeLot (1..*)
output:
contract Contract (1..1)
assign-output contract:
MkGet
( MkTruncate
( fx -> settlementTerms -> settlementDate -> valueDate
, ForeignExchangeToContract
( fx -> underlier -> foreignExchange
, tradeLot
, fx -> settlementTerms
)
)
)
func OptionPayoutToEuropean:
inputs:
optionPayout OptionPayout (1..1)
tradeLot TradeLot (1..*)
output:
contract Contract (1..1)
alias europeanExerciseTerms:
optionPayout -> exerciseTerms -> optionStyle -> europeanExercise
alias adjustedExpirationDate:
europeanExerciseTerms -> expirationDate only-element -> adjustableDate -> adjustedDate
assign-output contract:
EuropeanOption
( adjustedExpirationDate only-element
// The cardinality on europeanExerciseTerms -> expirationDate is not (1..1)!
, ProductToContract(optionPayout -> underlier, tradeLot, optionPayout -> settlementTerms)
, optionPayout -> settlementTerms
)
func ContractualProductToContract:
inputs:
contractualProduct ContractualProduct (1..1)
tradeLot TradeLot (1..*)
settlementTerms SettlementTerms (0..1)
output:
contract Contract (1..1)
alias payout: contractualProduct -> economicTerms -> payout
assign-output contract:
if payout -> optionPayout exists then
payout
-> optionPayout
map [OptionPayoutToEuropean(item,tradeLot)]
reduce c1 c2 [MkBoth(c1,c2)]
else if payout -> forwardPayout exists then
payout
-> forwardPayout
map [ForwardPayoutToContract(item,tradeLot)]
reduce c1 c2 [MkBoth(c1,c2)]
else /* assume cashflow otherwise */
payout
-> cashflow
map [CashflowPayoutToContract(item,tradeLot,settlementTerms)]
reduce c1 c2 [MkBoth(c1,c2)]
func ProductToContract:
inputs:
product Product (1..1)
tradeLot TradeLot (1..*)
settlementTerms SettlementTerms (0..1)
output:
contract Contract (1..1)
assign-output contract:
if product -> contractualProduct exists then
ContractualProductToContract(product -> contractualProduct, tradeLot, settlementTerms)
else if product -> foreignExchange exists then
ForeignExchangeToContract(product -> foreignExchange, tradeLot, settlementTerms)
else
MkZero()
func Main:
inputs:
//meta MetaData (1..1)
trade Trade (1..1)
output:
contract Contract (1..1)
assign-output contract:
ProductToContract(trade -> tradableProduct -> product, trade -> tradableProduct -> tradeLot, empty)

View File

@@ -1,4 +1,4 @@
namespace imports.types : <"Types used for the contract dsl"> namespace imports : <"Types used for the contract dsl">
version "${version.ok}" version "${version.ok}"
import imports.enums.* import imports.enums.*

View File

@@ -135,7 +135,10 @@ data Cardinality =
Bounds (Integer, Integer) Bounds (Integer, Integer)
-- |The cardinality starting from one bound until infinity (ex. 5 - *) -- |The cardinality starting from one bound until infinity (ex. 5 - *)
| OneBound Integer | OneBound Integer
deriving Show
instance Show Cardinality where
show (Bounds (x, y)) = "(" ++ show x ++ ".." ++ show y ++ ")"
show (OneBound x) = "(" ++ show x ++ ".." ++ "*)"
instance Eq Cardinality where instance Eq Cardinality where
(==) (Bounds (x1, x2)) (Bounds (y1, y2)) (==) (Bounds (x1, x2)) (Bounds (y1, y2))

View File

@@ -66,13 +66,13 @@ listParser =
return $ List (expressions ++ [lastExpr]) return $ List (expressions ++ [lastExpr])
listOperations :: [String] listOperations :: [String]
listOperations = ["map", "filter", "reduce"] listOperations = ["map", "filter", "reduce", "contains", "disjoint"]
-- |Parses a variable in Rosetta into an Expression -- |Parses a variable in Rosetta into an Expression
variableParser :: Parser Expression variableParser :: Parser Expression
variableParser = variableParser =
do do
Variable <$> camelNameParser Variable <$> nameParser
enumValueParser :: Parser Expression enumValueParser :: Parser Expression
enumValueParser = enumValueParser =
@@ -124,8 +124,9 @@ terminalParser =
try booleanParser, try booleanParser,
try emptyParser, try emptyParser,
try decimalParser, try decimalParser,
try variableParser, try functionCallParser,
try enumValueParser, try enumValueParser,
try variableParser,
integerParser integerParser
] ]
@@ -164,7 +165,7 @@ eqParser =
-- |The list of equality statements in Rosetta -- |The list of equality statements in Rosetta
eqFunctions :: [String] eqFunctions :: [String]
eqFunctions = ["=", "<", "<=", ">", ">=", "<>"] eqFunctions = ["=", "<=", "<>", "<", ">=", ">"]
-- |Parses a sum statement in Rosetta into an Expression -- |Parses a sum statement in Rosetta into an Expression
sumParser :: Parser Expression sumParser :: Parser Expression
@@ -254,6 +255,14 @@ listOpParser =
con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser
exp <- nestedPostOp lst exp <- nestedPostOp lst
return $ reverseExpression $ Reduce (Text.unpack o) exp v1 v2 con return $ reverseExpression $ Reduce (Text.unpack o) exp v1 v2 con
"contains" -> do
con <- expressionParser
exp <- nestedPostOp lst
return $ reverseExpression $ ListOp "contains" exp con
"disjoint" -> do
con <- expressionParser
exp <- nestedPostOp lst
return $ reverseExpression $ ListOp "disjoint" exp con
_ -> do _ -> do
con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser
exp <- nestedPostOp lst exp <- nestedPostOp lst
@@ -286,6 +295,14 @@ nestedListOp ex =
con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser
exp <- nestedPostOp ex exp <- nestedPostOp ex
return $ reverseExpression $ Reduce (Text.unpack o) exp v1 v2 con return $ reverseExpression $ Reduce (Text.unpack o) exp v1 v2 con
"contains" -> do
con <- expressionParser
exp <- nestedPostOp ex
return $ reverseExpression $ ListOp "contains" exp con
"disjoint" -> do
con <- expressionParser
exp <- nestedPostOp ex
return $ reverseExpression $ ListOp "disjoint" exp con
_ -> do _ -> do
con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser con <- between (lexeme $ char '[') (lexeme $ char ']') expressionParser
exp <- nestedPostOp ex exp <- nestedPostOp ex

View File

@@ -38,9 +38,10 @@ aliasParser =
assignmentParser :: Parser (Expression, Expression) assignmentParser :: Parser (Expression, Expression)
assignmentParser = assignmentParser =
do do
_ <- lexeme $ string "assign-output" _ <- lexeme $ string "assign-output" <|> string "set" <|> string "add"
out <- expressionParser out <- expressionParser
_ <- lexeme $ char ':' _ <- lexeme $ char ':'
_ <- lexeme $ optional descriptionParser
assignment <- expressionParser assignment <- expressionParser
return (out, assignment) return (out, assignment)

View File

@@ -6,13 +6,13 @@ import Model.Type
import Text.Megaparsec.Char import Text.Megaparsec.Char
import Text.Megaparsec import Text.Megaparsec
import Data.Maybe import Data.Maybe
import Parser.General import Parser.General
import Parser.Expression (expressionParser) import Parser.Expression (expressionParser)
-- |Parses a type declaration statement in Rosetta into an Type -- |Parses a type declaration statement in Rosetta into an Type
typeParser :: Parser Type typeParser :: Parser Type
typeParser = typeParser =
do do
tName <- try typeNameParser tName <- try typeNameParser
tSuper <- superTypeParser tSuper <- superTypeParser
_ <- lexeme $ char ':' _ <- lexeme $ char ':'
@@ -33,29 +33,38 @@ superTypeParser =
-- |Parses a declared type attribute in Rosetta into a TypeAttribute -- |Parses a declared type attribute in Rosetta into a TypeAttribute
typeAttributeParser :: Parser TypeAttribute typeAttributeParser :: Parser TypeAttribute
typeAttributeParser = typeAttributeParser =
do do
_ <- many $ lexeme metaParser
aName <- try camelNameParser aName <- try camelNameParser
aType <- try nameParser aType <- try nameParser
card <- cardinalityParser card <- cardinalityParser
desc <- optional descriptionParser desc <- optional descriptionParser
_ <- many $ lexeme metaParser
return (MakeTypeAttribute aName (MakeType aType (BasicType "Object") Nothing [] []) card desc) return (MakeTypeAttribute aName (MakeType aType (BasicType "Object") Nothing [] []) card desc)
metaParser :: Parser String
metaParser =
do
_ <- lexeme $ char '['
manyTill (letterChar <|> char ' ') (char ']')
-- |Parses the cardinality of a type attribute in Rosetta into a Cardinality -- |Parses the cardinality of a type attribute in Rosetta into a Cardinality
cardinalityParser :: Parser Cardinality cardinalityParser :: Parser Cardinality
cardinalityParser = try parseBounded <|> try parseSemiBounded cardinalityParser = try parseBounded <|> try parseSemiBounded
-- |Parser the condition of a type attribute in Rosetta into a Condition -- |Parser the condition of a type attribute in Rosetta into a Condition
conditionParser :: Parser Condition conditionParser :: Parser Condition
conditionParser = do conditionParser = do
_ <- lexeme $ string "condition" _ <- lexeme $ string "condition"
description <- optional descriptionParser _ <- optional $ lexeme pascalNameParser
_ <- lexeme $ char ':' _ <- lexeme $ char ':'
description <- optional descriptionParser
MakeCondition description <$> expressionParser MakeCondition description <$> expressionParser
-- |Parses a bounded cardinality statement in Rosetta into a Cardinality -- |Parses a bounded cardinality statement in Rosetta into a Cardinality
parseBounded :: Parser Cardinality parseBounded :: Parser Cardinality
parseBounded = parseBounded =
do do
_ <- lexeme $ char '(' _ <- lexeme $ char '('
low <- lexeme $ many digitChar low <- lexeme $ many digitChar
@@ -66,7 +75,7 @@ parseBounded =
-- |Parses a one bounded cardinality statement in Rosetta into a Cardinality -- |Parses a one bounded cardinality statement in Rosetta into a Cardinality
parseSemiBounded :: Parser Cardinality parseSemiBounded :: Parser Cardinality
parseSemiBounded = parseSemiBounded =
do do
_ <- lexeme $ char '(' _ <- lexeme $ char '('
low <- lexeme $ many digitChar low <- lexeme $ many digitChar
@@ -75,7 +84,7 @@ parseSemiBounded =
-- |Parses the name of a type in Rosetta into a String -- |Parses the name of a type in Rosetta into a String
typeNameParser :: Parser String typeNameParser :: Parser String
typeNameParser = typeNameParser =
do do
_ <- lexeme $ string "type" _ <- lexeme $ string "type"
pascalNameParser pascalNameParser

View File

@@ -9,17 +9,17 @@ import Data.Char
import Utils.Utils import Utils.Utils
-- |Converts a Header into a haskell valid String -- |Converts a Header into a haskell valid String
printHeader :: Header -> String printHeader :: FilePath -> Header -> String
printHeader (MakeHeader name (Just description) _ imports) = printHeader path (MakeHeader name (Just description) _ imports) =
show $ vcat ["module" <+> pretty (removePeriods name) <+> "where", show $ vcat ["module" <+> pretty (removeChar path '-') <+> "where",
enclose "{-" "-}" (pretty description), enclose "{-" "-}" (pretty description),
emptyDoc, emptyDoc,
"import" <+> "Data.List", "import" <+> "Data.List",
"import" <+> "Data.Maybe", "import" <+> "Data.Maybe",
vcat (map printImport imports), vcat (map printImport imports),
emptyDoc] emptyDoc]
printHeader (MakeHeader name Nothing _ imports) = printHeader path (MakeHeader name Nothing _ imports) =
show $ vcat ["module" <+> pretty (removePeriods name) <+> "where", show $ vcat ["module" <+> pretty (removeChar path '-') <+> "where",
emptyDoc, emptyDoc,
"import" <+> "Data.List", "import" <+> "Data.List",
"import" <+> "Data.Maybe", "import" <+> "Data.Maybe",
@@ -28,4 +28,4 @@ printHeader (MakeHeader name Nothing _ imports) =
-- |Converts an import name into an import prettyprinter doc -- |Converts an import name into an import prettyprinter doc
printImport :: String -> Doc a printImport :: String -> Doc a
printImport name = "import" <+> pretty (removePeriods name) printImport name = "import" <+> pretty (removeChar name '.')

View File

@@ -9,15 +9,19 @@ import Utils.Utils
-- |A declared variable or function -- |A declared variable or function
data Symbol = Var{ data Symbol = Var{
varName :: String, symbolName :: String,
declaredType :: Type, declaredType :: Type,
cardinality :: Cardinality cardinality :: Cardinality
} }
| Func { | Func {
funcName :: String, symbolName :: String,
argsType :: [(Type, Cardinality)], argsType :: [(Type, Cardinality)],
returnType :: (Type, Cardinality) returnType :: (Type, Cardinality)
} deriving (Show) }
instance Show Symbol where
show (Var n t c) = "Variable {name: " ++ show n ++ ", type: " ++ show t ++ ", card: " ++ show c ++ "}"
show (Func n i o) = "Function {name: " ++ show n ++ ", arguments: " ++ show [((typeName . fst) t, (snd t)) | t <- i] ++ ", return: (" ++ typeName (fst o) ++ ", " ++ show (snd o) ++ ")}"
instance Eq Symbol where instance Eq Symbol where
(==) (Var name1 _ _) (Var name2 _ _) (==) (Var name1 _ _) (Var name2 _ _)
@@ -96,7 +100,7 @@ addFunction (definedTypes, definedSymbols) (MakeFunction (MakeFunctionSignature
case head $ checkAttributes definedTypes [out] of case head $ checkAttributes definedTypes [out] of
Left err -> Left [err] Left err -> Left [err]
Right checkedOutput -> if null (lefts checkedInputs) Right checkedOutput -> if null (lefts checkedInputs)
then if name `elem` map funcName definedSymbols then if name `elem` map symbolName definedSymbols
then Left [MultipleDeclarations name] then Left [MultipleDeclarations name]
else Right $ Func name (map typeAndCardinality (rights checkedInputs)) (attributeType checkedOutput, Model.Type.cardinality out) : definedSymbols else Right $ Func name (map typeAndCardinality (rights checkedInputs)) (attributeType checkedOutput, Model.Type.cardinality out) : definedSymbols
else Left $ lefts checkedInputs else Left $ lefts checkedInputs
@@ -261,10 +265,10 @@ checkList1 defT symbs (ex : exps) typ =
-- |Checks whether the function that is called is already defined with the same argument types -- |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 :: [Symbol] -> String -> [Either TypeCheckError ExplicitExpression ] -> Either TypeCheckError ExplicitExpression
checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: " ++ fun ++ " [" checkFunctionCall [] fun args = Left $ UndefinedFunction $ "Undefined function: " ++ fun ++ " [" ++ show args ++ "]"
++ show [(typeName $ typeFromExpression x, toCardinality $ cardinalityCoercion $ returnCoercion x) | x <- rights args] ++ "]" ++ show [(typeName $ typeFromExpression x, toCardinality $ cardinalityCoercion $ returnCoercion x) | x <- rights args] ++ "]"
checkFunctionCall ((Func n a r):symbolMap) name args checkFunctionCall ((Func n a r):symbolMap) name args
| not $ null $ lefts args = Left $ ErrorInsideFunction (name ++ ": " ++ show (lefts args)) | not $ null $ lefts args = error $ show symbolMap ++ "\n" ++ show (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))) | name == n = if all isRight coerce then Right $ ExplicitFunction name (zip (rights args) (rights coerce)) (MakeCoercion [MakeIdCoercion (fst r)] (MakeCardinalityIdCoercion (snd r)))
else checkFunctionCall symbolMap name args else checkFunctionCall symbolMap name args
| otherwise = checkFunctionCall symbolMap name args | otherwise = checkFunctionCall symbolMap name args
@@ -411,4 +415,4 @@ cardinalityIncluded (OneBound x) (Bounds (x2, y2)) = Left $ CardinalityMismatch
cardinalityIncluded (Bounds (x1, x2)) (Bounds (y1, y2)) cardinalityIncluded (Bounds (x1, x2)) (Bounds (y1, y2))
| x1 == y1 && x2 == y2 = Right $ MakeCardinalityIdCoercion (Bounds (x1, x2)) | x1 == y1 && x2 == y2 = Right $ MakeCardinalityIdCoercion (Bounds (x1, x2))
| x1 >= y1 && x2 <= y2 = Right $ MakeListCardinalityCoercion (Bounds (x1, x2)) (Bounds (y1, y2)) | x1 >= y1 && x2 <= y2 = Right $ MakeListCardinalityCoercion (Bounds (x1, x2)) (Bounds (y1, y2))
| otherwise = Left $ CardinalityMismatch (Bounds (x1, x2)) (Bounds (y1, y2)) | otherwise = Left $ CardinalityMismatch (Bounds (x1, x2)) (Bounds (y1, y2))

View File

@@ -16,42 +16,27 @@ uncapitalize s = toLower (head s) : tail s
-- |Convert a namespace to a filename -- |Convert a namespace to a filename
namespaceToName :: String -> String namespaceToName :: String -> String
namespaceToName [] = ".rosetta" namespaceToName [] = ".rosetta"
namespaceToName ".*" = ".rosetta" namespaceToName ".*" = ".*"
namespaceToName (c : cs) namespaceToName (c : cs)
| c == '.' = '-' : namespaceToName cs | c == '.' = '-' : namespaceToName cs
| otherwise = c : namespaceToName cs | otherwise = c : namespaceToName cs
-- |Returns the directory of a file from a path
fileDirectory :: String -> String
fileDirectory s = take (length s - length (fileName s)) s
-- |Returns the name of a file from a path
fileName :: String -> String
fileName path = reverse $ fileName1 $ reverse path
-- |Auxiliary function for the name of a file from a path
fileName1 :: String -> String
fileName1 [] = []
fileName1 (c : cs)
| c == '/' = []
| otherwise = c : fileName1 cs
-- |Create a new haskell filename based on the namespace -- |Create a new haskell filename based on the namespace
haskellFileName :: String -> String haskellFileName :: String -> String
haskellFileName s = "resources/Generated/" ++ removePeriods s ++".hs" haskellFileName s = "resources/Generated/" ++ removeChar s '-' ++".hs"
-- |Function to remove all the periods from a name, and convert the name to CamelCase -- |Function to remove all the periods from a name, and convert the name to CamelCase
removePeriods :: String -> String removeChar :: String -> Char -> String
removePeriods [] = [] removeChar [] _ = []
removePeriods ['*'] = [] removeChar ['*'] _ = []
removePeriods (c:cs) = toUpper c : removePeriods1 cs removeChar (c:cs) ch = toUpper c : removeChar1 cs ch
-- |Auxiliary function for converting names -- |Auxiliary function for converting names
removePeriods1 :: String -> String removeChar1 :: String -> Char -> String
removePeriods1 [] = [] removeChar1 [] ch = []
removePeriods1 (c:cs) removeChar1 (c:cs) ch
| c == '.' = removePeriods cs | c == ch = removeChar cs ch
| otherwise = c : removePeriods1 cs | otherwise = c : removeChar1 cs ch
-- |Extract the first elements from a list of tuples -- |Extract the first elements from a list of tuples
fstlst :: [(a, b)] -> [a] fstlst :: [(a, b)] -> [a]
@@ -101,4 +86,10 @@ trd3 (_, _, x) = x
replacePrefix :: Eq a => [a] -> [a] -> [a] -> [a] replacePrefix :: Eq a => [a] -> [a] -> [a] -> [a]
replacePrefix a b c = case stripPrefix a b of replacePrefix a b c = case stripPrefix a b of
Nothing -> b Nothing -> b
Just bs -> c ++ bs Just bs -> c ++ bs
-- |Get the namespace name from the import
getNamespace :: String -> String
getNamespace [] = []
getNamespace ".*" = []
getNamespace (s : ss) = s : getNamespace ss