packages feed

SableCC2Hs-0.0.0.1: src/SableCC/XML/XML2Parser.hs

----------------------------------------------------------------------------
-- |
-- Module      :  SableCC.XML.XML2Parser
-- Copyright   :  (c) Fontaine 2011
-- License     :  BSD3
--
-- Maintainer  :  fontaine@cs.uni-duesseldorf.de
-- Stability   :  experimental
-- Portability :  GHC-only
--
-- Todo: This is all repetitive boilerplate
-- Replace this with a more powerfull XML-combinator libary.
-----------------------------------------------------------------------------

{-# LANGUAGE RecordWildCards, TemplateHaskell #-}
module SableCC.XML.XML2Parser
(
  readParser
)
where

import SableCC.XML.ParserDefinitionRaw as Raw

import Text.XML.Light
import Text.XML.Light.Input
import Text.XML.Light.Proc
import Debug.Trace.LocationTH
import Data.Maybe

-- | Read a SableCC generated XML file
-- and compute a low-level Haskell representation of the XML content.
readParser :: FilePath -> IO Parser
readParser fname = do
  src <- readFile fname
  return $ toParser
    $ fromMaybe (error ("cannot parse XML at " ++ $__LOCATION__)) $ parseXMLDoc src

toParser :: Element -> Parser
toParser doc = Parser {..}
  where
    parser_tokens = toTokens $ getChild $__LOCATION__ "tokens" doc
    parser_parser_eof_index
      = read $ getAttr $__LOCATION__ "parser_index"
               $ getChild $__LOCATION__ "eof" $ getChild $__LOCATION__ "tokens" doc
    parser_prods
      = map toProd $ findChildren (unqual "prod")$ getChild $__LOCATION__ "prods" doc

    parser_lexer_data = toLexer $ getChild $__LOCATION__ "lexer_data" doc
    parser_parser_data = toParserData $ getChild $__LOCATION__ "parser_data" doc
    parser_rules = map toRule $ findChildren (unqual "rule") $ getChild $__LOCATION__ "rules" doc

getChild :: String -> String -> Element -> Element
getChild loc name xml = case findChild (unqual name) xml of
  Just e -> e
  Nothing -> error $ "cannot find child " ++ name ++ " in XML at " ++ loc

getAttr :: String -> String -> Element -> String
getAttr loc name xml = case findAttr (unqual name) xml of
  Just e -> e
  Nothing -> error $ "cannot find attribute " ++ name ++ " in XML at " ++ loc


getBoolAttr :: String -> Element -> Bool
getBoolAttr name doc
  = case (findAttr (unqual name) doc) of
      Just "true" -> True
      _ -> False

toTokens :: Element -> [Token]
toTokens = map toToken . findChildren (unqual "token")
  where
    toToken :: Element -> Token
    toToken e = Token {
       token_name = getAttr $__LOCATION__ "name" e
      ,token_ename = getAttr $__LOCATION__ "ename" e
      ,token_parser_index = fmap read $ findAttr (unqual "parser_index") e
      ,token_parser_text = findAttr (unqual "text") e
      ,token_transitions = map toTransition $ findChildren (unqual "transition") e
      }
    toTransition e = (getAttr $__LOCATION__ "from" e, getAttr $__LOCATION__ "to" e)


toLexer :: Element -> Lexer_Data
toLexer e = Lexer_Data {..}
  where
   lexer_modeNames
     = map (\x -> (getAttr $__LOCATION__ "name" x, read $ getAttr $__LOCATION__ "id" x))
           (findChildren (unqual "state") e)
   lexer_accept_table
     = map getIList $ findChildren (unqual "state")
             $ getChild $__LOCATION__ "accept_table" e
   getIList = map (read . strContent) . findChildren (unqual "i")
   lexer_goto_table = map toRowList $ findChildren (unqual "state") $
       getChild $__LOCATION__ "goto_table" e
   toRowList = map toGotoList . findChildren (unqual "row")
   toGotoList = map toGoto . findChildren (unqual "goto")
   toGoto x = Lexer_Goto {
     lexer_goto_state = read $ getAttr $__LOCATION__ "state" x
    ,lexer_goto_high = read $ getAttr $__LOCATION__ "high" x
    ,lexer_goto_low  = read $ getAttr $__LOCATION__ "low" x
    }




toParserData :: Element -> Parser_Data
toParserData doc = Parser_Data {..}
  where
    parser_error_messages = map strContent $ findChildren (unqual "msg")
                                  $ getChild $__LOCATION__ "error_messages" doc
    parser_errors = map (read . strContent) $ findChildren (unqual "i")
                                  $ getChild $__LOCATION__ "errors" doc
    parser_goto_table = map mkGotoList $ findChildren (unqual "row") $ getChild $__LOCATION__ "goto_table" doc

    mkGotoList = map (\x -> (read $ getAttr $__LOCATION__ "from" x,read $ getAttr $__LOCATION__ "to" x))
                   . findChildren (unqual "goto")
    parser_action_table = map (map toParserAction . findChildren (unqual "action"))
                              $ findChildren (unqual "row") $ getChild $__LOCATION__ "action_table" doc

    toParserAction x = ParserAction {
          action_to     = read $ getAttr $__LOCATION__ "to" x
         ,action_action = read $ getAttr $__LOCATION__ "action" x
         ,action_from   = read $ getAttr $__LOCATION__ "from" x
         }

toRule :: Element -> Rule
toRule doc = Rule {..}
  where
   rule_index = read $ getAttr $__LOCATION__ "index" doc
   rule_ename = getAttr $__LOCATION__ "ename" doc
   rule_leftside = read $ getAttr $__LOCATION__ "leftside" doc
   rule_actions = map toAction $ findChildren (unqual "action") doc


toAction :: Element -> Action
toAction doc = case getAttr $__LOCATION__ "cmd" doc of
  "POP" -> Pop args
  "MAKELIST" -> MakeList args
  "FETCHLIST" -> FetchList args
  "ADDLIST" -> AddList args
  "ADDNODE"   -> AddNode args
  "MAKENODE" -> MakeNode args
  "RETURNNODE" -> ReturnNode args
  "FETCHNODE" -> FetchNode args
  "RETURNLIST" -> ReturnList args
  attr -> error $ $__LOCATION__ ++ " cannot parse Action :" ++ attr
  where
    args = ActionArgs {..}
    action_result = optionalAttr $__LOCATION__ "result"
    action_index  = read $ optionalAttr "0" "index"
    action_etype  = optionalAttr $__LOCATION__ "etype"
    action_arg_from   = optionalAttr $__LOCATION__ "from"
    action_null   = case optionalAttr "false" "null" of
                        "true" -> True
                        "false" -> False
    action_node   = optionalAttr $__LOCATION__ "node"
    action_list   = optionalAttr $__LOCATION__ "list"
    action_tolist = optionalAttr $__LOCATION__ "tolist"
    action_fromlist = optionalAttr $__LOCATION__ "fromlist"
    action_args = map mkArg $ findChildren (unqual "arg") doc
    optionalAttr :: String -> String -> String
    optionalAttr def name = fromMaybe def $ findAttr (unqual name) doc

    mkArg :: Element -> ActionArgElem
    mkArg x = case (getBoolAttr "null" x, getBoolAttr "is_list" x) of
                (True , False) -> ActionArgNull
                (False, True ) -> ActionArgList $ strContent x
                (False, False) -> ActionArg $ strContent x
                _ -> error $__LOCATION__


toProd :: Element -> Prod
toProd doc = Prod {..}
  where
    prod_name   = getAttr $__LOCATION__ "name" doc
    prod_ename  = getAttr $__LOCATION__ "ename" doc
    prod_alt    = map toAlt $ findChildren (unqual "alt") doc

    toAlt :: Element -> Alt
    toAlt doc = Alt {..}
      where
        alt_name  = getAttr $__LOCATION__ "name" doc
        alt_ename = getAttr $__LOCATION__ "ename" doc
        alt_elem  = map toElem $ findChildren (unqual "elem") doc

    toElem :: Element -> Elem
    toElem doc = Raw.Elem {..}
      where
        elem_modifier = getAttr $__LOCATION__ "modifier" doc
        elem_name     = getAttr $__LOCATION__ "name" doc
        elem_ename    = getAttr $__LOCATION__ "ename" doc
        elem_type     = getAttr $__LOCATION__ "type" doc
        elem_etype    = getAttr $__LOCATION__ "etype" doc
        elem_is_list  = getBoolAttr "is_list" doc
        elem_is_token = getBoolAttr "is_token" doc