diff --git a/src/FileEval.hs b/src/FileEval.hs index 56f113b..7580499 100644 --- a/src/FileEval.hs +++ b/src/FileEval.hs @@ -10,6 +10,7 @@ import Control.Monad (foldM) import System.IO import qualified Data.Map as Map +import qualified Data.Set as Set evaluateFileResult :: FilePath -> IO T evaluateFileResult filePath = do @@ -61,18 +62,24 @@ mainAlias moduleName env = Nothing -> env preprocessFile :: FilePath -> IO [TricuAST] -preprocessFile filePath = do - contents <- readFile filePath - let tokens = lexTricu contents - case parseProgram tokens of - Left err -> errorWithoutStackTrace (handleParseError err) - Right asts -> do - let (moduleName, restAST) = extractModule asts - let (imports, nonImports) = partition isImport restAST - importedASTs <- concat <$> mapM (processImport moduleName) imports - let namespacedAST = namespaceDefinitions moduleName nonImports - let fullyNamespacedImports = map (namespaceBody moduleName) importedASTs - pure $ fullyNamespacedImports ++ namespacedAST +preprocessFile filePath = preprocessFile' Set.empty filePath + +preprocessFile' :: Set.Set FilePath -> FilePath -> IO [TricuAST] +preprocessFile' inProgress filePath + | filePath `Set.member` inProgress = + errorWithoutStackTrace $ "Encountered cyclic import: " ++ filePath + | otherwise = do + contents <- readFile filePath + let tokens = lexTricu contents + case parseProgram tokens of + Left err -> errorWithoutStackTrace (handleParseError err) + Right asts -> do + let (moduleName, restAST) = extractModule asts + let (imports, nonImports) = partition isImport restAST + let newInProgress = Set.insert filePath inProgress + importedASTs <- concat <$> mapM (processImport newInProgress) imports + let namespacedAST = namespaceDefinitions moduleName nonImports + pure $ importedASTs ++ namespacedAST where extractModule :: [TricuAST] -> (String, [TricuAST]) extractModule ((SModule name) : xs) = (name, xs) @@ -82,11 +89,11 @@ preprocessFile filePath = do isImport (SImport _ _) = True isImport _ = False - processImport :: String -> TricuAST -> IO [TricuAST] - processImport _ (SImport filePath moduleName) = do - importedAST <- preprocessFile filePath + processImport :: Set.Set FilePath -> TricuAST -> IO [TricuAST] + processImport inProgress (SImport filePath moduleName) = do + importedAST <- preprocessFile' inProgress filePath pure $ namespaceDefinitions moduleName importedAST - processImport _ _ = error "Unexpected non-import AST node in processImport" + processImport _ _ = error "Unexpected non-import in processImport" namespaceDefinitions :: String -> [TricuAST] -> [TricuAST] namespaceDefinitions moduleName = map (namespaceDefinition moduleName) diff --git a/test/cycle-1.tri b/test/cycle-1.tri new file mode 100644 index 0000000..2821bfe --- /dev/null +++ b/test/cycle-1.tri @@ -0,0 +1,5 @@ +!module Cycle + +!import "test/cycle-2.tri" Cycle2 + +cycle1 = t Cycle2.cycle2 diff --git a/test/cycle-2.tri b/test/cycle-2.tri new file mode 100644 index 0000000..e218ee4 --- /dev/null +++ b/test/cycle-2.tri @@ -0,0 +1,5 @@ +!module Cycle2 + +!import "test/cycle-1.tri" Cycle1 + +cycle2 = t Cycle1.cycle1