1 (* Bitmatch syntax extension.
2 * Copyright (C) 2008 Red Hat Inc., Richard W.M. Jones
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 (* If this is true then we emit some debugging code which can
28 * be useful to tell what is happening during matches. You
29 * also need to do 'Bitmatch.debug := true' in your main program.
31 * If this is false then no extra debugging code is emitted.
35 (* Work out if an expression is an integer constant.
37 * Returns [Some i] if so (where i is the integer value), else [None].
39 * Fairly simplistic algorithm: we can only detect simple constant
40 * expressions such as [k], [k+c], [k-c] etc.
42 let rec expr_is_constant = function
43 | <:expr< $int:i$ >> -> (* Literal integer constant. *)
44 Some (int_of_string i)
45 | <:expr< $a$ + $b$ >> -> (* Addition of constants. *)
46 (match expr_is_constant a, expr_is_constant b with
47 | Some a, Some b -> Some (a+b)
49 | <:expr< $a$ - $b$ >> -> (* Subtraction. *)
50 (match expr_is_constant a, expr_is_constant b with
51 | Some a, Some b -> Some (a-b)
53 | <:expr< $a$ * $b$ >> -> (* Multiplication. *)
54 (match expr_is_constant a, expr_is_constant b with
55 | Some a, Some b -> Some (a*b)
57 | <:expr< $a$ / $b$ >> -> (* Division. *)
58 (match expr_is_constant a, expr_is_constant b with
59 | Some a, Some b -> Some (a/b)
61 | <:expr< $a$ lsl $b$ >> -> (* Shift left. *)
62 (match expr_is_constant a, expr_is_constant b with
63 | Some a, Some b -> Some (a lsl b)
65 | <:expr< $a$ lsr $b$ >> -> (* Shift right. *)
66 (match expr_is_constant a, expr_is_constant b with
67 | Some a, Some b -> Some (a lsr b)
69 | _ -> None (* Anything else is not constant. *)
71 (* Field. In bitmatch (patterns) the type is [patt field]. In
72 * BITSTRING (constructor) the type is [expr field].
75 field : 'a; (* field ('a is either patt or expr) *)
76 flen : expr; (* length in bits, may be non-const *)
77 endian : Bitmatch.endian; (* endianness *)
78 signed : bool; (* true if signed, false if unsigned *)
80 _loc : Loc.t; (* location in source code *)
81 printer : 'a -> string; (* turn the field into a string *)
83 and t = Int | String | Bitstring
85 (* Generate a fresh, unique symbol each time called. *)
90 sprintf "__pabitmatch_%s_%d" name i
92 (* Deal with the qualifiers which appear for a field of both types. *)
93 let parse_field _loc field flen qs printer =
94 let endian, signed, t =
96 | None -> (None, None, None)
99 fun (endian, signed, t) q ->
102 if endian <> None then
103 Loc.raise _loc (Failure "an endian flag has been set already")
105 let endian = Some Bitmatch.BigEndian in
109 if endian <> None then
110 Loc.raise _loc (Failure "an endian flag has been set already")
112 let endian = Some Bitmatch.LittleEndian in
116 if endian <> None then
117 Loc.raise _loc (Failure "an endian flag has been set already")
119 let endian = Some Bitmatch.NativeEndian in
123 if signed <> None then
124 Loc.raise _loc (Failure "a signed flag has been set already")
126 let signed = Some true in
130 if signed <> None then
131 Loc.raise _loc (Failure "a signed flag has been set already")
133 let signed = Some false in
138 Loc.raise _loc (Failure "a type flag has been set already")
145 Loc.raise _loc (Failure "a type flag has been set already")
147 let t = Some String in
152 Loc.raise _loc (Failure "a type flag has been set already")
154 let t = Some Bitstring in
158 Loc.raise _loc (Failure (s ^ ": unknown qualifier"))
159 ) (None, None, None) qs in
161 (* If type is set to string or bitstring then endianness and
162 * signedness qualifiers are meaningless and must not be set.
164 if (t = Some Bitstring || t = Some String)
165 && (endian <> None || signed <> None) then
167 Failure "string types and endian or signed qualifiers cannot be mixed"
170 (* Default endianness, signedness, type. *)
171 let endian = match endian with None -> Bitmatch.BigEndian | Some e -> e in
172 let signed = match signed with None -> false | Some s -> s in
173 let t = match t with None -> Int | Some t -> t in
185 let string_of_t = function
188 | Bitstring -> "bitstring"
190 let patt_printer = function
191 | <:patt< $lid:id$ >> -> id
194 let expr_printer = function
195 | <:expr< $lid:id$ >> -> id
196 | _ -> "[expression]"
198 let string_of_field { field = field; flen = flen;
199 endian = endian; signed = signed; t = t;
203 match expr_is_constant flen with
204 | Some i -> string_of_int i
205 | None -> "[non-const-len]" in
206 let endian = Bitmatch.string_of_endian endian in
207 let signed = if signed then "signed" else "unsigned" in
208 let t = string_of_t t in
209 let loc_fname = Loc.file_name _loc in
210 let loc_line = Loc.start_line _loc in
211 let loc_char = Loc.start_off _loc - Loc.start_bol _loc in
213 sprintf "%s : %s : %s, %s, %s @ (%S, %d, %d)"
214 (printer field) flen t endian signed loc_fname loc_line loc_char
216 (* Generate the code for a constructor, ie. 'BITSTRING ...'. *)
217 let output_constructor _loc fields =
218 let loc_fname = Loc.file_name _loc in
219 let loc_line = string_of_int (Loc.start_line _loc) in
220 let loc_char = string_of_int (Loc.start_off _loc - Loc.start_bol _loc) in
222 (* Bitstrings are created like the 'Buffer' module (in fact, using
223 * the Buffer module), by appending snippets to a growing buffer.
224 * This is reasonably efficient and avoids a lot of garbage.
226 let buffer = gensym "buffer" in
228 (* General exception which is raised inside the constructor functions
229 * when an int expression is out of range at runtime.
231 let exn = gensym "exn" in
232 let exn_used = ref false in
234 (* Convert each field to a simple bitstring-generating expression. *)
235 let fields = List.map (
236 fun {field=fexpr; flen=flen; endian=endian; signed=signed;
238 (* Is flen an integer constant? If so, what is it? This
239 * is very simple-minded and only detects simple constants.
241 let flen_is_const = expr_is_constant flen in
243 let name_of_int_construct_const = function
244 (* XXX As an enhancement we should allow a 64-bit-only
245 * mode which lets us use 'int' up to 63 bits and won't
246 * compile on 32-bit platforms.
248 (* XXX The meaning of signed/unsigned breaks down at
249 * 31, 32, 63 and 64 bits.
251 | (1, _, _) -> "construct_bit"
252 | ((2|3|4|5|6|7|8), _, false) -> "construct_char_unsigned"
253 | ((2|3|4|5|6|7|8), _, true) -> "construct_char_signed"
254 | (i, Bitmatch.BigEndian, false) when i <= 31 ->
255 "construct_int_be_unsigned"
256 | (i, Bitmatch.BigEndian, true) when i <= 31 ->
257 "construct_int_be_signed"
258 | (i, Bitmatch.LittleEndian, false) when i <= 31 ->
259 "construct_int_le_unsigned"
260 | (i, Bitmatch.LittleEndian, true) when i <= 31 ->
261 "construct_int_le_signed"
262 | (i, Bitmatch.NativeEndian, false) when i <= 31 ->
263 "construct_int_ne_unsigned"
264 | (i, Bitmatch.NativeEndian, true) when i <= 31 ->
265 "construct_int_ne_signed"
266 | (32, Bitmatch.BigEndian, false) -> "construct_int32_be_unsigned"
267 | (32, Bitmatch.BigEndian, true) -> "construct_int32_be_signed"
268 | (32, Bitmatch.LittleEndian, false) -> "construct_int32_le_unsigned"
269 | (32, Bitmatch.LittleEndian, true) -> "construct_int32_le_signed"
270 | (32, Bitmatch.NativeEndian, false) -> "construct_int32_ne_unsigned"
271 | (32, Bitmatch.NativeEndian, true) -> "construct_int32_ne_signed"
272 | (_, Bitmatch.BigEndian, false) -> "construct_int64_be_unsigned"
273 | (_, Bitmatch.BigEndian, true) -> "construct_int64_be_signed"
274 | (_, Bitmatch.LittleEndian, false) -> "construct_int64_le_unsigned"
275 | (_, Bitmatch.LittleEndian, true) -> "construct_int64_le_signed"
276 | (_, Bitmatch.NativeEndian, false) -> "construct_int64_ne_unsigned"
277 | (_, Bitmatch.NativeEndian, true) -> "construct_int64_ne_signed"
279 let name_of_int_construct = function
280 (* XXX As an enhancement we should allow users to
281 * specify that a field length can fit into a char/int/int32
282 * (of course, this would have to be checked at runtime).
284 | (Bitmatch.BigEndian, false) -> "construct_int64_be_unsigned"
285 | (Bitmatch.BigEndian, true) -> "construct_int64_be_signed"
286 | (Bitmatch.LittleEndian, false) -> "construct_int64_le_unsigned"
287 | (Bitmatch.LittleEndian, true) -> "construct_int64_le_signed"
288 | (Bitmatch.NativeEndian, false) -> "construct_int64_ne_unsigned"
289 | (Bitmatch.NativeEndian, true) -> "construct_int64_ne_signed"
293 match t, flen_is_const with
294 (* Common case: int field, constant flen.
296 * Range checks are done inside the construction function
297 * because that's a lot simpler w.r.t. types. It might
298 * be better to move them here. XXX
300 | Int, Some i when i > 0 && i <= 64 ->
302 name_of_int_construct_const (i,endian,signed) in
306 Bitmatch.$lid:construct_func$ $lid:buffer$ $fexpr$ $`int:i$
311 Loc.raise _loc (Failure "length of int field must be [1..64]")
313 (* Int field, non-constant length. We need to perform a runtime
314 * test to ensure the length is [1..64].
316 * Range checks are done inside the construction function
317 * because that's a lot simpler w.r.t. types. It might
318 * be better to move them here. XXX
321 let construct_func = name_of_int_construct (endian,signed) in
325 if $flen$ >= 1 && $flen$ <= 64 then
326 Bitmatch.$lid:construct_func$ $lid:buffer$ $fexpr$ $flen$
329 raise (Bitmatch.Construct_failure
330 ("length of int field must be [1..64]",
332 $int:loc_line$, $int:loc_char$))
335 (* String, constant length > 0, must be a multiple of 8. *)
336 | String, Some i when i > 0 && i land 7 = 0 ->
337 let bs = gensym "bs" in
340 let $lid:bs$ = $fexpr$ in
341 if String.length $lid:bs$ = $`int:j$ then
342 Bitmatch.construct_string $lid:buffer$ $lid:bs$
344 raise (Bitmatch.Construct_failure
345 ("length of string does not match declaration",
347 $int:loc_line$, $int:loc_char$))
350 (* String, constant length -1, means variable length string
353 | String, Some (-1) ->
354 <:expr< Bitmatch.construct_string $lid:buffer$ $fexpr$ >>
356 (* String, constant length = 0 is probably an error, and so is
360 Loc.raise _loc (Failure "length of string must be > 0 and a multiple of 8, or the special value -1")
362 (* String, non-constant length.
363 * We check at runtime that the length is > 0, a multiple of 8,
364 * and matches the declared length.
367 let bslen = gensym "bslen" in
368 let bs = gensym "bs" in
370 let $lid:bslen$ = $flen$ in
371 if $lid:bslen$ > 0 then (
372 if $lid:bslen$ land 7 = 0 then (
373 let $lid:bs$ = $fexpr$ in
374 if String.length $lid:bs$ = ($lid:bslen$ lsr 3) then
375 Bitmatch.construct_string $lid:buffer$ $lid:bs$
377 raise (Bitmatch.Construct_failure
378 ("length of string does not match declaration",
380 $int:loc_line$, $int:loc_char$))
382 raise (Bitmatch.Construct_failure
383 ("length of string must be a multiple of 8",
385 $int:loc_line$, $int:loc_char$))
387 raise (Bitmatch.Construct_failure
388 ("length of string must be > 0",
390 $int:loc_line$, $int:loc_char$))
393 (* Bitstring, constant length > 0. *)
394 | Bitstring, Some i when i > 0 ->
395 let bs = gensym "bs" in
397 let $lid:bs$ = $fexpr$ in
398 if Bitmatch.bitstring_length $lid:bs$ = $`int:i$ then
399 Bitmatch.construct_bitstring $lid:buffer$ $lid:bs$
401 raise (Bitmatch.Construct_failure
402 ("length of bitstring does not match declaration",
404 $int:loc_line$, $int:loc_char$))
407 (* Bitstring, constant length -1, means variable length bitstring
410 | Bitstring, Some (-1) ->
411 <:expr< Bitmatch.construct_bitstring $lid:buffer$ $fexpr$ >>
413 (* Bitstring, constant length = 0 is probably an error, and so is
416 | Bitstring, Some _ ->
419 "length of bitstring must be > 0 or the special value -1")
421 (* Bitstring, non-constant length.
422 * We check at runtime that the length is > 0 and matches
423 * the declared length.
426 let bslen = gensym "bslen" in
427 let bs = gensym "bs" in
429 let $lid:bslen$ = $flen$ in
430 if $lid:bslen$ > 0 then (
431 let $lid:bs$ = $fexpr$ in
432 if Bitmatch.bitstring_length $lid:bs$ = $lid:bslen$ then
433 Bitmatch.construct_bitstring $lid:buffer$ $lid:bs$
435 raise (Bitmatch.Construct_failure
436 ("length of bitstring does not match declaration",
438 $int:loc_line$, $int:loc_char$))
440 raise (Bitmatch.Construct_failure
441 ("length of bitstring must be > 0",
443 $int:loc_line$, $int:loc_char$))
448 (* Create the final bitstring. Start by creating an empty buffer
449 * and then evaluate each expression above in turn which will
450 * append some more to the bitstring buffer. Finally extract
453 * XXX We almost have enough information to be able to guess
454 * a good initial size for the buffer.
458 | [] -> <:expr< [] >>
459 | h::t -> List.fold_left (fun h t -> <:expr< $h$; $t$ >>) h t in
463 let $lid:buffer$ = Bitmatch.Buffer.create () in
465 Bitmatch.Buffer.contents $lid:buffer$
471 Bitmatch.Construct_failure ("value out of range",
473 $int:loc_line$, $int:loc_char$) in
479 (* Generate the code for a bitmatch statement. '_loc' is the
480 * location, 'bs' is the bitstring parameter, 'cases' are
481 * the list of cases to test against.
483 let output_bitmatch _loc bs cases =
484 let data = gensym "data" and off = gensym "off" and len = gensym "len" in
485 let result = gensym "result" in
487 (* This generates the field extraction code for each
488 * field a single case. Each field must be wider than
489 * the minimum permitted for the type and there must be
490 * enough remaining data in the bitstring to satisfy it.
491 * As we go through the fields, symbols 'data', 'off' and 'len'
492 * track our position and remaining length in the bitstring.
494 * The whole thing is a lot of nested 'if' statements. Code
495 * is generated from the inner-most (last) field outwards.
497 let rec output_field_extraction inner = function
500 let {field=fpatt; flen=flen; endian=endian; signed=signed;
504 (* Is flen an integer constant? If so, what is it? This
505 * is very simple-minded and only detects simple constants.
507 let flen_is_const = expr_is_constant flen in
509 let name_of_int_extract_const = function
510 (* XXX As an enhancement we should allow a 64-bit-only
511 * mode which lets us use 'int' up to 63 bits and won't
512 * compile on 32-bit platforms.
514 (* XXX The meaning of signed/unsigned breaks down at
515 * 31, 32, 63 and 64 bits.
517 | (1, _, _) -> "extract_bit"
518 | ((2|3|4|5|6|7|8), _, false) -> "extract_char_unsigned"
519 | ((2|3|4|5|6|7|8), _, true) -> "extract_char_signed"
520 | (i, Bitmatch.BigEndian, false) when i <= 31 ->
521 "extract_int_be_unsigned"
522 | (i, Bitmatch.BigEndian, true) when i <= 31 ->
523 "extract_int_be_signed"
524 | (i, Bitmatch.LittleEndian, false) when i <= 31 ->
525 "extract_int_le_unsigned"
526 | (i, Bitmatch.LittleEndian, true) when i <= 31 ->
527 "extract_int_le_signed"
528 | (i, Bitmatch.NativeEndian, false) when i <= 31 ->
529 "extract_int_ne_unsigned"
530 | (i, Bitmatch.NativeEndian, true) when i <= 31 ->
531 "extract_int_ne_signed"
532 | (32, Bitmatch.BigEndian, false) -> "extract_int32_be_unsigned"
533 | (32, Bitmatch.BigEndian, true) -> "extract_int32_be_signed"
534 | (32, Bitmatch.LittleEndian, false) -> "extract_int32_le_unsigned"
535 | (32, Bitmatch.LittleEndian, true) -> "extract_int32_le_signed"
536 | (32, Bitmatch.NativeEndian, false) -> "extract_int32_ne_unsigned"
537 | (32, Bitmatch.NativeEndian, true) -> "extract_int32_ne_signed"
538 | (_, Bitmatch.BigEndian, false) -> "extract_int64_be_unsigned"
539 | (_, Bitmatch.BigEndian, true) -> "extract_int64_be_signed"
540 | (_, Bitmatch.LittleEndian, false) -> "extract_int64_le_unsigned"
541 | (_, Bitmatch.LittleEndian, true) -> "extract_int64_le_signed"
542 | (_, Bitmatch.NativeEndian, false) -> "extract_int64_ne_unsigned"
543 | (_, Bitmatch.NativeEndian, true) -> "extract_int64_ne_signed"
545 let name_of_int_extract = function
546 (* XXX As an enhancement we should allow users to
547 * specify that a field length can fit into a char/int/int32
548 * (of course, this would have to be checked at runtime).
550 | (Bitmatch.BigEndian, false) -> "extract_int64_be_unsigned"
551 | (Bitmatch.BigEndian, true) -> "extract_int64_be_signed"
552 | (Bitmatch.LittleEndian, false) -> "extract_int64_le_unsigned"
553 | (Bitmatch.LittleEndian, true) -> "extract_int64_le_signed"
554 | (Bitmatch.NativeEndian, false) -> "extract_int64_ne_unsigned"
555 | (Bitmatch.NativeEndian, true) -> "extract_int64_ne_signed"
559 match t, flen_is_const with
560 (* Common case: int field, constant flen *)
561 | Int, Some i when i > 0 && i <= 64 ->
562 let extract_func = name_of_int_extract_const (i,endian,signed) in
563 let v = gensym "val" in
565 if $lid:len$ >= $`int:i$ then (
566 let $lid:v$, $lid:off$, $lid:len$ =
567 Bitmatch.$lid:extract_func$ $lid:data$ $lid:off$ $lid:len$
569 match $lid:v$ with $fpatt$ when true -> $inner$ | _ -> ()
574 Loc.raise _loc (Failure "length of int field must be [1..64]")
576 (* Int field, non-const flen. We have to test the range of
577 * the field at runtime. If outside the range it's a no-match
581 let extract_func = name_of_int_extract (endian,signed) in
582 let v = gensym "val" in
584 if $flen$ >= 1 && $flen$ <= 64 && $flen$ <= $lid:len$ then (
585 let $lid:v$, $lid:off$, $lid:len$ =
586 Bitmatch.$lid:extract_func$ $lid:data$ $lid:off$ $lid:len$
588 match $lid:v$ with $fpatt$ when true -> $inner$ | _ -> ()
592 (* String, constant flen > 0. *)
593 | String, Some i when i > 0 && i land 7 = 0 ->
594 let bs = gensym "bs" in
596 if $lid:len$ >= $`int:i$ then (
597 let $lid:bs$, $lid:off$, $lid:len$ =
598 Bitmatch.extract_bitstring $lid:data$ $lid:off$ $lid:len$
600 match Bitmatch.string_of_bitstring $lid:bs$ with
601 | $fpatt$ when true -> $inner$
606 (* String, constant flen = -1, means consume all the
609 | String, Some i when i = -1 ->
610 let bs = gensym "bs" in
612 let $lid:bs$, $lid:off$, $lid:len$ =
613 Bitmatch.extract_remainder $lid:data$ $lid:off$ $lid:len$ in
614 match Bitmatch.string_of_bitstring $lid:bs$ with
615 | $fpatt$ when true -> $inner$
620 Loc.raise _loc (Failure "length of string must be > 0 and a multiple of 8, or the special value -1")
622 (* String field, non-const flen. We check the flen is > 0
623 * and a multiple of 8 (-1 is not allowed here), at runtime.
626 let bs = gensym "bs" in
628 if $flen$ >= 0 && $flen$ <= $lid:len$
629 && $flen$ land 7 = 0 then (
630 let $lid:bs$, $lid:off$, $lid:len$ =
631 Bitmatch.extract_bitstring
632 $lid:data$ $lid:off$ $lid:len$ $flen$ in
633 match Bitmatch.string_of_bitstring $lid:bs$ with
634 | $fpatt$ when true -> $inner$
639 (* Bitstring, constant flen >= 0.
640 * At the moment all we can do is assign the bitstring to an
643 | Bitstring, Some i when i >= 0 ->
646 | <:patt< $lid:ident$ >> -> ident
647 | <:patt< _ >> -> "_"
650 (Failure "cannot compare a bitstring to a constant") in
652 if $lid:len$ >= $`int:i$ then (
653 let $lid:ident$, $lid:off$, $lid:len$ =
654 Bitmatch.extract_bitstring $lid:data$ $lid:off$ $lid:len$
660 (* Bitstring, constant flen = -1, means consume all the
663 | Bitstring, Some i when i = -1 ->
666 | <:patt< $lid:ident$ >> -> ident
667 | <:patt< _ >> -> "_"
670 (Failure "cannot compare a bitstring to a constant") in
672 let $lid:ident$, $lid:off$, $lid:len$ =
673 Bitmatch.extract_remainder $lid:data$ $lid:off$ $lid:len$ in
677 | Bitstring, Some _ ->
678 Loc.raise _loc (Failure "length of bitstring must be >= 0 or the special value -1")
680 (* Bitstring field, non-const flen. We check the flen is >= 0
681 * (-1 is not allowed here) at runtime.
686 | <:patt< $lid:ident$ >> -> ident
687 | <:patt< _ >> -> "_"
690 (Failure "cannot compare a bitstring to a constant") in
692 if $flen$ >= 0 && $flen$ <= $lid:len$ then (
693 let $lid:ident$, $lid:off$, $lid:len$ =
694 Bitmatch.extract_bitstring $lid:data$ $lid:off$ $lid:len$
701 (* Emit extra debugging code. *)
703 if not debug then expr else (
704 let field = string_of_field field in
707 if !Bitmatch.debug then (
708 Printf.eprintf "PA_BITMATCH: TEST:\n";
709 Printf.eprintf " %s\n" $str:field$;
710 Printf.eprintf " off %d len %d\n%!" $lid:off$ $lid:len$;
711 (*Bitmatch.hexdump_bitstring stderr
712 ($lid:data$,$lid:off$,$lid:len$);*)
718 output_field_extraction expr fields
721 (* Convert each case in the match. *)
722 let cases = List.map (
723 fun (fields, bind, whenclause, code) ->
724 let inner = <:expr< $lid:result$ := Some ($code$); raise Exit >> in
726 match whenclause with
728 <:expr< if $whenclause$ then $inner$ >>
734 let $lid:name$ = ($lid:data$, $lid:off$, $lid:len$) in
738 output_field_extraction inner (List.rev fields)
741 (* Join them into a single expression.
743 * Don't do it with a normal fold_right because that leaves
744 * 'raise Exit; ()' at the end which causes a compiler warning.
745 * Hence a bit of complexity here.
747 * Note that the number of cases is always >= 1 so List.hd is safe.
749 let cases = List.rev cases in
751 List.fold_left (fun base case -> <:expr< $case$ ; $base$ >>)
752 (List.hd cases) (List.tl cases) in
754 (* The final code just wraps the list of cases in a
755 * try/with construct so that each case is tried in
756 * turn until one case matches (that case sets 'result'
757 * and raises 'Exit' to leave the whole statement).
758 * If result isn't set by the end then we will raise
759 * Match_failure with the location of the bitmatch
760 * statement in the original code.
762 let loc_fname = Loc.file_name _loc in
763 let loc_line = string_of_int (Loc.start_line _loc) in
764 let loc_char = string_of_int (Loc.start_off _loc - Loc.start_bol _loc) in
767 let ($lid:data$, $lid:off$, $lid:len$) = $bs$ in
768 let $lid:result$ = ref None in
772 match ! $lid:result$ with
774 | None -> raise (Match_failure ($str:loc_fname$,
775 $int:loc_line$, $int:loc_char$))
782 [ LIST0 [ q = LIDENT -> q ] SEP "," ]
785 (* Field used in the bitmatch operator (a pattern). *)
787 [ fpatt = patt; ":"; len = expr LEVEL "top";
788 qs = OPT [ ":"; qs = qualifiers -> qs ] ->
789 parse_field _loc fpatt len qs patt_printer
793 (* Case inside bitmatch operator. *)
796 fields = LIST0 patt_field SEP ";";
798 bind = OPT [ "as"; name = LIDENT -> name ];
799 whenclause = OPT [ "when"; e = expr -> e ]; "->";
801 (fields, bind, whenclause, code)
805 (* Field used in the BITSTRING constructor (an expression). *)
807 [ fexpr = expr LEVEL "top"; ":"; len = expr LEVEL "top";
808 qs = OPT [ ":"; qs = qualifiers -> qs ] ->
809 parse_field _loc fexpr len qs expr_printer
813 (* 'bitmatch' expressions. *)
816 bs = expr; "with"; OPT "|";
817 cases = LIST1 match_case SEP "|" ->
818 output_bitmatch _loc bs cases
822 | [ "BITSTRING"; "{";
823 fields = LIST0 constr_field SEP ";";
825 output_constructor _loc fields