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
28 module P = Bitmatch_persistent
30 (* If this is true then we emit some debugging code which can
31 * be useful to tell what is happening during matches. You
32 * also need to do 'Bitmatch.debug := true' in your main program.
34 * If this is false then no extra debugging code is emitted.
38 (* Work out if an expression is an integer constant.
40 * Returns [Some i] if so (where i is the integer value), else [None].
42 * Fairly simplistic algorithm: we can only detect simple constant
43 * expressions such as [k], [k+c], [k-c] etc.
45 let rec expr_is_constant = function
46 | <:expr< $int:i$ >> -> (* Literal integer constant. *)
47 Some (int_of_string i)
48 | <:expr< $a$ + $b$ >> -> (* Addition of constants. *)
49 (match expr_is_constant a, expr_is_constant b with
50 | Some a, Some b -> Some (a+b)
52 | <:expr< $a$ - $b$ >> -> (* Subtraction. *)
53 (match expr_is_constant a, expr_is_constant b with
54 | Some a, Some b -> Some (a-b)
56 | <:expr< $a$ * $b$ >> -> (* Multiplication. *)
57 (match expr_is_constant a, expr_is_constant b with
58 | Some a, Some b -> Some (a*b)
60 | <:expr< $a$ / $b$ >> -> (* Division. *)
61 (match expr_is_constant a, expr_is_constant b with
62 | Some a, Some b -> Some (a/b)
64 | <:expr< $a$ lsl $b$ >> -> (* Shift left. *)
65 (match expr_is_constant a, expr_is_constant b with
66 | Some a, Some b -> Some (a lsl b)
68 | <:expr< $a$ lsr $b$ >> -> (* Shift right. *)
69 (match expr_is_constant a, expr_is_constant b with
70 | Some a, Some b -> Some (a lsr b)
72 | _ -> None (* Anything else is not constant. *)
74 (* Generate a fresh, unique symbol each time called. *)
79 sprintf "__pabitmatch_%s_%d" name i
81 (* Deal with the qualifiers which appear for a field of both types. *)
82 let parse_field _loc field qs =
83 let endian_set, signed_set, type_set, field =
85 | None -> (false, false, false, field)
88 fun (endian_set, signed_set, type_set, field) qual_expr ->
90 | "bigendian", None ->
92 Loc.raise _loc (Failure "an endian flag has been set already")
94 let field = P.set_endian field BigEndian in
95 (true, signed_set, type_set, field)
97 | "littleendian", None ->
99 Loc.raise _loc (Failure "an endian flag has been set already")
101 let field = P.set_endian field LittleEndian in
102 (true, signed_set, type_set, field)
104 | "nativeendian", None ->
106 Loc.raise _loc (Failure "an endian flag has been set already")
108 let field = P.set_endian field NativeEndian in
109 (true, signed_set, type_set, field)
111 | "endian", Some expr ->
113 Loc.raise _loc (Failure "an endian flag has been set already")
115 let field = P.set_endian_expr field expr in
116 (true, signed_set, type_set, field)
120 Loc.raise _loc (Failure "a signed flag has been set already")
122 let field = P.set_signed field true in
123 (endian_set, true, type_set, field)
125 | "unsigned", None ->
127 Loc.raise _loc (Failure "a signed flag has been set already")
129 let field = P.set_signed field false in
130 (endian_set, true, type_set, field)
134 Loc.raise _loc (Failure "a type flag has been set already")
136 let field = P.set_type_int field in
137 (endian_set, signed_set, true, field)
141 Loc.raise _loc (Failure "a type flag has been set already")
143 let field = P.set_type_string field in
144 (endian_set, signed_set, true, field)
146 | "bitstring", None ->
148 Loc.raise _loc (Failure "a type flag has been set already")
150 let field = P.set_type_bitstring field in
151 (endian_set, signed_set, true, field)
154 Loc.raise _loc (Failure (s ^ ": unknown qualifier, or qualifier should not be followed by an expression"))
156 Loc.raise _loc (Failure (s ^ ": unknown qualifier, or qualifier should be followed by an expression"))
157 ) (false, false, false, field) qs in
159 (* If type is set to string or bitstring then endianness and
160 * signedness qualifiers are meaningless and must not be set.
163 let t = P.get_type field in
164 if (t = P.Bitstring || t = P.String) && (endian_set || signed_set) then
166 Failure "string types and endian or signed qualifiers cannot be mixed"
169 (* Default endianness, signedness, type if not set already. *)
170 let field = if endian_set then field else P.set_endian field BigEndian in
171 let field = if signed_set then field else P.set_signed field false in
172 let field = if type_set then field else P.set_type_int field in
176 (* Generate the code for a constructor, ie. 'BITSTRING ...'. *)
177 let output_constructor _loc fields =
178 let loc_fname = Loc.file_name _loc in
179 let loc_line = string_of_int (Loc.start_line _loc) in
180 let loc_char = string_of_int (Loc.start_off _loc - Loc.start_bol _loc) in
182 (* Bitstrings are created like the 'Buffer' module (in fact, using
183 * the Buffer module), by appending snippets to a growing buffer.
184 * This is reasonably efficient and avoids a lot of garbage.
186 let buffer = gensym "buffer" in
188 (* General exception which is raised inside the constructor functions
189 * when an int expression is out of range at runtime.
191 let exn = gensym "exn" in
192 let exn_used = ref false in
194 (* Convert each field to a simple bitstring-generating expression. *)
195 let fields = List.map (
197 let fexpr = P.get_expr field in
198 let flen = P.get_length field in
199 let endian = P.get_endian field in
200 let signed = P.get_signed field in
201 let t = P.get_type field in
202 let _loc = P.get_location field in
204 (* Is flen an integer constant? If so, what is it? This
205 * is very simple-minded and only detects simple constants.
207 let flen_is_const = expr_is_constant flen in
209 (* Choose the right constructor function. *)
210 let int_construct_const = function
211 (* XXX The meaning of signed/unsigned breaks down at
212 * 31, 32, 63 and 64 bits.
215 <:expr<Bitmatch.construct_bit>>
216 | ((2|3|4|5|6|7|8), _, false) ->
217 <:expr<Bitmatch.construct_char_unsigned>>
218 | ((2|3|4|5|6|7|8), _, true) ->
219 <:expr<Bitmatch.construct_char_signed>>
220 | (i, P.ConstantEndian BigEndian, false) when i <= 31 ->
221 <:expr<Bitmatch.construct_int_be_unsigned>>
222 | (i, P.ConstantEndian BigEndian, true) when i <= 31 ->
223 <:expr<Bitmatch.construct_int_be_signed>>
224 | (i, P.ConstantEndian LittleEndian, false) when i <= 31 ->
225 <:expr<Bitmatch.construct_int_le_unsigned>>
226 | (i, P.ConstantEndian LittleEndian, true) when i <= 31 ->
227 <:expr<Bitmatch.construct_int_le_signed>>
228 | (i, P.ConstantEndian NativeEndian, false) when i <= 31 ->
229 <:expr<Bitmatch.construct_int_ne_unsigned>>
230 | (i, P.ConstantEndian NativeEndian, true) when i <= 31 ->
231 <:expr<Bitmatch.construct_int_ne_signed>>
232 | (i, P.EndianExpr expr, false) when i <= 31 ->
233 <:expr<Bitmatch.construct_int_ee_unsigned $expr$>>
234 | (i, P.EndianExpr expr, true) when i <= 31 ->
235 <:expr<Bitmatch.construct_int_ee_signed $expr$>>
236 | (32, P.ConstantEndian BigEndian, false) ->
237 <:expr<Bitmatch.construct_int32_be_unsigned>>
238 | (32, P.ConstantEndian BigEndian, true) ->
239 <:expr<Bitmatch.construct_int32_be_signed>>
240 | (32, P.ConstantEndian LittleEndian, false) ->
241 <:expr<Bitmatch.construct_int32_le_unsigned>>
242 | (32, P.ConstantEndian LittleEndian, true) ->
243 <:expr<Bitmatch.construct_int32_le_signed>>
244 | (32, P.ConstantEndian NativeEndian, false) ->
245 <:expr<Bitmatch.construct_int32_ne_unsigned>>
246 | (32, P.ConstantEndian NativeEndian, true) ->
247 <:expr<Bitmatch.construct_int32_ne_signed>>
248 | (32, P.EndianExpr expr, false) ->
249 <:expr<Bitmatch.construct_int32_ee_unsigned $expr$>>
250 | (32, P.EndianExpr expr, true) ->
251 <:expr<Bitmatch.construct_int32_ee_signed $expr$>>
252 | (_, P.ConstantEndian BigEndian, false) ->
253 <:expr<Bitmatch.construct_int64_be_unsigned>>
254 | (_, P.ConstantEndian BigEndian, true) ->
255 <:expr<Bitmatch.construct_int64_be_signed>>
256 | (_, P.ConstantEndian LittleEndian, false) ->
257 <:expr<Bitmatch.construct_int64_le_unsigned>>
258 | (_, P.ConstantEndian LittleEndian, true) ->
259 <:expr<Bitmatch.construct_int64_le_signed>>
260 | (_, P.ConstantEndian NativeEndian, false) ->
261 <:expr<Bitmatch.construct_int64_ne_unsigned>>
262 | (_, P.ConstantEndian NativeEndian, true) ->
263 <:expr<Bitmatch.construct_int64_ne_signed>>
264 | (_, P.EndianExpr expr, false) ->
265 <:expr<Bitmatch.construct_int64_ee_unsigned $expr$>>
266 | (_, P.EndianExpr expr, true) ->
267 <:expr<Bitmatch.construct_int64_ee_signed $expr$>>
269 let int_construct = function
270 | (P.ConstantEndian BigEndian, false) ->
271 <:expr<Bitmatch.construct_int64_be_unsigned>>
272 | (P.ConstantEndian BigEndian, true) ->
273 <:expr<Bitmatch.construct_int64_be_signed>>
274 | (P.ConstantEndian LittleEndian, false) ->
275 <:expr<Bitmatch.construct_int64_le_unsigned>>
276 | (P.ConstantEndian LittleEndian, true) ->
277 <:expr<Bitmatch.construct_int64_le_signed>>
278 | (P.ConstantEndian NativeEndian, false) ->
279 <:expr<Bitmatch.construct_int64_ne_unsigned>>
280 | (P.ConstantEndian NativeEndian, true) ->
281 <:expr<Bitmatch.construct_int64_ne_signed>>
282 | (P.EndianExpr expr, false) ->
283 <:expr<Bitmatch.construct_int64_ee_unsigned $expr$>>
284 | (P.EndianExpr expr, true) ->
285 <:expr<Bitmatch.construct_int64_ee_signed $expr$>>
289 match t, flen_is_const with
290 (* Common case: int field, constant flen.
292 * Range checks are done inside the construction function
293 * because that's a lot simpler w.r.t. types. It might
294 * be better to move them here. XXX
296 | P.Int, Some i when i > 0 && i <= 64 ->
297 let construct_fn = int_construct_const (i,endian,signed) in
301 $construct_fn$ $lid:buffer$ $fexpr$ $`int:i$ $lid:exn$
305 Loc.raise _loc (Failure "length of int field must be [1..64]")
307 (* Int field, non-constant length. We need to perform a runtime
308 * test to ensure the length is [1..64].
310 * Range checks are done inside the construction function
311 * because that's a lot simpler w.r.t. types. It might
312 * be better to move them here. XXX
315 let construct_fn = int_construct (endian,signed) in
319 if $flen$ >= 1 && $flen$ <= 64 then
320 $construct_fn$ $lid:buffer$ $fexpr$ $flen$ $lid:exn$
322 raise (Bitmatch.Construct_failure
323 ("length of int field must be [1..64]",
325 $int:loc_line$, $int:loc_char$))
328 (* String, constant length > 0, must be a multiple of 8. *)
329 | P.String, Some i when i > 0 && i land 7 = 0 ->
330 let bs = gensym "bs" in
333 let $lid:bs$ = $fexpr$ in
334 if String.length $lid:bs$ = $`int:j$ then
335 Bitmatch.construct_string $lid:buffer$ $lid:bs$
337 raise (Bitmatch.Construct_failure
338 ("length of string does not match declaration",
340 $int:loc_line$, $int:loc_char$))
343 (* String, constant length -1, means variable length string
346 | P.String, Some (-1) ->
347 <:expr< Bitmatch.construct_string $lid:buffer$ $fexpr$ >>
349 (* String, constant length = 0 is probably an error, and so is
352 | P.String, Some _ ->
353 Loc.raise _loc (Failure "length of string must be > 0 and a multiple of 8, or the special value -1")
355 (* String, non-constant length.
356 * We check at runtime that the length is > 0, a multiple of 8,
357 * and matches the declared length.
360 let bslen = gensym "bslen" in
361 let bs = gensym "bs" in
363 let $lid:bslen$ = $flen$ in
364 if $lid:bslen$ > 0 then (
365 if $lid:bslen$ land 7 = 0 then (
366 let $lid:bs$ = $fexpr$ in
367 if String.length $lid:bs$ = ($lid:bslen$ lsr 3) then
368 Bitmatch.construct_string $lid:buffer$ $lid:bs$
370 raise (Bitmatch.Construct_failure
371 ("length of string does not match declaration",
373 $int:loc_line$, $int:loc_char$))
375 raise (Bitmatch.Construct_failure
376 ("length of string must be a multiple of 8",
378 $int:loc_line$, $int:loc_char$))
380 raise (Bitmatch.Construct_failure
381 ("length of string must be > 0",
383 $int:loc_line$, $int:loc_char$))
386 (* Bitstring, constant length > 0. *)
387 | P.Bitstring, Some i when i > 0 ->
388 let bs = gensym "bs" in
390 let $lid:bs$ = $fexpr$ in
391 if Bitmatch.bitstring_length $lid:bs$ = $`int:i$ then
392 Bitmatch.construct_bitstring $lid:buffer$ $lid:bs$
394 raise (Bitmatch.Construct_failure
395 ("length of bitstring does not match declaration",
397 $int:loc_line$, $int:loc_char$))
400 (* Bitstring, constant length -1, means variable length bitstring
403 | P.Bitstring, Some (-1) ->
404 <:expr< Bitmatch.construct_bitstring $lid:buffer$ $fexpr$ >>
406 (* Bitstring, constant length = 0 is probably an error, and so is
409 | P.Bitstring, Some _ ->
412 "length of bitstring must be > 0 or the special value -1")
414 (* Bitstring, non-constant length.
415 * We check at runtime that the length is > 0 and matches
416 * the declared length.
418 | P.Bitstring, None ->
419 let bslen = gensym "bslen" in
420 let bs = gensym "bs" in
422 let $lid:bslen$ = $flen$ in
423 if $lid:bslen$ > 0 then (
424 let $lid:bs$ = $fexpr$ in
425 if Bitmatch.bitstring_length $lid:bs$ = $lid:bslen$ then
426 Bitmatch.construct_bitstring $lid:buffer$ $lid:bs$
428 raise (Bitmatch.Construct_failure
429 ("length of bitstring does not match declaration",
431 $int:loc_line$, $int:loc_char$))
433 raise (Bitmatch.Construct_failure
434 ("length of bitstring must be > 0",
436 $int:loc_line$, $int:loc_char$))
441 (* Create the final bitstring. Start by creating an empty buffer
442 * and then evaluate each expression above in turn which will
443 * append some more to the bitstring buffer. Finally extract
446 * XXX We almost have enough information to be able to guess
447 * a good initial size for the buffer.
451 | [] -> <:expr< [] >>
452 | h::t -> List.fold_left (fun h t -> <:expr< $h$; $t$ >>) h t in
456 let $lid:buffer$ = Bitmatch.Buffer.create () in
458 Bitmatch.Buffer.contents $lid:buffer$
464 Bitmatch.Construct_failure ("value out of range",
466 $int:loc_line$, $int:loc_char$) in
472 (* Generate the code for a bitmatch statement. '_loc' is the
473 * location, 'bs' is the bitstring parameter, 'cases' are
474 * the list of cases to test against.
476 let output_bitmatch _loc bs cases =
477 let data = gensym "data" and off = gensym "off" and len = gensym "len" in
478 let result = gensym "result" in
480 (* This generates the field extraction code for each
481 * field a single case. Each field must be wider than
482 * the minimum permitted for the type and there must be
483 * enough remaining data in the bitstring to satisfy it.
484 * As we go through the fields, symbols 'data', 'off' and 'len'
485 * track our position and remaining length in the bitstring.
487 * The whole thing is a lot of nested 'if' statements. Code
488 * is generated from the inner-most (last) field outwards.
490 let rec output_field_extraction inner = function
493 let fpatt = P.get_patt field in
494 let flen = P.get_length field in
495 let endian = P.get_endian field in
496 let signed = P.get_signed field in
497 let t = P.get_type field in
498 let _loc = P.get_location field in
500 (* Is flen an integer constant? If so, what is it? This
501 * is very simple-minded and only detects simple constants.
503 let flen_is_const = expr_is_constant flen in
505 let int_extract_const = function
506 (* XXX The meaning of signed/unsigned breaks down at
507 * 31, 32, 63 and 64 bits.
510 <:expr<Bitmatch.extract_bit>>
511 | ((2|3|4|5|6|7|8), _, false) ->
512 <:expr<Bitmatch.extract_char_unsigned>>
513 | ((2|3|4|5|6|7|8), _, true) ->
514 <:expr<Bitmatch.extract_char_signed>>
515 | (i, P.ConstantEndian BigEndian, false) when i <= 31 ->
516 <:expr<Bitmatch.extract_int_be_unsigned>>
517 | (i, P.ConstantEndian BigEndian, true) when i <= 31 ->
518 <:expr<Bitmatch.extract_int_be_signed>>
519 | (i, P.ConstantEndian LittleEndian, false) when i <= 31 ->
520 <:expr<Bitmatch.extract_int_le_unsigned>>
521 | (i, P.ConstantEndian LittleEndian, true) when i <= 31 ->
522 <:expr<Bitmatch.extract_int_le_signed>>
523 | (i, P.ConstantEndian NativeEndian, false) when i <= 31 ->
524 <:expr<Bitmatch.extract_int_ne_unsigned>>
525 | (i, P.ConstantEndian NativeEndian, true) when i <= 31 ->
526 <:expr<Bitmatch.extract_int_ne_signed>>
527 | (i, P.EndianExpr expr, false) when i <= 31 ->
528 <:expr<Bitmatch.extract_int_ee_unsigned $expr$>>
529 | (i, P.EndianExpr expr, true) when i <= 31 ->
530 <:expr<Bitmatch.extract_int_ee_signed $expr$>>
531 | (32, P.ConstantEndian BigEndian, false) ->
532 <:expr<Bitmatch.extract_int32_be_unsigned>>
533 | (32, P.ConstantEndian BigEndian, true) ->
534 <:expr<Bitmatch.extract_int32_be_signed>>
535 | (32, P.ConstantEndian LittleEndian, false) ->
536 <:expr<Bitmatch.extract_int32_le_unsigned>>
537 | (32, P.ConstantEndian LittleEndian, true) ->
538 <:expr<Bitmatch.extract_int32_le_signed>>
539 | (32, P.ConstantEndian NativeEndian, false) ->
540 <:expr<Bitmatch.extract_int32_ne_unsigned>>
541 | (32, P.ConstantEndian NativeEndian, true) ->
542 <:expr<Bitmatch.extract_int32_ne_signed>>
543 | (32, P.EndianExpr expr, false) ->
544 <:expr<Bitmatch.extract_int32_ee_unsigned $expr$>>
545 | (32, P.EndianExpr expr, true) ->
546 <:expr<Bitmatch.extract_int32_ee_signed $expr$>>
547 | (_, P.ConstantEndian BigEndian, false) ->
548 <:expr<Bitmatch.extract_int64_be_unsigned>>
549 | (_, P.ConstantEndian BigEndian, true) ->
550 <:expr<Bitmatch.extract_int64_be_signed>>
551 | (_, P.ConstantEndian LittleEndian, false) ->
552 <:expr<Bitmatch.extract_int64_le_unsigned>>
553 | (_, P.ConstantEndian LittleEndian, true) ->
554 <:expr<Bitmatch.extract_int64_le_signed>>
555 | (_, P.ConstantEndian NativeEndian, false) ->
556 <:expr<Bitmatch.extract_int64_ne_unsigned>>
557 | (_, P.ConstantEndian NativeEndian, true) ->
558 <:expr<Bitmatch.extract_int64_ne_signed>>
559 | (_, P.EndianExpr expr, false) ->
560 <:expr<Bitmatch.extract_int64_ee_unsigned $expr$>>
561 | (_, P.EndianExpr expr, true) ->
562 <:expr<Bitmatch.extract_int64_ee_signed $expr$>>
564 let int_extract = function
565 | (P.ConstantEndian BigEndian, false) ->
566 <:expr<Bitmatch.extract_int64_be_unsigned>>
567 | (P.ConstantEndian BigEndian, true) ->
568 <:expr<Bitmatch.extract_int64_be_signed>>
569 | (P.ConstantEndian LittleEndian, false) ->
570 <:expr<Bitmatch.extract_int64_le_unsigned>>
571 | (P.ConstantEndian LittleEndian, true) ->
572 <:expr<Bitmatch.extract_int64_le_signed>>
573 | (P.ConstantEndian NativeEndian, false) ->
574 <:expr<Bitmatch.extract_int64_ne_unsigned>>
575 | (P.ConstantEndian NativeEndian, true) ->
576 <:expr<Bitmatch.extract_int64_ne_signed>>
577 | (P.EndianExpr expr, false) ->
578 <:expr<Bitmatch.extract_int64_ee_unsigned $expr$>>
579 | (P.EndianExpr expr, true) ->
580 <:expr<Bitmatch.extract_int64_ee_signed $expr$>>
584 match t, flen_is_const with
585 (* Common case: int field, constant flen *)
586 | P.Int, Some i when i > 0 && i <= 64 ->
587 let extract_fn = int_extract_const (i,endian,signed) in
588 let v = gensym "val" in
590 if $lid:len$ >= $`int:i$ then (
591 let $lid:v$, $lid:off$, $lid:len$ =
592 $extract_fn$ $lid:data$ $lid:off$ $lid:len$ $`int:i$ in
593 match $lid:v$ with $fpatt$ when true -> $inner$ | _ -> ()
598 Loc.raise _loc (Failure "length of int field must be [1..64]")
600 (* Int field, non-const flen. We have to test the range of
601 * the field at runtime. If outside the range it's a no-match
605 let extract_fn = int_extract (endian,signed) in
606 let v = gensym "val" in
608 if $flen$ >= 1 && $flen$ <= 64 && $flen$ <= $lid:len$ then (
609 let $lid:v$, $lid:off$, $lid:len$ =
610 $extract_fn$ $lid:data$ $lid:off$ $lid:len$ $flen$ in
611 match $lid:v$ with $fpatt$ when true -> $inner$ | _ -> ()
615 (* String, constant flen > 0. *)
616 | P.String, Some i when i > 0 && i land 7 = 0 ->
617 let bs = gensym "bs" in
619 if $lid:len$ >= $`int:i$ then (
620 let $lid:bs$, $lid:off$, $lid:len$ =
621 Bitmatch.extract_bitstring $lid:data$ $lid:off$ $lid:len$
623 match Bitmatch.string_of_bitstring $lid:bs$ with
624 | $fpatt$ when true -> $inner$
629 (* String, constant flen = -1, means consume all the
632 | P.String, Some i when i = -1 ->
633 let bs = gensym "bs" in
635 let $lid:bs$, $lid:off$, $lid:len$ =
636 Bitmatch.extract_remainder $lid:data$ $lid:off$ $lid:len$ in
637 match Bitmatch.string_of_bitstring $lid:bs$ with
638 | $fpatt$ when true -> $inner$
642 | P.String, Some _ ->
643 Loc.raise _loc (Failure "length of string must be > 0 and a multiple of 8, or the special value -1")
645 (* String field, non-const flen. We check the flen is > 0
646 * and a multiple of 8 (-1 is not allowed here), at runtime.
649 let bs = gensym "bs" in
651 if $flen$ >= 0 && $flen$ <= $lid:len$
652 && $flen$ land 7 = 0 then (
653 let $lid:bs$, $lid:off$, $lid:len$ =
654 Bitmatch.extract_bitstring
655 $lid:data$ $lid:off$ $lid:len$ $flen$ in
656 match Bitmatch.string_of_bitstring $lid:bs$ with
657 | $fpatt$ when true -> $inner$
662 (* Bitstring, constant flen >= 0.
663 * At the moment all we can do is assign the bitstring to an
666 | P.Bitstring, Some i when i >= 0 ->
669 | <:patt< $lid:ident$ >> -> ident
670 | <:patt< _ >> -> "_"
673 (Failure "cannot compare a bitstring to a constant") in
675 if $lid:len$ >= $`int:i$ then (
676 let $lid:ident$, $lid:off$, $lid:len$ =
677 Bitmatch.extract_bitstring $lid:data$ $lid:off$ $lid:len$
683 (* Bitstring, constant flen = -1, means consume all the
686 | P.Bitstring, Some i when i = -1 ->
689 | <:patt< $lid:ident$ >> -> ident
690 | <:patt< _ >> -> "_"
693 (Failure "cannot compare a bitstring to a constant") in
695 let $lid:ident$, $lid:off$, $lid:len$ =
696 Bitmatch.extract_remainder $lid:data$ $lid:off$ $lid:len$ in
700 | P.Bitstring, Some _ ->
701 Loc.raise _loc (Failure "length of bitstring must be >= 0 or the special value -1")
703 (* Bitstring field, non-const flen. We check the flen is >= 0
704 * (-1 is not allowed here) at runtime.
706 | P.Bitstring, None ->
709 | <:patt< $lid:ident$ >> -> ident
710 | <:patt< _ >> -> "_"
713 (Failure "cannot compare a bitstring to a constant") in
715 if $flen$ >= 0 && $flen$ <= $lid:len$ then (
716 let $lid:ident$, $lid:off$, $lid:len$ =
717 Bitmatch.extract_bitstring $lid:data$ $lid:off$ $lid:len$
724 (* Emit extra debugging code. *)
726 if not debug then expr else (
727 let field = P.string_of_field field in
730 if !Bitmatch.debug then (
731 Printf.eprintf "PA_BITMATCH: TEST:\n";
732 Printf.eprintf " %s\n" $str:field$;
733 Printf.eprintf " off %d len %d\n%!" $lid:off$ $lid:len$;
734 (*Bitmatch.hexdump_bitstring stderr
735 ($lid:data$,$lid:off$,$lid:len$);*)
741 output_field_extraction expr fields
744 (* Convert each case in the match. *)
745 let cases = List.map (
746 fun (fields, bind, whenclause, code) ->
747 let inner = <:expr< $lid:result$ := Some ($code$); raise Exit >> in
749 match whenclause with
751 <:expr< if $whenclause$ then $inner$ >>
757 let $lid:name$ = ($lid:data$, $lid:off$, $lid:len$) in
761 output_field_extraction inner (List.rev fields)
764 (* Join them into a single expression.
766 * Don't do it with a normal fold_right because that leaves
767 * 'raise Exit; ()' at the end which causes a compiler warning.
768 * Hence a bit of complexity here.
770 * Note that the number of cases is always >= 1 so List.hd is safe.
772 let cases = List.rev cases in
774 List.fold_left (fun base case -> <:expr< $case$ ; $base$ >>)
775 (List.hd cases) (List.tl cases) in
777 (* The final code just wraps the list of cases in a
778 * try/with construct so that each case is tried in
779 * turn until one case matches (that case sets 'result'
780 * and raises 'Exit' to leave the whole statement).
781 * If result isn't set by the end then we will raise
782 * Match_failure with the location of the bitmatch
783 * statement in the original code.
785 let loc_fname = Loc.file_name _loc in
786 let loc_line = string_of_int (Loc.start_line _loc) in
787 let loc_char = string_of_int (Loc.start_off _loc - Loc.start_bol _loc) in
790 let ($lid:data$, $lid:off$, $lid:len$) = $bs$ in
791 let $lid:result$ = ref None in
795 match ! $lid:result$ with
797 | None -> raise (Match_failure ($str:loc_fname$,
798 $int:loc_line$, $int:loc_char$))
804 (* Qualifiers are a list of identifiers ("string", "bigendian", etc.)
805 * followed by an optional expression (used in certain cases). Note
806 * that we are careful not to declare any explicit reserved words.
811 e = OPT [ "("; e = expr; ")" -> e ] -> (q, e) ]
815 (* Field used in the bitmatch operator (a pattern). *)
817 [ fpatt = patt; ":"; len = expr LEVEL "top";
818 qs = OPT [ ":"; qs = qualifiers -> qs ] ->
819 let field = P.create_pattern_field _loc in
820 let field = P.set_patt field fpatt in
821 let field = P.set_length field len in
822 parse_field _loc field qs
826 (* Case inside bitmatch operator. *)
829 fields = LIST0 patt_field SEP ";";
831 bind = OPT [ "as"; name = LIDENT -> name ];
832 whenclause = OPT [ "when"; e = expr -> e ]; "->";
834 (fields, bind, whenclause, code)
838 (* Field used in the BITSTRING constructor (an expression). *)
840 [ fexpr = expr LEVEL "top"; ":"; len = expr LEVEL "top";
841 qs = OPT [ ":"; qs = qualifiers -> qs ] ->
842 let field = P.create_constructor_field _loc in
843 let field = P.set_expr field fexpr in
844 let field = P.set_length field len in
845 parse_field _loc field qs
849 (* 'bitmatch' expressions. *)
852 bs = expr; "with"; OPT "|";
853 cases = LIST1 match_case SEP "|" ->
854 output_bitmatch _loc bs cases
858 | [ "BITSTRING"; "{";
859 fields = LIST0 constr_field SEP ";";
861 output_constructor _loc fields