packages feed

zeolite-lang 0.6.0.0 → 0.7.0.0

raw patch · 74 files changed

+2752/−1666 lines, 74 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Base.CompileError: class CompileError a
- Base.CompileError: compileError :: CompileError a => String -> a
- Base.CompileError: instance Base.CompileError.CompileErrorM m => Base.CompileError.CompileError (m a)
- Base.CompileError: isCompileError :: CompileError a => a -> Bool
- Base.CompileError: isCompileErrorM :: CompileErrorM m => m a -> Bool
- Base.CompileError: reviseError :: CompileError a => a -> String -> a
- Base.Mergeable: mergeNested :: Mergeable a => a -> a -> a
- Base.Mergeable: mergeNestedM :: (MergeableM m, Mergeable a) => m a -> m a -> m a
- Cli.ParseCompileOptions: tryFastModes :: [String] -> IO ()
- Cli.ProcessMetadata: checkAllowedStale :: Bool -> ForceMode -> IO ()
- Cli.ProcessMetadata: checkMetadataFreshness :: FilePath -> CompileMetadata -> IO Bool
- Cli.ProcessMetadata: loadMetadata :: MetadataMap -> FilePath -> IO CompileMetadata
- Cli.ProcessMetadata: tryLoadRecompile :: FilePath -> IO (Maybe ModuleConfig)
- Compilation.CompileInfo: data CompileInfo a
- Compilation.CompileInfo: data CompileMessage
- Compilation.CompileInfo: getCompileError :: CompileInfo a -> CompileMessage
- Compilation.CompileInfo: getCompileSuccess :: CompileInfo a -> a
- Compilation.CompileInfo: getCompileWarnings :: CompileInfo a -> [String]
- Compilation.CompileInfo: instance Base.CompileError.CompileErrorM Compilation.CompileInfo.CompileInfo
- Compilation.CompileInfo: instance Base.Mergeable.MergeableM Compilation.CompileInfo.CompileInfo
- Compilation.CompileInfo: instance Control.Monad.Fail.MonadFail Compilation.CompileInfo.CompileInfo
- Compilation.CompileInfo: instance GHC.Base.Applicative Compilation.CompileInfo.CompileInfo
- Compilation.CompileInfo: instance GHC.Base.Functor Compilation.CompileInfo.CompileInfo
- Compilation.CompileInfo: instance GHC.Base.Monad Compilation.CompileInfo.CompileInfo
- Compilation.CompileInfo: instance GHC.Show.Show Compilation.CompileInfo.CompileMessage
- Config.LoadConfig: LocalConfig :: Backend -> Resolver -> LocalConfig
- Config.LoadConfig: SimpleResolver :: [FilePath] -> [FilePath] -> Resolver
- Config.LoadConfig: UnixBackend :: FilePath -> [String] -> FilePath -> Backend
- Config.LoadConfig: [lcBackend] :: LocalConfig -> Backend
- Config.LoadConfig: [lcResolver] :: LocalConfig -> Resolver
- Config.LoadConfig: [srExtraPaths] :: Resolver -> [FilePath]
- Config.LoadConfig: [srVisibleSystem] :: Resolver -> [FilePath]
- Config.LoadConfig: [ucArBinary] :: Backend -> FilePath
- Config.LoadConfig: [ucCxxBinary] :: Backend -> FilePath
- Config.LoadConfig: [ucCxxOptions] :: Backend -> [String]
- Config.LoadConfig: compilerVersion :: String
- Config.LoadConfig: data Backend
- Config.LoadConfig: data LocalConfig
- Config.LoadConfig: data Resolver
- Config.LoadConfig: instance Config.Paths.PathResolver Config.LoadConfig.Resolver
- Config.LoadConfig: instance Config.Programs.CompilerBackend Config.LoadConfig.Backend
- Config.LoadConfig: instance GHC.Read.Read Config.LoadConfig.Backend
- Config.LoadConfig: instance GHC.Read.Read Config.LoadConfig.LocalConfig
- Config.LoadConfig: instance GHC.Read.Read Config.LoadConfig.Resolver
- Config.LoadConfig: instance GHC.Show.Show Config.LoadConfig.Backend
- Config.LoadConfig: instance GHC.Show.Show Config.LoadConfig.LocalConfig
- Config.LoadConfig: instance GHC.Show.Show Config.LoadConfig.Resolver
- Config.LoadConfig: rootPath :: IO FilePath
- Config.Paths: class PathResolver r
- Config.Paths: isBaseModule :: PathResolver r => r -> FilePath -> IO Bool
- Config.Paths: isSystemModule :: PathResolver r => r -> FilePath -> FilePath -> IO Bool
- Config.Paths: resolveBaseModule :: PathResolver r => r -> IO FilePath
- Config.Paths: resolveModule :: PathResolver r => r -> FilePath -> FilePath -> IO FilePath
- Config.Programs: CompileToBinary :: String -> [String] -> String -> [String] -> [String] -> CxxCommand
- Config.Programs: CompileToObject :: String -> String -> String -> String -> [String] -> Bool -> CxxCommand
- Config.Programs: TestCommand :: String -> String -> TestCommand
- Config.Programs: TestCommandResult :: Bool -> [String] -> [String] -> TestCommandResult
- Config.Programs: VersionHash :: String -> VersionHash
- Config.Programs: [ctbLinkFlags] :: CxxCommand -> [String]
- Config.Programs: [ctbMain] :: CxxCommand -> String
- Config.Programs: [ctbOutput] :: CxxCommand -> String
- Config.Programs: [ctbPaths] :: CxxCommand -> [String]
- Config.Programs: [ctbSources] :: CxxCommand -> [String]
- Config.Programs: [ctoExtra] :: CxxCommand -> Bool
- Config.Programs: [ctoNamespaceMacro] :: CxxCommand -> String
- Config.Programs: [ctoNamespace] :: CxxCommand -> String
- Config.Programs: [ctoPath] :: CxxCommand -> String
- Config.Programs: [ctoPaths] :: CxxCommand -> [String]
- Config.Programs: [ctoSource] :: CxxCommand -> String
- Config.Programs: [tcBinary] :: TestCommand -> String
- Config.Programs: [tcPath] :: TestCommand -> String
- Config.Programs: [tcrError] :: TestCommandResult -> [String]
- Config.Programs: [tcrOutput] :: TestCommandResult -> [String]
- Config.Programs: [tcrSuccess] :: TestCommandResult -> Bool
- Config.Programs: class CompilerBackend b
- Config.Programs: data CxxCommand
- Config.Programs: data TestCommand
- Config.Programs: data TestCommandResult
- Config.Programs: getCompilerHash :: CompilerBackend b => b -> VersionHash
- Config.Programs: instance GHC.Classes.Eq Config.Programs.VersionHash
- Config.Programs: instance GHC.Show.Show Config.Programs.CxxCommand
- Config.Programs: instance GHC.Show.Show Config.Programs.TestCommand
- Config.Programs: instance GHC.Show.Show Config.Programs.TestCommandResult
- Config.Programs: instance GHC.Show.Show Config.Programs.VersionHash
- Config.Programs: newtype VersionHash
- Config.Programs: runCxxCommand :: CompilerBackend b => b -> CxxCommand -> IO String
- Config.Programs: runTestCommand :: CompilerBackend b => b -> TestCommand -> IO TestCommandResult
+ Base.CompileError: errorFromIO :: (MonadIO m, CompileErrorM m) => IO a -> m a
+ Base.CompileError: mapErrorsM :: CompileErrorM m => (a -> m b) -> [a] -> m [b]
+ Base.CompileError: mapErrorsM_ :: CompileErrorM m => (a -> m b) -> [a] -> m ()
+ Base.CompileInfo: data CompileMessage
+ Base.CompileInfo: fromCompileInfo :: Monad m => CompileInfo a -> CompileInfoT m a
+ Base.CompileInfo: getCompileError :: CompileInfo a -> CompileMessage
+ Base.CompileInfo: getCompileErrorT :: Monad m => CompileInfoT m a -> m CompileMessage
+ Base.CompileInfo: getCompileSuccess :: CompileInfo a -> a
+ Base.CompileInfo: getCompileSuccessT :: Monad m => CompileInfoT m a -> m a
+ Base.CompileInfo: getCompileWarnings :: CompileInfo a -> [String]
+ Base.CompileInfo: getCompileWarningsT :: Monad m => CompileInfoT m a -> m [String]
+ Base.CompileInfo: instance (GHC.Base.Applicative m, GHC.Base.Monad m) => GHC.Base.Applicative (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance (GHC.Base.Functor m, GHC.Base.Monad m) => GHC.Base.Functor (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance Control.Monad.Trans.Class.MonadTrans Base.CompileInfo.CompileInfoT
+ Base.CompileInfo: instance GHC.Base.Monad m => Base.CompileError.CompileErrorM (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance GHC.Base.Monad m => Base.Mergeable.MergeableM (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance GHC.Base.Monad m => Control.Monad.Fail.MonadFail (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance GHC.Base.Monad m => GHC.Base.Monad (Base.CompileInfo.CompileInfoT m)
+ Base.CompileInfo: instance GHC.Show.Show Base.CompileInfo.CompileMessage
+ Base.CompileInfo: isCompileError :: CompileInfo a -> Bool
+ Base.CompileInfo: isCompileErrorT :: Monad m => CompileInfoT m a -> m Bool
+ Base.CompileInfo: toCompileInfo :: Monad m => CompileInfoT m a -> m (CompileInfo a)
+ Base.CompileInfo: tryCompileInfoIO :: String -> CompileInfoIO a -> IO a
+ Base.CompileInfo: type CompileInfo a = CompileInfoT Identity a
+ Base.CompileInfo: type CompileInfoIO a = CompileInfoT IO a
+ Base.MergeTree: data MergeTree a
+ Base.MergeTree: instance Base.Mergeable.Mergeable (Base.MergeTree.MergeTree a)
+ Base.MergeTree: instance Data.Foldable.Foldable Base.MergeTree.MergeTree
+ Base.MergeTree: instance Data.Traversable.Traversable Base.MergeTree.MergeTree
+ Base.MergeTree: instance GHC.Base.Functor Base.MergeTree.MergeTree
+ Base.MergeTree: instance GHC.Classes.Eq a => GHC.Classes.Eq (Base.MergeTree.MergeTree a)
+ Base.MergeTree: instance GHC.Show.Show a => GHC.Show.Show (Base.MergeTree.MergeTree a)
+ Base.MergeTree: mergeLeaf :: a -> MergeTree a
+ Base.MergeTree: pruneMergeTree :: MergeableM m => MergeTree (m a) -> m (MergeTree a)
+ Base.MergeTree: reduceMergeTree :: (Mergeable b, MergeableM m) => (b -> m b) -> (b -> m b) -> (a -> m b) -> MergeTree a -> m b
+ Base.Mergeable: instance Base.Mergeable.Mergeable [a]
+ Base.Mergeable: instance Base.Mergeable.MergeableM GHC.Maybe.Maybe
+ Cli.Paths: class PathIOHandler r
+ Cli.Paths: isBaseModule :: (PathIOHandler r, MonadIO m, CompileErrorM m) => r -> FilePath -> m Bool
+ Cli.Paths: isSystemModule :: (PathIOHandler r, MonadIO m, CompileErrorM m) => r -> FilePath -> FilePath -> m Bool
+ Cli.Paths: resolveBaseModule :: (PathIOHandler r, MonadIO m, CompileErrorM m) => r -> m FilePath
+ Cli.Paths: resolveModule :: (PathIOHandler r, MonadIO m, CompileErrorM m) => r -> FilePath -> FilePath -> m FilePath
+ Cli.ProcessMetadata: loadModuleMetadata :: VersionHash -> ForceMode -> MetadataMap -> FilePath -> CompileInfoIO CompileMetadata
+ Cli.ProcessMetadata: loadRecompile :: FilePath -> CompileInfoIO ModuleConfig
+ Cli.Programs: CompileToBinary :: String -> [String] -> String -> [String] -> [String] -> CxxCommand
+ Cli.Programs: CompileToObject :: String -> String -> String -> String -> [String] -> Bool -> CxxCommand
+ Cli.Programs: TestCommand :: String -> String -> TestCommand
+ Cli.Programs: TestCommandResult :: Bool -> [String] -> [String] -> TestCommandResult
+ Cli.Programs: VersionHash :: String -> VersionHash
+ Cli.Programs: [ctbLinkFlags] :: CxxCommand -> [String]
+ Cli.Programs: [ctbMain] :: CxxCommand -> String
+ Cli.Programs: [ctbOutput] :: CxxCommand -> String
+ Cli.Programs: [ctbPaths] :: CxxCommand -> [String]
+ Cli.Programs: [ctbSources] :: CxxCommand -> [String]
+ Cli.Programs: [ctoExtra] :: CxxCommand -> Bool
+ Cli.Programs: [ctoNamespaceMacro] :: CxxCommand -> String
+ Cli.Programs: [ctoNamespace] :: CxxCommand -> String
+ Cli.Programs: [ctoPath] :: CxxCommand -> String
+ Cli.Programs: [ctoPaths] :: CxxCommand -> [String]
+ Cli.Programs: [ctoSource] :: CxxCommand -> String
+ Cli.Programs: [tcBinary] :: TestCommand -> String
+ Cli.Programs: [tcPath] :: TestCommand -> String
+ Cli.Programs: [tcrError] :: TestCommandResult -> [String]
+ Cli.Programs: [tcrOutput] :: TestCommandResult -> [String]
+ Cli.Programs: [tcrSuccess] :: TestCommandResult -> Bool
+ Cli.Programs: class CompilerBackend b
+ Cli.Programs: data CxxCommand
+ Cli.Programs: data TestCommand
+ Cli.Programs: data TestCommandResult
+ Cli.Programs: getCompilerHash :: CompilerBackend b => b -> VersionHash
+ Cli.Programs: instance GHC.Classes.Eq Cli.Programs.VersionHash
+ Cli.Programs: instance GHC.Show.Show Cli.Programs.CxxCommand
+ Cli.Programs: instance GHC.Show.Show Cli.Programs.TestCommand
+ Cli.Programs: instance GHC.Show.Show Cli.Programs.TestCommandResult
+ Cli.Programs: instance GHC.Show.Show Cli.Programs.VersionHash
+ Cli.Programs: newtype VersionHash
+ Cli.Programs: runCxxCommand :: (CompilerBackend b, MonadIO m, CompileErrorM m) => b -> CxxCommand -> m String
+ Cli.Programs: runTestCommand :: (CompilerBackend b, MonadIO m, CompileErrorM m) => b -> TestCommand -> m TestCommandResult
+ Config.LocalConfig: LocalConfig :: Backend -> Resolver -> LocalConfig
+ Config.LocalConfig: SimpleResolver :: [FilePath] -> [FilePath] -> Resolver
+ Config.LocalConfig: UnixBackend :: FilePath -> [String] -> FilePath -> Backend
+ Config.LocalConfig: [lcBackend] :: LocalConfig -> Backend
+ Config.LocalConfig: [lcResolver] :: LocalConfig -> Resolver
+ Config.LocalConfig: [srExtraPaths] :: Resolver -> [FilePath]
+ Config.LocalConfig: [srVisibleSystem] :: Resolver -> [FilePath]
+ Config.LocalConfig: [ucArBinary] :: Backend -> FilePath
+ Config.LocalConfig: [ucCxxBinary] :: Backend -> FilePath
+ Config.LocalConfig: [ucCxxOptions] :: Backend -> [String]
+ Config.LocalConfig: compilerVersion :: String
+ Config.LocalConfig: data Backend
+ Config.LocalConfig: data LocalConfig
+ Config.LocalConfig: data Resolver
+ Config.LocalConfig: instance Cli.Paths.PathIOHandler Config.LocalConfig.Resolver
+ Config.LocalConfig: instance Cli.Programs.CompilerBackend Config.LocalConfig.Backend
+ Config.LocalConfig: instance GHC.Read.Read Config.LocalConfig.Backend
+ Config.LocalConfig: instance GHC.Read.Read Config.LocalConfig.LocalConfig
+ Config.LocalConfig: instance GHC.Read.Read Config.LocalConfig.Resolver
+ Config.LocalConfig: instance GHC.Show.Show Config.LocalConfig.Backend
+ Config.LocalConfig: instance GHC.Show.Show Config.LocalConfig.LocalConfig
+ Config.LocalConfig: instance GHC.Show.Show Config.LocalConfig.Resolver
+ Config.LocalConfig: rootPath :: IO FilePath
+ Parser.Common: inferredParam :: Parser ()
+ Parser.Procedure: instance Parser.Common.ParseFromSource (Types.Procedure.InstanceOrInferred Text.Parsec.Pos.SourcePos)
+ Test.CompileInfo: tests :: [IO (CompileInfo ())]
+ Test.MergeTree: tests :: [IO (CompileInfo ())]
+ Types.Positional: processPairsM :: (Show a, Show b, Mergeable c, CompileErrorM m) => (a -> b -> m c) -> Positional a -> Positional b -> m c
+ Types.Procedure: AssignedInstance :: [c] -> GeneralInstance -> InstanceOrInferred c
+ Types.Procedure: InferredInstance :: [c] -> InstanceOrInferred c
+ Types.Procedure: data InstanceOrInferred c
+ Types.Procedure: instance GHC.Show.Show c => GHC.Show.Show (Types.Procedure.InstanceOrInferred c)
+ Types.TypeCategory: inferParamTypes :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> Map ParamName GeneralInstance -> [(ValueType, ValueType)] -> m (Map ParamName GeneralInstance)
+ Types.TypeCategory: mergeInferredTypes :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> MergeTree InferredTypeGuess -> m [InferredTypeGuess]
+ Types.TypeInstance: InferredTypeGuess :: ParamName -> GeneralInstance -> Variance -> InferredTypeGuess
+ Types.TypeInstance: JustInferredType :: ParamName -> TypeInstanceOrParam
+ Types.TypeInstance: [itgGuess] :: InferredTypeGuess -> GeneralInstance
+ Types.TypeInstance: [itgParam] :: InferredTypeGuess -> ParamName
+ Types.TypeInstance: [itgVariance] :: InferredTypeGuess -> Variance
+ Types.TypeInstance: [jitParam] :: TypeInstanceOrParam -> ParamName
+ Types.TypeInstance: checkValueTypeMatch_ :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> ValueType -> ValueType -> m ()
+ Types.TypeInstance: data InferredTypeGuess
+ Types.TypeInstance: instance GHC.Classes.Eq Types.TypeInstance.InferredTypeGuess
+ Types.TypeInstance: instance GHC.Classes.Ord Types.TypeInstance.InferredTypeGuess
+ Types.TypeInstance: instance GHC.Show.Show Types.TypeInstance.InferredTypeGuess
+ Types.TypeInstance: noInferredTypes :: (MergeableM m, CompileErrorM m) => m (MergeTree InferredTypeGuess) -> m ()
- Base.CompileError: class (Functor m, Monad m, MonadFail m) => CompileErrorM m
+ Base.CompileError: class (Monad m, MonadFail m) => CompileErrorM m
- Base.Mergeable: class (Functor m, Monad m) => MergeableM m
+ Base.Mergeable: class Monad m => MergeableM m
- Cli.Compiler: compileModule :: ModuleSpec -> IO ()
+ Cli.Compiler: compileModule :: (PathIOHandler r, CompilerBackend b) => r -> b -> ModuleSpec -> CompileInfoIO ()
- Cli.Compiler: createModuleTemplates :: FilePath -> FilePath -> [CompileMetadata] -> [CompileMetadata] -> IO ()
+ Cli.Compiler: createModuleTemplates :: FilePath -> FilePath -> [CompileMetadata] -> [CompileMetadata] -> CompileInfoIO ()
- Cli.Compiler: runModuleTests :: CompilerBackend b => b -> FilePath -> [FilePath] -> LoadedTests -> IO [((Int, Int), CompileInfo ())]
+ Cli.Compiler: runModuleTests :: (PathIOHandler r, CompilerBackend b) => r -> b -> FilePath -> [FilePath] -> LoadedTests -> CompileInfoIO [((Int, Int), CompileInfo ())]
- Cli.ProcessMetadata: createCachePath :: FilePath -> IO ()
+ Cli.ProcessMetadata: createCachePath :: FilePath -> CompileInfoIO ()
- Cli.ProcessMetadata: eraseCachedData :: FilePath -> IO ()
+ Cli.ProcessMetadata: eraseCachedData :: FilePath -> CompileInfoIO ()
- Cli.ProcessMetadata: findSourceFiles :: FilePath -> FilePath -> IO ([FilePath], [FilePath], [FilePath])
+ Cli.ProcessMetadata: findSourceFiles :: FilePath -> FilePath -> CompileInfoIO ([FilePath], [FilePath], [FilePath])
- Cli.ProcessMetadata: getExprMap :: FilePath -> ModuleConfig -> IO (ExprMap SourcePos)
+ Cli.ProcessMetadata: getExprMap :: FilePath -> ModuleConfig -> CompileInfoIO (ExprMap SourcePos)
- Cli.ProcessMetadata: isPathConfigured :: FilePath -> IO Bool
+ Cli.ProcessMetadata: isPathConfigured :: FilePath -> CompileInfoIO Bool
- Cli.ProcessMetadata: isPathUpToDate :: VersionHash -> FilePath -> IO Bool
+ Cli.ProcessMetadata: isPathUpToDate :: VersionHash -> ForceMode -> FilePath -> CompileInfoIO Bool
- Cli.ProcessMetadata: loadPrivateDeps :: VersionHash -> MetadataMap -> [CompileMetadata] -> IO (Bool, [CompileMetadata])
+ Cli.ProcessMetadata: loadPrivateDeps :: VersionHash -> ForceMode -> MetadataMap -> [CompileMetadata] -> CompileInfoIO [CompileMetadata]
- Cli.ProcessMetadata: loadPublicDeps :: VersionHash -> MetadataMap -> [FilePath] -> IO (Bool, [CompileMetadata])
+ Cli.ProcessMetadata: loadPublicDeps :: VersionHash -> ForceMode -> MetadataMap -> [FilePath] -> CompileInfoIO [CompileMetadata]
- Cli.ProcessMetadata: loadTestingDeps :: VersionHash -> MetadataMap -> CompileMetadata -> IO (Bool, [CompileMetadata])
+ Cli.ProcessMetadata: loadTestingDeps :: VersionHash -> ForceMode -> MetadataMap -> CompileMetadata -> CompileInfoIO [CompileMetadata]
- Cli.ProcessMetadata: writeCachedFile :: FilePath -> String -> FilePath -> String -> IO ()
+ Cli.ProcessMetadata: writeCachedFile :: FilePath -> String -> FilePath -> String -> CompileInfoIO ()
- Cli.ProcessMetadata: writeMetadata :: FilePath -> CompileMetadata -> IO ()
+ Cli.ProcessMetadata: writeMetadata :: FilePath -> CompileMetadata -> CompileInfoIO ()
- Cli.ProcessMetadata: writeRecompile :: FilePath -> ModuleConfig -> IO ()
+ Cli.ProcessMetadata: writeRecompile :: FilePath -> ModuleConfig -> CompileInfoIO ()
- Cli.RunCompiler: runCompiler :: CompileOptions -> IO ()
+ Cli.RunCompiler: runCompiler :: (PathIOHandler r, CompilerBackend b) => r -> b -> CompileOptions -> CompileInfoIO ()
- Cli.TestRunner: runSingleTest :: CompilerBackend b => b -> LanguageModule SourcePos -> FilePath -> [FilePath] -> [CompileMetadata] -> (String, String) -> IO ((Int, Int), CompileInfo ())
+ Cli.TestRunner: runSingleTest :: CompilerBackend b => b -> LanguageModule SourcePos -> FilePath -> [FilePath] -> [CompileMetadata] -> (String, String) -> CompileInfoIO ((Int, Int), CompileInfo ())
- Config.LoadConfig: loadConfig :: IO (Backend, Resolver)
+ Config.LoadConfig: loadConfig :: (MonadIO m, CompileErrorM m) => m (Resolver, Backend)
- Test.Common: checkEquals :: (Eq a, Show a, MergeableM m, CompileErrorM m) => a -> a -> m ()
+ Test.Common: checkEquals :: (Eq a, Show a) => a -> a -> CompileInfo ()
- Test.Common: containsAtLeast :: (Ord a, Show a, MergeableM m, CompileErrorM m) => [a] -> [a] -> m ()
+ Test.Common: containsAtLeast :: (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
- Test.Common: containsAtMost :: (Ord a, Show a, MergeableM m, CompileErrorM m) => [a] -> [a] -> m ()
+ Test.Common: containsAtMost :: (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
- Test.Common: containsExactly :: (Ord a, Show a, MergeableM m, CompileErrorM m) => [a] -> [a] -> m ()
+ Test.Common: containsExactly :: (Ord a, Show a) => [a] -> [a] -> CompileInfo ()
- Test.Common: containsNoDuplicates :: (Ord a, Show a, MergeableM m, CompileErrorM m) => [a] -> m ()
+ Test.Common: containsNoDuplicates :: (Ord a, Show a) => [a] -> CompileInfo ()
- Test.Common: parseFilterMap :: CompileErrorM m => [(String, [String])] -> m ParamFilters
+ Test.Common: parseFilterMap :: [(String, [String])] -> CompileInfo ParamFilters
- Test.Common: parseTheTest :: (ParseFromSource a, CompileErrorM m) => [(String, [String])] -> [String] -> m ([a], ParamFilters)
+ Test.Common: parseTheTest :: ParseFromSource a => [(String, [String])] -> [String] -> CompileInfo ([a], ParamFilters)
- Test.Common: readMulti :: CompileErrorM m => ParseFromSource a => String -> String -> m [a]
+ Test.Common: readMulti :: ParseFromSource a => String -> String -> CompileInfo [a]
- Test.Common: readSingle :: (ParseFromSource a, CompileErrorM m) => String -> String -> m a
+ Test.Common: readSingle :: ParseFromSource a => String -> String -> CompileInfo a
- Test.Common: readSingleWith :: CompileErrorM m => Parser a -> String -> String -> m a
+ Test.Common: readSingleWith :: Parser a -> String -> String -> CompileInfo a
- Types.Procedure: FunctionCall :: [c] -> FunctionName -> Positional GeneralInstance -> Positional (Expression c) -> FunctionCall c
+ Types.Procedure: FunctionCall :: [c] -> FunctionName -> Positional (InstanceOrInferred c) -> Positional (Expression c) -> FunctionCall c
- Types.Procedure: FunctionSpec :: [c] -> FunctionQualifier c -> FunctionName -> Positional GeneralInstance -> FunctionSpec c
+ Types.Procedure: FunctionSpec :: [c] -> FunctionQualifier c -> FunctionName -> Positional (InstanceOrInferred c) -> FunctionSpec c
- Types.TypeInstance: checkGeneralMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> Variance -> GeneralInstance -> GeneralInstance -> m ()
+ Types.TypeInstance: checkGeneralMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> Variance -> GeneralInstance -> GeneralInstance -> m (MergeTree InferredTypeGuess)
- Types.TypeInstance: checkValueTypeMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> ValueType -> ValueType -> m ()
+ Types.TypeInstance: checkValueTypeMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) => r -> ParamFilters -> ValueType -> ValueType -> m (MergeTree InferredTypeGuess)

Files

ChangeLog.md view
@@ -1,5 +1,22 @@ # Revision history for zeolite-lang +## 0.7.0.0  -- 2020-05-19++### Language++* **[new]** Adds limited inference of type parameters in function calls. The new+  syntax is `call<?,Int>(foo,bar)`, where `?` designates that inference is+  requested for the first position.++* **[behavior]** Reduces the memory cost of `$TraceCreation$` by avoiding+  storing the entire trace text.++### Compiler CLI++* **[behavior]** Improves handling of I/O errors when calling `zeolite`, and+  allows compilation to continue in `-r`/`-R` modes if compilation of one module+  fails.+ ## 0.6.0.0  -- 2020-05-14  ### Compiler CLI
base/logging.cpp view
@@ -40,25 +40,26 @@       std::cerr << " '" << condition_ << "'";     }     std::cerr << ": " << output_.str() << std::endl;-    const TraceList call_trace = TraceContext::GetTrace();-    for (const auto& trace : call_trace) {-      if (!trace.empty()) {-        std::cerr << "  " << trace << std::endl;-      }-    }+    PrintTrace(TraceContext::GetTrace());     const TraceList creation_trace = TraceCreation::GetTrace();     if (!creation_trace.empty()) {       std::cerr << TraceCreation::GetType() << " value originally created at:" << std::endl;-      for (const auto& trace : creation_trace) {-        if (!trace.empty()) {-          std::cerr << "  " << trace << std::endl;-        }-      }+      PrintTrace(creation_trace);     }     std::raise(signal_);   } } +// static+void LogThenCrash::PrintTrace(const TraceList &call_trace) {+  for (const auto& trace : call_trace) {+    const std::string message = trace();+    if (!message.empty()) {+      std::cerr << "  " << message << std::endl;+    }+  }+}+ // TODO: Should only be available used if POSIX is defined. void TraceOnSignal(int signal) {   LogThenCrash(true,signal) << "Recieved signal " << signal;@@ -118,13 +119,17 @@ }  void SourceContext::AppendTrace(TraceList& trace) const {-  std::ostringstream output;-  if (at_ == nullptr || at_[0] == 0x00) {-    output << "From " << name_;-  } else {-    output << "From " << name_ << " at " << at_;-  }-  trace.push_back(output.str());+  const char* const name = name_;+  const char* const at   = at_;+  trace.push_back([name,at]() {+      std::ostringstream output;+      if (at == nullptr || at[0] == 0x00) {+        output << "From " << name;+      } else {+        output << "From " << name << " at " << at;+      }+      return output.str();+    }); }  const TraceContext* SourceContext::GetNext() const {@@ -137,13 +142,16 @@ }  void CleanupContext::AppendTrace(TraceList& trace) const {-  std::ostringstream output;-  if (at_ == nullptr || at_[0] == 0x00) {-    output << "In cleanup block";-  } else {-    output << "In cleanup block at " << at_;-  }-  trace.push_back(output.str());+  const char* const at = at_;+  trace.push_back([at]() {+      std::ostringstream output;+      if (at == nullptr || at[0] == 0x00) {+        output << "In cleanup block";+      } else {+        output << "In cleanup block at " << at;+      }+      return output.str();+    }); }  const TraceContext* CleanupContext::GetNext() const {
base/logging.hpp view
@@ -19,6 +19,7 @@ #ifndef LOGGING_HPP_ #define LOGGING_HPP_ +#include <functional> #include <list> #include <sstream> #include <string>@@ -31,6 +32,8 @@  void SetSignalHandler(); +using TraceList = std::list<std::function<std::string()>>;+ class LogThenCrash {  public:   LogThenCrash(bool fail, const std::string& condition = "");@@ -52,6 +55,8 @@   LogThenCrash& operator =(LogThenCrash&&) = delete;   void* operator new(std::size_t size) = delete; +  static void PrintTrace(const TraceList&);+   const bool fail_;   const int signal_;   const std::string condition_;@@ -94,9 +99,6 @@   #define TRACE_CREATION  #endif---using TraceList = std::list<std::string>;   class TraceContext : public capture_thread::ThreadCapture<TraceContext> {
bin/unit-tests.hs view
@@ -17,9 +17,12 @@ -- Author: Kevin P. Barry [ta0kira@gmail.com]  import Base.CompileError+import Base.CompileInfo import Test.Common+import qualified Test.CompileInfo     as TestCompileInfo import qualified Test.DefinedCategory as TestDefinedCategory import qualified Test.IntegrationTest as TestIntegrationTest+import qualified Test.MergeTree       as TestMergeTree import qualified Test.ParseMetadata   as TestParseMetadata import qualified Test.Parser          as TestParser import qualified Test.Pragma          as TestPragma@@ -31,8 +34,10 @@  main :: IO () main = runAllTests $ concat [+    labelWith "CompileInfo"     TestCompileInfo.tests,     labelWith "DefinedCategory" TestDefinedCategory.tests,     labelWith "IntegrationTest" TestIntegrationTest.tests,+    labelWith "MergeTree"       TestMergeTree.tests,     labelWith "ParseMetadata"   TestParseMetadata.tests,     labelWith "Parser"          TestParser.tests,     labelWith "Pragma"          TestPragma.tests,@@ -42,5 +47,5 @@     labelWith "TypeInstance"    TestTypeInstance.tests   ] -labelWith :: CompileErrorM m => String -> [IO (m ())] -> [IO (m ())]-labelWith s ts = map (\(n,t) -> fmap (`reviseError` ("In " ++ s ++ " (#" ++ show n ++ "):")) t) (zip ([1..] :: [Int]) ts)+labelWith :: String -> [IO (CompileInfo ())] -> [IO (CompileInfo ())]+labelWith s ts = map (\(n,t) -> fmap (`reviseErrorM` ("In " ++ s ++ " (#" ++ show n ++ "):")) t) (zip ([1..] :: [Int]) ts)
bin/zeolite-setup.hs view
@@ -24,7 +24,9 @@  import Cli.CompileOptions import Cli.RunCompiler+import Base.CompileInfo import Config.LoadConfig+import Config.LocalConfig   main :: IO ()@@ -38,7 +40,7 @@   config <- createConfig   hPutStrLn stderr $ "Writing local config to " ++ f ++ "."   writeFile f (show config ++ "\n")-  initLibraries+  initLibraries config   hPutStrLn stderr "Setup is now complete!"  clangBinary :: String@@ -114,8 +116,8 @@     exitFailure   hGetLine stdin -initLibraries :: IO ()-initLibraries = do+initLibraries :: LocalConfig -> IO ()+initLibraries (LocalConfig backend resolver) = do   path <- rootPath >>= canonicalizePath   let options = CompileOptions {       coHelp = HelpNotNeeded,@@ -128,4 +130,4 @@       coMode = CompileRecompileRecursive,       coForce = ForceAll     }-  runCompiler options+  tryCompileInfoIO "Zeolite setup failed." $ runCompiler resolver backend options
bin/zeolite.hs view
@@ -17,15 +17,22 @@ -- Author: Kevin P. Barry [ta0kira@gmail.com]  import Control.Monad (when)+import System.Directory import System.Environment import System.Exit import System.IO+import qualified Data.Map as Map  import Base.CompileError+import Cli.CompileMetadata import Cli.CompileOptions+import Cli.ProcessMetadata import Cli.ParseCompileOptions -- Not safe, due to Text.Regex.TDFA.+import Cli.Programs import Cli.RunCompiler-import Compilation.CompileInfo+import Base.CompileInfo+import Config.LoadConfig+import Config.LocalConfig   main :: IO ()@@ -33,19 +40,51 @@   args <- getArgs   tryFastModes args   let options = parseCompileOptions args >>= validateCompileOptions-  compile options where+  compile options+  hPutStrLn stderr "Zeolite execution succeeded." where     compile co       | isCompileError co = do           hPutStr stderr $ show $ getCompileError co           hPutStrLn stderr "Use the -h option to show help."           exitFailure-      | otherwise = do-        let co' = getCompileSuccess co-        when (HelpNotNeeded /= (coHelp co')) $ showHelp >> exitFailure-        runCompiler co'+      | otherwise = tryCompileInfoIO "Zeolite execution failed." $ do+          let co' = getCompileSuccess co+          (resolver,backend) <- loadConfig+          when (HelpNotNeeded /= (coHelp co')) $ errorFromIO $ showHelp >> exitFailure+          runCompiler resolver backend co'  showHelp :: IO () showHelp = do   hPutStrLn stderr "Zeolite CLI Help:"   mapM_ (hPutStrLn stderr . ("  " ++)) optionHelpText   hPutStrLn stderr "Also see https://ta0kira.github.io/zeolite for more documentation."++tryFastModes :: [String] -> IO ()+tryFastModes ("--get-path":os) = do+  when (not $ null os) $ hPutStrLn stderr $ "Ignoring extra arguments: " ++ show os+  p <- rootPath >>= canonicalizePath+  hPutStrLn stdout p+  if null os+     then exitSuccess+     else exitFailure+tryFastModes ("--version":os) = do+  when (not $ null os) $ hPutStrLn stderr $ "Ignoring extra arguments: " ++ show os+  hPutStrLn stdout compilerVersion+  if null os+     then exitSuccess+     else exitFailure+tryFastModes ("--show-deps":ps) = do+  tryCompileInfoIO "Zeolite execution failed." $ mapM_ showDeps ps+  exitSuccess where+    showDeps p = do+      (_,backend) <- loadConfig+      p' <- errorFromIO $ canonicalizePath p+      m <- loadModuleMetadata (getCompilerHash backend) ForceAll Map.empty p'+      errorFromIO $ hPutStrLn stdout $ show p'+      errorFromIO $ mapM_ showDep (cmObjectFiles m)+    showDep (CategoryObjectFile c ds _) = do+      mapM_ (\d -> hPutStrLn stdout $ "  " ++ show (ciCategory c) +++                                      " -> " ++ show (ciCategory d) +++                                      " " ++ show (ciPath d)) ds+    showDep _ = return ()+tryFastModes _ = return ()
example/parser/README.md view
@@ -24,12 +24,6 @@   (see `parser.0rp` and `parser.0rx`), which allows `ParseState` to   conditionally expose the `ParseContext` interface to other functions. -- **Function Merging.** `ParseState` and `ParseContext` declare some of the same-  functions in `parser.0rp`. When `ParseState` inherits `ParseContext`-  internally in `parser.0rx`, functions with the same names are merged by the-  compiler. This allows `ParseState` to expose a subset of `ParseContext`-  without needing a superfluous interface with the shared functions.- - **Parameter Variance.** Several categories used in this example (e.g.,   `ParseState` and `ParseContext`) have a *covariant* parameter, which allows   their parameters to be converted to other types. Specifically:@@ -57,6 +51,11 @@ - **Module Config.** The `.zeolite-module` file contains the build configuration   for this example. This means that building and running the example does not   require special instructions, scripting, or `Makefile`s.++- **Type Inference.** Several of the function definitions in the `.0rx` files+  request parameter type-inference using `?`, e.g., `ErrorOr$$value<?>(match)`.+  This is useful when the parameter value can be easily guessed by the reader of+  the code from its context.  ## Running 
example/parser/parse-text.0rp view
@@ -20,6 +20,7 @@  */ concrete Parse {   @type const<#x> (#x)                     -> (Parser<#x>)+  @type error     (Formatted)              -> (Parser<all>)   @type try<#x>   (Parser<#x>)             -> (Parser<#x>)   @type or<#x>    (Parser<#x>,Parser<#x>)  -> (Parser<#x>)   @type left<#x>  (Parser<#x>,Parser<any>) -> (Parser<#x>)
example/parser/parse-text.0rx view
@@ -5,7 +5,7 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<String>()+      return contextOld.convertError()     }     String message <- "Failed to match \"" + match + "\" at " + contextOld.getPosition()     ParseContext<any> context <- contextOld@@ -17,14 +17,14 @@           // Partial match => set error context.           return context.setBrokenInput(message)         } else {-          return context.setValue<String>(ErrorOr$$error(message))+          return context.setValue<?>(ErrorOr$$error(message))         }       }     } update {       index <- index+1       context <- context.advance()     }-    return context.setValue<String>(ErrorOr$$value<String>(match))+    return context.setValue<?>(ErrorOr$$value<?>(match))   }    create (match) {@@ -41,7 +41,7 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<String>()+      return contextOld.convertError()     }     String message <- "Failed to match [" + matches + "]{" +                       min.formatted() + "," + max.formatted() + "} at " +@@ -70,12 +70,12 @@       context <- context.advance()     }     if (count >= min) {-      return context.setValue<String>(ErrorOr$$value<String>(builder.build()))+      return context.setValue<?>(ErrorOr$$value<?>(builder.build()))     } elif (count > 0) {       // Partial match => set error context.       return context.setBrokenInput(message)     } else {-      return context.setValue<String>(ErrorOr$$error(message))+      return context.setValue<?>(ErrorOr$$error(message))     }   } @@ -91,13 +91,13 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<Char>()+      return contextOld.convertError()     }     if (contextOld.atEof() || contextOld.current() != match) {       String message <- "Failed to match '" + match.formatted() + "' at " + contextOld.getPosition()-      return contextOld.setValue<Char>(ErrorOr$$error(message))+      return contextOld.setValue<?>(ErrorOr$$error(message))     } else {-      return contextOld.advance().setValue<Char>(ErrorOr$$value<Char>(match))+      return contextOld.advance().setValue<?>(ErrorOr$$value<?>(match))     }   } @@ -116,7 +116,7 @@   @value #x value    run (contextOld) {-    return contextOld.setValue<#x>(ErrorOr$$value<#x>(value))+    return contextOld.setValue<?>(ErrorOr$$value<?>(value))   }    create (value) {@@ -124,6 +124,24 @@   } } +concrete ErrorParser {+  @type create (Formatted) -> (Parser<all>)+}++define ErrorParser {+  refines Parser<all>++  @value Formatted message++  run (contextOld) {+    return contextOld.setValue<?>(ErrorOr$$error(message))+  }++  create (message) {+    return ErrorParser{ message }+  }+}+ concrete TryParser<#x> {   @type create (Parser<#x>) -> (Parser<#x>) }@@ -135,11 +153,11 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<#x>()+      return contextOld.convertError()     }     ParseContext<#x> context <- contextOld.run<#x>(parser)     if (context.hasAnyError()) {-      return contextOld.setValue<#x>(context.getValue().convertError())+      return contextOld.setValue<?>(context.getValue().convertError())     } else {       return context.toState()     }@@ -162,7 +180,7 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<#x>()+      return contextOld.convertError()     }     ParseContext<#x> context <- contextOld.run<#x>(parser1)     if (context.hasAnyError() && !context.hasBrokenInput()) {@@ -189,13 +207,18 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<#x>()+      return contextOld.convertError()     }     ParseContext<#x> context <- contextOld.run<#x>(parser1)-    if (!context.hasAnyError()) {-      return context.run<any>(parser2).setValue<#x>(context.getValue())-    } else {+    if (context.hasAnyError()) {       return context.toState()+    } else {+      ParseContext<any> context2 <- context.run<any>(parser2)+      if (context2.hasAnyError()) {+        return context2.convertError()+      } else {+        return context2.setValue<?>(context.getValue())+      }     }   } @@ -216,13 +239,13 @@    run (contextOld) {     if (contextOld.hasAnyError()) {-      return contextOld.convertError<#x>()+      return contextOld.convertError()     }     ParseContext<any> context <- contextOld.run<any>(parser1)-    if (!context.hasAnyError()) {-      return context.run<#x>(parser2).toState()+    if (context.hasAnyError()) {+      return context.convertError()     } else {-      return context.convertError<#x>()+      return context.run<#x>(parser2).toState()     }   } @@ -234,6 +257,10 @@ define Parse {   const (value) {     return ConstParser<#x>$create(value)+  }++  error (message) {+    return ErrorParser$create(message)   }    try (parser) {
example/parser/parser.0rp view
@@ -6,14 +6,8 @@  * ParseState<all> can convert to all other ParseState.  */ concrete ParseState<|#x> {-  @category new (String) -> (ParseState<any>)--  @value run<#y>       (Parser<#y>) -> (ParseState<#y>)-  @value runAndGet<#y> (Parser<#y>) -> (ParseState<any>,ErrorOr<#y>)--  @value atEof       () -> (Bool)-  @value hasAnyError () -> (Bool)-  @value getError    () -> (Formatted)+  // Consumes all input and returns the result.+  @category consumeAll<#y> (Parser<#y>,String) -> (ErrorOr<#y>) }  /* A self-contained parser operation.@@ -31,21 +25,24 @@  * ParseContext<all> can convert to all other ParseContext.  */ @value interface ParseContext<|#x> {+  // Continue computation.   run<#y>       (Parser<#y>) -> (ParseContext<#y>)   runAndGet<#y> (Parser<#y>) -> (ParseContext<any>,ErrorOr<#y>)--  convertError<#y> ()            -> (ParseState<#y>)-  getValue         ()            -> (ErrorOr<#x>)-  setValue<#y>     (ErrorOr<#y>) -> (ParseState<#y>)-  setBrokenInput   (Formatted)   -> (ParseState<all>)-  toState          ()            -> (ParseState<#x>)+  getValue      ()           -> (ErrorOr<#x>) -  getPosition () -> (String)+  // End computation and pass on the next state.+  convertError   ()            -> (ParseState<all>)+  setValue<#y>   (ErrorOr<#y>) -> (ParseState<#y>)+  setBrokenInput (Formatted)   -> (ParseState<all>)+  toState        ()            -> (ParseState<#x>) +  // Context metadata.+  getPosition    () -> (String)   atEof          () -> (Bool)   hasAnyError    () -> (Bool)   hasBrokenInput () -> (Bool) +  // Reading data.   current () -> (Char)   advance () -> (ParseContext<#x>) }
example/parser/parser.0rx view
@@ -1,11 +1,4 @@ define ParseState {-  // This internal inheritance takes advantage of function merging.-  //-  // Notice that several functions (e.g., run, hasAnyError) appear to be-  // declared separately in ParseState and ParseContext in parser.0rp. Since the-  // function types are compatible, the compiler automatically merges them. This-  // allows ParseState to expose a subset of ParseContext without needing a-  // superfluous interface that both categories refine.   refines ParseContext<#x>    @value String             data@@ -15,8 +8,15 @@   @value ErrorOr<#x>        value   @value optional Formatted error -  new (data) {-    return ParseState<any>{ data, 0, 0, 0, ErrorOr$$value<Void>(Void$void()), empty }+  consumeAll (parser,data) {+    ParseContext<#y> context <- parser.run(new(data))+    if (context.hasAnyError()) {+      return context.getValue()+    } elif (!context.atEof()) {+      return ErrorOr$$error("Parsing did not consume all of the data " + context.getPosition())+    } else {+      return context.getValue()+    }   }    run (parser) {@@ -24,14 +24,10 @@   }    runAndGet (parser) {-    ParseState<#y> context <- parser.run(self)+    ParseContext<#y> context <- parser.run(self)     return context, context.getValue()   } -  convertError () {-    return ParseState<#y>{ data, index, line, char, ErrorOr$$error(getError()), error }-  }-   getValue () {     if (present(error)) {       return ErrorOr$$error(require(error))@@ -40,9 +36,13 @@     }   } +  convertError () {+    return ParseState<all>{ data, index, line, char, ErrorOr$$error(getError()), error }+  }+   setValue (value2) {     if (hasBrokenInput()) {-      return convertError<#y>()+      return convertError()     } else {       return ParseState<#y>{ data, index, line, char, value2, error }     }@@ -58,11 +58,11 @@    getPosition () {     return String$builder()-        .append("(")+        .append("[line: ")         .append(line.formatted())-        .append(",")+        .append(", char: ")         .append(char.formatted())-        .append(")")+        .append("]")         .build()   } @@ -86,12 +86,18 @@   advance () {     \ sanityCheck()     if (data.readPosition(index) == '\n') {-      return ParseState<#x>{ data, index+1, line+1, 0, value, error }+      return ParseState<#x>{ data, index+1, line+1, 1, value, error }     } else {       return ParseState<#x>{ data, index+1, line, char+1, value, error }     }   } +  @category new (String) -> (ParseState<any>)+  new (data) {+    return ParseState<any>{ data, 0, 1, 1, ErrorOr$$value<?>(Void$void()), empty }+  }++  @value getError () -> (Formatted)   getError () {     if (present(error)) {       return require(error)
example/parser/test-data.0rp view
@@ -1,9 +1,11 @@ $TestsOnly$ -/* Parses the test-data.txt file using a one-off format.+/* A contrived object for test data.  */ concrete TestData {-  @type parseFrom (String) -> (ErrorOr<TestData>)+  // Parses the test-data.txt file using a one-off format.+  @type parseFrom (String)             -> (ErrorOr<TestData>)+  @type create    (String,String,Bool) -> (TestData)    @value getName        () -> (String)   @value getDescription () -> (String)
example/parser/test-data.0rx view
@@ -1,46 +1,16 @@ $TestsOnly$  define TestData {-  @category Parser<any> whitespace <- SequenceOfParser$create(" \n\t",1,0)--  @category Parser<String> sentence        <- SentenceParser$create()-  @category Parser<String> token           <- SequenceOfParser$create("ABCDEFGHIJKLMNOPQRSTUVWXYZ_",1,0)-  @category Parser<String> sentenceOrToken <- sentence `Parse$or<String>` token `Parse$left<String>` whitespace--  @category Parser<Bool> acronym           <- StringParser$create("acronym")  `Parse$right<Bool>` Parse$const<Bool>(true)-  @category Parser<Bool> aardvark          <- StringParser$create("aardvark") `Parse$right<Bool>` Parse$const<Bool>(false)-  @category Parser<Bool> acronymOrAardvark <- `Parse$try<Bool>` acronym `Parse$or<Bool>` aardvark `Parse$left<Bool>` whitespace--  @category Parser<any> fileStart      <- StringParser$create("file_start")   `Parse$left<any>` whitespace-  @category Parser<any> fileEnd        <- StringParser$create("file_end")     `Parse$left<any>` whitespace-  @category Parser<any> nameTag        <- StringParser$create("name:")        `Parse$left<any>` whitespace-  @category Parser<any> descriptionTag <- StringParser$create("description:") `Parse$left<any>` whitespace-  @category Parser<any> aWordTag       <- StringParser$create("a_word:")      `Parse$left<any>` whitespace-   @value String name   @value String description   @value Bool   boolean    parseFrom (data) {-    ParseState<any> state <- ParseState$$new(data)-    state                              <- state.run<any>(fileStart)-    state                              <- state.run<any>(nameTag)-    state, ErrorOr<String> name        <- state.runAndGet<String>(sentenceOrToken)-    state                              <- state.run<any>(descriptionTag)-    state, ErrorOr<String> description <- state.runAndGet<String>(sentenceOrToken)-    state                              <- state.run<any>(aWordTag)-    state, ErrorOr<Bool> boolean       <- state.runAndGet<Bool>(acronymOrAardvark)-    state                              <- state.run<any>(fileEnd)+    return TestDataParser$create() `ParseState$$consumeAll<?>` data+  } -    if (state.hasAnyError()) {-      return ErrorOr$$error(state.getError())-    } elif (!state.atEof()) {-      return ErrorOr$$error("Parsing did not consume all of the data")-    } else {-      return ErrorOr$$value<TestData>(TestData{ name.getValue(),-                                                description.getValue(),-                                                boolean.getValue() })-    }+  create (name,description,boolean) {+    return TestData{ name, description, boolean }   }    getName () {@@ -56,30 +26,57 @@   } } -concrete SentenceParser {-  @type create () -> (Parser<String>)+concrete TestDataParser {+  @type create () -> (Parser<TestData>) } -define SentenceParser {-  refines Parser<String>+define TestDataParser {+  refines Parser<TestData> +  @category Parser<any> whitespace <- SequenceOfParser$create(" \n\t",1,0) `Parse$or<?>` Parse$error("Expected whitespace")+   @category String sentenceChars <- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +                                     "abcdefghijklmnopqrstuvwxyz" +                                     "., !?-"-  @category Parser<String> string <- SequenceOfParser$create(sentenceChars,0,0)+  @category Parser<String> sentence <- SequenceOfParser$create(sentenceChars,0,0)+  @category Parser<any>    quote    <- CharParser$create('"') +  @category Parser<String> quotedSentence  <- quote `Parse$right<?>` sentence `Parse$left<?>` quote+  @category Parser<String> token           <- SequenceOfParser$create("ABCDEFGHIJKLMNOPQRSTUVWXYZ_",1,0)+  @category Parser<String> sentenceOrToken <- quotedSentence `Parse$or<?>` token `Parse$left<?>` whitespace++  @category Parser<Bool> acronym           <- StringParser$create("acronym")  `Parse$right<?>` Parse$const<?>(true)+  @category Parser<Bool> aardvark          <- StringParser$create("aardvark") `Parse$right<?>` Parse$const<?>(false)+  @category Parser<Bool> acronymOrAardvark <- Parse$try<?>(acronym) `Parse$or<?>` aardvark `Parse$left<?>` whitespace++  @category Parser<any> fileStart      <- StringParser$create("file_start")   `Parse$left<?>` whitespace+  @category Parser<any> fileEnd        <- StringParser$create("file_end")     `Parse$left<?>` whitespace+  @category Parser<any> nameTag        <- StringParser$create("name:")        `Parse$left<?>` whitespace+  @category Parser<any> descriptionTag <- StringParser$create("description:") `Parse$left<?>` whitespace+  @category Parser<any> aWordTag       <- StringParser$create("a_word:")      `Parse$left<?>` whitespace+   run (contextOld) {-    if (contextOld.hasAnyError()) {-      return contextOld.convertError<String>()-    }     ParseContext<any> context <- contextOld-    context                       <- context.run<any>(CharParser$create('"'))-    context, ErrorOr<String> text <- context.runAndGet<String>(string)-    context                       <- context.run<any>(CharParser$create('"'))-    return context.setValue<String>(text)+    context                              <- context.run<?>(fileStart)+    context                              <- context.run<?>(nameTag)+    context, ErrorOr<String> name        <- context.runAndGet<?>(sentenceOrToken)+    context                              <- context.run<?>(descriptionTag)+    context, ErrorOr<String> description <- context.runAndGet<?>(sentenceOrToken)+    context                              <- context.run<?>(aWordTag)+    context, ErrorOr<Bool> boolean       <- context.runAndGet<?>(acronymOrAardvark)+    context                              <- context.run<?>(fileEnd)++    if (context.hasAnyError()) {+      return context.convertError()+    } else {+      return context.setValue<?>(+        ErrorOr$$value<?>(TestData$create(name.getValue(),+                                          description.getValue(),+                                          boolean.getValue())))+    }   } -  create () {-    return SentenceParser{ }+  create ()  {+    return TestDataParser{ }   } }
example/tree/tree-demo.0rx view
@@ -11,15 +11,15 @@     TypeKey<Float>  keyFloat  <- TypeKey<Float>$new()     TypeKey<Value>  keyValue  <- TypeKey<Value>$new() -    \ tree.set<Int>(keyInt,1)-    \ tree.set<String>(keyString,"a")+    \ tree.set<?>(keyInt,1)+    \ tree.set<?>(keyString,"a") -    \ check<Int>(tree,keyInt)-    \ check<String>(tree,keyString)-    \ check<Float>(tree,keyFloat)  // Not found, since we never added a value.+    \ check<?>(tree,keyInt)+    \ check<?>(tree,keyString)+    \ check<?>(tree,keyFloat)  // Not found, since we never added a value. -    \ tree.set<Value>(keyValue,Value$new())-    \ check<Value>(tree,keyValue)+    \ tree.set<?>(keyValue,Value$new())+    \ check<?>(tree,keyValue)   }    @category check<#x>
example/tree/type-tree.0rx view
@@ -12,7 +12,7 @@   }    set (k,v) {-    \ tree.set(k,LockedType$$create<#x>(k,v))+    \ tree.set(k,LockedType$$create<?>(k,v))     return self   } @@ -25,7 +25,7 @@     scoped {       optional LockedType<any> value <- tree.get(k)     } in if (present(value)) {-      return require(value).check<#x>(k)+      return require(value).check<?>(k)     } else {       return empty     }
lib/math/tests.0rt view
@@ -22,7 +22,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$cos(2.0),-0.42,-0.41)+    \ Testing$checkBetween<?>(Math$cos(2.0),-0.42,-0.41)   } } @@ -37,7 +37,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$sin(2.0),0.90,0.91)+    \ Testing$checkBetween<?>(Math$sin(2.0),0.90,0.91)   } } @@ -52,7 +52,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$tan(2.0),-2.19,-2.18)+    \ Testing$checkBetween<?>(Math$tan(2.0),-2.19,-2.18)   } } @@ -67,7 +67,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$acos(0.5),1.04,1.05)+    \ Testing$checkBetween<?>(Math$acos(0.5),1.04,1.05)   } } @@ -82,7 +82,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$asin(0.5),0.52,0.53)+    \ Testing$checkBetween<?>(Math$asin(0.5),0.52,0.53)   } } @@ -97,7 +97,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$atan(0.5),0.46,0.47)+    \ Testing$checkBetween<?>(Math$atan(0.5),0.46,0.47)   } } @@ -112,7 +112,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$cosh(2.0),3.76,3.77)+    \ Testing$checkBetween<?>(Math$cosh(2.0),3.76,3.77)   } } @@ -127,7 +127,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$sinh(2.0),3.62,3.63)+    \ Testing$checkBetween<?>(Math$sinh(2.0),3.62,3.63)   } } @@ -142,7 +142,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$tanh(2.0),0.96,0.97)+    \ Testing$checkBetween<?>(Math$tanh(2.0),0.96,0.97)   } } @@ -157,7 +157,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$acosh(2.0),1.31,1.32)+    \ Testing$checkBetween<?>(Math$acosh(2.0),1.31,1.32)   } } @@ -172,7 +172,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$asinh(2.0),1.44,1.45)+    \ Testing$checkBetween<?>(Math$asinh(2.0),1.44,1.45)   } } @@ -187,7 +187,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$atanh(0.5),0.54,0.55)+    \ Testing$checkBetween<?>(Math$atanh(0.5),0.54,0.55)   } } @@ -202,7 +202,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$exp(1.0),2.71,2.72)+    \ Testing$checkBetween<?>(Math$exp(1.0),2.71,2.72)   } } @@ -217,7 +217,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$log(9.0),2.19,2.20)+    \ Testing$checkBetween<?>(Math$log(9.0),2.19,2.20)   } } @@ -232,7 +232,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$log10(100.0),1.99,2.01)+    \ Testing$checkBetween<?>(Math$log10(100.0),1.99,2.01)   } } @@ -247,7 +247,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$log2(8.0),2.99,3.01)+    \ Testing$checkBetween<?>(Math$log2(8.0),2.99,3.01)   } } @@ -262,7 +262,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$pow(2.0,3.0),7.99,8.01)+    \ Testing$checkBetween<?>(Math$pow(2.0,3.0),7.99,8.01)   } } @@ -277,7 +277,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$sqrt(4.0),1.99,2.01)+    \ Testing$checkBetween<?>(Math$sqrt(4.0),1.99,2.01)   } } @@ -292,7 +292,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$ceil(2.2),2.99,3.01)+    \ Testing$checkBetween<?>(Math$ceil(2.2),2.99,3.01)   } } @@ -307,7 +307,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$floor(2.2),1.99,2.01)+    \ Testing$checkBetween<?>(Math$floor(2.2),1.99,2.01)   } } @@ -322,7 +322,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$fmod(7.0,4.0),2.99,3.01)+    \ Testing$checkBetween<?>(Math$fmod(7.0,4.0),2.99,3.01)   } } @@ -337,7 +337,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$trunc(2.2),1.99,2.01)+    \ Testing$checkBetween<?>(Math$trunc(2.2),1.99,2.01)   } } @@ -352,7 +352,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$round(2.7),2.99,3.01)+    \ Testing$checkBetween<?>(Math$round(2.7),2.99,3.01)   } } @@ -367,7 +367,7 @@  define Test {   run () {-    \ Testing$checkBetween<Float>(Math$fabs(-10.0),9.99,10.01)+    \ Testing$checkBetween<?>(Math$fabs(-10.0),9.99,10.01)   } } 
lib/util/tests.0rt view
@@ -260,7 +260,7 @@ define Test {   run () {     String allContents <- TextReader$readAll(FakeFile$create())-    \ Testing$check<String>(allContents,"this is a partial line\nwith some more data\nand\nmore lines\nunfinished")+    \ Testing$check<?>(allContents,"this is a partial line\nwith some more data\nand\nmore lines\nunfinished")   } } @@ -315,7 +315,7 @@     if (!value.isError()) {       fail("Failed")     }-    \ Testing$check<String>(value.getError().formatted(),"error message")+    \ Testing$check<?>(value.getError().formatted(),"error message")   } } @@ -350,7 +350,7 @@     scoped {       ErrorOr<String> error <- ErrorOr$$error("error message")     } in ErrorOr<Int> value <- error.convertError()-    \ Testing$check<String>(value.getError().formatted(),"error message")+    \ Testing$check<?>(value.getError().formatted(),"error message")   } } 
src/Base/CompileError.hs view
@@ -21,14 +21,14 @@ {-# LANGUAGE Safe #-}  module Base.CompileError (-  CompileError(..),   CompileErrorM(..),+  errorFromIO,+  mapErrorsM,+  mapErrorsM_, ) where -#if MIN_VERSION_base(4,8,0)-#else-import Data.Foldable-#endif+import Control.Monad.IO.Class+import System.IO.Error (catchIOError)  #if MIN_VERSION_base(4,13,0) import Control.Monad.Fail ()@@ -37,27 +37,28 @@ #endif  -class CompileError a where-  compileError :: String -> a-  isCompileError :: a -> Bool-  reviseError :: a -> String -> a-  reviseError e _ = e- -- For some GHC versions, pattern-matching failures require MonadFail. #if MIN_VERSION_base(4,9,0)-class (Functor m, Monad m, MonadFail m) => CompileErrorM m where+class (Monad m, MonadFail m) => CompileErrorM m where #else-class (Functor m, Monad m) => CompileErrorM m where+class Monad m => CompileErrorM m where #endif   compileErrorM :: String -> m a-  isCompileErrorM :: m a -> Bool   collectAllOrErrorM :: Foldable f => f (m a) -> m [a]   collectOneOrErrorM :: Foldable f => f (m a) -> m a   reviseErrorM :: m a -> String -> m a   reviseErrorM e _ = e   compileWarningM :: String -> m () -instance CompileErrorM m => CompileError (m a) where-  compileError = compileErrorM-  isCompileError = isCompileErrorM-  reviseError = reviseErrorM+mapErrorsM :: CompileErrorM m => (a -> m b) -> [a] -> m [b]+mapErrorsM f = collectAllOrErrorM . map f++mapErrorsM_ :: CompileErrorM m => (a -> m b) -> [a] -> m ()+mapErrorsM_ f xs = mapErrorsM f xs >> return ()++errorFromIO :: (MonadIO m, CompileErrorM m) => IO a -> m a+errorFromIO x = do+  x' <- liftIO $ fmap Right x `catchIOError` (return . Left . show)+  case x' of+       (Right x2) -> return x2+       (Left e)   -> compileErrorM e
+ src/Base/CompileInfo.hs view
@@ -0,0 +1,224 @@+{- -----------------------------------------------------------------------------+Copyright 2019-2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE Safe #-}++module Base.CompileInfo (+  CompileInfo,+  CompileInfoIO,+  CompileMessage,+  fromCompileInfo,+  getCompileError,+  getCompileErrorT,+  getCompileSuccess,+  getCompileSuccessT,+  getCompileWarnings,+  getCompileWarningsT,+  isCompileError,+  isCompileErrorT,+  toCompileInfo,+  tryCompileInfoIO,+) where++import Control.Applicative+import Control.Monad ((>=>))+import Control.Monad.IO.Class ()+import Control.Monad.Trans+import Data.Foldable+import Data.Functor+import Data.Functor.Identity+import Data.List (intercalate)+import Prelude hiding (concat,foldr)+import System.Exit+import System.IO++#if MIN_VERSION_base(4,13,0)+import Control.Monad.Fail ()+#elif MIN_VERSION_base(4,9,0)+import Control.Monad.Fail+#endif++import Base.CompileError+import Base.Mergeable+++type CompileInfo a = CompileInfoT Identity a++type CompileInfoIO a = CompileInfoT IO a++data CompileInfoT m a =+  CompileInfoT {+    citState :: m (CompileInfoState a)+  }++getCompileError :: CompileInfo a -> CompileMessage+getCompileError = runIdentity . getCompileErrorT++getCompileSuccess :: CompileInfo a -> a+getCompileSuccess = runIdentity . getCompileSuccessT++getCompileWarnings :: CompileInfo a -> [String]+getCompileWarnings = runIdentity . getCompileWarningsT++isCompileError :: CompileInfo a -> Bool+isCompileError = runIdentity . isCompileErrorT++getCompileErrorT :: Monad m => CompileInfoT m a -> m CompileMessage+getCompileErrorT = fmap cfErrors . citState++getCompileSuccessT :: Monad m => CompileInfoT m a -> m a+getCompileSuccessT = fmap csData . citState++getCompileWarningsT :: Monad m => CompileInfoT m a -> m [String]+getCompileWarningsT = fmap getWarnings . citState++isCompileErrorT :: Monad m => CompileInfoT m a -> m Bool+isCompileErrorT x = do+  x' <- citState x+  case x' of+       CompileFail _ _ -> return True+       _               -> return False++fromCompileInfo :: Monad m => CompileInfo a -> CompileInfoT m a+fromCompileInfo x = runIdentity $ do+  x' <- citState x+  return $ CompileInfoT $ return x'++toCompileInfo :: Monad m => CompileInfoT m a -> m (CompileInfo a)+toCompileInfo x = do+  x' <- citState x+  return $ CompileInfoT $ return x'++tryCompileInfoIO :: String -> CompileInfoIO a -> IO a+tryCompileInfoIO message x = do+  x' <- toCompileInfo $ x `reviseErrorM` message+  if isCompileError x'+     then do+       hPutStr stderr $ concat $ map (++ "\n") (getCompileWarnings x')+       hPutStr stderr $ show $ getCompileError x'+       exitFailure+     else do+       hPutStr stderr $ concat $ map (++ "\n") (getCompileWarnings x')+       return $ getCompileSuccess x'++data CompileMessage =+  CompileMessage {+    cmMessage :: String,+    cmNested :: [CompileMessage]+  }++instance Show CompileMessage where+  show = format "" where+    format indent (CompileMessage [] ms) =+      concat (map (format indent) ms)+    format indent (CompileMessage m ms) =+      (doIndent indent m) ++ "\n" ++ concat (map (format $ indent ++ "  ") ms)+    doIndent indent s = intercalate "\n" $ map (indent ++) $ lines s++data CompileInfoState a =+  CompileFail {+    cfWarnings :: [String],+    cfErrors :: CompileMessage+  } |+  CompileSuccess {+    csWarnings :: [String],+    csData :: a+  }++instance (Functor m, Monad m) => Functor (CompileInfoT m) where+  fmap f x = CompileInfoT $ do+    x' <- citState x+    case x' of+         CompileFail w e    -> return $ CompileFail w e -- Not the same a.+         CompileSuccess w d -> return $ CompileSuccess w (f d)++instance (Applicative m, Monad m) => Applicative (CompileInfoT m) where+  pure = CompileInfoT .return . CompileSuccess []+  f <*> x = CompileInfoT $ do+    f' <- citState f+    x' <- citState x+    case (f',x') of+         (CompileFail w e,     _)                   -> return $ CompileFail w e -- Not the same a.+         (i,                   CompileFail w e)     -> return $ CompileFail (getWarnings i ++ w) e -- Not the same a.+         (CompileSuccess w1 f2,CompileSuccess w2 d) -> return $ CompileSuccess (w1 ++ w2) (f2 d)++instance Monad m => Monad (CompileInfoT m) where+  x >>= f = CompileInfoT $ do+    x' <- citState x+    case x' of+         CompileFail w e    -> return $ CompileFail w e -- Not the same a.+         CompileSuccess w d -> do+           d2 <- citState $ f d+           return $ prependWarning w d2+  return = pure++#if MIN_VERSION_base(4,9,0)+instance Monad m => MonadFail (CompileInfoT m) where+  fail = compileErrorM+#endif++instance MonadTrans CompileInfoT where+  lift = CompileInfoT . fmap (CompileSuccess [])++instance MonadIO m => MonadIO (CompileInfoT m) where+  liftIO = lift . liftIO++instance Monad m => CompileErrorM (CompileInfoT m) where+  compileErrorM e = CompileInfoT (return $ CompileFail [] $ CompileMessage e [])+  collectAllOrErrorM xs = CompileInfoT $ do+    xs' <- sequence $ map citState $ foldr (:) [] xs+    return $ result $ splitErrorsAndData xs' where+      result ([],xs2,ws) = CompileSuccess ws xs2+      result (es,_,ws)   = CompileFail ws $ CompileMessage "" es+  collectOneOrErrorM xs = CompileInfoT $ do+    xs' <- sequence $ map citState $ foldr (:) [] xs+    return $ result $ splitErrorsAndData xs' where+      result (_,x:_,ws) = CompileSuccess ws x+      result ([],_,ws)  = CompileFail ws $ CompileMessage "" []+      result (es,_,ws)  = CompileFail ws $ CompileMessage "" es+  reviseErrorM x e2 = CompileInfoT $ do+    x' <- citState x+    case x' of+         CompileFail w (CompileMessage [] ms) -> return $ CompileFail w $ CompileMessage e2 ms+         CompileFail w e                      -> return $ CompileFail w $ CompileMessage e2 [e]+         x2                                   -> return x2+  compileWarningM w = CompileInfoT (return $ CompileSuccess [w] ())++instance Monad m => MergeableM (CompileInfoT m) where+  mergeAnyM xs = CompileInfoT $ do+    xs' <- sequence $ map citState $ foldr (:) [] xs+    return $ result $ splitErrorsAndData xs' where+      result ([],[],ws) = CompileFail ws $ CompileMessage "" []+      result (es,[],ws) = CompileFail ws $ CompileMessage "" es+      result (_,xs2,ws) = CompileSuccess ws (mergeAny xs2)+  mergeAllM = collectAllOrErrorM >=> return . mergeAll++getWarnings :: CompileInfoState a -> [String]+getWarnings (CompileFail w _)    = w+getWarnings (CompileSuccess w _) = w++prependWarning :: [String] -> CompileInfoState a -> CompileInfoState a+prependWarning w (CompileSuccess w2 d) = CompileSuccess (w ++ w2) d+prependWarning w (CompileFail w2 e)    = CompileFail (w ++ w2) e++splitErrorsAndData :: Foldable f => f (CompileInfoState a) -> ([CompileMessage],[a],[String])+splitErrorsAndData = foldr partition ([],[],[]) where+  partition (CompileFail w e)    (es,ds,ws) = (e:es,ds,w++ws)+  partition (CompileSuccess w d) (es,ds,ws) = (es,d:ds,w++ws)
+ src/Base/MergeTree.hs view
@@ -0,0 +1,82 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE Safe #-}++module Base.MergeTree (+  MergeTree,+  mergeLeaf,+  pruneMergeTree,+  reduceMergeTree,+) where++import Base.Mergeable+++data MergeTree a =+  MergeAny [MergeTree a] |+  MergeAll [MergeTree a] |+  MergeLeaf a+  deriving (Eq)++instance Show a => Show (MergeTree a) where+  show (MergeAny xs) = "mergeAny " ++ show xs+  show (MergeAll xs) = "mergeAll " ++ show xs+  show (MergeLeaf x) = "mergeLeaf " ++ show x++mergeLeaf :: a -> MergeTree a+mergeLeaf = MergeLeaf++reduceMergeTree :: (Mergeable b, MergeableM m) => (b -> m b) -> (b -> m b) ->+  (a -> m b) -> MergeTree a -> m b+reduceMergeTree anyOp allOp leafOp xa = reduce xa where+  reduce (MergeAny xs) = do+    xs' <- mergeAnyM $ map reduce xs+    anyOp xs'+  reduce (MergeAll xs) = do+    xs' <- mergeAllM $ map reduce xs+    allOp xs'+  reduce (MergeLeaf x) = leafOp x++pruneMergeTree :: MergeableM m => MergeTree (m a) -> m (MergeTree a)+pruneMergeTree = reduceMergeTree return return (fmap MergeLeaf)++instance Functor MergeTree where+  fmap f (MergeAny xs) = MergeAny (map (fmap f) xs)+  fmap f (MergeAll xs) = MergeAll (map (fmap f) xs)+  fmap f (MergeLeaf x) = MergeLeaf (f x)++instance Foldable MergeTree where+  foldr f y = foldr f y . maybe [] id . reduceMergeTree return return (return . (:[]))++instance Traversable MergeTree where+  traverse f (MergeAny xs) = MergeAny <$> foldr (<*>) (pure []) (map (fmap (:) . traverse f) xs)+  traverse f (MergeAll xs) = MergeAll <$> foldr (<*>) (pure []) (map (fmap (:) . traverse f) xs)+  traverse f (MergeLeaf x) = fmap MergeLeaf (f x)++instance Mergeable (MergeTree a) where+  mergeAny = unnest . filter (not . isEmptyAny) . foldr (:) [] where+    isEmptyAny (MergeAny []) = True+    isEmptyAny _             = False+    unnest [x] = x+    unnest xs  = MergeAny xs+  mergeAll = unnest . filter (not . isEmptyAll) . foldr (:) [] where+    isEmptyAll (MergeAll []) = True+    isEmptyAll _             = False+    unnest [x] = x+    unnest xs  = MergeAll xs
src/Base/Mergeable.hs view
@@ -23,30 +23,38 @@ module Base.Mergeable (   Mergeable(..),   MergeableM(..),+  mergeDefault,+  mergeDefaultM, ) where -#if MIN_VERSION_base(4,8,0)+#if MIN_VERSION_base(4,11,0) #else-import Data.Foldable+import Data.Monoid ((<>)) #endif   class Mergeable a where   mergeAny :: Foldable f => f a -> a   mergeAll :: Foldable f => f a -> a-  mergeNested :: a -> a -> a-  mergeNested x y = mergeAll [x,y]-  mergeDefault :: a-  mergeDefault = mergeAll Nothing -class (Functor m, Monad m) => MergeableM m where+class Monad m => MergeableM m where   mergeAnyM :: (Mergeable a, Foldable f) => f (m a) -> m a   mergeAllM :: (Mergeable a, Foldable f) => f (m a) -> m a-  mergeNestedM :: Mergeable a => m a -> m a -> m a-  mergeNestedM x y = mergeAllM [x,y]-  mergeDefaultM :: Mergeable a => m a-  mergeDefaultM = mergeAllM Nothing +mergeDefault :: Mergeable a => a+mergeDefault = mergeAll Nothing++mergeDefaultM :: (MergeableM m, Mergeable a) => m a+mergeDefaultM = mergeAllM Nothing+ instance Mergeable () where   mergeAny = const ()   mergeAll = const ()++instance Mergeable [a] where+  mergeAny = foldr (++) []+  mergeAll = foldr (++) []++instance MergeableM Maybe where+  mergeAnyM = fmap mergeAny . foldr ((<>) . fmap (:[])) Nothing+  mergeAllM = fmap mergeAll . sequence . foldr (:) []
src/Cli/CompileMetadata.hs view
@@ -31,7 +31,7 @@ import Text.Parsec (SourcePos)  import Cli.CompileOptions-import Config.Programs (VersionHash)+import Cli.Programs (VersionHash) import Types.Procedure (Expression) import Types.TypeCategory (Namespace) import Types.TypeInstance (CategoryName)
src/Cli/Compiler.hs view
@@ -28,7 +28,6 @@ import Data.Either (partitionEithers) import Data.List (isSuffixOf,nub,sort) import System.Directory-import System.Exit import System.FilePath import System.Posix.Temp (mkstemps) import System.IO@@ -39,15 +38,14 @@ import Base.CompileError import Cli.CompileMetadata import Cli.CompileOptions+import Cli.Paths import Cli.ProcessMetadata+import Cli.Programs import Cli.TestRunner -- Not safe, due to Text.Regex.TDFA.-import Compilation.CompileInfo+import Base.CompileInfo import Compilation.ProcedureContext (ExprMap) import CompilerCxx.Category import CompilerCxx.Naming-import Config.LoadConfig-import Config.Paths-import Config.Programs import Parser.SourceFile import Types.Builtin import Types.DefinedCategory@@ -84,19 +82,15 @@   }   deriving (Show) -compileModule :: ModuleSpec -> IO ()-compileModule (ModuleSpec p d em is is2 ps xs ts es ep m f) = do-  (backend,resolver) <- loadConfig-  let hash = getCompilerHash backend-  as  <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is-  as2 <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is2+compileModule :: (PathIOHandler r, CompilerBackend b) => r -> b -> ModuleSpec -> CompileInfoIO ()+compileModule resolver backend (ModuleSpec p d em is is2 ps xs ts es ep m f) = do+  as  <- fmap fixPaths $ mapErrorsM (resolveModule resolver (p </> d)) is+  as2 <- fmap fixPaths $ mapErrorsM (resolveModule resolver (p </> d)) is2   let ca0 = Map.empty-  (fr1,deps1) <- loadPublicDeps hash ca0 as+  deps1 <- loadPublicDeps compilerHash f ca0 as   let ca1 = ca0 `Map.union` mapMetadata deps1-  checkAllowedStale fr1 f-  (fr2,deps2) <- loadPublicDeps hash ca1 as2+  deps2 <- loadPublicDeps compilerHash f ca1 as2   let ca2 = ca1 `Map.union` mapMetadata deps2-  checkAllowedStale fr2 f   base <- resolveBaseModule resolver   actual <- resolveModule resolver p d   isBase <- isBaseModule resolver actual@@ -104,42 +98,36 @@   deps1' <- if isBase                then return deps1                else do-                 (fr3,bpDeps) <- loadPublicDeps hash ca2 [base]-                 checkAllowedStale fr3 f+                 bpDeps <- loadPublicDeps compilerHash f ca2 [base]                  return $ bpDeps ++ deps1   ns0 <- createPublicNamespace p d   let ex = concat $ map getSourceCategories es-  cm <- loadLanguageModule p ns0 ex em ps deps1' deps2-  xa <- fmap collectAllOrErrorM $ sequence $ map (loadPrivateSource p) xs-  let fs = compileAll cm xa+  (cm,(pc,tc)) <- loadLanguageModule p ns0 ex em ps deps1' deps2+  xa <- mapErrorsM (loadPrivateSource p) xs+  (xx1,xx2) <- compileLanguageModule cm xa+  mf <- maybeCreateMain cm xa m+  let fs' = xx1++xx2   eraseCachedData (p </> d)-  when (isCompileError fs) $ do-    formatWarnings fs-    hPutStr stderr $ "Compiler errors:\n" ++ (show $ getCompileError fs)-    hPutStrLn stderr $ "Zeolite compilation failed."-    exitFailure-  formatWarnings fs-  let (pc,tc,mf,fs') = getCompileSuccess fs   let ps2 = map takeFileName ps   let xs2 = map takeFileName xs   let ts2 = map takeFileName ts   let paths = map (\ns -> getCachedPath (p </> d) ns "") $ nub $ filter (not . null) $ map show $ [ns0] ++ map coNamespace fs'-  paths' <- sequence $ map canonicalizePath paths-  s0 <- canonicalizePath $ getCachedPath (p </> d) (show ns0) ""+  paths' <- mapM (errorFromIO . canonicalizePath) paths+  s0 <- errorFromIO $ canonicalizePath $ getCachedPath (p </> d) (show ns0) ""   let paths2 = base:(getIncludePathsForDeps (deps1' ++ deps2)) ++ ep' ++ paths'   let hxx   = filter (isSuffixOf ".hpp" . coFilename)       fs'   let other = filter (not . isSuffixOf ".hpp" . coFilename) fs'-  os1 <- sequence $ map (writeOutputFile backend (show ns0) paths2) $ hxx ++ other+  os1 <- mapErrorsM (writeOutputFile (show ns0) paths2) $ hxx ++ other   let files = map (\f2 -> getCachedPath (p </> d) (show $ coNamespace f2) (coFilename f2)) fs' ++               map (\f2 -> p </> getSourceFile f2) es-  files' <- sequence $ map checkOwnedFile files-  os2 <- fmap concat $ sequence $ map (compileExtraSource backend (show ns0) paths2) es+  files' <- mapErrorsM checkOwnedFile files+  os2 <- fmap concat $ mapErrorsM (compileExtraSource (show ns0) paths2) es   let (hxx',cxx,os') = sortCompiledFiles files'   let (osCat,osOther) = partitionEithers os2-  path <- canonicalizePath $ p </> d+  path <- errorFromIO $ canonicalizePath $ p </> d   let os1' = resolveObjectDeps (deps1' ++ deps2) path path (os1 ++ osCat)   let cm2 = CompileMetadata {-      cmVersionHash = hash,+      cmVersionHash = compilerHash,       cmPath = path,       cmNamespace = ns0,       cmPublicDeps = as,@@ -156,7 +144,7 @@       cmLinkFlags = getLinkFlags m,       cmObjectFiles = os1' ++ osOther ++ map OtherObjectFile os'     }-  bs <- createBinary backend resolver paths' (cm2:(deps1' ++ deps2)) m mf+  bs <- createBinary paths' (cm2:(deps1' ++ deps2)) m mf   let cm2' = CompileMetadata {       cmVersionHash = cmVersionHash cm2,       cmPath = cmPath cm2,@@ -175,17 +163,11 @@       cmLinkFlags = cmLinkFlags cm2,       cmObjectFiles = cmObjectFiles cm2     }-  writeMetadata (p </> d) cm2'-  hPutStrLn stderr $ "Zeolite compilation succeeded." where-    compileAll cm xa = do-      (cm',(pc,tc)) <- cm-      xa' <- xa-      (xx1,xx2) <- compileLanguageModule cm' xa'-      ms <- maybeCreateMain cm' xa' m-      return (pc,tc,ms,xx1++xx2)+  writeMetadata (p </> d) cm2' where+    compilerHash = getCompilerHash backend     ep' = fixPaths $ map (p </>) ep-    writeOutputFile b ns0 paths ca@(CxxOutput _ f2 ns _ _ content) = do-      hPutStrLn stderr $ "Writing file " ++ f2+    writeOutputFile ns0 paths ca@(CxxOutput _ f2 ns _ _ content) = do+      errorFromIO $ hPutStrLn stderr $ "Writing file " ++ f2       writeCachedFile (p </> d) (show ns) f2 $ concat $ map (++ "\n") content       if isSuffixOf ".cpp" f2 || isSuffixOf ".cc" f2          then do@@ -195,17 +177,17 @@            createCachePath (p </> d)            let ns' = if isStaticNamespace ns then show ns else show ns0            let command = CompileToObject f2' (getCachedPath (p </> d) ns' "") dynamicNamespaceName "" (p0:p1:paths) False-           o2 <- runCxxCommand b command+           o2 <- runCxxCommand backend command            return $ ([o2],ca)          else return ([],ca)-    compileExtraSource b ns0 paths (CategorySource f2 cs ds2) = do-      f2' <- compileExtraFile False b ns0 paths f2+    compileExtraSource ns0 paths (CategorySource f2 cs ds2) = do+      f2' <- compileExtraFile False ns0 paths f2       let ds2' = nub $ cs ++ ds2       case f2' of            Nothing -> return []            Just o  -> return $ map (\c -> Left $ ([o],fakeCxxForSource ns0 ds2' c)) cs-    compileExtraSource b ns0 paths (OtherSource f2) = do-      f2' <- compileExtraFile True b ns0 paths f2+    compileExtraSource ns0 paths (OtherSource f2) = do+      f2' <- compileExtraFile True ns0 paths f2       case f2' of            Just o  -> return [Right $ OtherObjectFile o]            Nothing -> return []@@ -219,157 +201,126 @@       } where         ns' = if null ns then NoNamespace else StaticNamespace ns     checkOwnedFile f2 = do-      exists <- doesFileExist f2-      when (not exists) $ do-        hPutStrLn stderr $ "Owned file " ++ f2 ++ " does not exist."-        hPutStrLn stderr $ "Zeolite compilation failed."-        exitFailure-      canonicalizePath f2-    compileExtraFile e b ns0 paths f2+      exists <- errorFromIO $ doesFileExist f2+      when (not exists) $ compileErrorM $ "Owned file " ++ f2 ++ " does not exist."+      errorFromIO $ canonicalizePath f2+    compileExtraFile e ns0 paths f2       | isSuffixOf ".cpp" f2 || isSuffixOf ".cc" f2 = do           let f2' = p </> f2           createCachePath (p </> d)           let command = CompileToObject f2' (getCachedPath (p </> d) "" "") dynamicNamespaceName ns0 paths e-          fmap Just $ runCxxCommand b command+          fmap Just $ runCxxCommand backend command       | isSuffixOf ".a" f2 || isSuffixOf ".o" f2 = return (Just f2)       | otherwise = return Nothing-    createBinary b r paths deps (CompileBinary n _ o lf) ms-      | length ms > 1 = do-        hPutStrLn stderr $ "Multiple matches for main category " ++ show n ++ "."-        exitFailure-      | length ms == 0 = do-        hPutStrLn stderr $ "Main category " ++ show n ++ " not found."-        exitFailure+    createBinary paths deps (CompileBinary n _ o lf) ms+      | length ms >  1 = compileErrorM $ "Multiple matches for main category " ++ show n ++ "."+      | length ms == 0 = compileErrorM $ "Main category " ++ show n ++ " not found."       | otherwise = do           f0 <- if null o-                   then canonicalizePath $ p </> d </> show n-                   else canonicalizePath $ p </> d </> o+                   then errorFromIO $ canonicalizePath $ p </> d </> show n+                   else errorFromIO $ canonicalizePath $ p </> d </> o           let (CxxOutput _ _ _ ns2 req content) = head ms           -- TODO: Create a helper or a constant or something.-          (o',h) <- mkstemps "/tmp/zmain_" ".cpp"-          hPutStr h $ concat $ map (++ "\n") content-          hClose h-          base <- resolveBaseModule r-          (fr,deps2)  <- loadPrivateDeps (getCompilerHash b) (mapMetadata deps) deps-          checkAllowedStale fr f+          (o',h) <- errorFromIO $ mkstemps "/tmp/zmain_" ".cpp"+          errorFromIO $ hPutStr h $ concat $ map (++ "\n") content+          errorFromIO $ hClose h+          base <- resolveBaseModule resolver+          deps2  <- loadPrivateDeps compilerHash f (mapMetadata deps) deps           let lf' = lf ++ getLinkFlagsForDeps deps2           let paths' = fixPaths $ paths ++ base:(getIncludePathsForDeps deps)           let os     = getObjectFilesForDeps deps2           let ofr = getObjectFileResolver os           let os' = ofr ns2 req           let command = CompileToBinary o' os' f0 paths' lf'-          hPutStrLn stderr $ "Creating binary " ++ f0-          _ <- runCxxCommand b command-          removeFile o'-          return [f0]-    createBinary _ _ _ _ _ _ = return []+          errorFromIO $ hPutStrLn stderr $ "Creating binary " ++ f0+          f1 <- runCxxCommand backend command+          errorFromIO $ removeFile o'+          return [f1]+    createBinary _ _ _ _ = return []     maybeCreateMain cm2 xs2 (CompileBinary n f2 _ _) =       fmap (:[]) $ compileModuleMain cm2 xs2 n f2     maybeCreateMain _ _ _ = return [] -createModuleTemplates :: FilePath -> FilePath -> [CompileMetadata] -> [CompileMetadata] -> IO ()+createModuleTemplates :: FilePath -> FilePath -> [CompileMetadata] -> [CompileMetadata] -> CompileInfoIO () createModuleTemplates p d deps1 deps2 = do   ns0 <- createPublicNamespace p d   (ps,xs,_) <- findSourceFiles p d-  cm <- fmap (fmap fst) $ loadLanguageModule p ns0 [] Map.empty ps deps1 deps2+  (LanguageModule _ _ _ cs0 ps0 ts0 cs1 ps1 ts1 _ _,_) <-+    fmap (fmap fst) $ loadLanguageModule p ns0 [] Map.empty ps deps1 deps2   xs' <- zipWithContents p xs-  let ts = createTemplates cm xs'-  if isCompileError ts-      then do-        formatWarnings ts-        hPutStr stderr $ "Compiler errors:\n" ++ (show $ getCompileError ts)-        hPutStrLn stderr $ "Zeolite compilation failed."-        exitFailure-      else do-        formatWarnings ts-        sequence_ $ map writeTemplate $ getCompileSuccess ts where-  createTemplates cm xs = do-    (LanguageModule _ _ _ cs0 ps0 ts0 cs1 ps1 ts1 _ _) <- cm-    ds <- collectAllOrErrorM $ map parseInternalSource xs-    let ds2 = concat $ map (\(_,_,d2) -> d2) ds-    tm <- foldM includeNewTypes defaultCategories [cs0,cs1,ps0,ps1,ts0,ts1]-    let cs = filter isValueConcrete $ cs1++ps1++ts1-    let ca = Set.fromList $ map getCategoryName $ filter isValueConcrete cs-    let ca' = foldr Set.delete ca $ map dcName ds2-    collectAllOrErrorM $ map (compileConcreteTemplate tm) $ Set.toList ca'+  ds <- mapErrorsM parseInternalSource xs'+  let ds2 = concat $ map (\(_,_,d2) -> d2) ds+  tm <- foldM includeNewTypes defaultCategories [cs0,cs1,ps0,ps1,ts0,ts1]+  let cs = filter isValueConcrete $ cs1++ps1++ts1+  let ca = Set.fromList $ map getCategoryName $ filter isValueConcrete cs+  let ca' = foldr Set.delete ca $ map dcName ds2+  ts <- mapErrorsM (compileConcreteTemplate tm) $ Set.toList ca'+  mapErrorsM_ writeTemplate ts where   writeTemplate (CxxOutput _ n _ _ _ content) = do     let n' = p </> d </> n-    exists <- doesFileExist n'+    exists <- errorFromIO $ doesFileExist n'     if exists-        then hPutStrLn stderr $ "Skipping existing file " ++ n+        then compileWarningM $ "Skipping existing file " ++ n         else do-          hPutStrLn stderr $ "Writing file " ++ n-          writeFile n' $ concat $ map (++ "\n") content+          errorFromIO $ hPutStrLn stderr $ "Writing file " ++ n+          errorFromIO $ writeFile n' $ concat $ map (++ "\n") content -runModuleTests :: CompilerBackend b => b -> FilePath -> [FilePath] -> LoadedTests -> IO [((Int,Int),CompileInfo ())]-runModuleTests b base tp (LoadedTests p d m em deps1 deps2) = do+runModuleTests :: (PathIOHandler r, CompilerBackend b) => r -> b -> FilePath ->+  [FilePath] -> LoadedTests -> CompileInfoIO [((Int,Int),CompileInfo ())]+runModuleTests _ backend base tp (LoadedTests p d m em deps1 deps2) = do   let paths = base:(getIncludePathsForDeps deps1)-  mapM_ showSkipped $ filter (not . isTestAllowed) $ cmTestFiles m+  mapErrorsM_ showSkipped $ filter (not . isTestAllowed) $ cmTestFiles m   ts' <- zipWithContents p $ map (d </>) $ filter isTestAllowed $ cmTestFiles m-  path <- canonicalizePath (p </> d)-  cm <- fmap (fmap fst) $ loadLanguageModule path NoNamespace [] em [] deps1 []-  if isCompileError cm-      then return [((0,0),cm >> return ())]-      else sequence $ map (runSingleTest b (getCompileSuccess cm) path paths (m:deps2)) ts' where+  path <- errorFromIO $ canonicalizePath (p </> d)+  (cm,_) <- loadLanguageModule path NoNamespace [] em [] deps1 []+  mapErrorsM (runSingleTest backend cm path paths (m:deps2)) ts' where     allowTests = Set.fromList tp     isTestAllowed t = if null allowTests then True else t `Set.member` allowTests-    showSkipped f = do-      hPutStrLn stderr $ "Skipping tests in " ++ f ++ " due to explicit test filter."--createPublicNamespace :: FilePath -> FilePath -> IO Namespace-createPublicNamespace p d = canonicalizePath (p </> d) >>= return . StaticNamespace . publicNamespace+    showSkipped f = compileWarningM $ "Skipping tests in " ++ f ++ " due to explicit test filter." -createPrivateNamespace :: FilePath -> FilePath -> IO Namespace-createPrivateNamespace p f = canonicalizePath (p </> f) >>= return . StaticNamespace . publicNamespace+createPublicNamespace :: FilePath -> FilePath -> CompileInfoIO Namespace+createPublicNamespace p d = (errorFromIO $ canonicalizePath (p </> d)) >>= return . StaticNamespace . publicNamespace -formatWarnings :: CompileInfo a -> IO ()-formatWarnings c-  | null $ getCompileWarnings c = return ()-  | otherwise = hPutStr stderr $ "Compiler warnings:\n" ++ (concat $ map (++ "\n") (getCompileWarnings c))+createPrivateNamespace :: FilePath -> FilePath -> CompileInfoIO Namespace+createPrivateNamespace p f = (errorFromIO $ canonicalizePath (p </> f)) >>= return . StaticNamespace . publicNamespace -zipWithContents :: FilePath -> [FilePath] -> IO [(FilePath,String)]-zipWithContents p fs = fmap (zip $ map fixPath fs) $ sequence $ map (readFile . (p </>)) fs+zipWithContents :: FilePath -> [FilePath] -> CompileInfoIO [(FilePath,String)]+zipWithContents p fs = fmap (zip $ map fixPath fs) $ mapM (errorFromIO . readFile . (p </>)) fs -loadPrivateSource :: CompileErrorM m => FilePath -> FilePath -> IO (m (PrivateSource SourcePos))+loadPrivateSource :: FilePath -> FilePath -> CompileInfoIO (PrivateSource SourcePos) loadPrivateSource p f = do   [f'] <- zipWithContents p [f]   ns <- createPrivateNamespace p f-  return $ do-    (pragmas,cs,ds) <- parseInternalSource f'-    let cs' = map (setCategoryNamespace ns) cs-    let testing = any isTestsOnly pragmas-    return $ PrivateSource ns testing cs' ds+  (pragmas,cs,ds) <- parseInternalSource f'+  let cs' = map (setCategoryNamespace ns) cs+  let testing = any isTestsOnly pragmas+  return $ PrivateSource ns testing cs' ds -loadLanguageModule :: CompileErrorM m => FilePath -> Namespace ->-  [CategoryName] -> ExprMap SourcePos -> [FilePath] -> [CompileMetadata] ->-  [CompileMetadata] -> IO (m (LanguageModule SourcePos,([CategoryName],[CategoryName])))+loadLanguageModule :: FilePath -> Namespace -> [CategoryName] ->+  ExprMap SourcePos -> [FilePath] -> [CompileMetadata] -> [CompileMetadata] ->+  CompileInfoIO (LanguageModule SourcePos,([CategoryName],[CategoryName])) loadLanguageModule p ns2 ex em fs deps1 deps2 = do   let public = Set.fromList $ map cmPath deps1   let deps2' = filter (\cm -> not $ cmPath cm `Set.member` public) deps2   let ns0 = filter (not . isNoNamespace) $ getNamespacesForDeps deps1   let ns1 = filter (not . isNoNamespace) $ getNamespacesForDeps deps2'-  m0 <- fmap merge $ sequence $ map processAll deps1-  m1 <- fmap merge $ sequence $ map processAll deps2'-  m2 <- loadAllPublic "" fs-  return $ construct m0 m1 m2 ns0 ns1 where-    construct m0 m1 m2 ns0 ns1 = do-      (ps0,_,tsA0,_)      <- m0-      (ps1,_,tsA1,_)      <- m1-      (ps2,xs2,tsA2,tsB2) <- m2-      let cm = LanguageModule {-          lmPublicNamespaces = ns0,-          lmPrivateNamespaces = ns1,-          lmLocalNamespaces = [ns2],-          lmPublicDeps = ps0,-          lmPrivateDeps = ps1,-          lmTestingDeps = tsA0++tsA1,-          lmPublicLocal = map (setCategoryNamespace ns2) ps2,-          lmPrivateLocal = map (setCategoryNamespace ns2) xs2,-          lmTestingLocal = map (setCategoryNamespace ns2) $ tsA2 ++ tsB2,-          lmExternal = ex,-          lmExprMap = em-        }-      return (cm,(map getCategoryName $ ps2++tsA2,map getCategoryName $ xs2++tsB2))+  (ps0,_,  tsA0,_)    <- fmap merge $ mapErrorsM processAll deps1+  (ps1,_,  tsA1,_)    <- fmap merge $ mapErrorsM processAll deps2'+  (ps2,xs2,tsA2,tsB2) <- loadAllPublic "" fs+  let cm = LanguageModule {+      lmPublicNamespaces = ns0,+      lmPrivateNamespaces = ns1,+      lmLocalNamespaces = [ns2],+      lmPublicDeps = ps0,+      lmPrivateDeps = ps1,+      lmTestingDeps = tsA0++tsA1,+      lmPublicLocal = map (setCategoryNamespace ns2) ps2,+      lmPrivateLocal = map (setCategoryNamespace ns2) xs2,+      lmTestingLocal = map (setCategoryNamespace ns2) $ tsA2 ++ tsB2,+      lmExternal = ex,+      lmExprMap = em+    }+  return (cm,(map getCategoryName $ ps2++tsA2,map getCategoryName $ xs2++tsB2)) where     loadPublic p2 p3 = parsePublicSource p3 >>= return . uncurry (partition p2)     partition p2 pragmas cs       -- Allow ModuleOnly when the path is the same. Only needed for tests.@@ -382,12 +333,9 @@     processAll dep = do       let dep' = getSourceFilesForDeps [dep]       loadAllPublic (cmPath dep) dep'-    merge as = do-      as' <- collectAllOrErrorM as-      return $ foldl merge4 ([],[],[],[]) as'     loadAllPublic p2 fs2 = do       fs2' <- zipWithContents p fs2-      return $ do-        as <- collectAllOrErrorM $ map (loadPublic p2) fs2'-        return $ foldl merge4 ([],[],[],[]) as+      as <- mapErrorsM (loadPublic p2) fs2'+      return $ merge as+    merge = foldl merge4 ([],[],[],[])     merge4 (ps1,xs1,tsA1,tsB1) (ps2,xs2,tsA2,tsB2) = (ps1++ps2,xs1++xs2,tsA1++tsA2,tsB1++tsB2)
src/Cli/ParseCompileOptions.hs view
@@ -19,23 +19,15 @@ module Cli.ParseCompileOptions (   optionHelpText,   parseCompileOptions,-  tryFastModes,   validateCompileOptions, ) where  import Control.Monad (when) import Data.List (isSuffixOf)-import System.Directory-import System.Exit-import System.IO import Text.Regex.TDFA -- Not safe!-import qualified Data.Map as Map  import Base.CompileError-import Cli.CompileMetadata import Cli.CompileOptions-import Cli.ProcessMetadata-import Config.LoadConfig (compilerVersion,rootPath) import Types.TypeCategory (FunctionName(..)) import Types.TypeInstance (CategoryName(..)) @@ -85,42 +77,13 @@ defaultMainFunc :: String defaultMainFunc = "run" -tryFastModes :: [String] -> IO ()-tryFastModes ("--get-path":os) = do-  when (not $ null os) $ hPutStrLn stderr $ "Ignoring extra arguments: " ++ show os-  p <- rootPath >>= canonicalizePath-  hPutStrLn stdout p-  if null os-     then exitSuccess-     else exitFailure-tryFastModes ("--version":os) = do-  when (not $ null os) $ hPutStrLn stderr $ "Ignoring extra arguments: " ++ show os-  hPutStrLn stdout compilerVersion-  if null os-     then exitSuccess-     else exitFailure-tryFastModes ("--show-deps":ps) = do-  mapM_ showDeps ps-  exitSuccess where-    showDeps p = do-      p' <- canonicalizePath p-      m <- loadMetadata Map.empty p'-      hPutStrLn stdout $ show p'-      mapM_ showDep (cmObjectFiles m)-    showDep (CategoryObjectFile c ds _) = do-      mapM_ (\d -> hPutStrLn stdout $ "  " ++ show (ciCategory c) ++-                                      " -> " ++ show (ciCategory d) ++-                                      " " ++ show (ciPath d)) ds-    showDep _ = return ()-tryFastModes _ = return ()- parseCompileOptions :: CompileErrorM m => [String] -> m CompileOptions parseCompileOptions = parseAll emptyCompileOptions . zip ([1..] :: [Int]) where   parseAll co [] = return co   parseAll co os = do     (os',co') <- parseSingle co os     parseAll co' os'-  argError n o m = compileError $ "Argument " ++ show n ++ " (\"" ++ o ++ "\"): " ++ m+  argError n o m = compileErrorM $ "Argument " ++ show n ++ " (\"" ++ o ++ "\"): " ++ m   checkPathName n f o     | f =~ "^(/[^/]+|[^-/][^/]*)(/[^/]+)*$" = return ()     | null o    = argError n f "Invalid file path."@@ -246,16 +209,16 @@   | h /= HelpNotNeeded = return co    | (not $ null $ is ++ is2) && (isExecuteTests m) =-    compileError "Include paths (-i/-I) are not allowed in test mode (-t)."+    compileErrorM "Include paths (-i/-I) are not allowed in test mode (-t)."    | (not $ null $ is ++ is2) && (isCompileRecompile m) =-    compileError "Include paths (-i/-I) are not allowed in recompile mode (-r/-R)."+    compileErrorM "Include paths (-i/-I) are not allowed in recompile mode (-r/-R)."    | (length ds /= 0) && (isCompileFast m) =-    compileError "Input path is not allowed with fast mode (--fast)."+    compileErrorM "Input path is not allowed with fast mode (--fast)."   | null ds && (not $ isCompileFast m) =-    compileError "Please specify at least one input path."+    compileErrorM "Please specify at least one input path."   | (length ds > 1) && (not $ isCompileRecompile m) && (not $ isExecuteTests m) =-    compileError "Multiple input paths are only allowed with recompile mode (-r/-R) and test mode (-t)."+    compileErrorM "Multiple input paths are only allowed with recompile mode (-r/-R) and test mode (-t)."    | otherwise = return co
src/Cli/ParseMetadata.hs view
@@ -29,7 +29,7 @@ import Base.CompileError import Cli.CompileMetadata import Cli.CompileOptions-import Config.Programs (VersionHash(..))+import Cli.Programs (VersionHash(..)) import Parser.Common import Parser.Procedure () import Parser.Pragma (parseMacroName)@@ -48,7 +48,7 @@ autoReadConfig :: (ConfigFormat a, CompileErrorM m) => String -> String -> m a autoReadConfig f s  = unwrap parsed where   parsed = parse (between optionalSpace endOfDoc readConfig) f s-  unwrap (Left e)  = compileError (show e)+  unwrap (Left e)  = compileErrorM (show e)   unwrap (Right t) = return t  autoWriteConfig ::  (ConfigFormat a, CompileErrorM m) => a -> m String@@ -73,7 +73,7 @@ validateCategoryName :: CompileErrorM m => CategoryName -> m () validateCategoryName c =     when (not $ show c =~ "^[A-Z][A-Za-z0-9]*$") $-      compileError $ "Invalid category name: \"" ++ show c ++ "\""+      compileErrorM $ "Invalid category name: \"" ++ show c ++ "\""  parseCategoryName :: Parser CategoryName parseCategoryName = sourceParser :: Parser CategoryName@@ -81,7 +81,7 @@ validateFunctionName :: CompileErrorM m => FunctionName -> m () validateFunctionName f =     when (not $ show f =~ "^[a-z][A-Za-z0-9]*$") $-      compileError $ "Invalid function name: \"" ++ show f ++ "\""+      compileErrorM $ "Invalid function name: \"" ++ show f ++ "\""  parseFunctionName :: Parser FunctionName parseFunctionName = sourceParser :: Parser FunctionName@@ -89,7 +89,7 @@ validateHash :: CompileErrorM m => VersionHash -> m () validateHash h =     when (not $ show h =~ "^[A-Za-z0-9]+$") $-      compileError $ "Version hash must be a hex string: \"" ++ show h ++ "\""+      compileErrorM $ "Version hash must be a hex string: \"" ++ show h ++ "\""  parseHash :: Parser VersionHash parseHash = labeled "version hash" $ sepAfter (fmap VersionHash $ many1 hexDigit)@@ -97,7 +97,7 @@ maybeShowNamespace :: CompileErrorM m => String -> Namespace -> m [String] maybeShowNamespace l (StaticNamespace ns) = do   when (not $ ns =~ "^[A-Za-z][A-Za-z0-9_]*$") $-    compileError $ "Invalid category namespace: \"" ++ ns ++ "\""+    compileErrorM $ "Invalid category namespace: \"" ++ ns ++ "\""   return [l ++ " " ++ ns] maybeShowNamespace _ _ = return [] @@ -151,9 +151,9 @@   writeConfig m = do     validateHash (cmVersionHash m)     namespace <- maybeShowNamespace "namespace:" (cmNamespace m)-    _ <- collectAllOrErrorM $ map validateCategoryName (cmPublicCategories m)-    _ <- collectAllOrErrorM $ map validateCategoryName (cmPrivateCategories m)-    objects <- fmap concat $ collectAllOrErrorM $ map writeConfig $ cmObjectFiles m+    _ <- mapErrorsM validateCategoryName (cmPublicCategories m)+    _ <- mapErrorsM validateCategoryName (cmPrivateCategories m)+    objects <- fmap concat $ mapErrorsM writeConfig $ cmObjectFiles m     return $ [         "version_hash: " ++ (show $ cmVersionHash m),         "path: " ++ (show $ cmPath m)@@ -217,7 +217,7 @@       return (OtherObjectFile f)   writeConfig (CategoryObjectFile c rs fs) = do     category <- writeConfig c-    requires <- fmap concat $ collectAllOrErrorM $ map writeConfig rs+    requires <- fmap concat $ mapErrorsM writeConfig rs     return $ [         "category_object {"       ] ++ indents ("category: " `prependFirst` category) ++ [@@ -278,9 +278,9 @@       m   <- parseRequired "mode:"              readConfig       return (ModuleConfig p d em is is2 es ep m)   writeConfig m = do-    extra    <- fmap concat $ collectAllOrErrorM $ map writeConfig $ rmExtraFiles m+    extra    <- fmap concat $ mapErrorsM writeConfig $ rmExtraFiles m     mode <- writeConfig (rmMode m)-    when (not $ null $ rmExprMap m) $ compileError "Only empty expression maps are allowed when writing"+    when (not $ null $ rmExprMap m) $ compileErrorM "Only empty expression maps are allowed when writing"     return $ [         "root: " ++ show (rmRoot m),         "path: " ++ show (rmPath m),@@ -316,8 +316,8 @@       f <- parseQuoted       return (OtherSource f)   writeConfig (CategorySource f cs ds) = do-    _ <- collectAllOrErrorM $ map validateCategoryName cs-    _ <- collectAllOrErrorM $ map validateCategoryName ds+    _ <- mapErrorsM validateCategoryName cs+    _ <- mapErrorsM validateCategoryName ds     return $ [         "category_source {",         indent ("source: " ++ show f),@@ -370,7 +370,7 @@         "}"       ]   writeConfig CompileUnspecified = writeConfig (CompileIncremental [])-  writeConfig _ = compileError "Invalid compile mode"+  writeConfig _ = compileErrorM "Invalid compile mode"  parseExprMacro :: Parser (String,Expression SourcePos) parseExprMacro = do
+ src/Cli/Paths.hs view
@@ -0,0 +1,34 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE Safe #-}++module Cli.Paths (+  PathIOHandler(..),+) where++import Control.Monad.IO.Class++import Base.CompileError+++class PathIOHandler r where+  resolveModule     :: (MonadIO m, CompileErrorM m) => r -> FilePath -> FilePath -> m FilePath+  isSystemModule    :: (MonadIO m, CompileErrorM m) => r -> FilePath -> FilePath -> m Bool+  resolveBaseModule :: (MonadIO m, CompileErrorM m) => r -> m FilePath+  isBaseModule      :: (MonadIO m, CompileErrorM m) => r -> FilePath -> m Bool
src/Cli/ProcessMetadata.hs view
@@ -18,8 +18,6 @@  module Cli.ProcessMetadata (   MetadataMap,-  checkAllowedStale,-  checkMetadataFreshness,   createCachePath,   eraseCachedData,   findSourceFiles,@@ -37,15 +35,15 @@   getSourceFilesForDeps,   isPathConfigured,   isPathUpToDate,+  loadModuleMetadata,   loadPrivateDeps,   loadPublicDeps,+  loadRecompile,   loadTestingDeps,-  loadMetadata,   mapMetadata,   resolveCategoryDeps,   resolveObjectDeps,   sortCompiledFiles,-  tryLoadRecompile,   writeCachedFile,   writeMetadata,   writeRecompile,@@ -56,7 +54,6 @@ import Data.List (nub,isSuffixOf) import Data.Maybe (isJust) import System.Directory-import System.Exit (exitFailure) import System.FilePath import System.IO import Text.Parsec (SourcePos)@@ -67,10 +64,10 @@ import Cli.CompileMetadata import Cli.CompileOptions import Cli.ParseMetadata -- Not safe, due to Text.Regex.TDFA.-import Compilation.CompileInfo+import Cli.Programs (VersionHash(..))+import Base.CompileInfo import Compilation.ProcedureContext (ExprMap) import CompilerCxx.Category (CxxOutput(..))-import Config.Programs (VersionHash(..)) import Types.Procedure (Expression(Literal),ValueLiteral(..)) import Types.TypeCategory import Types.TypeInstance@@ -85,130 +82,66 @@ metadataFilename :: FilePath metadataFilename = "compile-metadata" -checkAllowedStale :: Bool -> ForceMode -> IO ()-checkAllowedStale fr f = do-  when (not fr && f < ForceAll) $ do-    hPutStrLn stderr $ "Some dependencies are out of date. " ++-                       "Recompile them or use -f to force."-    exitFailure- type MetadataMap = Map.Map FilePath CompileMetadata  mapMetadata :: [CompileMetadata] -> MetadataMap mapMetadata cs = Map.fromList $ zip (map cmPath cs) cs -loadMetadata :: MetadataMap -> FilePath -> IO CompileMetadata-loadMetadata ca p = do-  path <- canonicalizePath p-  case path `Map.lookup` ca of-       Just cm -> return cm-       Nothing -> do-         let f = p </> cachedDataPath </> metadataFilename-         isFile <- doesFileExist p-         when isFile $ do-           hPutStrLn stderr $ "Path \"" ++ p ++ "\" is not a directory."-           exitFailure-         isDir <- doesDirectoryExist p-         when (not isDir) $ do-           hPutStrLn stderr $ "Path \"" ++ p ++ "\" does not exist."-           exitFailure-         filePresent <- doesFileExist f-         when (not filePresent) $ do-           hPutStrLn stderr $ "Module \"" ++ p ++ "\" has not been compiled yet."-           exitFailure-         c <- readFile f-         let m = autoReadConfig f c-         if isCompileError m-            then do-              hPutStrLn stderr $ "Could not parse metadata from \"" ++ p ++ "\"; please recompile."-              hPutStrLn stderr $ show (getCompileError m)-              exitFailure-            else return (getCompileSuccess m)--checkMetadataFreshness :: FilePath -> CompileMetadata -> IO Bool-checkMetadataFreshness = checkModuleFreshness False--tryLoadMetadata :: FilePath -> IO (Maybe CompileMetadata)-tryLoadMetadata p = tryLoadData $ (p </> cachedDataPath </> metadataFilename)--tryLoadRecompile :: FilePath -> IO (Maybe ModuleConfig)-tryLoadRecompile p = tryLoadData $ (p </> moduleFilename)--tryLoadData :: ConfigFormat a => FilePath -> IO (Maybe a)-tryLoadData f = do-  filePresent <- doesFileExist f-  if not filePresent-    then return Nothing-    else do-      c <- readFile f-      let m = autoReadConfig f c-      if isCompileError m-         then do-           hPutStrLn stderr $ "Could not parse config file:"-           hPutStr stderr $ show (getCompileError m)-           return Nothing-         else return $ Just (getCompileSuccess m)+loadRecompile :: FilePath -> CompileInfoIO ModuleConfig+loadRecompile p = do+  let f = p </> moduleFilename+  isFile <- errorFromIO $ doesFileExist p+  when isFile $ compileErrorM $ "Path \"" ++ p ++ "\" is not a directory"+  isDir <- errorFromIO $ doesDirectoryExist p+  when (not isDir) $ compileErrorM $ "Path \"" ++ p ++ "\" does not exist"+  filePresent <- errorFromIO $ doesFileExist f+  when (not filePresent) $ compileErrorM $ "Module \"" ++ p ++ "\" has not been configured yet"+  c <- errorFromIO $ readFile f+  (autoReadConfig f c) `reviseErrorM`+    ("Could not parse metadata from \"" ++ p ++ "\"; please reconfigure") -isPathUpToDate :: VersionHash -> FilePath -> IO Bool-isPathUpToDate h p = do-  m <- tryLoadMetadata p-  case m of-       Nothing -> return False-       Just _ -> do-         (fr,_) <- loadDepsCommon True h Map.empty Set.empty (\m2 -> cmPublicDeps m2 ++ cmPrivateDeps m2) [p]-         return fr+isPathUpToDate :: VersionHash -> ForceMode -> FilePath -> CompileInfoIO Bool+isPathUpToDate h f p = do+  m <- errorFromIO $ toCompileInfo $ loadDepsCommon f h Map.empty Set.empty (\m2 -> cmPublicDeps m2 ++ cmPrivateDeps m2) [p]+  return $ not $ isCompileError m -isPathConfigured :: FilePath -> IO Bool+isPathConfigured :: FilePath -> CompileInfoIO Bool isPathConfigured p = do-  -- Just for error messages.-  _ <- tryLoadRecompile p-  doesFileExist (p </> moduleFilename)+  m <- errorFromIO $ toCompileInfo $ loadRecompile p+  return $ not $ isCompileError m -writeMetadata :: FilePath -> CompileMetadata -> IO ()+writeMetadata :: FilePath -> CompileMetadata -> CompileInfoIO () writeMetadata p m = do-  p' <- canonicalizePath p-  hPutStrLn stderr $ "Writing metadata for \"" ++ p' ++ "\"."-  let m' = autoWriteConfig m-  if isCompileError m'-     then do-       hPutStrLn stderr $ "Could not serialize metadata."-       hPutStrLn stderr $ show (getCompileError m')-       exitFailure-     else writeCachedFile p' "" metadataFilename (getCompileSuccess m')+  p' <- errorFromIO $ canonicalizePath p+  errorFromIO $ hPutStrLn stderr $ "Writing metadata for \"" ++ p' ++ "\"."+  m' <- autoWriteConfig m `reviseErrorM` ("In data for " ++ p)+  writeCachedFile p' "" metadataFilename m' -writeRecompile :: FilePath -> ModuleConfig -> IO ()+writeRecompile :: FilePath -> ModuleConfig -> CompileInfoIO () writeRecompile p m = do-  p' <- canonicalizePath p+  p' <- errorFromIO $ canonicalizePath p   let f = p </> moduleFilename-  hPutStrLn stderr $ "Updating config for \"" ++ p' ++ "\"."-  let m' = autoWriteConfig m-  if isCompileError m'-     then do-       hPutStrLn stderr $ "Could not serialize module config."-       hPutStrLn stderr $ show (getCompileError m')-       exitFailure-     else do-       exists <- doesFileExist f-       when exists $ removeFile f-       writeFile f (getCompileSuccess m')+  errorFromIO $ hPutStrLn stderr $ "Updating config for \"" ++ p' ++ "\"."+  m' <- autoWriteConfig m `reviseErrorM` ("In data for " ++ p)+  errorFromIO $ writeFile f m' -eraseCachedData :: FilePath -> IO ()+eraseCachedData :: FilePath -> CompileInfoIO () eraseCachedData p = do   let d  = p </> cachedDataPath-  dirExists <- doesDirectoryExist d-  when dirExists $ removeDirectoryRecursive d+  dirExists <- errorFromIO $ doesDirectoryExist d+  when dirExists $ errorFromIO $ removeDirectoryRecursive d -createCachePath :: FilePath -> IO ()+createCachePath :: FilePath -> CompileInfoIO () createCachePath p = do   let f = p </> cachedDataPath-  exists <- doesDirectoryExist f-  when (not exists) $ createDirectoryIfMissing False f+  exists <- errorFromIO $ doesDirectoryExist f+  when (not exists) $ errorFromIO $ createDirectoryIfMissing False f -writeCachedFile :: FilePath -> String -> FilePath -> String -> IO ()+writeCachedFile :: FilePath -> String -> FilePath -> String -> CompileInfoIO () writeCachedFile p ns f c = do   createCachePath p-  createDirectoryIfMissing False $ p </> cachedDataPath </> ns-  writeFile (getCachedPath p ns f) c+  errorFromIO $ createDirectoryIfMissing False $ p </> cachedDataPath </> ns+  errorFromIO $ writeFile (getCachedPath p ns f) c  getCachedPath :: FilePath -> String -> FilePath -> FilePath getCachedPath p ns f = fixPath $ p </> cachedDataPath </> ns </> f@@ -216,26 +149,22 @@ getCacheRelativePath :: FilePath -> FilePath getCacheRelativePath f = ".." </> f -findSourceFiles :: FilePath -> FilePath -> IO ([FilePath],[FilePath],[FilePath])+findSourceFiles :: FilePath -> FilePath -> CompileInfoIO ([FilePath],[FilePath],[FilePath]) findSourceFiles p0 p = do   let absolute = p0 </> p-  isFile <- doesFileExist absolute-  when isFile $ do-    hPutStrLn stderr $ "Path \"" ++ absolute ++ "\" is not a directory."-    exitFailure-  isDir <- doesDirectoryExist absolute-  when (not isDir) $ do-    hPutStrLn stderr $ "Path \"" ++ absolute ++ "\" does not exist."-    exitFailure-  ds <- getDirectoryContents absolute >>= return . map (p </>)+  isFile <- errorFromIO $ doesFileExist absolute+  when isFile $ compileErrorM $ "Path \"" ++ absolute ++ "\" is not a directory"+  isDir <- errorFromIO $ doesDirectoryExist absolute+  when (not isDir) $ compileErrorM $ "Path \"" ++ absolute ++ "\" does not exist"+  ds <- errorFromIO $ getDirectoryContents absolute >>= return . map (p </>)   let ps = filter (isSuffixOf ".0rp") ds   let xs = filter (isSuffixOf ".0rx") ds   let ts = filter (isSuffixOf ".0rt") ds   return (ps,xs,ts) -getExprMap :: FilePath -> ModuleConfig -> IO (ExprMap SourcePos)+getExprMap :: FilePath -> ModuleConfig -> CompileInfoIO (ExprMap SourcePos) getExprMap p m = do-  path <- canonicalizePath (p </> rmRoot m </> rmPath m)+  path <- errorFromIO $ canonicalizePath (p </> rmRoot m </> rmPath m)   let defaults = [("MODULE_PATH",Literal (StringLiteral [] path))]   return $ Map.fromList $ rmExprMap m ++ defaults @@ -258,42 +187,73 @@ getObjectFilesForDeps :: [CompileMetadata] -> [ObjectFile] getObjectFilesForDeps = concat . map cmObjectFiles -loadPublicDeps :: VersionHash -> MetadataMap -> [FilePath] -> IO (Bool,[CompileMetadata])-loadPublicDeps h ca = loadDepsCommon False h ca Set.empty cmPublicDeps+loadModuleMetadata :: VersionHash -> ForceMode -> MetadataMap -> FilePath ->+  CompileInfoIO CompileMetadata+loadModuleMetadata h f ca = fmap head . loadDepsCommon f h ca Set.empty (const []) . (:[]) -loadTestingDeps :: VersionHash -> MetadataMap -> CompileMetadata -> IO (Bool,[CompileMetadata])-loadTestingDeps h ca m = loadDepsCommon False h ca (Set.fromList [cmPath m]) cmPublicDeps (cmPublicDeps m ++ cmPrivateDeps m)+loadPublicDeps :: VersionHash -> ForceMode -> MetadataMap -> [FilePath] ->+  CompileInfoIO [CompileMetadata]+loadPublicDeps h f ca = loadDepsCommon f h ca Set.empty cmPublicDeps -loadPrivateDeps :: VersionHash -> MetadataMap -> [CompileMetadata] -> IO (Bool,[CompileMetadata])-loadPrivateDeps h ca ms = do-  (fr,new) <- loadDepsCommon False h ca pa (\m -> cmPublicDeps m ++ cmPrivateDeps m) paths-  return (fr,ms ++ new) where+loadTestingDeps :: VersionHash -> ForceMode -> MetadataMap -> CompileMetadata ->+  CompileInfoIO [CompileMetadata]+loadTestingDeps h f ca m = loadDepsCommon f h ca (Set.fromList [cmPath m]) cmPublicDeps (cmPublicDeps m ++ cmPrivateDeps m)++loadPrivateDeps :: VersionHash -> ForceMode -> MetadataMap -> [CompileMetadata] ->+  CompileInfoIO [CompileMetadata]+loadPrivateDeps h f ca ms = do+  new <- loadDepsCommon f h ca pa (\m -> cmPublicDeps m ++ cmPrivateDeps m) paths+  return $ ms ++ new where     paths = concat $ map (\m -> cmPublicDeps m ++ cmPrivateDeps m) ms     pa = Set.fromList $ map cmPath ms -loadDepsCommon :: Bool -> VersionHash -> MetadataMap -> Set.Set FilePath ->-  (CompileMetadata -> [FilePath]) -> [FilePath] -> IO (Bool,[CompileMetadata])-loadDepsCommon s h ca pa0 f ps = fmap snd $ fixedPaths >>= collect (pa0,(True,[])) where-  fixedPaths = sequence $ map canonicalizePath ps-  collect xa@(pa,(fr,xs)) (p:ps2)-    | p `Set.member` pa = collect xa ps2-    | otherwise = do-        (m,fr2) <-+loadDepsCommon :: ForceMode -> VersionHash -> MetadataMap -> Set.Set FilePath ->+  (CompileMetadata -> [FilePath]) -> [FilePath] -> CompileInfoIO [CompileMetadata]+loadDepsCommon f h ca pa0 getDeps ps = do+  (_,processed) <- fixedPaths >>= collect (pa0,[])+  mapErrorsM check processed where+    enforce = f /= ForceAll+    fixedPaths = mapM (errorFromIO . canonicalizePath) ps+    collect xa@(pa,xs) (p:ps2)+      | p `Set.member` pa = collect xa ps2+      | otherwise = do+          let continue m ds = collect (p `Set.insert` pa,xs ++ [m]) (ps2 ++ ds)           case p `Map.lookup` ca of-               Just m2 -> return (m2,True)+               Just m2 -> continue m2 []                Nothing -> do-                 when (not s) $ hPutStrLn stderr $ "Loading metadata for dependency \"" ++ p ++ "\"."+                 errorFromIO $ hPutStrLn stderr $ "Loading metadata for dependency \"" ++ p ++ "\"."                  m2 <- loadMetadata ca p-                 fresh <- checkModuleFreshness s p m2-                 when (not s && not fresh) $-                   hPutStrLn stderr $ "Module \"" ++ p ++ "\" is out of date and should be recompiled."-                 let sameVersion = checkModuleVersionHash h m2-                 when (not s && not sameVersion) $-                   hPutStrLn stderr $ "Module \"" ++ p ++ "\" was compiled with a different compiler setup."-                 return (m2,sameVersion && fresh)-        collect (p `Set.insert` pa,(fr2 && fr,xs ++ [m])) (ps2 ++ f m)-  collect xa _ = return xa+                 let ds = getDeps m2+                 continue m2 ds+    collect xa _ = return xa+    check m+      | cmPath m `Map.member` ca = return m+      | otherwise = do+          fresh <- checkModuleFreshness (cmPath m) m+          let sameVersion = checkModuleVersionHash h m+          when (enforce && not fresh) $+            compileErrorM $ "Module \"" ++ cmPath m ++ "\" is out of date and should be recompiled"+          when (enforce && not sameVersion) $+            compileErrorM $ "Module \"" ++ cmPath m ++ "\" was compiled with a different compiler setup"+          return m +loadMetadata :: MetadataMap -> FilePath -> CompileInfoIO CompileMetadata+loadMetadata ca p = do+  path <- errorFromIO $ canonicalizePath p+  case path `Map.lookup` ca of+       Just cm -> return cm+       Nothing -> do+         let f = p </> cachedDataPath </> metadataFilename+         isFile <- errorFromIO $ doesFileExist p+         when isFile $ compileErrorM $ "Path \"" ++ p ++ "\" is not a directory"+         isDir <- errorFromIO $ doesDirectoryExist p+         when (not isDir) $ compileErrorM $ "Path \"" ++ p ++ "\" does not exist"+         filePresent <- errorFromIO $ doesFileExist f+         when (not filePresent) $ compileErrorM $ "Module \"" ++ p ++ "\" has not been compiled yet"+         c <- errorFromIO $ readFile f+         (autoReadConfig f c) `reviseErrorM`+            ("Could not parse metadata from \"" ++ p ++ "\"; please recompile")+ fixPath :: FilePath -> FilePath fixPath = foldl (</>) "" . process [] . map dropSlash . splitPath where   dropSlash "/" = "/"@@ -324,46 +284,46 @@ checkModuleVersionHash :: VersionHash -> CompileMetadata -> Bool checkModuleVersionHash h m = cmVersionHash m == h -checkModuleFreshness :: Bool -> FilePath -> CompileMetadata -> IO Bool-checkModuleFreshness s p (CompileMetadata _ p2 _ is is2 _ _ _ ps xs ts hxx cxx bs _ _) = do-  time <- getModificationTime $ getCachedPath p "" metadataFilename+checkModuleFreshness :: FilePath -> CompileMetadata -> CompileInfoIO Bool+checkModuleFreshness p (CompileMetadata _ p2 _ is is2 _ _ _ ps xs ts hxx cxx bs _ _) = do+  time <- errorFromIO $ getModificationTime $ getCachedPath p "" metadataFilename   (ps2,xs2,ts2) <- findSourceFiles p ""   let e1 = checkMissing ps ps2   let e2 = checkMissing xs xs2   let e3 = checkMissing ts ts2   rm <- checkInput time (p </> moduleFilename)-  f1 <- sequence $ map (\p3 -> checkInput time $ getCachedPath p3 "" metadataFilename) $ is ++ is2-  f2 <- sequence $ map (checkInput time . (p2 </>)) $ ps ++ xs-  f3 <- sequence $ map (checkInput time . getCachedPath p2 "") $ hxx ++ cxx-  f4 <- sequence $ map checkOutput bs+  f1 <- mapErrorsM (\p3 -> checkInput time $ getCachedPath p3 "" metadataFilename) $ is ++ is2+  f2 <- mapErrorsM (checkInput time . (p2 </>)) $ ps ++ xs+  f3 <- mapErrorsM (checkInput time . getCachedPath p2 "") $ hxx ++ cxx+  f4 <- mapErrorsM checkOutput bs   let fresh = not $ any id $ [rm,e1,e2,e3] ++ f1 ++ f2 ++ f3 ++ f4   return fresh where     checkInput time f = do       exists <- doesFileOrDirExist f       if not exists          then do-           when (not s) $ hPutStrLn stderr $ "Required path \"" ++ f ++ "\" is missing."+           compileWarningM $ "Required path \"" ++ f ++ "\" is missing"            return True          else do-           time2 <- getModificationTime f+           time2 <- errorFromIO $ getModificationTime f            if time2 > time               then do-                when (not s) $ hPutStrLn stderr $ "Required path \"" ++ f ++ "\" is newer than cached data."+                compileWarningM $ "Required path \"" ++ f ++ "\" is newer than cached data"                 return True               else return False     checkOutput f = do-      exists <- doesFileExist f+      exists <- errorFromIO $ doesFileExist f       if not exists          then do-           when (not s) $ hPutStrLn stderr $ "Output file \"" ++ f ++ "\" is missing."+           compileWarningM $ "Output file \"" ++ f ++ "\" is missing"            return True          else return False     checkMissing s0 s1 = not $ null $ (Set.fromList s1) `Set.difference` (Set.fromList s0)     doesFileOrDirExist f2 = do-      existF <- doesFileExist f2+      existF <- errorFromIO $ doesFileExist f2       if existF         then return True-        else doesDirectoryExist f2+        else errorFromIO $ doesDirectoryExist f2  getObjectFileResolver :: [ObjectFile] -> [Namespace] -> [CategoryName] -> [FilePath] getObjectFileResolver os ns ds = resolved ++ nonCategories where
+ src/Cli/Programs.hs view
@@ -0,0 +1,75 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE Safe #-}++module Cli.Programs (+  CompilerBackend(..),+  CxxCommand(..),+  TestCommand(..),+  TestCommandResult(..),+  VersionHash(..),+) where++import Control.Monad.IO.Class++import Base.CompileError+++class CompilerBackend b where+  runCxxCommand   :: (MonadIO m, CompileErrorM m) => b -> CxxCommand -> m String+  runTestCommand  :: (MonadIO m, CompileErrorM m) => b -> TestCommand -> m TestCommandResult+  getCompilerHash :: b -> VersionHash++newtype VersionHash = VersionHash String deriving (Eq)++instance Show VersionHash where+  show (VersionHash h) = h++data CxxCommand =+  CompileToObject {+    ctoSource :: String,+    ctoPath :: String,+    ctoNamespaceMacro :: String,+    ctoNamespace :: String,+    ctoPaths :: [String],+    ctoExtra :: Bool+  } |+  CompileToBinary {+    ctbMain :: String,+    ctbSources :: [String],+    ctbOutput :: String,+    ctbPaths :: [String],+    ctbLinkFlags :: [String]+  }+  deriving (Show)++data TestCommand =+  TestCommand {+    tcBinary :: String,+    tcPath :: String+  }+  deriving (Show)++data TestCommandResult =+  TestCommandResult {+    tcrSuccess :: Bool,+    tcrOutput :: [String],+    tcrError :: [String]+  }+  deriving (Show)
src/Cli/RunCompiler.hs view
@@ -23,10 +23,8 @@ import Control.Monad (foldM,when) import Data.List (intercalate) import System.Directory-import System.Exit import System.FilePath import System.Posix.Temp (mkdtemp)-import System.IO import qualified Data.Map as Map import qualified Data.Set as Set @@ -35,67 +33,51 @@ import Cli.CompileMetadata import Cli.CompileOptions import Cli.Compiler+import Cli.Paths import Cli.ProcessMetadata-import Compilation.CompileInfo-import Config.LoadConfig-import Config.Paths-import Config.Programs+import Cli.Programs+import Base.CompileInfo  -runCompiler :: CompileOptions -> IO ()-runCompiler (CompileOptions _ _ _ ds _ _ p (ExecuteTests tp) f) = do-  (backend,resolver) <- loadConfig+runCompiler :: (PathIOHandler r, CompilerBackend b) => r -> b -> CompileOptions -> CompileInfoIO ()+runCompiler resolver backend (CompileOptions _ _ _ ds _ _ p (ExecuteTests tp) f) = do   base <- resolveBaseModule resolver-  ts <- fmap snd $ foldM (preloadTests backend base) (Map.empty,[]) ds+  ts <- fmap snd $ foldM (preloadTests base) (Map.empty,[]) ds   checkTestFilters ts-  allResults <- fmap concat $ sequence $ map (runModuleTests backend base tp) ts+  allResults <- fmap concat $ mapErrorsM (runModuleTests resolver backend base tp) ts   let passed = sum $ map (fst . fst) allResults   let failed = sum $ map (snd . fst) allResults-  processResults passed failed (mergeAllM $ map snd allResults) where-    preloadTests b base (ca,ms) d = do-      m <- loadMetadata ca (p </> d)+  processResults passed failed (mapErrorsM_ snd allResults) where+    compilerHash = getCompilerHash backend+    preloadTests base (ca,ms) d = do+      m <- loadModuleMetadata compilerHash f ca (p </> d)       let ca2 = ca `Map.union` mapMetadata [m]-      fr <- checkMetadataFreshness (p </> d) m-      checkAllowedStale fr f-      rm <- tryLoadRecompile (p </> d)-      rm' <- case rm of-                  Just rm2 -> return rm2-                  Nothing -> do-                    hPutStr stderr $ "Module config for " ++ d ++ " is missing."-                    exitFailure-      (fr0,deps0) <- loadPublicDeps (getCompilerHash b) ca2 [base]+      rm <- loadRecompile (p </> d)+      deps0 <- loadPublicDeps compilerHash f ca2 [base]       let ca3 = ca2 `Map.union` mapMetadata deps0-      checkAllowedStale fr0 f-      (fr1,deps1) <- loadTestingDeps (getCompilerHash b) ca3 m+      deps1 <- loadTestingDeps compilerHash f ca3 m       let ca4 = ca3 `Map.union` mapMetadata deps1-      checkAllowedStale fr1 f-      (fr2,deps2) <- loadPrivateDeps (getCompilerHash b) ca4 (deps0++[m]++deps1)+      deps2 <- loadPrivateDeps compilerHash f ca4 (deps0++[m]++deps1)       let ca5 = ca4 `Map.union` mapMetadata deps2-      checkAllowedStale fr2 f-      em <- getExprMap (p </> d) rm'+      em <- getExprMap (p </> d) rm       return (ca5,ms ++ [LoadedTests p d m em (deps0++[m]++deps1) deps2])     checkTestFilters ts = do       let possibleTests = Set.fromList $ concat $ map (cmTestFiles . ltMetadata) ts       case Set.toList $ (Set.fromList tp) `Set.difference` possibleTests of           [] -> return ()-          fs -> do-            hPutStr stderr $ "Some test files do not occur in the selected modules: " ++-                             intercalate ", " (map show fs) ++ "\n"-            exitFailure+          fs -> compileErrorM $ "Some test files do not occur in the selected modules: " +++                                intercalate ", " (map show fs) ++ "\n"     processResults passed failed rs-      | isCompileError rs = do-          hPutStr stderr $ "\nTest errors:\n" ++ (show $ getCompileError rs)-          hPutStrLn stderr $ "\nPassed: " ++ show passed ++ " test(s), Failed: " ++ show failed ++ " test(s)"-          hPutStrLn stderr $ "Zeolite tests failed."-          exitFailure-      | otherwise = do-          hPutStrLn stderr $ "\nPassed: " ++ show passed ++ " test(s), Failed: " ++ show failed ++ " test(s)"-          hPutStrLn stderr $ "Zeolite tests passed."+      | isCompileError rs =+        (fromCompileInfo rs) `reviseErrorM`+          ("\nPassed: " ++ show passed ++ " test(s), Failed: " ++ show failed ++ " test(s)")+      | otherwise =+        compileWarningM $ "\nPassed: " ++ show passed ++ " test(s), Failed: " ++ show failed ++ " test(s)" -runCompiler (CompileOptions _ is is2 _ _ _ p (CompileFast c fn f2) f) = do-  dir <- mkdtemp "/tmp/zfast_"-  absolute <- canonicalizePath p-  f2' <- canonicalizePath (p </> f2)+runCompiler resolver backend (CompileOptions _ is is2 _ _ _ p (CompileFast c fn f2) f) = do+  dir <- errorFromIO $ mkdtemp "/tmp/zfast_"+  absolute <- errorFromIO $ canonicalizePath p+  f2' <- errorFromIO $ canonicalizePath (p </> f2)   let rm = ModuleConfig {     rmRoot = "",     rmPath = ".",@@ -121,95 +103,81 @@     msMode = (CompileBinary c fn (absolute </> show c) []),     msForce = f   }-  compileModule spec-  removeDirectoryRecursive dir+  compileModule resolver backend spec `reviseErrorM` ("In compilation of \"" ++ f2' ++ "\"")+  errorFromIO $ removeDirectoryRecursive dir -runCompiler (CompileOptions h _ _ ds _ _ p CompileRecompileRecursive f) = do-  (_,resolver) <- loadConfig+runCompiler resolver backend (CompileOptions h _ _ ds _ _ p CompileRecompileRecursive f) = do   foldM (recursive resolver) Set.empty ds >> return () where     recursive r da d0 = do       isSystem <- isSystemModule r p d0       if isSystem          then do-           hPutStrLn stderr $ "Skipping system module " ++ d0 ++ "."-           exitFailure+           compileWarningM $ "Skipping system module " ++ d0 ++ "."+           return da          else do-           d <- canonicalizePath (p </> d0)-           rm <- tryLoadRecompile d-           case rm of-                Nothing -> do-                  hPutStrLn stderr $ "Path " ++ d ++ " does not have a valid configuration."-                  exitFailure-                Just m ->-                  if rmPath m `Set.member` da-                     then return da-                     else do-                       let ds3 = map (\d2 -> d </> d2) (rmPublicDeps m ++ rmPrivateDeps m)-                       da' <- foldM (recursive r) (rmPath m `Set.insert` da) ds3-                       runCompiler (CompileOptions h [] [] [d] [] [] p CompileRecompile f)-                       return da'+           d <- errorFromIO $ canonicalizePath (p </> d0)+           rm <- loadRecompile d+           if rmPath rm `Set.member` da+               then return da+               else do+                 let ds3 = map (\d2 -> d </> d2) (rmPublicDeps rm ++ rmPrivateDeps rm)+                 da' <- foldM (recursive r) (rmPath rm `Set.insert` da) ds3+                 runCompiler resolver backend (CompileOptions h [] [] [d] [] [] p CompileRecompile f)+                 return da' -runCompiler (CompileOptions _ _ _ ds _ _ p CompileRecompile f) = do-  (backend,_) <- loadConfig-  fmap mergeAll $ sequence $ map (recompileSingle $ getCompilerHash backend) ds where-    recompileSingle h2 d0 = do-      let d = p </> d0-      rm <- tryLoadRecompile d-      upToDate <- isPathUpToDate h2 d-      maybeCompile rm upToDate where-        maybeCompile Nothing _ = do-          hPutStrLn stderr $ "Path " ++ d0 ++ " does not have a valid configuration."-          exitFailure-        maybeCompile (Just rm') upToDate-          | f < ForceAll && upToDate = hPutStrLn stderr $ "Path " ++ d0 ++ " is up to date."-          | otherwise = do-              let (ModuleConfig p2 d _ is is2 es ep m) = rm'-              -- In case the module is manually configured with a p such as "..",-              -- since the absolute path might not be known ahead of time.-              absolute <- canonicalizePath (p </> d0)-              let fixed = fixPath (absolute </> p2)-              (ps,xs,ts) <- findSourceFiles fixed d-              em <- getExprMap (p </> d0) rm'-              let spec = ModuleSpec {-                msRoot = fixed,-                msPath = d,-                msExprMap = em,-                msPublicDeps = is,-                msPrivateDeps = is2,-                msPublicFiles = ps,-                msPrivateFiles = xs,-                msTestFiles = ts,-                msExtraFiles = es,-                msExtraPaths = ep,-                msMode = m,-                msForce = f-              }-              compileModule spec+runCompiler resolver backend (CompileOptions _ _ _ ds _ _ p CompileRecompile f) = do+  mergeAllM $ map recompileSingle ds where+    compilerHash = getCompilerHash backend+    recompileSingle d0 = do+      d <- errorFromIO $ canonicalizePath (p </> d0)+      upToDate <- isPathUpToDate compilerHash f d+      if f < ForceAll && upToDate+         then compileWarningM $ "Path " ++ d0 ++ " is up to date"+         else do+           rm@(ModuleConfig p2 d2 _ is is2 es ep m) <- loadRecompile d+           -- In case the module is manually configured with a p such as "..",+           -- since the absolute path might not be known ahead of time.+           absolute <- errorFromIO $ canonicalizePath (p </> d0)+           let fixed = fixPath (absolute </> p2)+           (ps,xs,ts) <- findSourceFiles fixed d2+           em <- getExprMap (p </> d0) rm+           let spec = ModuleSpec {+             msRoot = fixed,+             msPath = d2,+             msExprMap = em,+             msPublicDeps = is,+             msPrivateDeps = is2,+             msPublicFiles = ps,+             msPrivateFiles = xs,+             msTestFiles = ts,+             msExtraFiles = es,+             msExtraPaths = ep,+             msMode = m,+             msForce = f+           }+           compileModule resolver backend spec `reviseErrorM` ("In compilation of module \"" ++ d ++ "\"") -runCompiler (CompileOptions _ is is2 ds _ _ p CreateTemplates f) = mapM_ compileSingle ds where+runCompiler resolver backend (CompileOptions _ is is2 ds _ _ p CreateTemplates f) = mapM_ compileSingle ds where+  compilerHash = getCompilerHash backend   compileSingle d = do-    (backend,resolver) <- loadConfig+    d' <- errorFromIO $ canonicalizePath (p </> d)     base <- resolveBaseModule resolver-    as  <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is-    as2 <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is2-    (fr1,deps1) <- loadPublicDeps (getCompilerHash backend) Map.empty (base:as)-    checkAllowedStale fr1 f-    (fr2,deps2) <- loadPublicDeps (getCompilerHash backend) (mapMetadata deps1) as2-    checkAllowedStale fr2 f-    path <- canonicalizePath p-    createModuleTemplates path d deps1 deps2+    as  <- fmap fixPaths $ mapErrorsM (resolveModule resolver d') is+    as2 <- fmap fixPaths $ mapErrorsM (resolveModule resolver d') is2+    deps1 <- loadPublicDeps compilerHash f Map.empty (base:as)+    deps2 <- loadPublicDeps compilerHash f (mapMetadata deps1) as2+    path <- errorFromIO $ canonicalizePath p+    createModuleTemplates path d deps1 deps2 `reviseErrorM` ("In module \"" ++ d' ++ "\"") -runCompiler (CompileOptions h is is2 ds es ep p m f) = mapM_ compileSingle ds where+runCompiler resolver backend (CompileOptions h is is2 ds es ep p m f) = mapM_ compileSingle ds where   compileSingle d = do-    (_,resolver) <- loadConfig-    as  <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is-    as2 <- fmap fixPaths $ sequence $ map (resolveModule resolver (p </> d)) is2+    as  <- fmap fixPaths $ mapErrorsM (resolveModule resolver (p </> d)) is+    as2 <- fmap fixPaths $ mapErrorsM (resolveModule resolver (p </> d)) is2     isConfigured <- isPathConfigured d     when (isConfigured && f == DoNotForce) $ do-      hPutStrLn stderr $ "Module " ++ d ++ " has an existing configuration. " ++-                        "Recompile with -r or use -f to overwrite the config."-      exitFailure-    absolute <- canonicalizePath p+      compileErrorM $ "Module " ++ d ++ " has an existing configuration. " +++                      "Recompile with -r or use -f to overwrite the config."+    absolute <- errorFromIO $ canonicalizePath p     let rm = ModuleConfig {       rmRoot = absolute,       rmPath = d,@@ -221,4 +189,4 @@       rmMode = m     }     writeRecompile (p </> d) rm-    runCompiler (CompileOptions h [] [] [d] [] [] p CompileRecompile DoNotForce)+    runCompiler resolver backend (CompileOptions h [] [] [d] [] [] p CompileRecompile DoNotForce)
src/Cli/TestRunner.hs view
@@ -34,10 +34,10 @@ import Base.Mergeable import Cli.CompileMetadata import Cli.ProcessMetadata-import Compilation.CompileInfo+import Cli.Programs+import Base.CompileInfo import CompilerCxx.Category import CompilerCxx.Naming-import Config.Programs import Parser.SourceFile import Types.IntegrationTest import Types.TypeCategory@@ -45,14 +45,14 @@  runSingleTest :: CompilerBackend b => b -> LanguageModule SourcePos ->   FilePath -> [FilePath] -> [CompileMetadata] -> (String,String) ->-  IO ((Int,Int),CompileInfo ())+  CompileInfoIO ((Int,Int),CompileInfo ()) runSingleTest b cm p paths deps (f,s) = do-  hPutStrLn stderr $ "\nExecuting tests from " ++ f+  errorFromIO $ hPutStrLn stderr $ "\nExecuting tests from " ++ f   allResults <- checkAndRun (parseTestSource (f,s))-  return $ second (flip reviseError $ "\nIn test file " ++ f) allResults where+  return $ second (flip reviseErrorM $ "\nIn test file " ++ f) allResults where     checkAndRun ts       | isCompileError ts = do-        hPutStrLn stderr $ "Failed to parse tests in " ++ f+        errorFromIO $ hPutStrLn stderr $ "Failed to parse tests in " ++ f         return ((0,1),ts >> return ())       | otherwise = do           let (_,ts') = getCompileSuccess ts@@ -61,14 +61,14 @@           let failed = length $ filter isCompileError allResults           return ((passed,failed),mergeAllM allResults)     runSingle t = do-      let name = ithTestName $ itHeader t+      let name = "\"" ++ ithTestName (itHeader t) ++ "\" (from " ++ f ++ ")"       let context = formatFullContextBrace (ithContext $ itHeader t)-      hPutStrLn stderr $ "\n*** Executing test \"" ++ name ++ "\" ***"-      outcome <- fmap (flip reviseError ("\nIn test \"" ++ name ++ "\"" ++ context)) $+      errorFromIO $ hPutStrLn stderr $ "\n*** Executing test " ++ name ++ " ***"+      outcome <- fmap (flip reviseErrorM ("\nIn test \"" ++ name ++ "\"" ++ context)) $                    run (ithResult $ itHeader t) (itCategory t) (itDefinition t)       if isCompileError outcome-         then hPutStrLn stderr $ "*** Test \"" ++ name ++ "\" failed ***"-         else hPutStrLn stderr $ "*** Test \"" ++ name ++ "\" passed ***"+         then errorFromIO $ hPutStrLn stderr $ "*** Test " ++ name ++ " failed ***"+         else errorFromIO $ hPutStrLn stderr $ "*** Test " ++ name ++ " passed ***"       return outcome      run (ExpectCompileError _ rs es) cs ds = do@@ -88,21 +88,21 @@       let ce = checkExcluded es comp err out       let compError = if null comp                          then return ()-                         else (mergeAllM $ map compileError comp) `reviseError` "\nOutput from compiler:"+                         else (mergeAllM $ map compileErrorM comp) `reviseErrorM` "\nOutput from compiler:"       let errError = if null err                         then return ()-                        else (mergeAllM $ map compileError err) `reviseError` "\nOutput to stderr from test:"+                        else (mergeAllM $ map compileErrorM err) `reviseErrorM` "\nOutput to stderr from test:"       let outError = if null out                         then return ()-                        else (mergeAllM $ map compileError out) `reviseError` "\nOutput to stdout from test:"+                        else (mergeAllM $ map compileErrorM out) `reviseErrorM` "\nOutput to stdout from test:"       if isCompileError cr || isCompileError ce          then mergeAllM [cr,ce,compError,errError,outError]          else mergeAllM [cr,ce] -    execute s2 e rs es cs ds = do+    execute s2 e rs es cs ds = toCompileInfo $ do       let result = compileAll (Just e) cs ds       if isCompileError result-         then return $ result >> return ()+         then fromCompileInfo result >> return ()          else do            let warnings = getCompileWarnings result            let (xx,main) = getCompileSuccess result@@ -110,12 +110,12 @@            let command = TestCommand binaryName (takeDirectory binaryName)            (TestCommandResult s2' out err) <- runTestCommand b command            case (s2,s2') of-                (True,False) -> return $ mergeAllM $ map compileError $ warnings ++ err ++ out-                (False,True) -> return $ compileError "Expected runtime failure"+                (True,False) -> mergeAllM $ map compileErrorM $ warnings ++ err ++ out+                (False,True) -> compileErrorM "Expected runtime failure"                 _ -> do                   let result2 = checkContent rs es warnings err out-                  when (not $ isCompileError result) $ removeDirectoryRecursive dir-                  return result2+                  when (not $ isCompileError result) $ errorFromIO $ removeDirectoryRecursive dir+                  fromCompileInfo result2      compileAll e cs ds = do       let ns1 = StaticNamespace $ privateNamespace s@@ -129,7 +129,7 @@       (_,xx) <- compileLanguageModule cm [xs]       main <- case e of                    Just e2 -> compileTestMain cm xs e2-                   Nothing -> compileError "Expected compiler error"+                   Nothing -> compileErrorM "Expected compiler error"       return (xx,main)      checkRequired rs comp err out = mergeAllM $ map (checkSubsetForRegex True  comp err out) rs@@ -145,17 +145,17 @@     checkForRegex :: Bool -> [String] -> String -> String -> CompileInfo ()     checkForRegex expected ms r n = do       let found = any (=~ r) ms-      when (found && not expected) $ compileError $ "Pattern \"" ++ r ++ "\" present in " ++ n-      when (not found && expected) $ compileError $ "Pattern \"" ++ r ++ "\" missing from " ++ n+      when (found && not expected) $ compileErrorM $ "Pattern \"" ++ r ++ "\" present in " ++ n+      when (not found && expected) $ compileErrorM $ "Pattern \"" ++ r ++ "\" missing from " ++ n     createBinary (CxxOutput _ f2 _ ns req content) xx = do-      dir <- mkdtemp "/tmp/ztest_"-      hPutStrLn stderr $ "Writing temporary files to " ++ dir-      sources <- sequence $ map (writeSingleFile dir) xx+      dir <- errorFromIO $ mkdtemp "/tmp/ztest_"+      errorFromIO $ hPutStrLn stderr $ "Writing temporary files to " ++ dir+      sources <- mapErrorsM (writeSingleFile dir) xx       -- TODO: Cache CompileMetadata here for debugging failures.       let sources' = resolveObjectDeps deps p dir sources       let main   = dir </> f2       let binary = dir </> "testcase"-      writeFile main $ concat $ map (++ "\n") content+      errorFromIO $ writeFile main $ concat $ map (++ "\n") content       let flags = getLinkFlagsForDeps deps       let paths' = nub $ map fixPath (dir:paths)       let os  = getObjectFilesForDeps deps@@ -165,7 +165,7 @@       file <- runCxxCommand b command       return (dir,file)     writeSingleFile d ca@(CxxOutput _ f2 _ _ _ content) = do-      writeFile (d </> f2) $ concat $ map (++ "\n") content+      errorFromIO $ writeFile (d </> f2) $ concat $ map (++ "\n") content       if isSuffixOf ".cpp" f2          then return ([d </> f2],ca)          else return ([],ca)
− src/Compilation/CompileInfo.hs
@@ -1,151 +0,0 @@-{- ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at--    http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ -}---- Author: Kevin P. Barry [ta0kira@gmail.com]--{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE Safe #-}--module Compilation.CompileInfo (-  CompileInfo,-  CompileMessage,-  getCompileError,-  getCompileSuccess,-  getCompileWarnings,-) where--import Control.Applicative-import Data.List (intercalate)-import Data.Foldable-import Data.Functor-import Prelude hiding (concat,foldr)--#if MIN_VERSION_base(4,8,0)-#else-import Data.Foldable-#endif--#if MIN_VERSION_base(4,13,0)-import Control.Monad.Fail ()-#elif MIN_VERSION_base(4,9,0)-import Control.Monad.Fail-#endif--import Base.CompileError-import Base.Mergeable---data CompileMessage =-  CompileMessage {-    cmMessage :: String,-    cmNested :: [CompileMessage]-  }--instance Show CompileMessage where-  show = format "" where-    format indent (CompileMessage [] ms) =-      concat (map (format indent) ms)-    format indent (CompileMessage m ms) =-      (doIndent indent m) ++ "\n" ++ concat (map (format $ indent ++ "  ") ms)-    doIndent indent s = intercalate "\n" $ map (indent ++) $ lines s--data CompileInfo a =-  CompileFail {-    cfWarnings :: [String],-    cfErrors :: CompileMessage-  } |-  CompileSuccess {-    csWarnings :: [String],-    csData :: a-  }--getCompileError :: CompileInfo a -> CompileMessage-getCompileError   = cfErrors--getCompileSuccess :: CompileInfo a -> a-getCompileSuccess = csData--getCompileWarnings :: CompileInfo a -> [String]-getCompileWarnings (CompileFail w _)    = w-getCompileWarnings (CompileSuccess w _) = w---instance Functor CompileInfo where-  fmap _ (CompileFail w e)    = CompileFail w e -- Not the same a.-  fmap f (CompileSuccess w d) = CompileSuccess w (f d)--instance Applicative CompileInfo where-  pure = CompileSuccess []-  (CompileFail w e) <*> _ = CompileFail w e -- Not the same a.-  i <*> (CompileFail w e) = CompileFail (getCompileWarnings i ++ w) e -- Not the same a.-  (CompileSuccess w1 f) <*> (CompileSuccess w2 d) = CompileSuccess (w1 ++ w2) (f d)--instance Monad CompileInfo where-  (CompileFail w e)    >>= _ = CompileFail w e -- Not the same a.-  (CompileSuccess w d) >>= f = prependWarning w $ f d-  return = pure--prependWarning :: [String] -> CompileInfo a -> CompileInfo a-prependWarning w (CompileSuccess w2 d) = CompileSuccess (w ++ w2) d-prependWarning w (CompileFail w2 e)    = CompileFail (w ++ w2) e--instance CompileErrorM CompileInfo where-  compileErrorM = CompileFail [] . flip CompileMessage []-  isCompileErrorM (CompileFail _ _) = True-  isCompileErrorM _                 = False-  collectAllOrErrorM = result . splitErrorsAndData where-    result ([],xs,ws) = CompileSuccess ws xs-    result (es,_,ws) = CompileFail ws $ CompileMessage "" es-  collectOneOrErrorM = result . splitErrorsAndData where-    result (_,x:_,ws) = CompileSuccess ws x-    result ([],_,ws)  = CompileFail ws $ CompileMessage "" []-    result (es,_,ws)  = CompileFail ws $ CompileMessage "" es-  reviseErrorM x@(CompileSuccess _ _) _ = x-  reviseErrorM (CompileFail w (CompileMessage [] ms)) s = CompileFail w $ CompileMessage s ms-  reviseErrorM (CompileFail w e) s = CompileFail w $ CompileMessage s [e]-  compileWarningM w = CompileSuccess [w] ()--instance MergeableM CompileInfo where-  mergeAnyM = result . splitErrorsAndData where-    result (_,xs@(_:_),ws) = CompileSuccess ws $ mergeAny xs-    result ([],_,ws)       = CompileFail ws $ CompileMessage "" []-    result (es,_,ws)       = CompileFail ws $ CompileMessage "" es-  mergeAllM = result . splitErrorsAndData where-    result ([],xs,ws) = CompileSuccess ws $ mergeAll xs-    result (es,_,ws)  = CompileFail ws $ CompileMessage "" es-  (CompileSuccess w1 x) `mergeNestedM` (CompileSuccess w2 y) = CompileSuccess (w1 ++ w2) $ x `mergeNested` y-  (CompileFail w1 e)    `mergeNestedM` (CompileSuccess w2 _) = CompileFail (w1 ++ w2) e-  (CompileSuccess w1 _) `mergeNestedM` (CompileFail w2 e)    = CompileFail (w1 ++ w2) e-  (CompileFail w1 e1)   `mergeNestedM` (CompileFail w2 e2)   = CompileFail (w1 ++ w2) $ e1 `nestMessages` e2--#if MIN_VERSION_base(4,9,0)-instance MonadFail CompileInfo where-  fail = compileErrorM-#endif--nestMessages :: CompileMessage -> CompileMessage -> CompileMessage-nestMessages (CompileMessage m1 ms1) (CompileMessage [] ms2) =-  CompileMessage m1 (ms1 ++ ms2)-nestMessages (CompileMessage [] ms1) (CompileMessage m2 ms2) =-  CompileMessage m2 (ms1 ++ ms2)-nestMessages (CompileMessage m1 ms1) ma@(CompileMessage _ _) =-  CompileMessage m1 (ms1 ++ [ma])--splitErrorsAndData :: Foldable f => f (CompileInfo a) -> ([CompileMessage],[a],[String])-splitErrorsAndData = foldr partition ([],[],[]) where-  partition (CompileFail w e)    (es,ds,ws) = (e:es,ds,w++ws)-  partition (CompileSuccess w d) (es,ds,ws) = (es,d:ds,w++ws)
src/Compilation/CompilerState.hs view
@@ -149,7 +149,7 @@   show (VariableValue c _ t _) = show t ++ formatFullContextBrace c  reviseErrorStateT :: (CompileErrorM m) => CompilerState a m b -> String -> CompilerState a m b-reviseErrorStateT x s = mapStateT (`reviseError` s) x+reviseErrorStateT x s = mapStateT (`reviseErrorM` s) x  csCurrentScope :: CompilerContext c m s a => CompilerState a m SymbolScope csCurrentScope = fmap ccCurrentScope get >>= lift
src/Compilation/ProcedureContext.hs view
@@ -90,7 +90,7 @@   ccGetParamScope ctx p = do     case p `Map.lookup` pcParamScopes ctx of             (Just s) -> return s-            _ -> compileError $ "Param " ++ show p ++ " does not exist"+            _ -> compileErrorM $ "Param " ++ show p ++ " does not exist"   ccRequiresTypes ctx ts = return $     ProcedureContext {       pcScope = pcScope ctx,@@ -128,30 +128,30 @@         checkFunction $ n `Map.lookup` fa     checkFunction (Just f) = do       when (pcDisallowInit ctx && t == pcType ctx && pcScope ctx == CategoryScope) $-        compileError $ "Function " ++ show n +++        compileErrorM $ "Function " ++ show n ++                        " disallowed during initialization" ++ formatFullContextBrace c       when (sfScope f /= CategoryScope) $-        compileError $ "Function " ++ show n ++ " in " ++ show t ++ " cannot be used as a category function"+        compileErrorM $ "Function " ++ show n ++ " in " ++ show t ++ " cannot be used as a category function"       return f     checkFunction _ =-      compileError $ "Category " ++ show t +++      compileErrorM $ "Category " ++ show t ++                      " does not have a category function named " ++ show n ++                      formatFullContextBrace c   ccGetTypeFunction ctx c t n = getFunction t where     getFunction (Just t2@(TypeMerge MergeUnion _)) =-      compileError $ "Use explicit type conversion to call " ++ show n ++ " for union type " +++      compileErrorM $ "Use explicit type conversion to call " ++ show n ++ " for union type " ++                      show t2 ++ formatFullContextBrace c     getFunction (Just ta@(TypeMerge MergeIntersect ts)) =-      collectOneOrErrorM (map getFunction $ map Just ts) `reviseError`+      collectOneOrErrorM (map getFunction $ map Just ts) `reviseErrorM`         ("Function " ++ show n ++ " not available for type " ++ show ta ++ formatFullContextBrace c)     getFunction (Just (SingleType (JustParamName p))) = do       fa <- ccAllFilters ctx       fs <- case p `Map.lookup` fa of                 (Just fs) -> return fs-                _ -> compileError $ "Param " ++ show p ++ " does not exist"+                _ -> compileErrorM $ "Param " ++ show p ++ " does not exist"       let ts = map tfType $ filter isRequiresFilter fs       let ds = map dfType $ filter isDefinesFilter  fs-      collectOneOrErrorM (map (getFunction . Just . SingleType) ts ++ map checkDefine ds) `reviseError`+      collectOneOrErrorM (map (getFunction . Just . SingleType) ts ++ map checkDefine ds) `reviseErrorM`         ("Function " ++ show n ++ " not available for param " ++ show p ++ formatFullContextBrace c)     getFunction (Just (SingleType (JustTypeInstance t2)))       -- Same category as the procedure itself.@@ -166,6 +166,7 @@     getFunction Nothing = do       let ps = fmap (SingleType . JustParamName . vpParam) $ pcExtParams ctx       getFunction (Just $ SingleType $ JustTypeInstance $ TypeInstance (pcType ctx) ps)+    getFunction (Just t2) = compileErrorM $ "Type " ++ show t2 ++ " contains unresolved types"     checkDefine t2 = do       (_,ca) <- getCategory (pcCategories ctx) (c,diName t2)       let params = Positional $ map vpParam $ getCategoryParams ca@@ -173,24 +174,24 @@       checkFunction (diName t2) params (diParams t2) $ n `Map.lookup` fa     checkFunction t2 ps1 ps2 (Just f) = do       when (pcDisallowInit ctx && t2 == pcType ctx) $-        compileError $ "Function " ++ show n +++        compileErrorM $ "Function " ++ show n ++                        " disallowed during initialization" ++ formatFullContextBrace c       when (sfScope f == CategoryScope) $-        compileError $ "Function " ++ show n ++ " in " ++ show t2 +++        compileErrorM $ "Function " ++ show n ++ " in " ++ show t2 ++                        " is a category function" ++ formatFullContextBrace c-      paired <- processPairs alwaysPair ps1 ps2 `reviseError`+      paired <- processPairs alwaysPair ps1 ps2 `reviseErrorM`         ("In external function call at " ++ formatFullContext c)       let assigned = Map.fromList paired       uncheckedSubFunction assigned f     checkFunction t2 _ _ _ =-      compileError $ "Category " ++ show t2 +++      compileErrorM $ "Category " ++ show t2 ++                      " does not have a type or value function named " ++ show n ++                      formatFullContextBrace c   ccCheckValueInit ctx c (TypeInstance t as) ts ps     | t /= pcType ctx =-      compileError $ "Category " ++ show (pcType ctx) ++ " cannot initialize values from " +++      compileErrorM $ "Category " ++ show (pcType ctx) ++ " cannot initialize values from " ++                      show t ++ formatFullContextBrace c-    | otherwise = flip reviseError ("In initialization at " ++ formatFullContext c) $ do+    | otherwise = flip reviseErrorM ("In initialization at " ++ formatFullContext c) $ do       let t' = TypeInstance (pcType ctx) as       r <- ccResolver ctx       allFilters <- ccAllFilters ctx@@ -202,10 +203,10 @@       let mapped = Map.fromListWith (++) $ map (\f -> (pfParam f,[pfFilter f])) (pcIntFilters ctx)       let positional = map (getFilters mapped) (map vpParam $ pValues $ pcIntParams ctx)       assigned <- fmap Map.fromList $ processPairs alwaysPair (fmap vpParam $ pcIntParams ctx) ps-      subbed <- fmap Positional $ collectAllOrErrorM $ map (assignFilters assigned) positional+      subbed <- fmap Positional $ mapErrorsM (assignFilters assigned) positional       processPairs_ (validateAssignment r allFilters) ps subbed       -- Check initializer types.-      ms <- fmap Positional $ collectAllOrErrorM $ map (subSingle pa') (pcMembers ctx)+      ms <- fmap Positional $ mapErrorsM (subSingle pa') (pcMembers ctx)       processPairs_ (checkInit r allFilters) ms (Positional $ zip ([1..] :: [Int]) $ pValues ts)       return ()       where@@ -214,9 +215,9 @@               (Just fs) -> fs               _ -> []         assignFilters fm fs = do-          collectAllOrErrorM $ map (uncheckedSubFilter $ getValueForParam fm) fs+          mapErrorsM (uncheckedSubFilter $ getValueForParam fm) fs         checkInit r fa (MemberValue c2 n t0) (i,t1) = do-          checkValueTypeMatch r fa t1 t0 `reviseError`+          checkValueTypeMatch r fa t1 t0 `reviseErrorM`             ("In initializer " ++ show i ++ " for " ++ show n ++ formatFullContextBrace c2)         subSingle pa (DefinedMember c2 _ t2 n _) = do           t2' <- uncheckedSubValueType (getValueForParam pa) t2@@ -224,12 +225,12 @@   ccGetVariable ctx c n =     case n `Map.lookup` pcVariables ctx of           (Just v) -> return v-          _ -> compileError $ "Variable " ++ show n ++ " is not defined" +++          _ -> compileErrorM $ "Variable " ++ show n ++ " is not defined" ++                               formatFullContextBrace c   ccAddVariable ctx c n t = do     case n `Map.lookup` pcVariables ctx of           Nothing -> return ()-          (Just v) -> compileError $ "Variable " ++ show n +++          (Just v) -> compileErrorM $ "Variable " ++ show n ++                                     formatFullContextBrace c ++                                     " is already defined: " ++ show v     return $ ProcedureContext {@@ -258,7 +259,7 @@   ccCheckVariableInit ctx c n =     case pcReturns ctx of          ValidateNames _ na -> when (n `Map.member` na) $-           compileError $ "Named return " ++ show n ++ " might not be initialized" ++ formatFullContextBrace c+           compileErrorM $ "Named return " ++ show n ++ " might not be initialized" ++ formatFullContextBrace c          _ -> return ()   ccWrite ctx ss = return $     ProcedureContext {@@ -399,23 +400,23 @@                        Nothing -> Positional []                        Just vs2 -> vs2         -- Check for a count match first, to avoid the default error message.-        processPairs_ alwaysPair (fmap pvType rs) vs' `reviseError`+        processPairs_ alwaysPair (fmap pvType rs) vs' `reviseErrorM`           ("In procedure return at " ++ formatFullContext c)-        processPairs_ checkReturnType rs (Positional $ zip ([0..] :: [Int]) $ pValues vs') `reviseError`+        processPairs_ checkReturnType rs (Positional $ zip ([0..] :: [Int]) $ pValues vs') `reviseErrorM`           ("In procedure return at " ++ formatFullContext c)         return ()         where           checkReturnType ta0@(PassedValue _ t0) (n,t) = do             r <- ccResolver ctx             pa <- ccAllFilters ctx-            checkValueTypeMatch r pa t t0 `reviseError`+            checkValueTypeMatch r pa t t0 `reviseErrorM`               ("Cannot convert " ++ show t ++ " to " ++ show ta0 ++ " in return " ++                show n ++ " at " ++ formatFullContext c)       check (ValidateNames ts ra) =         case vs of              Just _ -> check (ValidatePositions ts)              Nothing -> mergeAllM $ map alwaysError $ Map.toList ra where-               alwaysError (n,t) = compileError $ "Named return " ++ show n ++ " (" ++ show t +++               alwaysError (n,t) = compileErrorM $ "Named return " ++ show n ++ " (" ++ show t ++                                                   ") might not have been set before return at " ++                                                   formatFullContext c       check _ = return ()@@ -503,7 +504,7 @@   ccGetCleanup = return . pcCleanupSetup   ccExprLookup ctx c n =     case n `Map.lookup` pcExprMap ctx of-         Nothing -> compileError $ "Env expression " ++ n ++ " is not defined" ++ formatFullContextBrace c+         Nothing -> compileErrorM $ "Env expression " ++ n ++ " is not defined" ++ formatFullContextBrace c          Just e -> return e   ccSetNoTrace ctx t =     return $ ProcedureContext {@@ -545,7 +546,7 @@           va' <- va           case ovName r `Map.lookup` va' of                Nothing -> return $ Map.insert (ovName r) (VariableValue c LocalScope t True) va'-               (Just v) -> compileError $ "Variable " ++ show (ovName r) +++               (Just v) -> compileErrorM $ "Variable " ++ show (ovName r) ++                                           formatFullContextBrace (ovContext r) ++                                           " is already defined" ++                                           formatFullContextBrace (vvContext v)@@ -562,7 +563,7 @@       va' <- va       case ivName a `Map.lookup` va' of             Nothing -> return $ Map.insert (ivName a) (VariableValue c LocalScope t False) va'-            (Just v) -> compileError $ "Variable " ++ show (ivName a) +++            (Just v) -> compileErrorM $ "Variable " ++ show (ivName a) ++                                        formatFullContextBrace (ivContext a) ++                                        " is already defined" ++                                        formatFullContextBrace (vvContext v)
src/Compilation/ScopeContext.hs view
@@ -102,7 +102,7 @@       let fa' = Map.union fa $ getFilterMap pi2 fi2       mergeAllM $ map (checkFilter r fa') fi2     checkFilter r fa (ParamFilter c2 n2 f) =-      validateTypeFilter r fa f `reviseError`+      validateTypeFilter r fa f `reviseErrorM`         (show n2 ++ " " ++ show f ++ formatFullContextBrace c2)     checkFunction pm f =       when (sfScope f == ValueScope) $@@ -110,7 +110,7 @@     checkParam pm p =       case vpParam p `Map.lookup` pm of            Nothing -> return ()-           (Just c2) -> compileError $ "Internal param " ++ show (vpParam p) +++           (Just c2) -> compileErrorM $ "Internal param " ++ show (vpParam p) ++                                        formatFullContextBrace (vpContext p) ++                                        " is already defined at " ++                                        formatFullContext c2
src/CompilerCxx/Category.hs view
@@ -99,10 +99,10 @@   -- Check public sources up front so that error messages aren't duplicated for   -- every source file.   _ <- tmTesting-  (hxx1,cxx1) <- fmap mergeGeneratedP $ collectAllOrErrorM $ map (compileSourceP tmPublic  nsPublic)  cs1-  (hxx2,cxx2) <- fmap mergeGeneratedP $ collectAllOrErrorM $ map (compileSourceP tmPrivate nsPrivate) ps1-  (hxx3,cxx3) <- fmap mergeGeneratedP $ collectAllOrErrorM $ map (compileSourceP tmTesting nsTesting) ts1-  (ds,xx) <- fmap mergeGeneratedX $ collectAllOrErrorM $ map compileSourceX xa+  (hxx1,cxx1) <- fmap mergeGeneratedP $ mapErrorsM (compileSourceP tmPublic  nsPublic)  cs1+  (hxx2,cxx2) <- fmap mergeGeneratedP $ mapErrorsM (compileSourceP tmPrivate nsPrivate) ps1+  (hxx3,cxx3) <- fmap mergeGeneratedP $ mapErrorsM (compileSourceP tmTesting nsTesting) ts1+  (ds,xx) <- fmap mergeGeneratedX $ mapErrorsM compileSourceX xa   -- TODO: This should account for a name clash between a category declared in a   -- TestsOnly .0rp and one declared in a non-TestOnly .0rx.   let dm = mapByName ds@@ -140,11 +140,11 @@       -- Ensures that there isn't an inavertent collision when resolving       -- dependencies for the module later on.       tmTesting' <- tmTesting-      _ <- includeNewTypes tmTesting' cs2 `reviseError` "In a module source that is conditionally public"-      hxx <- collectAllOrErrorM $ map (compileCategoryDeclaration tm' ns4) cs2+      _ <- includeNewTypes tmTesting' cs2 `reviseErrorM` "In a module source that is conditionally public"+      hxx <- mapErrorsM (compileCategoryDeclaration tm' ns4) cs2       let interfaces = filter (not . isValueConcrete) cs2-      cxx1 <- collectAllOrErrorM $ map compileInterfaceDefinition interfaces-      cxx2 <- collectAllOrErrorM $ map (compileDefinition tm' (ns:ns4)) ds+      cxx1 <- mapErrorsM compileInterfaceDefinition interfaces+      cxx2 <- mapErrorsM (compileDefinition tm' (ns:ns4)) ds       return (ds,hxx ++ cxx1 ++ cxx2)     mergeGeneratedX ((ds,xx):xs2) = let (ds2,xx2) = mergeGeneratedX xs2 in (ds++ds2,xx++xx2)     mergeGeneratedX _             = ([],[])@@ -158,7 +158,7 @@     checkLocal cs2 d =       if dcName d `Set.member` cs2          then return ()-         else compileError ("Definition for " ++ show (dcName d) +++         else compileErrorM ("Definition for " ++ show (dcName d) ++                             formatFullContextBrace (dcContext d) ++                             " does not correspond to a visible category in this module")     checkDefined dm ex2 = mergeAllM . map (checkSingle dm (Set.fromList ex2))@@ -167,21 +167,21 @@            (False,Just [_]) -> return ()            (True,Nothing)   -> return ()            (True,Just [d]) ->-             compileError ("Category " ++ show (getCategoryName t) +++             compileErrorM ("Category " ++ show (getCategoryName t) ++                            formatFullContextBrace (getCategoryContext t) ++                            " was declared external but is also defined at " ++ formatFullContext (dcContext d))            (False,Nothing) ->-             compileError ("Category " ++ show (getCategoryName t) +++             compileErrorM ("Category " ++ show (getCategoryName t) ++                            formatFullContextBrace (getCategoryContext t) ++                            " has not been defined or declared external")            (_,Just ds) ->-             flip reviseError ("Category " ++ show (getCategoryName t) +++             flip reviseErrorM ("Category " ++ show (getCategoryName t) ++                                formatFullContextBrace (getCategoryContext t) ++                                " is defined " ++ show (length ds) ++ " times") $-               mergeAllM $ map (\d -> compileError $ "Defined at " ++ formatFullContext (dcContext d)) ds+               mergeAllM $ map (\d -> compileErrorM $ "Defined at " ++ formatFullContext (dcContext d)) ds     checkSupefluous es2       | null es2 = return ()-      | otherwise = compileError $ "External categories either not concrete or not present: " +++      | otherwise = compileErrorM $ "External categories either not concrete or not present: " ++                                    intercalate ", " (map show es2)  compileTestMain :: (Show c, CompileErrorM m, MergeableM m) =>@@ -206,8 +206,8 @@     reconcile [_] = return ()     reconcile []  = compileErrorM $ "No matches for main category " ++ show n ++ " ($TestsOnly$ sources excluded)"     reconcile ds  =-      flip reviseError ("Multiple matches for main category " ++ show n) $-        mergeAllM $ map (\d -> compileError $ "Defined at " ++ formatFullContext (dcContext d)) ds+      flip reviseErrorM ("Multiple matches for main category " ++ show n) $+        mergeAllM $ map (\d -> compileErrorM $ "Defined at " ++ formatFullContext (dcContext d)) ds  compileCategoryDeclaration :: (Show c, CompileErrorM m, MergeableM m) =>   CategoryMap c -> [Namespace] -> AnyCategory c -> m CxxOutput@@ -265,7 +265,7 @@   CategoryMap c -> CategoryName -> m CxxOutput compileConcreteTemplate ta n = do   (_,t) <- getConcreteCategory ta ([],n)-  compileConcreteDefinition ta Map.empty [] Nothing (defined t) `reviseError` ("In generated template for " ++ show n) where+  compileConcreteDefinition ta Map.empty [] Nothing (defined t) `reviseErrorM` ("In generated template for " ++ show n) where     defined t = DefinedCategory {         dcContext = [],         dcName = getCategoryName t,@@ -356,7 +356,7 @@       [DefinedMember c] -> m ()     disallowTypeMembers tm =       mergeAllM $ flip map tm-        (\m -> compileError $ "Member " ++ show (dmName m) +++        (\m -> compileErrorM $ "Member " ++ show (dmName m) ++                               " is not allowed to be @type-scoped" ++                               formatFullContextBrace (dmContext m))     createParams = mergeAllM $ map createParam pi@@ -408,11 +408,11 @@       return $ onlyCode $ valueName n ++ "(" ++ allArgs ++ ") : " ++ allInit ++ " {}"     unwrappedArg i m = writeStoredVariable (dmType m) (UnwrappedSingle $ "args.At(" ++ show i ++ ")")     createMember r filters m = do-      validateGeneralInstance r filters (vtType $ dmType m) `reviseError`+      validateGeneralInstance r filters (vtType $ dmType m) `reviseErrorM`         ("In creation of " ++ show (dmName m) ++ " at " ++ formatFullContext (dmContext m))       return $ onlyCode $ variableStoredType (dmType m) ++ " " ++ variableName (dmName m) ++ ";"     createMemberLazy r filters m = do-      validateGeneralInstance r filters (vtType $ dmType m) `reviseError`+      validateGeneralInstance r filters (vtType $ dmType m) `reviseErrorM`         ("In creation of " ++ show (dmName m) ++ " at " ++ formatFullContext (dmContext m))       return $ onlyCode $ variableLazyType (dmType m) ++ " " ++ variableName (dmName m) ++ ";"     initMember (DefinedMember _ _ _ _ Nothing) = return mergeDefault@@ -664,6 +664,7 @@   where     ps' = map expandLocalType $ pValues ps expandLocalType (SingleType (JustParamName p)) = paramName p+expandLocalType _ = undefined  -- The instance is an InferredType.  defineCategoryName :: CategoryName -> CompiledData [String] defineCategoryName t = onlyCode $ "std::string CategoryName() const final { return \"" ++ show t ++ "\"; }"@@ -771,7 +772,7 @@  createMainFile :: (Show c, CompileErrorM m, MergeableM m) =>   CategoryMap c -> ExprMap c -> CategoryName -> FunctionName -> m (Namespace,[String])-createMainFile tm em n f = flip reviseError ("In the creation of the main binary procedure") $ do+createMainFile tm em n f = flip reviseErrorM ("In the creation of the main binary procedure") $ do   ca <- fmap indentCompiled (compileMainProcedure tm em expr)   let file = createMainCommon "main" ca   (_,t) <- getConcreteCategory tm ([],n)@@ -782,7 +783,7 @@  createTestFile :: (Show c, CompileErrorM m, MergeableM m) =>   CategoryMap c -> ExprMap c  -> Expression c -> m ([CategoryName],[String])-createTestFile tm em e = flip reviseError ("In the creation of the test binary procedure") $ do+createTestFile tm em e = flip reviseErrorM ("In the creation of the test binary procedure") $ do   ca@(CompiledData req _) <- fmap indentCompiled (compileMainProcedure tm em e)   let file = createMainCommon "test" ca   return (Set.toList req,file)
src/CompilerCxx/Procedure.hs view
@@ -37,6 +37,7 @@ import Control.Monad.Trans.State (execStateT,get,put,runStateT) import Control.Monad.Trans (lift) import Data.List (intercalate)+import qualified Data.Map as Map import qualified Data.Set as Set  import Base.CompileError@@ -151,7 +152,7 @@       where         checkCondition (Positional [t]) | t == boolRequiredValue = return ()         checkCondition (Positional ts) =-          compileError $ "Conditionals must have exactly one Bool return but found {" +++          compileErrorM $ "Conditionals must have exactly one Bool return but found {" ++                          intercalate "," (map show ts) ++ "}"  -- Returns the state so that returns can be properly checked for if/elif/else.@@ -192,7 +193,7 @@       autoPositionalCleanup e     -- Multi-expression => must all be singles.     getReturn rs = do-      lift $ mergeAllM (map checkArity $ zip ([0..] :: [Int]) $ map (fst . snd) rs) `reviseError`+      lift $ mergeAllM (map checkArity $ zip ([0..] :: [Int]) $ map (fst . snd) rs) `reviseErrorM`         ("In return at " ++ formatFullContext c)       csRegisterReturn c $ Just $ Positional $ map (head . pValues . fst . snd) rs       let e = OpaqueMulti $ "ReturnTuple(" ++ intercalate "," (map (useAsUnwrapped . snd . snd) rs) ++ ")"@@ -200,30 +201,30 @@       autoPositionalCleanup e     checkArity (_,Positional [_]) = return ()     checkArity (i,Positional ts)  =-      compileError $ "Return position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1"+      compileErrorM $ "Return position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1" compileStatement (LoopBreak c) = do   loop <- csGetLoop   case loop of        NotInLoop ->-         lift $ compileError $ "Using break outside of while is no allowed" ++ formatFullContextBrace c+         lift $ compileErrorM $ "Using break outside of while is no allowed" ++ formatFullContextBrace c        _ -> return ()   csWrite ["break;"] compileStatement (LoopContinue c) = do   loop <- csGetLoop   case loop of        NotInLoop ->-         lift $ compileError $ "Using continue outside of while is no allowed" ++ formatFullContextBrace c+         lift $ compileErrorM $ "Using continue outside of while is no allowed" ++ formatFullContextBrace c        _ -> return ()   csWrite $ ["{"] ++ lsUpdate loop ++ ["}","continue;"] compileStatement (FailCall c e) = do   csRequiresTypes (Set.fromList [BuiltinFormatted,BuiltinString])   e' <- compileExpression e   when (length (pValues $ fst e') /= 1) $-    lift $ compileError $ "Expected single return in argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected single return in argument" ++ formatFullContextBrace c   let (Positional [t0],e0) = e'   r <- csResolver   fa <- csAllFilters-  lift $ (checkValueTypeMatch r fa t0 formattedRequiredValue) `reviseError`+  lift $ (checkValueTypeMatch_ r fa t0 formattedRequiredValue) `reviseErrorM`     ("In fail call at " ++ formatFullContext c)   csSetNoReturn   maybeSetTrace c@@ -258,16 +259,16 @@     createVariable r fa (CreateVariable c2 t1 n) t2 = do       -- TODO: Call csRequiresTypes for t1. (Maybe needs a helper function.)       lift $ mergeAllM [validateGeneralInstance r fa (vtType t1),-                        checkValueTypeMatch r fa t2 t1] `reviseError`+                        checkValueTypeMatch_ r fa t2 t1] `reviseErrorM`         ("In creation of " ++ show n ++ " at " ++ formatFullContext c2)       csAddVariable c2 n (VariableValue c2 LocalScope t1 True)       csWrite [variableStoredType t1 ++ " " ++ variableName n ++ ";"]     createVariable r fa (ExistingVariable (InputValue c2 n)) t2 = do       (VariableValue _ _ t1 w) <- csGetVariable c2 n-      when (not w) $ lift $ compileError $ "Cannot assign to read-only variable " +++      when (not w) $ lift $ compileErrorM $ "Cannot assign to read-only variable " ++                                            show n ++ formatFullContextBrace c2       -- TODO: Also show original context.-      lift $ (checkValueTypeMatch r fa t2 t1) `reviseError`+      lift $ (checkValueTypeMatch_ r fa t2 t1) `reviseErrorM`         ("In assignment to " ++ show n ++ " at " ++ formatFullContext c2)       csUpdateAssigned n     createVariable _ _ _ _ = return ()@@ -296,11 +297,11 @@ compileLazyInit (DefinedMember c _ t1 n (Just e)) = do   (ts,e') <- compileExpression e   when (length (pValues ts) /= 1) $-    lift $ compileError $ "Expected single return in initializer" ++ formatFullContextBrace (getExpressionContext e)+    lift $ compileErrorM $ "Expected single return in initializer" ++ formatFullContextBrace (getExpressionContext e)   r <- csResolver   fa <- csAllFilters   let Positional [t2] = ts-  lift $ (checkValueTypeMatch r fa t2 t1) `reviseError`+  lift $ (checkValueTypeMatch_ r fa t2 t1) `reviseErrorM`     ("In initialization of " ++ show n ++ " at " ++ formatFullContext c)   csWrite [variableName n ++ "([this]() { return " ++ writeStoredVariable t1 e' ++ "; })"] @@ -418,7 +419,7 @@   csInheritReturns [ctxCl]   where     createVariable r fa (c,t,n) = do-      lift $ validateGeneralInstance r fa (vtType t) `reviseError`+      lift $ validateGeneralInstance r fa (vtType t) `reviseErrorM`         ("In creation of " ++ show n ++ " at " ++ formatFullContext c)       csWrite [variableStoredType t ++ " " ++ variableName n ++ ";"]     showVariable (c,t,n) = do@@ -457,15 +458,15 @@     return (Positional [charRequiredValue],UnboxedPrimitive PrimChar $ "PrimChar('" ++ escapeChar l ++ "')")   compile (Literal (IntegerLiteral c True l)) = do     csRequiresTypes (Set.fromList [BuiltinInt])-    when (l > 2^(64 :: Integer) - 1) $ lift $ compileError $+    when (l > 2^(64 :: Integer) - 1) $ lift $ compileErrorM $       "Literal " ++ show l ++ formatFullContextBrace c ++ " is greater than the max value for 64-bit unsigned"     let l' = if l > 2^(63 :: Integer) - 1 then l - 2^(64 :: Integer) else l     return (Positional [intRequiredValue],UnboxedPrimitive PrimInt $ "PrimInt(" ++ show l' ++ ")")   compile (Literal (IntegerLiteral c False l)) = do     csRequiresTypes (Set.fromList [BuiltinInt])-    when (l > 2^(63 :: Integer) - 1) $ lift $ compileError $+    when (l > 2^(63 :: Integer) - 1) $ lift $ compileErrorM $       "Literal " ++ show l ++ formatFullContextBrace c ++ " is greater than the max value for 64-bit signed"-    when ((-l) > (2^(63 :: Integer) - 2)) $ lift $ compileError $+    when ((-l) > (2^(63 :: Integer) - 2)) $ lift $ compileErrorM $       "Literal " ++ show l ++ formatFullContextBrace c ++ " is less than the min value for 64-bit signed"     return (Positional [intRequiredValue],UnboxedPrimitive PrimInt $ "PrimInt(" ++ show l ++ ")")   compile (Literal (DecimalLiteral _ l e)) = do@@ -503,11 +504,11 @@         | o == "!" = doNot t e2         | o == "-" = doNeg t e2         | o == "~" = doComp t e2-        | otherwise = lift $ compileError $ "Unknown unary operator \"" ++ o ++ "\" " +++        | otherwise = lift $ compileErrorM $ "Unknown unary operator \"" ++ o ++ "\" " ++                                             formatFullContextBrace c       doNot t e2 = do         when (t /= boolRequiredValue) $-          lift $ compileError $ "Cannot use " ++ show t ++ " with unary ! operator" +++          lift $ compileErrorM $ "Cannot use " ++ show t ++ " with unary ! operator" ++                                 formatFullContextBrace c         return $ (Positional [boolRequiredValue],UnboxedPrimitive PrimBool $ "!" ++ useAsUnboxed PrimBool e2)       doNeg t e2@@ -515,12 +516,12 @@                                             UnboxedPrimitive PrimInt $ "-" ++ useAsUnboxed PrimInt e2)         | t == floatRequiredValue = return $ (Positional [floatRequiredValue],                                              UnboxedPrimitive PrimFloat $ "-" ++ useAsUnboxed PrimFloat e2)-        | otherwise = lift $ compileError $ "Cannot use " ++ show t ++ " with unary - operator" +++        | otherwise = lift $ compileErrorM $ "Cannot use " ++ show t ++ " with unary - operator" ++                                             formatFullContextBrace c       doComp t e2         | t == intRequiredValue = return $ (Positional [intRequiredValue],                                             UnboxedPrimitive PrimInt $ "~" ++ useAsUnboxed PrimInt e2)-        | otherwise = lift $ compileError $ "Cannot use " ++ show t ++ " with unary ~ operator" +++        | otherwise = lift $ compileErrorM $ "Cannot use " ++ show t ++ " with unary ~ operator" ++                                             formatFullContextBrace c   compile (InitializeValue c t ps es) = do     es' <- sequence $ map compileExpression $ pValues es@@ -542,13 +543,13 @@       getValues [(Positional ts,e)] = return (ts,useAsArgs e)       -- Multi-expression => must all be singles.       getValues rs = do-        lift $ mergeAllM (map checkArity $ zip ([0..] :: [Int]) $ map fst rs) `reviseError`+        lift $ mergeAllM (map checkArity $ zip ([0..] :: [Int]) $ map fst rs) `reviseErrorM`           ("In return at " ++ formatFullContext c)         return (map (head . pValues . fst) rs,                 "ArgTuple(" ++ intercalate ", " (map (useAsUnwrapped . snd) rs) ++ ")")       checkArity (_,Positional [_]) = return ()       checkArity (i,Positional ts)  =-        compileError $ "Initializer position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1"+        compileErrorM $ "Initializer position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1"   compile (InfixExpression c e1 (FunctionOperator _ (FunctionSpec _ (CategoryFunction c2 cn) fn ps)) e2) =     compile (Expression c (CategoryCall c2 cn (FunctionCall c fn ps (Positional [e1,e2]))) [])   compile (InfixExpression c e1 (FunctionOperator _ (FunctionSpec _ (TypeFunction c2 tn) fn ps)) e2) =@@ -583,7 +584,7 @@     where       bind t1 t2         | t1 /= t2 =-          lift $ compileError $ "Cannot " ++ show o ++ " " ++ show t1 ++ " and " +++          lift $ compileErrorM $ "Cannot " ++ show o ++ " " ++ show t1 ++ " and " ++                                 show t2 ++ formatFullContextBrace c         | o `Set.member` comparison && t1 == intRequiredValue = do           return (Positional [boolRequiredValue],glueInfix PrimInt PrimBool e1 o e2)@@ -614,7 +615,7 @@         | o `Set.member` equals && t1 == boolRequiredValue = do           return (Positional [boolRequiredValue],glueInfix PrimBool PrimBool e1 o e2)         | otherwise =-          lift $ compileError $ "Cannot " ++ show o ++ " " ++ show t1 ++ " and " +++          lift $ compileErrorM $ "Cannot " ++ show o ++ " " ++ show t1 ++ " and " ++                                 show t2 ++ formatFullContextBrace c       glueInfix t1 t2 e3 o2 e4 =         UnboxedPrimitive t2 $ useAsUnboxed t1 e3 ++ o2 ++ useAsUnboxed t1 e4@@ -624,7 +625,7 @@     r <- csResolver     fa <- csAllFilters     let vt = ValueType RequiredValue $ SingleType $ JustTypeInstance t-    lift $ (checkValueTypeMatch r fa t' vt) `reviseError`+    lift $ (checkValueTypeMatch_ r fa t' vt) `reviseErrorM`       ("In converted call at " ++ formatFullContext c)     f' <- lookupValueFunction vt f     compileFunctionCall (Just $ useAsUnwrapped e') f' f@@ -635,17 +636,17 @@     compileFunctionCall (Just $ useAsUnwrapped e') f' f   requireSingle _ [t] = return t   requireSingle c2 ts =-    lift $ compileError $ "Function call requires 1 return but found but found {" +++    lift $ compileErrorM $ "Function call requires 1 return but found but found {" ++                           intercalate "," (map show ts) ++ "}" ++ formatFullContextBrace c2  lookupValueFunction :: (Show c, CompileErrorM m, MergeableM m,                         CompilerContext c m [String] a) =>   ValueType -> FunctionCall c -> CompilerState a m (ScopedFunction c) lookupValueFunction (ValueType WeakValue t) (FunctionCall c _ _ _) =-  lift $ compileError $ "Use strong to convert " ++ show t +++  lift $ compileErrorM $ "Use strong to convert " ++ show t ++                         " to optional first" ++ formatFullContextBrace c lookupValueFunction (ValueType OptionalValue t) (FunctionCall c _ _ _) =-  lift $ compileError $ "Use require to convert " ++ show t +++  lift $ compileErrorM $ "Use require to convert " ++ show t ++                         " to required first" ++ formatFullContextBrace c lookupValueFunction (ValueType RequiredValue t) (FunctionCall c n _ _) =   csGetTypeFunction c (Just t) n@@ -670,9 +671,9 @@ compileExpressionStart (TypeCall c t f@(FunctionCall _ n _ _)) = do   r <- csResolver   fa <- csAllFilters-  lift $ validateGeneralInstance r fa (SingleType t) `reviseError` ("In function call at " ++ formatFullContext c)+  lift $ validateGeneralInstance r fa (SingleType t) `reviseErrorM` ("In function call at " ++ formatFullContext c)   f' <- csGetTypeFunction c (Just $ SingleType t) n-  when (sfScope f' /= TypeScope) $ lift $ compileError $ "Function " ++ show n +++  when (sfScope f' /= TypeScope) $ lift $ compileErrorM $ "Function " ++ show n ++                                           " cannot be used as a type function" ++                                           formatFullContextBrace c   csRequiresTypes $ Set.unions $ map categoriesFromTypes [SingleType t]@@ -689,39 +690,39 @@     tryNonCategory ctx = do       f' <- ccGetTypeFunction ctx c Nothing n       s <- ccCurrentScope ctx-      when (sfScope f' > s) $ compileError $+      when (sfScope f' > s) $ compileErrorM $         "Function " ++ show n ++ " is not in scope here" ++ formatFullContextBrace c       return f' -- TODO: Compile BuiltinCall like regular functions, for consistent validation. compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinPresent ps es)) = do   csRequiresTypes (Set.fromList [BuiltinBool])   when (length (pValues ps) /= 0) $-    lift $ compileError $ "Expected 0 type parameters" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c   when (length (pValues es) /= 1) $-    lift $ compileError $ "Expected 1 argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 1 argument" ++ formatFullContextBrace c   es' <- sequence $ map compileExpression $ pValues es   when (length (pValues $ fst $ head es') /= 1) $-    lift $ compileError $ "Expected single return in argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected single return in argument" ++ formatFullContextBrace c   let (Positional [t0],e) = head es'   when (isWeakValue t0) $-    lift $ compileError $ "Weak values not allowed here" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Weak values not allowed here" ++ formatFullContextBrace c   return $ (Positional [boolRequiredValue],             UnboxedPrimitive PrimBool $ valueBase ++ "::Present(" ++ useAsUnwrapped e ++ ")") compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinReduce ps es)) = do   when (length (pValues ps) /= 2) $-    lift $ compileError $ "Expected 2 type parameters" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 2 type parameters" ++ formatFullContextBrace c   when (length (pValues es) /= 1) $-    lift $ compileError $ "Expected 1 argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 1 argument" ++ formatFullContextBrace c   es' <- sequence $ map compileExpression $ pValues es   when (length (pValues $ fst $ head es') /= 1) $-    lift $ compileError $ "Expected single return in argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected single return in argument" ++ formatFullContextBrace c   let (Positional [t0],e) = head es'-  let (Positional [t1,t2]) = ps+  [t1,t2] <- lift $ disallowInferred ps   r <- csResolver   fa <- csAllFilters   lift $ validateGeneralInstance r fa t1   lift $ validateGeneralInstance r fa t2-  lift $ (checkValueTypeMatch r fa t0 (ValueType OptionalValue t1)) `reviseError`+  lift $ (checkValueTypeMatch_ r fa t0 (ValueType OptionalValue t1)) `reviseErrorM`     ("In argument to reduce call at " ++ formatFullContext c)   -- TODO: If t1 -> t2 then just return e without a Reduce call.   t1' <- expandGeneralInstance t1@@ -732,25 +733,25 @@             UnwrappedSingle $ typeBase ++ "::Reduce(" ++ t1' ++ ", " ++ t2' ++ ", " ++ useAsUnwrapped e ++ ")") compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinRequire ps es)) = do   when (length (pValues ps) /= 0) $-    lift $ compileError $ "Expected 0 type parameters" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c   when (length (pValues es) /= 1) $-    lift $ compileError $ "Expected 1 argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 1 argument" ++ formatFullContextBrace c   es' <- sequence $ map compileExpression $ pValues es   when (length (pValues $ fst $ head es') /= 1) $-    lift $ compileError $ "Expected single return in argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected single return in argument" ++ formatFullContextBrace c   let (Positional [t0],e) = head es'   when (isWeakValue t0) $-    lift $ compileError $ "Weak values not allowed here" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Weak values not allowed here" ++ formatFullContextBrace c   return $ (Positional [ValueType RequiredValue (vtType t0)],             UnwrappedSingle $ valueBase ++ "::Require(" ++ useAsUnwrapped e ++ ")") compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinStrong ps es)) = do   when (length (pValues ps) /= 0) $-    lift $ compileError $ "Expected 0 type parameters" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 0 type parameters" ++ formatFullContextBrace c   when (length (pValues es) /= 1) $-    lift $ compileError $ "Expected 1 argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 1 argument" ++ formatFullContextBrace c   es' <- sequence $ map compileExpression $ pValues es   when (length (pValues $ fst $ head es') /= 1) $-    lift $ compileError $ "Expected single return in argument" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected single return in argument" ++ formatFullContextBrace c   let (Positional [t0],e) = head es'   let t1 = Positional [ValueType OptionalValue (vtType t0)]   if isWeakValue t0@@ -759,27 +760,27 @@      else return (t1,e) compileExpressionStart (BuiltinCall c (FunctionCall _ BuiltinTypename ps es)) = do   when (length (pValues ps) /= 1) $-    lift $ compileError $ "Expected 1 type parameter" ++ formatFullContextBrace c+    lift $ compileErrorM $ "Expected 1 type parameter" ++ formatFullContextBrace c   when (length (pValues es) /= 0) $-    lift $ compileError $ "Expected 0 arguments" ++ formatFullContextBrace c-  let t = head $ pValues ps+    lift $ compileErrorM $ "Expected 0 arguments" ++ formatFullContextBrace c+  [t] <- lift $ disallowInferred ps   r <- csResolver   fa <- csAllFilters   lift $ validateGeneralInstance r fa t   t' <- expandGeneralInstance t-  csRequiresTypes $ Set.unions $ map categoriesFromTypes $ pValues ps+  csRequiresTypes $ Set.unions $ map categoriesFromTypes [t]   return $ (Positional [formattedRequiredValue],             valueAsWrapped $ UnboxedPrimitive PrimString $ typeBase ++ "::TypeName(" ++ t' ++ ")") compileExpressionStart (BuiltinCall _ _) = undefined compileExpressionStart (ParensExpression _ e) = compileExpression e compileExpressionStart (InlineAssignment c n e) = do   (VariableValue _ s t0 w) <- csGetVariable c n-  when (not w) $ lift $ compileError $ "Cannot assign to read-only variable " +++  when (not w) $ lift $ compileErrorM $ "Cannot assign to read-only variable " ++                                         show n ++ formatFullContextBrace c   (Positional [t],e') <- compileExpression e -- TODO: Get rid of the Positional matching here.   r <- csResolver   fa <- csAllFilters-  lift $ (checkValueTypeMatch r fa t t0) `reviseError`+  lift $ (checkValueTypeMatch_ r fa t t0) `reviseErrorM`     ("In assignment at " ++ formatFullContext c)   csUpdateAssigned n   scoped <- autoScope s@@ -787,31 +788,35 @@   return (Positional [t0],readStoredVariable lazy t0 $ "(" ++ scoped ++ variableName n ++                                                      " = " ++ writeStoredVariable t0 e' ++ ")") +disallowInferred :: (Show c, CompileErrorM m) => Positional (InstanceOrInferred c) -> m [GeneralInstance]+disallowInferred = mapErrorsM disallow . pValues where+  disallow (AssignedInstance _ t) = return t+  disallow (InferredInstance c) =+    compileErrorM $ "Type inference is not allowed in reduce calls" ++ formatFullContextBrace c+ compileFunctionCall :: (Show c, CompileErrorM m, MergeableM m,                         CompilerContext c m [String] a) =>   Maybe String -> ScopedFunction c -> FunctionCall c ->   CompilerState a m (ExpressionType,ExprValue)-compileFunctionCall e f (FunctionCall c _ ps es) = do+compileFunctionCall e f (FunctionCall c _ ps es) = flip reviseErrorStateT errorContext $ do   r <- csResolver   fa <- csAllFilters-  f' <- lift $ parsedToFunctionType f `reviseError`-          ("In function call at " ++ formatFullContext c)-  f'' <- lift $ assignFunctionParams r fa ps f' `reviseError`-          ("In function call at " ++ formatFullContext c)   es' <- sequence $ map compileExpression $ pValues es   (ts,es'') <- getValues es'+  ps2 <- lift $ guessParamsFromArgs r fa f ps (Positional ts)+  f' <- lift $ parsedToFunctionType f+  f'' <- lift $ assignFunctionParams r fa ps2 f'   -- Called an extra time so arg count mismatches have reasonable errors.-  lift $ processPairs_ (\_ _ -> return ()) (ftArgs f'') (Positional ts) `reviseError`-    ("In function call at " ++ formatFullContext c)-  lift $ processPairs_ (checkArg r fa) (ftArgs f'') (Positional $ zip ([0..] :: [Int]) ts) `reviseError`-    ("In function call at " ++ formatFullContext c)-  csRequiresTypes $ Set.unions $ map categoriesFromTypes $ pValues ps+  lift $ processPairs_ (\_ _ -> return ()) (ftArgs f'') (Positional ts)+  lift $ processPairs_ (checkArg r fa) (ftArgs f'') (Positional $ zip ([0..] :: [Int]) ts)+  csRequiresTypes $ Set.unions $ map categoriesFromTypes $ pValues ps2   csRequiresTypes (Set.fromList [sfType f])-  params <- expandParams2 ps+  params <- expandParams2 ps2   scoped <- autoScope (sfScope f)   call <- assemble e scoped (sfScope f) params es''   return $ (ftReturns f'',OpaqueMulti call)   where+    errorContext = "In call to " ++ show (sfName f) ++ " at " ++ formatFullContext c     assemble Nothing _ ValueScope ps2 es2 =       return $ callName (sfName f) ++ "(Var_self, " ++ ps2 ++ ", " ++ es2 ++ ")"     assemble Nothing scoped _ ps2 es2 =@@ -825,15 +830,33 @@     getValues [(Positional ts,e2)] = return (ts,useAsArgs e2)     -- Multi-expression => must all be singles.     getValues rs = do-      lift $ mergeAllM (map checkArity $ zip ([0..] :: [Int]) $ map fst rs) `reviseError`+      lift $ mergeAllM (map checkArity $ zip ([0..] :: [Int]) $ map fst rs) `reviseErrorM`         ("In return at " ++ formatFullContext c)       return (map (head . pValues . fst) rs, "ArgTuple(" ++ intercalate ", " (map (useAsUnwrapped . snd) rs) ++ ")")     checkArity (_,Positional [_]) = return ()     checkArity (i,Positional ts)  =-      compileError $ "Return position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1"+      compileErrorM $ "Return position " ++ show i ++ " has " ++ show (length ts) ++ " values but should have 1"     checkArg r fa t0 (i,t1) = do-      checkValueTypeMatch r fa t1 t0 `reviseError` ("In argument " ++ show i ++ " to " ++ show (sfName f))+      checkValueTypeMatch r fa t1 t0 `reviseErrorM` ("In argument " ++ show i ++ " to " ++ show (sfName f)) +guessParamsFromArgs :: (Show c, MergeableM m, CompileErrorM m, TypeResolver r) =>+  r -> ParamFilters -> ScopedFunction c -> Positional (InstanceOrInferred c) ->+  Positional ValueType -> m (Positional GeneralInstance)+guessParamsFromArgs r fa f ps ts = do+  let fa2 = fa `Map.union` getFunctionFilterMap f+  args <- processPairs alwaysPair ts (fmap pvType $ sfArgs f)+  pa <- fmap Map.fromList $ processPairs toInstance (fmap vpParam $ sfParams f) ps+  let pa2 = pa `Map.union` (Map.fromList $ zip (Map.keys fa2) (map (SingleType . JustParamName) $ Map.keys fa2))+  pa3 <- inferParamTypes r fa2 pa2 args+  fmap Positional $ mapErrorsM (subPosition pa3) (pValues $ sfParams f) where+    subPosition pa2 p =+      case (vpParam p) `Map.lookup` pa2 of+           Just t  -> return t+           Nothing -> compileErrorM $ "Something went wrong inferring " +++                      show (vpParam p) ++ formatFullContextBrace (vpContext p)+    toInstance p1 (AssignedInstance _ t) = return (p1,t)+    toInstance p1 (InferredInstance _)   = return (p1,SingleType $ JustInferredType p1)+ compileMainProcedure :: (Show c, CompileErrorM m, MergeableM m) =>   CategoryMap c -> ExprMap c -> Expression c -> m (CompiledData [String]) compileMainProcedure tm em e = do@@ -868,13 +891,13 @@ categoriesFromDefine :: DefinesInstance -> Set.Set CategoryName categoriesFromDefine (DefinesInstance t ps) = t `Set.insert` (Set.unions $ map categoriesFromTypes $ pValues ps) -expandParams :: (CompilerContext c m s a) =>+expandParams :: (CompileErrorM m, CompilerContext c m s a) =>   Positional GeneralInstance -> CompilerState a m String expandParams ps = do   ps' <- sequence $ map expandGeneralInstance $ pValues ps   return $ "T_get(" ++ intercalate "," (map ("&" ++) ps') ++ ")" -expandParams2 :: (CompilerContext c m s a) =>+expandParams2 :: (CompileErrorM m, CompilerContext c m s a) =>   Positional GeneralInstance -> CompilerState a m String expandParams2 ps = do   ps' <- sequence $ map expandGeneralInstance $ pValues ps@@ -884,7 +907,7 @@   CategoryName -> CompilerState a m String expandCategory t = return $ categoryGetter t ++ "()" -expandGeneralInstance :: (CompilerContext c m s a) =>+expandGeneralInstance :: (CompileErrorM m, CompilerContext c m s a) =>   GeneralInstance -> CompilerState a m String expandGeneralInstance (TypeMerge MergeUnion     []) = return $ allGetter ++ "()" expandGeneralInstance (TypeMerge MergeIntersect []) = return $ anyGetter ++ "()"@@ -901,6 +924,7 @@   s <- csGetParamScope p   scoped <- autoScope s   return $ scoped ++ paramName p+expandGeneralInstance t = lift $ compileErrorM $ "Type " ++ show t ++ " contains unresolved types"  doImplicitReturn :: (Show c,CompilerContext c m [String] a) => [c] -> CompilerState a m () doImplicitReturn c = do
src/Config/LoadConfig.hs view
@@ -19,83 +19,39 @@ {-# LANGUAGE Safe #-}  module Config.LoadConfig (-  Backend(..),-  LocalConfig(..),-  Resolver(..),-  compilerVersion,   localConfigPath,   loadConfig,-  rootPath, ) where -import Config.Paths-import Config.Programs- import Control.Monad (when)-import Data.Hashable (hash)-import Data.List (intercalate,isPrefixOf,isSuffixOf)-import Data.Maybe (isJust)-import Data.Version (showVersion,versionBranch)-import GHC.IO.Handle-import Numeric (showHex)+import Control.Monad.IO.Class import System.Directory-import System.Exit-import System.FilePath-import System.IO-import System.Posix.Process (ProcessStatus(..),executeFile,forkProcess,getProcessStatus)-import System.Posix.Temp (mkstemps) -import Paths_zeolite_lang (getDataFileName,version)+import Base.CompileError+import Config.LocalConfig +import Paths_zeolite_lang (getDataFileName) -loadConfig :: IO (Backend,Resolver)++loadConfig :: (MonadIO m, CompileErrorM m) => m (Resolver,Backend) loadConfig = do-  configFile <- localConfigPath-  isFile <- doesFileExist configFile-  when (not isFile) $ do-    hPutStrLn stderr "Zeolite has not been configured. Please run zeolite-setup."-    exitFailure-  configString <- readFile configFile+  configFile <- liftIO localConfigPath+  isFile <- liftIO $ doesFileExist configFile+  when (not isFile) $ compileErrorM "Zeolite has not been configured. Please run zeolite-setup."+  configString <- liftIO $ readFile configFile   lc <- check $ (reads configString :: [(LocalConfig,String)])-  pathsFile <- globalPathsPath-  pathsExists <- doesFileExist pathsFile+  pathsFile   <- liftIO $ globalPathsPath+  pathsExists <- liftIO $ doesFileExist pathsFile   paths <- if pathsExists-              then readFile pathsFile >>= return . lines+              then liftIO $ readFile pathsFile >>= return . lines               else return []-  return (lcBackend lc,addPaths (lcResolver lc) paths) where-    check [(cm,"")] = return cm+  return (addPaths (lcResolver lc) paths,lcBackend lc) where+    check [(cm,"")]   = return cm     check [(cm,"\n")] = return cm-    check _ = do-      hPutStrLn stderr "Zeolite configuration is corrupt. Please rerun zeolite-setup."-      exitFailure--rootPath :: IO FilePath-rootPath = getDataFileName ""--compilerVersion :: String-compilerVersion = showVersion version--data Backend =-  UnixBackend {-    ucCxxBinary :: FilePath,-    ucCxxOptions :: [String],-    ucArBinary :: FilePath-  }-  deriving (Read,Show)--data Resolver =-  SimpleResolver {-    srVisibleSystem :: [FilePath],-    srExtraPaths :: [FilePath]-  }-  deriving (Read,Show)+    check _ = compileErrorM "Zeolite configuration is corrupt. Please rerun zeolite-setup." -data LocalConfig =-  LocalConfig {-    lcBackend :: Backend,-    lcResolver :: Resolver-  }-  deriving (Read,Show)+localConfigPath :: IO FilePath+localConfigPath = getDataFileName localConfigFilename >>= canonicalizePath  localConfigFilename :: FilePath localConfigFilename = ".local-config"@@ -103,114 +59,8 @@ globalPathsFilename :: FilePath globalPathsFilename = "global-paths" -localConfigPath :: IO FilePath-localConfigPath = getDataFileName localConfigFilename >>= canonicalizePath- globalPathsPath :: IO FilePath globalPathsPath = getDataFileName globalPathsFilename >>= canonicalizePath  addPaths :: Resolver -> [FilePath] -> Resolver addPaths (SimpleResolver ls ps) ps2 = SimpleResolver ls (ps ++ ps2)--instance CompilerBackend Backend where-  runCxxCommand (UnixBackend cb co ab) (CompileToObject s p nm ns ps e) = do-    objName <- canonicalizePath $ p </> (takeFileName $ dropExtension s ++ ".o")-    executeProcess cb $ co ++ otherOptions ++ ["-c", s, "-o", objName]-    if e-      then do-        -- Extra files are put into .a since they will be unconditionally-        -- included. This prevents unwanted symbol dependencies.-        arName  <- canonicalizePath $ p </> (takeFileName $ dropExtension s ++ ".a")-        executeProcess ab ["-q",arName,objName]-        return arName-      else return objName where-      otherOptions = map (("-I" ++) . normalise) ps ++ nsFlag-      nsFlag-        | null ns = []-        | otherwise = ["-D" ++ nm ++ "=" ++ ns]-  runCxxCommand (UnixBackend cb co _) (CompileToBinary m ss o ps lf) = do-    let arFiles    = filter (isSuffixOf ".a")       ss-    let otherFiles = filter (not . isSuffixOf ".a") ss-    executeProcess cb $ co ++ otherOptions ++ m:otherFiles ++ arFiles ++ ["-o", o]-    return o where-      otherOptions = lf ++ map ("-I" ++) (map normalise ps)-  runTestCommand _ (TestCommand b p) = do-    (outF,outH) <- mkstemps "/tmp/ztest_" ".txt"-    (errF,errH) <- mkstemps "/tmp/ztest_" ".txt"-    pid <- forkProcess (execWithCapture outH errH)-    hClose outH-    hClose errH-    status <- getProcessStatus True True pid-    out <- readFile outF-    removeFile outF-    err <- readFile errF-    removeFile errF-    let success = case status of-                       Just (Exited ExitSuccess) -> True-                       _ -> False-    return $ TestCommandResult success (lines out) (lines err) where-      execWithCapture h1 h2 = do-        when (not $ null p) $ setCurrentDirectory p-        hDuplicateTo h1 stdout-        hDuplicateTo h2 stderr-        executeFile b True [] Nothing-  getCompilerHash b = VersionHash $ flip showHex "" $ abs $ hash $ minorVersion ++ show b where-    minorVersion = show $ take 3 $ versionBranch version--executeProcess :: String -> [String] -> IO ()-executeProcess c os = do-  hPutStrLn stderr $ "Executing: " ++ intercalate " " (c:os)-  pid <- forkProcess $ executeFile c True os Nothing-  status <- getProcessStatus True True pid-  case status of-       Just (Exited ExitSuccess) -> return ()-       _ -> exitFailure--instance PathResolver Resolver where-  resolveModule r p m = do-    ps2 <- potentialSystemPaths r m-    firstExisting m $ [p</>m] ++ ps2-  isSystemModule r p m = do-    isDir <- doesDirectoryExist (p</>m)-    if isDir-       then return False-       else do-         ps2 <- potentialSystemPaths r m-         findModule ps2 >>= return . not . isJust-  resolveBaseModule _ = do-    let m = "base"-    m0 <- getDataFileName m-    firstExisting m [m0]-  isBaseModule r f = do-    b <- resolveBaseModule r-    return (f == b)--potentialSystemPaths :: Resolver -> FilePath -> IO [FilePath]-potentialSystemPaths (SimpleResolver ls ps) m = do-  let allowGlobal = not (".." `elem` components)-  m0 <- if allowGlobal && any (\l -> isPrefixOf (l ++ "/") m) ls-           then getDataFileName m >>= return . (:[])-           else return []-  let m2 = if allowGlobal-              then map (</> m) ps-              else []-  return $ m0 ++ m2 where-    components = map stripSlash $ splitPath m-    stripSlash = reverse . dropWhile (== '/') . reverse--firstExisting :: FilePath -> [FilePath] -> IO FilePath-firstExisting m ps = do-  p <- findModule ps-  case p of-       Nothing -> do-         hPutStrLn stderr $ "Could not find path " ++ m-         exitFailure-       Just p2 -> return p2--findModule :: [FilePath] -> IO (Maybe FilePath)-findModule [] = return Nothing-findModule (p:ps) = do-  isDir <- doesDirectoryExist p-  if isDir-     then fmap Just $ canonicalizePath p-     else findModule ps
+ src/Config/LocalConfig.hs view
@@ -0,0 +1,180 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE Safe #-}++module Config.LocalConfig (+  Backend(..),+  LocalConfig(..),+  Resolver(..),+  rootPath,+  compilerVersion,+) where++import Control.Monad (when)+import Control.Monad.IO.Class+import Data.Hashable (hash)+import Data.List (intercalate,isPrefixOf,isSuffixOf)+import Data.Maybe (isJust)+import Data.Version (showVersion,versionBranch)+import GHC.IO.Handle+import Numeric (showHex)+import System.Directory+import System.Exit+import System.FilePath+import System.IO+import System.Posix.Process (ProcessStatus(..),executeFile,forkProcess,getProcessStatus)+import System.Posix.Temp (mkstemps)++import Base.CompileError+import Cli.Paths+import Cli.Programs++import Paths_zeolite_lang (getDataFileName,version)+++data Backend =+  UnixBackend {+    ucCxxBinary :: FilePath,+    ucCxxOptions :: [String],+    ucArBinary :: FilePath+  }+  deriving (Read,Show)++data Resolver =+  SimpleResolver {+    srVisibleSystem :: [FilePath],+    srExtraPaths :: [FilePath]+  }+  deriving (Read,Show)++data LocalConfig =+  LocalConfig {+    lcBackend :: Backend,+    lcResolver :: Resolver+  }+  deriving (Read,Show)++rootPath :: IO FilePath+rootPath = getDataFileName ""++compilerVersion :: String+compilerVersion = showVersion version++instance CompilerBackend Backend where+  runCxxCommand (UnixBackend cb co ab) (CompileToObject s p nm ns ps e) = do+    objName <- errorFromIO $ canonicalizePath $ p </> (takeFileName $ dropExtension s ++ ".o")+    executeProcess cb $ co ++ otherOptions ++ ["-c", s, "-o", objName]+    if e+      then do+        -- Extra files are put into .a since they will be unconditionally+        -- included. This prevents unwanted symbol dependencies.+        arName  <- errorFromIO $ canonicalizePath $ p </> (takeFileName $ dropExtension s ++ ".a")+        executeProcess ab ["-q",arName,objName]+        return arName+      else return objName where+      otherOptions = map (("-I" ++) . normalise) ps ++ nsFlag+      nsFlag+        | null ns = []+        | otherwise = ["-D" ++ nm ++ "=" ++ ns]+  runCxxCommand (UnixBackend cb co _) (CompileToBinary m ss o ps lf) = do+    let arFiles    = filter (isSuffixOf ".a")       ss+    let otherFiles = filter (not . isSuffixOf ".a") ss+    executeProcess cb $ co ++ otherOptions ++ m:otherFiles ++ arFiles ++ ["-o", o]+    return o where+      otherOptions = lf ++ map ("-I" ++) (map normalise ps)+  runTestCommand _ (TestCommand b p) = errorFromIO $ do+    (outF,outH) <- mkstemps "/tmp/ztest_" ".txt"+    (errF,errH) <- mkstemps "/tmp/ztest_" ".txt"+    pid <- forkProcess (execWithCapture outH errH)+    hClose outH+    hClose errH+    status <- getProcessStatus True True pid+    out <- readFile outF+    removeFile outF+    err <- readFile errF+    removeFile errF+    let success = case status of+                       Just (Exited ExitSuccess) -> True+                       _ -> False+    return $ TestCommandResult success (lines out) (lines err) where+      execWithCapture h1 h2 = do+        when (not $ null p) $ setCurrentDirectory p+        hDuplicateTo h1 stdout+        hDuplicateTo h2 stderr+        executeFile b True [] Nothing+  getCompilerHash b = VersionHash $ flip showHex "" $ abs $ hash $ minorVersion ++ show b where+    minorVersion = show $ take 3 $ versionBranch version++executeProcess :: (MonadIO m, CompileErrorM m) => String -> [String] -> m ()+executeProcess c os = do+  errorFromIO $ hPutStrLn stderr $ "Executing: " ++ intercalate " " (c:os)+  pid    <- errorFromIO $ forkProcess $ executeFile c True os Nothing+  status <- errorFromIO $ getProcessStatus True True pid+  case status of+       Just (Exited ExitSuccess) -> return ()+       _ -> do+         errorFromIO $ hPutStrLn stderr $ "Execution of " ++ c ++ " failed"+         compileErrorM $ "Execution of " ++ c ++ " failed"++instance PathIOHandler Resolver where+  resolveModule r p m = do+    ps2 <- errorFromIO $ potentialSystemPaths r m+    firstExisting m $ [p</>m] ++ ps2+  isSystemModule r p m = do+    isDir <- errorFromIO $ doesDirectoryExist (p</>m)+    if isDir+       then return False+       else do+         ps2 <- errorFromIO $ potentialSystemPaths r m+         errorFromIO (findModule ps2) >>= return . not . isJust+  resolveBaseModule _ = do+    let m = "base"+    m0 <- errorFromIO $ getDataFileName m+    firstExisting m [m0]+  isBaseModule r f = do+    b <- resolveBaseModule r+    return (f == b)++potentialSystemPaths :: Resolver -> FilePath -> IO [FilePath]+potentialSystemPaths (SimpleResolver ls ps) m = do+  let allowGlobal = not (".." `elem` components)+  m0 <- if allowGlobal && any (\l -> isPrefixOf (l ++ "/") m) ls+           then getDataFileName m >>= return . (:[])+           else return []+  let m2 = if allowGlobal+              then map (</> m) ps+              else []+  return $ m0 ++ m2 where+    components = map stripSlash $ splitPath m+    stripSlash = reverse . dropWhile (== '/') . reverse++firstExisting :: (MonadIO m, CompileErrorM m) => FilePath -> [FilePath] -> m FilePath+firstExisting m ps = do+  p <- errorFromIO $ findModule ps+  case p of+       Nothing -> compileErrorM $ "Could not find path " ++ m+       Just p2 -> return p2++findModule :: [FilePath] -> IO (Maybe FilePath)+findModule [] = return Nothing+findModule (p:ps) = do+  isDir <- doesDirectoryExist p+  if isDir+     then fmap Just $ canonicalizePath p+     else findModule ps
− src/Config/Paths.hs
@@ -1,30 +0,0 @@-{- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at--    http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ -}---- Author: Kevin P. Barry [ta0kira@gmail.com]--{-# LANGUAGE Safe #-}--module Config.Paths (-  PathResolver(..),-) where---class PathResolver r where-  resolveModule :: r -> FilePath -> FilePath -> IO FilePath-  isSystemModule :: r -> FilePath -> FilePath -> IO Bool-  resolveBaseModule :: r -> IO FilePath-  isBaseModule :: r -> FilePath -> IO Bool
− src/Config/Programs.hs
@@ -1,71 +0,0 @@-{- ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry--Licensed under the Apache License, Version 2.0 (the "License");-you may not use this file except in compliance with the License.-You may obtain a copy of the License at--    http://www.apache.org/licenses/LICENSE-2.0--Unless required by applicable law or agreed to in writing, software-distributed under the License is distributed on an "AS IS" BASIS,-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.-See the License for the specific language governing permissions and-limitations under the License.------------------------------------------------------------------------------ -}---- Author: Kevin P. Barry [ta0kira@gmail.com]--{-# LANGUAGE Safe #-}--module Config.Programs (-  CompilerBackend(..),-  CxxCommand(..),-  TestCommand(..),-  TestCommandResult(..),-  VersionHash(..),-) where---class CompilerBackend b where-  runCxxCommand :: b -> CxxCommand -> IO String-  runTestCommand :: b -> TestCommand -> IO TestCommandResult-  getCompilerHash :: b -> VersionHash--newtype VersionHash = VersionHash String deriving (Eq)--instance Show VersionHash where-  show (VersionHash h) = h--data CxxCommand =-  CompileToObject {-    ctoSource :: String,-    ctoPath :: String,-    ctoNamespaceMacro :: String,-    ctoNamespace :: String,-    ctoPaths :: [String],-    ctoExtra :: Bool-  } |-  CompileToBinary {-    ctbMain :: String,-    ctbSources :: [String],-    ctbOutput :: String,-    ctbPaths :: [String],-    ctbLinkFlags :: [String]-  }-  deriving (Show)--data TestCommand =-  TestCommand {-    tcBinary :: String,-    tcPath :: String-  }-  deriving (Show)--data TestCommandResult =-  TestCommandResult {-    tcrSuccess :: Bool,-    tcrOutput :: [String],-    tcrError :: [String]-  }-  deriving (Show)
src/Parser/Common.hs view
@@ -28,6 +28,7 @@   char_,   endOfDoc,   escapeStart,+  inferredParam,   infixFuncEnd,   infixFuncStart,   keyword,@@ -379,6 +380,9 @@  pragmaArgsEnd :: Parser () pragmaArgsEnd = string_ "]"++inferredParam :: Parser ()+inferredParam = string_ "?"  operator :: String -> Parser String operator o = labeled o $ do
src/Parser/Procedure.hs view
@@ -31,8 +31,8 @@ import Parser.Pragma import Parser.TypeCategory () import Parser.TypeInstance ()-import Types.Pragma import Types.Positional+import Types.Pragma import Types.Procedure import Types.TypeCategory import Types.TypeInstance@@ -388,6 +388,17 @@                           (sepAfter $ string_ ">")                           (sepBy sourceParser (sepAfter $ string_ ",")) <|> return []       return $ FunctionSpec [c] UnqualifiedFunction n (Positional ps)++instance ParseFromSource (InstanceOrInferred SourcePos) where+  sourceParser = assigned <|> inferred where+    assigned = do+      c <- getPosition+      t <- sourceParser+      return $ AssignedInstance [c] t+    inferred = do+      c <- getPosition+      sepAfter_ inferredParam+      return $ InferredInstance [c]  parseFunctionCall :: SourcePos -> FunctionName -> Parser (FunctionCall SourcePos) parseFunctionCall c n = do
src/Parser/SourceFile.hs view
@@ -43,7 +43,7 @@   (FilePath,String) -> m ([Pragma SourcePos],[AnyCategory SourcePos],[DefinedCategory SourcePos]) parseInternalSource (f,s) = unwrap parsed where   parsed = parse (between optionalSpace endOfDoc withPragmas) f s-  unwrap (Left e)  = compileError (show e)+  unwrap (Left e)  = compileErrorM (show e)   unwrap (Right t) = return t   withPragmas = do     pragmas <- parsePragmas internalSourcePragmas@@ -54,7 +54,7 @@ parsePublicSource :: CompileErrorM m => (FilePath,String) -> m ([Pragma SourcePos],[AnyCategory SourcePos]) parsePublicSource (f,s) = unwrap parsed where   parsed = parse (between optionalSpace endOfDoc withPragmas) f s-  unwrap (Left e)  = compileError (show e)+  unwrap (Left e)  = compileErrorM (show e)   unwrap (Right t) = return t   withPragmas = do     pragmas <- parsePragmas publicSourcePragmas@@ -65,7 +65,7 @@ parseTestSource :: CompileErrorM m => (FilePath,String) -> m ([Pragma SourcePos],[IntegrationTest SourcePos]) parseTestSource (f,s) = unwrap parsed where   parsed = parse (between optionalSpace endOfDoc withPragmas) f s-  unwrap (Left e)  = compileError (show e)+  unwrap (Left e)  = compileErrorM (show e)   unwrap (Right t) = return t   withPragmas = do     pragmas <- parsePragmas testSourcePragmas
src/Test/Common.hs view
@@ -52,7 +52,7 @@  import Base.CompileError import Base.Mergeable-import Compilation.CompileInfo+import Base.CompileInfo import Parser.Common import Parser.TypeInstance () import Types.TypeInstance@@ -77,36 +77,35 @@   force (Right x) = x   force _         = undefined -readSingle :: (ParseFromSource a, CompileErrorM m) => String -> String -> m a+readSingle :: ParseFromSource a => String -> String -> CompileInfo a readSingle = readSingleWith (optionalSpace >> sourceParser) -readSingleWith :: CompileErrorM m => Parser a -> String -> String -> m a+readSingleWith :: Parser a -> String -> String -> CompileInfo a readSingleWith p f s =   unwrap $ parse (between nullParse endOfDoc p) f s   where-    unwrap (Left e)  = compileError (show e)+    unwrap (Left e)  = compileErrorM (show e)     unwrap (Right t) = return t -readMulti :: CompileErrorM m => ParseFromSource a => String -> String -> m [a]+readMulti :: ParseFromSource a => String -> String -> CompileInfo [a] readMulti f s =   unwrap $ parse (between optionalSpace endOfDoc (sepBy sourceParser optionalSpace)) f s   where-    unwrap (Left e)  = compileError (show e)+    unwrap (Left e)  = compileErrorM (show e)     unwrap (Right t) = return t -parseFilterMap :: CompileErrorM m => [(String,[String])] -> m ParamFilters+parseFilterMap :: [(String,[String])] -> CompileInfo ParamFilters parseFilterMap pa = do-  pa2 <- collectAllOrErrorM $ map parseFilters pa+  pa2 <- mapErrorsM parseFilters pa   return $ Map.fromList pa2   where     parseFilters (n,fs) = do-      fs2 <- collectAllOrErrorM $ map (readSingle "(string)") fs+      fs2 <- mapErrorsM (readSingle "(string)") fs       return (ParamName n,fs2) -parseTheTest :: (ParseFromSource a, CompileErrorM m) =>-  [(String,[String])] -> [String] -> m ([a],ParamFilters)+parseTheTest :: ParseFromSource a => [(String,[String])] -> [String] -> CompileInfo ([a],ParamFilters) parseTheTest pa xs = do-  ts <- collectAllOrErrorM $ map (readSingle "(string)") xs+  ts <- mapErrorsM (readSingle "(string)") xs   pa2 <- parseFilterMap pa   return (ts,pa2) @@ -114,17 +113,15 @@ showParams pa = "[" ++ intercalate "," (concat $ map expand pa) ++ "]" where   expand (n,ps) = map (\p -> n ++ " " ++ p) ps -checkTypeSuccess :: (TypeResolver r) =>-  r -> [(String,[String])] -> String -> CompileInfo ()+checkTypeSuccess :: TypeResolver r => r -> [(String,[String])] -> String -> CompileInfo () checkTypeSuccess r pa x = do   ([t],pa2) <- parseTheTest pa [x]   check $ validateGeneralInstance r pa2 t   where     prefix = x ++ " " ++ showParams pa-    check = flip reviseError (prefix ++ ":")+    check = flip reviseErrorM (prefix ++ ":") -checkTypeFail :: (TypeResolver r) =>-  r -> [(String,[String])] -> String -> CompileInfo ()+checkTypeFail :: TypeResolver r => r -> [(String,[String])] -> String -> CompileInfo () checkTypeFail r pa x = do   ([t],pa2) <- parseTheTest pa [x]   check $ validateGeneralInstance r pa2 t@@ -133,19 +130,17 @@     check :: CompileInfo a -> CompileInfo ()     check c       | isCompileError c = return ()-      | otherwise = compileError $ prefix ++ ": Expected failure\n"+      | otherwise = compileErrorM $ prefix ++ ": Expected failure\n" -checkDefinesSuccess :: (TypeResolver r) =>-  r -> [(String,[String])] -> String -> CompileInfo ()+checkDefinesSuccess :: TypeResolver r => r -> [(String,[String])] -> String -> CompileInfo () checkDefinesSuccess r pa x = do   ([t],pa2) <- parseTheTest pa [x]   check $ validateDefinesInstance r pa2 t   where     prefix = x ++ " " ++ showParams pa-    check = flip reviseError (prefix ++ ":")+    check = flip reviseErrorM (prefix ++ ":") -checkDefinesFail :: (TypeResolver r) =>-  r -> [(String,[String])] -> String -> CompileInfo ()+checkDefinesFail :: TypeResolver r => r -> [(String,[String])] -> String -> CompileInfo () checkDefinesFail r pa x = do   ([t],pa2) <- parseTheTest pa [x]   check $ validateDefinesInstance r pa2 t@@ -154,51 +149,46 @@     check :: CompileInfo a -> CompileInfo ()     check c       | isCompileError c = return ()-      | otherwise = compileError $ prefix ++ ": Expected failure\n"+      | otherwise = compileErrorM $ prefix ++ ": Expected failure\n" -containsExactly :: (Ord a, Show a, MergeableM m, CompileErrorM m) =>-  [a] -> [a] -> m ()+containsExactly :: (Ord a, Show a) => [a] -> [a] -> CompileInfo () containsExactly actual expected = do   containsNoDuplicates actual   containsAtLeast actual expected   containsAtMost actual expected -containsNoDuplicates :: (Ord a, Show a, MergeableM m, CompileErrorM m) =>-  [a] -> m ()+containsNoDuplicates :: (Ord a, Show a) => [a] -> CompileInfo () containsNoDuplicates expected =-  (mergeAllM $ map checkSingle $ group $ sort expected) `reviseError` (show expected)+  (mergeAllM $ map checkSingle $ group $ sort expected) `reviseErrorM` (show expected)   where     checkSingle xa@(x:_:_) =-      compileError $ "Item " ++ show x ++ " occurs " ++ show (length xa) ++ " times"+      compileErrorM $ "Item " ++ show x ++ " occurs " ++ show (length xa) ++ " times"     checkSingle _ = return () -containsAtLeast :: (Ord a, Show a, MergeableM m, CompileErrorM m) =>-  [a] -> [a] -> m ()+containsAtLeast :: (Ord a, Show a) => [a] -> [a] -> CompileInfo () containsAtLeast actual expected =-  (mergeAllM $ map (checkInActual $ Set.fromList actual) expected) `reviseError`+  (mergeAllM $ map (checkInActual $ Set.fromList actual) expected) `reviseErrorM`         (show actual ++ " (actual) vs. " ++ show expected ++ " (expected)")   where     checkInActual va v =       if v `Set.member` va          then return ()-         else compileError $ "Item " ++ show v ++ " was expected but not present"+         else compileErrorM $ "Item " ++ show v ++ " was expected but not present" -containsAtMost :: (Ord a, Show a, MergeableM m, CompileErrorM m) =>-  [a] -> [a] -> m ()+containsAtMost :: (Ord a, Show a) => [a] -> [a] -> CompileInfo () containsAtMost actual expected =-  (mergeAllM $ map (checkInExpected $ Set.fromList expected) actual) `reviseError`+  (mergeAllM $ map (checkInExpected $ Set.fromList expected) actual) `reviseErrorM`         (show actual ++ " (actual) vs. " ++ show expected ++ " (expected)")   where     checkInExpected va v =       if v `Set.member` va          then return ()-         else compileError $ "Item " ++ show v ++ " is unexpected"+         else compileErrorM $ "Item " ++ show v ++ " is unexpected" -checkEquals :: (Eq a, Show a, MergeableM m, CompileErrorM m) =>-  a -> a -> m ()+checkEquals :: (Eq a, Show a) => a -> a -> CompileInfo () checkEquals actual expected   | actual == expected = return ()-  | otherwise = compileError $ "Expected " ++ show expected ++ " but got " ++ show actual+  | otherwise = compileErrorM $ "Expected " ++ show expected ++ " but got " ++ show actual  loadFile :: String -> IO String loadFile f = readFile ("src" </> "Test" </> f)
+ src/Test/CompileInfo.hs view
@@ -0,0 +1,89 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE Safe #-}++module Test.CompileInfo (tests) where++import Base.CompileError+import Base.Mergeable+import Base.CompileInfo+++tests :: [IO (CompileInfo ())]+tests = [+    checkSuccess 'a' (return 'a'),+    checkError "error\n" (compileErrorM "error" :: CompileInfoIO Char),++    checkSuccess ['a','b']          (collectAllOrErrorM [return 'a',return 'b']),+    checkSuccess []                 (collectAllOrErrorM [] :: CompileInfoIO [Char]),+    checkError   "error1\nerror2\n" (collectAllOrErrorM [compileErrorM "error1",return 'b',compileErrorM "error2"]),++    checkSuccess 'a' (collectOneOrErrorM [return 'a',return 'b']),+    checkError   ""  (collectOneOrErrorM [] :: CompileInfoIO Char),+    checkSuccess 'b' (collectOneOrErrorM [compileErrorM "error1",return 'b',compileErrorM "error2"]),++    checkSuccess ['a','b','c']      (mergeAllM [return ['a'],return ['b','c']]),+    checkSuccess []                 (mergeAllM [] :: CompileInfoIO [Char]),+    checkError   "error1\nerror2\n" (mergeAllM [compileErrorM "error1",return ['b'],compileErrorM "error2"]),++    checkSuccess ['a','b'] (mergeAnyM [return ['a'],return ['b']]),+    checkError   ""        (mergeAnyM [] :: CompileInfoIO [Char]),+    checkSuccess ['b']     (mergeAnyM [compileErrorM "error1",return ['b'],compileErrorM "error2"]),++    checkSuccessAndWarnings ["warning1","warning2"] ()+      (compileWarningM "warning1" >> return () >> compileWarningM "warning2"),+    checkErrorAndWarnings ["warning1"] "error\n"+      (compileWarningM "warning1" >> compileErrorM "error" >> compileWarningM "warning2" :: CompileInfoIO ()),++    checkSuccess ['a','b']  (sequence [return 'a',return 'b']),+    checkSuccess []         (sequence [] :: CompileInfoIO [Char]),+    checkError   "error1\n" (sequence [compileErrorM "error1",return 'b',compileErrorM "error2"])+  ]++checkSuccess :: (Eq a, Show a) => a -> CompileInfoIO a -> IO (CompileInfo ())+checkSuccess x y = do+  y' <- toCompileInfo y+  if isCompileError y' || getCompileSuccess y' == x+     then return $ y' >> return ()+     else return $ compileErrorM $ "Expected value " ++ show x ++ " but got value " ++ show (getCompileSuccess y')++checkError :: (Eq a, Show a) => String -> CompileInfoIO a -> IO (CompileInfo ())+checkError e y = do+  y' <- toCompileInfo y+  if not (isCompileError y')+     then return $ compileErrorM $ "Expected error \"" ++ e ++ "\" but got value " ++ show (getCompileSuccess y')+     else if show (getCompileError y') == e+          then return $ return ()+          else return $ compileErrorM $ "Expected error \"" ++ e ++ "\" but got error \"" ++ show (getCompileError y') ++ "\""++checkSuccessAndWarnings :: (Eq a, Show a) => [String] -> a -> CompileInfoIO a -> IO (CompileInfo ())+checkSuccessAndWarnings w x y = do+  y' <- toCompileInfo y+  outcome <- checkSuccess x y+  if getCompileWarnings y' == w+     then return $ outcome >> return ()+     else return $ compileErrorM $ "Expected warnings " ++ show w ++ " but got warnings " ++ show (getCompileWarnings y')++checkErrorAndWarnings :: (Eq a, Show a) => [String] -> String -> CompileInfoIO a -> IO (CompileInfo ())+checkErrorAndWarnings w e y = do+  y' <- toCompileInfo y+  outcome <- checkError e y+  if getCompileWarnings y' == w+     then return $ outcome >> return ()+     else return $ compileErrorM $ "Expected warnings " ++ show w ++ " but got warnings " ++ show (getCompileWarnings y')
src/Test/DefinedCategory.hs view
@@ -24,7 +24,7 @@ import Text.Parsec  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Parser.DefinedCategory () import Test.Common import Types.DefinedCategory@@ -45,7 +45,7 @@   return $ check parsed   where   check c-    | isCompileError c = compileError $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)+    | isCompileError c = compileErrorM $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)     | otherwise = return ()  checkParseFail :: String -> IO (CompileInfo ())@@ -56,5 +56,5 @@   where   check c     | isCompileError c = return ()-    | otherwise = compileError $ "Parse " ++ f ++ ": Expected failure but got\n" +++    | otherwise = compileErrorM $ "Parse " ++ f ++ ": Expected failure but got\n" ++                                  show (getCompileSuccess c) ++ "\n"
src/Test/IntegrationTest.hs view
@@ -25,7 +25,7 @@ import Text.Parsec  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Parser.Common import Parser.IntegrationTest () import Test.Common@@ -43,7 +43,7 @@       ("testfiles" </> "basic_error_test.0rt")       (\t -> return $ do         let h = itHeader t-        when (not $ isExpectCompileError $ ithResult h) $ compileError "Expected ExpectCompileError"+        when (not $ isExpectCompileError $ ithResult h) $ compileErrorM "Expected ExpectCompileError"         checkEquals (ithTestName h) "basic error test"         containsExactly (getRequirePattern $ ithResult h) [             OutputPattern OutputCompiler "pattern in output 1",@@ -61,7 +61,7 @@       ("testfiles" </> "basic_crash_test.0rt")       (\t -> return $ do         let h = itHeader t-        when (not $ isExpectRuntimeError $ ithResult h) $ compileError "Expected ExpectRuntimeError"+        when (not $ isExpectRuntimeError $ ithResult h) $ compileErrorM "Expected ExpectRuntimeError"         checkEquals (ithTestName h) "basic crash test"         let match = case ereExpression $ ithResult h of                          (Expression _@@ -69,7 +69,7 @@                              (JustTypeInstance (TypeInstance (CategoryName "Test") (Positional [])))                              (FunctionCall _ (FunctionName "execute") (Positional []) (Positional []))) []) -> True                          _ -> False-        when (not match) $ compileError "Expected test expression \"Test$execute()\""+        when (not match) $ compileErrorM "Expected test expression \"Test$execute()\""         containsExactly (getRequirePattern $ ithResult h) [             OutputPattern OutputAny "pattern in output 1",             OutputPattern OutputAny "pattern in output 2"@@ -86,7 +86,7 @@       ("testfiles" </> "basic_success_test.0rt")       (\t -> return $ do         let h = itHeader t-        when (not $ isExpectRuntimeSuccess $ ithResult h) $ compileError "Expected ExpectRuntimeSuccess"+        when (not $ isExpectRuntimeSuccess $ ithResult h) $ compileErrorM "Expected ExpectRuntimeSuccess"         checkEquals (ithTestName h) "basic success test"         let match = case ersExpression $ ithResult h of                          (Expression _@@ -94,7 +94,7 @@                              (JustTypeInstance (TypeInstance (CategoryName "Test") (Positional [])))                              (FunctionCall _ (FunctionName "execute") (Positional []) (Positional []))) []) -> True                          _ -> False-        when (not match) $ compileError "Expected test expression \"Test$execute()\""+        when (not match) $ compileErrorM "Expected test expression \"Test$execute()\""         containsExactly (getRequirePattern $ ithResult h) [             OutputPattern OutputAny "pattern in output 1",             OutputPattern OutputAny "pattern in output 2"@@ -114,8 +114,8 @@   s <- loadFile f   unwrap $ parse (between optionalSpace endOfDoc sourceParser) f s   where-    unwrap (Left e)  = return $ compileError (show e)-    unwrap (Right t) = fmap (flip reviseError ("Check " ++ f ++ ":")) $ o t+    unwrap (Left e)  = return $ compileErrorM (show e)+    unwrap (Right t) = fmap (flip reviseErrorM ("Check " ++ f ++ ":")) $ o t  extractCategoryNames :: IntegrationTest c -> [String] extractCategoryNames = map (show . getCategoryName) . itCategory
+ src/Test/MergeTree.hs view
@@ -0,0 +1,103 @@+{- -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- -}++-- Author: Kevin P. Barry [ta0kira@gmail.com]++{-# LANGUAGE Safe #-}++module Test.MergeTree (tests) where++import Control.Monad (when)++import Base.CompileError+import Base.CompileInfo+import Base.MergeTree+import Base.Mergeable+++tests :: [IO (CompileInfo ())]+tests = [+   checkMatch (mergeAny $ fmap mergeLeaf [2,4,6]) (fmap (*2))+              (mergeAny $ map mergeLeaf [1..3] :: MergeTree Int),+   checkMatch (mergeAll $ fmap mergeLeaf [2,4,6]) (fmap (*2))+              (mergeAll $ map mergeLeaf [1..3] :: MergeTree Int),++   checkMatch (mergeLeaf 1) id (mergeAny [mergeLeaf 1,mergeAny []] :: MergeTree Int),+   checkMatch (mergeLeaf 1) id (mergeAll [mergeLeaf 1,mergeAll []] :: MergeTree Int),++   checkMatch ([1,2]) (foldr (:) [])+              (mergeAny [mergeLeaf 1,mergeAll [mergeLeaf 2]] :: MergeTree Int),+   checkMatch ([1,2]) (foldr (:) [])+              (mergeAll [mergeLeaf 1,mergeAny [mergeLeaf 2]] :: MergeTree Int),++   checkSuccess (mergeAny $ fmap mergeLeaf [1,2,3]) (sequence . fmap return)+                (mergeAny $ map mergeLeaf [1..3] :: MergeTree Int),+   checkSuccess (mergeAll $ fmap mergeLeaf [1,2,3]) (sequence . fmap return)+                (mergeAll $ map mergeLeaf [1..3] :: MergeTree Int),++   checkError "1 is odd\n" (sequence . fmap oddError)+              (mergeAny $ map mergeLeaf [1..3] :: MergeTree Int),+   checkError "1 is odd\n" (sequence . fmap oddError)+              (mergeAll $ map mergeLeaf [1..3] :: MergeTree Int),+   checkSuccess (mergeAny $ map mergeLeaf [1..3]) (sequence . fmap return)+                (mergeAny $ map mergeLeaf [1..3] :: MergeTree Int),+   checkSuccess (mergeAll $ map mergeLeaf [1..3]) (sequence . fmap return)+                (mergeAll $ map mergeLeaf [1..3] :: MergeTree Int),++   checkSuccess (mergeAny $ map mergeLeaf [2,4]) (pruneMergeTree . fmap oddError)+                (mergeAny $ map mergeLeaf [1..4] :: MergeTree Int),+   checkError "1 is odd\n3 is odd\n" (pruneMergeTree . fmap oddError)+              (mergeAll $ map mergeLeaf [1..4] :: MergeTree Int),+   checkSuccess (mergeAny $ map mergeLeaf [1..4]) (pruneMergeTree . fmap return)+                (mergeAny $ map mergeLeaf [1..4] :: MergeTree Int),+   checkSuccess (mergeAll $ map mergeLeaf [1..4]) (pruneMergeTree . fmap return)+                (mergeAll $ map mergeLeaf [1..4] :: MergeTree Int),++   checkSuccess [2,4]+                (reduceMergeTree return (\xs -> compileErrorM $ "mergeAll " ++ show xs) oddError2)+                (mergeAny $ map mergeLeaf [1..4] :: MergeTree Int),+   checkError "1 is odd\n3 is odd\n"+              (reduceMergeTree (\xs -> compileErrorM $ "mergeAny " ++ show xs) return oddError2)+              (mergeAll $ map mergeLeaf [1..4] :: MergeTree Int)+ ]++oddError :: Int -> CompileInfo Int+oddError x = do+  when (x `mod` 2 == 1) $ compileErrorM $ show x ++ " is odd"+  return x++oddError2 :: Int -> CompileInfo [Int]+oddError2 = fmap (:[]) . oddError++checkMatch :: (Eq b, Show b) => b -> (a -> b) -> a -> IO (CompileInfo ())+checkMatch x f y = let y' = f y in+  return $ if x /= y'+              then compileErrorM $ "Expected " ++ show x ++ " but got " ++ show y'+              else return ()++checkSuccess :: (Eq b, Show b) => b -> (a -> CompileInfo b) -> a -> IO (CompileInfo ())+checkSuccess x f y = let y' = f y in+  return $ if isCompileError y' || getCompileSuccess y' == x+              then y' >> return ()+              else compileErrorM $ "Expected value " ++ show x ++ " but got value " ++ show (getCompileSuccess y')++checkError :: Show b => String -> (a -> CompileInfo b) -> a -> IO (CompileInfo ())+checkError e f y = let y' = f y in+  return $ if not (isCompileError y')+              then compileErrorM $ "Expected error \"" ++ e ++ "\" but got value " ++ show (getCompileSuccess y')+              else if show (getCompileError y') == e+                      then return ()+                      else compileErrorM $ "Expected error \"" ++ e ++ "\" but got error \"" ++ show (getCompileError y') ++ "\""
src/Test/ParseMetadata.hs view
@@ -22,11 +22,11 @@ import Text.Regex.TDFA -- Not safe!  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Cli.CompileMetadata import Cli.CompileOptions import Cli.ParseMetadata-import Config.Programs (VersionHash(..))+import Cli.Programs (VersionHash(..)) import System.FilePath import Test.Common import Types.Positional@@ -335,9 +335,9 @@ checkWriteThenRead :: (Eq a, Show a, ConfigFormat a) => a -> IO (CompileInfo ()) checkWriteThenRead m = return $ do   text <- fmap spamComments $ autoWriteConfig m-  m' <- autoReadConfig "(string)" text `reviseError` ("Serialized >>>\n\n" ++ text ++ "\n<<< Serialized\n\n")+  m' <- autoReadConfig "(string)" text `reviseErrorM` ("Serialized >>>\n\n" ++ text ++ "\n<<< Serialized\n\n")   when (m' /= m) $-    compileError $ "Failed to match after write/read\n" +++    compileErrorM $ "Failed to match after write/read\n" ++                    "Before:\n" ++ show m ++ "\n" ++                    "After:\n" ++ show m' ++ "\n" ++                    "Intermediate:\n" ++ text where@@ -352,9 +352,9 @@       | isCompileError c = do           let text = show (getCompileError c)           when (not $ text =~ p) $-            compileError $ "Expected pattern " ++ show p ++ " in error output but got\n" ++ text+            compileErrorM $ "Expected pattern " ++ show p ++ " in error output but got\n" ++ text       | otherwise =-          compileError $ "Expected write failure but got\n" ++ getCompileSuccess c+          compileErrorM $ "Expected write failure but got\n" ++ getCompileSuccess c  checkParsesAs :: (Show a, ConfigFormat a) => String -> (a -> Bool) -> IO (CompileInfo ()) checkParsesAs f m = do@@ -363,8 +363,8 @@   return $ check parsed contents   where     check x contents = do-      x' <- x `reviseError` ("While parsing " ++ f)+      x' <- x `reviseErrorM` ("While parsing " ++ f)       when (not $ m x') $-        compileError $ "Failed to match after write/read\n" +++        compileErrorM $ "Failed to match after write/read\n" ++                        "Unparsed:\n" ++ contents ++ "\n" ++                        "Parsed:\n" ++ show x' ++ "\n"
src/Test/Parser.hs view
@@ -23,7 +23,7 @@ import Control.Monad (when)  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Parser.Common import Test.Common import Text.Parsec.String@@ -63,10 +63,10 @@   check parsed   e <- parsed   when (e /= m) $-    compileError $ show s ++ " does not parse as " ++ show m ++ ":\n" ++ show e+    compileErrorM $ show s ++ " does not parse as " ++ show m ++ ":\n" ++ show e   where     check c-      | isCompileError c = compileError $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)       | otherwise = return ()  checkParseFail :: Show a => Parser a -> [Char] -> IO (CompileInfo ())@@ -76,5 +76,5 @@   where     check c       | isCompileError c = return ()-      | otherwise = compileError $ "Parse '" ++ s ++ "': Expected failure but got\n" +++      | otherwise = compileErrorM $ "Parse '" ++ s ++ "': Expected failure but got\n" ++                                    show (getCompileSuccess c) ++ "\n"
src/Test/Pragma.hs view
@@ -24,7 +24,7 @@ import Text.Regex.TDFA -- Not safe!  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Parser.Pragma import Test.Common import Types.Pragma@@ -99,10 +99,10 @@   check parsed   e <- parsed   when (not $ m e) $-    compileError $ "No match in '" ++ s ++ "':\n" ++ show e+    compileErrorM $ "No match in '" ++ s ++ "':\n" ++ show e   where     check c-      | isCompileError c = compileError $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)       | otherwise = return ()  checkParseError :: String -> String -> Parser (Pragma SourcePos) -> IO (CompileInfo ())@@ -114,6 +114,6 @@       | isCompileError c = do           let text = show (getCompileError c)           when (not $ text =~ m) $-            compileError $ "Expected pattern " ++ show m ++ " in error output but got\n" ++ text+            compileErrorM $ "Expected pattern " ++ show m ++ " in error output but got\n" ++ text       | otherwise =-          compileError $ "Expected write failure but got\n" ++ show (getCompileSuccess c)+          compileErrorM $ "Expected write failure but got\n" ++ show (getCompileSuccess c)
src/Test/Procedure.hs view
@@ -25,7 +25,7 @@ import Text.Parsec  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Parser.Procedure () import Test.Common import Types.Positional@@ -411,7 +411,7 @@   return $ check parsed   where     check c-      | isCompileError c = compileError $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)       | otherwise = return ()  checkParseFail :: String -> IO (CompileInfo ())@@ -422,7 +422,7 @@   where     check c       | isCompileError c = return ()-      | otherwise = compileError $ "Parse " ++ f ++ ": Expected failure but got\n" +++      | otherwise = compileErrorM $ "Parse " ++ f ++ ": Expected failure but got\n" ++                                    show (getCompileSuccess c) ++ "\n"  checkShortParseSuccess :: String -> IO (CompileInfo ())@@ -431,7 +431,7 @@   return $ check parsed   where     check c-      | isCompileError c = compileError $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)       | otherwise = return ()  checkShortParseFail :: String -> IO (CompileInfo ())@@ -441,7 +441,7 @@   where     check c       | isCompileError c = return ()-      | otherwise = compileError $ "Parse '" ++ s ++ "': Expected failure but got\n" +++      | otherwise = compileErrorM $ "Parse '" ++ s ++ "': Expected failure but got\n" ++                                    show (getCompileSuccess c) ++ "\n"  checkParsesAs :: String -> (Expression SourcePos -> Bool) -> IO (CompileInfo ())@@ -450,8 +450,8 @@   check parsed   e <- parsed   when (not $ m e) $-    compileError $ "No match in '" ++ s ++ "':\n" ++ show e+    compileErrorM $ "No match in '" ++ s ++ "':\n" ++ show e   where     check c-      | isCompileError c = compileError $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)       | otherwise = return ()
src/Test/SourceFile.hs view
@@ -23,7 +23,7 @@ import System.FilePath  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo import Parser.SourceFile import Test.Common @@ -42,5 +42,5 @@   return $ check parsed   where     check c-      | isCompileError c = compileError $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)       | otherwise = return ()
src/Test/TypeCategory.hs view
@@ -27,10 +27,11 @@  import Base.CompileError import Base.Mergeable-import Compilation.CompileInfo+import Base.CompileInfo import Parser.TypeCategory () import Test.Common import Types.Builtin+import Types.GeneralType import Types.Positional import Types.TypeCategory import Types.TypeInstance@@ -120,7 +121,7 @@       (\ts -> do         ts2 <- topoSortCategories defaultCategories ts         map (show . getCategoryName) ts2 `containsPaired` [-            "Type","Object2","Object3","Object1","Parent","Child"+            "Object2","Object3","Object1","Type","Parent","Child"           ]),     checkOperationSuccess       ("testfiles" </> "flatten.0rx")@@ -791,20 +792,189 @@       ("testfiles" </> "resolved_in_preserved.0rx")       (\ts -> do         ts2 <- topoSortCategories defaultCategories ts-        flattenAllConnections defaultCategories ts2 >> return ())+        flattenAllConnections defaultCategories ts2 >> return ()),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Type1","#x")]+          [("#x","Type1",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Type2","#x"),("Type1","#x")]+          [("#x","Type1",Covariant)]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface1<Type2>","#x"),("Interface1<Type1>","#x")]+          [("#x","Interface1<Type1>",Covariant)]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface2<Type2>","#x"),("Interface2<Type1>","#x")]+          [("#x","Interface2<Type2>",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface2<Type2>","Interface2<#x>"),+           ("Interface2<Type1>","Interface2<#x>")]+          [("#x","Type2",Contravariant)]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface3<Type1>","#x"),("Interface3<Type1>","#x")]+          [("#x","Interface3<Type1>",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceFail tm+          [("#x",[])] ["#x"]+          [("Interface3<Type1>","#x"),("Interface3<Type2>","#x")]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface3<Type1>","Interface3<#x>"),+           ("Interface3<Type1>","Interface3<#x>")]+          [("#x","Type1",Invariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceFail tm+          [("#x",[])] ["#x"]+          [("Interface3<Type1>","Interface3<#x>"),+           ("Interface3<Type2>","Interface3<#x>")]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Type1","#x"),+           ("Interface1<Type2>","Interface1<#x>"),+           ("Interface2<Type0>","Interface2<#x>")]+          [("#x","Type1",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface3<Type2>","Interface3<#x>"),+           ("Interface1<Type2>","Interface1<#x>"),+           ("Interface2<Type1>","Interface2<#x>")]+          [("#x","Type2",Invariant)]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[]),("#y",["allows #x"])] ["#x"]+          [("Interface1<Type1>","Interface1<#x>"),+           ("Type0","#y")]  -- The filter for #y influences the guess for #x.+          [("#x","Type0",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[]),("#y",["allows #x"])] ["#x"]+          [("Interface1<Type1>","Interface1<#x>"),+           ("Type2","#y")]+          [("#x","Type1",Covariant)]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface1<Type1>","Interface1<[#x|Interface2<#x>]>")]+          [("#x","Type1",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface1<Type2>","Interface1<[#x&Type1]>")]+          [("#x","Type2",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface2<Type1>","Interface2<[#x&Interface2<#x>]>")]+          [("#x","Type1",Contravariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface2<Type0>","Interface2<[#x|Type1]>")]+          [("#x","Type0",Contravariant)]),++    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          [("Interface3<Type0>","[Interface1<#x>|Interface3<#x>]")]+          -- Guesses are either Type0 or Type1, and Type1 is more specific.+          [("#x","Type1",Covariant)]),+    checkOperationSuccess+      ("testfiles" </> "inference.0rx")+      (\ts -> do+        tm <- includeNewTypes defaultCategories ts+        checkInferenceSuccess tm+          [("#x",[])] ["#x"]+          -- Guesses are both Type0 and Type1, and Type0 is more general.+          [("Interface3<Type0>","[Interface1<#x>&Interface3<#x>]")]+          [("#x","Type0",Invariant)])   ]  getRefines :: Map.Map CategoryName (AnyCategory c) -> String -> CompileInfo [String] getRefines tm n =   case (CategoryName n) `Map.lookup` tm of        (Just t) -> return $ map (show . vrType) (getCategoryRefines t)-       _ -> compileError $ "Type " ++ n ++ " not found"+       _ -> compileErrorM $ "Type " ++ n ++ " not found"  getDefines ::  Map.Map CategoryName (AnyCategory c) -> String -> CompileInfo [String] getDefines tm n =   case (CategoryName n) `Map.lookup` tm of        (Just t) -> return $ map (show . vdType) (getCategoryDefines t)-       _ -> compileError $ "Type " ++ n ++ " not found"+       _ -> compileErrorM $ "Type " ++ n ++ " not found"  getTypeRefines :: Show c => [AnyCategory c] -> String -> String -> CompileInfo [String] getTypeRefines ts s n = do@@ -856,21 +1026,19 @@   scrapeSingle (ValueConcrete _ _ n _ _ ds _ _) = map ((,) n . vdType) ds   scrapeSingle _ = [] -checkPaired :: (Show a, CompileErrorM m, MergeableM m) =>-  (a -> a -> m ()) -> [a] -> [a] -> m ()+checkPaired :: Show a => (a -> a -> CompileInfo ()) -> [a] -> [a] -> CompileInfo () checkPaired f actual expected   | length actual /= length expected =-    compileError $ "Different item counts: " ++ show actual ++ " (actual) vs. " +++    compileErrorM $ "Different item counts: " ++ show actual ++ " (actual) vs. " ++                    show expected ++ " (expected)"   | otherwise = mergeAllM $ map check (zip3 actual expected ([1..] :: [Int])) where-    check (a,e,n) = f a e `reviseError` ("Item " ++ show n ++ " mismatch")+    check (a,e,n) = f a e `reviseErrorM` ("Item " ++ show n ++ " mismatch") -containsPaired :: (Eq a, Show a, CompileErrorM m, MergeableM m) =>-  [a] -> [a] -> m ()+containsPaired :: (Eq a, Show a) => [a] -> [a] -> CompileInfo () containsPaired = checkPaired checkSingle where   checkSingle a e     | a == e = return ()-    | otherwise = compileError $ show a ++ " (actual) vs. " ++ show e ++ " (expected)"+    | otherwise = compileErrorM $ show a ++ " (actual) vs. " ++ show e ++ " (expected)"  checkOperationSuccess :: String -> ([AnyCategory SourcePos] -> CompileInfo a) -> IO (CompileInfo ()) checkOperationSuccess f o = do@@ -878,7 +1046,7 @@   let parsed = readMulti f contents :: CompileInfo [AnyCategory SourcePos]   return $ check (parsed >>= o >> return ())   where-    check = flip reviseError ("Check " ++ f ++ ":")+    check = flip reviseErrorM ("Check " ++ f ++ ":")  checkOperationFail :: String -> ([AnyCategory SourcePos] -> CompileInfo a) -> IO (CompileInfo ()) checkOperationFail f o = do@@ -888,7 +1056,7 @@   where     check c       | isCompileError c = return ()-      | otherwise = compileError $ "Check " ++ f ++ ": Expected failure but got\n" +++      | otherwise = compileErrorM $ "Check " ++ f ++ ": Expected failure but got\n" ++                                    show (getCompileSuccess c) ++ "\n"  checkSingleParseSuccess :: String -> IO (CompileInfo ())@@ -898,7 +1066,7 @@   return $ check parsed   where     check c-      | isCompileError c = compileError $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse " ++ f ++ ":\n" ++ show (getCompileError c)       | otherwise = return ()  checkSingleParseFail :: String -> IO (CompileInfo ())@@ -909,7 +1077,7 @@   where     check c       | isCompileError c = return ()-      | otherwise = compileError $ "Parse " ++ f ++ ": Expected failure but got\n" +++      | otherwise = compileErrorM $ "Parse " ++ f ++ ": Expected failure but got\n" ++                                    show (getCompileSuccess c) ++ "\n"  checkShortParseSuccess :: String -> IO (CompileInfo ())@@ -918,7 +1086,7 @@   return $ check parsed   where     check c-      | isCompileError c = compileError $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)+      | isCompileError c = compileErrorM $ "Parse '" ++ s ++ "':\n" ++ show (getCompileError c)       | otherwise = return ()  checkShortParseFail :: String -> IO (CompileInfo ())@@ -928,5 +1096,59 @@   where     check c       | isCompileError c = return ()-      | otherwise = compileError $ "Parse '" ++ s ++ "': Expected failure but got\n" +++      | otherwise = compileErrorM $ "Parse '" ++ s ++ "': Expected failure but got\n" ++                                    show (getCompileSuccess c) ++ "\n"++checkInferenceSuccess :: CategoryMap SourcePos -> [(String, [String])] ->+  [String] -> [(String, String)] -> [(String,String,Variance)] -> CompileInfo ()+checkInferenceSuccess tm pa is ts gs = checkInferenceCommon check tm pa is ts gs where+  prefix = show ts ++ " " ++ showParams pa+  check gs2 c+    | isCompileError c = compileErrorM $ prefix ++ ":\n" ++ show (getCompileError c)+    | otherwise        = getCompileSuccess c `containsExactly` gs2++checkInferenceFail :: CategoryMap SourcePos -> [(String, [String])] ->+  [String] -> [(String, String)] -> CompileInfo ()+checkInferenceFail tm pa is ts = checkInferenceCommon check tm pa is ts [] where+  prefix = show ts ++ " " ++ showParams pa+  check _ c+    | isCompileError c = return ()+    | otherwise = compileErrorM $ prefix ++ ": Expected failure\n"++checkInferenceCommon :: ([InferredTypeGuess] -> CompileInfo [InferredTypeGuess] -> CompileInfo ()) ->+  CategoryMap SourcePos -> [(String, [String])] -> [String] ->+  [(String,String)] -> [(String,String,Variance)] -> CompileInfo ()+checkInferenceCommon check tm pa is ts gs = checked `reviseErrorM` context where+  context = "With params = " ++ show pa ++ ", pairs = " ++ show ts+  checked = do+    let r = CategoryResolver tm+    pa2 <- parseFilterMap pa+    ts2 <- mapErrorsM parsePair ts+    ia2 <- mapErrorsM readInferred is+    gs' <- mapErrorsM parseGuess gs+    let iaMap = Map.fromList ia2+    -- TODO: Put the next few lines in a function in TypeCategory.+    pa3 <- fmap Map.fromList $ mapErrorsM (filterSub iaMap) $ Map.toList pa2+    gs2 <- mergeAllM $ map (subAndInfer r pa3 iaMap) ts2+    check gs' $ mergeInferredTypes r pa3 gs2+  subAndInfer r f im (t1,t2) = do+    t2' <- uncheckedSubInstance (weakLookup im) t2+    checkGeneralMatch r f Covariant t1 t2'+  readInferred p = do+    p' <- readSingle "(string)" p+    return (p',SingleType $ JustInferredType p')+  parseGuess (p,t,v) = do+    p' <- readSingle "(string)" p+    t' <- readSingle "(string)" t+    return $ InferredTypeGuess p' t' v+  parsePair (t1,t2) = do+    t1' <- readSingle "(string)" t1+    t2' <- readSingle "(string)" t2+    return (t1',t2')+  weakLookup tm2 n =+    case n `Map.lookup` tm2 of+         Just t  -> return t+         Nothing -> return $ SingleType $ JustParamName n+  filterSub im (k,fs) = do+    fs' <- mapErrorsM (uncheckedSubFilter (weakLookup im)) fs+    return (k,fs')
src/Test/TypeInstance.hs view
@@ -23,9 +23,12 @@ import qualified Data.Map as Map  import Base.CompileError-import Compilation.CompileInfo+import Base.CompileInfo+import Base.MergeTree+import Base.Mergeable import Parser.TypeInstance () import Test.Common+import Types.GeneralType import Types.Positional import Types.TypeInstance import Types.Variance@@ -559,7 +562,70 @@       "Instance1<Type3>",     return $ checkDefinesSuccess Resolver       []-      "Instance1<Type1<Type3>>"+      "Instance1<Type1<Type3>>",++    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Type1<Type0>" "Type1<#x>"+      (mergeLeaf ("#x","Type0",Invariant)),+    checkInferenceFail+      [("#x",[])] ["#x"]+      "Type1<Type3>" "Type4<#x>",++    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Instance1<Type1<Type3>>" "Instance1<#x>"+      (mergeLeaf ("#x","Type1<Type3>",Contravariant)),+    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Instance1<Type1<Type3>>" "Instance1<Type1<#x>>"+      (mergeLeaf ("#x","Type3",Invariant)),++    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Type2<Type3,Type0,Type3>" "Type2<#x,Type0,#x>"+      (mergeAll [mergeLeaf ("#x","Type3",Contravariant),+                 mergeLeaf ("#x","Type3",Covariant)]),+    checkInferenceSuccess+      [("#x",[]),("#y",[])] ["#x"]+      "Type2<Type3,#y,Type3>" "Type2<#x,#y,#x>"+      (mergeAll [mergeLeaf ("#x","Type3",Contravariant),+                 mergeLeaf ("#x","Type3",Covariant)]),+    checkInferenceFail+      [("#x",[]),("#y",[])] ["#x"]+      "Type2<Type3,Type0,Type3>" "Type2<#x,#y,#x>",++    checkInferenceSuccess+      [("#x",[]),("#y",[])] ["#x"]+      "Type2<Type3,#y,Type0>" "Type1<#x>"+      (mergeLeaf ("#x","Type3",Invariant)),++    checkInferenceSuccess+      [("#x",[]),("#y",[])] ["#x"]+      "Instance1<#y>" "Instance1<#x>"+      (mergeLeaf ("#x","#y",Contravariant)),++    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Instance1<Instance0>" "Instance1<[#x&Type0]>"+      (mergeLeaf ("#x","Instance0",Contravariant)),+    checkInferenceFail+      [("#x",[])] ["#x"]+      "Instance1<Instance0>" "Instance1<[#x|Type0]>",+    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Instance1<Type1<Type0>>" "Instance1<[Type0&Type1<#x>]>"+      (mergeLeaf ("#x","Type0",Invariant)),+    checkInferenceSuccess+      [("#x",[])] ["#x"]+      "Instance1<Type1<Type0>>" "Instance1<[#x&Type1<#x>]>"+      (mergeAny [mergeLeaf ("#x","Type1<Type0>",Contravariant),+                 mergeLeaf ("#x","Type0",Invariant)]),++    checkInferenceSuccess+      [("#x",[]),("#y",["allows #x"])] ["#x"]+      "Type0" "#y"  -- The filter for #y influences the guess for #x.+      (mergeLeaf ("#x","Type0",Covariant))   ]  @@ -679,23 +745,69 @@            ])   ] -checkSimpleConvertSuccess :: [Char] -> [Char] -> IO (CompileInfo ())+checkSimpleConvertSuccess :: String -> String -> IO (CompileInfo ()) checkSimpleConvertSuccess = checkConvertSuccess [] -checkSimpleConvertFail :: [Char] -> [Char] -> IO (CompileInfo ())+checkSimpleConvertFail :: String -> String -> IO (CompileInfo ()) checkSimpleConvertFail = checkConvertFail [] -checkConvertSuccess :: [(String, [String])] -> [Char] -> [Char] -> IO (CompileInfo ())+checkConvertSuccess :: [(String, [String])] -> String -> String -> IO (CompileInfo ()) checkConvertSuccess pa x y = return checked where   prefix = x ++ " -> " ++ y ++ " " ++ showParams pa   checked = do     ([t1,t2],pa2) <- parseTheTest pa [x,y]     check $ checkValueTypeMatch Resolver pa2 t1 t2   check c-    | isCompileError c = compileError $ prefix ++ ":\n" ++ show (getCompileError c)+    | isCompileError c = compileErrorM $ prefix ++ ":\n" ++ show (getCompileError c)     | otherwise = return () -checkConvertFail :: [(String, [String])] -> [Char] -> [Char] -> IO (CompileInfo ())+checkInferenceSuccess :: [(String, [String])] -> [String] -> String ->+  String -> MergeTree (String,String,Variance) -> IO (CompileInfo ())+checkInferenceSuccess pa is x y gs = checkInferenceCommon check pa is x y gs where+  prefix = x ++ " -> " ++ y ++ " " ++ showParams pa+  check gs2 c+    | isCompileError c = compileErrorM $ prefix ++ ":\n" ++ show (getCompileError c)+    | otherwise        = getCompileSuccess c `checkEquals` gs2++checkInferenceFail :: [(String, [String])] -> [String] -> String ->+  String -> IO (CompileInfo ())+checkInferenceFail pa is x y = checkInferenceCommon check pa is x y (mergeAll []) where+  prefix = x ++ " -> " ++ y ++ " " ++ showParams pa+  check _ c+    | isCompileError c = return ()+    | otherwise = compileErrorM $ prefix ++ ": Expected failure\n"++checkInferenceCommon ::+  (MergeTree InferredTypeGuess -> CompileInfo (MergeTree InferredTypeGuess) -> CompileInfo ()) ->+  [(String, [String])] -> [String] -> String -> String ->+  MergeTree (String,String,Variance) -> IO (CompileInfo ())+checkInferenceCommon check pa is x y gs = return $ checked `reviseErrorM` context where+  context = "With params = " ++ show pa ++ ", pair = (" ++ show x ++ "," ++ show y ++ ")"+  checked = do+    ([t1,t2],pa2) <- parseTheTest pa [x,y]+    ia2 <- mapErrorsM readInferred is+    gs' <- sequence $ fmap parseGuess gs+    let iaMap = Map.fromList ia2+    -- TODO: Merge duplication with Test.TypeCategory.+    pa3 <- fmap Map.fromList $ mapErrorsM (filterSub iaMap) $ Map.toList pa2+    t2' <- uncheckedSubInstance (weakLookup iaMap) t2+    check gs' $ checkGeneralMatch Resolver pa3 Covariant t1 t2'+  readInferred p = do+    p' <- readSingle "(string)" p+    return (p',SingleType $ JustInferredType p')+  parseGuess (p,t,v) = do+    p' <- readSingle "(string)" p+    t' <- readSingle "(string)" t+    return $ InferredTypeGuess p' t' v+  weakLookup tm n =+    case n `Map.lookup` tm of+         Just t  -> return t+         Nothing -> return $ SingleType $ JustParamName n+  filterSub im (k,fs) = do+    fs' <- mapErrorsM (uncheckedSubFilter (weakLookup im)) fs+    return (k,fs')++checkConvertFail :: [(String, [String])] -> String -> String -> IO (CompileInfo ()) checkConvertFail pa x y = return checked where   prefix = x ++ " /> " ++ y ++ " " ++ showParams pa   checked = do@@ -704,7 +816,7 @@   check :: CompileInfo a -> CompileInfo ()   check c     | isCompileError c = return ()-    | otherwise = compileError $ prefix ++ ": Expected failure\n"+    | otherwise = compileErrorM $ prefix ++ ": Expected failure\n"  data Resolver = Resolver @@ -721,21 +833,21 @@   Map.Map CategoryName (Map.Map CategoryName (InstanceParams -> InstanceParams))   -> TypeInstance -> CategoryName -> m InstanceParams getParams ma (TypeInstance n1 ps1) n2 = do-  ra <- mapLookup ma n1-  f <- mapLookup ra n2+  ra <- mapLookup ma n1 `reviseErrorM` ("In lookup of category " ++ show n1)+  f <- mapLookup ra n2 `reviseErrorM` ("In lookup of parent " ++ show n2 ++ " of " ++ show n1)   return $ f ps1  getTypeFilters :: CompileErrorM m => TypeInstance -> m InstanceFilters-getTypeFilters (TypeInstance n ps) = do+getTypeFilters (TypeInstance n ps) = flip reviseErrorM "In type filters lookup" $ do   f <- mapLookup typeFilters n   return $ f ps  getDefinesFilters :: CompileErrorM m => DefinesInstance -> m InstanceFilters-getDefinesFilters (DefinesInstance n ps) = do+getDefinesFilters (DefinesInstance n ps) = flip reviseErrorM "In defines filters lookup" $ do   f <- mapLookup definesFilters n   return $ f ps  mapLookup :: (Ord n, Show n, CompileErrorM m) => Map.Map n a -> n -> m a mapLookup ma n = resolve $ n `Map.lookup` ma where   resolve (Just x) = return x-  resolve _        = compileError $ "Map key " ++ show n ++ " not found"+  resolve _        = compileErrorM $ "Map key " ++ show n ++ " not found"
src/Test/testfiles/flatten.0rx view
@@ -5,16 +5,6 @@  @value interface Object2 {} -@value interface Object3<#x> {-  refines Object2-}--@value interface Parent<#x> {-  refines Object1<#x,Object3<Object2>>-  // -> refines Object3<Object3<Object2>>-  // -> refines Object2-}- @type interface Type<#x> {}  concrete Child {@@ -24,4 +14,14 @@   // -> refines Object2    defines Type<Child>+}++@value interface Parent<#x> {+  refines Object1<#x,Object3<Object2>>+  // -> refines Object3<Object3<Object2>>+  // -> refines Object2+}++@value interface Object3<#x> {+  refines Object2 }
+ src/Test/testfiles/inference.0rx view
@@ -0,0 +1,19 @@+@value interface Interface1<|#x> {}++@value interface Interface2<#y|> {}++@value interface Interface3<#z> {+  refines Interface1<Type1>+}++@value interface Interface4<#x|#y|#z> {}++@value interface Type0 {}++@value interface Type1 {+  refines Type0+}++@value interface Type2 {+  refines Type1+}
src/Types/DefinedCategory.hs view
@@ -90,7 +90,7 @@     case n `Map.lookup` fa' of          Nothing -> return $ Map.insert n f fa'          (Just f0@(ScopedFunction c2 _ _ _ _ _ _ _ ms2)) -> do-           flip reviseError ("In function merge:\n---\n" ++ show f0 +++           flip reviseErrorM ("In function merge:\n---\n" ++ show f0 ++                              "\n  ->\n" ++ show f ++ "\n---\n") $ do              f0' <- parsedToFunctionType f0              f' <- parsedToFunctionType f@@ -110,7 +110,7 @@       case epName p `Map.lookup` pa' of            Nothing -> return ()            -- TODO: The error might show things in the wrong order.-           (Just p0) -> compileError $ "Procedure " ++ show (epName p) +++           (Just p0) -> compileErrorM $ "Procedure " ++ show (epName p) ++                                        formatFullContextBrace (epContext p) ++                                        " is already defined" ++                                        formatFullContextBrace (epContext p0)@@ -120,15 +120,15 @@       p <- getPair (n `Map.lookup` fa2) (n `Map.lookup` pa)       return (p:ps2')     getPair (Just f) Nothing =-      compileError $ "Function " ++ show (sfName f) +++      compileErrorM $ "Function " ++ show (sfName f) ++                      formatFullContextBrace (sfContext f) ++                      " has no procedure definition"     getPair Nothing (Just p) =-      compileError $ "Procedure " ++ show (epName p) +++      compileErrorM $ "Procedure " ++ show (epName p) ++                      formatFullContextBrace (epContext p) ++                      " does not correspond to a function"     getPair (Just f) (Just p) = do-      processPairs_ alwaysPair (sfArgs f) (avNames $ epArgs p) `reviseError`+      processPairs_ alwaysPair (sfArgs f) (avNames $ epArgs p) `reviseErrorM`         ("Procedure for " ++ show (sfName f) ++          formatFullContextBrace (avContext $ epArgs p) ++          " has the wrong number of arguments" ++@@ -136,7 +136,7 @@       if isUnnamedReturns (epReturns p)          then return ()          else do-           processPairs_ alwaysPair (sfReturns f) (nrNames $ epReturns p) `reviseError`+           processPairs_ alwaysPair (sfReturns f) (nrNames $ epReturns p) `reviseErrorM`              ("Procedure for " ++ show (sfName f) ++               formatFullContextBrace (nrContext $ epReturns p) ++               " has the wrong number of returns" ++@@ -153,7 +153,7 @@     case dmName m `Map.lookup` ma' of          Nothing ->  return ()          -- TODO: The error might show things in the wrong order.-         (Just m0) -> compileError $ "Member " ++ show (dmName m) +++         (Just m0) -> compileErrorM $ "Member " ++ show (dmName m) ++                                      formatFullContextBrace (dmContext m) ++                                      " is already defined" ++                                      formatFullContextBrace (vvContext m0)
src/Types/Function.hs view
@@ -70,28 +70,28 @@   where     allVariances = Map.union vm (Map.fromList $ zip (pValues ps) (repeat Invariant))     checkCount xa@(x:_:_) =-      compileError $ "Param " ++ show x ++ " occurs " ++ show (length xa) ++ " times"+      compileErrorM $ "Param " ++ show x ++ " occurs " ++ show (length xa) ++ " times"     checkCount _ = return ()     checkHides n =       when (n `Map.member` fm) $-        compileError $ "Param " ++ show n ++ " hides another param in a higher scope"+        compileErrorM $ "Param " ++ show n ++ " hides another param in a higher scope"     checkFilterType fa2 (n,f) =-      validateTypeFilter r fa2 f `reviseError` ("In filter " ++ show n ++ " " ++ show f)+      validateTypeFilter r fa2 f `reviseErrorM` ("In filter " ++ show n ++ " " ++ show f)     checkFilterVariance (n,f@(TypeFilter FilterRequires t)) =-      validateInstanceVariance r allVariances Contravariant (SingleType t) `reviseError`+      validateInstanceVariance r allVariances Contravariant (SingleType t) `reviseErrorM`         ("In filter " ++ show n ++ " " ++ show f)     checkFilterVariance (n,f@(TypeFilter FilterAllows t)) =-      validateInstanceVariance r allVariances Covariant (SingleType t) `reviseError`+      validateInstanceVariance r allVariances Covariant (SingleType t) `reviseErrorM`         ("In filter " ++ show n ++ " " ++ show f)     checkFilterVariance (n,f@(DefinesFilter t)) =-      validateDefinesVariance r allVariances Contravariant t `reviseError`+      validateDefinesVariance r allVariances Contravariant t `reviseErrorM`         ("In filter " ++ show n ++ " " ++ show f)-    checkArg fa2 ta@(ValueType _ t) = flip reviseError ("In argument " ++ show ta) $ do-      when (isWeakValue ta) $ compileError "Weak values not allowed as argument types"+    checkArg fa2 ta@(ValueType _ t) = flip reviseErrorM ("In argument " ++ show ta) $ do+      when (isWeakValue ta) $ compileErrorM "Weak values not allowed as argument types"       validateGeneralInstance r fa2 t       validateInstanceVariance r allVariances Contravariant t-    checkReturn fa2 ta@(ValueType _ t) = flip reviseError ("In return " ++ show ta) $ do-      when (isWeakValue ta) $ compileError "Weak values not allowed as return types"+    checkReturn fa2 ta@(ValueType _ t) = flip reviseErrorM ("In return " ++ show ta) $ do+      when (isWeakValue ta) $ compileErrorM "Weak values not allowed as return types"       validateGeneralInstance r fa2 t       validateInstanceVariance r allVariances Covariant t @@ -102,15 +102,15 @@   mergeAllM $ map (validateGeneralInstance r fm) $ pValues ts   assigned <- fmap Map.fromList $ processPairs alwaysPair ps ts   let allAssigned = Map.union assigned (Map.fromList $ map (\n -> (n,SingleType $ JustParamName n)) $ Map.keys fm)-  fa' <- fmap Positional $ collectAllOrErrorM $ map (assignFilters allAssigned) (pValues fa)+  fa' <- fmap Positional $ mapErrorsM (assignFilters allAssigned) (pValues fa)   processPairs_ (validateAssignment r fm) ts fa'-  as' <- fmap Positional $ collectAllOrErrorM $-         map (uncheckedSubValueType $ getValueForParam allAssigned) (pValues as)-  rs' <- fmap Positional $ collectAllOrErrorM $-         map (uncheckedSubValueType $ getValueForParam allAssigned) (pValues rs)+  as' <- fmap Positional $+         mapErrorsM (uncheckedSubValueType $ getValueForParam allAssigned) (pValues as)+  rs' <- fmap Positional $+         mapErrorsM (uncheckedSubValueType $ getValueForParam allAssigned) (pValues rs)   return $ FunctionType as' rs' (Positional []) (Positional [])   where-    assignFilters fm2 fs = collectAllOrErrorM $ map (uncheckedSubFilter $ getValueForParam fm2) fs+    assignFilters fm2 fs = mapErrorsM (uncheckedSubFilter $ getValueForParam fm2) fs  checkFunctionConvert :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> FunctionType -> FunctionType -> m ()
src/Types/Positional.hs view
@@ -21,12 +21,14 @@   alwaysPair,   processPairs,   processPairs_,+  processPairsM,   processPairsT, ) where  import Control.Monad.Trans (MonadTrans(..))  import Base.CompileError+import Base.Mergeable   newtype Positional a =@@ -45,9 +47,13 @@   (a -> b -> m c) -> Positional a -> Positional b -> m [c] processPairs f (Positional ps1) (Positional ps2)   | length ps1 == length ps2 =-    collectAllOrErrorM $ map (uncurry f) (zip ps1 ps2)+    mapErrorsM (uncurry f) (zip ps1 ps2)   | otherwise = mismatchError ps1 ps2 +processPairsM :: (Show a, Show b, Mergeable c, CompileErrorM m) =>+  (a -> b -> m c) -> Positional a -> Positional b -> m c+processPairsM f x y = fmap mergeAll $ processPairs f x y+ processPairs_ :: (Show a, Show b, CompileErrorM m) =>   (a -> b -> m c) -> Positional a -> Positional b -> m () processPairs_ f xs ys = processPairs f xs ys >> return ()@@ -60,5 +66,5 @@   | otherwise = lift $ mismatchError ps1 ps2  mismatchError :: (Show a, Show b, CompileErrorM m) => [a] -> [b] -> m c-mismatchError ps1 ps2 = compileError $ "Count mismatch: " ++ show ps1 +++mismatchError ps1 ps2 = compileErrorM $ "Count mismatch: " ++ show ps1 ++                                        " (expected) vs. " ++ show ps2 ++ " (actual)"
src/Types/Procedure.hs view
@@ -29,6 +29,7 @@   FunctionSpec(..),   IfElifElse(..),   InputValue(..),+  InstanceOrInferred(..),   Operator(..),   OutputValue(..),   Procedure(..),@@ -211,8 +212,13 @@   UnqualifiedFunction   deriving (Show) +data InstanceOrInferred c =+  AssignedInstance [c] GeneralInstance |+  InferredInstance [c]+  deriving (Show)+ data FunctionSpec c =-  FunctionSpec [c] (FunctionQualifier c) FunctionName (Positional GeneralInstance)+  FunctionSpec [c] (FunctionQualifier c) FunctionName (Positional (InstanceOrInferred c))   deriving (Show)  data Operator c =@@ -228,7 +234,7 @@ getExpressionContext (InitializeValue c _ _ _) = c  data FunctionCall c =-  FunctionCall [c] FunctionName (Positional GeneralInstance) (Positional (Expression c))+  FunctionCall [c] FunctionName (Positional (InstanceOrInferred c)) (Positional (Expression c))   deriving (Show)  data ExpressionStart c =
src/Types/TypeCategory.hs view
@@ -56,6 +56,7 @@   getInstanceCategory,   getValueCategory,   includeNewTypes,+  inferParamTypes,   isInstanceInterface,   isDynamicNamespace,   isNoNamespace,@@ -64,6 +65,7 @@   isValueInterface,   mergeDefines,   mergeFunctions,+  mergeInferredTypes,   mergeRefines,   noDuplicateDefines,   noDuplicateRefines,@@ -82,6 +84,7 @@ import qualified Data.Set as Set  import Base.CompileError+import Base.MergeTree import Base.Mergeable import Types.Function import Types.GeneralType@@ -323,8 +326,8 @@         let pa = Map.fromList $ map (\r -> (tiName r,tiParams r)) $ map vrType $ getCategoryRefines t         ps2 <- case n2 `Map.lookup` pa of                     (Just x) -> return x-                    _ -> compileError $ "Category " ++ show n1 ++ " does not refine " ++ show n2-        fmap Positional $ collectAllOrErrorM $ map (subAllParams assigned) $ pValues ps2+                    _ -> compileErrorM $ "Category " ++ show n1 ++ " does not refine " ++ show n2+        fmap Positional $ mapErrorsM (subAllParams assigned) $ pValues ps2     trDefines (CategoryResolver tm) (TypeInstance n1 ps1) n2 = do       (_,t) <- getValueCategory tm ([],n1)       let params = map vpParam $ getCategoryParams t@@ -332,8 +335,8 @@       let pa = Map.fromList $ map (\r -> (diName r,diParams r)) $ map vdType $ getCategoryDefines t       ps2 <- case n2 `Map.lookup` pa of                   (Just x) -> return x-                  _ -> compileError $ "Category " ++ show n1 ++ " does not define " ++ show n2-      fmap Positional $ collectAllOrErrorM $ map (subAllParams assigned) $ pValues ps2+                  _ -> compileErrorM $ "Category " ++ show n1 ++ " does not define " ++ show n2+      fmap Positional $ mapErrorsM (subAllParams assigned) $ pValues ps2     trVariance (CategoryResolver tm) n = do       (_,t) <- getCategory tm ([],n)       return $ Positional $ map vpVariance $ getCategoryParams t@@ -374,15 +377,15 @@ checkFilters t ps = do   let params = map vpParam $ getCategoryParams t   assigned <- fmap Map.fromList $ processPairs alwaysPair (Positional params) ps-  fs <- collectAllOrErrorM $ map (subSingleFilter assigned . \f -> (pfParam f,pfFilter f))+  fs <- mapErrorsM (subSingleFilter assigned . \f -> (pfParam f,pfFilter f))                                   (getCategoryFilters t)   let fa = Map.fromListWith (++) $ map (second (:[])) fs-  fmap Positional $ collectAllOrErrorM $ map (assignFilter fa) params where+  fmap Positional $ mapErrorsM (assignFilter fa) params where     subSingleFilter pa (n,(TypeFilter v t2)) = do       (SingleType t3) <- uncheckedSubInstance (getValueForParam pa) (SingleType t2)       return (n,(TypeFilter v t3))     subSingleFilter pa (n,(DefinesFilter (DefinesInstance n2 ps2))) = do-      ps3 <- collectAllOrErrorM $ map (uncheckedSubInstance $ getValueForParam pa) (pValues ps2)+      ps3 <- mapErrorsM (uncheckedSubInstance $ getValueForParam pa) (pValues ps2)       return (n,(DefinesFilter (DefinesInstance n2 (Positional ps3))))     assignFilter fa n =       case n `Map.lookup` fa of@@ -400,7 +403,7 @@ getCategory tm (c,n) =   case n `Map.lookup` tm of        (Just t) -> return (c,t)-       _ -> compileError $ "Type " ++ show n ++ context ++ " not found"+       _ -> compileErrorM $ "Type " ++ show n ++ context ++ " not found"   where     context       | null c = ""@@ -412,7 +415,7 @@   (c2,t) <- getCategory tm (c,n)   if isValueInterface t || isValueConcrete t      then return (c2,t)-     else compileError $ "Category " ++ show n +++     else compileErrorM $ "Category " ++ show n ++                          " cannot be used as a value" ++                          formatFullContextBrace c @@ -422,7 +425,7 @@   (c2,t) <- getCategory tm (c,n)   if isInstanceInterface t      then return (c2,t)-     else compileError $ "Category " ++ show n +++     else compileErrorM $ "Category " ++ show n ++                          " cannot be used as a type interface" ++                          formatFullContextBrace c @@ -432,7 +435,7 @@   (c2,t) <- getCategory tm (c,n)   if isValueConcrete t      then return (c2,t)-     else compileError $ "Category " ++ show n +++     else compileErrorM $ "Category " ++ show n ++                          " cannot be used as concrete" ++                          formatFullContextBrace c @@ -452,14 +455,11 @@ declareAllTypes tm0 = foldr (\t tm -> tm >>= update t) (return tm0) where   update t tm =     case getCategoryName t `Map.lookup` tm of-        (Just t2) -> compileError $ "Type " ++ show (getCategoryName t) ++-                                    formatFullContextBrace (getCategoryContext t) ++-                                    " has already been declared" ++-                                    showExisting t2+        (Just t2) -> compileErrorM $ "Type " ++ show (getCategoryName t) +++                                     formatFullContextBrace (getCategoryContext t) +++                                     " has already been declared" +++                                     formatFullContextBrace (getCategoryContext t2)         _ -> return $ Map.insert (getCategoryName t) t tm-  showExisting t-    | isBuiltinCategory (getCategoryName t) = " [builtin type]"-    | otherwise = formatFullContextBrace (getCategoryContext t)  getFilterMap :: [ValueParam c] -> [ParamFilter c] -> ParamFilters getFilterMap ps fs = getFilters $ zip (Set.toList pa) (repeat []) where@@ -482,14 +482,14 @@   where     checkSingle tm (ValueInterface c _ n _ rs _ _) = do       let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs-      is <- collectAllOrErrorM $ map (getCategory tm) ts2+      is <- mapErrorsM (getCategory tm) ts2       mergeAllM (map (valueRefinesInstanceError c n) is)       mergeAllM (map (valueRefinesConcreteError c n) is)     checkSingle tm (ValueConcrete c _ n _ rs ds _ _) = do       let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs       let ts3 = map (\d -> (vdContext d,diName $ vdType d)) ds-      is1 <- collectAllOrErrorM $ map (getCategory tm) ts2-      is2 <- collectAllOrErrorM $ map (getCategory tm) ts3+      is1 <- mapErrorsM (getCategory tm) ts2+      is2 <- mapErrorsM (getCategory tm) ts3       mergeAllM (map (concreteRefinesInstanceError c n) is1)       mergeAllM (map (concreteDefinesValueError c n) is2)       mergeAllM (map (concreteRefinesConcreteError c n) is1)@@ -497,39 +497,39 @@     checkSingle _ _ = return ()     valueRefinesInstanceError c n (c2,t)       | isInstanceInterface t =-        compileError $ "Value interface " ++ show n ++ formatFullContextBrace c ++-                      " cannot refine type interface " ++-                      show (iiName t) ++ formatFullContextBrace c2+        compileErrorM $ "Value interface " ++ show n ++ formatFullContextBrace c +++                        " cannot refine type interface " +++                        show (iiName t) ++ formatFullContextBrace c2       | otherwise = return ()     valueRefinesConcreteError c n (c2,t)       | isValueConcrete t =-        compileError $ "Value interface " ++ show n ++ formatFullContextBrace c ++-                      " cannot refine concrete type " ++-                      show (getCategoryName t) ++ formatFullContextBrace c2+        compileErrorM $ "Value interface " ++ show n ++ formatFullContextBrace c +++                        " cannot refine concrete type " +++                        show (getCategoryName t) ++ formatFullContextBrace c2       | otherwise = return ()     concreteRefinesInstanceError c n (c2,t)       | isInstanceInterface t =-        compileError $ "Concrete type " ++ show n ++ formatFullContextBrace c ++-                      " cannot refine instance interface " ++-                      show (getCategoryName t) ++ formatFullContextBrace c2 ++-                      " => use defines instead"+        compileErrorM $ "Concrete type " ++ show n ++ formatFullContextBrace c +++                        " cannot refine instance interface " +++                        show (getCategoryName t) ++ formatFullContextBrace c2 +++                        " => use defines instead"       | otherwise = return ()     concreteDefinesValueError c n (c2,t)       | isValueInterface t =-        compileError $ "Concrete type " ++ show n ++ formatFullContextBrace c +++        compileErrorM $ "Concrete type " ++ show n ++ formatFullContextBrace c ++                       " cannot define value interface " ++                       show (getCategoryName t) ++ formatFullContextBrace c2 ++                       " => use refines instead"       | otherwise = return ()     concreteRefinesConcreteError c n (c2,t)       | isValueConcrete t =-        compileError $ "Concrete type " ++ show n ++ formatFullContextBrace c +++        compileErrorM $ "Concrete type " ++ show n ++ formatFullContextBrace c ++                       " cannot refine concrete type " ++                       show (getCategoryName t) ++ formatFullContextBrace c2       | otherwise = return ()     concreteDefinesConcreteError c n (c2,t)       | isValueConcrete t =-        compileError $ "Concrete type " ++ show n ++ formatFullContextBrace c +++        compileErrorM $ "Concrete type " ++ show n ++ formatFullContextBrace c ++                       " cannot define concrete type " ++                       show (getCategoryName t) ++ formatFullContextBrace c2       | otherwise = return ()@@ -541,17 +541,17 @@   checker us (ValueInterface c _ n _ rs _ _) = do     failIfCycle n c us     let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs-    is <- collectAllOrErrorM $ map (getValueCategory tm) ts2+    is <- mapErrorsM (getValueCategory tm) ts2     mergeAllM (map (checker (us ++ [n]) . snd) is)   checker us (ValueConcrete c _ n _ rs _ _ _) = do     failIfCycle n c us     let ts2 = map (\r -> (vrContext r,tiName $ vrType r)) rs-    is <- collectAllOrErrorM $ map (getValueCategory tm) ts2+    is <- mapErrorsM (getValueCategory tm) ts2     mergeAllM (map (checker (us ++ [n]) . snd) is)   checker _ _ = return ()   failIfCycle n c us =     when (n `Set.member` (Set.fromList us)) $-      compileError $ "Category " ++ show n ++ formatFullContextBrace c +++      compileErrorM $ "Category " ++ show n ++ formatFullContextBrace c ++                      " refers back to itself: " ++                      intercalate " -> " (map show (us ++ [n])) @@ -579,37 +579,37 @@       mergeAllM $ map (checkFilterVariance r vm) fa     noDuplicates c n ps = mergeAllM (map checkCount $ group $ sort $ map vpParam ps) where       checkCount xa@(x:_:_) =-        compileError $ "Param " ++ show x ++ " occurs " ++ show (length xa) +++        compileErrorM $ "Param " ++ show x ++ " occurs " ++ show (length xa) ++                       " times in " ++ show n ++ formatFullContextBrace c       checkCount _ = return ()     checkRefine r vm (ValueRefine c t) =-      validateInstanceVariance r vm Covariant (SingleType $ JustTypeInstance t) `reviseError`+      validateInstanceVariance r vm Covariant (SingleType $ JustTypeInstance t) `reviseErrorM`         (show t ++ formatFullContextBrace c)     checkDefine r vm (ValueDefine c t) =-      validateDefinesVariance r vm Covariant t `reviseError`+      validateDefinesVariance r vm Covariant t `reviseErrorM`         (show t ++ formatFullContextBrace c)     checkFilterVariance r vs (ParamFilter c n f@(TypeFilter FilterRequires t)) =-      flip reviseError ("In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c) $ do+      flip reviseErrorM ("In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c) $ do         case n `Map.lookup` vs of-             Just Contravariant -> compileError $ "Contravariant param " ++ show n +++             Just Contravariant -> compileErrorM $ "Contravariant param " ++ show n ++                                                   " cannot have a requires filter"-             Nothing -> compileError $ "Param " ++ show n ++ " is undefined"+             Nothing -> compileErrorM $ "Param " ++ show n ++ " is undefined"              _ -> return ()         validateInstanceVariance r vs Contravariant (SingleType t)     checkFilterVariance r vs (ParamFilter c n f@(TypeFilter FilterAllows t)) =-      flip reviseError ("In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c) $ do+      flip reviseErrorM ("In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c) $ do         case n `Map.lookup` vs of-             Just Covariant -> compileError $ "Covariant param " ++ show n +++             Just Covariant -> compileErrorM $ "Covariant param " ++ show n ++                                               " cannot have an allows filter"-             Nothing -> compileError $ "Param " ++ show n ++ " is undefined"+             Nothing -> compileErrorM $ "Param " ++ show n ++ " is undefined"              _ -> return ()         validateInstanceVariance r vs Covariant (SingleType t)     checkFilterVariance r vs (ParamFilter c n f@(DefinesFilter t)) =-      flip reviseError ("In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c) $ do+      flip reviseErrorM ("In filter " ++ show n ++ " " ++ show f ++ formatFullContextBrace c) $ do         case n `Map.lookup` vs of-             Just Contravariant -> compileError $ "Contravariant param " ++ show n +++             Just Contravariant -> compileErrorM $ "Contravariant param " ++ show n ++                                                   " cannot have a defines filter"-             Nothing -> compileError $ "Param " ++ show n ++ " is undefined"+             Nothing -> compileErrorM $ "Param " ++ show n ++ " is undefined"              _ -> return ()         validateDefinesVariance r vs Contravariant t @@ -630,15 +630,15 @@       mergeAllM $ map (validateCategoryFunction r t) (getCategoryFunctions t)     checkFilterParam pa (ParamFilter c n _) =       when (not $ n `Set.member` pa) $-        compileError $ "Param " ++ show n ++ formatFullContextBrace c ++ " does not exist"+        compileErrorM $ "Param " ++ show n ++ formatFullContextBrace c ++ " does not exist"     checkRefine r fm (ValueRefine c t) =-      validateTypeInstance r fm t `reviseError`+      validateTypeInstance r fm t `reviseErrorM`         (show t ++ formatFullContextBrace c)     checkDefine r fm (ValueDefine c t) =-      validateDefinesInstance r fm t `reviseError`+      validateDefinesInstance r fm t `reviseErrorM`         (show t ++ formatFullContextBrace c)     checkFilter r fm (ParamFilter c n f) =-      validateTypeFilter r fm f `reviseError`+      validateTypeFilter r fm f `reviseErrorM`         (show n ++ " " ++ show f ++ formatFullContextBrace c)  validateCategoryFunction :: (Show c, MergeableM m, CompileErrorM m, TypeResolver r) =>@@ -646,7 +646,7 @@ validateCategoryFunction r t f = do   let fm = getCategoryFilterMap t   let vm = Map.fromList $ map (\p -> (vpParam p,vpVariance p)) $ getCategoryParams t-  flip reviseError ("In function:\n---\n" ++ show f ++ "\n---\n") $ do+  flip reviseErrorM ("In function:\n---\n" ++ show f ++ "\n---\n") $ do     funcType <- parsedToFunctionType f     case sfScope f of          CategoryScope -> validatateFunctionType r Map.empty Map.empty funcType@@ -658,49 +658,43 @@   CategoryMap c -> [AnyCategory c] -> m [AnyCategory c] topoSortCategories tm0 ts = do   tm <- declareAllTypes tm0 ts-  (ts',_) <- foldr (update tm) (return ([],Map.keysSet tm0)) ts-  return ts'+  fmap fst $ update tm (Map.keysSet tm0) ts   where-    update tm t u = do-      (_,ta) <- u+    update tm ta (t:ts2) = do       if getCategoryName t `Set.member` ta-         then u+         then update tm ta ts2          else do-          refines <- collectAllOrErrorM $-                    map (\r -> getCategory tm (vrContext r,tiName $ vrType r)) $ getCategoryRefines t-          defines <- collectAllOrErrorM $-                    map (\d -> getCategory tm (vdContext d,diName $ vdType d)) $ getCategoryDefines t-          (ts',ta') <- foldr (update tm) u (map snd $ refines ++ defines)-          let ts'' = ts' ++ [t]-          let ta'' = Set.insert (getCategoryName t) ta'-          return (ts'',ta'')+           refines <- mapErrorsM (\r -> getCategory tm (vrContext r,tiName $ vrType r)) $ getCategoryRefines t+           defines <- mapErrorsM (\d -> getCategory tm (vdContext d,diName $ vdType d)) $ getCategoryDefines t+           (ts3,ta2) <- update tm (getCategoryName t `Set.insert` ta) (map snd $ refines ++ defines)+           (ts4,ta3) <- update tm ta2 ts2+           return (ts3 ++ [t] ++ ts4,ta3)+    update _ ta _ = return ([],ta)  mergeObjects :: (MergeableM m, CompileErrorM m) =>   (a -> a -> m ()) -> [a] -> m [a]-mergeObjects f = return . merge [] where-  merge cs [] = cs-  merge cs (x:xs) = merge (cs ++ ys) xs where-    -- TODO: Should f just perform merging? In case we want to preserve info-    -- about what was merged, e.g., return m [(p,a)].-    checker x2 = f x2 x-    ys = if isCompileError $ mergeAnyM (map checker (cs ++ xs))-            then [x] -- x is not redundant => keep.-            else []  -- x is redundant => remove.+mergeObjects f = merge [] where+  merge cs [] = return cs+  merge cs (x:xs) = do+    ys <- collectOneOrErrorM $ map check (cs ++ xs) ++ [return [x]]+    merge (cs ++ ys) xs where+      check x2 = x2 `f` x >> return []  mergeRefines :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> [ValueRefine c] -> m [ValueRefine c] mergeRefines r f = mergeObjects check where   check (ValueRefine _ t1@(TypeInstance n1 _)) (ValueRefine _ t2@(TypeInstance n2 _))-    | n1 /= n2 = compileError $ show t1 ++ " and " ++ show t2 ++ " are incompatible"-    | otherwise = do-      checkGeneralMatch r f Covariant (SingleType $ JustTypeInstance $ t1)-                                      (SingleType $ JustTypeInstance $ t2)+    | n1 /= n2 = compileErrorM $ show t1 ++ " and " ++ show t2 ++ " are incompatible"+    | otherwise =+      noInferredTypes $ checkGeneralMatch r f Covariant+                        (SingleType $ JustTypeInstance $ t1)+                        (SingleType $ JustTypeInstance $ t2)  mergeDefines :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> [ValueDefine c] -> m [ValueDefine c] mergeDefines r f = mergeObjects check where   check (ValueDefine _ t1@(DefinesInstance n1 _)) (ValueDefine _ t2@(DefinesInstance n2 _))-    | n1 /= n2 = compileError $ show t1 ++ " and " ++ show t2 ++ " are incompatible"+    | n1 /= n2 = compileErrorM $ show t1 ++ " and " ++ show t2 ++ " are incompatible"     | otherwise = do       checkDefinesMatch r f t1 t2       return ()@@ -723,7 +717,7 @@   mergeAllM $ map checkCount $ groupBy (\x y -> fst x == fst y) $                                sortBy (\x y -> fst x `compare` fst y) ns where     checkCount xa@(x:_:_) =-      compileError $ "Category " ++ show (fst x) ++ " occurs " ++ show (length xa) +++      compileErrorM $ "Category " ++ show (fst x) ++ " occurs " ++ show (length xa) ++                       " times in " ++ show n ++ formatFullContextBrace c ++ " :\n---\n" ++                       intercalate "\n---\n" (map (show . snd) xa)     checkCount _ = return ()@@ -742,21 +736,21 @@       t' <- preMergeSingle tm t       return $ Map.insert (getCategoryName t') t' tm     preMergeSingle tm (ValueInterface c ns n ps rs vs fs) = do-      rs' <- fmap concat $ collectAllOrErrorM $ map (getRefines tm) rs+      rs' <- fmap concat $ mapErrorsM (getRefines tm) rs       return $ ValueInterface c ns n ps rs' vs fs     preMergeSingle tm (ValueConcrete c ns n ps rs ds vs fs) = do-      rs' <- fmap concat $ collectAllOrErrorM $ map (getRefines tm) rs+      rs' <- fmap concat $ mapErrorsM (getRefines tm) rs       return $ ValueConcrete c ns n ps rs' ds vs fs     preMergeSingle _ t = return t     update r t u = do       (ts2,tm) <- u-      t' <- updateSingle r tm t `reviseError`+      t' <- updateSingle r tm t `reviseErrorM`               ("In category " ++ show (getCategoryName t) ++                formatFullContextBrace (getCategoryContext t))       return (ts2 ++ [t'],Map.insert (getCategoryName t') t' tm)     updateSingle r tm t@(ValueInterface c ns n ps rs vs fs) = do       let fm = getCategoryFilterMap t-      rs' <- fmap concat $ collectAllOrErrorM $ map (getRefines tm) rs+      rs' <- fmap concat $ mapErrorsM (getRefines tm) rs       rs'' <- mergeRefines r fm rs'       noDuplicateRefines c n rs''       checkMerged r fm rs rs''@@ -766,7 +760,7 @@     -- TODO: Remove duplication below and/or have separate tests.     updateSingle r tm t@(ValueConcrete c ns n ps rs ds vs fs) = do       let fm = getCategoryFilterMap t-      rs' <- fmap concat $ collectAllOrErrorM $ map (getRefines tm) rs+      rs' <- fmap concat $ mapErrorsM (getRefines tm) rs       rs'' <- mergeRefines r fm rs'       noDuplicateRefines c n rs''       checkMerged r fm rs rs''@@ -780,7 +774,7 @@       (_,v) <- getValueCategory tm (c,n)       let refines = getCategoryRefines v       pa <- assignParams tm c t-      fmap (ra:) $ collectAllOrErrorM $ map (subAll c pa) refines+      fmap (ra:) $ mapErrorsM (subAll c pa) refines     subAll c pa (ValueRefine c1 t1) = do       (SingleType (JustTypeInstance t2)) <-         uncheckedSubInstance (getValueForParam pa) (SingleType (JustTypeInstance t1))@@ -794,9 +788,10 @@       let rm = Map.fromList $ map (\t -> (tiName $ vrType t,t)) rs       mergeAllM $ map (\t -> checkConvert r fm (tiName (vrType t) `Map.lookup` rm) t) rs2     checkConvert r fm (Just ta1@(ValueRefine _ t1)) ta2@(ValueRefine _ t2) = do-      checkGeneralMatch r fm Covariant (SingleType $ JustTypeInstance t1)-                                       (SingleType $ JustTypeInstance t2) `reviseError`-        ("Cannot refine " ++ show ta1 ++ " from inherited " ++ show ta2)+      noInferredTypes $ checkGeneralMatch r fm Covariant+                        (SingleType $ JustTypeInstance t1)+                        (SingleType $ JustTypeInstance t2) `reviseErrorM`+                        ("Cannot refine " ++ show ta1 ++ " from inherited " ++ show ta2)       return ()     checkConvert _ _ _ _ = return () @@ -804,39 +799,39 @@   r -> CategoryMap c -> ParamFilters -> [ValueRefine c] ->   [ValueDefine c] -> [ScopedFunction c] -> m [ScopedFunction c] mergeFunctions r tm fm rs ds fs = do-  inheritValue <- fmap concat $ collectAllOrErrorM $ map (getRefinesFuncs tm) rs-  inheritType  <- fmap concat $ collectAllOrErrorM $ map (getDefinesFuncs tm) ds+  inheritValue <- fmap concat $ mapErrorsM (getRefinesFuncs tm) rs+  inheritType  <- fmap concat $ mapErrorsM (getDefinesFuncs tm) ds   let inheritByName  = Map.fromListWith (++) $ map (\f -> (sfName f,[f])) $ inheritValue ++ inheritType   let explicitByName = Map.fromListWith (++) $ map (\f -> (sfName f,[f])) fs   let allNames = Set.toList $ Set.union (Map.keysSet inheritByName) (Map.keysSet explicitByName)-  collectAllOrErrorM $ map (mergeByName r fm inheritByName explicitByName) allNames where-    getRefinesFuncs tm2 ra@(ValueRefine c (TypeInstance n ts2)) = flip reviseError (show ra) $ do+  mapErrorsM (mergeByName r fm inheritByName explicitByName) allNames where+    getRefinesFuncs tm2 ra@(ValueRefine c (TypeInstance n ts2)) = flip reviseErrorM (show ra) $ do       (_,t) <- getValueCategory tm2 (c,n)       let ps = map vpParam $ getCategoryParams t       let fs2 = getCategoryFunctions t       paired <- processPairs alwaysPair (Positional ps) ts2       let assigned = Map.fromList paired-      collectAllOrErrorM (map (uncheckedSubFunction assigned) fs2)-    getDefinesFuncs tm2 da@(ValueDefine c (DefinesInstance n ts2)) = flip reviseError (show da) $  do+      mapErrorsM (uncheckedSubFunction assigned) fs2+    getDefinesFuncs tm2 da@(ValueDefine c (DefinesInstance n ts2)) = flip reviseErrorM (show da) $  do       (_,t) <- getInstanceCategory tm2 (c,n)       let ps = map vpParam $ getCategoryParams t       let fs2 = getCategoryFunctions t       paired <- processPairs alwaysPair (Positional ps) ts2       let assigned = Map.fromList paired-      collectAllOrErrorM (map (uncheckedSubFunction assigned) fs2)+      mapErrorsM (uncheckedSubFunction assigned) fs2     mergeByName r2 fm2 im em n =       tryMerge r2 fm2 n (n `Map.lookup` im) (n `Map.lookup` em)     -- Inherited without an override.     tryMerge _ _ n (Just is) Nothing       | length is == 1 = return $ head is-      | otherwise = compileError $ "Function " ++ show n ++ " is inherited " +++      | otherwise = compileErrorM $ "Function " ++ show n ++ " is inherited " ++                                    show (length is) ++ " times:\n---\n" ++                                    intercalate "\n---\n" (map show is)     -- Not inherited.     tryMerge r2 fm2 n Nothing es = tryMerge r2 fm2 n (Just []) es     -- Explicit override, possibly inherited.     tryMerge r2 fm2 n (Just is) (Just es)-      | length es /= 1 = compileError $ "Function " ++ show n ++ " is declared " +++      | length es /= 1 = compileErrorM $ "Function " ++ show n ++ " is declared " ++                                         show (length es) ++ " times:\n---\n" ++                                         intercalate "\n---\n" (map show es)       | otherwise = do@@ -846,11 +841,11 @@         where           checkMerge r3 fm3 f1 f2             | sfScope f1 /= sfScope f2 =-              compileError $ "Cannot merge " ++ show (sfScope f2) ++ " with " +++              compileErrorM $ "Cannot merge " ++ show (sfScope f2) ++ " with " ++                              show (sfScope f1) ++ " in function merge:\n---\n" ++                              show f2 ++ "\n  ->\n" ++ show f1             | otherwise =-              flip reviseError ("In function merge:\n---\n" ++ show f2 +++              flip reviseErrorM ("In function merge:\n---\n" ++ show f2 ++                                 "\n  ->\n" ++ show f1 ++ "\n---\n") $ do                 f1' <- parsedToFunctionType f1                 f2' <- parsedToFunctionType f2@@ -933,7 +928,7 @@     pa = Set.fromList $ map vpParam $ pValues ps     checkFilter f =       when (not $ (pfParam f) `Set.member` pa) $-      compileError $ "Filtered param " ++ show (pfParam f) +++      compileErrorM $ "Filtered param " ++ show (pfParam f) ++                      " is not defined for function " ++ show n ++                      formatFullContextBrace c     getFilters fm2 n2 =@@ -944,13 +939,13 @@ uncheckedSubFunction :: (Show c, MergeableM m, CompileErrorM m) =>   Map.Map ParamName GeneralInstance -> ScopedFunction c -> m (ScopedFunction c) uncheckedSubFunction pa ff@(ScopedFunction c n t s as rs ps fa ms) =-  flip reviseError ("In function:\n---\n" ++ show ff ++ "\n---\n") $ do+  flip reviseErrorM ("In function:\n---\n" ++ show ff ++ "\n---\n") $ do     let fixed = Map.fromList $ map (\n2 -> (n2,SingleType $ JustParamName n2)) $ map vpParam $ pValues ps     let pa' = Map.union pa fixed-    as' <- fmap Positional $ collectAllOrErrorM $ map (subPassed pa') $ pValues as-    rs' <- fmap Positional $ collectAllOrErrorM $ map (subPassed pa') $ pValues rs-    fa' <- collectAllOrErrorM $ map (subFilter pa') fa-    ms' <- collectAllOrErrorM $ map (uncheckedSubFunction pa) ms+    as' <- fmap Positional $ mapErrorsM (subPassed pa') $ pValues as+    rs' <- fmap Positional $ mapErrorsM (subPassed pa') $ pValues rs+    fa' <- mapErrorsM (subFilter pa') fa+    ms' <- mapErrorsM (uncheckedSubFunction pa) ms     return $ (ScopedFunction c n t s as' rs' ps fa' ms')     where       subPassed pa2 (PassedValue c2 t2) = do@@ -959,3 +954,59 @@       subFilter pa2 (ParamFilter c2 n2 f) = do         f' <- uncheckedSubFilter (getValueForParam pa2) f         return $ ParamFilter c2 n2 f'++inferParamTypes :: (MergeableM m, CompileErrorM m, TypeResolver r) =>+  r -> ParamFilters -> Map.Map ParamName GeneralInstance ->+  [(ValueType,ValueType)] -> m (Map.Map ParamName GeneralInstance)+inferParamTypes r f ps ts = do+  ts2 <- mapErrorsM subAll ts+  f2  <- fmap Map.fromList $ mapErrorsM filterSub $ Map.toList f+  gs  <- mergeAllM $ map (uncurry $ checkValueTypeMatch r f2) ts2+  let gs2 = concat $ map (filtersToGuess f2) $ Map.elems ps+  let gs3 = mergeAll $ gs:(map mergeLeaf gs2)+  gs4 <- mergeInferredTypes r f2 gs3+  let ga = Map.fromList $ zip (map itgParam gs4) (map itgGuess gs4)+  return $ ga `Map.union` ps where+    subAll (t1,t2) = do+      t2' <- uncheckedSubValueType (getValueForParam ps) t2+      return (t1,t2')+    filterSub (k,fs) = do+      fs' <- mapErrorsM (uncheckedSubFilter (getValueForParam ps)) fs+      return (k,fs')+    filtersToGuess f2 (SingleType (JustInferredType p)) =+      case p `Map.lookup` f2 of+           Nothing -> []+           Just fs -> concat $ map (filterToGuess p) fs+    filtersToGuess _ _ = []+    filterToGuess p (TypeFilter FilterRequires t) =+      [InferredTypeGuess p (SingleType t) Contravariant]+    filterToGuess p (TypeFilter FilterAllows t) =+      [InferredTypeGuess p (SingleType t) Covariant]+    filterToGuess _ _ = []++mergeInferredTypes :: (MergeableM m, CompileErrorM m, TypeResolver r) =>+  r -> ParamFilters -> MergeTree InferredTypeGuess -> m [InferredTypeGuess]+mergeInferredTypes r f = reduceMergeTree anyOp allOp leafOp where+  leafOp i = noInferred (itgGuess i) >> return [i]+  anyOp = mergeCommon anyCheck+  allOp = mergeCommon allCheck+  mergeCommon check is = do+    let ia = Map.fromListWith (++) $ zip (map itgParam is) (map (:[]) is)+    mergeAllM $ map (tryMerge check) $ Map.toList ia+  tryMerge check (i,is) = do+    is' <- mergeObjects check is+    case is' of+         []   -> undefined  -- Shouldn't happen.+         [i2] -> return [i2]+         is2  -> compileErrorM $ "Could not reconcile guesses for " ++ show i +++                                 ": " ++ show is2+  noInferred (TypeMerge _ ts) = mergeAllM $ map noInferred ts+  noInferred (SingleType (JustTypeInstance (TypeInstance _ (Positional ts)))) = mergeAllM $ map noInferred ts+  noInferred (SingleType (JustInferredType i)) = compileErrorM $ "Failed to infer " ++ show i+  noInferred _ = return ()+  anyCheck (InferredTypeGuess _ g1 v1) (InferredTypeGuess _ g2 _) =+    -- Find the least-general guess: If g1 can be replaced with g2, prefer g1.+    noInferredTypes $ checkGeneralMatch r f v1 g1 g2+  allCheck (InferredTypeGuess _ g1 _) (InferredTypeGuess _ g2 v2) =+    -- Find the most-general guess: If g2 can be replaced with g1, prefer g1.+    noInferredTypes $ checkGeneralMatch r f v2 g2 g1
src/Types/TypeInstance.hs view
@@ -26,6 +26,7 @@   DefinesInstance(..),   FilterDirection(..),   GeneralInstance,+  InferredTypeGuess(..),   InstanceFilters,   InstanceParams,   InstanceVariances,@@ -41,6 +42,7 @@   checkDefinesMatch,   checkGeneralMatch,   checkValueTypeMatch,+  checkValueTypeMatch_,   uncheckedSubFilter,   uncheckedSubFilters,   uncheckedSubInstance,@@ -50,6 +52,7 @@   isDefinesFilter,   isRequiresFilter,   isWeakValue,+  noInferredTypes,   requiredParam,   requiredSingleton,   validateAssignment,@@ -61,11 +64,12 @@   validateTypeInstance, ) where -import Control.Monad (when)+import Control.Monad ((>=>),when) import Data.List (intercalate) import qualified Data.Map as Map  import Base.CompileError+import Base.MergeTree import Base.Mergeable import Types.GeneralType import Types.Positional@@ -172,18 +176,33 @@   show (DefinesInstance n (Positional ts)) =     show n ++ "<" ++ intercalate "," (map show ts) ++ ">" +data InferredTypeGuess =+  InferredTypeGuess {+    itgParam :: ParamName,+    itgGuess :: GeneralInstance,+    itgVariance :: Variance+  }+  deriving (Eq,Ord)++instance Show InferredTypeGuess where+  show (InferredTypeGuess n g v) = show n ++ " = " ++ show g ++ " (" ++ show v ++ ")"+ data TypeInstanceOrParam =   JustTypeInstance {     jtiType :: TypeInstance   } |   JustParamName {     jpnName :: ParamName+  } |+  JustInferredType {+    jitParam :: ParamName   }   deriving (Eq,Ord)  instance Show TypeInstanceOrParam where   show (JustTypeInstance t) = show t   show (JustParamName n)    = show n+  show (JustInferredType i) = show i ++ " /*inferred*/"  data FilterDirection =   FilterRequires |@@ -261,38 +280,58 @@   ParamFilters -> ParamName -> m [TypeFilter] filterLookup ps n = resolve $ n `Map.lookup` ps where   resolve (Just x) = return x-  resolve _        = compileError $ "Param " ++ show n ++ " not found"+  resolve _        = compileErrorM $ "Param " ++ show n ++ " not found"  getValueForParam :: (CompileErrorM m) =>   Map.Map ParamName GeneralInstance -> ParamName -> m GeneralInstance getValueForParam pa n =   case n `Map.lookup` pa of         (Just x) -> return x-        _ -> compileError $ "Param " ++ show n ++ " does not exist"+        _ -> compileErrorM $ "Param " ++ show n ++ " does not exist" -checkValueTypeMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) =>+noInferredTypes :: (MergeableM m, CompileErrorM m) => m (MergeTree InferredTypeGuess) -> m ()+noInferredTypes = id >=> reduceMergeTree return return message where+  message i = compileErrorM $ "Type guess " ++ show i ++ " not allowed here"++checkValueTypeMatch_ :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> ValueType -> ValueType -> m ()+checkValueTypeMatch_ r f t1 t2 = noInferredTypes $ checkValueTypeMatch r f t1 t2++checkValueTypeMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) =>+  r -> ParamFilters -> ValueType -> ValueType -> m (MergeTree InferredTypeGuess) checkValueTypeMatch r f ts1@(ValueType r1 t1) ts2@(ValueType r2 t2)   | r1 < r2 =-    compileError $ "Cannot convert " ++ show ts1 ++ " to " ++ show ts2-  | otherwise = checkGeneralMatch r f Covariant t1 t2 `reviseError`+    compileErrorM $ "Cannot convert " ++ show ts1 ++ " to " ++ show ts2+  | otherwise = checkGeneralMatch r f Covariant t1 t2 `reviseErrorM`       ("Cannot convert " ++ show ts1 ++ " to " ++ show ts2)  checkGeneralMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> Variance ->-  GeneralInstance -> GeneralInstance -> m ()-checkGeneralMatch r f Invariant ts1 ts2 = do+  GeneralInstance -> GeneralInstance -> m (MergeTree InferredTypeGuess)+checkGeneralMatch r f v (SingleType (JustInferredType p1)) t2 = do+  compileWarningM $ "Treating inferred parameter " ++ show p1 ++ " on the left as a regular parameter"+  checkGeneralMatch r f v (SingleType $ JustParamName p1) t2+checkGeneralMatch _ _ v t1 (SingleType (JustInferredType p2)) =+  return $ mergeLeaf $ InferredTypeGuess p2 t1 v+checkGeneralMatch r f Invariant ts1 ts2 =   -- This ensures that any and all behave as expected in Invariant positions.-  checkGeneralType (checkSingleMatch r f Covariant) ts1 ts2-  checkGeneralType (checkSingleMatch r f Covariant) ts2 ts1+  mergeAllM [checkGeneralMatch r f Covariant     ts1 ts2,+             checkGeneralMatch r f Contravariant ts1 ts2] checkGeneralMatch r f Contravariant ts1 ts2 =-  checkGeneralType (checkSingleMatch r f Covariant) ts2 ts1-checkGeneralMatch r f Covariant ts1 ts2 =-  checkGeneralType (checkSingleMatch r f Covariant) ts1 ts2+  -- NOTE: ts1 and ts2 can't be swapped in checkSingleMatch due to type+  -- inference; however, checkGeneralType is sensitive to which side the empty+  -- union or intersection is on.+  checkGeneralType (flip $ checkSingleMatch r f Contravariant) ts2 ts1+checkGeneralMatch r f v ts1 ts2 = checkGeneralType (checkSingleMatch r f v) ts1 ts2  checkSingleMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> Variance ->-  TypeInstanceOrParam -> TypeInstanceOrParam -> m ()+  TypeInstanceOrParam -> TypeInstanceOrParam -> m (MergeTree InferredTypeGuess)+checkSingleMatch r f v (JustInferredType p1) t2 = do+  compileWarningM $ "Treating inferred parameter " ++ show p1 ++ " on the left as a regular parameter"+  checkSingleMatch r f v (JustParamName p1) t2+checkSingleMatch _ _ v t1 (JustInferredType p2) =+  return $ mergeLeaf $ InferredTypeGuess p2 (SingleType t1) v checkSingleMatch r f v (JustTypeInstance t1) (JustTypeInstance t2) =   checkInstanceToInstance r f v t1 t2 checkSingleMatch r f v (JustParamName p1) (JustTypeInstance t2) =@@ -303,80 +342,105 @@   checkParamToParam r f v p1 p2  checkInstanceToInstance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>-  r -> ParamFilters -> Variance -> TypeInstance -> TypeInstance -> m ()+  r -> ParamFilters -> Variance -> TypeInstance -> TypeInstance -> m (MergeTree InferredTypeGuess) checkInstanceToInstance r f Invariant t1 t2     | t1 == t2 = mergeDefaultM     | otherwise =       -- Implicit equality, inferred by t1 <-> t2.       mergeAllM [checkInstanceToInstance r f Covariant     t1 t2,                  checkInstanceToInstance r f Contravariant t1 t2]-checkInstanceToInstance r f Contravariant t1 t2 =-  checkInstanceToInstance r f Covariant t2 t1+checkInstanceToInstance r f Contravariant t1@(TypeInstance n1 ps1) t2@(TypeInstance n2 ps2)+  | n1 == n2 = do+    paired <- processPairs alwaysPair ps1 ps2+    let zipped = Positional paired+    variance <- fmap (fmap (composeVariance Contravariant)) $ trVariance r n1+    processPairsM (\v2 (p1,p2) -> checkGeneralMatch r f v2 p1 p2) variance zipped+  | otherwise = do+    ps2' <- trRefines r t2 n1+    checkInstanceToInstance r f Contravariant t1 (TypeInstance n1 ps2') checkInstanceToInstance r f Covariant t1@(TypeInstance n1 ps1) t2@(TypeInstance n2 ps2)   | n1 == n2 = do     paired <- processPairs alwaysPair ps1 ps2     let zipped = Positional paired-    variance <- trVariance r n1-    -- NOTE: Covariant is identity, so v2 has technically been composed with it.-    processPairs_ (\v2 (p1,p2) -> checkGeneralMatch r f v2 p1 p2) variance zipped >> mergeDefaultM+    variance <- fmap (fmap (composeVariance Covariant)) $ trVariance r n1+    processPairsM (\v2 (p1,p2) -> checkGeneralMatch r f v2 p1 p2) variance zipped   | otherwise = do     ps1' <- trRefines r t1 n2     checkInstanceToInstance r f Covariant (TypeInstance n2 ps1') t2  checkParamToInstance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>-  r -> ParamFilters -> Variance -> ParamName -> TypeInstance -> m ()+  r -> ParamFilters -> Variance -> ParamName -> TypeInstance -> m (MergeTree InferredTypeGuess) checkParamToInstance r f Invariant n1 t2 =   -- Implicit equality, inferred by n1 <-> t2.   mergeAllM [checkParamToInstance r f Covariant     n1 t2,              checkParamToInstance r f Contravariant n1 t2]-checkParamToInstance r f Contravariant p1 t2 =-  checkInstanceToParam r f Covariant t2 p1-checkParamToInstance r f Covariant n1 t2@(TypeInstance _ _) = do+checkParamToInstance r f v@Contravariant n1 t2@(TypeInstance _ _) = do+  cs2 <- fmap (filter isTypeFilter) $ f `filterLookup` n1+  mergeAnyM (map checkConstraintToInstance cs2) `reviseErrorM`+    ("No filters imply " ++ show t2 ++ " <- " ++ show n1 ++ " in " ++ show v ++ " contexts")+  where+    checkConstraintToInstance (TypeFilter FilterAllows t) =+      -- F -> x implies T -> x only if T -> F+      checkSingleMatch r f v t (JustTypeInstance t2)+    checkConstraintToInstance f2 =+      -- x -> F cannot imply T -> x+      compileErrorM $ "Constraint " ++ viewTypeFilter n1 f2 +++                      " does not imply " ++ show t2 ++ " <- " ++ show n1+checkParamToInstance r f v@Covariant n1 t2@(TypeInstance _ _) = do   cs1 <- fmap (filter isTypeFilter) $ f `filterLookup` n1-  mergeAnyM (map checkConstraintToInstance cs1) `reviseError`-    ("No filters imply " ++ show n1 ++ " -> " ++ show t2)+  mergeAnyM (map checkConstraintToInstance cs1) `reviseErrorM`+    ("No filters imply " ++ show n1 ++ " -> " ++ show t2 ++ " in " ++ show v ++ " contexts")   where     checkConstraintToInstance (TypeFilter FilterRequires t) =       -- x -> F implies x -> T only if F -> T-      checkSingleMatch r f Covariant t (JustTypeInstance t2)+      checkSingleMatch r f v t (JustTypeInstance t2)     checkConstraintToInstance f2 =       -- F -> x cannot imply x -> T       -- DefinesInstance cannot be converted to TypeInstance-      compileError $ "Constraint " ++ viewTypeFilter n1 f2 ++-                    " does not imply " ++ show n1 ++ " -> " ++ show t2+      compileErrorM $ "Constraint " ++ viewTypeFilter n1 f2 +++                      " does not imply " ++ show n1 ++ " -> " ++ show t2  checkInstanceToParam :: (MergeableM m, CompileErrorM m, TypeResolver r) =>-  r -> ParamFilters -> Variance -> TypeInstance -> ParamName -> m ()+  r -> ParamFilters -> Variance -> TypeInstance -> ParamName -> m (MergeTree InferredTypeGuess) checkInstanceToParam r f Invariant t1 n2 =   -- Implicit equality, inferred by t1 <-> n2.   mergeAllM [checkInstanceToParam r f Covariant     t1 n2,              checkInstanceToParam r f Contravariant t1 n2]-checkInstanceToParam r f Contravariant t1 p2 =-  checkParamToInstance r f Covariant p2 t1-checkInstanceToParam r f Covariant t1@(TypeInstance _ _) n2 = do+checkInstanceToParam r f v@Contravariant t1@(TypeInstance _ _) n2 = do+  cs1 <- fmap (filter isTypeFilter) $ f `filterLookup` n2+  mergeAnyM (map checkInstanceToConstraint cs1) `reviseErrorM`+    ("No filters imply " ++ show n2 ++ " <- " ++ show t1 ++ " in " ++ show v ++ " contexts")+  where+    checkInstanceToConstraint (TypeFilter FilterRequires t) =+      -- x -> F implies x -> T only if F -> T+      checkSingleMatch r f v (JustTypeInstance t1) t+    checkInstanceToConstraint f2 =+      -- F -> x cannot imply x -> T+      -- DefinesInstance cannot be converted to TypeInstance+      compileErrorM $ "Constraint " ++ viewTypeFilter n2 f2 +++                      " does not imply " ++ show n2 ++ " <- " ++ show t1+checkInstanceToParam r f v@Covariant t1@(TypeInstance _ _) n2 = do   cs2 <- fmap (filter isTypeFilter) $ f `filterLookup` n2-  mergeAnyM (map checkInstanceToConstraint cs2) `reviseError`-    ("No filters imply " ++ show t1 ++ " -> " ++ show n2)+  mergeAnyM (map checkInstanceToConstraint cs2) `reviseErrorM`+    ("No filters imply " ++ show t1 ++ " -> " ++ show n2 ++ " in " ++ show v ++ " contexts")   where     checkInstanceToConstraint (TypeFilter FilterAllows t) =       -- F -> x implies T -> x only if T -> F-      checkSingleMatch r f Covariant (JustTypeInstance t1) t+      checkSingleMatch r f v (JustTypeInstance t1) t     checkInstanceToConstraint f2 =       -- x -> F cannot imply T -> x-      compileError $ "Constraint " ++ viewTypeFilter n2 f2 ++-                    " does not imply " ++ show t1 ++ " -> " ++ show n2+      compileErrorM $ "Constraint " ++ viewTypeFilter n2 f2 +++                      " does not imply " ++ show t1 ++ " -> " ++ show n2  checkParamToParam :: (MergeableM m, CompileErrorM m, TypeResolver r) =>-  r -> ParamFilters -> Variance -> ParamName -> ParamName -> m ()+  r -> ParamFilters -> Variance -> ParamName -> ParamName -> m (MergeTree InferredTypeGuess) checkParamToParam r f Invariant n1 n2     | n1 == n2 = mergeDefaultM     | otherwise =       -- Implicit equality, inferred by n1 <-> n2.       mergeAllM [checkParamToParam r f Covariant     n1 n2,                  checkParamToParam r f Contravariant n1 n2]-checkParamToParam r f Contravariant n1 n2 =-  checkParamToParam r f Covariant n2 n1-checkParamToParam r f Covariant n1 n2+checkParamToParam r f v n1 n2   | n1 == n2 = mergeDefaultM   | otherwise = do     cs1 <- fmap (filter isTypeFilter) $ f `filterLookup` n1@@ -384,44 +448,59 @@     let typeFilters = [(c1,c2) | c1 <- cs1, c2 <- cs2] ++                       [(self1,c2) | c2 <- cs2] ++                       [(c1,self2) | c1 <- cs1]-    mergeAnyM (map (\(c1,c2) -> checkConstraintToConstraint c1 c2) typeFilters) `reviseError`+    mergeAnyM (map (\(c1,c2) -> checkConstraintToConstraint v c1 c2) typeFilters) `reviseErrorM`       ("No filters imply " ++ show n1 ++ " -> " ++ show n2)     where-      self1 = TypeFilter FilterRequires (JustParamName n1)-      self2 = TypeFilter FilterAllows   (JustParamName n2)-      checkConstraintToConstraint (TypeFilter FilterRequires t1) (TypeFilter FilterAllows t2)+      self1+        | v == Covariant = TypeFilter FilterRequires (JustParamName n1)+        | otherwise      = TypeFilter FilterAllows   (JustParamName n1)+      self2+        | v == Covariant = TypeFilter FilterAllows   (JustParamName n2)+        | otherwise      = TypeFilter FilterRequires (JustParamName n2)+      checkConstraintToConstraint Covariant (TypeFilter FilterRequires t1) (TypeFilter FilterAllows t2)         | t1 == (JustParamName n1) && t2 == (JustParamName n2) =-          compileError $ "Infinite recursion in " ++ show n1 ++ " -> " ++ show n2+          compileErrorM $ "Infinite recursion in " ++ show n1 ++ " -> " ++ show n2         -- x -> F1, F2 -> y implies x -> y only if F1 -> F2         | otherwise = checkSingleMatch r f Covariant t1 t2-      checkConstraintToConstraint f1 f2 =+      checkConstraintToConstraint Covariant f1 f2 =         -- x -> F1, y -> F2 cannot imply x -> y         -- F1 -> x, F1 -> y cannot imply x -> y         -- F1 -> x, y -> F2 cannot imply x -> y-        compileError $ "Constraints " ++ viewTypeFilter n1 f1 ++ " and " ++-                      viewTypeFilter n2 f2 ++ " do not imply " ++-                      show n1 ++ " -> " ++ show n2+        compileErrorM $ "Constraints " ++ viewTypeFilter n1 f1 ++ " and " +++                        viewTypeFilter n2 f2 ++ " do not imply " +++                        show n1 ++ " -> " ++ show n2+      checkConstraintToConstraint Contravariant (TypeFilter FilterAllows t1) (TypeFilter FilterRequires t2)+        | t1 == (JustParamName n1) && t2 == (JustParamName n2) =+          compileErrorM $ "Infinite recursion in " ++ show n1 ++ " <- " ++ show n2+        -- x <- F1, F2 <- y implies x <- y only if F1 <- F2+        | otherwise = checkSingleMatch r f Contravariant t1 t2+      checkConstraintToConstraint Contravariant f1 f2 =+        -- x <- F1, y <- F2 cannot imply x <- y+        -- F1 <- x, F1 <- y cannot imply x <- y+        -- F1 <- x, y <- F2 cannot imply x <- y+        compileErrorM $ "Constraints " ++ viewTypeFilter n1 f1 ++ " and " +++                        viewTypeFilter n2 f2 ++ " do not imply " +++                        show n1 ++ " <- " ++ show n2+      checkConstraintToConstraint _ _ _ = undefined  validateGeneralInstance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> GeneralInstance -> m ()-validateGeneralInstance _ _ (TypeMerge _ ts)-  | length ts == 1 = compileError $ "Unions and intersections must have at least 2 types to avoid ambiguity"-validateGeneralInstance r f (TypeMerge MergeIntersect ts) =-  mergeAllM (map (validateGeneralInstance r f) ts)-validateGeneralInstance r f (TypeMerge _ ts) =-  mergeAllM (map (validateGeneralInstance r f) ts)+validateGeneralInstance r f (TypeMerge _ ts)+  | length ts == 1 = compileErrorM $ "Unions and intersections must have at least 2 types to avoid ambiguity"+  | otherwise      = mergeAllM (map (validateGeneralInstance r f) ts) validateGeneralInstance r f (SingleType (JustTypeInstance t)) =   validateTypeInstance r f t validateGeneralInstance _ f (SingleType (JustParamName n)) =   when (not $ n `Map.member` f) $-    compileError $ "Param " ++ show n ++ " does not exist"+    compileErrorM $ "Param " ++ show n ++ " does not exist"+validateGeneralInstance _ _ t = compileErrorM $ "Type " ++ show t ++ " contains unresolved types"  validateTypeInstance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> TypeInstance -> m () validateTypeInstance r f t@(TypeInstance _ ps) = do   fa <- trTypeFilters r t   processPairs_ (validateAssignment r f) ps fa-  mergeAllM (map (validateGeneralInstance r f) (pValues ps)) `reviseError`+  mergeAllM (map (validateGeneralInstance r f) (pValues ps)) `reviseErrorM`     ("Recursive error in " ++ show t)  validateDefinesInstance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>@@ -429,7 +508,7 @@ validateDefinesInstance r f t@(DefinesInstance _ ps) = do   fa <- trDefinesFilters r t   processPairs_ (validateAssignment r f) ps fa-  mergeAllM (map (validateGeneralInstance r f) (pValues ps)) `reviseError`+  mergeAllM (map (validateGeneralInstance r f) (pValues ps)) `reviseErrorM`     ("Recursive error in " ++ show t)  validateTypeFilter :: (MergeableM m, CompileErrorM m, TypeResolver r) =>@@ -442,20 +521,21 @@ validateAssignment :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> GeneralInstance -> [TypeFilter] -> m () validateAssignment r f t fs = mergeAllM (map (checkFilter t) fs) where-  checkFilter t1 (TypeFilter FilterRequires t2) = do-    checkGeneralMatch r f Covariant t1 (SingleType t2)-  checkFilter t1 (TypeFilter FilterAllows t2) = do-    checkGeneralMatch r f Contravariant t1 (SingleType t2)+  checkFilter t1 (TypeFilter FilterRequires t2) =+    noInferredTypes $ checkGeneralMatch r f Covariant t1 (SingleType t2)+  checkFilter t1 (TypeFilter FilterAllows t2) =+    noInferredTypes $ checkGeneralMatch r f Contravariant t1 (SingleType t2)   checkFilter t1@(TypeMerge _ _) (DefinesFilter t2) =-    compileError $ "Merged type " ++ show t1 ++ " cannot satisfy defines constraint " ++ show t2+    compileErrorM $ "Merged type " ++ show t1 ++ " cannot satisfy defines constraint " ++ show t2   checkFilter (SingleType t1) (DefinesFilter f2) = checkDefinesFilter f2 t1   checkDefinesFilter f2@(DefinesInstance n2 _) (JustTypeInstance t1) = do     ps1' <- trDefines r t1 n2     checkDefinesMatch r f f2 (DefinesInstance n2 ps1')   checkDefinesFilter f2 (JustParamName n1) = do       fs1 <- fmap (map dfType . filter isDefinesFilter) $ f `filterLookup` n1-      mergeAnyM (map (checkDefinesMatch r f f2) fs1) `reviseError`+      mergeAnyM (map (checkDefinesMatch r f f2) fs1) `reviseErrorM`         ("No filters imply " ++ show n1 ++ " defines " ++ show f2)+  checkDefinesFilter _ t2 = compileErrorM $ "Type " ++ show t2 ++ " contains unresolved types"  checkDefinesMatch :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamFilters -> DefinesInstance -> DefinesInstance -> m ()@@ -464,8 +544,7 @@     paired <- processPairs alwaysPair ps1 ps2     variance <- trVariance r n2     processPairs_ (\v2 (p1,p2) -> checkGeneralMatch r f v2 p1 p2) variance (Positional paired)-    mergeDefaultM-  | otherwise = compileError $ "Constraint " ++ show f1 ++ " does not imply " ++ show f2+  | otherwise = compileErrorM $ "Constraint " ++ show f1 ++ " does not imply " ++ show f2  validateInstanceVariance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamVariances -> Variance -> GeneralInstance -> m ()@@ -479,9 +558,10 @@   mergeAllM (map (validateInstanceVariance r vm v) ts) validateInstanceVariance _ vm v (SingleType (JustParamName n)) =   case n `Map.lookup` vm of-      Nothing -> compileError $ "Param " ++ show n ++ " is undefined"+      Nothing -> compileErrorM $ "Param " ++ show n ++ " is undefined"       (Just v0) -> when (not $ v0 `paramAllowsVariance` v) $-                        compileError $ "Param " ++ show n ++ " cannot be " ++ show v+                        compileErrorM $ "Param " ++ show n ++ " cannot be " ++ show v+validateInstanceVariance _ _ _ t = compileErrorM $ "Type " ++ show t ++ " contains unresolved types"  validateDefinesVariance :: (MergeableM m, CompileErrorM m, TypeResolver r) =>   r -> ParamVariances -> Variance -> DefinesInstance -> m ()@@ -500,17 +580,18 @@   (ParamName -> m GeneralInstance) -> GeneralInstance -> m GeneralInstance uncheckedSubInstance replace = subAll where   subAll (TypeMerge MergeUnion ts) = do-    gs <- collectAllOrErrorM $ map subAll ts+    gs <- mapErrorsM subAll ts     return (TypeMerge MergeUnion gs)   subAll (TypeMerge MergeIntersect ts) = do-    gs <- collectAllOrErrorM $ map subAll ts+    gs <- mapErrorsM subAll ts     return (TypeMerge MergeIntersect gs)   subAll (SingleType t) = subInstance t   subInstance (JustTypeInstance (TypeInstance n (Positional ts))) = do-    gs <- collectAllOrErrorM $ map subAll ts+    gs <- mapErrorsM subAll ts     let t2 = SingleType $ JustTypeInstance $ TypeInstance n (Positional gs)     return (t2)   subInstance (JustParamName n) = replace n+  subInstance t = compileErrorM $ "Type " ++ show t ++ " contains unresolved types"  uncheckedSubFilter :: (MergeableM m, CompileErrorM m) =>   (ParamName -> m GeneralInstance) -> TypeFilter -> m TypeFilter@@ -518,15 +599,15 @@   t' <- uncheckedSubInstance replace (SingleType t)   return (TypeFilter d (stType t')) uncheckedSubFilter replace (DefinesFilter (DefinesInstance n ts)) = do-  ts' <- collectAllOrErrorM $ map (uncheckedSubInstance replace) (pValues ts)+  ts' <- mapErrorsM (uncheckedSubInstance replace) (pValues ts)   return (DefinesFilter (DefinesInstance n (Positional ts')))  uncheckedSubFilters :: (MergeableM m, CompileErrorM m) =>   (ParamName -> m GeneralInstance) -> ParamFilters -> m ParamFilters uncheckedSubFilters replace fa = do-  fa' <- collectAllOrErrorM $ map subParam $ Map.toList fa+  fa' <- mapErrorsM subParam $ Map.toList fa   return $ Map.fromList fa'   where     subParam (n,fs) = do-      fs' <- collectAllOrErrorM $ map (uncheckedSubFilter replace) fs+      fs' <- mapErrorsM (uncheckedSubFilter replace) fs       return (n,fs')
tests/builtin-types.0rt view
@@ -285,9 +285,9 @@ define Test {   run () {     Builder<String> builder <- String$builder()-    \ Testing$check<String>(builder.build(),"")-    \ Testing$check<String>(builder.append("xyz").build(),"xyz")-    \ Testing$check<String>(builder.append("123").build(),"xyz123")+    \ Testing$check<?>(builder.build(),"")+    \ Testing$check<?>(builder.append("xyz").build(),"xyz")+    \ Testing$check<?>(builder.append("123").build(),"xyz123")   } } 
tests/check-defs/README.md view
@@ -14,9 +14,9 @@ The compiler errors should look something like this:  ```text-Compiler errors:-Public category Type ["tests/check-defs/public.0rp" (line 19, column 1)] is defined 2 times-  Defined at "tests/check-defs/private2.0rx" (line 19, column 1)-  Defined at "tests/check-defs/private1.0rx" (line 19, column 1)-Public category Undefined ["tests/check-defs/public.0rp" (line 21, column 1)] has not been defined or declared external+Zeolite execution failed.+  Category Type ["tests/check-defs/public.0rp" (line 19, column 1)] is defined 2 times+    Defined at "tests/check-defs/private2.0rx" (line 19, column 1)+    Defined at "tests/check-defs/private1.0rx" (line 19, column 1)+  Category Undefined ["tests/check-defs/public.0rp" (line 21, column 1)] has not been defined or declared external ```
tests/expr-lookup.0rt view
@@ -102,7 +102,7 @@  define Test {   run () {-    \ Testing$check<Int>($ExprLookup[INT_EXPR]$,4)+    \ Testing$check<?>($ExprLookup[INT_EXPR]$,4)   } } @@ -117,7 +117,7 @@  define Test {   run () {-    \ Testing$check<Int>(ExprLookup$intExpr(),4)+    \ Testing$check<?>(ExprLookup$intExpr(),4)   } } @@ -134,7 +134,7 @@   @category String macroLocalVar <- "hello"    run () {-    \ Testing$check<String>($ExprLookup[LOCAL_VAR]$,"hello")+    \ Testing$check<?>($ExprLookup[LOCAL_VAR]$,"hello")   } } @@ -166,7 +166,7 @@  define Test {   run () {-    \ Testing$check<Int>(ExprLookup$localVar(),99)+    \ Testing$check<?>(ExprLookup$localVar(),99)   } } @@ -181,7 +181,7 @@  define Test {   run () {-    \ Testing$check<Int>($ExprLookup[META_VAR]$,20)+    \ Testing$check<?>($ExprLookup[META_VAR]$,20)   } } @@ -196,7 +196,7 @@  define Test {   run () {-    \ Testing$check<String>($ExprLookup[INT_EXPR]$.formatted(),"4")+    \ Testing$check<?>($ExprLookup[INT_EXPR]$.formatted(),"4")   } } 
+ tests/inference.0rt view
@@ -0,0 +1,219 @@+/* -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "simple inference" {+  success Test$run()+}++define Test {+  run () {+    Int value <- get<?>(10)+  }++  @type get<#x> (#x) -> (#x)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "inference mismatch" {+  error+  require "String"+  require "Int"+}++define Test {+  run () {+    String value <- get<?>(10)+  }++  @type get<#x> (#x) -> (#x)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "nested inference" {+  success Test$run()+}++concrete Type<#x> {+  @type create () -> (Type<#x>)+}++define Type {+  create () {+    return Type<#x>{ }+  }+}++define Test {+  run () {+    Type<Int> value <- get<?>(Type<Int>$create())+  }++  @type get<#x> (Type<#x>) -> (Type<#x>)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "simple inference with qualification" {+  success Test$run()+}++define Test {+  run () {+    Int value <- Test$get<?>(10)+  }++  @type get<#x> (#x) -> (#x)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "inference mismatch with qualification" {+  error+  require "String"+  require "Int"+}++define Test {+  run () {+    String value <- Test$get<?>(10)+  }++  @type get<#x> (#x) -> (#x)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "nested inference with qualification" {+  success Test$run()+}++concrete Type<#x> {+  @type create () -> (Type<#x>)+}++define Type {+  create () {+    return Type<#x>{ }+  }+}++define Test {+  run () {+    Type<Int> value <- Test$get<?>(Type<Int>$create())+  }++  @type get<#x> (Type<#x>) -> (Type<#x>)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "inference conflict" {+  error+  require "String"+  require "Int"+}++concrete Type<#x> {+  @type create () -> (Type<#x>)+}++define Type {+  create () {+    return Type<#x>{ }+  }+}++define Test {+  run () {+    Type<Int> value <- get<?>(Type<Int>$create(),"bad")+  }++  @type get<#x> (Type<#x>,#x) -> (Type<#x>)+  get (x,_) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}+++testcase "inference from filter" {+  error+  require "Formatted"+  require "String"+  require "value2"+  exclude "value1"+}++define Test {+  run () {+    Formatted value1 <- get<?>("value")+    String    value2 <- get<?>("value")+  }++  @type get<#x>+    #x allows Formatted+  (#x) -> (#x)+  get (x) {+    return x+  }+}++concrete Test {+  @type run () -> ()+}
tests/infix-operations.0rt view
@@ -22,7 +22,7 @@  define Test {   run () {-    \ Testing$check<Int>(\x10 + 1 * 2 - 8 / 2 - 3 % 2,13)+    \ Testing$check<?>(\x10 + 1 * 2 - 8 / 2 - 3 % 2,13)   } } @@ -37,11 +37,11 @@  define Test {   run () {-    \ Testing$check<Int>(8 + 2,10)-    \ Testing$check<Int>(8 - 2,6)-    \ Testing$check<Int>(8 * 2,16)-    \ Testing$check<Int>(8 / 2,4)-    \ Testing$check<Int>(8 % 2,0)+    \ Testing$check<?>(8 + 2,10)+    \ Testing$check<?>(8 - 2,6)+    \ Testing$check<?>(8 * 2,16)+    \ Testing$check<?>(8 / 2,4)+    \ Testing$check<?>(8 % 2,0)   } } @@ -56,11 +56,11 @@  define Test {   run () {-    \ Testing$check<Int>(1 << 2,4)-    \ Testing$check<Int>(7 >> 1,3)-    \ Testing$check<Int>(7 ^ 2 ,5)-    \ Testing$check<Int>(7 & ~2,5)-    \ Testing$check<Int>(5 | 2 ,7)+    \ Testing$check<?>(1 << 2,4)+    \ Testing$check<?>(7 >> 1,3)+    \ Testing$check<?>(7 ^ 2 ,5)+    \ Testing$check<?>(7 & ~2,5)+    \ Testing$check<?>(5 | 2 ,7)   } } @@ -75,7 +75,7 @@  define Test {   run () {-    \ Testing$check<Int>(1 << 4 | 7 >> 1 & ~2,17)+    \ Testing$check<?>(1 << 4 | 7 >> 1 & ~2,17)   } } @@ -90,7 +90,7 @@  define Test {   run () {-    \ Testing$check<Int>(2 - 1 - 1,0)+    \ Testing$check<?>(2 - 1 - 1,0)   } } @@ -137,7 +137,7 @@  define Test {   run () {-    \ Testing$check<String>("x" + "y" + "z","xyz")+    \ Testing$check<?>("x" + "y" + "z","xyz")   } } @@ -152,7 +152,7 @@  define Test {   run () {-    \ Testing$check<Float>(16.0 + 1.0 * 2.0 - 8.0 / 2.0 - 3.0 / 3.0,13.0)+    \ Testing$check<?>(16.0 + 1.0 * 2.0 - 8.0 / 2.0 - 3.0 / 3.0,13.0)   } } @@ -167,7 +167,7 @@  define Test {   run () {-    \ Testing$check<Int>('z' - 'a',25)+    \ Testing$check<?>('z' - 'a',25)   } } 
tests/internal-params.0rt view
@@ -273,7 +273,7 @@  testcase "value mismatch with internal param" {   error-  require "call"+  require "create"   require "Bool"   require "String" }
tests/member-init.0rt view
@@ -107,7 +107,7 @@   }    run () {-    \ Testing$check<Int>(get(),2)+    \ Testing$check<?>(get(),2)   } } 
tests/module-only/README.md view
@@ -14,7 +14,7 @@ The compiler errors should look something like this:  ```text-Compiler errors:-In creation of val1 at "tests/module-only/private.0rx" (line 22, column 3)-  Type Type1 not found+Zeolite execution failed.+  In creation of val1 at "tests/module-only/private.0rx" (line 22, column 3)+    Type Type1 not found ```
tests/tests-only/README.md view
@@ -14,6 +14,6 @@ The compiler errors should look something like this:  ```text-Compiler errors:-Definition for Type1 ["tests/tests-only/private.0rx" (line 19, column 1)] does not correspond to a visible category in this module+Zeolite execution failed.+  Definition for Type1 ["tests/tests-only/private.0rx" (line 19, column 1)] does not correspond to a visible category in this module ```
tests/tests-only2/README.md view
@@ -13,6 +13,6 @@ The compiler errors should look something like this:  ```text-Compiler errors:-No matches for main category Testing ($TestsOnly$ sources excluded)+Zeolite execution failed.+  No matches for main category Testing ($TestsOnly$ sources excluded) ```
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.2  name:                zeolite-lang-version:             0.6.0.0+version:             0.7.0.0 synopsis:            Zeolite is a statically-typed, general-purpose programming language.  description:@@ -147,16 +147,19 @@   import:              defaults    exposed-modules:     Base.CompileError,+                       Base.CompileInfo,+                       Base.MergeTree,                        Base.Mergeable,                        Cli.CompileMetadata,                        Cli.CompileOptions,                        Cli.Compiler,                        Cli.ParseCompileOptions,                        Cli.ParseMetadata,+                       Cli.Paths,                        Cli.ProcessMetadata,+                       Cli.Programs,                        Cli.RunCompiler,                        Cli.TestRunner,-                       Compilation.CompileInfo,                        Compilation.CompilerState,                        Compilation.ProcedureContext,                        Compilation.ScopeContext,@@ -166,8 +169,7 @@                        CompilerCxx.Naming,                        CompilerCxx.Procedure,                        Config.LoadConfig,-                       Config.Paths,-                       Config.Programs,+                       Config.LocalConfig,                        Parser.Common,                        Parser.DefinedCategory,                        Parser.IntegrationTest,@@ -177,8 +179,10 @@                        Parser.TypeCategory,                        Parser.TypeInstance,                        Test.Common,+                       Test.CompileInfo,                        Test.DefinedCategory,                        Test.IntegrationTest,+                       Test.MergeTree,                        Test.ParseMetadata,                        Test.Parser,                        Test.Pragma,