{- | Module : $Header$ Description : Parser for conditional compiling Copyright : (c) 2017 Kai-Oliver Prott 2017 Finn Teegen License : BSD-3-clause Maintainer : fte@informatik.uni-kiel.de Stability : experimental Portability : portable TODO -} {-# LANGUAGE CPP #-} module Curry.CondCompile.Parser where #if __GLASGOW_HASKELL__ < 710 import Control.Applicative ((<$>), (<*>), (*>), (<*)) #endif import Text.Parsec import Curry.CondCompile.Type type Parser a = Parsec String () a program :: Parser Program program = statement `sepBy` eol <* eof statement :: Parser Stmt statement = ifElse "if" condition If <|> ifElse "ifdef" identifier IfDef <|> ifElse "ifndef" identifier IfNDef <|> define <|> undef <|> line ifElse :: String -> Parser a -> (a -> [Stmt] -> [Elif] -> Else -> Stmt) -> Parser Stmt ifElse k p c = c <$> (try (many sp *> keyword k *> many1 sp) *> p <* many sp <* eol) <*> many (statement <* eol) <*> many (Elif <$> ((,) <$> (try (many sp *> keyword "elif" *> many1 sp) *> condition <* many sp <* eol) <*> many (statement <* eol))) <*> (Else <$> optionMaybe (try (many sp *> keyword "else" *> many sp) *> eol *> many (statement <* eol))) <* try (many sp <* keyword "endif" <* many sp) define :: Parser Stmt define = Define <$> (try (many sp *> keyword "define" *> many1 sp) *> identifier <* many1 sp) <*> value <* many sp undef :: Parser Stmt undef = Undef <$> (try (many sp *> keyword "undef" *> many1 sp) *> identifier <* many sp) line :: Parser Stmt line = do sps <- many sp try $ ((char '#' "") *> fail "unknown directive") <|> ((Line . (sps ++)) <$> manyTill anyChar (try (lookAhead (eol <|> eof)))) keyword :: String -> Parser String keyword = string . ('#' :) condition :: Parser Cond condition = (Defined <$> (try (string "defined(") *> many sp *> identifier <* many sp <* char ')')) <|> (NDefined <$> (try (string "!defined(") *> many sp *> identifier <* many sp <* char ')')) <|> (Comp <$> (identifier <* many sp) <*> operator <*> (many sp *> value) "condition") identifier :: Parser String identifier = (:) <$> firstChar <*> many (firstChar <|> digit) "identifier" where firstChar = letter <|> char '_' operator :: Parser Op operator = choice [ Leq <$ try (string "<=") , Lt <$ try (string "<") , Geq <$ try (string ">=") , Gt <$ try (string ">") , Neq <$ try (string "!=") , Eq <$ string "==" ] "operator" value :: Parser Int value = fmap read (many1 digit) eol :: Parser () eol = endOfLine *> return () sp :: Parser Char sp = try $ lookAhead (eol *> unexpected "end of line" "") <|> space