{-# LANGUAGE OverloadedStrings #-}

module Funcons.Tools (
    -- * Creating standalone interpreters.

    -- $moduledoc
    mkMain, mkMainWithLibrary, mkMainWithLibraryEntities,
    mkMainWithLibraryTypes, mkMainWithLibraryEntitiesTypes,
    mkFullyFreshInterpreter, mkFreshInterpreter,
    -- * Creating embedded interpreters.
    run, runWithExtensions, runWithExtensionsNoCore, runWithExtensionsNoNothing,
    -- * Utility functions for interpreter extensions. 
    -- ** Funcon libraries.
    FunconLibrary, libEmpty, libUnion, libOverride, libUnions, libOverrides, libFromList,
    -- ** Type environments.
    TypeRelation, DataTypeMembers(..), DataTypeAltt(..), TypeParam, 
        emptyTypeRelation, typeEnvUnion, typeEnvUnions, typeEnvFromList,
    -- ** Entity declarations 
    EntityDefaults, EntityDefault(..), noEntityDefaults,
    ) where

import Funcons.EDSL (library)
import Funcons.RunOptions
import Funcons.Types
import Funcons.Entities
import Funcons.MSOS
import Funcons.Core.Library
import Funcons.Core.Manual
import Funcons.Printer

import System.Environment (getArgs)

import Data.Text (unpack)
import Data.List ((\\), intercalate)
import qualified Data.Map as M
import Control.Monad (forM_, when, unless)

-- | The empty collection of entity defaults.
noEntityDefaults :: [EntityDefault]
noEntityDefaults :: [EntityDefault]
noEntityDefaults = []

-- | Creates a /main/ function for the default interpreter (no extension).
-- The executable made from this /main/ function receives command line
-- argumenst as explained above ("Funcons.Tools"). 
mkMain :: IO ()
mkMain :: IO ()
mkMain = FunconLibrary -> IO ()
mkMainWithLibrary FunconLibrary
libEmpty 

-- | Creates a /main/ function for the interpreter obtained by extending
-- the default library with the funcons in the 'FunconLibrary' argument.
mkMainWithLibrary :: FunconLibrary -> IO() 
mkMainWithLibrary :: FunconLibrary -> IO ()
mkMainWithLibrary FunconLibrary
lib = FunconLibrary -> [EntityDefault] -> IO ()
mkMainWithLibraryEntities FunconLibrary
lib [] 

-- | Creates a /main/ function for the interpreter obtained by extending
-- the main interpreter  with the funcons in the 'FunconLibrary' argument
-- and with default values for entities defined in the 'EntityDefaults' 
-- argument.
mkMainWithLibraryEntities :: FunconLibrary -> EntityDefaults -> IO ()
mkMainWithLibraryEntities :: FunconLibrary -> [EntityDefault] -> IO ()
mkMainWithLibraryEntities FunconLibrary
lib [EntityDefault]
ents = 
    FunconLibrary -> [EntityDefault] -> TypeRelation -> IO ()
mkMainWithLibraryEntitiesTypes FunconLibrary
lib [EntityDefault]
ents TypeRelation
emptyTypeRelation

-- | Creates a /main/ function for the interpreter obtained by extending
-- the main interpreter with the funcons in the 'FunconLibrary' argument
-- and with a 'TypeRelation' mapping datatypes to their constructors and
-- type arguments.
mkMainWithLibraryTypes :: FunconLibrary -> TypeRelation -> IO ()
mkMainWithLibraryTypes :: FunconLibrary -> TypeRelation -> IO ()
mkMainWithLibraryTypes FunconLibrary
lib TypeRelation
tys = FunconLibrary -> [EntityDefault] -> TypeRelation -> IO ()
mkMainWithLibraryEntitiesTypes FunconLibrary
lib [] TypeRelation
tys

-- | Creates a /main/ function for the interpreter obtained by extending
-- the main interpreter with funcons, 'EntityDefaults' and a 'TypeRelation'. 
mkMainWithLibraryEntitiesTypes :: FunconLibrary -> EntityDefaults -> TypeRelation -> IO ()
mkMainWithLibraryEntitiesTypes :: FunconLibrary -> [EntityDefault] -> TypeRelation -> IO ()
mkMainWithLibraryEntitiesTypes FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv = do   
    [String]
args <- IO [String]
getArgs
    FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensions FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv [String]
args forall a. Maybe a
Nothing

-- | Creates a /main/ function for the interpreter aware of only
-- the given 'FunconLibrary', 'EntityDefaults' and 'TypeRelation'. 
mkFullyFreshInterpreter :: FunconLibrary -> EntityDefaults -> TypeRelation -> IO ()
mkFullyFreshInterpreter :: FunconLibrary -> [EntityDefault] -> TypeRelation -> IO ()
mkFullyFreshInterpreter FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv = do   
    [String]
args <- IO [String]
getArgs
    FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensionsNoNothing FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv [String]
args forall a. Maybe a
Nothing 

-- | Creates a /main/ function for the interpreter aware of only
-- the given 'FunconLibrary', 'EntityDefaults' and 'TypeRelation',
-- and the built-in types and operations. 
mkFreshInterpreter :: FunconLibrary -> EntityDefaults -> TypeRelation -> IO ()
mkFreshInterpreter :: FunconLibrary -> [EntityDefault] -> TypeRelation -> IO ()
mkFreshInterpreter FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv = do   
    [String]
args <- IO [String]
getArgs
    FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensionsNoCore FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv [String]
args forall a. Maybe a
Nothing 

-- | Same as 'run', except receiving additional interpreter extensions as arguments.
-- Useful when a translation to 'Funcons' has been implemented in Haskell as
-- well as 'Funcons', entities or datatypes specific to the object language.
-- Includes the 'Funcons.Core' funcons.
runWithExtensions :: 
    FunconLibrary -> EntityDefaults -> TypeRelation -> [String] -> Maybe Funcons -> IO ()
runWithExtensions :: FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensions FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv = 
  FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensionsNoCore 
    ([FunconLibrary] -> FunconLibrary
libUnions [FunconLibrary
Funcons.Core.Library.funcons, FunconLibrary
lib]) 
    (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[EntityDefault]
defaults, forall a. [a]
Funcons.Core.Library.entities])
    ([TypeRelation] -> TypeRelation
typeEnvUnions [TypeRelation
tyenv, TypeRelation
Funcons.Core.Library.types])

