Change syntax so that { ... } surrounds match patterns.
authorRichard W.M. Jones <rich@annexia.org>
Fri, 25 Apr 2008 11:08:43 +0000 (11:08 +0000)
committerRichard W.M. Jones <rich@annexia.org>
Fri, 25 Apr 2008 11:08:43 +0000 (11:08 +0000)
13 files changed:
TODO
bitmatch.mli
configure.ac
pa_bitmatch.ml
tests/05_bits.ml
tests/06_ints1.ml
tests/06_ints2.ml
tests/06_ints3.ml
tests/10_constr1.ml
tests/10_constr2.ml
tests/20_varsize.ml
tests/60_ping.ml
tests/70_ext3_sb.ml

diff --git a/TODO b/TODO
index 11e2d02..a895ee3 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,11 +1,11 @@
-$Id: TODO,v 1.1 2008-04-15 13:41:14 rjones Exp $
+$Id: TODO,v 1.2 2008-04-25 11:08:43 rjones Exp $
 Major to-do items.
 
 (1) In bitmatch operator, use patterns not expressions.
 
 (2) Allow matching against strings.
 
-(3) Change the syntax so { ... } surrounds match patterns.
+(3) DONE - Change the syntax so { ... } surrounds match patterns.
 
 (4) Provide UInt32 and UInt64 types.
 
@@ -20,3 +20,11 @@ Major to-do items.
     { start : 16;
       another : 16 : align(32);     (* implicit 16 bit gap before this *)
     }
+
+(7) Assertions:
+
+    { start : 16 : assert (offset = 0); }
+
+   (Q: Are these evaluated at compile time or at run time or selectable?)
+
+(8) Named but unbound patterns to avoid "Warning Y: unused variable".
index b700f2b..b901ac0 100644 (file)
@@ -15,7 +15,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  *
- * $Id: bitmatch.mli,v 1.13 2008-04-15 13:40:51 rjones Exp $
+ * $Id: bitmatch.mli,v 1.14 2008-04-25 11:08:43 rjones Exp $
  *)
 
 (**
@@ -55,13 +55,13 @@ let display pkt =
    |                    Options                    |    Padding    |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   *)
-  | 4 : 4; hdrlen : 4; tos : 8;   length : 16;
-    identification : 16;          flags : 3; fragoffset : 13;
-    ttl : 8; protocol : 8;        checksum : 16;
-    source : 32;
-    dest : 32;
-    options : (hdrlen-5)*32 : bitstring;
-    payload : -1 : bitstring ->
+  | 4 : 4; hdrlen : 4; tos : 8;   length : 16;
+      identification : 16;          flags : 3; fragoffset : 13;
+      ttl : 8; protocol : 8;        checksum : 16;
+      source : 32;
+      dest : 32;
+      options : (hdrlen-5)*32 : bitstring;
+      payload : -1 : bitstring } ->
 
     printf "IPv4:\n";
     printf "  header length: %d * 32 bit words\n" hdrlen;
@@ -79,11 +79,11 @@ let display pkt =
     printf "  packet payload:\n";
     Bitmatch.hexdump_bitstring stdout payload
 
-  | version : 4 ->
+  | { version : 4 } ->
     eprintf "unknown IP version %d\n" version;
     exit 1
 
-  | _ as pkt ->
+  | { _ } as pkt ->
     eprintf "data is smaller than one nibble:\n";
     Bitmatch.hexdump_bitstring stderr pkt;
     exit 1
@@ -97,22 +97,22 @@ let bits = Bitmatch.bitstring_of_file "tests/ext3_sb"
 
 let () =
   bitmatch bits with
-  | s_inodes_count : 32 : littleendian;       (* Inodes count *)
-    s_blocks_count : 32 : littleendian;       (* Blocks count *)
-    s_r_blocks_count : 32 : littleendian;     (* Reserved blocks count *)
-    s_free_blocks_count : 32 : littleendian;  (* Free blocks count *)
-    s_free_inodes_count : 32 : littleendian;  (* Free inodes count *)
-    s_first_data_block : 32 : littleendian;   (* First Data Block *)
-    s_log_block_size : 32 : littleendian;     (* Block size *)
-    s_log_frag_size : 32 : littleendian;      (* Fragment size *)
-    s_blocks_per_group : 32 : littleendian;   (* # Blocks per group *)
-    s_frags_per_group : 32 : littleendian;    (* # Fragments per group *)
-    s_inodes_per_group : 32 : littleendian;   (* # Inodes per group *)
-    s_mtime : 32 : littleendian;              (* Mount time *)
-    s_wtime : 32 : littleendian;              (* Write time *)
-    s_mnt_count : 16 : littleendian;          (* Mount count *)
-    s_max_mnt_count : 16 : littleendian;      (* Maximal mount count *)
-    0xef53 : 16 : littleendian ->             (* Magic signature *)
+  | s_inodes_count : 32 : littleendian;       (* Inodes count *)
+      s_blocks_count : 32 : littleendian;       (* Blocks count *)
+      s_r_blocks_count : 32 : littleendian;     (* Reserved blocks count *)
+      s_free_blocks_count : 32 : littleendian;  (* Free blocks count *)
+      s_free_inodes_count : 32 : littleendian;  (* Free inodes count *)
+      s_first_data_block : 32 : littleendian;   (* First Data Block *)
+      s_log_block_size : 32 : littleendian;     (* Block size *)
+      s_log_frag_size : 32 : littleendian;      (* Fragment size *)
+      s_blocks_per_group : 32 : littleendian;   (* # Blocks per group *)
+      s_frags_per_group : 32 : littleendian;    (* # Fragments per group *)
+      s_inodes_per_group : 32 : littleendian;   (* # Inodes per group *)
+      s_mtime : 32 : littleendian;              (* Mount time *)
+      s_wtime : 32 : littleendian;              (* Write time *)
+      s_mnt_count : 16 : littleendian;          (* Mount count *)
+      s_max_mnt_count : 16 : littleendian;      (* Maximal mount count *)
+      0xef53 : 16 : littleendian } ->           (* Magic signature *)
 
     printf "ext3 superblock:\n";
     printf "  s_inodes_count = %ld\n" s_inodes_count;
@@ -120,7 +120,7 @@ let () =
     printf "  s_free_inodes_count = %ld\n" s_free_inodes_count;
     printf "  s_free_blocks_count = %ld\n" s_free_blocks_count
 
-  | _ ->
+  | { _ } ->
     eprintf "not an ext3 superblock!\n%!";
     exit 2
 ]}
@@ -139,10 +139,11 @@ let () =
 *)
 
 let make_message typ subtype param =
-  (BITSTRING
+  (BITSTRING {
      typ : 16;
      subtype : 16;
-     param : 32) ;;
+     param : 32
+   }) ;;
 ]}
 
    {2 Loading, creating bitstrings}
@@ -172,11 +173,11 @@ let make_message typ subtype param =
 
    The general form of [bitmatch] is:
 
-   [bitmatch] {i bitstring-expression} [with]
+   [bitmatch {] {i bitstring-expression} [} with]
 
-   [|] {i pattern} [->] {i code}
+   [| {] {i pattern} [} ->] {i code}
 
-   [|] {i pattern} [->] {i code}
+   [| {] {i pattern} [} ->] {i code}
 
    [|] ...
 
@@ -193,25 +194,25 @@ let make_message typ subtype param =
 {[
 bitmatch bits with
 
-| version : 8; name : 8; param : 8 -> ...
+| { version : 8; name : 8; param : 8 } -> ...
 
    (* Bitstring of at least 3 bytes.  First byte is the version
       number, second byte is a field called name, third byte is
       a field called parameter. *)
 
-| flag : 1 ->
+| { flag : 1 } ->
    printf "flag is %b\n" flag
 
    (* A single flag bit (mapped into an OCaml boolean). *)
 
-| len : 4; data : 1+len ->
+| { len : 4; data : 1+len } ->
    printf "len = %d, data = 0x%Lx\n" len data
 
    (* A 4-bit length, followed by 1-16 bits of data, where the
       length of the data is computed from len. *)
 
-| ipv6_source : 128 : bitstring;
-  ipv6_dest : 128 : bitstring -> ...
+| ipv6_source : 128 : bitstring;
+    ipv6_dest : 128 : bitstring } -> ...
 
    (* IPv6 source and destination addresses.  Each is 128 bits
       and is mapped into a bitstring type which will be a substring
@@ -221,7 +222,7 @@ bitmatch bits with
    You can also add conditional when-clauses:
 
 {[
-| version : 4
+| { version : 4 }
     when version = 4 || version = 6 -> ...
 
    (* Only match and run the code when version is 4 or 6.  If
@@ -237,8 +238,8 @@ bitmatch bits with
    length is zero in the when-clause:
 
 {[
-| n : 4;
-  rest : -1 : bitstring
+| n : 4;
+    rest : -1 : bitstring }
     when Bitmatch.bitstring_length rest = 0 -> ...
 
    (* Only matches exactly 4 bits. *)
@@ -248,7 +249,7 @@ bitmatch bits with
    but you can also match a constant, as in:
 
 {[
-| 6 : 4 -> ...
+| { 6 : 4 } -> ...
 
    (* Only matches if the first 4 bits contain the integer 6. *)
 ]}
@@ -302,11 +303,11 @@ bitmatch bits with
    bitstring and/or have a default match case:
 
 {[
-| _ -> ...
+| { _ } -> ...
 
    (* Default match case. *)
 
-| _ as pkt -> ...
+| { _ } as pkt -> ...
 
    (* Default match case, with 'pkt' bound to the whole bitstring. *)
 ]}
@@ -321,9 +322,10 @@ bitmatch bits with
 let version = 1 ;;
 let data = 10 ;;
 let bits =
-  BITSTRING
+  BITSTRING {
     version : 4;
-    data : 12 ;;
+    data : 12
+  } ;;
 
    (* Constructs a 16-bit bitstring with the first four bits containing
       the integer 1, and the following 12 bits containing the integer 10,
@@ -437,8 +439,8 @@ Bitmatch.hexdump_bitstring stdout bits ;;
 
 {[
 bitmatch bits with
-| len : 64;
-  buffer : Int64.to_int len : bitstring ->
+| len : 64;
+    buffer : Int64.to_int len : bitstring } ->
 ]}
 
    The [len] field can be set arbitrarily large by an attacker, but
@@ -460,8 +462,9 @@ bitmatch bits with
 {[
 let len = read_untrusted_source () in
 let buffer = allocate_bitstring () in
-BITSTRING
+BITSTRING {
   buffer : len : bitstring
+}
 ]}
 
    This code merely causes a check that buffer's length is the same as
index 3f6a9e4..2ba7e97 100644 (file)
@@ -17,7 +17,7 @@
 
 dnl Process this file with autoconf to produce a configure script.
 
-AC_INIT(ocaml-bitmatch,0.4)
+AC_INIT(ocaml-bitmatch,0.5)
 
 dnl Check for basic C environment.
 AC_PROG_CC
index b5e9758..d10ff6f 100644 (file)
@@ -15,7 +15,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  *
- * $Id: pa_bitmatch.ml,v 1.7 2008-04-25 10:44:00 rjones Exp $
+ * $Id: pa_bitmatch.ml,v 1.8 2008-04-25 11:08:43 rjones Exp $
  *)
 
 open Printf
@@ -688,13 +688,15 @@ EXTEND Gram
   ];
 
   match_case: [
-    [ "_";
+    [ "{"; "_"; "}";
       bind = OPT [ "as"; name = LIDENT -> name ];
       w = OPT [ "when"; e = expr -> e ]; "->";
       code = expr ->
        (Bind bind, w, code)
     ]
-  | [ fields = LIST0 field SEP ";";
+  | [ "{";
+      fields = LIST0 field SEP ";";
+      "}";
       w = OPT [ "when"; e = expr -> e ]; "->";
       code = expr ->
        (Fields fields, w, code)
@@ -703,14 +705,16 @@ EXTEND Gram
 
   (* 'bitmatch' expressions. *)
   expr: LEVEL ";" [
-    [ "bitmatch"; bs = expr; "with"; OPT "|";
+    [ "bitmatch";
+      bs = expr; "with"; OPT "|";
       cases = LIST1 match_case SEP "|" ->
        output_bitmatch _loc bs cases
     ]
 
   (* Constructor. *)
-  | [ "BITSTRING";
-      fields = LIST0 field SEP ";" ->
+  | [ "BITSTRING"; "{";
+      fields = LIST0 field SEP ";";
+      "}" ->
        output_constructor _loc fields
     ]
   ];
index 7f78b46..829643c 100644 (file)
@@ -1,15 +1,15 @@
 (* Extract bits.
- * $Id: 05_bits.ml,v 1.2 2008-04-01 08:56:43 rjones Exp $
+ * $Id: 05_bits.ml,v 1.3 2008-04-25 11:08:43 rjones Exp $
  *)
 
 let bits = Bitmatch.make_bitstring 24 '\x5a' (* makes the string 0x5a5a5a *)
 
 let () =
   bitmatch bits with
-  | b0  : 1; b1  : 1; b2  : 1; b3  : 1; b4  : 1; b5  : 1; b6  : 1; b7  : 1;
-    b8  : 1; b9  : 1; b10 : 1; b11 : 1; b12 : 1; b13 : 1; b14 : 1; b15 : 1;
-    b16 : 1; b17 : 1; b18 : 1; b19 : 1; b20 : 1; b21 : 1; b22 : 1; b23 : 1;
-    rest : -1 : bitstring ->
+  | b0  : 1; b1  : 1; b2  : 1; b3  : 1; b4  : 1; b5  : 1; b6  : 1; b7  : 1;
+      b8  : 1; b9  : 1; b10 : 1; b11 : 1; b12 : 1; b13 : 1; b14 : 1; b15 : 1;
+      b16 : 1; b17 : 1; b18 : 1; b19 : 1; b20 : 1; b21 : 1; b22 : 1; b23 : 1;
+      rest : -1 : bitstring } ->
       assert (not b0 && b1 && not b2 && b3 && (* 0x5 *)
                b4 && not b5 && b6 && not b7); (* 0xA *)
       assert (not b8 && b9 && not b10 && b11 && (* 0x5 *)
@@ -19,5 +19,5 @@ let () =
       let _, off, len = rest in
       assert (off = 24 && len = 0) (* no further data *)
 
-  | _ ->
+  | { _ } ->
       failwith "error: did not match\n"
index 5a49bff..962f83e 100644 (file)
@@ -1,13 +1,13 @@
 (* Extract some simple integers.
- * $Id: 06_ints1.ml,v 1.1 2008-04-01 08:56:43 rjones Exp $
+ * $Id: 06_ints1.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
 let bits = Bitmatch.make_bitstring 16 '\xcf' (* makes the string 0xcfcf *)
 
 let () =
   bitmatch bits with
-  | n0 : 4; n1 : 4; n2 : 4; n3 : 4;
-    rest : -1 : bitstring ->
+  | n0 : 4; n1 : 4; n2 : 4; n3 : 4;
+      rest : -1 : bitstring } ->
       assert (n0 = 0xc);
       assert (n1 = 0xf);
       assert (n2 = 0xc);
@@ -16,5 +16,5 @@ let () =
       let _, off, len = rest in
       assert (off = 16 && len = 0) (* no further data *)
 
-  | _ ->
+  | { _ } ->
       failwith "error: did not match\n"
index c0bd76e..3587b4a 100644 (file)
@@ -1,13 +1,13 @@
 (* Extract some simple integers.
- * $Id: 06_ints2.ml,v 1.1 2008-04-01 08:56:43 rjones Exp $
+ * $Id: 06_ints2.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
 let bits = Bitmatch.make_bitstring 16 '\xcf' (* makes the string 0xcfcf *)
 
 let () =
   bitmatch bits with
-  | n0 : 2; n1 : 2; n2 : 2; n3 : 2; n4 : 2; n5 : 2; n6 : 2; n7 : 2;
-    rest : -1 : bitstring ->
+  | n0 : 2; n1 : 2; n2 : 2; n3 : 2; n4 : 2; n5 : 2; n6 : 2; n7 : 2;
+      rest : -1 : bitstring } ->
       assert (n0 = 0x3); (* 0xc *)
       assert (n1 = 0x0);
       assert (n2 = 0x3); (* 0xf *)
@@ -20,5 +20,5 @@ let () =
       let _, off, len = rest in
       assert (off = 16 && len = 0) (* no further data *)
 
-  | _ ->
+  | { _ } ->
       failwith "error: did not match\n"
index dc5b687..850dd04 100644 (file)
@@ -1,13 +1,13 @@
 (* Extract some simple integers.
- * $Id: 06_ints3.ml,v 1.1 2008-04-01 08:56:43 rjones Exp $
+ * $Id: 06_ints3.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
 let bits = Bitmatch.make_bitstring 16 '\xcf' (* makes the string 0xcfcf *)
 
 let () =
   bitmatch bits with
-  | n0 : 3; n1 : 3; n2 : 3; n3 : 3; n4 : 3; n5 : 1;
-    rest : -1 : bitstring ->
+  | n0 : 3; n1 : 3; n2 : 3; n3 : 3; n4 : 3; n5 : 1;
+      rest : -1 : bitstring } ->
       assert (n0 = 0b110);
       assert (n1 = 0b011);
       assert (n2 = 0b111);
@@ -18,5 +18,5 @@ let () =
       let _, off, len = rest in
       assert (off = 16 && len = 0) (* no further data *)
 
-  | _ ->
+  | { _ } ->
       failwith "error: did not match\n"
index ba7ccc8..0a14928 100644 (file)
@@ -1,15 +1,15 @@
 (* Test a simple constructor.
- * $Id: 10_constr1.ml,v 1.1 2008-04-01 17:05:37 rjones Exp $
+ * $Id: 10_constr1.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
-let bits = BITSTRING 0xc : 4; 0xf : 4; 0xc : 4; 0xf : 4 ;;
+let bits = BITSTRING { 0xc : 4; 0xf : 4; 0xc : 4; 0xf : 4 } ;;
 
 assert (bits = Bitmatch.make_bitstring 16 '\xcf') ;;
 
 let () =
   bitmatch bits with
-  | n0 : 4; n1 : 4; n2 : 4; n3 : 4;
-    rest : -1 : bitstring ->
+  | n0 : 4; n1 : 4; n2 : 4; n3 : 4;
+      rest : -1 : bitstring } ->
       assert (n0 = 0xc);
       assert (n1 = 0xf);
       assert (n2 = 0xc);
@@ -18,5 +18,5 @@ let () =
       let _, off, len = rest in
       assert (off = 16 && len = 0) (* no further data *)
 
-  | _ ->
+  | { _ } ->
       failwith "error: did not match\n"
index 31af87f..92b1470 100644 (file)
@@ -1,12 +1,12 @@
 (* Test a simple constructor.
- * $Id: 10_constr2.ml,v 1.1 2008-04-02 11:06:07 rjones Exp $
+ * $Id: 10_constr2.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
 let version = 1 ;;
 let data = 10 ;;
 let bits =
   BITSTRING
-    version : 4;
-    data : 12 ;;
+    version : 4;
+      data : 12 } ;;
 
 Bitmatch.hexdump_bitstring stdout bits ;;
index 5222766..b90763c 100644 (file)
@@ -1,5 +1,5 @@
 (* Construct and match against random variable sized strings.
- * $Id: 20_varsize.ml,v 1.1 2008-04-01 17:05:37 rjones Exp $
+ * $Id: 20_varsize.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
 open Printf
@@ -56,11 +56,12 @@ let () =
     (* Construct the bitstring. *)
     let bits =
       try
-       (BITSTRING
-         n0 : n0sz;
-          n1 : n1sz;
-         n2 : n2sz;
-         n3 : n3sz)
+       (BITSTRING {
+          n0 : n0sz;
+           n1 : n1sz;
+          n2 : n2sz;
+          n3 : n3sz
+        })
       with
        Bitmatch.Construct_failure (msg, _, _, _) ->
          eprintf "FAILED: Construct_failure %s\n%!" msg;
@@ -70,7 +71,7 @@ let () =
 
     let r0, r1, r2, r3 =
       bitmatch bits with
-      | r0 : n0sz; r1 : n1sz; r2 : n2sz; r3 : n3sz; rest : -1 : bitstring ->
+      | { r0 : n0sz; r1 : n1sz; r2 : n2sz; r3 : n3sz; rest : -1 : bitstring } ->
          let rest_len = Bitmatch.bitstring_length rest in
           if rest_len <> 0 then (
            eprintf "FAILED: rest is not zero length (length = %d)\n%!"
@@ -79,7 +80,7 @@ let () =
            exit 2
          );
           r0, r1, r2, r3
-      | _ ->
+      | { _ } ->
          eprintf "FAILED: bitmatch operator did not match\n%!";
          dump n0 n0sz n1 n1sz n2 n2sz n3 n3sz bits 0L 0L 0L 0L;
          exit 2 in
index 1954de1..7a274cb 100644 (file)
@@ -1,5 +1,5 @@
 (* Read in IPv4 and IPv6 ping packets and display them.
- * $Id: 60_ping.ml,v 1.2 2008-04-01 15:22:46 rjones Exp $
+ * $Id: 60_ping.ml,v 1.3 2008-04-25 11:08:43 rjones Exp $
  *)
 
 open Printf
@@ -7,13 +7,13 @@ open Printf
 let display pkt =
   bitmatch pkt with
   (* IPv4 packet header *)
-  | 4 : 4; hdrlen : 4; tos : 8; length : 16;
-    identification : 16; flags : 3; fragoffset : 13;
-    ttl : 8; protocol : 8; checksum : 16;
-    source : 32;
-    dest : 32;
-    options : (hdrlen-5)*32 : bitstring;
-    payload : -1 : bitstring ->
+  | 4 : 4; hdrlen : 4; tos : 8; length : 16;
+      identification : 16; flags : 3; fragoffset : 13;
+      ttl : 8; protocol : 8; checksum : 16;
+      source : 32;
+      dest : 32;
+      options : (hdrlen-5)*32 : bitstring;
+      payload : -1 : bitstring } ->
 
     printf "IPv4:\n";
     printf "  header length: %d * 32 bit words\n" hdrlen;
@@ -32,11 +32,11 @@ let display pkt =
     Bitmatch.hexdump_bitstring stdout payload
 
   (* IPv6 packet header *)
-  | 6 : 4; tclass : 8; flow : 20;
-    length : 16; nexthdr : 8; ttl : 8;
-    source : 128 : bitstring;
-    dest : 128 : bitstring;
-    payload : -1 : bitstring ->
+  | 6 : 4; tclass : 8; flow : 20;
+      length : 16; nexthdr : 8; ttl : 8;
+      source : 128 : bitstring;
+      dest : 128 : bitstring;
+      payload : -1 : bitstring } ->
 
     printf "IPv6:\n";
     printf "  traffic class: %d\n" tclass;
@@ -51,11 +51,11 @@ let display pkt =
     printf "packet payload:\n";
     Bitmatch.hexdump_bitstring stdout payload
 
-  | version : 4 ->
+  | { version : 4 } ->
     eprintf "unknown IP version %d\n" version;
     exit 1
 
-  | _ as pkt ->
+  | { _ } as pkt ->
     eprintf "data is smaller than one nibble:\n";
     Bitmatch.hexdump_bitstring stderr pkt;
     exit 1
index e8cebb4..af5169a 100644 (file)
@@ -1,5 +1,5 @@
 (* Parse an ext3 superblock.
- * $Id: 70_ext3_sb.ml,v 1.1 2008-04-01 19:10:45 rjones Exp $
+ * $Id: 70_ext3_sb.ml,v 1.2 2008-04-25 11:08:43 rjones Exp $
  *)
 
 open Printf
@@ -12,58 +12,58 @@ let bits = Bitmatch.bitstring_of_file "tests/ext3_sb"
 
 let () =
   bitmatch bits with
-  | s_inodes_count : 32 : littleendian;                (* Inodes count *)
-    s_blocks_count : 32 : littleendian;                (* Blocks count *)
-    s_r_blocks_count : 32 : littleendian;      (* Reserved blocks count *)
-    s_free_blocks_count : 32 : littleendian;   (* Free blocks count *)
-    s_free_inodes_count : 32 : littleendian;   (* Free inodes count *)
-    s_first_data_block : 32 : littleendian;    (* First Data Block *)
-    s_log_block_size : 32 : littleendian;      (* Block size *)
-    s_log_frag_size : 32 : littleendian;       (* Fragment size *)
-    s_blocks_per_group : 32 : littleendian;    (* # Blocks per group *)
-    s_frags_per_group : 32 : littleendian;     (* # Fragments per group *)
-    s_inodes_per_group : 32 : littleendian;    (* # Inodes per group *)
-    s_mtime : 32 : littleendian;               (* Mount time *)
-    s_wtime : 32 : littleendian;               (* Write time *)
-    s_mnt_count : 16 : littleendian;           (* Mount count *)
-    s_max_mnt_count : 16 : littleendian;       (* Maximal mount count *)
-    0xef53 : 16 : littleendian;                        (* Magic signature *)
-    s_state : 16 : littleendian;               (* File system state *)
-    s_errors : 16 : littleendian;              (* Behaviour when detecting errors *)
-    s_minor_rev_level : 16 : littleendian;     (* minor revision level *)
-    s_lastcheck : 32 : littleendian;           (* time of last check *)
-    s_checkinterval : 32 : littleendian;       (* max. time between checks *)
-    s_creator_os : 32 : littleendian;          (* OS *)
-    s_rev_level : 32 : littleendian;           (* Revision level *)
-    s_def_resuid : 16 : littleendian;          (* Default uid for reserved blocks *)
-    s_def_resgid : 16 : littleendian;          (* Default gid for reserved blocks *)
-    s_first_ino : 32 : littleendian;           (* First non-reserved inode *)
-    s_inode_size : 16 : littleendian;          (* size of inode structure *)
-    s_block_group_nr : 16 : littleendian;      (* block group # of this superblock *)
-    s_feature_compat : 32 : littleendian;      (* compatible feature set *)
-    s_feature_incompat : 32 : littleendian;    (* incompatible feature set *)
-    s_feature_ro_compat : 32 : littleendian;   (* readonly-compatible feature set *)
-    s_uuid : 128 : bitstring;                  (* 128-bit uuid for volume *)
-    s_volume_name : 128 : bitstring;           (* volume name XXX string *)
-    s_last_mounted : 512 : bitstring;          (* directory where last mounted XXX string *)
-    s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *)
-    s_prealloc_blocks : 8;                     (* Nr of blocks to try to preallocate*)
-    s_prealloc_dir_blocks : 8;                 (* Nr to preallocate for dirs *)
-    s_reserved_gdt_blocks : 16 : littleendian; (* Per group desc for online growth *)
-    s_journal_uuid : 128 : bitstring;          (* uuid of journal superblock *)
-    s_journal_inum : 32 : littleendian;                (* inode number of journal file *)
-    s_journal_dev : 32 : littleendian;         (* device number of journal file *)
-    s_last_orphan : 32 : littleendian;         (* start of list of inodes to delete *)
-    s_hash_seed0 : 32 : littleendian;          (* HTREE hash seed *)
-    s_hash_seed1 : 32 : littleendian;
-    s_hash_seed2 : 32 : littleendian;
-    s_hash_seed3 : 32 : littleendian;
-    s_def_hash_version : 8;                    (* Default hash version to use *)
-    s_reserved_char_pad : 8;
-    s_reserved_word_pad : 16 : littleendian;
-    s_default_mount_opts : 32 : littleendian;
-    s_first_meta_bg : 32 : littleendian;       (* First metablock block group *)
-    s_reserved : 6080 : bitstring ->            (* Padding to the end of the block *)
+  | { s_inodes_count : 32 : littleendian;      (* Inodes count *)
+      s_blocks_count : 32 : littleendian;      (* Blocks count *)
+      s_r_blocks_count : 32 : littleendian;    (* Reserved blocks count *)
+      s_free_blocks_count : 32 : littleendian; (* Free blocks count *)
+      s_free_inodes_count : 32 : littleendian; (* Free inodes count *)
+      s_first_data_block : 32 : littleendian;  (* First Data Block *)
+      s_log_block_size : 32 : littleendian;    (* Block size *)
+      s_log_frag_size : 32 : littleendian;     (* Fragment size *)
+      s_blocks_per_group : 32 : littleendian;  (* # Blocks per group *)
+      s_frags_per_group : 32 : littleendian;   (* # Fragments per group *)
+      s_inodes_per_group : 32 : littleendian;  (* # Inodes per group *)
+      s_mtime : 32 : littleendian;             (* Mount time *)
+      s_wtime : 32 : littleendian;             (* Write time *)
+      s_mnt_count : 16 : littleendian;         (* Mount count *)
+      s_max_mnt_count : 16 : littleendian;     (* Maximal mount count *)
+      0xef53 : 16 : littleendian;              (* Magic signature *)
+      s_state : 16 : littleendian;             (* File system state *)
+      s_errors : 16 : littleendian;            (* Behaviour when detecting errors *)
+      s_minor_rev_level : 16 : littleendian;   (* minor revision level *)
+      s_lastcheck : 32 : littleendian;         (* time of last check *)
+      s_checkinterval : 32 : littleendian;     (* max. time between checks *)
+      s_creator_os : 32 : littleendian;                (* OS *)
+      s_rev_level : 32 : littleendian;         (* Revision level *)
+      s_def_resuid : 16 : littleendian;                (* Default uid for reserved blocks *)
+      s_def_resgid : 16 : littleendian;                (* Default gid for reserved blocks *)
+      s_first_ino : 32 : littleendian;         (* First non-reserved inode *)
+      s_inode_size : 16 : littleendian;                (* size of inode structure *)
+      s_block_group_nr : 16 : littleendian;    (* block group # of this superblock *)
+      s_feature_compat : 32 : littleendian;    (* compatible feature set *)
+      s_feature_incompat : 32 : littleendian;  (* incompatible feature set *)
+      s_feature_ro_compat : 32 : littleendian; (* readonly-compatible feature set *)
+      s_uuid : 128 : bitstring;                        (* 128-bit uuid for volume *)
+      s_volume_name : 128 : bitstring;         (* volume name XXX string *)
+      s_last_mounted : 512 : bitstring;                (* directory where last mounted XXX string *)
+      s_algorithm_usage_bitmap : 32 : littleendian; (* For compression *)
+      s_prealloc_blocks : 8;                   (* Nr of blocks to try to preallocate*)
+      s_prealloc_dir_blocks : 8;               (* Nr to preallocate for dirs *)
+      s_reserved_gdt_blocks : 16 : littleendian;(* Per group desc for online growth *)
+      s_journal_uuid : 128 : bitstring;                (* uuid of journal superblock *)
+      s_journal_inum : 32 : littleendian;      (* inode number of journal file *)
+      s_journal_dev : 32 : littleendian;       (* device number of journal file *)
+      s_last_orphan : 32 : littleendian;       (* start of list of inodes to delete *)
+      s_hash_seed0 : 32 : littleendian;                (* HTREE hash seed *)
+      s_hash_seed1 : 32 : littleendian;
+      s_hash_seed2 : 32 : littleendian;
+      s_hash_seed3 : 32 : littleendian;
+      s_def_hash_version : 8;                  (* Default hash version to use *)
+      s_reserved_char_pad : 8;
+      s_reserved_word_pad : 16 : littleendian;
+      s_default_mount_opts : 32 : littleendian;
+      s_first_meta_bg : 32 : littleendian;     (* First metablock block group *)
+      s_reserved : 6080 : bitstring } ->        (* Padding to the end of the block *)
 
     printf "ext3 superblock:\n";
     printf "  s_inodes_count = %ld\n" s_inodes_count;
@@ -71,6 +71,6 @@ let () =
     printf "  s_free_inodes_count = %ld\n" s_free_inodes_count;
     printf "  s_free_blocks_count = %ld\n" s_free_blocks_count
 
-  | _ ->
+  | { _ } ->
     eprintf "not an ext3 superblock!\n%!";
     exit 2