Commits

John Lenz  committed f17dd1c

The full latex parser now checks the -b and -f arguments

  • Participants
  • Parent commits 10a74d9

Comments (0)

Files changed (8)

File latex-candle.cabal

       , Text.LatexCandle.Options
       , Text.LatexCandle.Parser
       , Text.LatexCandle.Parser.Commands
+      , Text.LatexCandle.Parser.Header
 
   other-modules:
         Text.LatexCandle.Parser.Base

File src/Text/LatexCandle/Options.hs

 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -}
 
+{-# LANGUAGE FlexibleContexts #-}
+
 module Text.LatexCandle.Options(
-    Options(..)
-  , defaultOptions
+  -- * Working with Options
+    defaultOptions
   , processArguments
   , getargOptions
+  , testOpt
+
+  -- * Options
+  , Options(..)
 ) where
 
+import Control.Monad.Reader
 import System.Console.GetOpt
 
 data Options = Options {
      (actions, [], []) -> Right $ foldl (flip (.)) id actions o
      (_,_,err@(_:_))   -> Left $ concat err
      (_,args,[])       -> Left $ "Extra arguments " ++ show args
+
+-- | Run a parser only if the given option is true.
+testOpt :: MonadReader Options m => (Options -> Bool) -> m () -> m ()
+testOpt f a = asks f >>= flip when a

File src/Text/LatexCandle/Parser.hs

 
     -- * Parsers
   , whitespace
+  , latexBody
+  , documentclass
+  , latexFullDoc
   , latexParser
 ) where
 
+import Control.Monad.Reader (asks)
+import Text.LatexCandle.Options
 import Text.LatexCandle.Parser.Base
-import Text.LatexCandle.Parser.Commands
+import Text.LatexCandle.Parser.Header
 
-beginDoc :: LatexP ()
-beginDoc = void (string "\\begin{document}") <?> "\\begin{document}"
+-- | Check a LaTeX body: the text between \begin{document} and \end{document}.
+-- This is the parser used if --only-body is passed as an option.
+latexBody :: LatexP ()
+latexBody = void $ manyTill anyChar $ try (lookAhead $ string_ "\\end{document}") <|> eof
 
-endDoc :: LatexP ()
-endDoc = do void (string "\\end{document}") <?> "\\end{document}"
-            whitespace
-            eof
+-- | Check a full LaTeX document except the documentclass, which must be parsed
+-- separately using 'documentclass'. This is the parser used if --full-document
+-- is passed as an option.
+latexFullDoc :: LatexP ()
+latexFullDoc = do
+   whitespace
+   header
+   string_ "\\begin{document}"
+   whitespace
+   latexBody
+   string_ "\\end{document}" <|> tellErr "Expecting \\end{document}"
+   whitespace
+   eof <|> tellErr "Extra characters after \\end{document}"
 
--- | Parse an entire LaTeX document, from documentclass to the end of the file
+-- | Parse a LaTeX document.  Calls either 'latexBody' or 'latexFullDoc' depending
+-- on options or if no options are given detecting the existance of documentclass
 latexParser :: LatexP ()
-latexParser = whitespace >> documentclass >> beginDoc >> skipMany (space <|> newline) >> endDoc
+latexParser = do
+    onlybody <- asks optOnlyBody
+    fulldoc  <- asks optFullDocument
+    case (onlybody, fulldoc) of
+       (True, False) -> latexBody
+
+       (False, True) -> do whitespace
+                           documentclass <|> tellErr "Expecting documentclass"
+                           latexFullDoc
+
+       _             -> do whitespace
+                           hasdoc <- (try documentclass >> return True) <|> return False
+                           if hasdoc
+                             then latexFullDoc
+                             else latexBody

File src/Text/LatexCandle/Parser/Base.hs

 
     -- * Basic parsers
   , whitespace
+  , string_
 
     -- * Re-exports
   , module X
 import Text.Parsec.Prim as X ((<?>), skipMany, try)
 import Text.Parsec.Char as X
 import Text.Parsec.Combinator as X
-import Text.Parsec.Text.Lazy () -- For Stream instance
+import Text.Parsec.Text.Lazy as X () -- For Stream instance
 
 import Text.LatexCandle.Errors as X
 import Text.LatexCandle.Options as X
 runLatexM :: Options -> LatexM () -> [LatexError]
 runLatexM o (LatexM w) = snd $ runReader (runWriterT w) o
 
+-- | Parse a string and discard the result.
+string_ :: String -> LatexP ()
+string_ = void . string
+
 -- | A whitespace parser.  Skips spaces, tabs, and single line comments
 whitespace :: LatexP ()
 whitespace = void $ many (void space 
                <|> void newline
-               <|> (void $ char '%' >> manyTill anyChar newline))
+               <|> void (char '%' >> manyTill anyChar newline))
 

File src/Text/LatexCandle/Parser/Commands.hs

 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -}
 
-{-# LANGUAGE FlexibleContexts #-}
-
 -- | Contains the parsers for all the different LaTeX commands
 module Text.LatexCandle.Parser.Commands(
     optionalArgument
   , requiredArgumentInBrace
-  , documentclass
 ) where
 
-import Control.Monad.Writer.Class
-import Control.Monad.Trans.Class (lift)
 import Text.LatexCandle.Parser.Base
 
 -- | Parse an optional argument to a command.
     whitespace
     void (char '}') <|> tellErrM start "No matching closing brace '}' found"
     return ret
-
-checkValidClass :: MonadWriter [LatexError] m => Range -> String -> [(Range,String)] -> m ()
-checkValidClass _ _ _ = return ()
-
--- | A parser for the documentclass command.  Expects leading whitespace to have been already skipped.
--- If the documentclass command is not found, the parser succeeds but logs an error.
-documentclass :: LatexP ()
-documentclass = documentclassReq <|> tellErr "Expecting documentclass"
-
-documentclassReq :: LatexP ()
-documentclassReq = do
-    void $ try $ string "\\documentclass"
-
-    opt <- optionalArgument
-
-    docClassStart <- mark
-    cl <-     requiredArgumentInBrace (many (alphaNum <|> space))
-         <|> (tellErr "Expecting document class" >> return "")
-    docClassEnd <- mark
-
-    lift $ checkValidClass (docClassStart, docClassEnd) cl opt
-
-    whitespace
-
-    return ()

File src/Text/LatexCandle/Parser/Header.hs

+{-
+Copyright (C) 2012 John Lenz <lenz@math.uic.edu>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+
+{-# LANGUAGE FlexibleContexts #-}
+
+module Text.LatexCandle.Parser.Header(
+    documentclass
+  , header
+) where
+
+import Control.Monad.Writer.Class
+import Control.Monad.Trans.Class (lift)
+import Text.LatexCandle.Parser.Base
+import Text.LatexCandle.Parser.Commands
+
+-- | A parser for the documentclass command.  Expects leading whitespace to have been already skipped.
+-- If the documentclass command is not found, the parser fails.
+documentclass :: LatexP ()
+documentclass = do
+    try $ string_ "\\documentclass"
+
+    opt <- optionalArgument
+
+    docClassStart <- mark
+    cl <-     requiredArgumentInBrace (many (alphaNum <|> space))
+         <|> (tellErr "Expecting document class" >> return "")
+    docClassEnd <- mark
+
+    lift $ checkValidClass (docClassStart, docClassEnd) cl opt
+
+    whitespace
+
+    return ()
+
+checkValidClass :: MonadWriter [LatexError] m => Range -> String -> [(Range,String)] -> m ()
+checkValidClass _ _ _ = return ()
+
+-- | Check the header: everything between documentclass and \begin{document}
+-- Currently this does no checking.
+header :: LatexP ()
+header = void $ manyTill anyChar $ try (lookAhead $ string_ "\\begin{document}") <|> eof

File test/tex/beginend.tex

-\documentclass{article}
-\begin{document}
-
-\end{document}

File test/tex/empty.tex

+\documentclass{article}
+\begin{document}
+
+\end{document}
+
+%Run:detect:
+
+%Run:forcefull: -f