|
Packit |
2cbdf3 |
{-# LANGUAGE CPP #-}
|
|
Packit |
2cbdf3 |
-- -----------------------------------------------------------------------------
|
|
Packit |
2cbdf3 |
--
|
|
Packit |
2cbdf3 |
-- Main.hs, part of Alex
|
|
Packit |
2cbdf3 |
--
|
|
Packit |
2cbdf3 |
-- (c) Chris Dornan 1995-2000, Simon Marlow 2003
|
|
Packit |
2cbdf3 |
--
|
|
Packit |
2cbdf3 |
-- ----------------------------------------------------------------------------}
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
module Main (main) where
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
import AbsSyn
|
|
Packit |
2cbdf3 |
import CharSet
|
|
Packit |
2cbdf3 |
import DFA
|
|
Packit |
2cbdf3 |
import DFAMin
|
|
Packit |
2cbdf3 |
import NFA
|
|
Packit |
2cbdf3 |
import Info
|
|
Packit |
2cbdf3 |
import Map ( Map )
|
|
Packit |
2cbdf3 |
import qualified Map hiding ( Map )
|
|
Packit |
2cbdf3 |
import Output
|
|
Packit |
2cbdf3 |
import ParseMonad ( runP )
|
|
Packit |
2cbdf3 |
import Parser
|
|
Packit |
2cbdf3 |
import Scan
|
|
Packit |
2cbdf3 |
import Util ( hline )
|
|
Packit |
2cbdf3 |
import Paths_alex ( version, getDataDir )
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
#if __GLASGOW_HASKELL__ < 610
|
|
Packit |
2cbdf3 |
import Control.Exception as Exception ( block, unblock, catch, throw )
|
|
Packit |
2cbdf3 |
#endif
|
|
Packit |
2cbdf3 |
#if __GLASGOW_HASKELL__ >= 610
|
|
Packit |
2cbdf3 |
import Control.Exception ( bracketOnError )
|
|
Packit |
2cbdf3 |
#endif
|
|
Packit |
2cbdf3 |
import Control.Monad ( when, liftM )
|
|
Packit |
2cbdf3 |
import Data.Char ( chr )
|
|
Packit |
2cbdf3 |
import Data.List ( isSuffixOf, nub )
|
|
Packit |
2cbdf3 |
import Data.Maybe ( isJust, fromJust )
|
|
Packit |
2cbdf3 |
import Data.Version ( showVersion )
|
|
Packit |
2cbdf3 |
import System.Console.GetOpt ( getOpt, usageInfo, ArgOrder(..), OptDescr(..), ArgDescr(..) )
|
|
Packit |
2cbdf3 |
import System.Directory ( removeFile )
|
|
Packit |
2cbdf3 |
import System.Environment ( getProgName, getArgs )
|
|
Packit |
2cbdf3 |
import System.Exit ( ExitCode(..), exitWith )
|
|
Packit |
2cbdf3 |
import System.IO ( stderr, Handle, IOMode(..), openFile, hClose, hPutStr, hPutStrLn )
|
|
Packit |
2cbdf3 |
#if __GLASGOW_HASKELL__ >= 612
|
|
Packit |
2cbdf3 |
import System.IO ( hGetContents, hSetEncoding, utf8 )
|
|
Packit |
2cbdf3 |
#endif
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- We need to force every file we open to be read in
|
|
Packit |
2cbdf3 |
-- as UTF8
|
|
Packit |
2cbdf3 |
alexReadFile :: FilePath -> IO String
|
|
Packit |
2cbdf3 |
#if __GLASGOW_HASKELL__ >= 612
|
|
Packit |
2cbdf3 |
alexReadFile file = do
|
|
Packit |
2cbdf3 |
h <- alexOpenFile file ReadMode
|
|
Packit |
2cbdf3 |
hGetContents h
|
|
Packit |
2cbdf3 |
#else
|
|
Packit |
2cbdf3 |
alexReadFile = readFile
|
|
Packit |
2cbdf3 |
#endif
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- We need to force every file we write to be written
|
|
Packit |
2cbdf3 |
-- to as UTF8
|
|
Packit |
2cbdf3 |
alexOpenFile :: FilePath -> IOMode -> IO Handle
|
|
Packit |
2cbdf3 |
#if __GLASGOW_HASKELL__ >= 612
|
|
Packit |
2cbdf3 |
alexOpenFile file mode = do
|
|
Packit |
2cbdf3 |
h <- openFile file mode
|
|
Packit |
2cbdf3 |
hSetEncoding h utf8
|
|
Packit |
2cbdf3 |
return h
|
|
Packit |
2cbdf3 |
#else
|
|
Packit |
2cbdf3 |
alexOpenFile = openFile
|
|
Packit |
2cbdf3 |
#endif
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- `main' decodes the command line arguments and calls `alex'.
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
main:: IO ()
|
|
Packit |
2cbdf3 |
main = do
|
|
Packit |
2cbdf3 |
args <- getArgs
|
|
Packit |
2cbdf3 |
case getOpt Permute argInfo args of
|
|
Packit |
2cbdf3 |
(cli,_,[]) | DumpHelp `elem` cli -> do
|
|
Packit |
2cbdf3 |
prog <- getProgramName
|
|
Packit |
2cbdf3 |
bye (usageInfo (usageHeader prog) argInfo)
|
|
Packit |
2cbdf3 |
(cli,_,[]) | DumpVersion `elem` cli ->
|
|
Packit |
2cbdf3 |
bye copyright
|
|
Packit |
2cbdf3 |
(cli,[file],[]) ->
|
|
Packit |
2cbdf3 |
runAlex cli file
|
|
Packit |
2cbdf3 |
(_,_,errors) -> do
|
|
Packit |
2cbdf3 |
prog <- getProgramName
|
|
Packit |
2cbdf3 |
die (concat errors ++ usageInfo (usageHeader prog) argInfo)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
projectVersion :: String
|
|
Packit |
2cbdf3 |
projectVersion = showVersion version
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
copyright :: String
|
|
Packit |
2cbdf3 |
copyright = "Alex version " ++ projectVersion ++ ", (c) 2003 Chris Dornan and Simon Marlow\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
usageHeader :: String -> String
|
|
Packit |
2cbdf3 |
usageHeader prog = "Usage: " ++ prog ++ " [OPTION...] file\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
runAlex :: [CLIFlags] -> FilePath -> IO ()
|
|
Packit |
2cbdf3 |
runAlex cli file = do
|
|
Packit |
2cbdf3 |
basename <- case (reverse file) of
|
|
Packit |
2cbdf3 |
'x':'.':r -> return (reverse r)
|
|
Packit |
2cbdf3 |
_ -> die (file ++ ": filename must end in \'.x\'\n")
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
prg <- alexReadFile file
|
|
Packit |
2cbdf3 |
script <- parseScript file prg
|
|
Packit |
2cbdf3 |
alex cli file basename script
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
parseScript :: FilePath -> String
|
|
Packit |
2cbdf3 |
-> IO (Maybe (AlexPosn,Code), [Directive], Scanner, Maybe (AlexPosn,Code))
|
|
Packit |
2cbdf3 |
parseScript file prg =
|
|
Packit |
2cbdf3 |
case runP prg initialParserEnv parse of
|
|
Packit |
2cbdf3 |
Left (Just (AlexPn _ line col),err) ->
|
|
Packit |
2cbdf3 |
die (file ++ ":" ++ show line ++ ":" ++ show col
|
|
Packit |
2cbdf3 |
++ ": " ++ err ++ "\n")
|
|
Packit |
2cbdf3 |
Left (Nothing, err) ->
|
|
Packit |
2cbdf3 |
die (file ++ ": " ++ err ++ "\n")
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
Right script -> return script
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
alex :: [CLIFlags] -> FilePath -> FilePath
|
|
Packit |
2cbdf3 |
-> (Maybe (AlexPosn, Code), [Directive], Scanner, Maybe (AlexPosn, Code))
|
|
Packit |
2cbdf3 |
-> IO ()
|
|
Packit |
2cbdf3 |
alex cli file basename script = do
|
|
Packit |
2cbdf3 |
(put_info, finish_info) <-
|
|
Packit |
2cbdf3 |
case [ f | OptInfoFile f <- cli ] of
|
|
Packit |
2cbdf3 |
[] -> return (\_ -> return (), return ())
|
|
Packit |
2cbdf3 |
[Nothing] -> infoStart file (basename ++ ".info")
|
|
Packit |
2cbdf3 |
[Just f] -> infoStart file f
|
|
Packit |
2cbdf3 |
_ -> dieAlex "multiple -i/--info options"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
o_file <- case [ f | OptOutputFile f <- cli ] of
|
|
Packit |
2cbdf3 |
[] -> return (basename ++ ".hs")
|
|
Packit |
2cbdf3 |
[f] -> return f
|
|
Packit |
2cbdf3 |
_ -> dieAlex "multiple -o/--outfile options"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
tab_size <- case [ s | OptTabSize s <- cli ] of
|
|
Packit |
2cbdf3 |
[] -> return (8 :: Int)
|
|
Packit |
2cbdf3 |
[s] -> case reads s of
|
|
Packit |
2cbdf3 |
[(n,"")] -> return n
|
|
Packit |
2cbdf3 |
_ -> dieAlex "-s/--tab-size option is not a valid integer"
|
|
Packit |
2cbdf3 |
_ -> dieAlex "multiple -s/--tab-size options"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
let target
|
|
Packit |
2cbdf3 |
| OptGhcTarget `elem` cli = GhcTarget
|
|
Packit |
2cbdf3 |
| otherwise = HaskellTarget
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
let encodingsCli
|
|
Packit |
2cbdf3 |
| OptLatin1 `elem` cli = [Latin1]
|
|
Packit |
2cbdf3 |
| otherwise = []
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
template_dir <- templateDir getDataDir cli
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
let (maybe_header, directives, scanner1, maybe_footer) = script
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
scheme <- getScheme directives
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- open the output file; remove it if we encounter an error
|
|
Packit |
2cbdf3 |
bracketOnError
|
|
Packit |
2cbdf3 |
(alexOpenFile o_file WriteMode)
|
|
Packit |
2cbdf3 |
(\h -> do hClose h; removeFile o_file)
|
|
Packit |
2cbdf3 |
$ \out_h -> do
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
let
|
|
Packit |
2cbdf3 |
wrapper_name = wrapperFile template_dir scheme
|
|
Packit |
2cbdf3 |
(scanner2, scs, sc_hdr) = encodeStartCodes scanner1
|
|
Packit |
2cbdf3 |
(scanner_final, actions) = extractActions scheme scanner2
|
|
Packit |
2cbdf3 |
encodingsScript = [ e | EncodingDirective e <- directives ]
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
encoding <- case nub (encodingsCli ++ encodingsScript) of
|
|
Packit |
2cbdf3 |
[] -> return UTF8 -- default
|
|
Packit |
2cbdf3 |
[e] -> return e
|
|
Packit |
2cbdf3 |
_ | null encodingsCli -> dieAlex "conflicting %encoding directives"
|
|
Packit |
2cbdf3 |
| otherwise -> dieAlex "--latin1 flag conflicts with %encoding directive"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
hPutStr out_h (optsToInject target cli)
|
|
Packit |
2cbdf3 |
injectCode maybe_header file out_h
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
hPutStr out_h (importsToInject target cli)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- add the wrapper, if necessary
|
|
Packit |
2cbdf3 |
when (isJust wrapper_name) $
|
|
Packit |
2cbdf3 |
do str <- alexReadFile (fromJust wrapper_name)
|
|
Packit |
2cbdf3 |
hPutStr out_h str
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- Inject the tab size
|
|
Packit |
2cbdf3 |
hPutStrLn out_h $ "alex_tab_size :: Int"
|
|
Packit |
2cbdf3 |
hPutStrLn out_h $ "alex_tab_size = " ++ show (tab_size :: Int)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
let dfa = scanner2dfa encoding scanner_final scs
|
|
Packit |
2cbdf3 |
min_dfa = minimizeDFA dfa
|
|
Packit |
2cbdf3 |
nm = scannerName scanner_final
|
|
Packit |
2cbdf3 |
usespreds = usesPreds min_dfa
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
put_info "\nStart codes\n"
|
|
Packit |
2cbdf3 |
put_info (show $ scs)
|
|
Packit |
2cbdf3 |
put_info "\nScanner\n"
|
|
Packit |
2cbdf3 |
put_info (show $ scanner_final)
|
|
Packit |
2cbdf3 |
put_info "\nNFA\n"
|
|
Packit |
2cbdf3 |
put_info (show $ scanner2nfa encoding scanner_final scs)
|
|
Packit |
2cbdf3 |
put_info "\nDFA"
|
|
Packit |
2cbdf3 |
put_info (infoDFA 1 nm dfa "")
|
|
Packit |
2cbdf3 |
put_info "\nMinimized DFA"
|
|
Packit |
2cbdf3 |
put_info (infoDFA 1 nm min_dfa "")
|
|
Packit |
2cbdf3 |
hPutStr out_h (outputDFA target 1 nm scheme min_dfa "")
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
injectCode maybe_footer file out_h
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
hPutStr out_h (sc_hdr "")
|
|
Packit |
2cbdf3 |
hPutStr out_h (actions "")
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- add the template
|
|
Packit |
2cbdf3 |
let template_name = templateFile template_dir target usespreds cli
|
|
Packit |
2cbdf3 |
tmplt <- alexReadFile template_name
|
|
Packit |
2cbdf3 |
hPutStr out_h tmplt
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
hClose out_h
|
|
Packit |
2cbdf3 |
finish_info
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
getScheme :: [Directive] -> IO Scheme
|
|
Packit |
2cbdf3 |
getScheme directives =
|
|
Packit |
2cbdf3 |
do
|
|
Packit |
2cbdf3 |
token <- case [ ty | TokenType ty <- directives ] of
|
|
Packit |
2cbdf3 |
[] -> return Nothing
|
|
Packit |
2cbdf3 |
[res] -> return (Just res)
|
|
Packit |
2cbdf3 |
_ -> dieAlex "multiple %token directives"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
action <- case [ ty | ActionType ty <- directives ] of
|
|
Packit |
2cbdf3 |
[] -> return Nothing
|
|
Packit |
2cbdf3 |
[res] -> return (Just res)
|
|
Packit |
2cbdf3 |
_ -> dieAlex "multiple %action directives"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
typeclass <- case [ tyclass | TypeClass tyclass <- directives ] of
|
|
Packit |
2cbdf3 |
[] -> return Nothing
|
|
Packit |
2cbdf3 |
[res] -> return (Just res)
|
|
Packit |
2cbdf3 |
_ -> dieAlex "multiple %typeclass directives"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
case [ f | WrapperDirective f <- directives ] of
|
|
Packit |
2cbdf3 |
[] ->
|
|
Packit |
2cbdf3 |
case (typeclass, token, action) of
|
|
Packit |
2cbdf3 |
(Nothing, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
return Default { defaultTypeInfo = Nothing }
|
|
Packit |
2cbdf3 |
(Nothing, Nothing, Just actionty) ->
|
|
Packit |
2cbdf3 |
return Default { defaultTypeInfo = Just (Nothing, actionty) }
|
|
Packit |
2cbdf3 |
(Just _, Nothing, Just actionty) ->
|
|
Packit |
2cbdf3 |
return Default { defaultTypeInfo = Just (typeclass, actionty) }
|
|
Packit |
2cbdf3 |
(_, Just _, _) ->
|
|
Packit |
2cbdf3 |
dieAlex "%token directive only allowed with a wrapper"
|
|
Packit |
2cbdf3 |
(Just _, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
dieAlex "%typeclass directive without %token directive"
|
|
Packit |
2cbdf3 |
[single]
|
|
Packit |
2cbdf3 |
| single == "gscan" ->
|
|
Packit |
2cbdf3 |
case (typeclass, token, action) of
|
|
Packit |
2cbdf3 |
(Nothing, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
return GScan { gscanTypeInfo = Nothing }
|
|
Packit |
2cbdf3 |
(Nothing, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return GScan { gscanTypeInfo = Just (Nothing, tokenty) }
|
|
Packit |
2cbdf3 |
(Just _, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return GScan { gscanTypeInfo = Just (typeclass, tokenty) }
|
|
Packit |
2cbdf3 |
(_, _, Just _) ->
|
|
Packit |
2cbdf3 |
dieAlex "%action directive not allowed with a wrapper"
|
|
Packit |
2cbdf3 |
(Just _, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
dieAlex "%typeclass directive without %token directive"
|
|
Packit |
2cbdf3 |
| single == "basic" || single == "basic-bytestring" ||
|
|
Packit |
2cbdf3 |
single == "strict-bytestring" ->
|
|
Packit |
2cbdf3 |
let
|
|
Packit |
2cbdf3 |
strty = case single of
|
|
Packit |
2cbdf3 |
"basic" -> Str
|
|
Packit |
2cbdf3 |
"basic-bytestring" -> Lazy
|
|
Packit |
2cbdf3 |
"strict-bytestring" -> Strict
|
|
Packit |
2cbdf3 |
_ -> error "Impossible case"
|
|
Packit |
2cbdf3 |
in case (typeclass, token, action) of
|
|
Packit |
2cbdf3 |
(Nothing, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
return Basic { basicStrType = strty,
|
|
Packit |
2cbdf3 |
basicTypeInfo = Nothing }
|
|
Packit |
2cbdf3 |
(Nothing, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return Basic { basicStrType = strty,
|
|
Packit |
2cbdf3 |
basicTypeInfo = Just (Nothing, tokenty) }
|
|
Packit |
2cbdf3 |
(Just _, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return Basic { basicStrType = strty,
|
|
Packit |
2cbdf3 |
basicTypeInfo = Just (typeclass, tokenty) }
|
|
Packit |
2cbdf3 |
(_, _, Just _) ->
|
|
Packit |
2cbdf3 |
dieAlex "%action directive not allowed with a wrapper"
|
|
Packit |
2cbdf3 |
(Just _, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
dieAlex "%typeclass directive without %token directive"
|
|
Packit |
2cbdf3 |
| single == "posn" || single == "posn-bytestring" ->
|
|
Packit |
2cbdf3 |
let
|
|
Packit |
2cbdf3 |
isByteString = single == "posn-bytestring"
|
|
Packit |
2cbdf3 |
in case (typeclass, token, action) of
|
|
Packit |
2cbdf3 |
(Nothing, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
return Posn { posnByteString = isByteString,
|
|
Packit |
2cbdf3 |
posnTypeInfo = Nothing }
|
|
Packit |
2cbdf3 |
(Nothing, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return Posn { posnByteString = isByteString,
|
|
Packit |
2cbdf3 |
posnTypeInfo = Just (Nothing, tokenty) }
|
|
Packit |
2cbdf3 |
(Just _, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return Posn { posnByteString = isByteString,
|
|
Packit |
2cbdf3 |
posnTypeInfo = Just (typeclass, tokenty) }
|
|
Packit |
2cbdf3 |
(_, _, Just _) ->
|
|
Packit |
2cbdf3 |
dieAlex "%action directive not allowed with a wrapper"
|
|
Packit |
2cbdf3 |
(Just _, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
dieAlex "%typeclass directive without %token directive"
|
|
Packit |
2cbdf3 |
| single == "monad" || single == "monad-bytestring" ||
|
|
Packit |
2cbdf3 |
single == "monadUserState" ||
|
|
Packit |
2cbdf3 |
single == "monadUserState-bytestring" ->
|
|
Packit |
2cbdf3 |
let
|
|
Packit |
2cbdf3 |
isByteString = single == "monad-bytestring" ||
|
|
Packit |
2cbdf3 |
single == "monadUserState-bytestring"
|
|
Packit |
2cbdf3 |
userState = single == "monadUserState" ||
|
|
Packit |
2cbdf3 |
single == "monadUserState-bytestring"
|
|
Packit |
2cbdf3 |
in case (typeclass, token, action) of
|
|
Packit |
2cbdf3 |
(Nothing, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
return Monad { monadByteString = isByteString,
|
|
Packit |
2cbdf3 |
monadUserState = userState,
|
|
Packit |
2cbdf3 |
monadTypeInfo = Nothing }
|
|
Packit |
2cbdf3 |
(Nothing, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return Monad { monadByteString = isByteString,
|
|
Packit |
2cbdf3 |
monadUserState = userState,
|
|
Packit |
2cbdf3 |
monadTypeInfo = Just (Nothing, tokenty) }
|
|
Packit |
2cbdf3 |
(Just _, Just tokenty, Nothing) ->
|
|
Packit |
2cbdf3 |
return Monad { monadByteString = isByteString,
|
|
Packit |
2cbdf3 |
monadUserState = userState,
|
|
Packit |
2cbdf3 |
monadTypeInfo = Just (typeclass, tokenty) }
|
|
Packit |
2cbdf3 |
(_, _, Just _) ->
|
|
Packit |
2cbdf3 |
dieAlex "%action directive not allowed with a wrapper"
|
|
Packit |
2cbdf3 |
(Just _, Nothing, Nothing) ->
|
|
Packit |
2cbdf3 |
dieAlex "%typeclass directive without %token directive"
|
|
Packit |
2cbdf3 |
| otherwise -> dieAlex ("unknown wrapper type " ++ single)
|
|
Packit |
2cbdf3 |
_many -> dieAlex "multiple %wrapper directives"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- inject some code, and add a {-# LINE #-} pragma at the top
|
|
Packit |
2cbdf3 |
injectCode :: Maybe (AlexPosn,Code) -> FilePath -> Handle -> IO ()
|
|
Packit |
2cbdf3 |
injectCode Nothing _ _ = return ()
|
|
Packit |
2cbdf3 |
injectCode (Just (AlexPn _ ln _,code)) filename hdl = do
|
|
Packit |
2cbdf3 |
hPutStrLn hdl ("{-# LINE " ++ show ln ++ " \"" ++ filename ++ "\" #-}")
|
|
Packit |
2cbdf3 |
hPutStrLn hdl code
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
optsToInject :: Target -> [CLIFlags] -> String
|
|
Packit |
2cbdf3 |
optsToInject GhcTarget _ = optNoWarnings ++ "{-# LANGUAGE CPP,MagicHash #-}\n"
|
|
Packit |
2cbdf3 |
optsToInject _ _ = optNoWarnings ++ "{-# LANGUAGE CPP #-}\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
optNoWarnings :: String
|
|
Packit |
2cbdf3 |
optNoWarnings = "{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-missing-signatures #-}\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
importsToInject :: Target -> [CLIFlags] -> String
|
|
Packit |
2cbdf3 |
importsToInject _ cli = always_imports ++ debug_imports ++ glaexts_import
|
|
Packit |
2cbdf3 |
where
|
|
Packit |
2cbdf3 |
glaexts_import | OptGhcTarget `elem` cli = import_glaexts
|
|
Packit |
2cbdf3 |
| otherwise = ""
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
debug_imports | OptDebugParser `elem` cli = import_debug
|
|
Packit |
2cbdf3 |
| otherwise = ""
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- CPP is turned on for -fglasogw-exts, so we can use conditional
|
|
Packit |
2cbdf3 |
-- compilation. We need to #include "config.h" to get hold of
|
|
Packit |
2cbdf3 |
-- WORDS_BIGENDIAN (see GenericTemplate.hs).
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
always_imports :: String
|
|
Packit |
2cbdf3 |
always_imports = "#if __GLASGOW_HASKELL__ >= 603\n" ++
|
|
Packit |
2cbdf3 |
"#include \"ghcconfig.h\"\n" ++
|
|
Packit |
2cbdf3 |
"#elif defined(__GLASGOW_HASKELL__)\n" ++
|
|
Packit |
2cbdf3 |
"#include \"config.h\"\n" ++
|
|
Packit |
2cbdf3 |
"#endif\n" ++
|
|
Packit |
2cbdf3 |
"#if __GLASGOW_HASKELL__ >= 503\n" ++
|
|
Packit |
2cbdf3 |
"import Data.Array\n" ++
|
|
Packit |
2cbdf3 |
"import Data.Array.Base (unsafeAt)\n" ++
|
|
Packit |
2cbdf3 |
"#else\n" ++
|
|
Packit |
2cbdf3 |
"import Array\n" ++
|
|
Packit |
2cbdf3 |
"#endif\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
import_glaexts :: String
|
|
Packit |
2cbdf3 |
import_glaexts = "#if __GLASGOW_HASKELL__ >= 503\n" ++
|
|
Packit |
2cbdf3 |
"import GHC.Exts\n" ++
|
|
Packit |
2cbdf3 |
"#else\n" ++
|
|
Packit |
2cbdf3 |
"import GlaExts\n" ++
|
|
Packit |
2cbdf3 |
"#endif\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
import_debug :: String
|
|
Packit |
2cbdf3 |
import_debug = "#if __GLASGOW_HASKELL__ >= 503\n" ++
|
|
Packit |
2cbdf3 |
"import System.IO\n" ++
|
|
Packit |
2cbdf3 |
"import System.IO.Unsafe\n" ++
|
|
Packit |
2cbdf3 |
"import Debug.Trace\n" ++
|
|
Packit |
2cbdf3 |
"#else\n" ++
|
|
Packit |
2cbdf3 |
"import IO\n" ++
|
|
Packit |
2cbdf3 |
"import IOExts\n" ++
|
|
Packit |
2cbdf3 |
"#endif\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
templateDir :: IO FilePath -> [CLIFlags] -> IO FilePath
|
|
Packit |
2cbdf3 |
templateDir def cli
|
|
Packit |
2cbdf3 |
= case [ d | OptTemplateDir d <- cli ] of
|
|
Packit |
2cbdf3 |
[] -> def
|
|
Packit |
2cbdf3 |
ds -> return (last ds)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
templateFile :: FilePath -> Target -> UsesPreds -> [CLIFlags] -> FilePath
|
|
Packit |
2cbdf3 |
templateFile dir target usespreds cli
|
|
Packit |
2cbdf3 |
= dir ++ "/AlexTemplate" ++ maybe_ghc ++ maybe_debug ++ maybe_nopred
|
|
Packit |
2cbdf3 |
where
|
|
Packit |
2cbdf3 |
maybe_ghc = case target of
|
|
Packit |
2cbdf3 |
GhcTarget -> "-ghc"
|
|
Packit |
2cbdf3 |
_ -> ""
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
maybe_debug
|
|
Packit |
2cbdf3 |
| OptDebugParser `elem` cli = "-debug"
|
|
Packit |
2cbdf3 |
| otherwise = ""
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
maybe_nopred =
|
|
Packit |
2cbdf3 |
case usespreds of
|
|
Packit |
2cbdf3 |
DoesntUsePreds | not (null maybe_ghc)
|
|
Packit |
2cbdf3 |
&& null maybe_debug -> "-nopred"
|
|
Packit |
2cbdf3 |
_ -> ""
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
wrapperFile :: FilePath -> Scheme -> Maybe FilePath
|
|
Packit |
2cbdf3 |
wrapperFile dir scheme =
|
|
Packit |
2cbdf3 |
do
|
|
Packit |
2cbdf3 |
f <- wrapperName scheme
|
|
Packit |
2cbdf3 |
return (dir ++ "/AlexWrapper-" ++ f)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
infoStart :: FilePath -> FilePath -> IO (String -> IO (), IO ())
|
|
Packit |
2cbdf3 |
infoStart x_file info_file = do
|
|
Packit |
2cbdf3 |
bracketOnError
|
|
Packit |
2cbdf3 |
(alexOpenFile info_file WriteMode)
|
|
Packit |
2cbdf3 |
(\h -> do hClose h; removeFile info_file)
|
|
Packit |
2cbdf3 |
(\h -> do infoHeader h x_file
|
|
Packit |
2cbdf3 |
return (hPutStr h, hClose h)
|
|
Packit |
2cbdf3 |
)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
infoHeader :: Handle -> FilePath -> IO ()
|
|
Packit |
2cbdf3 |
infoHeader h file = do
|
|
Packit |
2cbdf3 |
-- hSetBuffering h NoBuffering
|
|
Packit |
2cbdf3 |
hPutStrLn h ("Info file produced by Alex version " ++ projectVersion ++
|
|
Packit |
2cbdf3 |
", from " ++ file)
|
|
Packit |
2cbdf3 |
hPutStrLn h hline
|
|
Packit |
2cbdf3 |
hPutStr h "\n"
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
initialParserEnv :: (Map String CharSet, Map String RExp)
|
|
Packit |
2cbdf3 |
initialParserEnv = (initSetEnv, initREEnv)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
initSetEnv :: Map String CharSet
|
|
Packit |
2cbdf3 |
initSetEnv = Map.fromList [("white", charSet " \t\n\v\f\r"),
|
|
Packit |
2cbdf3 |
("printable", charSetRange (chr 32) (chr 0x10FFFF)), -- FIXME: Look it up the unicode standard
|
|
Packit |
2cbdf3 |
(".", charSetComplement emptyCharSet
|
|
Packit |
2cbdf3 |
`charSetMinus` charSetSingleton '\n')]
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
initREEnv :: Map String RExp
|
|
Packit |
2cbdf3 |
initREEnv = Map.empty
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- -----------------------------------------------------------------------------
|
|
Packit |
2cbdf3 |
-- Command-line flags
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
data CLIFlags
|
|
Packit |
2cbdf3 |
= OptDebugParser
|
|
Packit |
2cbdf3 |
| OptGhcTarget
|
|
Packit |
2cbdf3 |
| OptOutputFile FilePath
|
|
Packit |
2cbdf3 |
| OptInfoFile (Maybe FilePath)
|
|
Packit |
2cbdf3 |
| OptTabSize String
|
|
Packit |
2cbdf3 |
| OptTemplateDir FilePath
|
|
Packit |
2cbdf3 |
| OptLatin1
|
|
Packit |
2cbdf3 |
| DumpHelp
|
|
Packit |
2cbdf3 |
| DumpVersion
|
|
Packit |
2cbdf3 |
deriving Eq
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
argInfo :: [OptDescr CLIFlags]
|
|
Packit |
2cbdf3 |
argInfo = [
|
|
Packit |
2cbdf3 |
Option ['o'] ["outfile"] (ReqArg OptOutputFile "FILE")
|
|
Packit |
2cbdf3 |
"write the output to FILE (default: file.hs)",
|
|
Packit |
2cbdf3 |
Option ['i'] ["info"] (OptArg OptInfoFile "FILE")
|
|
Packit |
2cbdf3 |
"put detailed state-machine info in FILE (or file.info)",
|
|
Packit |
2cbdf3 |
Option ['t'] ["template"] (ReqArg OptTemplateDir "DIR")
|
|
Packit |
2cbdf3 |
"look in DIR for template files",
|
|
Packit |
2cbdf3 |
Option ['g'] ["ghc"] (NoArg OptGhcTarget)
|
|
Packit |
2cbdf3 |
"use GHC extensions",
|
|
Packit |
2cbdf3 |
Option ['l'] ["latin1"] (NoArg OptLatin1)
|
|
Packit |
2cbdf3 |
"generated lexer will use the Latin-1 encoding instead of UTF-8",
|
|
Packit |
2cbdf3 |
Option ['s'] ["tab-size"] (ReqArg OptTabSize "NUMBER")
|
|
Packit |
2cbdf3 |
"set tab size to be used in the generated lexer (default: 8)",
|
|
Packit |
2cbdf3 |
Option ['d'] ["debug"] (NoArg OptDebugParser)
|
|
Packit |
2cbdf3 |
"produce a debugging scanner",
|
|
Packit |
2cbdf3 |
Option ['?'] ["help"] (NoArg DumpHelp)
|
|
Packit |
2cbdf3 |
"display this help and exit",
|
|
Packit |
2cbdf3 |
Option ['V','v'] ["version"] (NoArg DumpVersion) -- ToDo: -v is deprecated!
|
|
Packit |
2cbdf3 |
"output version information and exit"
|
|
Packit |
2cbdf3 |
]
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
-- -----------------------------------------------------------------------------
|
|
Packit |
2cbdf3 |
-- Utils
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
getProgramName :: IO String
|
|
Packit |
2cbdf3 |
getProgramName = liftM (`withoutSuffix` ".bin") getProgName
|
|
Packit |
2cbdf3 |
where str `withoutSuffix` suff
|
|
Packit |
2cbdf3 |
| suff `isSuffixOf` str = take (length str - length suff) str
|
|
Packit |
2cbdf3 |
| otherwise = str
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
bye :: String -> IO a
|
|
Packit |
2cbdf3 |
bye s = putStr s >> exitWith ExitSuccess
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
die :: String -> IO a
|
|
Packit |
2cbdf3 |
die s = hPutStr stderr s >> exitWith (ExitFailure 1)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
dieAlex :: String -> IO a
|
|
Packit |
2cbdf3 |
dieAlex s = getProgramName >>= \prog -> die (prog ++ ": " ++ s)
|
|
Packit |
2cbdf3 |
|
|
Packit |
2cbdf3 |
#if __GLASGOW_HASKELL__ < 610
|
|
Packit |
2cbdf3 |
bracketOnError
|
|
Packit |
2cbdf3 |
:: IO a -- ^ computation to run first (\"acquire resource\")
|
|
Packit |
2cbdf3 |
-> (a -> IO b) -- ^ computation to run last (\"release resource\")
|
|
Packit |
2cbdf3 |
-> (a -> IO c) -- ^ computation to run in-between
|
|
Packit |
2cbdf3 |
-> IO c -- returns the value from the in-between computation
|
|
Packit |
2cbdf3 |
bracketOnError before after thing =
|
|
Packit |
2cbdf3 |
block (do
|
|
Packit |
2cbdf3 |
a <- before
|
|
Packit |
2cbdf3 |
r <- Exception.catch
|
|
Packit |
2cbdf3 |
(unblock (thing a))
|
|
Packit |
2cbdf3 |
(\e -> do { after a; throw e })
|
|
Packit |
2cbdf3 |
return r
|
|
Packit |
2cbdf3 |
)
|
|
Packit |
2cbdf3 |
#endif
|