module DesugarSI (loadProg, desugarProg, desugarBlock, desugarComm) where
import System.FilePath (pathSeparator)
import SourceParser (parseProg)
import Lexer (scan)
import PureSyntax
import InterSyntax
import SugarSyntax
import qualified Data.Set as S
import Control.Monad.Except
import Control.Exception (try)
import Control.Exception.Base (SomeException)
import Control.Arrow (left)
loadProg ::
FilePath ->
FilePath ->
[FilePath] ->
ExceptT String IO InProgram
loadProg dir fileBaseName macroStack =
if fileBaseName `elem` macroStack then
throwError "Recursive macros detected."
else do
fileStr <- safeReadFile $
dir ++ pathSeparator : fileBaseName ++ ".while"
let fileTokens = scan fileStr fileBaseName
suProg <- parseProg fileTokens
case (suProg, macroStack) of
( SuProgram n _ _ _ , _ ) | nameName n /= fileBaseName ->
throwError $ "Program name (" ++ nameName n
++ ") must match file base name."
( _ , [] ) ->
desugarProg dir ( fileBaseName : macroStack ) suProg
( SuProgram n r b w , _ ) ->
let namesToInit = S.delete r $ S.insert w $ namesSuBlock b
initCode = map ( \n ->
SuAssign ( Info ( "+IMPL+", 0 ) ) n ( Lit ENil ) )
(S.toList namesToInit)
in desugarProg dir ( fileBaseName : macroStack )
( SuProgram n r ( initCode ++ b ) w )
safeReadFile :: FilePath -> ExceptT String IO String
safeReadFile file = do
tryFile <- lift $ try $ readFile file
case tryFile of
Left exc -> throwError $ show (exc :: SomeException)
Right fileContents -> return fileContents
desugarProg :: FilePath -> [FilePath] -> SuProgram ->
ExceptT String IO InProgram
desugarProg dir macroStack ( SuProgram n r blk w ) = do
desugaredBlk <- desugarBlock dir macroStack blk
return $ InProgram n r desugaredBlk w
desugarBlock :: FilePath -> [FilePath] -> SuBlock -> ExceptT String IO InBlock
desugarBlock dir _ [] = return []
desugarBlock dir macroStack ( c : cs ) = do
desugaredC <- desugarComm dir macroStack c
desugaredCs <- desugarBlock dir macroStack cs
return $ desugaredC ++ desugaredCs
desugarComm ::
FilePath ->
[FilePath] ->
SuCommand ->
ExceptT String IO InBlock
desugarComm dir macroStack suComm = case suComm of
SuAssign i x exp -> return [ InAssign i x exp ]
SuWhile i gd blk -> do
desugaredBlk <- desugarBlock dir macroStack blk
return [ InWhile i gd desugaredBlk ]
SuIfElse i gd bt bf -> do
desugaredBT <- desugarBlock dir macroStack bt
desugaredBF <- desugarBlock dir macroStack bf
return [ InIfElse i gd desugaredBT desugaredBF ]
Macro i x f e -> do
prog <- loadProg dir f macroStack
return $
[ InAssign i ( inReadVar prog ) e ] ++
inBlock prog ++
[ InAssign i x ( Var ( inWriteVar prog ) ) ]
Switch i e cases def -> do
desugaredDef <- desugarBlock dir macroStack def
desugaredCases <- sequence $ map ( \( matchE , blk ) -> do
desugaredBlk <- desugarBlock dir macroStack blk
return ( matchE , desugaredBlk )
) cases
return $ [ InSwitch i e desugaredCases desugaredDef ]