Skip to content

Instantly share code, notes, and snippets.

@lasandell
Last active August 29, 2015 14:27
Show Gist options
  • Save lasandell/051b6177bcaf11c9b0a3 to your computer and use it in GitHub Desktop.
Save lasandell/051b6177bcaf11c9b0a3 to your computer and use it in GitHub Desktop.
Parsing DBus type signatures. Comparing FParsec solution to an earlier solution using active patterns and regular pattern matching. More info on what I'm parsing: http://dbus.freedesktop.org/doc/dbus-specification.html#type-system
[<RequireQualifiedAccess>]
type DBusType =
| Byte
| Boolean
| Int16
| UInt16
| Int32
| UInt32
| Int64
| UInt64
| Double
| String
| Signature
| ObjectPath
| Array of DBusType
| Struct of DBusType list
| Variant
| Dictionary of DBusType * DBusType
| UnixFD
let parseSignature signature =
let rec (|BasicType|_|) = function
| code::rest ->
match code with
| 'b' -> Some DBusType.Boolean
| 'y' -> Some DBusType.Byte
| 'n' -> Some DBusType.Int16
| 'q' -> Some DBusType.UInt16
| 'i' -> Some DBusType.Int32
| 'u' -> Some DBusType.UInt32
| 'x' -> Some DBusType.Int64
| 't' -> Some DBusType.UInt64
| 'd' -> Some DBusType.Double
| 's' -> Some DBusType.String
| 'g' -> Some DBusType.Signature
| 'o' -> Some DBusType.ObjectPath
| 'v' -> Some DBusType.Variant
| 'h' -> Some DBusType.UnixFD
| _ -> None
|> Option.map(fun ty -> ty, rest)
| _ ->
None
and (|ArrayType|_|) = function
| 'a'::AnyType(ty, rest) ->
Some(DBusType.Array ty, rest)
| _ ->
None
and (|DictionaryType|_|) = function
| 'a'::'{'::BasicType(keyType, AnyType(valueType, '}'::rest)) ->
Some(DBusType.Dictionary(keyType, valueType), rest)
| _ ->
None
and (|StructType|_|) = function
| '('::AnyTypes(tys, (')'::rest)) when tys <> [] ->
Some(DBusType.Struct tys, rest)
| _ ->
None
and (|AnyType|_|) = function
| BasicType x
| ArrayType x
| DictionaryType x
| StructType x ->
Some x
| _ ->
None
and (|AnyTypes|) = function
| AnyType (ty, AnyTypes(tys, rest)) ->
((ty::tys), rest)
| rest ->
[], rest
match List.ofSeq signature with
| AnyType (ty, []) -> ty
| _ -> failwithf "Invalid type signature '%s'." signature
open FParsec
[<RequireQualifiedAccess>]
type DBusType =
| Byte
| Boolean
| Int16
| UInt16
| Int32
| UInt32
| Int64
| UInt64
| Double
| String
| Signature
| ObjectPath
| Array of DBusType
| Struct of DBusType list
| Variant
| Dictionary of DBusType * DBusType
| UnixFD
let signatureParser =
// Needed due to F# not liking mutually recursive values
let anyType, anyTypeImpl =
createParserForwardedToRef()
let basicType =
[ 'b', DBusType.Boolean
'y', DBusType.Byte
'n', DBusType.Int16
'q', DBusType.UInt16
'i', DBusType.Int32
'u', DBusType.UInt32
'x', DBusType.Int64
't', DBusType.UInt64
'd', DBusType.Double
's', DBusType.String
'g', DBusType.Signature
'o', DBusType.ObjectPath
'v', DBusType.Variant
'h', DBusType.UnixFD ]
|> List.map ((<||) charReturn)
|> choice
let structType =
pchar '('
>>. many1 anyType
.>> pchar ')'
|>> DBusType.Struct
let dictType =
pstring "a{"
>>. tuple2 basicType anyType
.>> pchar '}'
|>> DBusType.Dictionary
let arrayType =
pstring "a"
>>. anyType
|>> DBusType.Array
anyTypeImpl :=
[ basicType
structType
dictType
arrayType ]
|> choice
anyType .>> eof
let parseSignature signature =
match run signatureParser signature with
| Success (result, _, _) -> result
| Failure (error, _, _) -> failwith error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment