Last active
October 22, 2015 15:32
-
-
Save izgzhen/bb0b3d12998e90d5bbf8 to your computer and use it in GitHub Desktop.
Parse autoconf.mk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- autoconf parser | |
module AutoParser where | |
import Data.List.Extra (splitOn) | |
import qualified Data.Map as M | |
isComment ('#':_) = True | |
isComment _ = False | |
isBlank = all (`elem` " \n\t\r") | |
data Segment = Plain String | |
| Var String | |
| For String String String | |
deriving (Show) | |
parseRHS :: String -> [Segment] | |
parseRHS "" = [] | |
parseRHS s = case span (/= '$') s of | |
("", '$':_:rest) | take 7 rest == "foreach" -> foreach (drop 7 rest) | |
("", '$':_:rest) -> f Var rest | |
(plain, rest) -> Plain plain : parseRHS rest | |
where | |
f cons rest = case span (not . flip elem "})") rest of | |
(_, "") -> error "undefined string" | |
(var, _:rest) -> cons var : parseRHS rest | |
foreach rest = case splitOn "," rest of | |
(var:src:str:[]) -> [For var src (drop (length str - 1) str)] | |
_ -> error $ "illegal foreach: " ++ rest | |
data Expr = Assign String String | |
| Append String String | |
parseExpr :: M.Map String String -> Expr -> M.Map String String | |
parseExpr m expr = let f v = concat $ (map fSeg) (parseRHS v) | |
in case expr of | |
Assign k v -> M.insert k (f v) m | |
Append k v -> | |
case M.lookup k m of | |
Nothing -> error $ "not defined: " ++ k | |
Just v' -> M.insert k (v' ++ " " ++ f v) m | |
where | |
fSeg seg = case seg of | |
Plain x -> x | |
Var var -> case M.lookup var m of | |
Nothing -> error $ "not defined: " ++ var | |
Just value -> value | |
For iter src str -> | |
let srcs = case src of | |
'$':_:rest -> | |
let rest' = take (length rest - 1) rest | |
in case M.lookup rest' m of | |
Nothing -> error $ "not defined: " ++ rest' | |
Just v -> words v | |
x -> words x | |
xs = flip map srcs $ \str -> | |
let Just k = M.lookup "____" (parseExpr m (Assign "____" str)) | |
in k | |
in unwords xs | |
breakdown :: String -> Expr | |
breakdown s = case words s of | |
var:":=":key -> Assign var (unwords key) | |
var:"+=":key -> Append var (unwords key) | |
_ -> error $ "illegal line: " ++ show s | |
parseText :: [String] -> M.Map String String | |
parseText = foldl parseExpr M.empty . map breakdown | |
readAutoConf :: String -> IO (M.Map String String) | |
readAutoConf filename = do | |
s <- readFile filename | |
let lns = filter (not . isBlank) . filter (not . isComment) $ lines s | |
return $ parseText lns |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment