module Language.ASN1.Parser where
import Text.ParserCombinators.Parsec
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language
import System.Exit (exitFailure)
import Data.Generics
data Module = Module { module_id::ModuleIdentifier
, default_tag_type::TagType
, module_body::ModuleBody
} deriving (Eq,Ord,Show, Typeable, Data)
data GlobalType = GlobalT TheType | GlobalDMT DefinedMacroType deriving (Eq,Ord,Show, Typeable, Data)
data TheType = TheType { type_id::Type
, subtype::SubtypeSpec
}
deriving (Eq,Ord,Show, Typeable, Data)
newtype TypeName = TypeName TheIdentifier deriving (Eq,Ord,Show, Typeable, Data)
data NamedNumber = NamedNumber { number_name::NumberName
, named_number::NumberValue
} deriving (Eq,Ord,Show, Typeable, Data)
newtype NumberName = NumberName TheIdentifier deriving (Eq,Ord,Show, Typeable, Data)
data NumberValue = Number Integer | DefinedVal DefinedValue | UndefinedNV deriving (Eq,Ord,Show, Typeable, Data)
data ElementType = NamedElementType { element_name::TypeName
, element_body::TheType
, element_presence::ElementPresence
}
| ComponentsOf TheType deriving (Eq,Ord,Show, Typeable, Data)
data ElementPresence = Optional | Default NamedValue | UndefinedElementPresence deriving (Eq,Ord,Show, Typeable, Data)
data NamedValue = NamedValue { value_name::ValueName
, named_value::TheValue
} deriving (Eq,Ord,Show, Typeable, Data)
newtype ValueName = ValueName TheIdentifier deriving (Eq,Ord,Show, Typeable, Data)
data SizeConstraint = SizeConstraint SubtypeSpec | UndefinedSizeContraint deriving (Eq,Ord,Show, Typeable, Data)
parseASN1FromFileOrDie :: String -> IO ([Module])
parseASN1FromFileOrDie fname =
do result <- parseASN1FromFile fname
case result of
Left err -> do { putStr "parse error at: "
; print err
; exitFailure
}
Right x -> return x
parseASN1FromFile :: String -> IO (Either ParseError [Module])
parseASN1FromFile fname =
parseFromFile asn1Input fname
parseASN1 source =
parse asn1Input "" source
objectIdentifier =
do { reserved "OBJECT" ; reserved "IDENTIFIER" }
data StringConst = StringConst String deriving (Eq,Ord,Show, Typeable, Data)
stringConst allowedSet marker =
do { char '\'' ; body <- many (oneOf allowedSet) ; char '\''; char marker ; return (StringConst body) }
bstring = stringConst "01" 'B' <?> "bstring"
hstring = stringConst "0123456789ABCDEFabcdef" 'H' <?> "hstring"
cstring =
do { char '"'; s <- anyChar `manyTill` (char '"' ); return (StringConst s) } <?> "cstring"
numberERange = natural
lcaseFirstIdent = do { c <- lower
; cs <- many (alphaNum <|> char '-')
; whiteSpace
; return (c:cs)
}
ucaseFirstIdent = do { c <-upper
; cs <- many (alphaNum <|> char '-')
; whiteSpace
; return (c:cs)
}
asn1Input =
do { whiteSpace
; modules <- many1 moduleDefinition
; eof
; return modules
}
<?> "asn1Input"
moduleDefinition =
do { id <- moduleIdentifier
; reserved "DEFINITIONS"
; td <- option UndefinedTagType tagDefault
; reserved "::="
; reserved "BEGIN"
; body <- moduleBody
; reserved "END"
; return (Module id td body)
}
<?> "moduleDefinition"
data TagType = Explicit | Implicit | UndefinedTagType deriving (Eq,Ord,Show, Typeable, Data)
tagType = choice [ reserved "EXPLICIT" >> return Explicit
, reserved "IMPLICIT" >> return Implicit
]
tagDefault =
do { t <- tagType
; reserved "TAGS"
; return t
}
<?> "tagDefault"
data ModuleIdentifier = ModuleIdentifier ModuleReference [ObjIdComponent] deriving (Eq,Ord,Show, Typeable, Data)
data ModuleReference = ModuleReference String
| UndefinedModuleReference
deriving (Eq,Ord,Show, Typeable, Data)
moduleIdentifier =
do { ref <- moduleReference
; id <- option [] assignedIdentifier
; return (ModuleIdentifier ref id)
}
<?> "moduleIdentifier"
assignedIdentifier = objectIdentifierValue
<?> "assignedIdentifier"
data ModuleBody = ModuleBody { module_exports::[[ExportedSymbol]]
, module_imports::[[SymbolsFromModule]]
, module_assignments::[Assignment]
} deriving (Eq,Ord,Show, Typeable, Data)
moduleBody =
do { e <- option [] exports
; i <- option [] imports
; a <- option [] assignmentList
; return (ModuleBody e i a)
}
<?> "moduleBody"
newtype ExportedSymbol = ExportedSymbol TheSymbol deriving (Eq,Ord,Show, Typeable, Data)
exports =
do { reserved "EXPORTS"
; endBy (commaSep1 (theSymbol >>= return . ExportedSymbol)) semi
}
<?> "Exports"
imports =
do { reserved "IMPORTS"
; endBy (many1 symbolsFromModule) semi
}
<?> "Imports"
data SymbolsFromModule = SymbolsFromModule [TheSymbol] ModuleIdentifier deriving (Eq,Ord,Show, Typeable, Data)
symbolsFromModule =
do { ss <- commaSep1 theSymbol
; reserved "FROM"
; id <- moduleIdentifier
; return (SymbolsFromModule ss id)
}
<?> "SymbolsFromModule"
data TypeReference = TypeReference String deriving (Eq,Ord,Show, Typeable, Data)
data TheSymbol = TypeReferenceSymbol TypeReference
| TheIdentifierSymbol TheIdentifier
| DefinedMacroNameSymbol DefinedMacroName
deriving (Eq,Ord,Show, Typeable, Data)
theSymbol =
choice $ map try [ typereference >>= return . TypeReferenceSymbol
, theIdentifier >>= return . TheIdentifierSymbol
, definedMacroName >>= return . DefinedMacroNameSymbol
]
assignmentList =
do { sepBy1 assignment (optional semi)
}
<?> "assignmentList"
data Assignment = MacroDefinition { macro_def_type::MacroDefinitionType
, macro_body::MacroBody
}
| ValueAssignment { value_ref::TheIdentifier
, value_ref_type::GlobalType
, assigned_value_ref::TheIdentifier
, assigned_value::BuiltinValue
}
| TypeAssignment { type_ref::TypeReference
, assigned_type::GlobalType
}
deriving (Eq,Ord,Show, Typeable, Data)
assignment =
choice $ map try [ macroDefinition >>= return
, valueAssignment >>= return
, typeAssignment >>= return
]
data MacroDefinitionType = DefinedMacroNameMDT DefinedMacroName
| TypeReferenceMDT TypeReference
deriving (Eq,Ord,Show, Typeable, Data)
macroDefinition =
do { t <- choice [ definedMacroName >>= return . DefinedMacroNameMDT
, typereference >>= return . TypeReferenceMDT
]
; reserved "MACRO"
; reserved "::="
; reserved "BEGIN"
; body <- macroBody
; reserved "END"
; return (MacroDefinition t body)
}
<?> "macroDefinition"
data MacroBody = MacroBody String deriving (Eq,Ord,Show, Typeable, Data)
macroBody = anyChar `manyTill` (reserved "END") >>= return . MacroBody
data MacroReference = TypeMacroReference TypeReference
| DefinedNameMacroReference DefinedMacroName
deriving (Eq,Ord,Show, Typeable, Data)
macroReference =
do {
choice [ typereference >>= return . TypeMacroReference
, definedMacroName >>= return . DefinedNameMacroReference
]
}
<?> "MacroReference"
typeAssignment =
do { t1 <- typereference
; reserved "::="
; t2 <- globalType
; return (TypeAssignment t1 t2)
}
<?> "TypeAssignment"
globalType =
choice [ theType >>= return . GlobalT
, definedMacroType >>= return . GlobalDMT
]
<?> "GlobalType"
theType :: Parser TheType
theType =
do {
; t <- parseType
; subt <- option [] (subtypeSpec)
; return (TheType t subt)
}
<?> "Type"
definedType =
do {
; mref <- option UndefinedModuleReference (try moduleReferenceAndDot)
; typeref <- typereference
; return (Defined mref typeref)
}
<?> "DefinedType"
moduleReferenceAndDot =
do {
; mref <- moduleReference
; reserved "."
; return (mref)
}
data Type = IntegerT [NamedNumber]
| BitString [NamedNumber]
| Set [ElementType]
| Sequence [ElementType]
| SetOf SizeConstraint TheType
| SequenceOf SizeConstraint TheType
| Choice [ElementType]
| Selection TheIdentifier TheType
| Tagged Tag TagType TheType
| Any TheIdentifier
| Enumerated [NamedNumber]
| OctetString
| ObjectIdentifier
| Real
| Boolean
| Null
| External
| Defined ModuleReference TypeReference
deriving (Eq,Ord,Show, Typeable, Data)
parseType =
do {
choice $ map try [ integrType >>= return . IntegerT
, bitStringType >>= return . BitString
, setOrSequenceType
, setOrSequenceOfType
, choiceType >>= return . Choice
, selectionType
, taggedType
, anyType >>= return . Any
, enumeratedType >>= return . Enumerated
, octetString >> return OctetString
, objectIdentifier >> return ObjectIdentifier
, reserved "REAL" >> return Real
, reserved "BOOLEAN" >> return Boolean
, reserved "NULL" >> return Null
, reserved "EXTERNAL" >> return External
, definedType
]
}
<?> "BuiltinType"
octetString =
do { reserved "OCTET" ; reserved "STRING" }
enumeratedType =
do { reserved "ENUMERATED"
; braces namedNumberList
}
<?> "EnumeratedType"
integrType =
do { reserved "INTEGER"
; option [] $ braces namedNumberList
}
<?> "IntegerType"
bitStringType =
do { reserved "BIT"; reserved "STRING"
; option [] $ braces namedNumberList
}
<?> "BitStringType"
namedNumberList = commaSep1 namedNumber
<?> "NamedNumberList"
namedNumber =
do { id <- theIdentifier
; v <- parens $ choice [ signedNumber >>= return . Number
, definedValue >>= return . DefinedVal
]
; return (NamedNumber (NumberName id) v)
}
<?> "NamedNumber"
signedNumber = integer
<?> "SignedNumber"
data SetOrSeq = SetT | SequenceT deriving (Eq,Ord,Show, Typeable, Data)
setOrSeq = choice $ map try [ reserved "SET" >> return SetT
, reserved "SEQUENCE" >> return SequenceT
]
setOrSequenceType =
do { t <- setOrSeq
; e <- braces elementTypeList
; case t of
SetT -> return (Set e)
SequenceT -> return (Sequence e)
}
<?> "SetOrSequenceType"
setOrSequenceOfType =
do { t <- setOrSeq
; sc <- option UndefinedSizeContraint ( sizeConstraint <|> parens sizeConstraint )
; reserved "OF"
; innert <- theType
; case t of
SetT -> return (SetOf sc innert)
SequenceT -> return (SequenceOf sc innert)
}
<?> "SetOrSequenceOfType"
choiceType =
do { reserved "CHOICE"
; braces elementTypeList
}
<?> "ChoiceType"
elementTypeList = commaSep1 elementType
<?> "ElementTypeList"
elementType =
choice $ map try
[ componentsType >>= return . ComponentsOf
, do { id <- option UndefinedIdentifier (try theIdentifier)
; t <- theType
; presence <- option UndefinedElementPresence $ choice
[ reserved "OPTIONAL" >> return Optional
, reserved "DEFAULT" >> namedValue >>= return . Default
]
; return (NamedElementType (TypeName id) t presence)
}
]
componentsType :: Parser TheType
componentsType =
do {
; reserved "COMPONENTS"
; reserved "OF"
; t <- theType
; return t
}
<?> "ComponentsType"
selectionType =
do { id <- theIdentifier;
; symbol "<"
; t <- theType
; return (Selection id t)
}
<?> "SelectionType"
taggedType =
do { t <- tag
; tt <- option UndefinedTagType tagType
; typ <- theType
; return (Tagged t tt typ)
}
<?> "TaggedType"
data Tag = Tag TheClass ClassNumber deriving (Eq,Ord,Show, Typeable, Data)
tag = squares $ do { c <- option UndefinedClass theClass
; cn <- classNumber
; return (Tag c cn)
}
data ClassNumber = ClassNumber Integer | ClassNumberAsDefinedValue DefinedValue deriving (Eq,Ord,Show, Typeable, Data)
classNumber =
choice [ number >>= return . ClassNumber
, definedValue >>= return . ClassNumberAsDefinedValue
]
<?> "ClassNumber"
data TheClass = Universal | Application | Private | UndefinedClass deriving (Eq,Ord,Show, Typeable, Data)
theClass = choice [ reserved "UNIVERSAL" >> return Universal
, reserved "APPLICATION" >> return Application
, reserved "PRIVATE" >> return Private
]
anyType =
do { reserved "ANY"
; option UndefinedIdentifier ( do {reserved "DEFINED" ; reserved "BY" ; theIdentifier } )
}
<?> "AnyType"
type SubtypeSpec = [SubtypeValueSet]
subtypeSpec :: Parser SubtypeSpec
subtypeSpec = parens subtypeValueSetList
<?> "SubtypeSpec"
subtypeValueSetList = sepBy1 subtypeValueSet (symbol "|") <?> "SubtypeValueSetList"
data ValueRangeElement = MinValue | MaxValue | UndefinedValue | Value TheValue deriving (Eq,Ord,Show, Typeable, Data)
data SubtypeValueSet = ValueRange { range_from::ValueRangeElement
, range_to::ValueRangeElement
}
| ContainedSubType TheType
| PermittedAlphabet SubtypeSpec
| SizeConstr SizeConstraint
| SingleTypeConstraint SubtypeSpec
| MultipleTypeConstaint TypeConstraints
deriving (Eq,Ord,Show, Typeable, Data)
subtypeValueSet :: Parser SubtypeValueSet
subtypeValueSet =
do {
choice $ map try [ valueRange
, containedSubtype >>= return . ContainedSubType
, permittedAlphabet >>= return . PermittedAlphabet
, sizeConstraint >>= return . SizeConstr
, innerTypeConstraints
]
}
<?> "SubtypeValueSet"
containedSubtype =
do { reserved "INCLUDES"
; theType >>= return
}
<?> "ContainedSubtype"
singleValue =
do {
theValue
}
<?> "SingleValue"
valueRange =
do { from <- choice [ theValue >>= return . Value
, do reserved "MIN"
return MinValue
]
; to <- option UndefinedValue ( do optional (symbol "<")
dot
dot
optional (symbol "<")
choice [ theValue >>= return . Value
, do reserved "MAX"
return MaxValue
]
)
; return (ValueRange from to)
}
<?> "ValueRange"
sizeConstraint :: Parser SizeConstraint
sizeConstraint =
do {
; reserved "SIZE"
; spec <- subtypeSpec
; return (SizeConstraint spec)
}
<?> "SizeConstraint"
permittedAlphabet :: Parser SubtypeSpec
permittedAlphabet =
do { reserved "FROM"
; subtypeSpec >>= return
}
<?> "PermittedAlphabet"
innerTypeConstraints =
do { reserved "WITH"
; choice [ do { reserved "COMPONENT"
; singleTypeConstraint >>= return . SingleTypeConstraint
}
, do { reserved "COMPONENTS"
; multipleTypeConstraints >>= return . MultipleTypeConstaint
}
]
}
<?> "InnerTypeConstraints"
singleTypeConstraint = subtypeSpec <?> "SingleTypeConstraint"
multipleTypeConstraints =
do {
braces( do { optional ( reserved "...," )
; typeConstraints
}
)
}
<?> "MultipleTypeConstraints"
type TypeConstraints = [NamedConstraint]
typeConstraints = commaSep1 namedConstraint <?> "TypeConstraints"
data NamedConstraint = NamedConstraint TheIdentifier Constraint deriving (Eq,Ord,Show, Typeable, Data)
namedConstraint =
do { id <- option UndefinedIdentifier theIdentifier
; c <- constraint
; return (NamedConstraint id c)
}
<?> "NamedConstraint"
data Constraint = Constraint ValueConstraint PresenceConstraint deriving (Eq,Ord,Show, Typeable, Data)
constraint =
do { vc <- option UndefinedVC (valueConstraint)
; pc <- option UndefinedContraint (presenceConstraint)
; return (Constraint vc pc)
}
<?> "Constraint"
data ValueConstraint = DefinedVC SubtypeSpec | UndefinedVC deriving (Eq,Ord,Show, Typeable, Data)
valueConstraint = subtypeSpec >>= return . DefinedVC <?> "ValueConstraint"
data PresenceConstraint = PresentConstraint
| AbsentConstraint
| OptionalConstraint
| UndefinedContraint deriving (Eq,Ord,Show, Typeable, Data)
presenceConstraint =
choice [ do reserved "PRESENT"; return PresentConstraint
, do reserved "ABSENT"; return AbsentConstraint
, do reserved "OPTIONAL"; return OptionalConstraint
]
<?> "PresenceConstraint"
valueAssignment =
do { id <- theIdentifier
; t <- globalType
; reserved "::="
; id2 <- option UndefinedIdentifier $ do { i <- theIdentifier
; optional $ symbol ":"
; return i
}
; v <- option UndefinedBuiltinValue builtinValue
; return (ValueAssignment id t id2 v)
}
<?> "ValueAssignment"
data TheValue = BuiltinV BuiltinValue
| DefinedV DefinedValue
| UndefinedV deriving (Eq,Ord,Show, Typeable, Data)
theValue =
do {
; choice [ builtinValue >>= return . BuiltinV
, definedValue >>= return . DefinedV
]
}
<?> "Value"
data DefinedValue = DefinedValue ModuleReference TheIdentifier deriving (Eq,Ord,Show, Typeable, Data)
definedValue =
do {
; mref <- option UndefinedModuleReference ( moduleReferenceAndDot )
; id <- theIdentifier
; return (DefinedValue mref id)
}
<?> "DefinedValue"
data BuiltinValue = BooleanValue Bool
| NullValue
| PlusInfinity
| MinusInfinity
| SignedNumber Integer
| HexString StringConst
| BinaryString StringConst
| CharString StringConst
| CompoundValue [ObjIdComponent]
| UndefinedBuiltinValue deriving (Eq,Ord,Show, Typeable, Data)
builtinValue =
do {
choice $ map try [ booleanValue >>= return . BooleanValue
, nullValue >> return NullValue
, specialRealValue
, signedNumber >>= return . SignedNumber
, hexString >>= return . HexString
, binaryString >>= return . BinaryString
, charString >>= return . CharString
, compoundValue >>= return . CompoundValue
]
}
<?> "BuiltinValue"
compoundValue = braces objIdComponentList
<?> "CompoundValue"
booleanValue =
choice [ reserved "TRUE" >> return True
, reserved "FALSE" >> return False
]
specialRealValue =
choice [ reserved "PLUS-INFINITY" >> return PlusInfinity
, reserved "MINUS-INFINITY" >> return MinusInfinity
]
nullValue = reserved "NULL"
namedValue =
do {
; id <- option UndefinedIdentifier ( try theIdentifier )
; v <- theValue
; return (NamedValue (ValueName id) v)
}
<?> "NamedValue"
objectIdentifierValue =
do {
braces objIdComponentList
}
<?> "ObjectIdentifierValue"
objIdComponentList =
do {
many1 objIdComponent
}
<?> "ObjIdComponentList"
data ObjIdComponent = ObjIdNumberForm Integer | ObjIdNameAndNumberForm NamedNumber deriving (Eq,Ord,Show, Typeable, Data)
objIdComponent =
choice [ numberForm >>= return . ObjIdNumberForm
, nameAndNumberForm >>= return . ObjIdNameAndNumberForm
]
<?> "ObjIdComponent"
numberForm = number <?> "NumberForm"
nameAndNumberForm =
do { id <- theIdentifier
; v <- option UndefinedNV $ braces $ choice [ numberForm >>= return . Number
, definedValue >>= return . DefinedVal
]
; return (NamedNumber (NumberName id) v)
}
<?> "NameAndNumberForm"
binaryString = bstring <?> "BinaryString"
hexString = hstring <?> "HexString"
charString = cstring <?> "CharString"
number = natural <?> "number"
data TheIdentifier = TheIdentifier String
| UndefinedIdentifier
deriving (Eq,Ord,Show, Typeable, Data)
theIdentifier = lcaseFirstIdent >>= return . TheIdentifier <?> "identifier"
moduleReference = ucaseFirstIdent >>= return . ModuleReference <?> "modulereference"
typereference = ucaseFirstIdent >>= return . TypeReference <?> "typereference"
data DefinedMacroType = TextualConventionDMT TextualConventionMacroType | SnmpObjectDMT SnmpObjectTypeMacroType deriving (Eq,Ord,Show, Typeable, Data)
definedMacroType =
do {
choice [ textualConventionMacroType >>= return . TextualConventionDMT
, snmpObjectTypeMacroType >>= return . SnmpObjectDMT
]
}
<?> "DefinedMacroType"
data DefinedMacroName = ObjectType | TextualConvention deriving (Eq,Ord,Show, Typeable, Data)
definedMacroName =
do {
choice [ reserved "OBJECT-TYPE" >> return ObjectType
, reserved "TEXTUAL-CONVENTION" >> return TextualConvention
]
}
<?> "DefinedMacroName"
data SnmpObjectTypeMacroType = SnmpObjectTypeMacroType TheType SnmpAccess SnmpStatus SnmpDescr SnmpRefer SnmpIndex TheValue
deriving (Eq,Ord,Show, Typeable, Data)
snmpObjectTypeMacroType =
do { reserved "OBJECT-TYPE"
; reserved "SYNTAX"
; t <- theType
; reserved "ACCESS"
; sa <- snmpAccess
; reserved "STATUS"
; ss <- snmpStatus
; sd <- option UndefinedSnmpDescr (snmpDescrPart)
; sr <- option UndefinedSnmpRefer (snmpReferPart)
; si <- option UndefinedSnmpIndex (snmpIndexPart)
; sdvp <- option UndefinedV (snmpDefValPart)
; return (SnmpObjectTypeMacroType t sa ss sd sr si sdvp)
}
<?> "SnmpObjectTypeMacroType"
data SnmpAccess = SnmpAccess TheIdentifier deriving (Eq,Ord,Show, Typeable, Data)
snmpAccess = theIdentifier >>= return . SnmpAccess
<?> "SnmpAccess"
data SnmpStatus = SnmpStatus TheIdentifier deriving (Eq,Ord,Show, Typeable, Data)
snmpStatus = theIdentifier >>= return . SnmpStatus
<?> "SnmpStatus"
data SnmpDescr = SnmpDescr StringConst
| UndefinedSnmpDescr
deriving (Eq,Ord,Show, Typeable, Data)
snmpDescrPart =
do { reserved "DESCRIPTION"
; charString >>= return . SnmpDescr
}
<?> "SnmpDescrPart"
data SnmpRefer = SnmpRefer StringConst
| UndefinedSnmpRefer
deriving (Eq,Ord,Show, Typeable, Data)
snmpReferPart =
do { reserved "REFERENCE"
; charString >>= return . SnmpRefer
}
<?> "SnmpReferPart"
data SnmpIndex = SnmpIndex [TypeOrValue]
| UndefinedSnmpIndex
deriving (Eq,Ord,Show, Typeable, Data)
snmpIndexPart =
do { reserved "INDEX"
; braces typeOrValueList >>= return . SnmpIndex
}
<?> "SnmpIndexPart"
typeOrValueList =
do {
typeOrValue
; many ( do {reserved "," ; typeOrValue} )
}
<?> "TypeOrValueList"
data TypeOrValue = T TheType | V TheValue deriving (Eq,Ord,Show, Typeable, Data)
typeOrValue =
do {
choice $ map try [ theType >>= return . T
, theValue >>= return . V
]
}
<?> "TypeOrValue"
snmpDefValPart =
do { reserved "DEFVAL"
; braces theValue
}
<?> "SnmpDefValPart"
data TextualConventionMacroType = TextualConventionMacroType DisplayHint SnmpStatus SnmpDescr SnmpRefer TheType
deriving (Eq,Ord,Show, Typeable, Data)
data DisplayHint = DisplayHint StringConst
| UndefinedDisplayHint
deriving (Eq,Ord,Show, Typeable, Data)
textualConventionMacroType =
do { reserved "TEXTUAL-CONVENTION"
; dh <- option UndefinedDisplayHint (displayHint)
; reserved "STATUS"
; ss <- snmpStatus
; sd <- option UndefinedSnmpDescr (snmpDescrPart)
; sr <- option UndefinedSnmpRefer (snmpReferPart)
; reserved "SYNTAX"
; t <- theType
; return (TextualConventionMacroType dh ss sd sr t)
}
<?> "TextualConventionMacroType"
displayHint =
do { reserved "DISPLAY-HINT"
; charString >>= return . DisplayHint
}
<?> "DisplayHint"
asn1Style
= emptyDef
{ commentLine = "--"
, nestedComments = False
, identStart = alphaNum
, identLetter = alphaNum <|> oneOf "_-#"
, caseSensitive = True
}
asn1 = P.makeTokenParser asn1Style
whiteSpace = P.whiteSpace asn1
symbol = P.symbol asn1
identifier = P.identifier asn1
reserved = P.reserved asn1
decimal = P.decimal asn1
charLiteral = P.charLiteral asn1
stringLiteral = P.stringLiteral asn1
comma = P.comma asn1
colon = P.colon asn1
commaSep1 = P.commaSep1 asn1
semiSep1 = P.semiSep1 asn1
braces = P.braces asn1
squares = P.squares asn1
parens = P.parens asn1
semi = P.semi asn1
natural = P.natural asn1
integer = P.integer asn1
dot = P.dot asn1