{ {- | Module : Lighttpd.Conf.Parser Copyright : (c) Matt Morrow 2008 License : BSD3 Maintainer : Matt Morrow Stability : unstable Portability : portable -} module Lighttpd.Conf.Parser ( parseConf , parseConf' ) where import Lighttpd.Conf.Syntax import Lighttpd.Conf.Lexer import Data.Char import Data.Monoid import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as B } %name parseConfig %tokentype {Token} %error {parseError} %token '$' {TSplice $$} '#' {TComment $$} global {TGlobal} integer {TInteger $$} string {TString $$} boolean {TBoolean $$} name {TName $$} fieldname {TFieldName $$} include {TIncludeValue} include_shell {TIncludeShell} else {TElse} '==' {TEq} '!=' {TNEq} '=~' {TMatch} '!~' {TNotMatch} '=' {TOptionOp} '+=' {TMergeOp} '+' {TPlusVal} '=>' {TArrayValOp} '.' {TDot} ',' {TComma} '(' {TOParen} ')' {TCParen} '[' {TOBrack} ']' {TCBrack} '{' {TOBrace} '}' {TCBrace} %right '+' %nonassoc '==' '!=' '=~' '!~' '=' '+=' %right ',' %% Config :: {Config} : Exps {Config $1} Exp :: {Exp} : '#' {CommentE $1} | global '{' Exps '}' {GlobalCxtE $3} | QName '=' Val {OptionE $1 $3} | QName '+=' Val {MergeE $1 $3} | Include {IncludeE $1} | Cond '{' Exps '}' CondElses {CondE $1 $3 $5} CondElse :: {CondElse} : else Cond '{' Exps '}' {CondElse $2 $4} CondElses :: {[CondElse]} : {- empty -} {[]} | CondElses1 {$1} CondElses1 :: {[CondElse]} : CondElse CondElses1 {$1 : $2} | CondElse {[$1]} Exps :: {[Exp]} : {- empty -} {[]} | Exps1 {$1} Exps1 :: {[Exp]} : Exp Exps1 {$1 : $2} | Exp {[$1]} Val :: {Val} : '$' {SpliceV $1} | string {StringV $1} | integer {IntegerV $1} | boolean {BooleanV (if $1 then Enable else Disable)} | '(' ArrayElems ')' {ArrayV $2} | Val '+' Val {ManyV [$1,$3]} | QName {VarV $1} ArrayElem :: {ArrayElem} : name '=>' Val {ArrayElem (Just (Name $1)) $3} | Val {ArrayElem Nothing $1} ArrayElems :: {[ArrayElem]} : {- empty -} {[]} | ArrayElems1 {$1} ArrayElems1 :: {[ArrayElem]} : ArrayElem ',' ArrayElems1 {$1 : $3} | ArrayElem {[$1]} Name :: {Name} : name {Name $1} QName :: {QName} : name '.' name {QName (Name $1) (Name $3)} Cond :: {Cond} : fieldname '[' string ']' Op string {Cond (Field (Name $1) $3) $5 ((case $5 of op | op `elem` [Equal,NotEqual] -> StringP _ -> RegexP) $6)} Op :: {Op} : '==' {Equal} | '!=' {NotEqual} | '=~' {Match} | '!~' {NotMatch} Include :: {Include} : include Val {ValueI $2} | include_shell string {ShellI $2} { -- XXX: deal with errors less program-endingly parseError :: [Token] -> a parseError xs = error ("Parse error"++(show xs)) lexConf :: ByteString -> [Token] lexConf = scanTokens parseConf :: ByteString -> Maybe Config parseConf s = let toks = lexConf s in if null toks then Nothing else Just (parseConfig toks) parseConf' :: String -> Maybe Config parseConf' = parseConf . B.pack }