-- | Same as 'run', except receiving additional interpreter extensions as arguments.
-- Useful when a translation to 'Funcons' has been implemented in Haskell as
-- well as 'Funcons', entities or datatypes specific to the object language.
-- Does not include the 'Funcons.Core' funcons.
runWithExtensionsNoCore :: 
    FunconLibrary -> EntityDefaults -> TypeRelation -> [String] -> Maybe Funcons -> IO ()
runWithExtensionsNoCore :: FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensionsNoCore FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv = FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensionsNoNothing FunconLibrary
full_lib [EntityDefault]
defaults TypeRelation
tyenv
 where  full_lib :: FunconLibrary
full_lib = [FunconLibrary] -> FunconLibrary
libUnions    [FunconLibrary
lib
                                ,FunconLibrary
Funcons.EDSL.library
                                ,FunconLibrary
Funcons.Core.Manual.library]

-- | Same as 'run', except receiving additional interpreter extensions as arguments.
-- Useful when a translation to 'Funcons' has been implemented in Haskell as
-- well as 'Funcons', entities or datatypes specific to the object language.
-- Does not include the 'Funcons.Core' funcons.
runWithExtensionsNoNothing :: 
    FunconLibrary -> EntityDefaults -> TypeRelation -> [String] -> Maybe Funcons -> IO ()
runWithExtensionsNoNothing :: FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensionsNoNothing FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv = FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
emulate FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv 


-- | 
-- Creates a main function by passing in a list of command line arguments 
-- and an optional initial 'Funcons' to execute. The 'Funcons' argument is optional
-- as one of the command line arguments may refer to an .fct file or .config
-- file that specifies an initial 'Funcons' term.
-- Useful when a translation to 'Funcons' has been implemented in Haskell.
run :: [String] -> Maybe Funcons -> IO ()
run :: [String] -> Maybe Funcons -> IO ()
run = FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
runWithExtensions FunconLibrary
libEmpty [] TypeRelation
emptyTypeRelation 

------------------------------------------------------------------------------
--- running programs 
emulate :: FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> [String]
-> Maybe Funcons
-> IO ()
emulate FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv [String]
args Maybe Funcons
mf0 = do
    (RunOptions
opts, [String]
unknown_opts) <- [String] -> IO (RunOptions, [String])
run_options [String]
args
    forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [String]
unknown_opts forall a b. (a -> b) -> a -> b
$ \String
arg -> do
        String -> IO ()
putStrLn (String
"unknown option: " forall a. [a] -> [a] -> [a]
++ String
arg)
    case RunOptions -> Bool
interactive_mode RunOptions
opts of 
        Bool
True    -> forall (m :: * -> *).
Interactive m =>
(Name -> m Funcons)
-> FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> RunOptions
-> Maybe Funcons
-> IO ()
emulate' (forall (m :: * -> *). Interactive m => Bool -> Name -> m Funcons
fread (RunOptions -> Bool
string_inputs RunOptions
opts) :: Name -> IO Funcons) FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv RunOptions
opts Maybe Funcons
mf0
        Bool
False   -> forall (m :: * -> *).
Interactive m =>
(Name -> m Funcons)
-> FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> RunOptions
-> Maybe Funcons
-> IO ()
emulate' (forall (m :: * -> *). Interactive m => Bool -> Name -> m Funcons
fread (RunOptions -> Bool
string_inputs RunOptions
opts) :: Name -> SimIO Funcons) FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv RunOptions
opts Maybe Funcons
mf0

emulate' :: Interactive m => (Name -> m Funcons) ->
            FunconLibrary -> EntityDefaults -> TypeRelation -> RunOptions -> Maybe Funcons -> IO ()
emulate' :: forall (m :: * -> *).
Interactive m =>
(Name -> m Funcons)
-> FunconLibrary
-> [EntityDefault]
-> TypeRelation
-> RunOptions
-> Maybe Funcons
-> IO ()
emulate' Name -> m Funcons
reader FunconLibrary
lib [EntityDefault]
defaults TypeRelation
tyenv RunOptions
opts Maybe Funcons
mf0 = do
    -- the initial funcon term must be either given from a .fct file (Maybe Funcons)
    -- or specified in a configuration file
    let f0 :: Funcons
f0 = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (RunOptions -> Funcons
funcon_term RunOptions
opts) forall a. a -> a
id Maybe Funcons
mf0
        msos_ctxt :: MSOSReader m
msos_ctxt = forall (m :: * -> *).
RewriteReader
-> InputValues
-> DownControl
-> (Name -> m Funcons)
-> MSOSReader m
MSOSReader (FunconLibrary
-> TypeRelation
-> RunOptions
-> Funcons
-> Funcons
-> RewriteReader
RewriteReader FunconLibrary
lib TypeRelation
tyenv RunOptions
opts Funcons
f0 Funcons
f0) InputValues
emptyINH DownControl
emptyDCTRL Name -> m Funcons
reader
    -- run the Interactive monad, returning in the evaluation results + entity values.
    -- if in --interactive-mode the Interactive monad will be IO 
    --  and all the desired output will already have been printed to the screen
    ((Either IException StepRes
e_exc_f, MSOSState m
mut, MSOSWriter
wr), InputValues
rem_ins) <- 
        forall (m :: * -> *) a.
Interactive m =>
m a -> InputValues -> IO (a, InputValues)
fexec (forall a.
MSOS a
-> forall (m :: * -> *).
   Interactive m =>
   MSOSReader m
   -> MSOSState m -> m (Either IException a, MSOSState m, MSOSWriter)
runMSOS ([EntityDefault] -> MSOS StepRes -> MSOS StepRes
setEntityDefaults [EntityDefault]
defaults (RunOptions -> Int -> StepRes -> MSOS StepRes
stepTrans RunOptions
opts Int
0 (Funcons -> StepRes
toStepRes Funcons
f0)))
                MSOSReader m
msos_ctxt ((forall (m :: * -> *). Int -> MSOSState m
emptyMSOSState (RunOptions -> Int
random_seed RunOptions
opts)){inp_es :: Input m
inp_es = forall {a}. Map Name ([a], Maybe (m Funcons))
inputs})) (RunOptions -> InputValues
inputValues RunOptions
opts)
    -- if not in --interactive-mode then print additional information based on flags
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (RunOptions -> Bool
interactive_mode RunOptions
opts)
        (forall {m :: * -> *}.
[EntityDefault]
-> MSOSReader m
-> Either IException StepRes
-> MSOSState m
-> MSOSWriter
-> InputValues
-> IO ()
withResults [EntityDefault]
defaults MSOSReader m
msos_ctxt Either IException StepRes
e_exc_f MSOSState m
mut MSOSWriter
wr InputValues
rem_ins)
 where inputs :: Map Name ([a], Maybe (m Funcons))
inputs = forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
M.foldrWithKey forall {p} {a}.
Name
-> p
-> Map Name ([a], Maybe (m Funcons))
-> Map Name ([a], Maybe (m Funcons))
op forall k a. Map k a
M.empty (RunOptions -> InputValues
inputValues RunOptions
opts)
                where   op :: Name
-> p
-> Map Name ([a], Maybe (m Funcons))
-> Map Name ([a], Maybe (m Funcons))
op Name
nm p
_ = forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Name
nm ([], forall a. a -> Maybe a
Just (Name -> m Funcons
reader Name
nm))

withResults :: [EntityDefault]
-> MSOSReader m
-> Either IException StepRes
-> MSOSState m
-> MSOSWriter
-> InputValues
-> IO ()
withResults [EntityDefault]
defaults MSOSReader m
msos_ctxt Either IException StepRes
e_exc_f MSOSState m
msos_state MSOSWriter
wr InputValues
rem_ins
        | RunOptions -> Bool
show_tests RunOptions
opts =
            case Either IException StepRes
e_exc_f of
             Left IException
ie -> String -> IO ()
putStrLn (IException -> String
showIException IException
ie)
             Right StepRes
efvs -> forall (m :: * -> *).
[Funcons]
-> [EntityDefault]
-> MSOSReader m
-> MSOSState m
-> MSOSWriter
-> InputValues
-> IO ()
printTestResults (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a. a -> [a] -> [a]
:[]) (forall a b. (a -> b) -> [a] -> [b]
map Values -> Funcons
FValue) StepRes
efvs)
                              [EntityDefault]
defaults MSOSReader m
msos_ctxt MSOSState m
msos_state MSOSWriter
wr InputValues
rem_ins
        | Bool
otherwise = do
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (RunOptions -> Bool
show_output_only RunOptions
opts) forall a b. (a -> b) -> a -> b
$ do
        IO ()
printCounts 
        case Either IException StepRes
e_exc_f of
            Left IException
ie -> String -> IO ()
putStrLn (IException -> String
showIException IException
ie)
            Right StepRes
f -> [Funcons] -> IO ()
printResult (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a. a -> [a] -> [a]
:[]) (forall a b. (a -> b) -> [a] -> [b]
map Values -> Funcons
FValue) StepRes
f)
        IO ()
printMutable
        IO ()
printControl
        InputValues -> [Name] -> IO ()
printInput InputValues
rem_ins (RunOptions -> [Name]
hide_input RunOptions
opts)
    IO ()
printOutput
 where
    muts :: InputValues
muts = forall (m :: * -> *). MSOSState m -> InputValues
mut_entities MSOSState m
msos_state 
    opts :: RunOptions
opts = RewriteReader -> RunOptions
run_opts (forall (m :: * -> *). MSOSReader m -> RewriteReader
ereader MSOSReader m
msos_ctxt)
    printResult :: [Funcons] -> IO ()
printResult [Funcons]
f = forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (RunOptions -> Bool
show_result RunOptions
opts) forall a b. (a -> b) -> a -> b
$ do
                        String -> IO ()
putStrLn String
"Result:"
                        String -> IO ()
putStrLn (RunOptions -> [Funcons] -> String
ppFunconsSeq RunOptions
opts [Funcons]
f)
                        String -> IO ()
putStrLn String
""

    printCounts :: IO ()
printCounts = do
      forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (RunOptions -> Bool
show_counts RunOptions
opts) forall a b. (a -> b) -> a -> b
$ do 
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (RunOptions -> Bool
csv_output_with_keys RunOptions
opts) (String -> IO ()
putStrLn String
counterKeys) 
        if (RunOptions -> Bool
csv_output RunOptions
opts) 
          then String -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ Counters -> String
displayCounters (RewriteWriterr -> Counters
counters (MSOSWriter -> RewriteWriterr
ewriter MSOSWriter
wr))
          else String -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ Counters -> String
ppCounters (RewriteWriterr -> Counters
counters (MSOSWriter -> RewriteWriterr
ewriter MSOSWriter
wr))

    printMutable :: IO ()
printMutable = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Name]
toShow Name -> IO ()
display
     where toShow :: [Name]
toShow = RunOptions -> [Name]
show_mutable RunOptions
opts
           display :: Name -> IO ()
display Name
name = case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name InputValues
muts of
                            Maybe [Values]
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
                            Just [Values]
v ->  String -> IO ()
putStrLn (String
"Mutable Entity: " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
                                       String -> IO ()
putStrLn ([Values] -> String
displayValues [Values]
v) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> IO ()
putStrLn String
""

    printControl :: IO ()
printControl = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [k]
M.keys DownControl
ctrl forall a. Eq a => [a] -> [a] -> [a]
\\ [Name]
toHide) Name -> IO ()
display
     where ctrl :: DownControl
ctrl = MSOSWriter -> DownControl
ctrl_entities MSOSWriter
wr
           toHide :: [Name]
toHide = RunOptions -> [Name]
hide_control RunOptions
opts
           display :: Name -> IO ()
display Name
name = case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name DownControl
ctrl of
                            Just (Just Values
v) -> do
                                String -> IO ()
putStrLn (String
"Control Entity: " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name) 
                                String -> IO ()
putStrLn (Values -> String
displayValue Values
v) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> IO ()
putStrLn String
""
                            Maybe (Maybe Values)
_             -> forall (m :: * -> *) a. Monad m => a -> m a
return ()

    printOutput :: IO ()
printOutput = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [k]
M.keys InputValues
out forall a. Eq a => [a] -> [a] -> [a]
\\ [Name]
toHide) Name -> IO ()
display
     where out :: InputValues
out = MSOSWriter -> InputValues
out_entities MSOSWriter
wr
           display :: Name -> IO ()
display Name
name = do
                    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (RunOptions -> Bool
show_output_only RunOptions
opts) 
                        (String -> IO ()
putStrLn (String
"Output Entity: " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name))
                    case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all forall t. HasValues t => Values t -> Bool
isString_ [Values]
vs Bool -> Bool -> Bool
&& RunOptions -> Bool
pp_string_outputs RunOptions
opts of
                        Bool
True    -> forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (String -> IO ()
putStr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. HasValues t => Values t -> String
unString) [Values]
vs
                        Bool
False   -> String -> IO ()
putStrLn ([Values] -> String
displayValues [Values]
vs)
                    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (RunOptions -> Bool
show_output_only RunOptions
opts) (String -> IO ()
putStrLn String
"")
            where vs :: [Values]
vs = InputValues
out forall k a. Ord k => Map k a -> k -> a
M.! Name
name
           toHide :: [Name]
toHide = RunOptions -> [Name]
hide_output RunOptions
opts


    printInput :: InputValues -> [Name] -> IO ()
printInput InputValues
ios [Name]
toHide = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [k]
M.keys InputValues
ios forall a. Eq a => [a] -> [a] -> [a]
\\ [Name]
toHide) Name -> IO ()
display
     where display :: Name -> IO ()
display Name
name = forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Values]
vs) forall a b. (a -> b) -> a -> b
$ do 
                            String -> IO ()
putStrLn (String
"Input Entity: " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name)
                            String -> IO ()
putStrLn ([Values] -> String
displayValues [Values]
vs)
                            String -> IO ()
putStrLn String
""
            where vs :: [Values]
vs = InputValues
ios forall k a. Ord k => Map k a -> k -> a
M.! Name
name

    displayValues :: [Values] -> String
displayValues [Values]
vs = forall a. [a] -> [[a]] -> [a]
intercalate String
"," (forall a b. (a -> b) -> [a] -> [b]
map Values -> String
displayValue [Values]
vs)
    displayValue :: Values -> String
displayValue (Map ValueMaps Values
m) = forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" 
                                   [ Values -> String
displayValue Values
key forall a. [a] -> [a] -> [a]
++ String
" |-> " forall a. [a] -> [a] -> [a]
++ [Values] -> String
displayValues [Values]
val 
                                   | (Values
key, [Values]
val) <- forall k a. Map k a -> [(k, a)]
M.assocs ValueMaps Values
m ]
    displayValue (ADTVal Name
"variable" [FValue (Atom String
a)
                                     ,FValue (ComputationType (Type Types Funcons
t))]) = 
        String
"variable(" forall a. [a] -> [a] -> [a]
++ Values -> String
displayValue (forall t. String -> Values t
Atom String
a) forall a. [a] -> [a] -> [a]
++ String
", " forall a. [a] -> [a] -> [a]
++ forall t. HasValues t => (t -> String) -> Types t -> String
ppTypes (RunOptions -> Funcons -> String
ppFuncons RunOptions
opts) Types Funcons
t forall a. [a] -> [a] -> [a]
++ String
")"
    displayValue (Atom String
a) = String
a
    displayValue Values
val | forall t. HasValues t => Values t -> Bool
isString_ Values
val = forall a. Show a => a -> String
show (forall t. HasValues t => Values t -> String
unString Values
val)
    displayValue Values
val = forall t. HasValues t => (t -> String) -> Values t -> String
ppValues (RunOptions -> Funcons -> String
ppFuncons RunOptions
opts) Values
val

printTestResults :: [Funcons] -> EntityDefaults -> MSOSReader m -> 
                        MSOSState m -> MSOSWriter -> InputValues -> IO ()
printTestResults :: forall (m :: * -> *).
[Funcons]
-> [EntityDefault]
-> MSOSReader m
-> MSOSState m
-> MSOSWriter
-> InputValues
-> IO ()
printTestResults [Funcons]
fs [EntityDefault]
defaults MSOSReader m
msos_ctxt MSOSState m
msos_state MSOSWriter
wr InputValues
rem_ins = do
        forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [k]
M.keys TestOptions
opts) Name -> IO ()
printNotExists
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall k a. Ord k => k -> Map k a -> Bool
M.member Name
"result-term" TestOptions
opts) forall a b. (a -> b) -> a -> b
$
            forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([Funcons]
result_term forall a. Eq a => a -> a -> Bool
== [Funcons]
fs) (Name -> String -> String -> IO ()
reportError Name
"result-term" ([Funcons] -> String
showFunconsSeq [Funcons]
result_term) ([Funcons] -> String
showFunconsSeq [Funcons]
fs))
        IO ()
printMutable
        IO ()
printControl
        InputValues -> IO ()
printInputOutput InputValues
out
        InputValues -> IO ()
printInputOutput InputValues
rem_ins

    where   eval_ctxt :: RewriteReader
eval_ctxt = forall (m :: * -> *). MSOSReader m -> RewriteReader
ereader MSOSReader m
msos_ctxt
            muts :: InputValues
muts = forall (m :: * -> *). MSOSState m -> InputValues
mut_entities MSOSState m
msos_state
            eval_state :: RewriteState
eval_state = forall (m :: * -> *). MSOSState m -> RewriteState
estate MSOSState m
msos_state
            localEval :: Name -> Funcons -> Values
localEval Name
name Funcons
term = case forall a.
Rewrite a
-> RewriteReader
-> RewriteState
-> (Either IException a, RewriteState, RewriteWriterr)
runRewrite (Funcons -> Rewrite Rewritten
rewriteFuncons Funcons
term) RewriteReader
eval_ctxt RewriteState
eval_state
                of  (Left IException
ie,RewriteState
_,RewriteWriterr
_) -> forall a. HasCallStack => String -> a
error (String
"internal exception in " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name 
                                    forall a. [a] -> [a] -> [a]
++ String
" evaluation:\n" forall a. [a] -> [a] -> [a]
++ IException -> String
showIException IException
ie)
                    (Right (ValTerm [Values
v]),RewriteState
_,RewriteWriterr
_) -> Values
v
                    (Right (ValTerm [Values]
vs),RewriteState
_,RewriteWriterr
_) -> forall a. HasCallStack => String -> a
error 
                      (String
"evaluation of " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
" results in sequence")
                    (Right Rewritten
_,RewriteState
_,RewriteWriterr
_) ->
                         forall a. HasCallStack => String -> a
error (String
"evaluation of " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
" requires step")
    
            mLocalEval :: Funcons -> Maybe Values
mLocalEval Funcons
term = case forall a.
Rewrite a
-> RewriteReader
-> RewriteState
-> (Either IException a, RewriteState, RewriteWriterr)
runRewrite(Funcons -> Rewrite Rewritten
rewriteFuncons Funcons
term) RewriteReader
eval_ctxt RewriteState
eval_state of
                (Right (ValTerm [Values
v]),RewriteState
_,RewriteWriterr
_) -> forall a. a -> Maybe a
Just Values
v
                (Either IException Rewritten, RewriteState, RewriteWriterr)
_                         -> forall a. Maybe a
Nothing

            result_term :: [Funcons]
result_term = case forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Funcons -> Maybe Values
recursiveFunconValue [Funcons]
rf) of
                Maybe [Values]
Nothing -> case forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Funcons -> Maybe Values
mLocalEval [Funcons]
rf) of
                                Maybe [Values]
Nothing -> [Funcons]
rf
                                Just [Values]
vs -> forall a b. (a -> b) -> [a] -> [b]
map Values -> Funcons
FValue [Values]
vs
                Just [Values]
vs -> forall a b. (a -> b) -> [a] -> [b]
map Values -> Funcons
FValue [Values]
vs
             where rf :: [Funcons]
rf = (TestOptions
opts forall k a. Ord k => Map k a -> k -> a
M.! Name
"result-term")
            opts :: TestOptions
opts = RunOptions -> TestOptions
expected_outcomes (RewriteReader -> RunOptions
run_opts RewriteReader
eval_ctxt)

            reportError :: Name -> String -> String -> IO ()
reportError Name
name String
expected String
actual = do
                String -> IO ()
putStrLn (String
"expected " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
": " forall a. [a] -> [a] -> [a]
++ String
expected)
                String -> IO ()
putStrLn (String
"actual   " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
": " forall a. [a] -> [a] -> [a]
++ String
actual)

            printNotExists :: Name -> IO ()
printNotExists Name
"result-term" = forall (m :: * -> *) a. Monad m => a -> m a
return ()
            printNotExists Name
name = 
                case (forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name InputValues
muts, forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name InputValues
out
                     ,forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name DownControl
ctrl, forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name InputValues
rem_ins) of
                    (Maybe [Values]
Nothing, Maybe [Values]
Nothing, Maybe (Maybe Values)
Nothing, Maybe [Values]
Nothing) -> 
                        String -> IO ()
putStrLn (String
"unknown entity: " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name)
                    (Maybe [Values], Maybe [Values], Maybe (Maybe Values),
 Maybe [Values])
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
        
            printMutable :: IO ()
printMutable = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [(k, a)]
M.assocs InputValues
muts) (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Name -> [Values] -> IO ()
display)
             where display :: Name -> [Values] -> IO ()
display Name
name [Values]
vals = case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name TestOptions
opts of
                        Maybe [Funcons]
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
                        Just [Funcons]
expected -> forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless 
                                            (forall a b. (a -> b) -> [a] -> [b]
map (Name -> Funcons -> Values
localEval Name
name) [Funcons]
expected forall a. Eq a => a -> a -> Bool
== [Values]
vals) 
                                            (Name -> String -> String -> IO ()
reportError Name
name ([String] -> String
showL forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Funcons -> String
showFuncons [Funcons]
expected) ([String] -> String
showL forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Values -> String
showValues [Values]
vals))

            -- set default values of output and control entities
            ctrl :: M.Map Name (Maybe Values)
            ctrl :: DownControl
ctrl = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall {a}.
EntityDefault -> Map Name (Maybe a) -> Map Name (Maybe a)
op (MSOSWriter -> DownControl
ctrl_entities MSOSWriter
wr) [EntityDefault]
defaults
             where  op :: EntityDefault -> Map Name (Maybe a) -> Map Name (Maybe a)
op (DefControl Name
name) Map Name (Maybe a)
ctrl 
                        | Bool -> Bool
not (forall k a. Ord k => k -> Map k a -> Bool
M.member Name
name Map Name (Maybe a)
ctrl) = forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Name
name forall a. Maybe a
Nothing Map Name (Maybe a)
ctrl
                    op EntityDefault
_ Map Name (Maybe a)
ctrl = Map Name (Maybe a)
ctrl

            out :: InputValues
out = forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall {a}. EntityDefault -> Map Name [a] -> Map Name [a]
op (MSOSWriter -> InputValues
out_entities MSOSWriter
wr) [EntityDefault]
defaults
             where  op :: EntityDefault -> Map Name [a] -> Map Name [a]
op (DefOutput Name
name) Map Name [a]
out 
                        | Bool -> Bool
not (forall k a. Ord k => k -> Map k a -> Bool
M.member Name
name Map Name [a]
out) = forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Name
name [] Map Name [a]
out
                    op EntityDefault
_ Map Name [a]
out = Map Name [a]
out

            -- TODO this does not test the case that a control signal is expected 
            --      according to the test, but not present.
            printControl :: IO ()
printControl = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [(k, a)]
M.assocs DownControl
ctrl) (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Name -> Maybe Values -> IO ()
display)
             where  display :: Name -> Maybe Values -> IO ()
                    -- test whether control signal is expected when there is none
                    -- shows expected signal 
                    display :: Name -> Maybe Values -> IO ()
display Name
name Maybe Values
Nothing = case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name TestOptions
opts of 
                        Maybe [Funcons]
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
                        Just [Funcons]
vals -> String -> IO ()
putStrLn (String
"expected "forall a. [a] -> [a] -> [a]
++Name -> String
unpack Name
nameforall a. [a] -> [a] -> [a]
++String
": "
                                        forall a. [a] -> [a] -> [a]
++ [String] -> String
showL (forall a b. (a -> b) -> [a] -> [b]
map (Values -> String
showValues forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> Funcons -> Values
localEval Name
name) [Funcons]
vals))
                    -- test whether control signal is expected when there is one
                    -- shows that the emitted signal was unexpected
                    -- if a signal was expected, shows if actual and expected are unequal
                    display Name
name (Just Values
val) = case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name TestOptions
opts of
                        Maybe [Funcons]
Nothing -> String -> IO ()
putStrLn (String
"unexpected " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
": " forall a. [a] -> [a] -> [a]
++ Values -> String
showValues Values
val)
                        Just [Funcons]
expected -> forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless 
                                            (forall a b. (a -> b) -> [a] -> [b]
map (Name -> Funcons -> Values
localEval Name
name) [Funcons]
expected forall a. Eq a => a -> a -> Bool
== [Values
val]) 
                                            (Name -> String -> String -> IO ()
reportError Name
name ([String] -> String
showL forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Funcons -> String
showFuncons [Funcons]
expected) (Values -> String
showValues Values
val))

            printInputOutput :: InputValues -> IO ()
printInputOutput InputValues
remaining = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (forall k a. Map k a -> [(k, a)]
M.assocs InputValues
remaining) (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Name -> [Values] -> IO ()
display)
             where  -- no test-error if the input/output is empty 
                    -- (and no input/output was specified)
                    display :: Name -> [Values] -> IO ()
display Name
name [] | Maybe [Funcons]
Nothing <- forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name TestOptions
opts = forall (m :: * -> *) a. Monad m => a -> m a
return ()
                    display Name
name [Values]
vals = case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Name
name TestOptions
opts of
                        Maybe [Funcons]
Nothing -> String -> IO ()
putStrLn (String
"unexpected " forall a. [a] -> [a] -> [a]
++ Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
": " forall a. [a] -> [a] -> [a]
++ [String] -> String
showL (forall a b. (a -> b) -> [a] -> [b]
map Values -> String
showValues [Values]
vals))
                        Just [Funcons]
expected -> case forall a b. (a -> b) -> [a] -> [b]
map (Name -> Funcons -> Values
localEval Name
name) [Funcons]
expected of 
                            [ADTVal Name
"list" [Funcons]
exps] -> forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([Funcons]
exps forall a. Eq a => a -> a -> Bool
== forall a b. (a -> b) -> [a] -> [b]
map Values -> Funcons
FValue [Values]
vals) (Name -> String -> String -> IO ()
reportError Name
name ([String] -> String
showL forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Funcons -> String
showFuncons [Funcons]
exps) ([String] -> String
showL forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map Values -> String
showValues [Values]
vals))
                            [Values]
val -> forall a. HasCallStack => String -> a
error (String
"non-list given as expected output entity ("forall a. [a] -> [a] -> [a]
++
                                        Name -> String
unpack Name
name forall a. [a] -> [a] -> [a]
++ String
"): " forall a. [a] -> [a] -> [a]
++ [String] -> String
showL (forall a b. (a -> b) -> [a] -> [b]
map Values -> String
showValues [Values]
val))
                    

-- $moduledoc
-- This module exports functions for creating executables for funcon interpeters.
-- The executables accepts a number of command line and configuration options that
-- are explained here. The /funcons-tools/ package exports an interpreter for
-- the core library of reusable funcons. This executable is called /runfct/ and is used
-- as an example here.
--
-- @ dist\/build\/runfct\/runfct \<options\>@
--
-- === Options
--  Options are used to change the behaviour of the interpreter and to change the
--  output the interpreter provides after execution.
--  An option is either a boolean-option, a string-option, a .config file or a .fct file.
--  All command line flags are considered from left to right,
--    each changing the current configuration.
--
-- (1) __Funcon term file__: A file containing a funcon term. (must have .fct extension). 
--        These files contain funcon terms written 
--          in prefix form with parentheses surrounding comma-separated arguments,
--          e.g. integer-multiply(6,7). The parser also accepts notation for lists, 
--          tuples, sets and map. For example, @[1,2,3]@, @(1,2,3)@, @&#x7b;1,2,3&#x7d;@,
--          and @&#x7b;1 |-> true, 2 |-> false, 3 |-> true &#x7d;@ respectively.
--  
-- (2) __Configurations file__: A file containing configuration options (see below).
--          (must have .config extension)
--  
-- (3) __String options__ (comma-separate strings for multiple inputs):
--
--      * --display-mutable-entity \<string\>: by default mutable entities are not displayed
--            this option is used to display one or more mutable entities.
--
--      * --hide-output-entity \<string\>:
--            by default output entities are displayed when output is available.
--            this option is used to hide one or more output entities.
--
--      * --hide-control-entity \<string\>:
--            by default control entities are displayed when a signal is raised.
--            this option is used to hide one or more control entities .
--
--      * --hide-input-entity \<string\>:
--            by default input entities are displayed when input has not been consumed.
--            this option is used to hide one or more input entities.
--      * --max-restarts \<natural\>:
--          perform a maximum of `n` transitive steps, useful for debugging.
--
--      * --non-deterministic <ND-SOURCES+>: make specific parts of the interpreter non-determinstic (experimental)
--            <ND-SOURCES+> is a comma-separated list (of length at least one) containing one or more of:
--           rules: when several rules of a funcon "overlap"
--           pattern-matching: when multiple sequence variables occur in a pattern
--           interleaving-of-args: strict parameters in a funcon signature induce congruence rules that can be considered in different orders
--           value-operations: value operations may produce several valid results (e.g. `some-element`)
--
--     *seed <INT>: set a seed for the source of randomness, ineffective if --non-deterministic is not set
--
--
-- (4) __Boolean options__ (/true/, /false/ or no argument (/true/ by default)):
--
--      * --refocus \<bool\>: use refocusing, only valid under certain conditions.
--    
--      * --full-environments \<bool\>: when printing funcons, display environments 
--              using map-notation, by default an environment is printed as "...".
--    
--      * --hide-result \<bool\>: do not show the resulting funcon term.
--    
--      * --display-steps \<bool\>: show meta-information about the interpretation, 
--              e.g. the number of steps, rewrites and restarts. 
--    
--      * --no-abrupt-termination \<bool\>: disable abrupt termination (affects uncaught control signals).
--    
--      * --interactive-mode \<bool\>: use real I/O for input and output.
--              By default I/O is simulated and all input is expected to be 
--              provided in a configuration file (see below) and output is collected
--              and displayed after execution is finished.
--              In interactive mode, the user has to provide input via the standard input,
--              and output is printed to the standard output as soon as it is available.
--    
--      * --string-inputs \<bool\>: by default input is parsed into a 'Values'.
--            This option tells the interpreter to yield the given string as input.
--    
--      * --format-string-outputs \<bool\>: if all output values are strings (and with this option on),
--            any escape characters are interpreted (e.g. "\\n" becomes an actual newline), and
--            the strings are concatenated and not enclosed in double quotes.
--    
--      * --hide-tests \<bool\>: do not execute tests (by default tests are executed if specified in a configuration file).
--    
--      * --show-output-only \<bool\>: print only output (omits all other information).
--    
--      * --auto-config \<bool\>: if a .fct file is given, search for a .config file
--            with the same name and apply it (on by default).
--     
-- === Configuration files
--  A configuration file is a sequence of 'fragments', where each fragment is of the form:
--
-- > <group> {
-- >    <keyvalue>*
-- > }
-- 
--  A \<keyvalue\> is a colon separated key-value pair, closed off by a semicolon, e.g.
-- 
-- > hide-control-entity: failed,thrown;
--
--  There are 4 valid groups: /general/, /funcons/, /tests/ and /inputs/.
--  
-- (1) __general__:
--    The general /group/ is used as an alternative to command line flags,
--    All Boolean and string options are available.
--    Additionally, the option "funcon-term" is available for giving an initial 
--    funcon term:
--
--        > general {
--        >     funcon-term: integer-add(3,2);
--        > }
--
-- (2) __funcons__:
--    This group is used to define simple (nullary) funcons.
--    They key is the name of the funcon,
--    the value is a funcon term to which the funcon will rewrite once evaluated.
--    Keys and values are separated by '=' in this group. This group is useful
--    to choose an interpretation for unspecified components of a language specification.
--    For example (from a Caml Light specification):
--
--         > funcons {
--         >     implemented-vectors        = vectors(values);
--         >     implemented-floats-format  = binary64;
--         >     implemented-integers-width = 31;
--         >     implemented-characters     = unicode-characters;
--         >     implemented-strings        = strings;
--         > }
--
-- (3) __tests__:
--    With this group unit-tests can be defined.
--    Each key-value pairs specifies the expected value of a semantic entities,
--    where the key is the name of a semantic entity
--    and the value is the expected value.
--    Additionally, the key "result-term" can be used to specify the expected result term.
--    The tests group is useful to specify a complete unit-test in a single file, e.g.
--
--         > general {
--         >     funcon-term: else(integer-add(integer-add(2,3),fail),print(3));
--         > }
--         > tests {
--         >    result-term: ();
--         >    standard-out: [3];
--         > }
--
-- (4) __inputs__:
--    The inputs group is used to specify default values for input entities, e.g.
--
--         > inputs {
--         >     standard-in: [1,2,3];
--         > }
--
--        When input entities are given default values, simulation mode is turned on
--        (even if --interactive-mode is used).
-- 
-- === Languages specific interpreters
--    This package does not provide just one interpreter, it provides
--    the ability to play `mix and match' with 'FunconLibrary's to form interpreters.
--    This enables the creation of interpreters for object languages from funcons
--    (entities, or datatypes) specific to that object language.
-- 
--    For this purpose, this module exports 'mkMainWithLibraryEntitiesTypes' (and variants). 
--    Say that a module exporting
--    a 'FunconLibrary' is a "funcon module".
--    An interpreter is obtained by importing the chosen "funcon modules" and uniting 
--    their 'FunconLibrary's (with 'libUnions'), perhaps together with default
--    values for entities ('EntityDefault') and information about custom datatypes ('TypeRelation').
--    The resulting maps are given as arguments to 'mkMainWithLibraryEntitiesTypes'
--    (or variant).
--    By using 'mkMainWithLibraryEntitiesTypes', all interpreters inherit the 
--        core reusable funcon library.