module Parser.ImportSystem (resolveImports, constructForAst) where
import Control.Exception (try, IOException)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Text.Megaparsec.Error (errorBundlePretty)
import Data.List (isSuffixOf)
import AST.Ast (Ast(..))
import Parser.Statement (parseALL)
resolveImports :: [Ast] -> IO (Either String [Ast])
resolveImports :: [Ast] -> IO (Either String [Ast])
resolveImports [Ast]
asts = do
res <- [String] -> [Ast] -> IO (Either String ([Ast], [String]))
resolveImportsRec [] [Ast]
asts
case res of
Left String
err -> Either String [Ast] -> IO (Either String [Ast])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String [Ast]
forall a b. a -> Either a b
Left String
err)
Right ([Ast]
newAsts, [String]
_) -> Either String [Ast] -> IO (Either String [Ast])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Ast] -> Either String [Ast]
forall a b. b -> Either a b
Right [Ast]
newAsts)
resolveImportsRec :: [String] -> [Ast] -> IO (Either String ([Ast], [String]))
resolveImportsRec :: [String] -> [Ast] -> IO (Either String ([Ast], [String]))
resolveImportsRec [String]
visited [] = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([], [String]
visited))
resolveImportsRec [String]
visited (Ast
node:[Ast]
xs) = do
processedHead <- [String] -> Ast -> IO (Either String ([Ast], [String]))
processNode [String]
visited Ast
node
handleRecResult processedHead xs
handleRecResult :: Either String ([Ast], [String]) -> [Ast] ->
IO (Either String ([Ast], [String]))
handleRecResult :: Either String ([Ast], [String])
-> [Ast] -> IO (Either String ([Ast], [String]))
handleRecResult (Left String
err) [Ast]
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
handleRecResult (Right ([Ast]
headNodes, [String]
visitedAfterHead)) [Ast]
xs = do
processedTail <- [String] -> [Ast] -> IO (Either String ([Ast], [String]))
resolveImportsRec [String]
visitedAfterHead [Ast]
xs
return $ case processedTail of
Left String
err -> String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err
Right ([Ast]
tailNodes, [String]
visitedAfterTail) ->
([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Ast]
headNodes [Ast] -> [Ast] -> [Ast]
forall a. [a] -> [a] -> [a]
++ [Ast]
tailNodes, [String]
visitedAfterTail)
readImportFile :: String -> IO (Either String T.Text)
readImportFile :: String -> IO (Either String Text)
readImportFile String
path = do
res <- IO Text -> IO (Either IOException Text)
forall e a. Exception e => IO a -> IO (Either e a)
try (String -> IO Text
TIO.readFile String
path) :: IO (Either IOException T.Text)
return $ case res of
Left IOException
ex -> String -> Either String Text
forall a b. a -> Either a b
Left (String
"IO Error reading import '"
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
path String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"': " String -> String -> String
forall a. [a] -> [a] -> [a]
++ IOException -> String
forall a. Show a => a -> String
show IOException
ex)
Right Text
txt -> Text -> Either String Text
forall a b. b -> Either a b
Right Text
txt
parseImportContent :: [String] -> String -> T.Text ->
IO (Either String ([Ast], [String]))
parseImportContent :: [String] -> String -> Text -> IO (Either String ([Ast], [String]))
parseImportContent [String]
visited String
path Text
content = case Text -> Either (ParseErrorBundle Text Void) [Ast]
parseALL Text
content of
Left ParseErrorBundle Text Void
err -> Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left (String
"Parse error in '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
path String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"':\n" String -> String -> String
forall a. [a] -> [a] -> [a]
++
ParseErrorBundle Text Void -> String
forall s e.
(VisualStream s, TraversableStream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> String
errorBundlePretty ParseErrorBundle Text Void
err))
Right [Ast]
asts -> [String] -> [Ast] -> IO (Either String ([Ast], [String]))
resolveImportsRec (String
path String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
visited) [Ast]
asts
processImport :: [String] -> T.Text -> IO (Either String ([Ast], [String]))
processImport :: [String] -> Text -> IO (Either String ([Ast], [String]))
processImport [String]
visited Text
path =
let pathStr :: String
pathStr = Text -> String
T.unpack Text
path
in if Bool -> Bool
not (String
".npy" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
pathStr)
then Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left (String -> Either String ([Ast], [String]))
-> String -> Either String ([Ast], [String])
forall a b. (a -> b) -> a -> b
$ String
"Import Error: File '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
pathStr String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"' must have .npy extension")
else [String] -> String -> IO (Either String ([Ast], [String]))
processImportLogic [String]
visited String
pathStr
processImportLogic :: [String] -> String ->
IO (Either String ([Ast], [String]))
processImportLogic :: [String] -> String -> IO (Either String ([Ast], [String]))
processImportLogic [String]
visited String
pathStr
| String
pathStr String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
visited = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left (String -> Either String ([Ast], [String]))
-> String -> Either String ([Ast], [String])
forall a b. (a -> b) -> a -> b
$
String
"Circular or duplicate import detected: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
pathStr String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
" is already in the import stack " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
forall a. Show a => a -> String
show [String]
visited)
| Bool
otherwise = do
content <- String -> IO (Either String Text)
readImportFile String
pathStr
case content of
Left String
err -> Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
Right Text
txt -> [String] -> String -> Text -> IO (Either String ([Ast], [String]))
parseImportContent [String]
visited String
pathStr Text
txt
processNode :: [String] -> Ast -> IO (Either String ([Ast], [String]))
processNode :: [String] -> Ast -> IO (Either String ([Ast], [String]))
processNode [String]
visited (AImport Text
path) = [String] -> Text -> IO (Either String ([Ast], [String]))
processImport [String]
visited Text
path
processNode [String]
visited (AList [Ast]
subStmts) = [String] -> [Ast] -> IO (Either String ([Ast], [String]))
processAList [String]
visited [Ast]
subStmts
processNode [String]
visited (ADefineFunc Text
name [(Text, Text)]
args Text
ret Ast
body) =
[String]
-> Text
-> [(Text, Text)]
-> Text
-> Ast
-> IO (Either String ([Ast], [String]))
processFunc [String]
visited Text
name [(Text, Text)]
args Text
ret Ast
body
processNode [String]
visited (ADefineLambda [Text]
args Ast
body) =
[String] -> [Text] -> Ast -> IO (Either String ([Ast], [String]))
processLambda [String]
visited [Text]
args Ast
body
processNode [String]
visited (AWhile Ast
cond Ast
body) = [String] -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processWhile [String]
visited Ast
cond Ast
body
processNode [String]
visited (AFor Ast
i Ast
c Ast
u Ast
b) = [String]
-> Ast -> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processFor [String]
visited Ast
i Ast
c Ast
u Ast
b
processNode [String]
visited (AIf Ast
c Ast
t Ast
e) = [String]
-> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processIf [String]
visited Ast
c Ast
t Ast
e
processNode [String]
visited (APos Int
l Int
c Ast
ast) = [String]
-> Int -> Int -> Ast -> IO (Either String ([Ast], [String]))
processAPos [String]
visited Int
l Int
c Ast
ast
processNode [String]
visited Ast
other = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Ast
other], [String]
visited))
processAList :: [String] -> [Ast] -> IO (Either String ([Ast], [String]))
processAList :: [String] -> [Ast] -> IO (Either String ([Ast], [String]))
processAList [String]
visited [Ast]
subStmts = do
res <- [String] -> [Ast] -> IO (Either String ([Ast], [String]))
resolveImportsRec [String]
visited [Ast]
subStmts
case res of
Left String
err -> Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
Right ([Ast]
newStmts, [String]
newVisited) ->
Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([[Ast] -> Ast
AList [Ast]
newStmts], [String]
newVisited))
processFunc :: [String] -> T.Text -> [(T.Text, T.Text)] -> T.Text -> Ast ->
IO (Either String ([Ast], [String]))
processFunc :: [String]
-> Text
-> [(Text, Text)]
-> Text
-> Ast
-> IO (Either String ([Ast], [String]))
processFunc [String]
visited Text
name [(Text, Text)]
args Text
ret Ast
body = do
res <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visited Ast
body
case res of
Left String
err -> Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
Right (Ast
newBody, [String]
newVisited) ->
Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Text -> [(Text, Text)] -> Text -> Ast -> Ast
ADefineFunc Text
name [(Text, Text)]
args Text
ret Ast
newBody], [String]
newVisited))
processLambda :: [String] -> [T.Text] -> Ast ->
IO (Either String ([Ast], [String]))
processLambda :: [String] -> [Text] -> Ast -> IO (Either String ([Ast], [String]))
processLambda [String]
visited [Text]
args Ast
body = do
res <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visited Ast
body
case res of
Left String
err -> Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
Right (Ast
newBody, [String]
newVisited) ->
Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([[Text] -> Ast -> Ast
ADefineLambda [Text]
args Ast
newBody], [String]
newVisited))
processWhile :: [String] -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processWhile :: [String] -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processWhile [String]
visited Ast
cond Ast
body = do
resCond <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visited Ast
cond
processWhileBody resCond body
processWhileBody :: Either String (Ast, [String]) -> Ast ->
IO (Either String ([Ast], [String]))
processWhileBody :: Either String (Ast, [String])
-> Ast -> IO (Either String ([Ast], [String]))
processWhileBody (Left String
err) Ast
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
processWhileBody (Right (Ast
nc, [String]
visitedAfterCond)) Ast
body = do
resBody <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visitedAfterCond Ast
body
return $ case resBody of
Left String
err -> String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err
Right (Ast
nb, [String]
visitedAfterBody) ->
([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Ast -> Ast -> Ast
AWhile Ast
nc Ast
nb], [String]
visitedAfterBody)
constructForAst :: [Ast] -> Either String [Ast]
constructForAst :: [Ast] -> Either String [Ast]
constructForAst [Ast
ni, Ast
nc, Ast
nu, Ast
nb] = [Ast] -> Either String [Ast]
forall a b. b -> Either a b
Right [Ast -> Ast -> Ast -> Ast -> Ast
AFor Ast
ni Ast
nc Ast
nu Ast
nb]
constructForAst [Ast]
_ =
String -> Either String [Ast]
forall a b. a -> Either a b
Left String
"Internal Error: Invalid argument count in For loop processing"
processFor :: [String] -> Ast -> Ast -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processFor :: [String]
-> Ast -> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processFor [String]
visited Ast
i Ast
c Ast
u Ast
b = do
resI <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visited Ast
i
processForCond resI c u b
processForCond :: Either String (Ast, [String]) -> Ast -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processForCond :: Either String (Ast, [String])
-> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processForCond (Left String
err) Ast
_ Ast
_ Ast
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
processForCond (Right (Ast
ni, [String]
v1)) Ast
c Ast
u Ast
b = do
resC <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
v1 Ast
c
processForUpdate resC ni u b
processForUpdate :: Either String (Ast, [String]) -> Ast -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processForUpdate :: Either String (Ast, [String])
-> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processForUpdate (Left String
err) Ast
_ Ast
_ Ast
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
processForUpdate (Right (Ast
nc, [String]
v2)) Ast
ni Ast
u Ast
b = do
resU <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
v2 Ast
u
processForBody resU ni nc b
processForBody :: Either String (Ast, [String]) -> Ast -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processForBody :: Either String (Ast, [String])
-> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processForBody (Left String
err) Ast
_ Ast
_ Ast
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
processForBody (Right (Ast
nu, [String]
v3)) Ast
ni Ast
nc Ast
b = do
resB <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
v3 Ast
b
return $ case resB of
Left String
err -> String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err
Right (Ast
nb, [String]
v4) -> ([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Ast -> Ast -> Ast -> Ast -> Ast
AFor Ast
ni Ast
nc Ast
nu Ast
nb], [String]
v4)
processIf :: [String] -> Ast -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processIf :: [String]
-> Ast -> Ast -> Ast -> IO (Either String ([Ast], [String]))
processIf [String]
visited Ast
c Ast
t Ast
e = do
resC <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visited Ast
c
processIfThen resC t e
processIfThen :: Either String (Ast, [String]) -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processIfThen :: Either String (Ast, [String])
-> Ast -> Ast -> IO (Either String ([Ast], [String]))
processIfThen (Left String
err) Ast
_ Ast
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
processIfThen (Right (Ast
nc, [String]
v1)) Ast
t Ast
e = do
resT <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
v1 Ast
t
processIfElse resT nc e
processIfElse :: Either String (Ast, [String]) -> Ast -> Ast ->
IO (Either String ([Ast], [String]))
processIfElse :: Either String (Ast, [String])
-> Ast -> Ast -> IO (Either String ([Ast], [String]))
processIfElse (Left String
err) Ast
_ Ast
_ = Either String ([Ast], [String])
-> IO (Either String ([Ast], [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err)
processIfElse (Right (Ast
nt, [String]
v2)) Ast
nc Ast
e = do
resE <- [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
v2 Ast
e
return $ case resE of
Left String
err -> String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err
Right (Ast
ne, [String]
v3) -> ([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Ast -> Ast -> Ast -> Ast
AIf Ast
nc Ast
nt Ast
ne], [String]
v3)
processAPos :: [String] -> Int -> Int -> Ast ->
IO (Either String ([Ast], [String]))
processAPos :: [String]
-> Int -> Int -> Ast -> IO (Either String ([Ast], [String]))
processAPos [String]
visited Int
l Int
c Ast
ast = do
res <- [String] -> Ast -> IO (Either String ([Ast], [String]))
processNode [String]
visited Ast
ast
return $ case res of
Left String
err -> String -> Either String ([Ast], [String])
forall a b. a -> Either a b
Left String
err
Right ([Ast
single], [String]
newVisited) ->
([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Int -> Int -> Ast -> Ast
APos Int
l Int
c Ast
single], [String]
newVisited)
Right ([Ast]
multiple, [String]
newVisited) -> ([Ast], [String]) -> Either String ([Ast], [String])
forall a b. b -> Either a b
Right ([Ast]
multiple, [String]
newVisited)
processSingleNode :: [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode :: [String] -> Ast -> IO (Either String (Ast, [String]))
processSingleNode [String]
visited Ast
node = do
res <- [String] -> Ast -> IO (Either String ([Ast], [String]))
processNode [String]
visited Ast
node
return $ case res of
Left String
err -> String -> Either String (Ast, [String])
forall a b. a -> Either a b
Left String
err
Right ([], [String]
newVisited) -> (Ast, [String]) -> Either String (Ast, [String])
forall a b. b -> Either a b
Right (Ast
AVoid, [String]
newVisited)
Right ([Ast
x], [String]
newVisited) -> (Ast, [String]) -> Either String (Ast, [String])
forall a b. b -> Either a b
Right (Ast
x, [String]
newVisited)
Right (Ast
x:[Ast]
_, [String]
newVisited) -> (Ast, [String]) -> Either String (Ast, [String])
forall a b. b -> Either a b
Right (Ast
x, [String]
newVisited)