Skip to content

Instantly share code, notes, and snippets.

@stevan
Created February 8, 2013 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevan/ce835d10395640410507 to your computer and use it in GitHub Desktop.
Save stevan/ce835d10395640410507 to your computer and use it in GitHub Desktop.
(* A polymorphic variant type to represent Perl values
in a more Ocaml-ish way, along with functions for
converting between representations *)
module Utils =
struct
exception Cannot_convert of string
type variant = [ `Null
| `String of string
| `Int of int
| `Float of float
| `Bool of bool
| `Array of variant list
| `Hash of (string * variant) list
]
(** Perl <-> Variant *)
let rec perl_of_variant = function
| `Null -> Scalar.sv_undef ()
| `String s -> Scalar.sv_of_string s
| `Int i -> Scalar.sv_of_int i
| `Float f -> Scalar.sv_of_float f
| `Bool b -> Scalar.sv_of_bool b
| `Array xs -> Ref.ref_of_av
(Array.from_list (List.map perl_of_variant xs))
| `Hash xs -> Ref.ref_of_hv
(let hv = Hash.create_empty () in
List.iter (fun (k, v) -> Hash.set hv k (perl_of_variant v)) xs;
hv)
let rec variant_of_perl x =
let is_scalar_ref s_ref =
try ignore(Ref.sv_of_ref(s_ref)); true
with Invalid_argument(_) -> false
in
let reftype s =
try ignore(Ref.av_of_ref s); Scalar.SVt_PVAV
with Invalid_argument(_) ->
try ignore(Ref.hv_of_ref s); Scalar.SVt_PVHV
with Invalid_argument(_) -> raise (Cannot_convert "Cannot convert unknown reftype")
in
let rec loop sv_type =
match sv_type with
| Scalar.SVt_NULL -> `Null
| Scalar.SVt_IV -> `Int(Scalar.int_of_sv x)
| Scalar.SVt_NV -> `Float(Scalar.float_of_sv x)
| Scalar.SVt_PV -> `String(Scalar.string_of_sv x)
| Scalar.SVt_PVAV -> `Array(Array.map variant_of_perl (Ref.av_of_ref x))
| Scalar.SVt_PVHV -> `Hash(List.map
(fun (k,v) -> (k, (variant_of_perl v)))
(Hash.to_assoc (Ref.hv_of_ref x)))
| Scalar.SVt_RV
when is_scalar_ref(x)
-> variant_of_perl (Ref.sv_of_ref x)
| Scalar.SVt_RV -> loop (reftype x)
| Scalar.SVt_PVMG -> raise (Cannot_convert "Cannot convert magic value")
| Scalar.SVt_PVGV -> raise (Cannot_convert "Cannot convert Glob (possibly a file handle)")
| Scalar.SVt_PVCV -> raise (Cannot_convert "Cannot convert Code value")
in loop (Scalar.sv_type x)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment