content: {-# LANGUAGE OverloadedStrings #-}
  module Parse where
  import Text.Parsec
  import Text.Parsec.Text
  import qualified Data.Text as T
  
  import Types
  encode :: T.Text -> String -> [Chunk]
  encode txt fileName =
      case (parse entire fileName txt) of
      Left err -> []
      Right result -> result
  entire :: Parser Program
  entire = manyTill chunk eof
  chunk :: Parser Chunk
  chunk = (try def) <|> prose
  prose :: Parser Chunk
  prose = grabLine >>= (\line -> return $ Prose line)
  def :: Parser Chunk
  def = do
      (indent, header, lineNum) <- title
      parts <- manyTill (part indent) $ endDef indent
      return $ Def lineNum header parts
  endDef :: String -> Parser ()
  endDef indent = try $ do { skipMany newline; notFollowedBy (string indent) <|> (lookAhead title >> parserReturn ()) }
  -- Returns (indent, macro-name, SourcePos)
  title :: Parser (String, T.Text, SourcePos)
  title = do
      pos <- getPosition
      indent <- many ws
      name <- packM =<< between (string "<<") (string ">>=") (many notDelim)
      newline
      return $ (indent, T.strip name, pos)
  notDelim = noneOf ">="
  part :: String -> Parser Part
  part indent =
      try (string indent >> varLine) <|>
      try (string indent >> defLine) <|>
      (grabLine >>= \extra -> return $ Code extra)
  varLine :: Parser Part
  varLine = do
      indent <- packM =<< many ws
      name <- packM =<< between (string "<<") (string ">>") (many notDelim)
      newline
      return $ Ref name indent
  defLine :: Parser Part
  defLine = do
      line <- grabLine
      return $ Code line
  grabLine :: Parser T.Text
  grabLine = do
      line <- many (noneOf "\n\r")
      last <- newline
      return $ T.pack $ line ++ [last]
  ws :: Parser Char
  ws = char ' ' <|> char '\t'
  packM str = return $ T.pack str
  textP :: Parsec T.Text () T.Text ->  T.Text -> T.Text
  textP p txt =
      case (parse p "" txt) of
      Left err -> T.empty
      Right result -> result
  
  chunkP :: Parsec T.Text () Chunk ->  T.Text -> Maybe Chunk
  chunkP p txt =
      case (parse p "" txt) of
      Left err -> Nothing
      Right result -> Just result
  