REPL namespaces; lib function for pattern matching
Adds support for REPL namespacing, primarily to avoid `main` collisions. Also adds a library function for an ergonomic pattern matching function that I've been noodling on. I might explore ways to make list syntax less annoying specifically for pattern matching like this.
This commit is contained in:
@ -6,6 +6,7 @@ import Parser
|
||||
import Research
|
||||
|
||||
import Data.List (partition)
|
||||
import Data.Maybe (mapMaybe)
|
||||
import Control.Monad (foldM)
|
||||
import System.IO
|
||||
import System.FilePath (takeDirectory, normalise, (</>))
|
||||
@ -13,6 +14,26 @@ import System.FilePath (takeDirectory, normalise, (</>))
|
||||
import qualified Data.Map as Map
|
||||
import qualified Data.Set as Set
|
||||
|
||||
extractMain :: Env -> Either String T
|
||||
extractMain env =
|
||||
case Map.lookup "main" env of
|
||||
Just result -> Right result
|
||||
Nothing -> Left "No `main` function detected"
|
||||
|
||||
processImports :: Set.Set FilePath -> FilePath -> FilePath -> [TricuAST]
|
||||
-> Either String ([TricuAST], [(FilePath, String, FilePath)])
|
||||
processImports seen base currentPath asts =
|
||||
let (imports, nonImports) = partition isImp asts
|
||||
importPaths = mapMaybe getImportInfo imports
|
||||
in if currentPath `Set.member` seen
|
||||
then Left $ "Encountered cyclic import: " ++ currentPath
|
||||
else Right (nonImports, importPaths)
|
||||
where
|
||||
isImp (SImport _ _) = True
|
||||
isImp _ = False
|
||||
getImportInfo (SImport p n) = Just (p, n, makeRelativeTo currentPath p)
|
||||
getImportInfo _ = Nothing
|
||||
|
||||
evaluateFileResult :: FilePath -> IO T
|
||||
evaluateFileResult filePath = do
|
||||
contents <- readFile filePath
|
||||
@ -20,11 +41,11 @@ evaluateFileResult filePath = do
|
||||
case parseProgram tokens of
|
||||
Left err -> errorWithoutStackTrace (handleParseError err)
|
||||
Right ast -> do
|
||||
ast <- preprocessFile filePath
|
||||
let finalEnv = evalTricu Map.empty ast
|
||||
case Map.lookup "main" finalEnv of
|
||||
Just finalResult -> return finalResult
|
||||
Nothing -> errorWithoutStackTrace "No `main` function detected"
|
||||
processedAst <- preprocessFile filePath
|
||||
let finalEnv = evalTricu Map.empty processedAst
|
||||
case extractMain finalEnv of
|
||||
Right result -> return result
|
||||
Left err -> errorWithoutStackTrace err
|
||||
|
||||
evaluateFile :: FilePath -> IO Env
|
||||
evaluateFile filePath = do
|
||||
@ -50,37 +71,25 @@ preprocessFile :: FilePath -> IO [TricuAST]
|
||||
preprocessFile p = preprocessFile' Set.empty p p
|
||||
|
||||
preprocessFile' :: Set.Set FilePath -> FilePath -> FilePath -> IO [TricuAST]
|
||||
preprocessFile' s b p
|
||||
| p `Set.member` s =
|
||||
errorWithoutStackTrace $ "Encountered cyclic import: " ++ p
|
||||
| otherwise = do
|
||||
c <- readFile p
|
||||
let t = lexTricu c
|
||||
case parseProgram t of
|
||||
Left e -> errorWithoutStackTrace (handleParseError e)
|
||||
Right a -> do
|
||||
let (i, n) = partition isImp a
|
||||
let s' = Set.insert p s
|
||||
r <- concat <$>
|
||||
mapM (procImp s' "" p) i
|
||||
pure $ r ++ n
|
||||
preprocessFile' seen base currentPath = do
|
||||
contents <- readFile currentPath
|
||||
let tokens = lexTricu contents
|
||||
case parseProgram tokens of
|
||||
Left err -> errorWithoutStackTrace (handleParseError err)
|
||||
Right ast ->
|
||||
case processImports seen base currentPath ast of
|
||||
Left err -> errorWithoutStackTrace err
|
||||
Right (nonImports, importPaths) -> do
|
||||
let seen' = Set.insert currentPath seen
|
||||
imported <- concat <$> mapM (processImportPath seen' base) importPaths
|
||||
pure $ imported ++ nonImports
|
||||
where
|
||||
isImp :: TricuAST -> Bool
|
||||
processImportPath seen base (path, name, importPath) = do
|
||||
ast <- preprocessFile' seen base importPath
|
||||
pure $ map (nsDefinition (if name == "!Local" then "" else name))
|
||||
$ filter (not . isImp) ast
|
||||
isImp (SImport _ _) = True
|
||||
isImp _ = False
|
||||
|
||||
procImp :: Set.Set FilePath -> String -> FilePath -> TricuAST -> IO [TricuAST]
|
||||
procImp s m f (SImport p "!Local") = do
|
||||
let ip = makeRelativeTo f p
|
||||
a <- preprocessFile' s b ip
|
||||
let d = filter (not . isImp) a
|
||||
pure $ map (nsDefinition m) d
|
||||
procImp s _ f (SImport p n) = do
|
||||
let ip = makeRelativeTo f p
|
||||
a <- preprocessFile' s b ip
|
||||
let d = filter (not . isImp) a
|
||||
pure $ map (nsDefinition n) d
|
||||
procImp _ _ _ _ = error "Unexpected non-import in processImport"
|
||||
isImp _ = False
|
||||
|
||||
makeRelativeTo :: FilePath -> FilePath -> FilePath
|
||||
makeRelativeTo f i =
|
||||
@ -94,7 +103,7 @@ nsDefinition :: String -> TricuAST -> TricuAST
|
||||
nsDefinition "" def = def
|
||||
nsDefinition moduleName (SDef name args body)
|
||||
| isPrefixed name = SDef name args (nsBody moduleName body)
|
||||
| otherwise = SDef (nsVariable moduleName name)
|
||||
| otherwise = SDef (nsVariable moduleName name)
|
||||
args (nsBody moduleName body)
|
||||
nsDefinition moduleName other =
|
||||
nsBody moduleName other
|
||||
@ -115,7 +124,7 @@ nsBody moduleName (TStem subtree) =
|
||||
TStem (nsBody moduleName subtree)
|
||||
nsBody moduleName (SDef name args body)
|
||||
| isPrefixed name = SDef name args (nsBody moduleName body)
|
||||
| otherwise = SDef (nsVariable moduleName name)
|
||||
| otherwise = SDef (nsVariable moduleName name)
|
||||
args (nsBody moduleName body)
|
||||
nsBody _ other = other
|
||||
|
||||
@ -125,19 +134,19 @@ nsBodyScoped moduleName args body = case body of
|
||||
if name `elem` args
|
||||
then SVar name
|
||||
else nsBody moduleName (SVar name)
|
||||
SApp func arg ->
|
||||
SApp func arg ->
|
||||
SApp (nsBodyScoped moduleName args func) (nsBodyScoped moduleName args arg)
|
||||
SLambda innerArgs innerBody ->
|
||||
SLambda innerArgs innerBody ->
|
||||
SLambda innerArgs (nsBodyScoped moduleName (args ++ innerArgs) innerBody)
|
||||
SList items ->
|
||||
SList items ->
|
||||
SList (map (nsBodyScoped moduleName args) items)
|
||||
TFork left right ->
|
||||
TFork (nsBodyScoped moduleName args left)
|
||||
TFork left right ->
|
||||
TFork (nsBodyScoped moduleName args left)
|
||||
(nsBodyScoped moduleName args right)
|
||||
TStem subtree ->
|
||||
TStem subtree ->
|
||||
TStem (nsBodyScoped moduleName args subtree)
|
||||
SDef name innerArgs innerBody ->
|
||||
SDef (nsVariable moduleName name) innerArgs
|
||||
SDef (nsVariable moduleName name) innerArgs
|
||||
(nsBodyScoped moduleName (args ++ innerArgs) innerBody)
|
||||
other -> other
|
||||
|
||||
|
Reference in New Issue
Block a user