Last active
August 29, 2015 14:27
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[<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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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