OpenGLRaw-2.0.0.0: RegistryProcessor/src/Registry.hs
-- This module contains a 1:1 translation of registry.rnc with an (un-)parser.
-- No simplifications or GL/GLX/EGL/WGL-specific things are done here.
module Registry (
parseRegistry, unparseRegistry,
Registry(..),
RegistryElement(..),
Types(..),
Type(..),
Groups(..),
Group(..),
Enums(..),
Enum'(..),
Unused(..),
Commands(..),
Command(..),
Proto(..),
Param(..),
GLX(..),
Feature(..),
Modification(..),
ModificationKind(..),
Extensions(..),
Extension(..),
ConditionalModification(..),
InterfaceElement(..),
InterfaceElementKind(..),
Integer'(..),
TypeName(..),
TypeSuffix(..),
StringGroup(..),
ProfileName(..),
Vendor(..),
Comment(..),
Name(..)
) where
import Data.Maybe ( maybeToList )
import Text.XML.HXT.Core
parseRegistry :: String -> Either String Registry
parseRegistry = head . (runLA $
xreadDoc >>>
neg isXmlPi >>>
removeAllWhiteSpace >>>
canonicalizeAllNodes >>> -- needed to e.g. process CDATA, remove XML comments, etc.
arr (unpickleDoc' xpRegistry))
unparseRegistry :: Registry -> String
unparseRegistry =
concat . (pickleDoc xpRegistry >>>
runLA (writeDocumentToString [withIndent yes,
withOutputEncoding utf8,
withXmlPi yes]))
-- Note: We do this slightly different from the schema.
newtype Registry = Registry {
unRegistry :: [RegistryElement]
} deriving (Eq, Ord, Show)
xpRegistry :: PU Registry
xpRegistry =
xpWrap (Registry, unRegistry) $
xpElem "registry" $
xpList xpRegistryElement
data RegistryElement
= CommentElement { unCommentElement :: Comment }
| TypesElement { unTypesElement:: Types }
| GroupsElement { unGroupsElement :: Groups }
| EnumsElement { unEnumsElement :: Enums }
| CommandsElement { unCommandsElement :: Commands }
| FeatureElement { unFeatureElement :: Feature }
| ExtensionsElement { unExtensionsElement :: Extensions }
deriving (Eq, Ord, Show)
xpRegistryElement :: PU RegistryElement
xpRegistryElement = xpAlt tag pus
where tag (CommentElement _)= 0
tag (TypesElement _) = 1
tag (GroupsElement _) = 2
tag (EnumsElement _) = 3
tag (CommandsElement _) = 4
tag (FeatureElement _) = 5
tag (ExtensionsElement _) = 6
pus = [ xpWrap (CommentElement, unCommentElement) $
xpElem "comment" xpComment
, xpWrap (TypesElement, unTypesElement) xpTypes
, xpWrap (GroupsElement, unGroupsElement) xpGroups
, xpWrap (EnumsElement, unEnumsElement) xpEnums
, xpWrap (CommandsElement, unCommandsElement) xpCommands
, xpWrap (FeatureElement, unFeatureElement) xpFeature
, xpWrap (ExtensionsElement, unExtensionsElement) xpExtensions ]
newtype Types = Types {
unTypes :: [Type]
} deriving (Eq, Ord, Show)
xpTypes :: PU Types
xpTypes =
xpWrap (Types, unTypes) $
xpElem "types" $
xpList xpType
data Type = Type {
typeAPI :: Maybe String,
typeRequires :: Maybe String,
typeName1 :: Maybe TypeName,
typeType :: Maybe String,
typeComment :: Maybe Comment,
typeText1 :: String,
typeAPIEntry :: Maybe String,
typeText2 :: String,
typeName2 :: Maybe TypeName,
typeText3 :: String
} deriving (Eq, Ord, Show)
xpType :: PU Type
xpType =
xpWrap (\(a,b,c,d,e,f,g,h,i,j) -> Type a b c d e f g h i j
,\(Type a b c d e f g h i j) -> (a,b,c,d,e,f,g,h,i,j)) $
xpElem "type" $
xp10Tuple
(xpAttrImplied "api" xpText)
(xpAttrImplied "requires" xpText)
(xpAttrImplied "name" xpTypeName)
(xpAttrImplied "type" xpText)
(xpOption xpCommentAttr)
xpText0
(xpOption $ xpElem "apientry" xpText0)
xpText0
(xpOption $ xpElem "name" xpTypeName)
xpText0
newtype Groups = Groups {
unGroups :: [Group]
} deriving (Eq, Ord, Show)
xpGroups :: PU Groups
xpGroups =
xpWrap (Groups, unGroups) $
xpElem "groups" $
xpList xpGroup
data Group = Group {
groupName :: Name,
groupComment :: Maybe Comment,
groupEnums :: [Name]
} deriving (Eq, Ord, Show)
xpGroup :: PU Group
xpGroup =
xpWrap (\(a,b,c) -> Group a b c
,\(Group a b c) -> (a,b,c)) $
xpElem "group" $
xpTriple
xpName
(xpOption xpCommentAttr)
(xpList $ xpElem "enum" xpName)
data Enums = Enums {
enumsNamespace :: Maybe String,
enumsGroup :: Maybe String,
enumsType :: Maybe String,
-- enumsStart is conceptually a 'Maybe Integer', but egl.xml cheats a bit and
-- uses e.g. 'start="0x3060-0x306F"' as a shorthand for
-- 'start="0x3060" end="0x306F"'.
enumsStart :: Maybe Integer',
enumsEnd :: Maybe Integer',
enumsVendor :: Maybe Vendor,
enumsComment :: Maybe Comment,
enumsEnumOrUnuseds :: [Either Enum' Unused]
} deriving (Eq, Ord, Show)
xpEnums :: PU Enums
xpEnums =
xpWrap (\(a,b,c,d,e,f,g,h) -> Enums a b c d e f g h
,\(Enums a b c d e f g h) -> (a,b,c,d,e,f,g,h)) $
xpElem "enums" $
xp8Tuple
(xpAttrImplied "namespace" xpText)
(xpAttrImplied "group" xpText)
(xpAttrImplied "type" xpText)
(xpAttrImplied "start" xpInteger)
(xpAttrImplied "end" xpInteger)
(xpOption xpVendor)
(xpOption xpCommentAttr)
(xpList $ xpEither xpEnum xpUnused)
xpEither :: PU a -> PU b -> PU (Either a b)
xpEither pl pr = xpAlt tag pus
where tag (Left _) = 0
tag (Right _) = 1
pus = [ xpWrap (Left, \(Left l) -> l) pl
, xpWrap (Right, \(Right r) -> r) pr ]
data Enum' = Enum {
enumValue :: String,
enumAPI :: Maybe String,
enumType :: Maybe TypeSuffix,
enumName :: String,
enumAlias :: Maybe String,
enumComment :: Maybe Comment
} deriving (Eq, Ord, Show)
-- NOTE: The spec uses the interleave pattern, which is not needed: Attributes
-- are by definition unordered.
xpEnum :: PU Enum'
xpEnum =
xpWrap (\(a,b,c,d,e,f) -> Enum a b c d e f
,\(Enum a b c d e f) -> (a,b,c,d,e,f)) $
xpElem "enum" $
xp6Tuple
(xpAttr "value" xpText)
(xpAttrImplied "api" xpText)
(xpAttrImplied "type" xpTypeSuffix)
(xpAttr "name" xpText)
(xpAttrImplied "alias" xpText)
(xpOption xpCommentAttr)
data Unused = Unused {
unusedStart :: Integer',
unusedEnd :: Maybe Integer',
unusedVendor :: Maybe Vendor,
unusedComment :: Maybe Comment
} deriving (Eq, Ord, Show)
xpUnused :: PU Unused
xpUnused =
xpWrap (\(a,b,c,d) -> Unused a b c d
,\(Unused a b c d) -> (a,b,c,d)) $
xpElem "unused" $
xp4Tuple
(xpAttr "start" xpInteger)
(xpAttrImplied "end" xpInteger)
(xpOption xpVendor)
(xpOption xpCommentAttr)
data Commands = Commands {
commandsNamespace :: Maybe String,
commandsCommands :: [Command]
} deriving (Eq, Ord, Show)
xpCommands :: PU Commands
xpCommands =
xpWrap (\(a,b) -> Commands a b
,\(Commands a b) -> (a,b)) $
xpElem "commands" $
xpPair
(xpAttrImplied "namespace" xpText)
(xpList xpCommand)
data Command = Command {
commandComment :: Maybe Comment,
commandProto :: Proto,
commandParams :: [Param],
commandAlias :: Maybe Name,
commandVecEquiv :: Maybe Name,
commandGLXs :: [GLX]
} deriving (Eq, Ord, Show)
xpCommand :: PU Command
xpCommand =
xpWrap (\(a,b,c,(d,e,f)) -> Command a b c d e f
,\(Command a b c d e f) -> (a,b,c,(d,e,f))) $
xpElem "command" $
xp4Tuple
(xpOption xpCommentAttr)
xpProto
(xpList xpParam)
xpCommandTail
-- The spec uses the interleave pattern here, which is not supported in hxt.
-- As a workaround, we use a list of disjoint types.
xpCommandTail :: PU (Maybe Name, Maybe Name, [GLX])
xpCommandTail =
xpWrapEither (\xs -> do a <- check "alias" [x | AliasElement x <- xs]
b <- check "vecequiv" [x | VecEquivElement x <- xs]
c <- return [x | GLXElement x <- xs]
return (a,b,c)
,\(a,b,c) -> map AliasElement (maybeToList a) ++
map VecEquivElement (maybeToList b) ++
map GLXElement c) $
xpList $
xpAlt tag pus
where tag (AliasElement _) = 0
tag (VecEquivElement _) = 1
tag (GLXElement _) = 2
pus = [xpWrap (AliasElement,unAliasElement) $ xpElem "alias" xpName
,xpWrap (VecEquivElement,unVecEquivElement) $ xpElem "vecequiv" xpName
,xpWrap (GLXElement,unGLXElement) xpGLX]
check n xs = case xs of
[] -> Right Nothing
[x] -> Right $ Just x
_ -> Left $ "expected at most one '" ++ n ++ "' element"
data CommandTail
= AliasElement { unAliasElement :: Name }
| VecEquivElement { unVecEquivElement :: Name }
| GLXElement { unGLXElement :: GLX }
deriving (Eq, Ord, Show)
data Proto = Proto {
protoGroup :: Maybe String,
protoText1 :: String,
protoPtype :: Maybe TypeName,
protoText2 :: String,
protoName :: String,
protoText3 :: String
} deriving (Eq, Ord, Show)
xpProto :: PU Proto
xpProto =
xpWrap (\(a,b,c,d,e,f) -> Proto a b c d e f
,\(Proto a b c d e f) -> (a,b,c,d,e,f)) $
xpElem "proto" $
xp6Tuple
(xpAttrImplied "group" xpText)
xpText0
(xpOption $ xpElem "ptype" xpTypeName)
xpText0
(xpElem "name" xpText)
xpText0
data Param = Param {
paramLen :: Maybe String,
paramProto :: Proto
} deriving (Eq, Ord, Show)
xpParam :: PU Param
xpParam =
xpWrap (\(b,a,c,d,e,f,g) -> Param a (Proto b c d e f g)
,\(Param a (Proto b c d e f g)) -> (b,a,c,d,e,f,g)) $
xpElem "param" $
xp7Tuple
(xpAttrImplied "group" xpText)
(xpAttrImplied "len" xpText)
xpText0
(xpOption $ xpElem "ptype" xpTypeName)
xpText0
(xpElem "name" xpText)
xpText0
data GLX = GLX {
glxType :: String,
glxOpcode :: Int,
glxName :: Maybe Name,
glxComment :: Maybe Comment
} deriving (Eq, Ord, Show)
xpGLX :: PU GLX
xpGLX =
xpWrap (\(a,b,c,d) -> GLX a b c d
,\(GLX a b c d) -> (a,b,c,d)) $
xpElem "glx" $
xp4Tuple
(xpAttr "type" xpText)
(xpAttr "opcode" xpInt)
(xpOption xpName)
(xpOption xpCommentAttr)
data Feature = Feature {
featureAPI :: String,
featureName :: Name,
featureNumber :: String, -- actually xsd:decimal, but used as a string
featureProtect :: Maybe String,
featureComment :: Maybe Comment,
featureModifications :: [Modification]
} deriving (Eq, Ord, Show)
xpFeature :: PU Feature
xpFeature =
xpWrap (\(a,b,c,d,e,f) -> Feature a b c d e f
,\(Feature a b c d e f) -> (a,b,c,d,e,f)) $
xpElem "feature" $
xp6Tuple
(xpAttr "api" xpText)
xpName
(xpAttr "number" xpText)
(xpAttrImplied "protect" xpText)
(xpOption xpCommentAttr)
(xpList xpModification)
data Modification = Modification {
modificationModificationKind :: ModificationKind,
modificationProfileName :: Maybe ProfileName,
modificationComment :: Maybe Comment,
modificationInterfaceElements :: [InterfaceElement]
} deriving (Eq, Ord, Show)
data ModificationKind = Require | Remove -- TODO: Better name
deriving (Eq, Ord, Show, Enum)
xpModification :: PU Modification
xpModification =
xpAlt (fromEnum . modificationModificationKind) pus
where pus = [ xpMod "require" Require
, xpMod "remove" Remove ]
xpMod el kind =
xpWrap (\(a,b,c) -> Modification kind a b c
,\(Modification _ a b c) -> (a,b,c)) $
xpElem el $
xpTriple
(xpOption xpProfileName)
(xpOption xpCommentAttr)
(xpList xpInterfaceElement)
newtype Extensions = Extensions {
unExtensions :: [Extension]
} deriving (Eq, Ord, Show)
xpExtensions :: PU Extensions
xpExtensions =
xpWrap (Extensions, unExtensions) $
xpElem "extensions" $
xpList xpExtension
data Extension = Extension {
extensionName :: Name,
extensionProtect :: Maybe String,
extensionSupported :: Maybe StringGroup,
extensionComment :: Maybe Comment,
extensionsRequireRemove :: [ConditionalModification]
} deriving (Eq, Ord, Show)
xpExtension :: PU Extension
xpExtension =
xpWrap (\(a,b,c,d,e) -> Extension a b c d e
,\(Extension a b c d e) -> (a,b,c,d,e)) $
xpElem "extension" $
xp5Tuple
xpName
(xpAttrImplied "protect" xpText)
(xpAttrImplied "supported" xpStringGroup)
(xpOption xpCommentAttr)
(xpList xpConditionalModification)
data ConditionalModification = ConditionalModification {
conditionalModificationAPI :: Maybe String,
conditionalModificationModification :: Modification
} deriving (Eq, Ord, Show)
xpConditionalModification :: PU ConditionalModification
xpConditionalModification =
xpAlt (fromEnum . modificationModificationKind . conditionalModificationModification) pus
where pus = [ xpMod "require" Require
, xpMod "remove" Remove ]
xpMod el kind =
xpWrap (\(a,b,c,d) -> ConditionalModification a (Modification kind b c d)
,\(ConditionalModification a (Modification _ b c d)) -> (a,b,c,d)) $
xpElem el $
xp4Tuple
(xpAttrImplied "api" xpText)
(xpOption xpProfileName)
(xpOption xpCommentAttr)
(xpList xpInterfaceElement)
data InterfaceElement = InterfaceElement {
interfaceElementKind :: InterfaceElementKind,
interfaceElementName :: Name,
interfaceElementComment :: Maybe Comment
} deriving (Eq, Ord, Show)
data InterfaceElementKind
= InterfaceElementType
| InterfaceElementEnum
| InterfaceElementCommand
deriving (Eq, Ord, Show, Enum)
xpInterfaceElement :: PU InterfaceElement
xpInterfaceElement = xpAlt (fromEnum . interfaceElementKind) pus
where pus = [ xpIE InterfaceElementType "type"
, xpIE InterfaceElementEnum "enum"
, xpIE InterfaceElementCommand "command" ]
xpIE ty el =
xpWrap (\(a,b) -> InterfaceElement ty a b
,\(InterfaceElement _ a b) -> (a,b)) $
xpElem el $
xpPair
xpName
(xpOption xpCommentAttr)
newtype Integer' = Integer { unInteger :: String } deriving (Eq, Ord, Show)
xpInteger :: PU Integer'
xpInteger = xpWrap (Integer, unInteger) xpText
newtype TypeName = TypeName { unTypeName :: String } deriving (Eq, Ord, Show)
xpTypeName :: PU TypeName
xpTypeName = xpWrap (TypeName, unTypeName) xpText
newtype TypeSuffix = TypeSuffix { unTypeSuffix :: String } deriving (Eq, Ord, Show)
xpTypeSuffix :: PU TypeSuffix
xpTypeSuffix = xpWrap (TypeSuffix, unTypeSuffix) xpText
newtype StringGroup = StringGroup { unStringGroup :: String } deriving (Eq, Ord, Show)
xpStringGroup :: PU StringGroup
xpStringGroup = xpWrap (StringGroup, unStringGroup) xpText
newtype ProfileName = ProfileName { unProfileName :: String } deriving (Eq, Ord, Show)
xpProfileName :: PU ProfileName
xpProfileName =
xpAttr "profile" $
xpWrap (ProfileName, unProfileName) xpText
newtype Vendor = Vendor { unVendor :: String } deriving (Eq, Ord, Show)
xpVendor :: PU Vendor
xpVendor =
xpAttr "vendor" $
xpWrap (Vendor, unVendor) xpText
newtype Comment = Comment { unComment :: String } deriving (Eq, Ord, Show)
xpComment :: PU Comment
xpComment = xpWrap (Comment, unComment) xpText
xpCommentAttr :: PU Comment
xpCommentAttr = xpAttr "comment" xpComment
newtype Name = Name { unName :: String } deriving (Eq, Ord, Show)
xpName :: PU Name
xpName =
xpAttr "name" $
xpWrap (Name, unName) xpText