packages feed

gl-0.1: Parser.hs

{-# LANGUAGE Arrows #-}
-----------------------------------------------------------------------------
-- |
-- Copyright   :  (C) 2014 Edward Kmett and Gabríel Arthúr Pétursson
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  experimental
-- Portability :  portable
--
----------------------------------------------------------------------------
module Parser
  ( parseFile
  ) where

import Control.Applicative
import Registry
import Text.XML.HXT.Core

to :: ArrowXml a => String -> a XmlTree XmlTree
to name = hasName name <<< isElem <<< getChildren

perhaps :: ArrowIf a => a b c -> a b (Maybe c)
perhaps x = (arr Just <<< x) `orElse` arr (const Nothing)

parseCommand :: ArrowXml a => a XmlTree Command
parseCommand = proc x -> do
  command <- to "command" -< x
  name <- getText <<< getChildren <<< to "name" <<< to "proto" -< command
  typ <- parseType <<< to "proto" -< command
  params <- listA $ to "param" >>>
    parseType &&& (getText <<< getChildren <<< to "name") -< command
  returnA -< Command name typ params

parseEnum :: ArrowXml a => a XmlTree Enumeratee
parseEnum = proc x -> do
  enum <- to "enum" -< x
  name <- getAttrValue0 "name" -< enum
  value <- getAttrValue0 "value" -< enum
  returnA -< Enumeratee name value

parseExtension :: ArrowXml a => a XmlTree Extension
parseExtension = proc x -> do
  extension <- to "extension" -< x
  name <- getAttrValue0 "name" -< extension
  supported <- getAttrValue "supported" -< extension
  require <- listA $ parseRequire <<< to "require" -< extension
  returnA -< Extension name supported require

parseFeature :: ArrowXml a => a XmlTree Feature
parseFeature = proc x -> do
  name <- getAttrValue0 "name" -< x
  require <- listA $ parseRequire <<< to "require" -< x
  remove <- listA $ parseRemove <<< to "remove" -< x
  returnA -< Feature name require remove

parseGroup :: ArrowXml a => a XmlTree Group
parseGroup = proc x -> do
  group <- to "group" -< x
  name <- getAttrValue0 "name" -< group
  enum <- listA $ getAttrValue0 "name" <<< to "enum" -< group
  returnA -< Group name enum

parseRemove :: ArrowXml a => a XmlTree Remove
parseRemove = proc x -> do
  profile <- getAttrValue "profile" -< x
  comment <- getAttrValue "comment" -< x
  enums <- listA $ getAttrValue0 "name" <<< to "enum" -< x
  commands <- listA $ getAttrValue0 "name" <<< to "command" -< x
  returnA -< Remove profile comment enums commands

parseRequire :: ArrowXml a => a XmlTree Require
parseRequire = proc x -> do
  comment <- getAttrValue "comment" -< x
  enums <- listA $ getAttrValue0 "name" <<< to "enum" -< x
  commands <- listA $ getAttrValue0 "name" <<< to "command" -< x
  profile <- getAttrValue "profile" -< x
  returnA -< Require enums commands comment profile

parseType :: ArrowXml a => a XmlTree Type
parseType = proc x -> do
  ptype <- perhaps $ getText <<< getChildren <<< to "ptype" -< x
  pointer <- (getText <<< getChildren) >. elem '*' . concat -< x
  returnA -< Type
    { typeName = ptype
    , typePointer = pointer
    }

parse = proc x -> do
  registry <- to "registry" -< x
  groups <- listA $ parseGroup <<< to "groups" -< registry
  enums <- listA $ parseEnum <<< to "enums" -< registry
  extensions <- listA $ parseExtension <<< to "extensions" -< registry
  commands <- listA $ parseCommand <<< to "commands" -< registry
  features <- listA $ parseFeature <<< to "feature" -< registry
  returnA -< Registry
    { registryCommands = commands
    , registryEnums = enums
    , registryExtensions = extensions
    , registryFeatures = features
    , registryGroups = groups
    }

parseFile :: String -> IO Registry
parseFile file = return . head =<< runX (readDocument [withRemoveWS yes] file >>> parse)