pax_global_header00006660000000000000000000000064137617134020014516gustar00rootroot0000000000000052 comment=4a4f08e08a9be78db9dd38821e80318cbe47dd96 parsexp-0.14.1/000077500000000000000000000000001376171340200132635ustar00rootroot00000000000000parsexp-0.14.1/.gitignore000066400000000000000000000000411376171340200152460ustar00rootroot00000000000000_build *.install *.merlin _opam parsexp-0.14.1/CHANGES.md000066400000000000000000000000741376171340200146560ustar00rootroot00000000000000# v0.11 Drop dependency on Base. # v0.10 Initial release parsexp-0.14.1/CONTRIBUTING.md000066400000000000000000000044101376171340200155130ustar00rootroot00000000000000This repository contains open source software that is developed and maintained by [Jane Street][js]. Contributions to this project are welcome and should be submitted via GitHub pull requests. Signing contributions --------------------- We require that you sign your contributions. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below (from [developercertificate.org][dco]): ``` Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1 Letterman Drive Suite D4700 San Francisco, CA, 94129 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` Then you just add a line to every git commit message: ``` Signed-off-by: Joe Smith ``` Use your real name (sorry, no pseudonyms or anonymous contributions.) If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with git commit -s. [dco]: http://developercertificate.org/ [js]: https://opensource.janestreet.com/ parsexp-0.14.1/LICENSE.md000066400000000000000000000021351376171340200146700ustar00rootroot00000000000000The MIT License Copyright (c) 2016--2020 Jane Street Group, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. parsexp-0.14.1/Makefile000066400000000000000000000004031376171340200147200ustar00rootroot00000000000000INSTALL_ARGS := $(if $(PREFIX),--prefix $(PREFIX),) default: dune build install: dune install $(INSTALL_ARGS) uninstall: dune uninstall $(INSTALL_ARGS) reinstall: uninstall install clean: dune clean .PHONY: default install uninstall reinstall clean parsexp-0.14.1/README.org000066400000000000000000000121721376171340200147340ustar00rootroot00000000000000* Parsexp - S-expression parser =Parsexp= contains functionality for parsing s-expressions, which are defined in the [[https://github.com/janestreet/base][Base]] library as follows: #+begin_src ocaml module Sexp : sig type t = Atom of string | List of t list end #+end_src =Parsexp= is platform independent and as such doesn't provide IO operations. The companion library [[https://github.com/janestreet/parsexp_io][Parsexp_io]] provides facilities for loading s-expressions from files. ** Syntax of s-expression *** Lexical conventions of s-expression Whitespace, which consists of space, newline, horizontal tab, and form feed, is ignored unless within an OCaml-string, where it is treated according to OCaml-conventions. The left parenthesis opens a new list, the right one closes it. Lists can be empty. The double quote denotes the beginning and end of a string using similar lexing conventions to the ones of OCaml (see the [[http://caml.inria.fr/pub/docs/manual-ocaml/][OCaml-manual]] for details). Differences are: - octal escape sequences (=\o123=) are not supported by parsexp - backslash that's not a part of any escape sequence is kept as it is instead of resulting in parse error - a backslash followed by a space does not form an escape sequence, so it's interpreted as is, while it is interpreted as just a space by OCaml All characters other than double quotes, left- and right parentheses, whitespace, carriage return, and comment-introducing characters or sequences (see next paragraph) are considered part of a contiguous string. *** Comments There are three kinds of comments: - _line comments_ are introduced with =;=, and end at the newline. - _sexp comments_ are introduced with =#;=, and end at the end of the following s-expression - _block comments_ are introduced with =#|= and end with =|#=. These can be nested, and double-quotes within them must be balanced and be lexically correct OCaml strings. *** Grammar of s-expressions s-expressions are either strings (= atoms) or lists. The lists can recursively contain further s-expressions or be empty, and must be balanced, /i.e./ parentheses must match. *** Examples #+begin_src scheme this_is_an_atom_123'&^%! ; this is a comment "another atom in an OCaml-string \"string in a string\" \123" ; empty list follows below () ; a more complex example ( ( list in a list ; comment within a list (list in a list in a list) 42 is the answer to all questions #; (this S-expression (has been commented out) ) #| Block comments #| can be "nested" |# |# ) ) #+end_src ** API =Parsexp= offers a few different parsers. Each of them comes in 3 variants: 1. =single=, for parsing a source expected to contain a single s-expression. Zero or more than 1 s-expressions is considered an error and reported as such. 2. =many=, for parsing a source expected to contain multiple s-expressions, returned as a list 3. =eager=, for reporting s-expressions to the user as soon as they are found in the input source Parsers all implement the same API. For each parsers, =Parsexp= offers a low-level API, where one feeds characters one-by-one to the parser, as well as a convenience functions to parse a whole string. *** Low-level API With the low-level API, ones must create a parser state and feed it characters one by one. This allows =Parsexp= to be used with any kind of input as well as to be =Lwt= or =Async= friendly. Essentially, if you want to parse from a different input source, you have to write the fetch-character-feed-to-parser loop yourself. *** Parsers =Parsexp= offers the following parsers: - _normal parsers_ returning values of type =Sexp.t= - _with positions_ returning s-expressions as well as a set of positions (see next section) - _just positions_ returning only a set of positions - _CST_ return a concrete syntax tree, including all comment and locations In addition, it provides convenience functions for parsing strings and converting the result with a =Sexp.t -> 'a= function, reporting errors with accurate locations. Each parsing/conversion functions comes in two variants: one raising exception in case of error and one returning a =Result.t= value. In general you should use the latter since parsing is an operation that can always fail. *** Positions sets and error reporting To deal with error locations when converting S-expressions to OCaml values, =Parsexp= introduces the notion of compact positions sets. A positions set represents positions in the input source of all s-expressions. It has a small memory footprint and is relatively cheap to construct. Using a positions set and the corresponding s-expression, one can reconstruct the location of any sub s-expressions in the input source. Depending on the input source, one can either: - parse a first time without recording positions and parse a second time only producing positions in case of error - parse only once producing both the s-expressions and the positions sets The first method has the advantage that it is faster where there are no errors, however it is not suitable for sources that can't guarantee repeatable reads such as files. parsexp-0.14.1/bench/000077500000000000000000000000001376171340200143425ustar00rootroot00000000000000parsexp-0.14.1/bench/dune000066400000000000000000000001721376171340200152200ustar00rootroot00000000000000(library (name parsexp_bench) (libraries core_kernel.caml_unix core_kernel parsexp sexplib) (preprocess (pps ppx_jane)))parsexp-0.14.1/bench/parsexp_vs_sexplib.ml000066400000000000000000000027011376171340200206140ustar00rootroot00000000000000open Core_kernel open Poly module Unix = Caml_unix let data = let data_fn = "data.sexp" in if Sys.file_exists data_fn then sprintf "(%s)" (In_channel.read_all data_fn) else ( (* Collect all the jbuilds in ${ROOT}/lib *) let ic = Unix.open_process_in "find ../../../lib -name jbuild -exec cat {} \\;" in let s = In_channel.input_all ic in assert (Unix.close_process_in ic = WEXITED 0); sprintf "(%s)" s) ;; (* To make sure the input is valid before starting the bench *) let (_ : Sexp.t) = Sexplib.Sexp.of_string data let _, positions = Parsexp.Single_and_positions.parse_string_exn data let () = let pos_mem_kb = Parsexp.Positions.memory_footprint_in_bytes positions / 1024 in printf "input size: %d KB\nposition set size: %d KB (%d KW)\n%!" (String.length data / 1024) pos_mem_kb (pos_mem_kb / match Word_size.word_size with | W32 -> 4 | W64 -> 8) ;; (* Obj.tag is a C call so the compiler can't consider the value as dead-code *) let don't_optimize_out x = ignore (Obj.tag (Obj.repr x) : int) let%bench "sexplib" = don't_optimize_out (Sexplib.Sexp.of_string data : Sexp.t) let%bench "sexplib.annotated" = don't_optimize_out (Sexplib.Sexp.Annotated.of_string data : Sexp.Annotated.t) ;; let%bench "parsexp" = don't_optimize_out (Parsexp.Single.parse_string_exn data : Sexp.t) let%bench "parsexp+positions" = don't_optimize_out (Parsexp.Single_and_positions.parse_string_exn data : _ * _) ;; parsexp-0.14.1/bench/parsexp_vs_sexplib.mli000066400000000000000000000000551376171340200207650ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/dune-project000066400000000000000000000000201376171340200155750ustar00rootroot00000000000000(lang dune 1.10)parsexp-0.14.1/fuzz/000077500000000000000000000000001376171340200142615ustar00rootroot00000000000000parsexp-0.14.1/fuzz/dune000066400000000000000000000002431376171340200151360ustar00rootroot00000000000000(executables (names parser_equivalence) (libraries aflPersistent base parsexp parsexp_test sexplib stdio) (preprocess (pps ppx_jane -allow-unannotated-ignores)))parsexp-0.14.1/fuzz/parser_equivalence.ml000066400000000000000000000231071376171340200204730ustar00rootroot00000000000000(* About this file: It checks the equivalence of the various parsexp parsers, as well some sexplib parsers. This check is manual, it is not run in hydra in any way. This requires instrumentation, so I build my own compiler like so: # ./configure -prefix $PWD/installed -afl-instrument && make world world.opt install Without a custom compiler, the stdlib will not be instrumented. The way I run it: {v function fuzz-run { ( mkdir -p input echo a > input/testcase rm -rf output/min-* shopt -s nullglob export AFL_SKIP_CPUFREQ= for prop in {0..14}; do export PROP=$prop timeout 2m afl-fuzz -i input -o output ./parser_equivalence.exe mkdir -p output/min-$prop for f in output/crashes/id\:*; do afl-tmin -i $f -o output/min-$prop/$(basename $f) -- ./parser_equivalence.exe done done ) } function fuzz-result { ( shopt -s nullglob for v in output/min-*; do prop=$(echo $(basename $v) | cut -d - -f 2-) for f in $(md5sum output/min-$prop/* | sort -u | awk '{ tbl[$1] = $2 } END { for (k in tbl) { print tbl[k] } }' | sort | grep -v '^-$'); do echo --- prop:$prop PROP=$prop NICE_EXN= ./parser_equivalence.exe < $f done done ) < /dev/null |& less -R } v} This is needed because the cli of afl-fuzz is wonky. Run fuzz-run to actually run tests. Run fuzz-result either during the tests or after to see the failures so far. *) open Base module P = Parsexp let compare_exn _ _ = 0 type 'a or_exn = ('a, exn) Result.t [@@deriving compare, sexp_of] let parsexp_single str = Result.try_with (fun () -> P.Single.parse_string_exn str) let parsexp_many str = Result.try_with (fun () -> P.Many.parse_string_exn str) let parsexp_eager str ~no_sexp_is_error = let r = ref [] in let state = P.Eager.State.create ~no_sexp_is_error (fun _ v -> r := v :: !r) in Result.try_with (fun () -> let stack = P.Eager.Stack.empty in let stack = P.Eager.feed_string state str stack in P.Eager.feed_eoi state stack; List.rev !r) ;; let parsexp_single_and_positions str = Result.try_with (fun () -> P.Single_and_positions.parse_string_exn str) ;; let parsexp_many_and_positions str = Result.try_with (fun () -> P.Many_and_positions.parse_string_exn str) ;; let parsexp_eager_and_positions str = let r = ref [] in let state = P.Eager_and_positions.State.create ~no_sexp_is_error:false (fun _ v -> r := v :: !r) in Result.try_with (fun () -> let stack = P.Eager_and_positions.Stack.empty in let stack = P.Eager_and_positions.feed_string state str stack in P.Eager_and_positions.feed_eoi state stack; List.rev !r) ;; let parsexp_single_just_positions str = Result.try_with (fun () -> P.Single_just_positions.parse_string_exn str) ;; let parsexp_many_just_positions str = Result.try_with (fun () -> P.Many_just_positions.parse_string_exn str) ;; let parsexp_eager_just_positions str = let r = ref [] in let state = P.Eager_just_positions.State.create ~no_sexp_is_error:false (fun _ v -> r := v :: !r) in Result.try_with (fun () -> let stack = P.Eager_just_positions.Stack.empty in let stack = P.Eager_just_positions.feed_string state str stack in P.Eager_just_positions.feed_eoi state stack; List.rev !r) ;; let parsexp_many_cst str = Result.try_with (fun () -> P.Many_cst.parse_string_exn str) let parsexp_eager_cst str = let r = ref [] in let state = P.Eager_cst.State.create ~no_sexp_is_error:false (fun _ v -> r := v :: !r) in Result.try_with (fun () -> let stack = P.Eager_cst.Stack.empty in let stack = P.Eager_cst.feed_string state str stack in P.Eager_cst.feed_eoi state stack; List.rev !r) ;; let sexplib_single str = Result.try_with (fun () -> Sexplib.Sexp.of_string str) let sexplib_many str = Result.try_with (fun () -> Parsexp_test.Import.sexplib_sexps_of_string str) ;; let single_of_many = function | Ok [ x ] -> Ok x | Ok _ -> Error (Failure "not single") | Error _ as e -> e ;; let fst_or_error = function | Ok p -> Ok (fst p) | Error _ as e -> e ;; let snd_or_error = function | Ok p -> Ok (snd p) | Error _ as e -> e ;; let main ~nice_exn ~property = let buf = Buffer.create 100000 in AflPersistent.run (fun () -> let str = ignore (Stdio.In_channel.input_buffer Stdio.In_channel.stdin buf ~len:100000); let str = Buffer.contents buf in Buffer.reset buf; str in let equal_or_raise (type a) sexp_of_a compare_a name1 name2 v1 v2 = if [%compare: a or_exn] v1 v2 <> 0 then if nice_exn then raise_s [%sexp (str : string) , ((name1 : string), (v1 : a or_exn)) , ((name2 : string), (v2 : a or_exn))] else Caml.raise_notrace Caml.Exit in match property with | 0 -> equal_or_raise [%sexp_of: Sexp.t] [%compare: Sexp.t] "parsexp_single" "parsexp_many" (parsexp_single str) (single_of_many (parsexp_many str)) | 1 -> equal_or_raise [%sexp_of: Sexp.t list] [%compare: Sexp.t list] "parsexp_many" "parsexp_eager_no_sexp_is_error:false" (parsexp_many str) (parsexp_eager str ~no_sexp_is_error:false) | 2 -> equal_or_raise [%sexp_of: Sexp.t list] [%compare: Sexp.t list] "parsexp_many" "parsexp_eager_no_sexp_is_error:true" (match parsexp_many str with | Ok [] -> Error (Failure "empty") | x -> x) (parsexp_eager str ~no_sexp_is_error:true) | 3 -> equal_or_raise [%sexp_of: Sexp.t] [%compare: Sexp.t] "parsexp_single" "parsexp_single_and_positions" (parsexp_single str) (fst_or_error (parsexp_single_and_positions str)) | 4 -> equal_or_raise [%sexp_of: Sexp.t list] [%compare: Sexp.t list] "parsexp_many" "parsexp_many_and_positions" (parsexp_many str) (fst_or_error (parsexp_many_and_positions str)) | 5 -> equal_or_raise [%sexp_of: Sexp.t list] [%compare: Sexp.t list] "parsexp_many" "parsexp_many_and_positions" (parsexp_many str) (match parsexp_eager_and_positions str with | Ok l -> Ok (List.map l ~f:fst) | Error _ as e -> e) | 6 -> equal_or_raise [%sexp_of: Sexp.t * P.Positions.t] [%compare: Sexp.t * P.Positions.t] "parsexp_single_and_positions" "parsexp_many_and_positions" (parsexp_single_and_positions str) (match parsexp_many_and_positions str with | Ok ([ v ], positions) -> Ok (v, positions) | Error _ as e -> e | Ok (_, _) -> Error (Failure "not many")) | 7 -> equal_or_raise [%sexp_of: P.Positions.t] [%compare: P.Positions.t] "parsexp_single_just_positions" "parsexp_single_and_positions" (parsexp_single_just_positions str) (snd_or_error (parsexp_single_and_positions str)) | 8 -> equal_or_raise [%sexp_of: P.Positions.t] [%compare: P.Positions.t] "parsexp_many_just_positions" "parsexp_many_and_positions" (parsexp_many_just_positions str) (snd_or_error (parsexp_many_and_positions str)) | 9 -> equal_or_raise [%sexp_of: P.Positions.t list] [%compare: P.Positions.t list] "parsexp_eager_just_positions" "parsexp_eager_and_positions" (parsexp_eager_just_positions str) (match parsexp_eager_and_positions str with | Ok l -> Ok (List.map l ~f:snd) | Error _ as e -> e) | 10 -> equal_or_raise [%sexp_of: P.Positions.pos array] [%compare: P.Positions.pos array] "parsexp_many_just_positions" "parsexp_eager_just_positions" (match parsexp_many_just_positions str with | Ok a -> Ok (P.Positions.to_array a) | Error _ as e -> e) (match parsexp_eager_and_positions str with | Ok l -> Ok (Array.concat_map (Array.of_list l) ~f:(fun a -> P.Positions.to_array (snd a))) | Error _ as e -> e) | 11 -> equal_or_raise [%sexp_of: Sexp.t list] [%compare: Sexp.t list] "parsexp_many" "parsexp_many_cst" (parsexp_many str) (match parsexp_many_cst str with | Error _ as e -> e | Ok l -> Ok (P.Cst.Forget.t_or_comments l)) | 12 -> equal_or_raise [%sexp_of: P.Cst.t_or_comment list] [%compare: P.Cst.t_or_comment list] "parsexp_many_cst" "parsexp_eager_cst" (parsexp_many_cst str) (parsexp_eager_cst str) | 13 -> equal_or_raise [%sexp_of: Sexp.t] [%compare: Sexp.t] "parsexp_single" "sexplib_single" (parsexp_single str) (sexplib_single str) | 14 -> equal_or_raise [%sexp_of: Sexp.t list] [%compare: Sexp.t list] "parsexp_many" "sexplib_many" (parsexp_many str) (sexplib_many str) | _ -> raise_s [%sexp "property out of range", (property : int)]) ;; let nice_exn = match Caml.Sys.getenv "NICE_EXN" with | exception (Not_found_s _ | Caml.Not_found) -> false | (_ : string) -> true ;; let property = match Caml.Sys.getenv "PROP" with | exception (Not_found_s _ | Caml.Not_found) -> assert false | s -> Int.of_string s ;; let () = main ~nice_exn ~property parsexp-0.14.1/fuzz/parser_equivalence.mli000066400000000000000000000000551376171340200206410ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/parsexp.opam000066400000000000000000000027671376171340200156370ustar00rootroot00000000000000opam-version: "2.0" version: "v0.14.0" maintainer: "opensource@janestreet.com" authors: ["Jane Street Group, LLC "] homepage: "https://github.com/janestreet/parsexp" bug-reports: "https://github.com/janestreet/parsexp/issues" dev-repo: "git+https://github.com/janestreet/parsexp.git" doc: "https://ocaml.janestreet.com/ocaml-core/latest/doc/parsexp/index.html" license: "MIT" build: [ ["dune" "build" "-p" name "-j" jobs] ] depends: [ "ocaml" {>= "4.04.2"} "base" {>= "v0.14" & < "v0.15"} "sexplib0" {>= "v0.14" & < "v0.15"} "dune" {>= "2.0.0"} ] synopsis: "S-expression parsing library" description: " This library provides generic parsers for parsing S-expressions from strings or other medium. The library is focused on performances but still provide full generic parsers that can be used with strings, bigstrings, lexing buffers, character streams or any other sources effortlessly. It provides three different class of parsers: - the normal parsers, producing [Sexp.t] or [Sexp.t list] values - the parsers with positions, building compact position sequences so that one can recover original positions in order to report properly located errors at little cost - the Concrete Syntax Tree parsers, produce values of type [Parsexp.Cst.t] which record the concrete layout of the s-expression syntax, including comments This library is portable and doesn't provide IO functions. To read s-expressions from files or other external sources, you should use parsexp_io. " parsexp-0.14.1/src/000077500000000000000000000000001376171340200140525ustar00rootroot00000000000000parsexp-0.14.1/src/automaton_helpers.ml000066400000000000000000000022111376171340200201310ustar00rootroot00000000000000open! Import let rec feed_substring_unsafe str state stack i stop = if i < stop then ( let c = String.unsafe_get str i in let stack = Parser_automaton.feed state c stack in feed_substring_unsafe str state stack (i + 1) stop) else stack ;; let rec feed_subbytes_unsafe str state stack i stop = if i < stop then ( let c = Bytes.unsafe_get str i in let stack = Parser_automaton.feed state c stack in feed_subbytes_unsafe str state stack (i + 1) stop) else stack ;; let feed_substring state str ~pos ~len stack = let str_len = String.length str in if pos < 0 || len < 0 || pos > str_len - len then invalid_arg "Parsexp.feed_substring"; feed_substring_unsafe str state stack pos (pos + len) ;; let feed_subbytes state str ~pos ~len stack = let str_len = Bytes.length str in if pos < 0 || len < 0 || pos > str_len - len then invalid_arg "Parsexp.feed_subbytes"; feed_subbytes_unsafe str state stack pos (pos + len) ;; let feed_string state str stack = feed_substring_unsafe str state stack 0 (String.length str) ;; let feed_bytes state str stack = feed_subbytes_unsafe str state stack 0 (Bytes.length str) ;; parsexp-0.14.1/src/automaton_helpers.mli000066400000000000000000000000611376171340200203030ustar00rootroot00000000000000include Automaton_helpers_intf.Automaton_helpers parsexp-0.14.1/src/automaton_helpers_intf.ml000066400000000000000000000010451376171340200211550ustar00rootroot00000000000000(** Convenience functions for feeding the automaton. *) open! Import module type Automaton_helpers = sig val feed_bytes : (_, 'stack) Parser_automaton.state -> bytes -> 'stack -> 'stack val feed_string : (_, 'stack) Parser_automaton.state -> string -> 'stack -> 'stack val feed_subbytes : (_, 'stack) Parser_automaton.state -> bytes -> pos:int -> len:int -> 'stack -> 'stack val feed_substring : (_, 'stack) Parser_automaton.state -> string -> pos:int -> len:int -> 'stack -> 'stack end parsexp-0.14.1/src/automaton_stack.ml000066400000000000000000000020211376171340200175730ustar00rootroot00000000000000open! Import include Automaton_stack_intf module For_cst = struct type t = | Empty | T_or_comment of Cst.t_or_comment * t | Open of Positions.pos * t | In_sexp_comment of { hash_semi_pos : Positions.pos ; rev_comments : Cst.comment list ; stack : t } let empty = Empty let get_many = let rec loop acc = function | Empty -> acc | T_or_comment (t, stack) -> loop (t :: acc) stack | Open _ | In_sexp_comment _ -> failwith "Automaton_stack.For_cst.get_many" in fun stack -> loop [] stack ;; end module Just_positions = struct type t = unit let empty = () end type t = | Empty | Open of t | Sexp of Sexp.t * t let empty = Empty let get_single = function | Sexp (sexp, Empty) -> sexp | _ -> failwith "Automaton_stack.get_single" ;; let get_many = let rec loop acc = function | Empty -> acc | Open _ -> failwith "Automaton_stack.get_many" | Sexp (sexp, stack) -> loop (sexp :: acc) stack in fun stack -> loop [] stack ;; parsexp-0.14.1/src/automaton_stack.mli000066400000000000000000000000551376171340200177510ustar00rootroot00000000000000include Automaton_stack_intf.Automaton_stack parsexp-0.14.1/src/automaton_stack_intf.ml000066400000000000000000000026621376171340200206260ustar00rootroot00000000000000open! Import (** Automaton stack represents a prefix of a sexp (or of a sexp sequence) while it's being parsed. We have three different types of the stack depending on how much detail about the sexp structure is being recorded (just the sexp, sexp with comments and positions (CST), or just positions. *) module type Automaton_stack = sig module For_cst : sig type t = | Empty (** at top-level *) | T_or_comment of Cst.t_or_comment * t (** after the given sexp or comment *) | Open of Positions.pos * t (** after the opening paren *) | In_sexp_comment of { hash_semi_pos : Positions.pos ; rev_comments : Cst.comment list ; stack : t } (** [In_sexp_comment] only indicates if the next s-expression is to be commented out, but if we are nested below parens below an sexp comment, the stack would look like [Open (.., In_sexp_comment ..)]. *) val empty : t (** Raises if [t] contains a partial sexp. *) val get_many : t -> Cst.t_or_comment list end (** The recorded positions are stored elsewhere *) module Just_positions : sig type t = unit val empty : t end type t = | Empty | Open of t | Sexp of Sexp.t * t val empty : t (** Raises if [t] is not exactly one complete sexp. *) val get_single : t -> Sexp.t (** Raises if [t] contains a partial sexp. *) val get_many : t -> Sexp.t list end parsexp-0.14.1/src/cinaps/000077500000000000000000000000001376171340200153275ustar00rootroot00000000000000parsexp-0.14.1/src/cinaps/dune000066400000000000000000000001531376171340200162040ustar00rootroot00000000000000(library (name parsexp_cinaps_helpers) (libraries base stdio gen_parsexp_lib) (preprocess (pps ppx_jane)))parsexp-0.14.1/src/cinaps/gen_parser_automaton.ml000066400000000000000000000074111376171340200221000ustar00rootroot00000000000000(* Parsing of S-expression. The parsing is written as an automaton for which we provide different implementations of actions. *) open! Base open! Import (* Sharing of transitions *) module Sharing = struct let create_assign_id () = let cache = Hashtbl.Poly.create () in ( cache , fun x -> if not (Hashtbl.mem cache x) then Hashtbl.add_exn cache ~key:x ~data:(Hashtbl.length cache) ) ;; let share (table : Automaton.Table.t) = let transitions, assign_transition_id = create_assign_id () in let transitions_eoi, assign_transition_eoi_id = create_assign_id () in Array.iter table.transitions ~f:assign_transition_id; Array.iter table.transitions_eoi ~f:assign_transition_eoi_id; transitions, transitions_eoi ;; end let pr fmt = Printf.ksprintf Stdio.print_endline fmt let ordered_ids tbl = Hashtbl.fold tbl ~init:[] ~f:(fun ~key:x ~data:id acc -> (id, x) :: acc) |> List.sort ~compare:(fun (id1, _) (id2, _) -> compare id1 id2) ;; let print_named_transition (id, tr) = match (tr : Automaton.Table.transition Automaton.Table.or_error) with | Error error -> pr "let tr_%02d _state _char _stack =" id; pr " raise _state ~at_eof:false %s" (Automaton.Error.to_string error) | Ok { action = eps_actions, action; goto; advance } -> let eps_actions = List.filter_map ~f:Automaton.Epsilon_action.to_runtime_function eps_actions in let action = Automaton.Action.to_runtime_function action in pr "let tr_%02d state %schar stack =" id (if Option.is_none action && not ([%compare.equal: Automaton.Table.goto_state] goto End_block_comment) then "_" else ""); List.iter eps_actions ~f:(pr " let stack = %s state stack in"); (match action with | None -> () | Some s -> pr " let stack = %s state char stack in" s); (match goto with | State n -> pr " set_automaton_state state %d;" n | End_block_comment -> pr " let stack = end_block_comment state char stack in"; pr " set_automaton_state state (if block_comment_depth state <> 0 then %d else %d);" (Automaton.State.to_int (Block_comment Normal)) (Automaton.State.to_int Whitespace)); pr " %s state;" (match advance with | Advance -> "advance" | Advance_eol -> "advance_eol"); pr " stack" ;; let print_named_transition_eoi (id, tr) = match (tr : Automaton.Epsilon_action.t list Automaton.Table.or_error) with | Error error -> pr "let tr_eoi_%02d state _stack =" id; pr " raise state ~at_eof:true %s" (Automaton.Error.to_string error) | Ok eps_actions -> pr "let tr_eoi_%02d state stack =" id; let eps_actions = List.filter_map eps_actions ~f:Automaton.Epsilon_action.to_runtime_function in List.iter eps_actions ~f:(pr " let stack = %s state stack in"); pr " eps_eoi_check state stack" ;; let print_table suffix tbl ids = Array.map tbl ~f:(fun tr -> Printf.sprintf "tr%s_%02d" suffix (Hashtbl.find_exn ids tr)) |> Array.to_list |> String.concat ~sep:";" |> Stdio.printf "let transitions%s = [| %s |]" suffix ;; let print_old_parser_approx_cont_states () = List.map Automaton.State.all ~f:Automaton.State.old_parser_approx_cont_state |> String.concat ~sep:";" |> Stdio.printf "let old_parser_approx_cont_states : Old_parser_cont_state.t array = [| %s |]" ;; let print_code () = let named_transitions, named_transitions_eoi = Sharing.share Automaton.table in List.iter (ordered_ids named_transitions) ~f:print_named_transition; List.iter (ordered_ids named_transitions_eoi) ~f:print_named_transition_eoi; print_table "" Automaton.table.transitions named_transitions; print_table "_eoi" Automaton.table.transitions_eoi named_transitions_eoi; print_old_parser_approx_cont_states () ;; parsexp-0.14.1/src/cinaps/gen_parser_automaton.mli000066400000000000000000000000671376171340200222510ustar00rootroot00000000000000open! Base open! Import val print_code : unit -> unit parsexp-0.14.1/src/cinaps/import.ml000066400000000000000000000000301376171340200171640ustar00rootroot00000000000000include Gen_parsexp_lib parsexp-0.14.1/src/cinaps/parsexp_cinaps_helpers.ml000066400000000000000000000000631376171340200224210ustar00rootroot00000000000000module Gen_parser_automaton = Gen_parser_automaton parsexp-0.14.1/src/conv.ml000066400000000000000000000027511376171340200153560ustar00rootroot00000000000000open! Import include Conv_intf module Make (Mode : Mode) (Sexp_parser : Parser.S with type parsed_value = Mode.parsed_sexp) (Positions_parser : Parser.S with type parsed_value = Positions.t) = struct let reraise positions parsed_value ~sub user_exn = let location = Mode.find positions parsed_value ~sub in Of_sexp_error.raise ~user_exn ~sub_sexp:sub ~location ;; let parse_string_exn str f = let parsed_value = Sexp_parser.parse_string_exn str in match Mode.apply_f parsed_value ~f with | x -> x | exception Sexp.Of_sexp_error (exn, sub) -> let positions = Positions_parser.parse_string_exn str in reraise positions parsed_value exn ~sub ;; let parse_string str f : (_, Conv_error.t) result = match parse_string_exn str f with | x -> Ok x | exception Parse_error.Parse_error e -> Error (Parse_error e) | exception Of_sexp_error.Of_sexp_error e -> Error (Of_sexp_error e) ;; let conv_exn (parsed_value, positions) f = match Mode.apply_f parsed_value ~f with | x -> x | exception Sexp.Of_sexp_error (exn, sub) -> reraise positions parsed_value exn ~sub ;; let conv x f = match conv_exn x f with | x -> Ok x | exception Of_sexp_error.Of_sexp_error e -> Error e ;; let conv_combine result f : (_, Conv_error.t) result = match result with | Error e -> Error (Parse_error e) | Ok x -> (match conv x f with | Ok _ as r -> r | Error e -> Error (Of_sexp_error e)) ;; end parsexp-0.14.1/src/conv.mli000066400000000000000000000000461376171340200155220ustar00rootroot00000000000000include Conv_intf.Conv (** @inline *) parsexp-0.14.1/src/conv_error.ml000066400000000000000000000012421376171340200165610ustar00rootroot00000000000000open! Import type t = | Parse_error of Parse_error.t | Of_sexp_error of Of_sexp_error.t [@@deriving_inline sexp_of] let sexp_of_t = (function | Parse_error v0 -> let v0 = Parse_error.sexp_of_t v0 in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "Parse_error"; v0 ] | Of_sexp_error v0 -> let v0 = Of_sexp_error.sexp_of_t v0 in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "Of_sexp_error"; v0 ] : t -> Ppx_sexp_conv_lib.Sexp.t) ;; [@@@end] let report ppf ~filename t = match t with | Parse_error e -> Parse_error.report ppf ~filename e | Of_sexp_error e -> Of_sexp_error.report ppf ~filename e ;; parsexp-0.14.1/src/conv_error.mli000066400000000000000000000005361376171340200167370ustar00rootroot00000000000000open! Import type t = | Parse_error of Parse_error.t | Of_sexp_error of Of_sexp_error.t [@@deriving_inline sexp_of] include sig [@@@ocaml.warning "-32"] val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t end [@@ocaml.doc "@inline"] [@@@end] (** Similar to [Parse_error.report] *) val report : Format.formatter -> filename:string -> t -> unit parsexp-0.14.1/src/conv_intf.ml000066400000000000000000000031771376171340200164010ustar00rootroot00000000000000open! Import module type S = sig type 'a res type chunk_to_conv type parsed_sexp val parse_string : string -> (chunk_to_conv -> 'a) -> ('a res, Conv_error.t) result val parse_string_exn : string -> (chunk_to_conv -> 'a) -> 'a res val conv : parsed_sexp * Positions.t -> (chunk_to_conv -> 'a) -> ('a res, Of_sexp_error.t) result val conv_exn : parsed_sexp * Positions.t -> (chunk_to_conv -> 'a) -> 'a res (** Convenience function for merging parsing and conversion errors. For instance if you have a [load] function as follow: {[ val load : string -> (Sexp.t list * Positions.t, Parse_error.t) result ]} then you can create a [load_conv] function as follow: {[ let load_conv : string -> (Sexp.t -> 'a) -> ('a list, Conv_error.t) result = fun filename f -> conv_combine (load filename) f ]} *) val conv_combine : (parsed_sexp * Positions.t, Parse_error.t) result -> (chunk_to_conv -> 'a) -> ('a res, Conv_error.t) result end module type Mode = sig type parsed_sexp type 'a res type chunk_to_conv val apply_f : parsed_sexp -> f:(chunk_to_conv -> 'r) -> 'r res val find : Positions.t -> parsed_sexp -> sub:Sexp.t -> Positions.range option end module type Conv = sig module type Mode = Mode module type S = S module Make (Mode : Mode) (Sexp_parser : Parser.S with type parsed_value = Mode.parsed_sexp) (Positions_parser : Parser.S with type parsed_value = Positions.t) : S with type parsed_sexp := Mode.parsed_sexp with type chunk_to_conv := Mode.chunk_to_conv with type 'a res := 'a Mode.res end parsexp-0.14.1/src/cst.ml000066400000000000000000000110661376171340200152010ustar00rootroot00000000000000open! Import type t = | Atom of { loc : Positions.range ; atom : string ; unescaped : string option } | List of { loc : Positions.range ; elements : t_or_comment list } and t_or_comment = | Sexp of t | Comment of comment and comment = | Plain_comment of { loc : Positions.range ; comment : string } | Sexp_comment of { hash_semi_pos : Positions.pos ; comments : comment list ; sexp : t } [@@deriving_inline sexp_of] let rec sexp_of_t = (function | Atom { loc = v_loc; atom = v_atom; unescaped = v_unescaped } -> let bnds = [] in let bnds = let arg = sexp_of_option sexp_of_string v_unescaped in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "unescaped"; arg ] :: bnds in let bnds = let arg = sexp_of_string v_atom in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "atom"; arg ] :: bnds in let bnds = let arg = Positions.sexp_of_range v_loc in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "loc"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List (Ppx_sexp_conv_lib.Sexp.Atom "Atom" :: bnds) | List { loc = v_loc; elements = v_elements } -> let bnds = [] in let bnds = let arg = sexp_of_list sexp_of_t_or_comment v_elements in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "elements"; arg ] :: bnds in let bnds = let arg = Positions.sexp_of_range v_loc in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "loc"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List (Ppx_sexp_conv_lib.Sexp.Atom "List" :: bnds) : t -> Ppx_sexp_conv_lib.Sexp.t) and sexp_of_t_or_comment = (function | Sexp v0 -> let v0 = sexp_of_t v0 in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "Sexp"; v0 ] | Comment v0 -> let v0 = sexp_of_comment v0 in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "Comment"; v0 ] : t_or_comment -> Ppx_sexp_conv_lib.Sexp.t) and sexp_of_comment = (function | Plain_comment { loc = v_loc; comment = v_comment } -> let bnds = [] in let bnds = let arg = sexp_of_string v_comment in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "comment"; arg ] :: bnds in let bnds = let arg = Positions.sexp_of_range v_loc in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "loc"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List (Ppx_sexp_conv_lib.Sexp.Atom "Plain_comment" :: bnds) | Sexp_comment { hash_semi_pos = v_hash_semi_pos; comments = v_comments; sexp = v_sexp } -> let bnds = [] in let bnds = let arg = sexp_of_t v_sexp in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "sexp"; arg ] :: bnds in let bnds = let arg = sexp_of_list sexp_of_comment v_comments in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "comments"; arg ] :: bnds in let bnds = let arg = Positions.sexp_of_pos v_hash_semi_pos in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "hash_semi_pos"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List (Ppx_sexp_conv_lib.Sexp.Atom "Sexp_comment" :: bnds) : comment -> Ppx_sexp_conv_lib.Sexp.t) ;; [@@@end] let compare = Caml.compare let compare_t_or_comment = Caml.compare let compare_comment = Caml.compare module Forget = struct (* In cps to prevent non-tail recursion. The polymorphism in the signature ensures that each function returns only through the continuation. *) module Cps : sig val forget_t : t -> (Sexp.t -> 'r) -> 'r val forget_toc : t_or_comment -> (Sexp.t option -> 'r) -> 'r val forget_tocs : t_or_comment list -> (Sexp.t list -> 'r) -> 'r end = struct let rec forget_t t k = match t with | Atom { atom; _ } -> k (Sexp.Atom atom) | List { elements; _ } -> forget_tocs elements (fun xs -> k (Sexp.List xs)) and forget_tocs tocs k = match tocs with | [] -> k [] | toc :: tocs -> forget_toc toc (function | None -> forget_tocs tocs k | Some x -> forget_tocs tocs (fun xs -> k (x :: xs))) and forget_toc toc k = match toc with | Comment _ -> k None | Sexp t -> forget_t t (fun x -> k (Some x)) ;; end let t x = Cps.forget_t x (fun y -> y) let t_or_comment x = Cps.forget_toc x (fun y -> y) let t_or_comments x = Cps.forget_tocs x (fun y -> y) end parsexp-0.14.1/src/cst.mli000066400000000000000000000031031376171340200153430ustar00rootroot00000000000000(** Concrete syntax tree of s-expressions *) (** This module exposes a type that describe the full contents of a source file containing s-expressions. One can use this type to do low-level rewriting of s-expression files. *) open! Import type t = | Atom of { loc : Positions.range ; atom : string (** Source syntax of atom. The parser only fills this for atoms that are quoted in the source, but it makes sense for unquoted atoms too (to ensure they get printed unquoted). *) ; unescaped : string option } | List of { loc : Positions.range ; elements : t_or_comment list } and t_or_comment = | Sexp of t | Comment of comment and comment = | Plain_comment of { loc : Positions.range ; comment : string } (** Line or block comment *) | Sexp_comment of { hash_semi_pos : Positions.pos ; comments : comment list ; sexp : t } [@@deriving_inline compare, sexp_of] include sig [@@@ocaml.warning "-32"] val compare : t -> t -> int val compare_t_or_comment : t_or_comment -> t_or_comment -> int val compare_comment : comment -> comment -> int val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t val sexp_of_t_or_comment : t_or_comment -> Ppx_sexp_conv_lib.Sexp.t val sexp_of_comment : comment -> Ppx_sexp_conv_lib.Sexp.t end [@@ocaml.doc "@inline"] [@@@end] module Forget : sig val t : t -> Ppx_sexp_conv_lib.Sexp.t val t_or_comment : t_or_comment -> Ppx_sexp_conv_lib.Sexp.t option val t_or_comments : t_or_comment list -> Ppx_sexp_conv_lib.Sexp.t list end parsexp-0.14.1/src/dependencies.dot000066400000000000000000000015621376171340200172140ustar00rootroot00000000000000digraph { conv -> parsexp_intf; conv -> parsexp; conv_error -> conv_intf; positions -> of_sexp_error; positions -> parse_error_intf; positions -> cst; parse_error -> conv_error; parse_error -> parser_automaton_internal; kind_intf -> kind; import -> old_parser_cont_state; import -> positions; cst -> automaton_stack_intf; of_sexp_error -> conv_error; old_parser_cont_state -> parser_automaton; parser_intf -> parser; automaton_stack -> parser_automaton_internal; kind -> parser_intf; automaton_stack_intf -> automaton_stack; parser_automaton -> automaton_helpers; parser_automaton -> automaton_helpers_intf; parser_automaton -> parser_intf; automaton_helpers -> parser; parser -> conv_intf; conv_intf -> conv; parser_automaton_internal -> parser_automaton; parser_automaton_internal -> kind_intf; parse_error_intf -> parse_error; bytes0 -> positions; } parsexp-0.14.1/src/dune000066400000000000000000000005371376171340200147350ustar00rootroot00000000000000(library (name parsexp) (public_name parsexp) (libraries sexplib0 base.caml) (preprocess no_preprocessing) (lint (pps ppx_js_style -check-doc-comments ppx_compare ppx_sexp_conv -type-conv-keep-w32=impl -apply=js_style,type_conv))) (rule (targets bytes0.ml) (deps (:first_dep gen/gen_bytes0.exe)) (action (bash "./%{first_dep} > %{targets}")))parsexp-0.14.1/src/gen/000077500000000000000000000000001376171340200146235ustar00rootroot00000000000000parsexp-0.14.1/src/gen/dune000066400000000000000000000001401376171340200154740ustar00rootroot00000000000000(executables (names gen_bytes0) (libraries) (modules gen_bytes0) (preprocess no_preprocessing))parsexp-0.14.1/src/gen/gen_bytes0.ml000066400000000000000000000024321376171340200172150ustar00rootroot00000000000000open StdLabels module Ocaml_version : sig type t val v407 : t val current : t val compare : t -> t -> int end = struct type t = int * int let parse s = try let d1 = String.index_from s 0 '.' in let d2 = try String.index_from s (d1 + 1) '.' with | Not_found -> String.length s in let p1 = int_of_string (String.sub s ~pos:0 ~len:d1) in let p2 = int_of_string (String.sub s ~pos:(d1 + 1) ~len:(d2 - d1 - 1)) in p1, p2 with | _ -> failwith (Printf.sprintf "Invalid ocaml version %S" s) ;; let v407 = parse "4.07" let current = parse Sys.ocaml_version let compare ((a1, b1) : t) ((a2, b2) : t) = match compare a1 a2 with | 0 -> compare b1 b2 | c -> c ;; end let () = let oc = stdout in let pr str = Printf.fprintf oc "%s\n" str in pr "(* This file is automatically generated *)"; pr ""; if Ocaml_version.compare Ocaml_version.current Ocaml_version.v407 < 0 then ( pr {|external get16 : bytes -> pos:int -> int = "%caml_string_get16"|}; pr {|external set16 : bytes -> pos:int -> int -> unit = "%caml_string_set16"|}) else ( pr {|external get16 : bytes -> pos:int -> int = "%caml_bytes_get16"|}; pr {|external set16 : bytes -> pos:int -> int -> unit = "%caml_bytes_set16"|}) ;; parsexp-0.14.1/src/gen/gen_bytes0.mli000066400000000000000000000000551376171340200173650ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/src/gen/src/000077500000000000000000000000001376171340200154125ustar00rootroot00000000000000parsexp-0.14.1/src/gen/src/automaton.ml000066400000000000000000000304751376171340200177640ustar00rootroot00000000000000(* Abstract version of the parsing automaton. It is used in two places: - to define the automaton. At runtime, we only use integer for states and a table of functions for transitions - for tests *) open Base module State = struct module Quoted_string = struct type t = | Normal | After_backslash | After_backslash_cr | After_backslash_digit | After_backslash_2digits | After_backslash_x | After_backslash_x_hex | Ignoring_blanks [@@deriving enumerate, compare, sexp_of] end module Block_comment = struct type t = | Normal | After_pipe | After_hash | Quoted_string of Quoted_string.t [@@deriving enumerate, compare, sexp_of] end module Unquoted_string = struct type t = | Normal | After_hash | After_pipe [@@deriving enumerate, compare, sexp_of] end type t = | Whitespace | Error | After_cr | Unquoted_string of Unquoted_string.t | Line_comment | After_hash | Quoted_string of Quoted_string.t | Block_comment of Block_comment.t [@@deriving enumerate, compare, sexp_of] let to_int t = let rec loop i t l = match l with | [] -> assert false | x :: l -> if [%compare.equal: t] t x then i else loop (i + 1) t l in loop 0 t all ;; let of_int i = List.nth_exn all i let count = List.length all let initial = to_int Whitespace let () = assert (initial = 0) (* This is assumed in parser_automaton_internal.ml *) let () = assert (to_int Error = 1) (* This is assumed in parser_automaton_internal.ml *) let old_parser_approx_cont_state = function | Whitespace -> "Parsing_toplevel_whitespace" | After_cr -> "Parsing_nested_whitespace" | Unquoted_string _ | Quoted_string _ -> "Parsing_atom" | After_hash -> "Parsing_atom" | Block_comment _ -> "Parsing_block_comment" | Line_comment -> "Parsing_toplevel_whitespace" (* This cannot happen with the old parser so the result is a dummy value *) | Error -> "Parsing_toplevel_whitespace" ;; end module Error = struct (* Subset of the [Parser_automaton_internal.Public.Error.Reason.t] type *) type t = | Unexpected_char_parsing_hex_escape | Unexpected_char_parsing_dec_escape | Unterminated_quoted_string | Unterminated_block_comment | Comment_token_in_unquoted_atom | Unexpected_character_after_cr | Automaton_in_error_state [@@deriving compare, sexp_of, hash, variants] let to_string = Variants.to_name end (* Action associated to transitions. Actions correspond to the similarly named functions in ../parser_automaton_internal.mli. *) module Action = struct type t = | Nop | Opening | Closing | Add_atom_char | Add_quoted_atom_char | Add_first_char | Add_escaped | Add_hex_escape_char | Add_dec_escape_char | Add_last_hex_escape_char | Add_last_dec_escape_char | Add_token_char | Comment_add_last_dec_escape_char | Push_quoted_atom | Start_quoted_string | Start_block_comment | Start_sexp_comment | Start_line_comment [@@deriving compare, sexp_of, hash, variants] let to_runtime_function = function | Nop -> None | t -> Some (String.uncapitalize (Variants.to_name t)) ;; end (* Action associated to epsilon transitions, i.e. transitions that do not consume a character. Having epsilon actions makes the definition of the automaton much simpler. *) module Epsilon_action = struct type t = | Nop | Push_atom | Add_first_char_hash | Add_escaped_cr | End_line_comment [@@deriving compare, sexp_of, hash, variants] let to_runtime_function = function | Nop -> None | End_line_comment -> Some "end_line_comment" | t -> Some ("eps_" ^ String.uncapitalize (Variants.to_name t)) ;; end module Transition = struct type t = | T of Action.t * State.t | E of Epsilon_action.t * State.t | Error of Error.t | End_block_comment (* can't be a normal transition, as the new state isn't known statically *) [@@deriving compare] end module Final_transition = struct type t = | Eoi_check | E of Epsilon_action.t * State.t | Error of Error.t end module type Automaton = sig val transition : State.t * char -> Transition.t val transition_eoi : State.t -> Final_transition.t end (* Definition of the automaton, compiled later to a transition table. *) module Automaton : Automaton = struct module Quoted_string_transition = struct type t = | T of Action.t * State.Quoted_string.t | E of Epsilon_action.t * State.Quoted_string.t | Error of Error.t | End_of_quoted_string end type context = | In_block_comment | In_atom let quoted_string_transition : context -> State.Quoted_string.t * char -> Quoted_string_transition.t = fun context x -> (* Distinguising atom and block comments is to optimize block comments. But we musn't optimize the exception on things like \321. *) let if_atom then_ else_ : Action.t = match context with | In_atom -> then_ | In_block_comment -> else_ in let if_atom_eps then_ else_ : Epsilon_action.t = match context with | In_atom -> then_ | In_block_comment -> else_ in match x with | Normal, '"' -> End_of_quoted_string | Normal, '\\' -> T (Add_token_char, After_backslash) | Normal, _ -> T (if_atom Add_quoted_atom_char Add_token_char, Normal) | After_backslash, '\n' -> T (Add_token_char, Ignoring_blanks) | After_backslash, '\r' -> T (Add_token_char, After_backslash_cr) | After_backslash, 'x' -> T (Add_token_char, After_backslash_x) | After_backslash, '0' .. '9' -> T (Add_dec_escape_char, After_backslash_digit) | After_backslash, _ -> T (if_atom Add_escaped Add_token_char, Normal) | After_backslash_cr, '\n' -> T (Add_token_char, Ignoring_blanks) | After_backslash_cr, _ -> E (if_atom_eps Add_escaped_cr Nop, Normal) | After_backslash_x, ('0' .. '9' | 'a' .. 'f' | 'A' .. 'F') -> T (if_atom Add_hex_escape_char Add_token_char, After_backslash_x_hex) | After_backslash_x, _ -> Error Unexpected_char_parsing_hex_escape | After_backslash_x_hex, ('0' .. '9' | 'a' .. 'f' | 'A' .. 'F') -> T (if_atom Add_last_hex_escape_char Add_token_char, Normal) | After_backslash_x_hex, _ -> Error Unexpected_char_parsing_hex_escape | After_backslash_digit, '0' .. '9' -> T (Add_dec_escape_char, After_backslash_2digits) | After_backslash_digit, _ -> Error Unexpected_char_parsing_dec_escape | After_backslash_2digits, '0' .. '9' -> T (if_atom Add_last_dec_escape_char Comment_add_last_dec_escape_char, Normal) | After_backslash_2digits, _ -> Error Unexpected_char_parsing_dec_escape | Ignoring_blanks, (' ' | '\t') -> T (Add_token_char, Ignoring_blanks) | Ignoring_blanks, _ -> E (Nop, Normal) ;; module Block_comment_transition = struct type t = | T of Action.t * State.Block_comment.t | E of Epsilon_action.t * State.Block_comment.t | Error of Error.t | End_comment end let block_comment_transition : State.Block_comment.t * char -> Block_comment_transition.t = function | Quoted_string state, c -> (match quoted_string_transition In_block_comment (state, c) with | End_of_quoted_string -> T (Add_token_char, Normal) | T (action, state) -> T (action, Quoted_string state) | E (action, state) -> E (action, Quoted_string state) | Error error -> Error error) | After_hash, '|' -> T (Start_block_comment, Normal) | After_pipe, '#' -> End_comment | _, '"' -> T (Add_token_char, Quoted_string Normal) | _, '|' -> T (Add_token_char, After_pipe) | _, '#' -> T (Add_token_char, After_hash) | _, _ -> T (Add_token_char, Normal) ;; let transition : State.t * char -> Transition.t = function | Whitespace, '(' -> T (Opening, Whitespace) | Whitespace, ')' -> T (Closing, Whitespace) | Whitespace, '\r' -> T (Nop, After_cr) | Whitespace, (' ' | '\t' | '\012' | '\n') -> T (Nop, Whitespace) | Whitespace, ';' -> T (Start_line_comment, Line_comment) | Whitespace, '"' -> T (Start_quoted_string, Quoted_string Normal) | Whitespace, '#' -> T (Nop, After_hash) | Whitespace, '|' -> T (Add_first_char, Unquoted_string After_pipe) | Whitespace, _ -> T (Add_first_char, Unquoted_string Normal) | After_cr, '\n' -> T (Nop, Whitespace) | After_cr, _ -> Error Unexpected_character_after_cr | Unquoted_string _, (';' | '(' | ')' | '"' | ' ' | '\t' | '\012' | '\r' | '\n') -> E (Push_atom, Whitespace) | Unquoted_string After_hash, '|' | Unquoted_string After_pipe, '#' -> Error Comment_token_in_unquoted_atom | Unquoted_string _, '#' -> T (Add_atom_char, Unquoted_string After_hash) | Unquoted_string _, '|' -> T (Add_atom_char, Unquoted_string After_pipe) | Unquoted_string _, _ -> T (Add_atom_char, Unquoted_string Normal) | Line_comment, ('\r' | '\n') -> E (End_line_comment, Whitespace) | Line_comment, _ -> T (Add_token_char, Line_comment) | After_hash, ';' -> T (Start_sexp_comment, Whitespace) | After_hash, '|' -> T (Start_block_comment, Block_comment Normal) | After_hash, _ -> E (Add_first_char_hash, Unquoted_string Normal) | Quoted_string state, c -> (match quoted_string_transition In_atom (state, c) with | End_of_quoted_string -> T (Push_quoted_atom, Whitespace) | T (action, state) -> T (action, Quoted_string state) | E (action, state) -> E (action, Quoted_string state) | Error error -> Error error) | Block_comment state, c -> (match block_comment_transition (state, c) with | T (action, state) -> T (action, Block_comment state) | E (action, state) -> E (action, Block_comment state) | End_comment -> End_block_comment | Error error -> Error error) | Error, _ -> Error Automaton_in_error_state ;; let transition_eoi : State.t -> Final_transition.t = function | Whitespace -> Eoi_check | After_cr -> Error Unexpected_character_after_cr | Unquoted_string _ -> E (Push_atom, Whitespace) | Line_comment -> E (End_line_comment, Whitespace) | After_hash -> E (Add_first_char_hash, Unquoted_string Normal) | Quoted_string _ -> Error Unterminated_quoted_string | Block_comment _ -> Error Unterminated_block_comment | Error -> Error Automaton_in_error_state ;; end module Table = struct type action = Epsilon_action.t list * Action.t [@@deriving compare, sexp_of, hash] type goto_state = | State of int | End_block_comment [@@deriving compare, sexp_of, hash] type advance = | Advance | Advance_eol [@@deriving compare, sexp_of, hash] type transition = { action : action ; goto : goto_state ; advance : advance } [@@deriving compare, sexp_of, hash] type 'a or_error = | Ok of 'a | Error of Error.t [@@deriving compare, sexp_of, hash] type t = { transitions : transition or_error array ; transitions_eoi : Epsilon_action.t list or_error array } let advance = function | '\n' -> Advance_eol | _ -> Advance ;; let compile (module A : Automaton) = let rec squash acc state c = match A.transition (state, c) with | T (action, state) -> Ok { action = List.rev acc, action ; goto = State (State.to_int state) ; advance = advance c } | E (action, state) -> squash (action :: acc) state c | Error error -> Error error | End_block_comment -> Ok { action = List.rev acc, Nop; goto = End_block_comment; advance = advance c } in let rec squash_eoi acc state = match A.transition_eoi state with | Eoi_check -> Ok (List.rev acc) | E (eps_action, state) -> squash_eoi (eps_action :: acc) state | Error error -> Error error in let transitions = Array.create ~len:(State.count * 256) (Ok { action = [], Action.Nop; goto = State 0; advance = Advance }) in let transitions_eoi = Array.create (Ok []) ~len:State.count in for s = 0 to State.count - 1 do let state = State.of_int s in for c = 0 to 255 do transitions.((s * 256) + c) <- squash [] state (Char.of_int_exn c) done; transitions_eoi.(s) <- squash_eoi [] state done; { transitions; transitions_eoi } ;; end let table = Table.compile (module Automaton) parsexp-0.14.1/src/gen/src/dune000066400000000000000000000002561376171340200162730ustar00rootroot00000000000000(library (name gen_parsexp_lib) (libraries base) (preprocess (pps ppx_js_style -check-doc-comments ppx_sexp_conv ppx_compare ppx_enumerate ppx_hash ppx_variants_conv)))parsexp-0.14.1/src/import.ml000066400000000000000000000003471376171340200157220ustar00rootroot00000000000000module Ppx_sexp_conv_lib = struct module Conv_error = Sexplib0.Sexp_conv_error module Conv = Sexplib0.Sexp_conv module Sexp = Sexplib0.Sexp end module Sexp = Sexplib0.Sexp include Sexplib0.Sexp_conv module List = ListLabels parsexp-0.14.1/src/kind.ml000066400000000000000000000010741376171340200153330ustar00rootroot00000000000000open! Import include Kind_intf let create (type stack state) (module Stack : Stack with type t = stack) kind : (module S with type Stack.t = stack and type state = state) = (module struct module Stack = Stack type nonrec state = state let kind = kind end) ;; module Sexp = (val create (module Automaton_stack) Sexp) module Sexp_with_positions = (val create (module Automaton_stack) Sexp_with_positions) module Positions = (val create (module Automaton_stack.Just_positions) Positions) module Cst = (val create (module Automaton_stack.For_cst) Cst) parsexp-0.14.1/src/kind.mli000066400000000000000000000000271376171340200155010ustar00rootroot00000000000000include Kind_intf.Kind parsexp-0.14.1/src/kind_intf.ml000066400000000000000000000014511376171340200163520ustar00rootroot00000000000000open! Import module type Stack = sig (** Parser stack. The stack is not in [state] for optimization purposes. *) type t val empty : t end module type S = sig module Stack : Stack type state val kind : (state, Stack.t) Parser_automaton_internal.Public.kind end module type Kind = sig module type Stack = Stack module type S = S module Sexp : S with type Stack.t = Automaton_stack.t and type state = unit module Sexp_with_positions : S with type Stack.t = Automaton_stack.t and type state = Positions.Builder.t module Positions : S with type Stack.t = Automaton_stack.Just_positions.t and type state = Positions.Builder.t module Cst : S with type Stack.t = Automaton_stack.For_cst.t and type state = Parser_automaton_internal.Public.state_cst end parsexp-0.14.1/src/of_sexp_error.ml000066400000000000000000000036031376171340200172620ustar00rootroot00000000000000open! Import type t = { user_exn : exn ; sub_sexp : Sexp.t ; location : Positions.range option } [@@deriving_inline sexp_of] let sexp_of_t = (function | { user_exn = v_user_exn; sub_sexp = v_sub_sexp; location = v_location } -> let bnds = [] in let bnds = let arg = sexp_of_option Positions.sexp_of_range v_location in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "location"; arg ] :: bnds in let bnds = let arg = Sexp.sexp_of_t v_sub_sexp in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "sub_sexp"; arg ] :: bnds in let bnds = let arg = sexp_of_exn v_user_exn in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "user_exn"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List bnds : t -> Ppx_sexp_conv_lib.Sexp.t) ;; [@@@end] let user_exn t = t.user_exn let sub_sexp t = t.sub_sexp let location t = t.location let report ppf ~filename t = let line, start, stop = match t.location with | None -> 1, 0, 0 | Some { start_pos; end_pos } -> start_pos.line, start_pos.col, start_pos.col + end_pos.offset - start_pos.offset in Format.fprintf ppf "File \"%s\", line %d, characters %d-%d:\n\ Error: s-expression conversion error;\n\ exception %s\n" filename line start stop (Printexc.to_string t.user_exn) ;; exception Of_sexp_error of t [@@deriving_inline sexp_of] let () = Ppx_sexp_conv_lib.Conv.Exn_converter.add [%extension_constructor Of_sexp_error] (function | Of_sexp_error v0 -> let v0 = sexp_of_t v0 in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "of_sexp_error.ml.Of_sexp_error"; v0 ] | _ -> assert false) ;; [@@@end] let raise ~user_exn ~sub_sexp ~location = raise (Of_sexp_error { user_exn; sub_sexp; location }) ;; parsexp-0.14.1/src/of_sexp_error.mli000066400000000000000000000012771376171340200174400ustar00rootroot00000000000000open! Import type t [@@deriving_inline sexp_of] include sig [@@@ocaml.warning "-32"] val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t end [@@ocaml.doc "@inline"] [@@@end] (** Exception raised by the user function *) val user_exn : t -> exn (** S-expression that failed to be converted *) val sub_sexp : t -> Sexp.t (** Position of [sub_sexp t] in the original source, if found *) val location : t -> Positions.range option (** Similar to [Parse_error.report] *) val report : Format.formatter -> filename:string -> t -> unit (** Exception raised in case of a conversion error *) exception Of_sexp_error of t val raise : user_exn:exn -> sub_sexp:Sexp.t -> location:Positions.range option -> 'a parsexp-0.14.1/src/old_parser_cont_state.ml000066400000000000000000000016231376171340200207630ustar00rootroot00000000000000open! Import type t = | Parsing_toplevel_whitespace | Parsing_nested_whitespace | Parsing_atom | Parsing_list | Parsing_sexp_comment | Parsing_block_comment [@@deriving_inline sexp_of] let sexp_of_t = (function | Parsing_toplevel_whitespace -> Ppx_sexp_conv_lib.Sexp.Atom "Parsing_toplevel_whitespace" | Parsing_nested_whitespace -> Ppx_sexp_conv_lib.Sexp.Atom "Parsing_nested_whitespace" | Parsing_atom -> Ppx_sexp_conv_lib.Sexp.Atom "Parsing_atom" | Parsing_list -> Ppx_sexp_conv_lib.Sexp.Atom "Parsing_list" | Parsing_sexp_comment -> Ppx_sexp_conv_lib.Sexp.Atom "Parsing_sexp_comment" | Parsing_block_comment -> Ppx_sexp_conv_lib.Sexp.Atom "Parsing_block_comment" : t -> Ppx_sexp_conv_lib.Sexp.t) ;; [@@@end] let to_string t = match sexp_of_t t with | Atom s -> s | List _ -> failwith "BUG: [sexp_of_t] returned a [List _]" ;; parsexp-0.14.1/src/old_parser_cont_state.mli000066400000000000000000000005421376171340200211330ustar00rootroot00000000000000open! Import type t = | Parsing_toplevel_whitespace | Parsing_nested_whitespace | Parsing_atom | Parsing_list | Parsing_sexp_comment | Parsing_block_comment [@@deriving_inline sexp_of] include sig [@@@ocaml.warning "-32"] val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t end [@@ocaml.doc "@inline"] [@@@end] val to_string : t -> string parsexp-0.14.1/src/parse_error.ml000066400000000000000000000062001376171340200167250ustar00rootroot00000000000000open! Import include Parse_error_intf type t = { position : Positions.pos ; message : string ; old_parser_exn : [ `Parse_error | `Failure ] } let sexp_of_t { position; message; old_parser_exn = _ } : Sexp.t = List [ List [ Atom "position"; Positions.sexp_of_pos position ] ; List [ Atom "message"; sexp_of_string message ] ] ;; let position t = t.position let message t = t.message let old_parser_exn t = t.old_parser_exn let report ppf ~filename t = let pos = position t in let msg = message t in Format.fprintf ppf "File \"%s\", line %d, character %d:\nError: s-expression parsing error;\n%s\n" filename pos.line pos.col msg ;; exception Parse_error of t [@@deriving_inline sexp] let () = Ppx_sexp_conv_lib.Conv.Exn_converter.add [%extension_constructor Parse_error] (function | Parse_error v0 -> let v0 = sexp_of_t v0 in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "parse_error.ml.Parse_error"; v0 ] | _ -> assert false) ;; [@@@end] let raise (reason : Reason.t) position ~at_eof ~atom_buffer = let message = (* These messages where choosen such that we can build the various Sexplib parsing functions on top of Parsexp and keep the same exceptions. At the time of writing this, a simple layer on top of parsexp to implement the sexplib API is passing all the sexplib tests. Note that parsexp matches the semantic of Sexp.parse which is slightly different from the ocamllex/ocamlyacc based parser of Sexplib. The latter one is less tested and assumed to be less used. *) match reason with | Unexpected_char_parsing_hex_escape -> "unterminated hexadecimal escape sequence" | Unexpected_char_parsing_dec_escape -> "unterminated decimal escape sequence" | Unterminated_quoted_string -> "unterminated quoted string" | Unterminated_block_comment -> "unterminated block comment" | Escape_sequence_out_of_range -> "escape sequence in quoted string out of range" | Unclosed_paren -> "unclosed parentheses at end of input" | Too_many_sexps -> "s-expression followed by data" | Closed_paren_without_opened -> "unexpected character: ')'" | Comment_token_in_unquoted_atom -> if String.equal (Buffer.contents atom_buffer) "|" then "illegal end of comment" else "comment tokens in unquoted atom" | Sexp_comment_without_sexp -> "unterminated sexp comment" | Unexpected_character_after_cr -> if at_eof then "unexpected end of input after carriage return" else "unexpected character after carriage return" | No_sexp_found_in_input -> "no s-expression found in input" | Automaton_in_error_state -> failwith "Parsexp.Parser_automaton: parser is dead" in let old_parser_exn = match reason, at_eof with | Too_many_sexps, _ | _, true -> `Failure | Comment_token_in_unquoted_atom, _ when String.equal (Buffer.contents atom_buffer) "|" -> `Failure | _ -> `Parse_error in raise (Parse_error { position; message; old_parser_exn }) ;; module Private = struct module Reason = Reason let old_parser_exn = old_parser_exn let raise = raise end parsexp-0.14.1/src/parse_error.mli000066400000000000000000000000451376171340200170770ustar00rootroot00000000000000include Parse_error_intf.Parse_error parsexp-0.14.1/src/parse_error_intf.ml000066400000000000000000000026561376171340200177600ustar00rootroot00000000000000open! Import module Reason = struct (*_ To be kept in sync with the Error module in gen/gen_parser_automaton.ml *) type t = | Unexpected_char_parsing_hex_escape | Unexpected_char_parsing_dec_escape | Unterminated_quoted_string | Unterminated_block_comment | Escape_sequence_out_of_range | Unclosed_paren | Too_many_sexps | Closed_paren_without_opened | Comment_token_in_unquoted_atom | Sexp_comment_without_sexp | Unexpected_character_after_cr | No_sexp_found_in_input | Automaton_in_error_state end module type Parse_error = sig type t [@@deriving_inline sexp_of] include sig [@@@ocaml.warning "-32"] val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t end [@@ocaml.doc "@inline"] [@@@end] val position : t -> Positions.pos val message : t -> string (** Report an error in a style similar to OCaml, for instance: File "blah", line 42, character 10: Error: s-expression parsing error; unterminated quoted string. *) val report : Format.formatter -> filename:string -> t -> unit exception Parse_error of t (**/**) module Private : sig module Reason = Reason (** To match the old behavior, the old parser sometimes raised [Failure] and sometimes raised [Parse_error] *) val old_parser_exn : t -> [ `Parse_error | `Failure ] val raise : Reason.t -> Positions.pos -> at_eof:bool -> atom_buffer:Buffer.t -> 'a end end parsexp-0.14.1/src/parser.ml000066400000000000000000000112731376171340200157040ustar00rootroot00000000000000open! Import include Parser_intf module Make (Kind : Kind.S) (Mode : Mode(Kind).S) : S with type parsed_value = Mode.parsed_value with type State.t = (Kind.state, Kind.Stack.t) A.state with module Stack = Kind.Stack = struct type parsed_value = Mode.parsed_value module Stack = Kind.Stack module State = struct type t = (Kind.state, Kind.Stack.t) A.state let create ?pos () = A.new_state ?initial_pos:pos Mode.mode Kind.kind let reset = A.reset let offset = A.offset let line = A.line let column = A.column let position t : Positions.pos = { offset = offset t; line = line t; col = column t } let stop state = A.set_error_state state end let feed = A.feed let feed_eoi state stack = Mode.make_value state (A.feed_eoi state stack) let feed_substring = Automaton_helpers.feed_substring let feed_string = Automaton_helpers.feed_string let feed_subbytes = Automaton_helpers.feed_subbytes let feed_bytes = Automaton_helpers.feed_bytes let parse_string_exn str = let state = State.create () in feed_eoi state (feed_string state str Kind.Stack.empty) ;; let parse_string str = match parse_string_exn str with | x -> Ok x | exception Parse_error.Parse_error e -> Error e ;; end module Make_eager (Kind : Kind.S) (Mode : Mode_eager(Kind).S) : S_eager with type parsed_value = Mode.parsed_value with type State.t = (Kind.state, Kind.Stack.t) A.state with module Stack = Kind.Stack = struct type parsed_value = Mode.parsed_value module Stack = Kind.Stack module State = struct module Read_only = struct type t = (Kind.state, Kind.Stack.t) A.state let offset = A.offset let line = A.line let column = A.column let position t : Positions.pos = { offset = offset t; line = line t; col = column t } ;; end include Read_only let create ?pos ?(no_sexp_is_error = false) f = let got_sexp state stack = let parsed_value = Mode.make_value state stack in f state parsed_value; Stack.empty in A.new_state ?initial_pos:pos (Eager { got_sexp; no_sexp_is_error }) Kind.kind ;; let reset = A.reset let stop t = A.set_error_state t let old_parser_cont_state t = Parser_automaton.old_parser_cont_state t end let feed = A.feed let feed_eoi state stack = ignore (A.feed_eoi state stack : Stack.t) let feed_substring = Automaton_helpers.feed_substring let feed_string = Automaton_helpers.feed_string let feed_subbytes = Automaton_helpers.feed_subbytes let feed_bytes = Automaton_helpers.feed_bytes module Lexbuf_consumer = struct type t = State.t exception Got_sexp of parsed_value * Positions.pos let got_sexp state parsed_value = raise_notrace (Got_sexp (parsed_value, State.position state)) ;; let create () = State.create got_sexp let pos_of_lexbuf lexbuf = let p = lexbuf.Lexing.lex_curr_p in { Positions.line = p.pos_lnum; col = p.pos_cnum - p.pos_bol; offset = p.pos_cnum } ;; let update_lexbuf (lexbuf : Lexing.lexbuf) (pos : Positions.pos) = let p = pos.offset - lexbuf.lex_abs_pos in lexbuf.lex_curr_pos <- p; lexbuf.lex_start_pos <- p; lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_lnum = pos.line ; pos_cnum = pos.offset ; pos_bol = pos.offset - pos.col } ;; let rec feed_lexbuf t (lexbuf : Lexing.lexbuf) stack = let stack = feed_subbytes t lexbuf.lex_buffer stack ~pos:lexbuf.lex_curr_pos ~len:(lexbuf.lex_buffer_len - lexbuf.lex_curr_pos) in lexbuf.lex_curr_pos <- lexbuf.lex_buffer_len; lexbuf.lex_start_pos <- lexbuf.lex_buffer_len; if not lexbuf.lex_eof_reached then ( lexbuf.refill_buff lexbuf; feed_lexbuf t lexbuf stack) else feed_eoi t stack ;; let parse_gen t (lexbuf : Lexing.lexbuf) = A.reset t ~pos:(pos_of_lexbuf lexbuf); match feed_lexbuf t lexbuf Stack.empty with | () -> update_lexbuf lexbuf (State.position t); None | exception Got_sexp (parsed_value, pos) -> update_lexbuf lexbuf pos; Some parsed_value | exception exn -> update_lexbuf lexbuf (State.position t); raise exn ;; let set_no_sexp_is_error t x = match A.mode t with | Eager e -> e.no_sexp_is_error <- x | _ -> assert false ;; let parse t lexbuf = set_no_sexp_is_error t true; match parse_gen t lexbuf with | Some x -> x | None -> failwith "Parsexp.parse_gen: None" ;; let parse_opt t lexbuf = set_no_sexp_is_error t false; parse_gen t lexbuf ;; end end parsexp-0.14.1/src/parser.mli000066400000000000000000000000521376171340200160460ustar00rootroot00000000000000include Parser_intf.Parser (** @inline *) parsexp-0.14.1/src/parser_automaton.ml000066400000000000000000002612211376171340200177730ustar00rootroot00000000000000open Parser_automaton_internal include Public let raise = Parser_automaton_internal.raise_error type u' type s' (*$ open Parsexp_cinaps_helpers.Gen_parser_automaton ;; *) (*$ print_code () ;; *) let tr_00 state char stack = let stack = add_first_char state char stack in set_automaton_state state 3; advance state; stack ;; let tr_01 state _char stack = set_automaton_state state 0; advance state; stack ;; let tr_02 state _char stack = set_automaton_state state 0; advance_eol state; stack ;; let tr_03 state _char stack = set_automaton_state state 2; advance state; stack ;; let tr_04 state char stack = let stack = start_quoted_string state char stack in set_automaton_state state 8; advance state; stack ;; let tr_05 state _char stack = set_automaton_state state 7; advance state; stack ;; let tr_06 state char stack = let stack = opening state char stack in set_automaton_state state 0; advance state; stack ;; let tr_07 state char stack = let stack = closing state char stack in set_automaton_state state 0; advance state; stack ;; let tr_08 state char stack = let stack = start_line_comment state char stack in set_automaton_state state 6; advance state; stack ;; let tr_09 state char stack = let stack = add_first_char state char stack in set_automaton_state state 5; advance state; stack ;; let tr_10 _state _char _stack = raise _state ~at_eof:false Automaton_in_error_state let tr_11 _state _char _stack = raise _state ~at_eof:false Unexpected_character_after_cr let tr_12 state char stack = let stack = add_atom_char state char stack in set_automaton_state state 3; advance state; stack ;; let tr_13 state _char stack = let stack = eps_push_atom state stack in set_automaton_state state 0; advance state; stack ;; let tr_14 state _char stack = let stack = eps_push_atom state stack in set_automaton_state state 0; advance_eol state; stack ;; let tr_15 state _char stack = let stack = eps_push_atom state stack in set_automaton_state state 2; advance state; stack ;; let tr_16 state char stack = let stack = eps_push_atom state stack in let stack = start_quoted_string state char stack in set_automaton_state state 8; advance state; stack ;; let tr_17 state char stack = let stack = add_atom_char state char stack in set_automaton_state state 4; advance state; stack ;; let tr_18 state char stack = let stack = eps_push_atom state stack in let stack = opening state char stack in set_automaton_state state 0; advance state; stack ;; let tr_19 state char stack = let stack = eps_push_atom state stack in let stack = closing state char stack in set_automaton_state state 0; advance state; stack ;; let tr_20 state char stack = let stack = eps_push_atom state stack in let stack = start_line_comment state char stack in set_automaton_state state 6; advance state; stack ;; let tr_21 state char stack = let stack = add_atom_char state char stack in set_automaton_state state 5; advance state; stack ;; let tr_22 _state _char _stack = raise _state ~at_eof:false Comment_token_in_unquoted_atom let tr_23 state char stack = let stack = add_token_char state char stack in set_automaton_state state 6; advance state; stack ;; let tr_24 state _char stack = let stack = end_line_comment state stack in set_automaton_state state 0; advance_eol state; stack ;; let tr_25 state _char stack = let stack = end_line_comment state stack in set_automaton_state state 2; advance state; stack ;; let tr_26 state char stack = let stack = eps_add_first_char_hash state stack in let stack = add_atom_char state char stack in set_automaton_state state 3; advance state; stack ;; let tr_27 state _char stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in set_automaton_state state 0; advance state; stack ;; let tr_28 state _char stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in set_automaton_state state 0; advance_eol state; stack ;; let tr_29 state _char stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in set_automaton_state state 2; advance state; stack ;; let tr_30 state char stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in let stack = start_quoted_string state char stack in set_automaton_state state 8; advance state; stack ;; let tr_31 state char stack = let stack = eps_add_first_char_hash state stack in let stack = add_atom_char state char stack in set_automaton_state state 4; advance state; stack ;; let tr_32 state char stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in let stack = opening state char stack in set_automaton_state state 0; advance state; stack ;; let tr_33 state char stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in let stack = closing state char stack in set_automaton_state state 0; advance state; stack ;; let tr_34 state char stack = let stack = start_sexp_comment state char stack in set_automaton_state state 0; advance state; stack ;; let tr_35 state char stack = let stack = start_block_comment state char stack in set_automaton_state state 16; advance state; stack ;; let tr_36 state char stack = let stack = add_quoted_atom_char state char stack in set_automaton_state state 8; advance state; stack ;; let tr_37 state char stack = let stack = add_quoted_atom_char state char stack in set_automaton_state state 8; advance_eol state; stack ;; let tr_38 state char stack = let stack = push_quoted_atom state char stack in set_automaton_state state 0; advance state; stack ;; let tr_39 state char stack = let stack = add_token_char state char stack in set_automaton_state state 9; advance state; stack ;; let tr_40 state char stack = let stack = add_escaped state char stack in set_automaton_state state 8; advance state; stack ;; let tr_41 state char stack = let stack = add_token_char state char stack in set_automaton_state state 15; advance_eol state; stack ;; let tr_42 state char stack = let stack = add_token_char state char stack in set_automaton_state state 10; advance state; stack ;; let tr_43 state char stack = let stack = add_dec_escape_char state char stack in set_automaton_state state 11; advance state; stack ;; let tr_44 state char stack = let stack = add_token_char state char stack in set_automaton_state state 13; advance state; stack ;; let tr_45 state char stack = let stack = eps_add_escaped_cr state stack in let stack = add_quoted_atom_char state char stack in set_automaton_state state 8; advance state; stack ;; let tr_46 state char stack = let stack = eps_add_escaped_cr state stack in let stack = push_quoted_atom state char stack in set_automaton_state state 0; advance state; stack ;; let tr_47 state char stack = let stack = eps_add_escaped_cr state stack in let stack = add_token_char state char stack in set_automaton_state state 9; advance state; stack ;; let tr_48 _state _char _stack = raise _state ~at_eof:false Unexpected_char_parsing_dec_escape ;; let tr_49 state char stack = let stack = add_dec_escape_char state char stack in set_automaton_state state 12; advance state; stack ;; let tr_50 state char stack = let stack = add_last_dec_escape_char state char stack in set_automaton_state state 8; advance state; stack ;; let tr_51 _state _char _stack = raise _state ~at_eof:false Unexpected_char_parsing_hex_escape ;; let tr_52 state char stack = let stack = add_hex_escape_char state char stack in set_automaton_state state 14; advance state; stack ;; let tr_53 state char stack = let stack = add_last_hex_escape_char state char stack in set_automaton_state state 8; advance state; stack ;; let tr_54 state char stack = let stack = add_quoted_atom_char state char stack in set_automaton_state state 8; advance state; stack ;; let tr_55 state char stack = let stack = add_token_char state char stack in set_automaton_state state 15; advance state; stack ;; let tr_56 state char stack = let stack = add_quoted_atom_char state char stack in set_automaton_state state 8; advance_eol state; stack ;; let tr_57 state char stack = let stack = push_quoted_atom state char stack in set_automaton_state state 0; advance state; stack ;; let tr_58 state char stack = let stack = add_token_char state char stack in set_automaton_state state 9; advance state; stack ;; let tr_59 state char stack = let stack = add_token_char state char stack in set_automaton_state state 16; advance state; stack ;; let tr_60 state char stack = let stack = add_token_char state char stack in set_automaton_state state 16; advance_eol state; stack ;; let tr_61 state char stack = let stack = add_token_char state char stack in set_automaton_state state 19; advance state; stack ;; let tr_62 state char stack = let stack = add_token_char state char stack in set_automaton_state state 18; advance state; stack ;; let tr_63 state char stack = let stack = add_token_char state char stack in set_automaton_state state 17; advance state; stack ;; let tr_64 state char stack = let stack = end_block_comment state char stack in set_automaton_state state (if block_comment_depth state <> 0 then 16 else 0); advance state; stack ;; let tr_65 state char stack = let stack = add_token_char state char stack in set_automaton_state state 19; advance_eol state; stack ;; let tr_66 state char stack = let stack = add_token_char state char stack in set_automaton_state state 20; advance state; stack ;; let tr_67 state char stack = let stack = add_token_char state char stack in set_automaton_state state 26; advance_eol state; stack ;; let tr_68 state char stack = let stack = add_token_char state char stack in set_automaton_state state 21; advance state; stack ;; let tr_69 state char stack = let stack = add_dec_escape_char state char stack in set_automaton_state state 22; advance state; stack ;; let tr_70 state char stack = let stack = add_token_char state char stack in set_automaton_state state 24; advance state; stack ;; let tr_71 state char stack = let stack = add_token_char state char stack in set_automaton_state state 19; advance state; stack ;; let tr_72 state char stack = let stack = add_token_char state char stack in set_automaton_state state 16; advance state; stack ;; let tr_73 state char stack = let stack = add_token_char state char stack in set_automaton_state state 20; advance state; stack ;; let tr_74 state char stack = let stack = add_dec_escape_char state char stack in set_automaton_state state 23; advance state; stack ;; let tr_75 state char stack = let stack = comment_add_last_dec_escape_char state char stack in set_automaton_state state 19; advance state; stack ;; let tr_76 state char stack = let stack = add_token_char state char stack in set_automaton_state state 25; advance state; stack ;; let tr_77 state char stack = let stack = add_token_char state char stack in set_automaton_state state 26; advance state; stack ;; let tr_78 state char stack = let stack = add_token_char state char stack in set_automaton_state state 19; advance_eol state; stack ;; let tr_eoi_00 state stack = eps_eoi_check state stack let tr_eoi_01 state _stack = raise state ~at_eof:true Automaton_in_error_state let tr_eoi_02 state _stack = raise state ~at_eof:true Unexpected_character_after_cr let tr_eoi_03 state stack = let stack = eps_push_atom state stack in eps_eoi_check state stack ;; let tr_eoi_04 state stack = let stack = end_line_comment state stack in eps_eoi_check state stack ;; let tr_eoi_05 state stack = let stack = eps_add_first_char_hash state stack in let stack = eps_push_atom state stack in eps_eoi_check state stack ;; let tr_eoi_06 state _stack = raise state ~at_eof:true Unterminated_quoted_string let tr_eoi_07 state _stack = raise state ~at_eof:true Unterminated_block_comment let transitions = [| tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_01 ; tr_02 ; tr_00 ; tr_01 ; tr_03 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_01 ; tr_00 ; tr_04 ; tr_05 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_06 ; tr_07 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_08 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_09 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_00 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_10 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_02 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_11 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_13 ; tr_14 ; tr_12 ; tr_13 ; tr_15 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_13 ; tr_12 ; tr_16 ; tr_17 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_18 ; tr_19 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_20 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_21 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_13 ; tr_14 ; tr_12 ; tr_13 ; tr_15 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_13 ; tr_12 ; tr_16 ; tr_17 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_18 ; tr_19 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_20 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_22 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_13 ; tr_14 ; tr_12 ; tr_13 ; tr_15 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_13 ; tr_12 ; tr_16 ; tr_22 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_18 ; tr_19 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_20 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_21 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_12 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_24 ; tr_23 ; tr_23 ; tr_25 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_23 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_27 ; tr_28 ; tr_26 ; tr_27 ; tr_29 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_27 ; tr_26 ; tr_30 ; tr_31 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_32 ; tr_33 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_34 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_35 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_26 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_37 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_38 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_39 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_36 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_41 ; tr_40 ; tr_40 ; tr_42 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_43 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_44 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_40 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_41 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_46 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_47 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_45 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_49 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_50 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_52 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_53 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_55 ; tr_56 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_55 ; tr_54 ; tr_57 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_58 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_54 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_60 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_61 ; tr_62 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_63 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_60 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_61 ; tr_64 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_63 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_60 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_61 ; tr_62 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_35 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_59 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_65 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_59 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_66 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_67 ; tr_61 ; tr_61 ; tr_68 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_69 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_70 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_67 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_72 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_73 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_74 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_75 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_48 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_76 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_61 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_51 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_77 ; tr_78 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_77 ; tr_71 ; tr_72 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_73 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 ; tr_71 |] ;; let transitions_eoi = [| tr_eoi_00 ; tr_eoi_01 ; tr_eoi_02 ; tr_eoi_03 ; tr_eoi_03 ; tr_eoi_03 ; tr_eoi_04 ; tr_eoi_05 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_06 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 ; tr_eoi_07 |] ;; let old_parser_approx_cont_states : Old_parser_cont_state.t array = [| Parsing_toplevel_whitespace ; Parsing_toplevel_whitespace ; Parsing_nested_whitespace ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_toplevel_whitespace ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_atom ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment ; Parsing_block_comment |] ;; (*$*) let feed (type u s) (state : (u, s) state) char (stack : s) : s = let idx = (automaton_state state lsl 8) lor Char.code char in (* We need an Obj.magic as the type of the array can't be generalized. This problem will go away when we get immutable arrays. *) let magic : ((u', s') state -> char -> s' -> s') array -> ((u, s) state -> char -> s -> s) array = Obj.magic in (magic transitions).(idx) state char stack [@@inline always] ;; let feed_eoi (type u s) (state : (u, s) state) (stack : s) : s = let magic : ((u', s') state -> s' -> s') array -> ((u, s) state -> s -> s) array = Obj.magic in let stack = (magic transitions_eoi).(automaton_state state) state stack in set_error_state state; stack ;; let old_parser_cont_state state : Old_parser_cont_state.t = match context state with | Sexp_comment -> Parsing_sexp_comment | Sexp -> (match old_parser_approx_cont_states.(automaton_state state), has_unclosed_paren state with | Parsing_toplevel_whitespace, true -> Parsing_list | s, _ -> s) ;; parsexp-0.14.1/src/parser_automaton.mli000066400000000000000000000006271376171340200201450ustar00rootroot00000000000000(** Parser automaton *) (** Warning: the API of this module is not fixed and might change! Use {!Sexp_parsing} for the stable version. *) include module type of Parser_automaton_internal.Public val feed : ('u, 's) state -> char -> 's -> 's val feed_eoi : ('u, 's) state -> 's -> 's (**/**) (*_ Continuation state of the old parser *) val old_parser_cont_state : _ state -> Old_parser_cont_state.t parsexp-0.14.1/src/parser_automaton_internal.ml000066400000000000000000000445601376171340200216740ustar00rootroot00000000000000open! Import module Public = struct type state_cst = { token_buffer : Buffer.t ; (* Starting positions of the current token *) mutable token_start_pos : Positions.pos } type ('u, 's) kind = | Positions : (Positions.Builder.t, unit) kind | Sexp : (unit, Automaton_stack.t) kind | Sexp_with_positions : (Positions.Builder.t, Automaton_stack.t) kind | Cst : (state_cst, Automaton_stack.For_cst.t) kind type ('u, 's) state = { mutable automaton_state : int ; kind : ('u, 's) kind ; mutable depth : int ; (* Number of opened #| when parsing a block comment *) mutable block_comment_depth : int ; (* Stack of ignoring depths; the current depth is pushed each time a #; comment is entered. *) mutable ignoring_stack : int list ; (* When parsing an escape sequence of the form "\\NNN" or "\\XX", this accumulates the computed number *) mutable escaped_value : int ; (* Buffer for accumulating atoms *) atom_buffer : Buffer.t ; user_state : 'u ; mode : ('u, 's) mode ; mutable full_sexps : int ; mutable offset : int (* global offset *) ; mutable line_number : int ; mutable bol_offset : int (* offset of beginning of line *) } and ('u, 's) mode = | Single | Many | Eager of { got_sexp : ('u, 's) state -> 's -> 's ; mutable no_sexp_is_error : bool } let initial_user_state : type u s. (u, s) kind -> Positions.pos -> u = fun kind initial_pos -> match kind with | Positions -> Positions.Builder.create ~initial_pos () | Sexp -> () | Sexp_with_positions -> Positions.Builder.create ~initial_pos () | Cst -> (* [token_start_pos] is set to a dummy location here. It is properly set when we start to capture a token from the input *) { token_buffer = Buffer.create 128; token_start_pos = Positions.beginning_of_file } ;; (* these magic numbers are checked in gen_parser_automaton.ml: let () = assert (initial = 0) let () = assert (to_int Error = 1) *) let initial_state = 0 let error_state = 1 let new_state ?(initial_pos = Positions.beginning_of_file) mode kind = { kind ; depth = 0 ; automaton_state = initial_state ; block_comment_depth = 0 ; ignoring_stack = [] ; escaped_value = 0 ; atom_buffer = Buffer.create 128 ; user_state = initial_user_state kind initial_pos ; mode ; full_sexps = 0 ; offset = initial_pos.offset ; line_number = initial_pos.line ; bol_offset = initial_pos.offset - initial_pos.col } ;; let mode t = t.mode let positions t = Positions.Builder.contents t.user_state let atom_buffer t = t.atom_buffer let offset state = state.offset let line state = state.line_number let column state = state.offset - state.bol_offset let position t = { Positions.col = column t; line = line t; offset = offset t } let reset_user_state : type u s. (u, s) state -> unit = fun t -> match t.kind with | Positions -> Positions.Builder.reset t.user_state (position t) | Sexp -> () | Sexp_with_positions -> Positions.Builder.reset t.user_state (position t) | Cst -> Buffer.clear t.user_state.token_buffer ;; let reset ?(pos = Positions.beginning_of_file) t = t.depth <- 0; t.automaton_state <- initial_state; t.block_comment_depth <- 0; t.ignoring_stack <- []; t.escaped_value <- 0; t.full_sexps <- 0; t.offset <- pos.offset; t.line_number <- pos.line; t.bol_offset <- pos.offset - pos.col; reset_user_state t; Buffer.clear t.atom_buffer ;; type context = | Sexp_comment | Sexp let is_ignoring state = match state.ignoring_stack with | _ :: _ -> true | [] -> false ;; let is_not_ignoring state = not (is_ignoring state) let context state = if is_not_ignoring state then Sexp else Sexp_comment let has_unclosed_paren state = state.depth > 0 let set_error_state state = state.automaton_state <- error_state module Error = Parse_error let automaton_state state = state.automaton_state end open Public let raise_error : type a b. (a, b) state -> _ = fun state ~at_eof reason -> set_error_state state; Parse_error.Private.raise reason { line = state.line_number ; col = state.offset - state.bol_offset ; offset = state.offset } ~at_eof ~atom_buffer:state.atom_buffer ;; type nonrec context = context = | Sexp_comment | Sexp let context = context type ('u, 's) action = ('u, 's) state -> char -> 's -> 's type ('u, 's) epsilon_action = ('u, 's) state -> 's -> 's let current_pos ?(delta = 0) state : Positions.pos = let offset = state.offset + delta in { line = state.line_number; col = offset - state.bol_offset; offset } ;; let set_automaton_state state x = state.automaton_state <- x let advance state = state.offset <- state.offset + 1 let advance_eol : type u s. (u, s) state -> unit = fun state -> let newline_offset = state.offset in state.offset <- newline_offset + 1; state.bol_offset <- state.offset; state.line_number <- state.line_number + 1; match state.kind with | Positions -> Positions.Builder.add_newline state.user_state ~offset:newline_offset | Sexp_with_positions -> Positions.Builder.add_newline state.user_state ~offset:newline_offset | _ -> () ;; let block_comment_depth state = state.block_comment_depth let add_token_char : type u s. (u, s) action = fun state char stack -> match state.kind with | Cst -> Buffer.add_char state.user_state.token_buffer char; stack | _ -> stack ;; let add_atom_char state c stack = Buffer.add_char state.atom_buffer c; stack ;; let add_quoted_atom_char state c stack = Buffer.add_char state.atom_buffer c; add_token_char state c stack ;; let check_new_sexp_allowed state = let is_single = match state.mode with | Single -> true | _ -> false in if is_single && state.full_sexps > 0 && is_not_ignoring state then raise_error state ~at_eof:false Too_many_sexps ;; let add_pos state ~delta = Positions.Builder.add state.user_state ~offset:(state.offset + delta) ;; let add_first_char : type u s. (u, s) action = fun state char stack -> check_new_sexp_allowed state; Buffer.add_char state.atom_buffer char; (* For non-quoted atoms, we save both positions at the end. We can always determine the start position from the end position and the atom length for non-quoted atoms. Doing it this way allows us to detect single characater atoms for which we need to save the position twice. *) stack ;; let eps_add_first_char_hash : type u s. (u, s) epsilon_action = fun state stack -> check_new_sexp_allowed state; Buffer.add_char state.atom_buffer '#'; stack ;; let start_quoted_string : type u s. (u, s) action = fun state _char stack -> check_new_sexp_allowed state; match state.kind with | Positions -> if is_not_ignoring state then add_pos state ~delta:0; stack | Sexp_with_positions -> if is_not_ignoring state then add_pos state ~delta:0; stack | Cst -> state.user_state.token_start_pos <- current_pos state; Buffer.add_char state.user_state.token_buffer '"'; stack | Sexp -> stack ;; let add_escaped state c stack = let c' = match c with | 'n' -> '\n' | 'r' -> '\r' | 'b' -> '\b' | 't' -> '\t' | '\\' | '\'' | '"' -> c | _ -> Buffer.add_char state.atom_buffer '\\'; c in Buffer.add_char state.atom_buffer c'; add_token_char state c stack ;; let eps_add_escaped_cr state stack = Buffer.add_char state.atom_buffer '\r'; stack ;; let dec_val c = Char.code c - Char.code '0' let hex_val c = match c with | '0' .. '9' -> Char.code c - Char.code '0' | 'a' .. 'f' -> Char.code c - Char.code 'a' + 10 | _ -> Char.code c - Char.code 'A' + 10 ;; let add_dec_escape_char state c stack = state.escaped_value <- (state.escaped_value * 10) + dec_val c; add_token_char state c stack ;; let add_last_dec_escape_char state c stack = let value = (state.escaped_value * 10) + dec_val c in state.escaped_value <- 0; if value > 255 then raise_error state ~at_eof:false Escape_sequence_out_of_range; Buffer.add_char state.atom_buffer (Char.chr value); add_token_char state c stack ;; let comment_add_last_dec_escape_char state c stack = let value = (state.escaped_value * 10) + dec_val c in state.escaped_value <- 0; if value > 255 then raise_error state ~at_eof:false Escape_sequence_out_of_range; add_token_char state c stack ;; let add_hex_escape_char state c stack = state.escaped_value <- (state.escaped_value lsl 4) lor hex_val c; add_token_char state c stack ;; let add_last_hex_escape_char state c stack = let value = (state.escaped_value lsl 4) lor hex_val c in state.escaped_value <- 0; Buffer.add_char state.atom_buffer (Char.chr value); add_token_char state c stack ;; let opening : type u s. (u, s) state -> char -> s -> s = fun state _char stack -> check_new_sexp_allowed state; state.depth <- state.depth + 1; match state.kind with | Positions -> if is_not_ignoring state then add_pos state ~delta:0; stack | Sexp -> if is_not_ignoring state then Open stack else stack | Sexp_with_positions -> if is_not_ignoring state then ( add_pos state ~delta:0; Open stack) else stack | Cst -> Open (current_pos state, stack) ;; let do_reset_positions state = Positions.Builder.reset state.user_state { line = state.line_number ; col = state.offset - state.bol_offset ; offset = state.offset } ;; let reset_positions : type u s. (u, s) state -> unit = fun state -> match state.kind with | Positions -> do_reset_positions state | Sexp_with_positions -> do_reset_positions state | Sexp -> () | Cst -> () ;; let toplevel_sexp_or_comment_added state stack ~delta = match state.mode with | Single | Many -> stack | Eager { got_sexp = f; _ } -> (* Modify the offset so that [f] get a state pointing to the end of the current s-expression *) let saved_offset = state.offset in state.offset <- state.offset + delta; let saved_full_sexps = state.full_sexps in (match f state stack with | exception e -> set_error_state state; raise e | stack -> (* This assert is not a full protection against the user mutating the state but it should catch most cases. *) assert (state.offset = saved_offset + delta && state.full_sexps = saved_full_sexps); state.offset <- saved_offset; reset_positions state; stack) ;; let is_top_level state = is_not_ignoring state && state.depth = 0 let comment_added_assuming_cst state stack ~delta = if is_top_level state then toplevel_sexp_or_comment_added state stack ~delta else stack ;; let maybe_pop_ignoring_stack state = match state.ignoring_stack with | inner_comment_depth :: _tl when inner_comment_depth > state.depth -> raise_error state ~at_eof:false Sexp_comment_without_sexp | inner_comment_depth :: tl when inner_comment_depth = state.depth -> state.ignoring_stack <- tl; true | _ -> false ;; let sexp_added : type u s. (u, s) state -> s -> delta:int -> s = fun state stack ~delta -> let is_comment = maybe_pop_ignoring_stack state in if is_top_level state then ( if not is_comment then state.full_sexps <- state.full_sexps + 1; if (not is_comment) || match state.kind with | Cst -> true | _ -> false then toplevel_sexp_or_comment_added state stack ~delta else stack) else stack ;; let rec make_list acc : Automaton_stack.t -> Automaton_stack.t = function | Empty -> assert false | Open stack -> Sexp (List acc, stack) | Sexp (sexp, stack) -> make_list (sexp :: acc) stack ;; let add_comment_to_stack_cst comment (stack : Automaton_stack.For_cst.t) : Automaton_stack.For_cst.t = match stack with | In_sexp_comment r -> In_sexp_comment { r with rev_comments = comment :: r.rev_comments } | _ -> T_or_comment (Comment comment, stack) ;; let add_sexp_to_stack_cst sexp : Automaton_stack.For_cst.t -> Automaton_stack.For_cst.t = function | In_sexp_comment { hash_semi_pos; rev_comments; stack } -> let comment : Cst.comment = Sexp_comment { hash_semi_pos; comments = List.rev rev_comments; sexp } in add_comment_to_stack_cst comment stack | stack -> T_or_comment (Sexp sexp, stack) ;; let rec make_list_cst end_pos acc : Automaton_stack.For_cst.t -> Automaton_stack.For_cst.t = function | T_or_comment (t, stack) -> make_list_cst end_pos (t :: acc) stack | Open (start_pos, stack) -> let sexp : Cst.t = List { loc = { start_pos; end_pos }; elements = acc } in add_sexp_to_stack_cst sexp stack | Empty | In_sexp_comment _ -> assert false ;; let closing : type u s. (u, s) state -> char -> s -> s = fun state _char stack -> if state.depth > 0 then ( let stack : s = match state.kind with | Positions -> (* Note we store end positions as inclusive in [Positions.t], so we use [delta:0], while in the [Cst] case we save directly the final ranges, so we use [delta:1]. *) if is_not_ignoring state then add_pos state ~delta:0; stack | Sexp -> if is_not_ignoring state then make_list [] stack else stack | Sexp_with_positions -> if is_not_ignoring state then ( add_pos state ~delta:0; make_list [] stack) else stack | Cst -> make_list_cst (current_pos state ~delta:1) [] stack in state.depth <- state.depth - 1; sexp_added state stack ~delta:1) else raise_error state ~at_eof:false Closed_paren_without_opened ;; let make_loc ?(delta = 0) state : Positions.range = { start_pos = state.user_state.token_start_pos; end_pos = current_pos state ~delta } ;; (* This is always called on the position exactly following the last character of a non-quoted atom *) let add_non_quoted_atom_pos state ~atom = let len = String.length atom in if len = 1 then Positions.Builder.add_twice state.user_state ~offset:(state.offset - 1) else ( add_pos state ~delta:(-len); add_pos state ~delta:(-1)) ;; let eps_push_atom : type u s. (u, s) epsilon_action = fun state stack -> let str = Buffer.contents state.atom_buffer in Buffer.clear state.atom_buffer; let stack : s = match state.kind with | Positions -> if is_not_ignoring state then add_non_quoted_atom_pos state ~atom:str; stack | Sexp -> if is_not_ignoring state then Sexp (Atom str, stack) else stack | Sexp_with_positions -> if is_not_ignoring state then ( add_non_quoted_atom_pos state ~atom:str; Sexp (Atom str, stack)) else stack | Cst -> let loc : Positions.range = { start_pos = current_pos state ~delta:(-String.length str) ; end_pos = current_pos state ~delta:0 } in let sexp : Cst.t = Atom { loc; atom = str; unescaped = Some str } in add_sexp_to_stack_cst sexp stack in sexp_added state stack ~delta:0 ;; let push_quoted_atom : type u s. (u, s) action = fun state _char stack -> let str = Buffer.contents state.atom_buffer in Buffer.clear state.atom_buffer; let stack : s = match state.kind with | Positions -> if is_not_ignoring state then add_pos state ~delta:0; stack | Sexp -> if is_not_ignoring state then Sexp (Atom str, stack) else stack | Sexp_with_positions -> if is_not_ignoring state then ( add_pos state ~delta:0; Sexp (Atom str, stack)) else stack | Cst -> let buf = state.user_state.token_buffer in Buffer.add_char buf '"'; let s = Buffer.contents buf in Buffer.clear buf; let sexp : Cst.t = Atom { loc = make_loc state ~delta:1; atom = str; unescaped = Some s } in add_sexp_to_stack_cst sexp stack in sexp_added state stack ~delta:1 ;; let start_sexp_comment : type u s. (u, s) action = fun state _char stack -> state.ignoring_stack <- state.depth :: state.ignoring_stack; match state.kind with | Cst -> In_sexp_comment { hash_semi_pos = current_pos state ~delta:(-1); rev_comments = []; stack } | _ -> stack ;; let start_block_comment : type u s. (u, s) state -> char -> s -> s = fun state char stack -> state.block_comment_depth <- state.block_comment_depth + 1; match state.kind with | Positions -> stack | Sexp -> stack | Sexp_with_positions -> stack | Cst -> if state.block_comment_depth = 1 then ( state.user_state.token_start_pos <- current_pos state ~delta:(-1); Buffer.add_char state.user_state.token_buffer '#'); Buffer.add_char state.user_state.token_buffer char; stack ;; let end_block_comment : type u s. (u, s) state -> char -> s -> s = fun state char stack -> state.block_comment_depth <- state.block_comment_depth - 1; match state.kind with | Positions -> stack | Sexp -> stack | Sexp_with_positions -> stack | Cst -> let buf = state.user_state.token_buffer in Buffer.add_char buf char; if state.block_comment_depth = 0 then ( let s = Buffer.contents buf in Buffer.clear buf; let comment : Cst.comment = Plain_comment { loc = make_loc state ~delta:1; comment = s } in let stack = add_comment_to_stack_cst comment stack in comment_added_assuming_cst state stack ~delta:1) else stack ;; let start_line_comment : type u s. (u, s) action = fun state char stack -> match state.kind with | Cst -> state.user_state.token_start_pos <- current_pos state; Buffer.add_char state.user_state.token_buffer char; stack | _ -> stack ;; let end_line_comment : type u s. (u, s) epsilon_action = fun state stack -> match state.kind with | Positions -> stack | Sexp -> stack | Sexp_with_positions -> stack | Cst -> let buf = state.user_state.token_buffer in let s = Buffer.contents buf in Buffer.clear buf; let comment : Cst.comment = Plain_comment { loc = make_loc state; comment = s } in let stack = add_comment_to_stack_cst comment stack in comment_added_assuming_cst state stack ~delta:0 ;; let eps_eoi_check : type u s. (u, s) epsilon_action = fun state stack -> if state.depth > 0 then raise_error state ~at_eof:true Unclosed_paren; if is_ignoring state then raise_error state ~at_eof:true Sexp_comment_without_sexp; if state.full_sexps = 0 then ( match state.mode with | Many | Eager { no_sexp_is_error = false; _ } -> () | Single | Eager { no_sexp_is_error = true; _ } -> raise_error state ~at_eof:true No_sexp_found_in_input); stack ;; parsexp-0.14.1/src/parser_automaton_internal.mli000066400000000000000000000104311376171340200220330ustar00rootroot00000000000000(** Internal bits used by the generated automaton, not part of the public API *) open! Import (*_ Interface exposed in [Parser_automaton] *) module Public : sig (** Internal state of the automaton *) type ('user_state, 'stack) state type ('u, 's) mode = | Single (** Parse a single s-expression *) | Many (** Parse a list of s-expressions *) | Eager of { got_sexp : ('u, 's) state -> 's -> 's (** Whether to consider no s-expression in the input as an error or not. The mutability is used in [Parsexp.Eager*.Lexbuf_consumer]. *) ; mutable no_sexp_is_error : bool } (** Gives back s-expressions as soon as they are found. *) type state_cst type ('u, 's) kind = (*_ [Positions] case needs no stack because the [state] type keeps track of [depth]. *) | Positions : (Positions.Builder.t, unit) kind | Sexp : (unit, Automaton_stack.t) kind | Sexp_with_positions : (Positions.Builder.t, Automaton_stack.t) kind | Cst : (state_cst, Automaton_stack.For_cst.t) kind val new_state : ?initial_pos:Positions.pos -> ('u, 's) mode -> ('u, 's) kind -> ('u, 's) state val reset : ?pos:Positions.pos -> _ state -> unit val positions : (Positions.Builder.t, _) state -> Positions.t val mode : ('u, 's) state -> ('u, 's) mode (** Number of characters fed to the parser *) val offset : _ state -> int (** Position in the text *) val line : _ state -> int val column : _ state -> int (** Whether there are some unclosed parentheses *) val has_unclosed_paren : ('u, 's) state -> bool val set_error_state : _ state -> unit (**/**) (*_ Only for converting errors to the old parser errors *) val atom_buffer : _ state -> Buffer.t (*_ For coverate tests *) val automaton_state : ('u, 's) state -> int end open Public val raise_error : _ state -> at_eof:bool -> Parse_error.Private.Reason.t -> _ type context = | Sexp_comment | Sexp val context : _ state -> context val set_automaton_state : ('u, 's) state -> int -> unit (** Advance the position counters. [advance_eol] is for when we read a newline character. *) val advance : ('u, 's) state -> unit val advance_eol : ('u, 's) state -> unit (** Number of opened #| *) val block_comment_depth : ('u, 's) state -> int type ('u, 's) action = ('u, 's) state -> char -> 's -> 's type ('u, 's) epsilon_action = ('u, 's) state -> 's -> 's (** Add a character to the atom buffer. [add_quoted_atom_char] does the same for quoted atoms *) val add_atom_char : _ action val add_quoted_atom_char : _ action (** Add a character that just follows a '\\' and the '\\' itself if necessary. *) val add_escaped : _ action (** [escaped_value <- escaped_value * 10 + (char - '0')] These functions make the assumption that [char] is between '0' and '9'. [add_dec_escape_char] also assumes the result doesn't overflow. The automaton definition must make sure this is the case. [add_last_dec_escape_char] also adds the resulting character to the atom buffer. *) val add_dec_escape_char : _ action val add_last_dec_escape_char : _ action (** Same but for quoted strings inside comments. Useful because it can fail. *) val comment_add_last_dec_escape_char : _ action (** Same as [add_dec_escape_char] but for hexadicemal escape sequences *) val add_hex_escape_char : _ action val add_last_hex_escape_char : _ action (** Ignore one more full sexp to come *) val start_sexp_comment : _ action (** Add the first char of an unquoted atom. *) val add_first_char : _ action val start_quoted_string : _ action (** Takes note of a control character in quoted atoms or the uninterpreted characters of comments, for which there is no corresponding [add_*] call (a backslash and the x in "\xff" or any character in a line comment). This does not get called for the opening ([start_quoted_string]) or closing ([push_quoted_atom]) quotes themselves. *) val add_token_char : _ action val opening : _ action val closing : _ action val push_quoted_atom : _ action val start_block_comment : _ action val end_block_comment : _ action val start_line_comment : _ action val end_line_comment : _ epsilon_action val eps_push_atom : _ epsilon_action val eps_add_first_char_hash : _ epsilon_action val eps_eoi_check : _ epsilon_action val eps_add_escaped_cr : _ epsilon_action parsexp-0.14.1/src/parser_intf.ml000066400000000000000000000136031376171340200167230ustar00rootroot00000000000000open! Import module A = Parser_automaton module type State = sig (** State of the parser *) type t (** Create a new parser state. [pos] is the initial position, it defaults to [{line=1;col=0;offset=0}]. *) val create : ?pos:Positions.pos -> unit -> t (** Reset the given parsing state. The following always succeed: {[ reset t ?pos; assert (t = create ?pos ()) ]} *) val reset : ?pos:Positions.pos -> t -> unit (** Number of characters fed to the parser *) val offset : t -> int (** Position in the text *) val line : t -> int val column : t -> int val position : t -> Positions.pos (** Prevent the state from receiving any more characters. Trying to feed more characters will result in an exception, unless the state is reset. *) val stop : t -> unit end module type Stack = Kind.Stack module type S = sig (** Values produced by the parser *) type parsed_value module State : State module Stack : Stack (** Feed one character to the parser. In case of error, it raises [Parse_error] *) val feed : State.t -> char -> Stack.t -> Stack.t (** Instruct the parser that the end of input was reached. In case of error, it raises [Parse_error] *) val feed_eoi : State.t -> Stack.t -> parsed_value (** {3 Convenience functions} *) val feed_string : State.t -> string -> Stack.t -> Stack.t val feed_substring : State.t -> string -> pos:int -> len:int -> Stack.t -> Stack.t val feed_bytes : State.t -> bytes -> Stack.t -> Stack.t val feed_subbytes : State.t -> bytes -> pos:int -> len:int -> Stack.t -> Stack.t (** {3 High-level functions} *) val parse_string : string -> (parsed_value, Parse_error.t) result val parse_string_exn : string -> parsed_value end module type S_eager = sig (** Same as [Parser] but gives back a s-expression as soon as they are found in the input. For instance you can use this function to parse a stream and stop at the first s-expression: {[ exception Got_sexp of Sexp.t let fetch_sexp stream = let module P = Parsexp.Sexp_parsing.Eager in let rec hot_loop state stream stack = match Stream.peek stream with | None -> P.feed_eoi state stack | Some char -> let stack = P.feed state char stack in Stream.junk stream; hot_loop state stream stack in let got_sexp state sexp = raise_notrace (Got_sexp sexp) in let count = Stream.count stream in let state = P.State.create ~f:got_sexp ~no_sexp_is_error:true in match hot_loop state stream P.Stack.empty with | () -> assert false | exception (Got_sexp sexp) -> (* This test is true if the s-expression includes the last character passed to the parser *) if P.State.offset state > Stream.count stream - count then Stream.junk stream; sexp ]} *) (** Values produces by the parser *) type parsed_value module State : sig include State module Read_only : sig (** Read-only handle to a parser state *) type t val offset : t -> int val line : t -> int val column : t -> int val position : t -> Positions.pos end (** [create ~f] create a new eager parser state. [f] will be called on each s-expression found. If [f] raises, then the parser is made unusable ([stop t] is invoked). [no_sexp_is_error] controls the behavior of the parse when the end of input is reached and no s-expression has been found. When [no_sexp_is_error] is [false] (the default) [feed_eoi] just returns [()], when it is [false] [feed_eoi] raises. In any case, if the end of input is reached while parsing an incomplete s-expression such as [(abc], error is raised. [f] must not save the read-only parser state it receives to access it after returning. It is unspecified what values it will read if it does so. *) val create : ?pos:Positions.pos -> ?no_sexp_is_error:bool (** default: false *) -> (Read_only.t -> parsed_value -> unit) -> t (**/**) val old_parser_cont_state : t -> Old_parser_cont_state.t (**/**) end module Stack : Stack val feed : State.t -> char -> Stack.t -> Stack.t val feed_eoi : State.t -> Stack.t -> unit val feed_string : State.t -> string -> Stack.t -> Stack.t val feed_substring : State.t -> string -> pos:int -> len:int -> Stack.t -> Stack.t val feed_bytes : State.t -> bytes -> Stack.t -> Stack.t val feed_subbytes : State.t -> bytes -> pos:int -> len:int -> Stack.t -> Stack.t module Lexbuf_consumer : sig type t val create : unit -> t (** Consume exactly one s-expression from the given lexing buffer *) val parse : t -> Lexing.lexbuf -> parsed_value (** Consume exactly one s-expression from the given lexing buffer. Returns [None] if the end of input is reached before seeing any s-expression. *) val parse_opt : t -> Lexing.lexbuf -> parsed_value option end end module Mode (Kind : Kind.S) = struct module type S = sig type parsed_value val mode : (Kind.state, Kind.Stack.t) A.mode val make_value : (Kind.state, Kind.Stack.t) A.state -> Kind.Stack.t -> parsed_value end end module Mode_eager (Kind : Kind.S) = struct module type S = sig type parsed_value val make_value : (Kind.state, Kind.Stack.t) A.state -> Kind.Stack.t -> parsed_value end end module type Parser = sig module Mode = Mode module Mode_eager = Mode_eager module type S = S module type S_eager = S_eager module type Stack = Stack module type State = State module Make (Kind : Kind.S) (Mode : Mode(Kind).S) : S with type parsed_value = Mode.parsed_value module Make_eager (Kind : Kind.S) (Mode : Mode_eager(Kind).S) : S_eager with type parsed_value = Mode.parsed_value end parsexp-0.14.1/src/parsexp.ml000066400000000000000000000073561376171340200161010ustar00rootroot00000000000000open! Import module type Conv = Conv.S module type Parser = Parser.S module type Eager_parser = Parser.S_eager module Conv_error = Conv_error module Of_sexp_error = Of_sexp_error module Old_parser_cont_state = Old_parser_cont_state module Parse_error = Parse_error module Positions = Positions module Cst = Cst module A = Parser_automaton exception Parse_error = Parse_error.Parse_error exception Of_sexp_error = Of_sexp_error.Of_sexp_error module Single = Parser.Make (Kind.Sexp) (struct type parsed_value = Sexp.t let mode = A.Single let make_value _ stack = Automaton_stack.get_single stack end) module Many = Parser.Make (Kind.Sexp) (struct type parsed_value = Sexp.t list let mode = A.Many let make_value _ stack = Automaton_stack.get_many stack end) module Eager = Parser.Make_eager (Kind.Sexp) (struct type parsed_value = Sexp.t let make_value _ stack = Automaton_stack.get_single stack end) module Single_and_positions = Parser.Make (Kind.Sexp_with_positions) (struct type parsed_value = Sexp.t * Positions.t let mode = A.Single let make_value state stack = Automaton_stack.get_single stack, A.positions state end) module Many_and_positions = Parser.Make (Kind.Sexp_with_positions) (struct type parsed_value = Sexp.t list * Positions.t let mode = A.Many let make_value state stack = Automaton_stack.get_many stack, A.positions state end) module Eager_and_positions = Parser.Make_eager (Kind.Sexp_with_positions) (struct type parsed_value = Sexp.t * Positions.t let make_value state stack = Automaton_stack.get_single stack, A.positions state end) module Single_just_positions = Parser.Make (Kind.Positions) (struct type parsed_value = Positions.t let mode = A.Single let make_value state () = A.positions state end) module Many_just_positions = Parser.Make (Kind.Positions) (struct type parsed_value = Positions.t let mode = A.Many let make_value state () = A.positions state end) module Eager_just_positions = Parser.Make_eager (Kind.Positions) (struct type parsed_value = Positions.t let make_value state () = A.positions state end) module Many_cst = Parser.Make (Kind.Cst) (struct type parsed_value = Cst.t_or_comment list let mode = A.Many let make_value _ stack = Automaton_stack.For_cst.get_many stack end) module Eager_cst = Parser.Make_eager (Kind.Cst) (struct type parsed_value = Cst.t_or_comment let make_value _ stack = match Automaton_stack.For_cst.get_many stack with | [ sexp ] -> sexp | _ -> assert false ;; end) type 'a id = 'a type sexp_list = Sexp.t list module Conv_single = Conv.Make (struct type 'a res = 'a type parsed_sexp = Sexp.t type chunk_to_conv = Sexp.t let apply_f x ~f = f x let find = Positions.find_sub_sexp_phys end) (Single) (Single_just_positions) module Conv_many = Conv.Make (struct type 'a res = 'a list type parsed_sexp = Sexp.t list type chunk_to_conv = Sexp.t let apply_f x ~f = List.rev (List.rev_map x ~f) let find = Positions.find_sub_sexp_in_list_phys end) (Many) (Many_just_positions) module Conv_many_at_once = Conv.Make (struct type 'a res = 'a type parsed_sexp = Sexp.t list type chunk_to_conv = Sexp.t list let apply_f x ~f = f x let find = Positions.find_sub_sexp_in_list_phys end) (Many) (Many_just_positions) module Private = struct module Automaton_stack = Automaton_stack module Parser_automaton = Parser_automaton end parsexp-0.14.1/src/parsexp.mli000066400000000000000000000000541376171340200162360ustar00rootroot00000000000000include Parsexp_intf.Parsexp (** @inline *) parsexp-0.14.1/src/parsexp_intf.ml000066400000000000000000000044521376171340200171130ustar00rootroot00000000000000(** Parsing of s-expression *) open! Import module type Parsexp = sig module Conv_error = Conv_error module Of_sexp_error = Of_sexp_error module Old_parser_cont_state = Old_parser_cont_state module Parse_error = Parse_error module Positions = Positions module Cst = Cst module type Conv = Conv.S module type Parser = Parser.S module type Eager_parser = Parser.S_eager (** Exception raised in case of a conversion error *) exception Of_sexp_error of Of_sexp_error.t (** Exception raised in case of a parsing error *) exception Parse_error of Parse_error.t module Single : Parser with type parsed_value = Sexp.t module Many : Parser with type parsed_value = Sexp.t list module Eager : Eager_parser with type parsed_value = Sexp.t module Single_and_positions : Parser with type parsed_value = Sexp.t * Positions.t module Many_and_positions : Parser with type parsed_value = Sexp.t list * Positions.t module Eager_and_positions : Eager_parser with type parsed_value = Sexp.t * Positions.t module Single_just_positions : Parser with type parsed_value = Positions.t module Many_just_positions : Parser with type parsed_value = Positions.t module Eager_just_positions : Eager_parser with type parsed_value = Positions.t module Many_cst : Parser with type parsed_value = Cst.t_or_comment list module Eager_cst : Eager_parser with type parsed_value = Cst.t_or_comment (*_ These type synonyms are introduced because ocaml <4.06 do not support destructive substitutions with `type 'a t1 = t2` or `type t1 = 'a t2`. *) type 'a id = 'a type sexp_list = Sexp.t list module Conv_single : Conv with type 'a res := 'a id and type parsed_sexp := Sexp.t and type chunk_to_conv := Sexp.t module Conv_many : Conv with type 'a res := 'a list and type parsed_sexp := sexp_list and type chunk_to_conv := Sexp.t module Conv_many_at_once : Conv with type 'a res := 'a id and type parsed_sexp := sexp_list and type chunk_to_conv := sexp_list (*_ For tests *) (*_ See the Jane Street Style Guide for an explanation of [Private] submodules: https://opensource.janestreet.com/standards/#private-submodules *) module Private : sig module Automaton_stack = Automaton_stack module Parser_automaton = Parser_automaton end end parsexp-0.14.1/src/positions.ml000066400000000000000000000404221376171340200164350ustar00rootroot00000000000000(* This module builds a buffer of "instructions", in order to represent a compact sequence of delimiting positions and newlines. The parser stores the positions of each: - newline - beginning of atom - end of atom - left parenthesis - right parenthesis Instructions are encoded as a sequence bits. The next instruction is determined by looking at the next few bits: - bit 0 represents a saved position followed by an offset increment - bits 10 represent an offset increment - bits 110 are followed by 5 bits of payload. The 5-bit payloads of any subsequent 110- instructions are squashed to form a number (least significant 5-bit chunk first). This number + 5 represents an offset increment - bits 1110 marks the beginning of a new line (with offset incremented) - bits 1111 represent a position saved twice followed by an offset increment For instance let's consider the following sexp: {[ {| (abc "foo bar" ) |} ]} the sequence of instructions to record in order to reconstruct the position of any sub-sexp is: - 0 save position and advance 1: first '(' - 0 save position and advance 1: start of "abc" - 10 advance 1 - 0 save position and advance 1: end of "abc" - 1110 newline - 1100_0001 advance 6 - 0 save position and advance 1: start of "foo\n bar" - 10 advance 1 - 10 advance 1 - 10 advance 1 - 1110 newline - 1100_0000 advance 5 - 0 save position and advance 1: end of "foo\n bar" - 1110 newline - 0 save position and advance 1: last ')' (we save the position after the closing parenthesis) The total sequence is 42 bits, so we need 6 bytes to store it The sequence of bits is encoded as a sequence of 16-bit values, where the earlier bits are most significant. Note that the parser stores the end positions as inclusive. This way only single character atoms require a double positions. If we were storing end positions as exclusive, we would need double positions for [)(] and [a(], which are likely to be frequent in s-expressions printed with the non [_hum] printer. We expect single character atoms to be less frequent so it makes sense to penalize them instead. *) open! Import type pos = { line : int ; col : int ; offset : int } [@@deriving_inline sexp_of] let sexp_of_pos = (function | { line = v_line; col = v_col; offset = v_offset } -> let bnds = [] in let bnds = let arg = sexp_of_int v_offset in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "offset"; arg ] :: bnds in let bnds = let arg = sexp_of_int v_col in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "col"; arg ] :: bnds in let bnds = let arg = sexp_of_int v_line in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "line"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List bnds : pos -> Ppx_sexp_conv_lib.Sexp.t) ;; [@@@end] let compare_pos = Caml.compare let beginning_of_file = { line = 1; col = 0; offset = 0 } let shift_pos pos ~cols = { pos with col = pos.col + cols; offset = pos.offset + cols } type range = { start_pos : pos ; end_pos : pos } [@@deriving_inline sexp_of] let sexp_of_range = (function | { start_pos = v_start_pos; end_pos = v_end_pos } -> let bnds = [] in let bnds = let arg = sexp_of_pos v_end_pos in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "end_pos"; arg ] :: bnds in let bnds = let arg = sexp_of_pos v_start_pos in Ppx_sexp_conv_lib.Sexp.List [ Ppx_sexp_conv_lib.Sexp.Atom "start_pos"; arg ] :: bnds in Ppx_sexp_conv_lib.Sexp.List bnds : range -> Ppx_sexp_conv_lib.Sexp.t) ;; [@@@end] let compare_range = Caml.compare let make_range_incl ~start_pos ~last_pos = { start_pos; end_pos = shift_pos last_pos ~cols:1 } ;; module Chunk : sig (** Represents an array of [length/2] signed 16-bit values *) type t (** Length in bytes. *) val length : int val alloc : unit -> t (** [get16 ~pos] and [set16 ~pos] manipulate the [pos/2]th stored value. [pos] must be even. [set16 x] only uses the 16 least significant bits of [x]. *) val get16 : t -> pos:int -> int val set16 : t -> pos:int -> int -> unit end = struct type t = bytes (* OCaml strings always waste two bytes at the end, so we take a power of two minus two to be sure we don't waste space. *) let length = 62 let alloc () = Bytes.create length let get16 = Bytes0.get16 let set16 = Bytes0.set16 (* If we want to make a [Positions.t] serializable: {[ external bswap16 : int -> int = "%bswap16";; let get16 = if Caml.Sys.arch_big_endian then fun buf ~pos -> get16 buf ~pos |> bswap16 else get16 let set16 = if Caml.Sys.arch_big_endian then fun buf ~pos x -> set16 buf ~pos (bswap16 x) else set16 ]} *) end type t_ = { chunks : Chunk.t list ; (* [num_bytes * 8 + extra_bits] is the number of bits stored in [chunks]. The last [extra_bits] bits will be stored as the *least* significant bits of the appropriate pair of bytes of the last chunk. *) num_bytes : int ; extra_bits : int ; initial_pos : pos } type t = t_ Lazy.t let memory_footprint_in_bytes (lazy t) = let num_fields = 4 in let header_words = 1 in let word_bytes = match Sys.word_size with | 32 -> 4 | 64 -> 8 | _ -> assert false in let chunk_words = let div_ceil a b = (a + b - 1) / b in let n = div_ceil (Chunk.length + 1 (* NUL terminating bytes *) + 1 (* number of wasted bytes to fill a word *)) word_bytes in n + header_words in let pos_fields = 3 in let pos_words = header_words + pos_fields in let list_cons_words = header_words + 2 in (header_words + num_fields + pos_words + (List.length t.chunks * (chunk_words + list_cons_words))) * word_bytes ;; module Builder = struct type t = { mutable chunk : Chunk.t ; mutable chunk_pos : int ; mutable filled_chunks : Chunk.t list (* Filled chunks in reverse order *) ; mutable offset : int (* Offset of the last saved position or newline plus one, or [initial_pos] *) ; mutable int_buf : int (* the [num_bits] least significant bits of [int_buf] are the bits not yet pushed to [chunk]. *) ; mutable num_bits : int (* number of bits stored in [int_buf] *) ; mutable initial_pos : pos } let invariant t = assert (t.chunk_pos >= 0 && t.chunk_pos <= Chunk.length); assert (t.offset >= t.initial_pos.offset); assert (t.num_bits <= 15) ;; let check_invariant = false let invariant t = if check_invariant then invariant t let create ?(initial_pos = beginning_of_file) () = { chunk = Chunk.alloc () ; chunk_pos = 0 ; filled_chunks = [] ; offset = initial_pos.offset ; int_buf = 0 ; num_bits = 0 ; initial_pos } ;; let reset t (pos : pos) = (* We need a new chunk as [contents] keeps the current chunk in the closure of the lazy value. *) t.chunk <- Chunk.alloc (); t.chunk_pos <- 0; t.filled_chunks <- []; t.offset <- pos.offset; t.int_buf <- 0; t.num_bits <- 0; t.initial_pos <- pos ;; let[@inlined never] alloc_new_chunk t = t.filled_chunks <- t.chunk :: t.filled_chunks; t.chunk <- Chunk.alloc (); t.chunk_pos <- 0 ;; let add_uint16 t n = if t.chunk_pos = Chunk.length then alloc_new_chunk t; Chunk.set16 t.chunk ~pos:t.chunk_pos n ;; let add_bits t n ~num_bits = let int_buf = (t.int_buf lsl num_bits) lor n in let num_bits = t.num_bits + num_bits in t.int_buf <- int_buf; if num_bits < 16 then t.num_bits <- num_bits else ( let num_bits = num_bits - 16 in t.num_bits <- num_bits; add_uint16 t (int_buf lsr num_bits); t.chunk_pos <- t.chunk_pos + 2 (* no need to clear the bits of int_buf we just wrote, as further set16 will ignore these extra bits. *)) ;; let contents t = (* Flush the current [t.int_buf] *) add_uint16 t t.int_buf; let rev_chunks = t.chunk :: t.filled_chunks in let chunk_pos = t.chunk_pos in let extra_bits = t.num_bits in let initial_pos = t.initial_pos in lazy { chunks = List.rev rev_chunks ; num_bytes = ((List.length rev_chunks - 1) * Chunk.length) + chunk_pos ; extra_bits ; initial_pos } ;; let long_shift t n = let n = ref (n - 5) in while !n > 0 do add_bits t (0b1100_0000 lor (!n land 0b0001_1111)) ~num_bits:8; n := !n lsr 5 done ;; (* precondition: n >= 5 *) let[@inlined never] add_gen_slow t n ~instr ~instr_bits = long_shift t n; add_bits t instr ~num_bits:instr_bits ;; let shift4 = 0b10_10_10_10 let[@inline always] add_gen t ~offset ~instr ~instr_bits = invariant t; let n = offset - t.offset in t.offset <- offset + 1; match n with | 0 | 1 | 2 | 3 | 4 -> let num_bits = (n lsl 1) + instr_bits in add_bits t ((shift4 lsl instr_bits) lor instr land ((1 lsl num_bits) - 1)) ~num_bits | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 -> add_bits t (((0b1100_0000 lor (n - 5)) lsl instr_bits) lor instr) ~num_bits:(8 + instr_bits) | _ -> if n < 0 then invalid_arg "Parsexp.Positions.add_gen"; add_gen_slow t n ~instr ~instr_bits ;; let add t ~offset = add_gen t ~offset ~instr:0b0 ~instr_bits:1 let add_twice t ~offset = add_gen t ~offset ~instr:0b1111 ~instr_bits:4 let add_newline t ~offset = add_gen t ~offset ~instr:0b1110 ~instr_bits:4 end type positions = t module Iterator : sig type t val create : positions -> t exception No_more (* [advance t ~skip] ignores [skip] saved positions and returns the next saved position. Raises [No_more] when reaching the end of the position set. *) val advance_exn : t -> skip:int -> pos end = struct type t = { mutable chunk : Chunk.t ; mutable chunks : Chunk.t list ; (* [num_bytes * 8 + extra_bits] is the number of bits available from [instr_pos] in [chunk :: chunks]. *) mutable num_bytes : int ; extra_bits : int ; mutable instr_pos : int (* position in [chunk] *) ; mutable offset : int ; mutable line : int ; mutable bol : int ; mutable int_buf : int ; mutable num_bits : int (* Number of bits not yet consumed in [int_buf] *) ; mutable pending : pos option } let create ((lazy p) : positions) = match p.chunks with | [] -> assert false | chunk :: chunks -> { chunk ; chunks ; num_bytes = p.num_bytes ; extra_bits = p.extra_bits ; instr_pos = 0 ; offset = p.initial_pos.offset ; line = p.initial_pos.line ; bol = p.initial_pos.offset - p.initial_pos.col ; int_buf = 0 ; num_bits = 0 ; pending = None } ;; exception No_more let no_more () = raise_notrace No_more let[@inlined never] fetch_chunk t = match t.chunks with | [] -> assert false | chunk :: chunks -> t.instr_pos <- 0; t.num_bytes <- t.num_bytes - Chunk.length; t.chunk <- chunk; t.chunks <- chunks ;; let fetch t = if t.instr_pos > t.num_bytes then no_more (); if t.instr_pos = Chunk.length then fetch_chunk t; let v = Chunk.get16 t.chunk ~pos:t.instr_pos in let added_bits = if t.instr_pos = t.num_bytes then t.extra_bits else 16 in t.int_buf <- (t.int_buf lsl added_bits) lor (v land ((1 lsl added_bits) - 1)); t.num_bits <- t.num_bits + added_bits; t.instr_pos <- t.instr_pos + 2 ;; let next_instruction_bits t ~num_bits = if t.num_bits < num_bits then ( fetch t; if t.num_bits < num_bits then no_more ()); let n = (t.int_buf lsr (t.num_bits - num_bits)) land ((1 lsl num_bits) - 1) in t.num_bits <- t.num_bits - num_bits; n ;; (* [offset_shift] and [offset_shift_num_bits] encode the offset number specified by the immediately preceding [110] instructions. *) let rec advance t ~skip ~offset_shift ~offset_shift_num_bits = match next_instruction_bits t ~num_bits:1 with | 0 -> (* bit seq 0 -> new item *) let offset = t.offset + offset_shift in t.offset <- offset + 1; if skip = 0 then { line = t.line; col = offset - t.bol; offset } else advance t ~skip:(skip - 1) ~offset_shift:0 ~offset_shift_num_bits:0 | _ -> (match next_instruction_bits t ~num_bits:1 with | 0 -> (* bit seq 10 -> shift *) t.offset <- t.offset + offset_shift + 1; advance t ~skip ~offset_shift:0 ~offset_shift_num_bits:0 | _ -> (match next_instruction_bits t ~num_bits:1 with | 0 -> (* bit seq 110 -> long shift *) let n = next_instruction_bits t ~num_bits:5 in let offset_shift = if offset_shift_num_bits = 0 then 5 else offset_shift in advance t ~skip ~offset_shift:(offset_shift + (n lsl offset_shift_num_bits)) ~offset_shift_num_bits:(offset_shift_num_bits + 5) | _ -> (match next_instruction_bits t ~num_bits:1 with | 0 -> (* bit seq 1110 -> newline *) t.offset <- t.offset + offset_shift + 1; t.bol <- t.offset; t.line <- t.line + 1; advance t ~skip ~offset_shift:0 ~offset_shift_num_bits:0 | _ -> (* bit seq 1111 -> 2 new items *) let offset = t.offset + offset_shift in t.offset <- offset + 1; if skip <= 1 then ( let pos = { line = t.line; col = offset - t.bol; offset } in if skip = 0 then t.pending <- Some pos; pos) else advance t ~skip:(skip - 2) ~offset_shift:0 ~offset_shift_num_bits:0))) ;; let advance_exn t ~skip = match t.pending with | Some pos -> t.pending <- None; if skip = 0 then pos else advance t ~skip:(skip - 1) ~offset_shift:0 ~offset_shift_num_bits:0 | None -> advance t ~skip ~offset_shift:0 ~offset_shift_num_bits:0 ;; end let find t a b = if a < 0 || b <= a then invalid_arg "Parsexp.Positions.find"; let iter = Iterator.create t in try let start_pos = Iterator.advance_exn iter ~skip:a in let last_pos = Iterator.advance_exn iter ~skip:(b - a - 1) in make_range_incl ~start_pos ~last_pos with | Iterator.No_more -> failwith "Parsexp.Position.find" ;; let rec sub_sexp_count (sexp : Sexp.t) = match sexp with | Atom _ -> 1 | List l -> List.fold_left l ~init:1 ~f:(fun acc x -> acc + sub_sexp_count x) ;; module Sexp_search = struct exception Found of int let rec loop ~sub index (sexp : Sexp.t) = if sexp == sub then raise_notrace (Found index) else ( match sexp with | Atom _ -> index + 2 | List l -> let index = loop_list ~sub (index + 1) l in index + 1) and loop_list ~sub index (sexps : Sexp.t list) = List.fold_left sexps ~init:index ~f:(loop ~sub) ;; let finalize t ~sub a = let b = a + (sub_sexp_count sub * 2) - 1 in Some (find t a b) ;; let find_sub_sexp_phys t sexp ~sub = match loop ~sub 0 sexp with | (_ : int) -> None | exception Found n -> finalize t ~sub n ;; let find_sub_sexp_in_list_phys t sexps ~sub = match loop_list ~sub 0 sexps with | (_ : int) -> None | exception Found n -> finalize t ~sub n ;; end let find_sub_sexp_phys = Sexp_search.find_sub_sexp_phys let find_sub_sexp_in_list_phys = Sexp_search.find_sub_sexp_in_list_phys let to_list t = let iter = Iterator.create t in let rec loop acc = match Iterator.advance_exn iter ~skip:0 with | exception Iterator.No_more -> List.rev acc | pos -> loop (pos :: acc) in loop [] ;; let to_array t = to_list t |> Array.of_list let compare t1 t2 = Caml.compare (to_array t1) (to_array t2) let sexp_of_t t = sexp_of_array sexp_of_pos (to_array t) parsexp-0.14.1/src/positions.mli000066400000000000000000000104241376171340200166050ustar00rootroot00000000000000(** Compact set of positions *) open! Import (** A [t] value represent a sequence of positions. The focus is on small memory footprint. Given a s-expression and a sequence of positions, one can reconstruct the location of every sub s-expression. This is used to report location informations without having to annotate every node in the s-expression during parsing. The s-expression parser saves the positions of each opening and closing parentheses as well as the positions of the first and last character of each atom. Note that a [t] can hold the same given positions no more than twice. The parser stores the same position twice for non-quoted single character atoms. *) type t [@@deriving_inline sexp_of, compare] include sig [@@@ocaml.warning "-32"] val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t val compare : t -> t -> int end [@@ocaml.doc "@inline"] [@@@end] (** Represent a position in the input *) type pos = { line : int (** Line number. The first line has number [1]. *) ; col : int (** Column number. The first column has number [0]. *) ; offset : int (** Number of bytes from the beginning of the input. The first byte has offset [0]. *) } [@@deriving_inline sexp_of, compare] include sig [@@@ocaml.warning "-32"] val sexp_of_pos : pos -> Ppx_sexp_conv_lib.Sexp.t val compare_pos : pos -> pos -> int end [@@ocaml.doc "@inline"] [@@@end] val beginning_of_file : pos val shift_pos : pos -> cols:int -> pos (** Range of positions, as reported in error messages. We follow the lexing conventions of OCaml, i.e. [start_pos] points to the first character and [end_pos] points to the position just after the last character. This allow for instance to represent empty ranges with [start_pos = end_pos]. *) type range = { start_pos : pos ; end_pos : pos } [@@deriving_inline sexp_of, compare] include sig [@@@ocaml.warning "-32"] val sexp_of_range : range -> Ppx_sexp_conv_lib.Sexp.t val compare_range : range -> range -> int end [@@ocaml.doc "@inline"] [@@@end] (** Make a range from two positions where both positions are inclusive, i.e. [start_pos] points to the first character and [end_pos] points to the last one. The character at [last_pos] is assumed to not be a newline character. *) val make_range_incl : start_pos:pos -> last_pos:pos -> range module Builder : sig type positions type t val create : ?initial_pos:pos -> unit -> t (** [add], [add_twice] and [add_newline] must be called with strictly increasing [offset] values. *) (** int is absolute offset of the position *) val add : t -> offset:int -> unit val add_twice : t -> offset:int -> unit (** int is absolute offset of the newline character *) val add_newline : t -> offset:int -> unit val contents : t -> positions val reset : t -> pos -> unit end with type positions := t (** Build the list of all positions in [t]. *) val to_list : t -> pos list (** Build the array of all positions in [t]. *) val to_array : t -> pos array (** [find t start stop] returns the range of positions starting at position with index [start] in [t] and ending at position with index [stop]. [find t i j] is the same as: {[ let a = to_array t in make_range_incl ~start_pos:a.(i) ~last_pos:a.(j) ]} but more efficient. *) val find : t -> int -> int -> range (** [find_sub_sexp_phys t sexp ~sub] looks for [sub] in [sexp] and return its location, assuming [t] is the sequence of positions associated with [sexp]. Comparison is done using physical equality. *) val find_sub_sexp_phys : t -> Sexp.t -> sub:Sexp.t -> range option val find_sub_sexp_in_list_phys : t -> Sexp.t list -> sub:Sexp.t -> range option (** Returns how much memory is used by [t] *) val memory_footprint_in_bytes : t -> int (** API for iterating over positions in an efficient way *) module Iterator : sig type positions = t type t val create : positions -> t (** Exception raised when the iterator has reached the end of the sequence. *) exception No_more (** [advance t ~skip] skips the next [skip] positions in the sequence, advance to the next position and return it. Raises [No_more] when reaching the end of the position set. *) val advance_exn : t -> skip:int -> pos end with type positions := t parsexp-0.14.1/test/000077500000000000000000000000001376171340200142425ustar00rootroot00000000000000parsexp-0.14.1/test/dune000066400000000000000000000002601376171340200151160ustar00rootroot00000000000000(library (name parsexp_test) (libraries base stdio parsexp gen_parsexp_lib expect_test_helpers_core) (preprocess (pps ppx_jane -allow-unannotated-ignores))) (ocamllex lexer)parsexp-0.14.1/test/import.ml000066400000000000000000000024351376171340200161120ustar00rootroot00000000000000include Base include Stdio include Expect_test_helpers_core include Parsexp module Automaton_stack = Private.Automaton_stack let dummy_sexplib_error () = (* a hack to raise an arbitrary Parse_error *) let _ = Sexplib.Sexp.of_string ")" in assert false ;; let sexplib_sexps_of_string str : Sexp.t list = (* [ws_buf] must contain a single space character *) let feed_end_of_input ~this_parse ~ws_buf = (* When parsing atoms, the incremental parser cannot tell whether it is at the end until it hits whitespace. We therefore feed it one space to determine whether it is finished. *) match this_parse ~pos:0 ~len:1 ws_buf with | Sexplib.Sexp.Done (sexp, _) -> Ok sexp | Cont (cont_state, _) -> Error cont_state in let of_string_bigstring this_parse ws_buf str = let rec loop parse_pos = match this_parse str ~parse_pos with | Sexplib.Sexp.Done (sexp, parse_pos) -> sexp :: loop (Some parse_pos) | Cont (_, this_parse) -> (match feed_end_of_input ~this_parse ~ws_buf with | Ok sexp -> [ sexp ] | Error Sexplib.Sexp.Cont_state.Parsing_toplevel_whitespace -> [] | Error _ -> dummy_sexplib_error ()) in loop None in of_string_bigstring (fun x ~parse_pos -> Sexplib.Sexp.parse ?parse_pos x) " " str ;; parsexp-0.14.1/test/lexer.mll000066400000000000000000000006001376171340200160630ustar00rootroot00000000000000rule assoc sexp_parser = parse | eof { [] } | ' '* '\n' { assoc sexp_parser lexbuf } | '#' [^'\n']* '\n' { assoc sexp_parser lexbuf } | (['a'-'z']+ as key) ' '* '=' ' '* { let value = Parsexp.Eager.Lexbuf_consumer.parse sexp_parser lexbuf in eol lexbuf; (key, value) :: assoc sexp_parser lexbuf } and eol = parse | ' '* '\n' { () } parsexp-0.14.1/test/test_coverage.ml000066400000000000000000000455211376171340200174350ustar00rootroot00000000000000open! Import open Gen_parsexp_lib.Automaton (* For the coverage tests, we write as input a list of string and expected s-expression. Each s-expression is parsed with both parsexp and sexplib and compared to the expected s-expression. We assert that both parsers agree with the expected result. While parsing, we record visited transition. At the end of all tests, we check that the full table is visited. These tests don't check that comments and sexps with layout are parsed correctly, they only test the main parser. *) (* Compute the classes of character that give the same transition whatever the state. *) module Char_class = struct open Table module T = struct type t = transition or_error list [@@deriving compare, sexp_of, hash] end let compute (table : Table.t) = let transitions_to_class = Hashtbl.create (module T) in let classes = Array.create 0 ~len:256 in for i = 0 to 255 do let transitions = List.init State.count ~f:(fun state -> table.transitions.((state * 256) + i)) in let cl = Hashtbl.find_or_add transitions_to_class transitions ~default:(fun () -> Hashtbl.length transitions_to_class) in classes.(i) <- cl done; Hashtbl.length transitions_to_class, classes ;; let count, class_table = compute table let () = assert (count <= 256) let of_char ch = class_table.(Char.to_int ch) let%expect_test "display char classes" = let classes = Array.to_list class_table in for cl = 0 to count - 1 do let groups = List.filter_mapi classes ~f:(fun i cl' -> Option.some_if (cl = cl') i) |> List.group ~break:(fun a b -> a + 1 <> b) |> List.map ~f:(function | [] -> assert false | [ x ] -> Printf.sprintf "%C" (Char.of_int_exn x) | x :: l -> Printf.sprintf "%C..%C" (Char.of_int_exn x) (Option.value (List.last l) ~default:x |> Char.of_int_exn)) in let open Caml.Format in printf "@[<10>class %2d:%t@]@." cl (fun ppf -> List.iter groups ~f:(fprintf ppf "@ %s")) done; [%expect {| class 0: '\000'..'\b' '\011' '\014'..'\031' '!' '$'..'\'' '*'..'/' ':' '<'..'@' 'G'..'[' ']'..'`' 'g'..'w' 'y'..'{' '}'..'\255' class 1: '\t' ' ' class 2: '\n' class 3: '\012' class 4: '\r' class 5: '"' class 6: '#' class 7: '(' class 8: ')' class 9: '0'..'9' class 10: ';' class 11: 'A'..'F' 'a'..'f' class 12: '\\' class 13: 'x' class 14: '|' |}] ;; end module A = Private.Parser_automaton type 'a result = | Sexp of 'a | Error [@@deriving compare, sexp_of] let transition_count = State.count * Char_class.count let transition_seen = Array.create false ~len:transition_count let transition_eoi_seen = Array.create false ~len:State.count let feed state char stack = transition_seen.((A.automaton_state state * Char_class.count) + Char_class.of_char char) <- true; A.feed state char stack ;; let feed_eoi state stack = transition_eoi_seen.(A.automaton_state state) <- true; A.feed_eoi state stack ;; let parse_string_gen mode s = let state = A.new_state mode Sexp in let len = String.length s in let rec loop pos stack = if pos = len then feed_eoi state stack else ( let stack = feed state s.[pos] stack in loop (pos + 1) stack) in loop 0 Automaton_stack.empty ;; let parse_string s = Automaton_stack.get_single (parse_string_gen Single s) let parse_string_many s = Automaton_stack.get_many (parse_string_gen Many s) let cases_where_sexplib_disagree_with_itself = ref [] let add_to_list cell x = cell := x :: !cell let test_one_case_dealing_with_a_single_sexp (str, expected) = let parsexp = match parse_string str with | sexp -> Ok sexp | exception Parse_error.Parse_error error -> Error error in let matches_expected = match parsexp, expected with | Ok a, Sexp b -> Sexp.equal a b | Error _, Error -> true | _ -> false in if not matches_expected then Caml.Format.printf "round-trip failure:@.input: %S@.expected: %a@.got: %a@.@." str Sexp.pp_hum [%sexp (expected : Sexp.t result)] Sexp.pp_hum [%sexp (parsexp : (Sexp.t, Parse_error.t) Result.t)]; let sexplib = match Sexplib.Sexp.of_string str with | sexp -> Ok sexp | exception exn -> Error exn in let matches_sexplib = match parsexp, sexplib with | Ok a, Ok b -> Sexp.equal a b | Error _, Error _ -> true | _ -> false in if not matches_sexplib then Caml.Format.printf "parsexp and sexplib disagree:@.input: %S@.parsexp: %a@.sexplib: %a@.@." str Sexp.pp_hum [%sexp (parsexp : (Sexp.t, Parse_error.t) Result.t)] Sexp.pp_hum [%sexp (sexplib : (Sexp.t, exn) Result.t)]; let sexplib_lexer = match Sexplib.Sexp.scan_sexps (Lexing.from_string str) with | [ sexp ] -> Ok sexp | exception exn -> Error exn | [] | _ :: _ :: _ -> dummy_sexplib_error () in let matches = match sexplib, sexplib_lexer with | Ok a, Ok b -> Sexp.equal a b | Error _, Error _ -> true | _ -> false in if not matches then add_to_list cases_where_sexplib_disagree_with_itself (str, sexplib, sexplib_lexer) ;; let test_one_case_dealing_with_many_sexps (str, expected) = let parsexp = match parse_string_many str with | sexps -> Ok sexps | exception Parse_error.Parse_error error -> Error error in let matches_expected = match parsexp, expected with | Ok a, Sexp b -> [%compare.equal: Sexp.t list] a b | Error _, Error -> true | _ -> false in if not matches_expected then Caml.Format.printf "round-trip failure:@.input: %S@.expected: %a@.got: %a@.@." str Sexp.pp_hum [%sexp (expected : Sexp.t list result)] Sexp.pp_hum [%sexp (parsexp : (Sexp.t list, Parse_error.t) Result.t)]; let sexplib = match sexplib_sexps_of_string str with | sexps -> Ok sexps | exception (Sexplib.Sexp.Parse_error _ as exn) -> Error exn in let matches_expected = match sexplib, expected with | Ok a, Sexp b -> [%compare.equal: Sexp.t list] a b | Error _, Error -> true | _ -> false in if not matches_expected then Caml.Format.printf "sexplib does not match expected:@.input: %S@.expected: %a@.sexplib: %a@.@." str Sexp.pp_hum [%sexp (expected : Sexp.t list result)] Sexp.pp_hum [%sexp (sexplib : (Sexp.t list, exn) Result.t)] ;; let witness_for_class cl = let rec loop i = if i = 256 then raise Caml.Not_found; if Char_class.of_char (Char.of_int_exn i) = cl then Char.of_int_exn i else loop (i + 1) in let ch = loop 0 in match ch with | '\000' -> if Char_class.of_char 'z' = cl then 'z' else ch | _ -> ch ;; let some_cases : (string * Sexp.t result) list = [ "foo", Sexp (Atom "foo") ; " foo", Sexp (Atom "foo") ; " zoo", Sexp (Atom "zoo") ; " 123", Sexp (Atom "123") ; "(foo bar)", Sexp (List [ Atom "foo"; Atom "bar" ]) ; "\\", Sexp (Atom "\\") ; "|", Sexp (Atom "|") ; "#", Sexp (Atom "#") ; "; foo\nx", Sexp (Atom "x") ; "; foo\r\nx", Sexp (Atom "x") ; "(# )", Sexp (List [ Atom "#" ]) ; "##", Sexp (Atom "##") ; "#|x|#z", Sexp (Atom "z") ; "(#\n)", Sexp (List [ Atom "#" ]) ; "(#\r\n)", Sexp (List [ Atom "#" ]) ; "#x", Sexp (Atom "#x") ; "(#())", Sexp (List [ Atom "#"; List [] ]) ; "(#)", Sexp (List [ Atom "#" ]) ; "(#\"x\")", Sexp (List [ Atom "#"; Atom "x" ]) ; "#; x z", Sexp (Atom "z") ; "foo#", Sexp (Atom "foo#") ; "(foo# )", Sexp (List [ Atom "foo#" ]) ; "(foo#\n)", Sexp (List [ Atom "foo#" ]) ; "(foo#\r\n)", Sexp (List [ Atom "foo#" ]) ; "foo#x", Sexp (Atom "foo#x") ; "foo##", Sexp (Atom "foo##") ; "(foo#\"bar\")", Sexp (List [ Atom "foo#"; Atom "bar" ]) ; "(foo#())", Sexp (List [ Atom "foo#"; List [] ]) ; "(foo#)", Sexp (List [ Atom "foo#" ]) ; "(foo#;\n)", Sexp (List [ Atom "foo#" ]) ; "foo#|", Error ; "foo|#", Error ; "foo|", Sexp (Atom "foo|") ; "foo|x", Sexp (Atom "foo|x") ; "(foo| )", Sexp (List [ Atom "foo|" ]) ; "(foo|\nz)", Sexp (List [ Atom "foo|"; Atom "z" ]) ; "(foo|\r\nz)", Sexp (List [ Atom "foo|"; Atom "z" ]) ; "(foo|\"bar\")", Sexp (List [ Atom "foo|"; Atom "bar" ]) ; "(foo|())", Sexp (List [ Atom "foo|"; List [] ]) ; "(foo|)", Sexp (List [ Atom "foo|" ]) ; "(foo|;\n)", Sexp (List [ Atom "foo|" ]) ; "foo||", Sexp (Atom "foo||") ; "(", Error ; ")", Error ; "\r", Error ; "\"", Error ; "x(", Error ; "x)", Error ; "x\r", Error ; "x\"", Error ; "\rx", Error ; "#|\n|#z", Sexp (Atom "z") ; "#|\"foo\"|#z", Sexp (Atom "z") ; "#| #| x |# |#z", Sexp (Atom "z") ; "#| \"x |#\" |#z", Sexp (Atom "z") ; "#| #x |#z", Sexp (Atom "z") ; "#| #\n |#z", Sexp (Atom "z") ; "#| ## |#z", Sexp (Atom "z") ; "#| #\"x\" |#z", Sexp (Atom "z") ; "#| |x |#z", Sexp (Atom "z") ; "#| |\n |#z", Sexp (Atom "z") ; "#| |\"x\" |#z", Sexp (Atom "z") ; "#| || |#z", Sexp (Atom "z") ; "#| \"\n\" |#z", Sexp (Atom "z") ; "#| \"\\n\" |#z", Sexp (Atom "z") ; "#| \"\\z\" |#z", Sexp (Atom "z") ; "#| \"\\\n\" |#z", Sexp (Atom "z") ; "#| \"\\\r\n\" |#z", Sexp (Atom "z") ; "#| \"\\123\" |#z", Sexp (Atom "z") ; "#| \"\\x42\" |#z", Sexp (Atom "z") ; "#| \"\\\rx\" |#z", Sexp (Atom "z") ; "#| \"\\\r\" |#z", Sexp (Atom "z") ; "#| \"\\\r\\n\" |#z", Sexp (Atom "z") ; "#| \"\\1z\" |#z", Error ; "#| \"\\12z\" |#z", Error ; "#| \"\\xz\" |#z", Error ; "#| \"\\x1z\" |#z", Error ; "#| \"\\\n x\" |#z", Sexp (Atom "z") ; "#| \"\\\n \t\" |#z", Sexp (Atom "z") ; "#| \"\\\n \n\" |#z", Sexp (Atom "z") ; "#| \"\\\n \\z\" |#z", Sexp (Atom "z") ; "\"", Error ; "\"\\", Error ; "\"\\\r", Error ; "\"\\1", Error ; "\"\\12", Error ; "\"\\x", Error ; "\"\\x1", Error ; "\"\\\n ", Error ; "#|", Error ; "#| #", Error ; "#| |", Error ; "#| \"", Error ; "#| \"\\", Error ; "#| \"\\\r", Error ; "#| \"\\1", Error ; "#| \"\\12", Error ; "#| \"\\x", Error ; "#| \"\\x1", Error ; "#| \"\\\n ", Error ; "\012z", Sexp (Atom "z") ; "\rz", Error ; "\r\t", Error ; "\r\012", Error ; "\r\r", Error ; "\r\"\"", Error ; "\r#", Error ; "\r()", Error ; "(\r)", Error ; "\r123", Error ; "\r;", Error ; "\rA", Error ; "\r\\", Error ; "\r|", Error ; "(abc\012)", Sexp (List [ Atom "abc" ]) ; "abcA", Sexp (Atom "abcA") ; "abc\\", Sexp (Atom "abc\\") ; "ax", Sexp (Atom "ax") ; "a#z", Sexp (Atom "a#z") ; "(a#\012)", Sexp (List [ Atom "a#" ]) ; "a#0", Sexp (Atom "a#0") ; "a#A", Sexp (Atom "a#A") ; "a#\\", Sexp (Atom "a#\\") ; "a|z", Sexp (Atom "a|z") ; "(a|\012)", Sexp (List [ Atom "a|" ]) ; "a|0", Sexp (Atom "a|0") ; "a|A", Sexp (Atom "a|A") ; "a|\\", Sexp (Atom "a|\\") ; ";\012\nz", Sexp (Atom "z") ; ";\"\nz", Sexp (Atom "z") ; ";#\nz", Sexp (Atom "z") ; ";(\nz", Sexp (Atom "z") ; ";)\nz", Sexp (Atom "z") ; ";0\nz", Sexp (Atom "z") ; ";;\nz", Sexp (Atom "z") ; ";\\\nz", Sexp (Atom "z") ; ";x\nz", Sexp (Atom "z") ; ";|\nz", Sexp (Atom "z") ; "#z", Sexp (Atom "#z") ; "(#\012)", Sexp (List [ Atom "#" ]) ; "#0", Sexp (Atom "#0") ; "#A", Sexp (Atom "#A") ; "#\\", Sexp (Atom "#\\") ; "#|z|#z", Sexp (Atom "z") ; "#|x|#z", Sexp (Atom "z") ; "#|\t|#z", Sexp (Atom "z") ; "#|\012|#z", Sexp (Atom "z") ; "#|(|#z", Sexp (Atom "z") ; "#|)|#z", Sexp (Atom "z") ; "#|;|#z", Sexp (Atom "z") ; "#|A|#z", Sexp (Atom "z") ; "#|||#z", Sexp (Atom "z") ; "#||#z", Sexp (Atom "z") ; "#|\r|#z", Sexp (Atom "z") ; "#|0|#z", Sexp (Atom "z") ; "#|\\|#z", Sexp (Atom "z") ; "#| |z|#z", Sexp (Atom "z") ; "#| |x|#z", Sexp (Atom "z") ; "#| |\t|#z", Sexp (Atom "z") ; "#| |\012|#z", Sexp (Atom "z") ; "#| |(|#z", Sexp (Atom "z") ; "#| |)|#z", Sexp (Atom "z") ; "#| |;|#z", Sexp (Atom "z") ; "#| |A|#z", Sexp (Atom "z") ; "#| |||#z", Sexp (Atom "z") ; "#| ||#z", Sexp (Atom "z") ; "#| |\r|#z", Sexp (Atom "z") ; "#| |0|#z", Sexp (Atom "z") ; "#| |\\|#z", Sexp (Atom "z") ; "#| #z|#z", Sexp (Atom "z") ; "#| #x|#z", Sexp (Atom "z") ; "#| #\t|#z", Sexp (Atom "z") ; "#| #\012|#z", Sexp (Atom "z") ; "#| #(|#z", Sexp (Atom "z") ; "#| #)|#z", Sexp (Atom "z") ; "#| #;|#z", Sexp (Atom "z") ; "#| #A|#z", Sexp (Atom "z") ; "#| #\r|#z", Sexp (Atom "z") ; "#| #0|#z", Sexp (Atom "z") ; "#| #\\|#z", Sexp (Atom "z") ] ;; let quoted_string_cases : (string * Sexp.t result) list = [ "\"foo\\\\bar\n1\r\n2\\\n3\\\r\n4\\\n 5\"", Sexp (Atom "foo\\bar\n1\r\n2345") ; "\"\\\r\"", Sexp (Atom "\r") ; "\"\\\n \"", Sexp (Atom "") ; "\"\\\n \n\"", Sexp (Atom "\n") ; "\"\\\n \\123\"", Sexp (Atom "\123") ; {|"\123"|}, Sexp (Atom "\123") ; {|"\x42"|}, Sexp (Atom "\x42") ; "\"\\\rx\"", Sexp (Atom "\rx") ; "\"\\\r\"", Sexp (Atom "\r") ; "\"\\\r\\123\"", Sexp (Atom "\r\123") ; "\"\\1z\"", Error ; "\"\\12z\"", Error ; "\"\\xz\"", Error ; "\"\\x1z\"", Error ; "\"\t\"", Sexp (Atom "\t") ; "\"\012\"", Sexp (Atom "\012") ; "\"#\"", Sexp (Atom "#") ; "\"(\"", Sexp (Atom "(") ; "\")\"", Sexp (Atom ")") ; "\";\"", Sexp (Atom ";") ; "\"|\"", Sexp (Atom "|") ; "\"\\z\"", Sexp (Atom "\\z") ; "\"\\ \"", Sexp (Atom "\\ ") ; "\"\\\t\"", Sexp (Atom "\\\t") ; "\"\\\012\"", Sexp (Atom "\\\012") ; "\"\\#\"", Sexp (Atom "\\#") ; "\"\\(\"", Sexp (Atom "\\(") ; "\"\\)\"", Sexp (Atom "\\)") ; "\"\\;\"", Sexp (Atom "\\;") ; "\"\\A\"", Sexp (Atom "\\A") ; "\"\\|\"", Sexp (Atom "\\|") ; "\"\\\"", Error ; "\"\\\rz\"", Sexp (Atom "\rz") ; "\"\\\r\t\"", Sexp (Atom "\r\t") ; "\"\\\r\012\"", Sexp (Atom "\r\012") ; "\"\\\r#\"", Sexp (Atom "\r#") ; "\"\\\r(\"", Sexp (Atom "\r(") ; "\"\\\r)\"", Sexp (Atom "\r)") ; "\"\\\r;\"", Sexp (Atom "\r;") ; "\"\\\rA\"", Sexp (Atom "\rA") ; "\"\\\r|\"", Sexp (Atom "\r|") ; "\"\\\r\"", Sexp (Atom "\r") ; "\"\\\r\r\"", Sexp (Atom "\r\r") ; "\"\\\r0\"", Sexp (Atom "\r0") ; "\"\\1z\"", Error ; "\"\\1\t\"", Error ; "\"\\1\012\"", Error ; "\"\\1#\"", Error ; "\"\\1(\"", Error ; "\"\\1)\"", Error ; "\"\\1;\"", Error ; "\"\\1A\"", Error ; "\"\\1|\"", Error ; "\"\\1\"", Error ; "\"\\1\r\"", Error ; "\"\\1\n\"", Error ; "\"\\1\\\"", Error ; "\"\\1x\"", Error ; "\"\\12z\"", Error ; "\"\\12\t\"", Error ; "\"\\12\012\"", Error ; "\"\\12#\"", Error ; "\"\\12(\"", Error ; "\"\\12)\"", Error ; "\"\\12;\"", Error ; "\"\\12A\"", Error ; "\"\\12|\"", Error ; "\"\\12\"", Error ; "\"\\12\r\"", Error ; "\"\\12\n\"", Error ; "\"\\12\\\"", Error ; "\"\\12x\"", Error ; "\"\\xz\"", Error ; "\"\\x\t\"", Error ; "\"\\x\012\"", Error ; "\"\\x#\"", Error ; "\"\\x(\"", Error ; "\"\\x)\"", Error ; "\"\\x;\"", Error ; "\"\\xA\"", Error ; "\"\\x|\"", Error ; "\"\\x\"", Error ; "\"\\x\r\"", Error ; "\"\\x\n\"", Error ; "\"\\x\\\"", Error ; "\"\\xx\"", Error ; "\"\\x1z\"", Error ; "\"\\x1\t\"", Error ; "\"\\x1\012\"", Error ; "\"\\x1#\"", Error ; "\"\\x1(\"", Error ; "\"\\x1)\"", Error ; "\"\\x1;\"", Error ; "\"\\x1A\"", Sexp (Atom "\x1a") ; "\"\\x1|\"", Error ; "\"\\x1\"", Error ; "\"\\x1\r\"", Error ; "\"\\x1\n\"", Error ; "\"\\x1\\\"", Error ; "\"\\x1x\"", Error ; "\"\\\nz\"", Sexp (Atom "z") ; "\"\\\nx\"", Sexp (Atom "x") ; "\"\\\n\t\"", Sexp (Atom "") ; "\"\\\n\012\"", Sexp (Atom "\012") ; "\"\\\n#\"", Sexp (Atom "#") ; "\"\\\n(\"", Sexp (Atom "(") ; "\"\\\n)\"", Sexp (Atom ")") ; "\"\\\n;\"", Sexp (Atom ";") ; "\"\\\nA\"", Sexp (Atom "A") ; "\"\\\n|\"", Sexp (Atom "|") ; "\"\\\n\"", Sexp (Atom "") ; "\"\\\n\r\"", Sexp (Atom "\r") ; "\"\\\n0\"", Sexp (Atom "0") ] ;; let trailing_whitespace_cases : (string * Sexp.t result) list = [ "x ", Sexp (Atom "x"); "x\n", Sexp (Atom "x"); "x;", Sexp (Atom "x") ] ;; let cases = some_cases @ quoted_string_cases @ trailing_whitespace_cases @ List.map quoted_string_cases ~f:(fun (s, result) -> ( "#| " ^ s ^ " |#blah" , match result with | Sexp _ -> Sexp (Sexp.Atom "blah") | Error -> Error )) ;; let zero_sexp_cases : (string * Sexp.t list result) list = [ " ", Sexp []; "\n", Sexp []; ";", Sexp [] ] ;; let%expect_test "coverage" = List.iter cases ~f:(fun (input, result) -> let result_many = match result with | Sexp x -> Sexp [ x ] | Error -> Error in test_one_case_dealing_with_a_single_sexp (input, result); test_one_case_dealing_with_many_sexps (input, result_many)); List.iter zero_sexp_cases ~f:test_one_case_dealing_with_many_sexps; (* Transition after an error *) let after_error () = let state = A.new_state Many Sexp in match feed state ')' Automaton_stack.empty with | (_ : Automaton_stack.t) -> assert false | exception _ -> state in List.iter Char.all ~f:(fun c -> let state = after_error () in match feed state c Automaton_stack.empty with | (_ : Automaton_stack.t) -> assert false | exception _ -> ()); (let state = after_error () in match feed_eoi state Automaton_stack.empty with | (_ : Automaton_stack.t) -> assert false | exception _ -> ()); for state = 0 to State.count - 1 do for cl = 0 to Char_class.count - 1 do if not transition_seen.((state * Char_class.count) + cl) then printf !"state %{sexp:State.t}, feed %C\n" (State.of_int state) (witness_for_class cl) done done; for s = 0 to State.count - 1 do if not transition_eoi_seen.(s) then printf !"state %{sexp:State.t}, feed EOI\n" (State.of_int s) done; (* This output represent the list of transition not visited. It must be empty. *) [%expect {| |}]; printf "%d of %d" (List.length !cases_where_sexplib_disagree_with_itself) (List.length cases); [%expect "131 of 409"]; List.iter !cases_where_sexplib_disagree_with_itself ~f:(fun (input, sexplib, sexplib_lexer) -> let suppress = (* there are many examples where continuation-based parser fails and lexer succeeds so we filter these out: lexer interprets broken hex and decimal escape sequences as if they are not escape sequences at all Also lexer interprets "\\\r" differently: it keeps the slash, but we drop the slash *) String.is_substring ~substring:{|"\x|} input || String.is_substring ~substring:{|"\1|} input || String.is_substring ~substring:({|"\|} ^ "\r") input in if not suppress then Caml.Format.printf "the various sexplib parsers disagree between themselves on this \ case:@.input: %S@.sexplib: %a@.sexplib_lexer: %a@.@." input Sexp.pp_hum [%sexp (sexplib : (Sexp.t, exn) Result.t)] Sexp.pp_hum [%sexp (sexplib_lexer : (Sexp.t, exn) Result.t)]); [%expect {| the various sexplib parsers disagree between themselves on this case: input: "\"\\ \"" sexplib: (Ok "\\ ") sexplib_lexer: (Ok " ") |}] ;; parsexp-0.14.1/test/test_coverage.mli000066400000000000000000000000551376171340200175770ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_cst.ml000066400000000000000000000016531376171340200164310ustar00rootroot00000000000000open! Import let parse_and_print input = let x = Many_cst.parse_string_exn input in print_s [%sexp (x : Cst.t_or_comment list)] ;; let%expect_test "escape sequence in block comment" = parse_and_print {|#| "\255" |#|}; [%expect {| (( Comment ( Plain_comment (loc ( (start_pos ( (line 1) (col 0) (offset 0))) (end_pos ( (line 1) (col 12) (offset 12))))) (comment "#| \"\\255\" |#")))) |}] ;; let%expect_test "quoted atom" = parse_and_print {| "foo bar" |}; [%expect {| (( Sexp ( Atom (loc ( (start_pos ( (line 1) (col 1) (offset 1))) (end_pos ( (line 1) (col 10) (offset 10))))) (atom "foo bar") (unescaped ("\"foo bar\""))))) |}] ;; parsexp-0.14.1/test/test_cst.mli000066400000000000000000000000551376171340200165750ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_parsexp.ml000066400000000000000000000272541376171340200173270ustar00rootroot00000000000000open! Import let test s = Single.parse_string s |> [%sexp_of: (Sexp.t, Parse_error.t) Result.t] |> print_s ;; let%expect_test "unterminated sexp" = test "(abc"; [%expect {| (Error ( (position ( (line 1) (col 4) (offset 4))) (message "unclosed parentheses at end of input"))) |}]; test " "; [%expect {| (Error ( (position ( (line 1) (col 2) (offset 2))) (message "no s-expression found in input"))) |}] ;; let%expect_test "parsexp bug: it accepts invalid syntax" = test "(#;)"; [%expect {| (Error ( (position ( (line 1) (col 3) (offset 3))) (message "unterminated sexp comment"))) |}]; test "#;(#;) a"; [%expect {| (Error ( (position ( (line 1) (col 5) (offset 5))) (message "unterminated sexp comment"))) |}]; test "#;"; [%expect {| (Error ( (position ( (line 1) (col 2) (offset 2))) (message "unterminated sexp comment"))) |}]; test "#;(#;q) (a)"; [%expect {| (Ok (a)) |}]; test "#;(#;(q)) (a)"; [%expect {| (Ok (a)) |}]; test "#;(#;(q)) a"; [%expect {| (Ok a) |}]; test "#;(#;((q))) a"; [%expect {| (Ok a) |}]; test "#;#;(#;x)y a"; [%expect {| (Ok a) |}] ;; let%expect_test "regression test (used to raise s-expression followed by data)" = test "a #;0"; [%expect {| (Ok a) |}] ;; let parse_eager_cst ~no_sexp_is_error str = let r = ref [] in let state = Eager_cst.State.create ~no_sexp_is_error (fun _ v -> r := v :: !r) in Result.try_with (fun () -> let stack = Eager_cst.Stack.empty in let stack = Eager_cst.feed_string state str stack in Eager_cst.feed_eoi state stack; List.rev !r) ;; let parse_eager_cst_no_sexp_is_error = parse_eager_cst ~no_sexp_is_error:true let parse_eager_cst = parse_eager_cst ~no_sexp_is_error:false let%expect_test "regression test (we didn't run the callback on comments, resulting in \ missing comments or assertion failures)" = let test s = parse_eager_cst s |> [%sexp_of: (Cst.t_or_comment list, exn) Result.t] |> print_s in test ";"; [%expect {| (Ok (( Comment ( Plain_comment (loc ( (start_pos ( (line 1) (col 0) (offset 0))) (end_pos ( (line 1) (col 1) (offset 1))))) (comment ";"))))) |}]; test "#||#"; [%expect {| (Ok (( Comment ( Plain_comment (loc ( (start_pos ( (line 1) (col 0) (offset 0))) (end_pos ( (line 1) (col 4) (offset 4))))) (comment "#||#"))))) |}]; test "#;#;a b"; [%expect {| (Ok (( Comment ( Sexp_comment (hash_semi_pos ( (line 1) (col 0) (offset 0))) (comments (( Sexp_comment (hash_semi_pos ( (line 1) (col 2) (offset 2))) (comments ()) (sexp ( Atom (loc ( (start_pos ( (line 1) (col 4) (offset 4))) (end_pos ( (line 1) (col 5) (offset 5))))) (atom a) (unescaped (a))))))) (sexp ( Atom (loc ( (start_pos ( (line 1) (col 6) (offset 6))) (end_pos ( (line 1) (col 7) (offset 7))))) (atom b) (unescaped (b)))))))) |}]; test "a;\nb"; [%expect {| (Ok ( (Sexp ( Atom (loc ( (start_pos ( (line 1) (col 0) (offset 0))) (end_pos ( (line 1) (col 1) (offset 1))))) (atom a) (unescaped (a)))) (Comment ( Plain_comment (loc ( (start_pos ( (line 1) (col 1) (offset 1))) (end_pos ( (line 1) (col 2) (offset 2))))) (comment ";"))) (Sexp ( Atom (loc ( (start_pos ( (line 2) (col 0) (offset 3))) (end_pos ( (line 2) (col 1) (offset 4))))) (atom b) (unescaped (b)))))) |}] ;; let%expect_test "regression test (we counted comments as sexps for the purpose of \ ~no_sexp_is_error" = let test s = parse_eager_cst_no_sexp_is_error s |> [%sexp_of: (Cst.t_or_comment list, exn) Result.t] |> print_s in test ";"; [%expect {| (Error ( parse_error.ml.Parse_error ( (position ( (line 1) (col 1) (offset 1))) (message "no s-expression found in input")))) |}]; test "#||#"; [%expect {| (Error ( parse_error.ml.Parse_error ( (position ( (line 1) (col 4) (offset 4))) (message "no s-expression found in input")))) |}]; test "#;#;a b"; [%expect {| (Error ( parse_error.ml.Parse_error ( (position ( (line 1) (col 7) (offset 7))) (message "no s-expression found in input")))) |}] ;; module Stream = Caml.Stream module P = Eager let rec hot_loop state stream stack = match Stream.peek stream with | None -> P.feed_eoi state stack | Some char -> let stack = P.feed state char stack in Stream.junk stream; hot_loop state stream stack ;; exception Got_sexp of Sexp.t let fetch_sexp (stream : char Stream.t) = let got_sexp _state sexp = Exn.raise_without_backtrace (Got_sexp sexp) in let count = Stream.count stream in let state = P.State.create got_sexp in match hot_loop state stream P.Stack.empty with | () -> None | exception Got_sexp sexp -> (* This test is true if the s-expression includes the last character passed to the parser *) if P.State.offset state > Stream.count stream - count then Stream.junk stream; Some sexp ;; let iter_sexps (stream : char Stream.t) ~f = let got_sexp _state sexp = f sexp in let state = P.State.create got_sexp in hot_loop state stream P.Stack.empty ;; let input = {| (Hello World) (a b c) "Hello world" (1 (2 3)) |} let%expect_test "eager parser raise" = let stream = Stream.of_string input in let rec loop stream = match fetch_sexp stream with | None -> assert (Option.is_none (Stream.peek stream)) | Some sexp -> Caml.Format.printf "got: %a@." Sexp.pp_hum sexp; loop stream in loop stream; [%expect {| got: (Hello World) got: (a b c) got: "Hello world" got: (1 (2 3)) |}] ;; let all_short_strings () = let all_chars = (* should have an example from every character class (see [Char_class] in test_coverage.ml) *) [ '\000' ; '\001' ; '\t' ; ' ' ; '\n' ; '\012' ; '\r' ; '"' ; '#' ; '(' ; ')' ; '8' ; ';' ; 'A' ; 'b' ; '\\' ; 'x' ; '|' ] in List.bind [ 0; 1; 2; 3; 4 ] ~f:(fun len -> List.all (List.init len ~f:(fun _ -> all_chars))) |> List.map ~f:String.of_char_list ;; (* A thorough test of [Eager] semantics expressed in terms of [Many]. - feed chars one by one, - note when sexps are detected, - assert that the position reported is how many chars we fed or 1 fewer - assert that the resulting chunks if we split at those positions can be parsed to the same sexps as the sexps being reported - assert that the whole thing parses iff it parses with [Many] *) let%expect_test "eager parser semantics" = let exception Got_sexp of { offset : int ; sexp : Sexp.t } in let got_sexp state sexp = Exn.raise_without_backtrace (Got_sexp { sexp; offset = P.State.Read_only.offset state }) in let inputs = all_short_strings () in printf "testing %d inputs\n" (List.length inputs); List.iter inputs ~f:(fun input -> let rec go start state stack i = if Int.( = ) i (String.length input) then ( match P.feed_eoi state stack with | exception Got_sexp { offset; sexp } -> let ate = P.State.offset state in assert (Int.( = ) offset ate); let fed = i - start in assert (List.mem [ fed ] ~equal:Int.( = ) ate); (match Single.parse_string (String.sub ~pos:start ~len:ate input) with | Error _ -> assert false | Ok sexp2 -> assert (Sexp.( = ) sexp sexp2); Ok ()) | exception exn -> Error (i, exn) | () -> (match Many.parse_string (String.sub ~pos:start ~len:(i - start) input) with | Ok [] -> Ok () | Ok (_ :: _) -> failwith "lost a sexp" | Error error -> raise_s [%message "succeeded with Eager, but failed with Many" ~pos:(start : int) ~len:(i - start : int) (error : Parse_error.t)])) else ( match P.feed state input.[i] stack with | exception Got_sexp { sexp; offset } -> let ate = P.State.offset state in assert (Int.( = ) offset ate); let fed = i + 1 - start in assert (List.mem [ fed; fed - 1 ] ~equal:Int.( = ) ate); let end_ = start + ate in (match Single.parse_string (String.sub ~pos:start ~len:ate input) with | Error _ -> raise_s [%message "Eager gave us a sexp that won't parse" (start : int) (i : int)] | Ok sexp2 -> assert (Sexp.( = ) sexp sexp2); let state = P.State.create got_sexp in go end_ state P.Stack.empty end_) | exception exn -> Error (i, exn) | stack -> go start state stack (i + 1)) in let state = P.State.create got_sexp in match go 0 state P.Stack.empty 0 with | Ok () -> () | Error exn -> (match Many.parse_string input with | Ok result_from_many -> print_s [%message "failed to parse with Eager, but succeeded with Many" (input : string) (exn : int * Exn.t) (result_from_many : Sexp.t list)] | Error _bad -> ()) | exception bad_thing -> print_s [%message "Bad" (input : string) (bad_thing : Exn.t)]); [%expect {| testing 111151 inputs |}] ;; let%expect_test "eager parser continue" = let stream = Stream.of_string input in iter_sexps stream ~f:(Caml.Format.printf "got: %a@." Sexp.pp_hum); [%expect {| got: (Hello World) got: (a b c) got: "Hello world" got: (1 (2 3)) |}] ;; let%expect_test "eager parser incorrect mutation" = let stream = Stream.of_string input in let state = ref (P.State.create (fun _ _ -> assert false)) in let got_sexp _state _sexp = P.State.reset !state in state := P.State.create got_sexp; show_raise ~hide_positions:true (fun () -> hot_loop !state stream P.Stack.empty); [%expect {| (raised "Assert_failure parser_automaton_internal.ml:LINE:COL") |}] ;; let%expect_test "eager parser feed after raise without reset" = let stream = Stream.of_string input in let got_sexp _state _sexp = raise Caml.Exit in let state = P.State.create got_sexp in (try hot_loop state stream P.Stack.empty with | Caml.Exit -> ()); show_raise (fun () -> hot_loop state stream P.Stack.empty); [%expect {| (raised (Failure "Parsexp.Parser_automaton: parser is dead")) |}] ;; parsexp-0.14.1/test/test_parsexp.mli000066400000000000000000000000551376171340200174660ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_parsexp_and_positions.ml000066400000000000000000000054131376171340200222510ustar00rootroot00000000000000open! Import let test input = Single_just_positions.parse_string input |> Result.map ~f:Positions.to_list |> [%sexp_of: (Positions.pos list, Parse_error.t) Result.t] |> print_s ;; let test_many input = Many_just_positions.parse_string input |> Result.map ~f:Positions.to_list |> [%sexp_of: (Positions.pos list, Parse_error.t) Result.t] |> print_s ;; let%expect_test "single" = test "(1 2 3)"; [%expect {| (Ok ( ((line 1) (col 0) (offset 0)) ((line 1) (col 1) (offset 1)) ((line 1) (col 1) (offset 1)) ((line 1) (col 3) (offset 3)) ((line 1) (col 3) (offset 3)) ((line 1) (col 5) (offset 5)) ((line 1) (col 5) (offset 5)) ((line 1) (col 6) (offset 6)))) |}]; test "; plop\natom"; [%expect {| (Ok ( ((line 2) (col 0) (offset 7)) ((line 2) (col 3) (offset 10)))) |}]; test "(1 (2 3)(4 5))"; [%expect {| (Ok ( ((line 1) (col 0) (offset 0)) ((line 1) (col 1) (offset 1)) ((line 1) (col 1) (offset 1)) ((line 1) (col 3) (offset 3)) ((line 1) (col 4) (offset 4)) ((line 1) (col 4) (offset 4)) ((line 1) (col 6) (offset 6)) ((line 1) (col 6) (offset 6)) ((line 1) (col 7) (offset 7)) ((line 1) (col 8) (offset 8)) ((line 1) (col 9) (offset 9)) ((line 1) (col 9) (offset 9)) ((line 1) (col 11) (offset 11)) ((line 1) (col 11) (offset 11)) ((line 1) (col 12) (offset 12)) ((line 1) (col 13) (offset 13)))) |}] ;; let%expect_test "many" = test_many "(1 2) (3)"; [%expect {| (Ok ( ((line 1) (col 0) (offset 0)) ((line 1) (col 1) (offset 1)) ((line 1) (col 1) (offset 1)) ((line 1) (col 3) (offset 3)) ((line 1) (col 3) (offset 3)) ((line 1) (col 4) (offset 4)) ((line 1) (col 6) (offset 6)) ((line 1) (col 7) (offset 7)) ((line 1) (col 7) (offset 7)) ((line 1) (col 8) (offset 8)))) |}]; test_many "(1 2 3)\nhello"; [%expect {| (Ok ( ((line 1) (col 0) (offset 0)) ((line 1) (col 1) (offset 1)) ((line 1) (col 1) (offset 1)) ((line 1) (col 3) (offset 3)) ((line 1) (col 3) (offset 3)) ((line 1) (col 5) (offset 5)) ((line 1) (col 5) (offset 5)) ((line 1) (col 6) (offset 6)) ((line 2) (col 0) (offset 8)) ((line 2) (col 4) (offset 12)))) |}]; test_many "(1 2)(3)"; [%expect {| (Ok ( ((line 1) (col 0) (offset 0)) ((line 1) (col 1) (offset 1)) ((line 1) (col 1) (offset 1)) ((line 1) (col 3) (offset 3)) ((line 1) (col 3) (offset 3)) ((line 1) (col 4) (offset 4)) ((line 1) (col 5) (offset 5)) ((line 1) (col 6) (offset 6)) ((line 1) (col 6) (offset 6)) ((line 1) (col 7) (offset 7)))) |}] ;; parsexp-0.14.1/test/test_parsexp_and_positions.mli000066400000000000000000000000551376171340200224170ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_parsexp_conv.ml000066400000000000000000000044751376171340200203540ustar00rootroot00000000000000open! Import type 'a conv_result = ('a, Conv_error.t) Result.t [@@deriving sexp_of] let test a_of_sexp input = match Conv_single.parse_string input a_of_sexp with | Ok _ -> () | Error error -> Conv_error.report Caml.Format.std_formatter error ~filename:"" ;; let test_many a_of_sexp input = match Conv_many.parse_string input a_of_sexp with | Ok _ -> () | Error error -> Conv_error.report Caml.Format.std_formatter error ~filename:"" ;; let%expect_test "parsing errors" = (* For the following tests, you can check that the reported character positions match the positions reported by emacs when you move the cursor over the faulty s-expressions. *) test [%of_sexp: int list] {| (1 2 3|}; [%expect {| File "", line 2, character 6: Error: s-expression parsing error; unclosed parentheses at end of input |}]; test [%of_sexp: int list] {| (1 2 "abc)|}; [%expect {| File "", line 2, character 10: Error: s-expression parsing error; unterminated quoted string |}]; test_many [%of_sexp: int list] {| (1 2 3) "a|}; [%expect {| File "", line 3, character 2: Error: s-expression parsing error; unterminated quoted string |}] ;; let%expect_test "conversion errors" = (* For the following tests, you can check that the reported character positions match the positions reported by emacs when you move the cursor over the faulty s-expressions. *) test [%of_sexp: int list] {| (1 2 3 abc 4 5 6) |}; [%expect {| File "", line 2, characters 7-10: Error: s-expression conversion error; exception (Failure "int_of_sexp: (Failure int_of_string)") |}]; test [%of_sexp: int list] {| (1 2 (1 2 3)) |}; [%expect {| File "", line 2, characters 5-12: Error: s-expression conversion error; exception (Failure "int_of_sexp: atom needed") |}]; test [%of_sexp: int list] {| (1 2 (1 2 3)) |}; [%expect {| File "", line 2, characters 5-12: Error: s-expression conversion error; exception (Failure "int_of_sexp: atom needed") |}]; test_many [%of_sexp: int list] {| (1 2 3) (a) |}; [%expect {| File "", line 3, characters 1-2: Error: s-expression conversion error; exception (Failure "int_of_sexp: (Failure int_of_string)") |}] ;; parsexp-0.14.1/test/test_parsexp_conv.mli000066400000000000000000000000551376171340200205130ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_parsexp_lexing.ml000066400000000000000000000015221376171340200206630ustar00rootroot00000000000000open! Import let assoc s = Lexer.assoc (Eager.Lexbuf_consumer.create ()) (Lexing.from_string s) |> [%sexp_of: (string * Sexp.t) list] |> print_s ;; let sexps s = let lexbuf = Lexing.from_string s in let p = Eager.Lexbuf_consumer.create () in let rec loop () = match Eager.Lexbuf_consumer.parse_opt p lexbuf with | None -> [] | Some sexp -> sexp :: loop () in loop () |> List.iter ~f:print_s ;; let%expect_test "simple test" = assoc {| # Hello x = (a b c) y = 42 z = "blah" a = 123 |}; [%expect {| ((x (a b c)) (y 42) (z blah) (a 123)) |}] ;; let%expect_test "empty lexing" = sexps ""; [%expect {| |}] ;; let%expect_test "the lexer doesn't consume more than it should" = sexps {| abc"123" |}; [%expect {| abc 123 |}]; sexps {| abc() |}; [%expect {| abc () |}] ;; parsexp-0.14.1/test/test_parsexp_lexing.mli000066400000000000000000000000551376171340200210340ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_positions.ml000066400000000000000000000146071376171340200176720ustar00rootroot00000000000000open! Import let cases = (* Cases of inputs, [.] represent a saved position, [:] represent a position saved twice. *) [ "" ; "." ; "1." ; "12." ; "123." ; "1234." ; "12345." ; "123456." ; ".\n" ; "\n." ; "\n\n\n" ; ". . . xxxxx\nxxxx . xxx . xxx\n" ; "....." ; ":" ; "..:.." ; Printf.sprintf "%*s." 40 "" ; Printf.sprintf "%*s." 300 "" ; String.concat (List.init (62 * 4) ~f:(fun _i -> "..")) ] ;; (* Extract the positions of the '.' in the input *) let build_positions s = let builder = Positions.Builder.create () in for i = 0 to String.length s - 1 do match s.[i] with | '\n' -> Positions.Builder.add_newline builder ~offset:i | '.' -> Positions.Builder.add builder ~offset:i | ':' -> Positions.Builder.add_twice builder ~offset:i | _ -> () done; Positions.Builder.contents builder ;; (* Same but with a trivial implementation (i.e. without using [Positions]). *) let build_positions_simple s = let rec loop i (pos : Positions.pos) = if i = String.length s then [] else ( let offset = pos.offset + 1 in match s.[i] with | '\n' -> loop (i + 1) { line = pos.line + 1; col = 0; offset } | '.' -> pos :: loop (i + 1) { pos with offset; col = pos.col + 1 } | ':' -> pos :: pos :: loop (i + 1) { pos with offset; col = pos.col + 1 } | _ -> loop (i + 1) { pos with offset; col = pos.col + 1 }) in loop 0 Positions.beginning_of_file ;; let%expect_test "build_positions_simple" = let f s = print_s [%sexp (build_positions_simple s : Positions.pos list)] in f ""; [%expect {| () |}]; f "."; [%expect {| (( (line 1) (col 0) (offset 0))) |}]; f ". ."; [%expect {| (((line 1) (col 0) (offset 0)) ((line 1) (col 2) (offset 2))) |}]; f ". xxx \n xxx ."; [%expect {| (((line 1) (col 0) (offset 0)) ((line 2) (col 5) (offset 12))) |}] ;; let check_all_subsexps_map_to_their_position s sexps positions = let check_subsexp subsexp = match Positions.find_sub_sexp_in_list_phys positions sexps ~sub:subsexp with | None -> failwith "not found" | Some range -> assert ( Sexp.( = ) (Single.parse_string_exn (String.sub s ~pos:range.start_pos.offset ~len:(range.end_pos.offset - range.start_pos.offset))) subsexp) in let rec iter sexps = List.iter sexps ~f:(fun sexp -> check_subsexp sexp; match sexp with | Atom _ -> () | List l -> iter l) in iter sexps ;; let%expect_test "build_positions_ignore_commented_expr" = let f s = let sexps, positions = Many_and_positions.parse_string_exn s in print_s [%sexp (Positions.to_list positions : Positions.pos list)]; check_all_subsexps_map_to_their_position s sexps positions in f "a #;((b)) c"; [%expect {| (((line 1) (col 0) (offset 0)) ((line 1) (col 0) (offset 0)) ((line 1) (col 10) (offset 10)) ((line 1) (col 10) (offset 10))) |}] ;; let%expect_test "all" = List.iter cases ~f:(fun input -> let expected = build_positions_simple input in let got = build_positions input |> Positions.to_list in require [%here] ([%compare.equal: Positions.pos list] got expected) ~if_false_then_print_s: (lazy [%sexp { input : string; expected : Positions.pos list; got : Positions.pos list }])) ;; let%expect_test "find" = List.iter cases ~f:(fun input -> let positions = build_positions_simple input |> Array.of_list in let from_parsexp = build_positions input in let count = Array.length positions in for i = 0 to count - 1 do for j = i + 1 to count - 1 do let expected = Positions.make_range_incl ~start_pos:positions.(i) ~last_pos:positions.(j) in let got = Result.try_with (fun () -> Positions.find from_parsexp i j) in require [%here] (match got with | Ok got -> [%compare.equal: Positions.range] got expected | Error _ -> false) ~if_false_then_print_s: (lazy [%sexp { input : string ; i : int ; j : int ; expected : (Positions.range, exn) Result.t = Ok expected ; got : (Positions.range, exn) Result.t }]) done done); [%expect] ;; let cases_for_find_sub_sexp = [ "( ( ( abc ) (+ 1 2) ) )" ] module Annotated = struct type t = | Atom of Positions.range * Sexp.t | List of Positions.range * Sexp.t * t list let of_sexp_and_positions = let rec loop (sexp : Sexp.t) (positions : Positions.pos list) = match sexp, positions with | Atom _, start_pos :: last_pos :: rest -> Atom (Positions.make_range_incl ~start_pos ~last_pos, sexp), rest | List l, start_pos :: rest -> let annots_rev, rest = List.fold_left l ~init:([], rest) ~f:(fun (acc, positions) sexp -> let annot, rest = loop sexp positions in annot :: acc, rest) in (match rest with | [] -> assert false | last_pos :: rest -> ( List (Positions.make_range_incl ~start_pos ~last_pos, sexp, List.rev annots_rev) , rest )) | _ -> assert false in fun sexp positions -> let t, rest = loop sexp positions in assert (List.is_empty rest); t ;; let rec iter t ~f = match t with | Atom (range, sexp) -> f range sexp | List (range, sexp, children) -> f range sexp; List.iter children ~f:(iter ~f) ;; end let%expect_test "find_sub_sexp_phys" = List.iter cases_for_find_sub_sexp ~f:(fun input -> let sexp, positions = Single_and_positions.parse_string_exn input in let annot = Annotated.of_sexp_and_positions sexp (Positions.to_list positions) in Annotated.iter annot ~f:(fun expected sub -> let got = Positions.find_sub_sexp_phys positions sexp ~sub in require [%here] (Option.value_map got ~default:false ~f:([%compare.equal: Positions.range] expected)) ~if_false_then_print_s: (lazy [%sexp { input : string ; sexp : Sexp.t ; sub : Sexp.t ; expected : Positions.range option = Some expected ; got : Positions.range option }]))); [%expect {| |}] ;; parsexp-0.14.1/test/test_positions.mli000066400000000000000000000000551376171340200200330ustar00rootroot00000000000000(*_ This signature is deliberately empty. *) parsexp-0.14.1/test/test_sexplib_vs_parsexp.ml000066400000000000000000000055611376171340200215620ustar00rootroot00000000000000open! Import (* Compare parsexp to the default cpp based sexplib parser *) let test s = let sexplib = Sexplib.Sexp.of_string (String.strip s) in let parsexp = Single.parse_string_exn s in if Sexp.equal sexplib parsexp then ( Caml.print_string "same\n"; print_s [%sexp (parsexp : Sexp.t)]) else ( Caml.print_string "FAILURE\n"; print_s [%sexp ~~(sexplib : Sexp.t)]; print_s [%sexp ~~(parsexp : Sexp.t)]); let sexplib_lexer = Sexplib.Sexp.scan_sexp (Lexing.from_string s) in if not (Sexp.equal sexplib sexplib_lexer) then ( Caml.print_string "\nNote: the various sexplib parsers disagree between themselves\n"; print_s [%sexp ~~(sexplib_lexer : Sexp.t)]) ;; let%expect_test _ = test {| "a\q" |}; [%expect {| same "a\\q" |}] ;; let%expect_test _ = test {| "a\ b" |}; [%expect {| same "a\\ b" Note: the various sexplib parsers disagree between themselves (sexplib_lexer "a b") |}] ;; let test_cont_state input = let sexplib : Sexp.t = try match Sexplib.Sexp.parse input with | Done (sexp, _) -> [%sexp Done (sexp : Sexp.t)] | Cont (st, _) -> [%sexp Cont (Sexplib.Sexp.Cont_state.to_string st : string)] with | _ -> [%sexp Raised] in let parsexp = let open Private.Parser_automaton in let state = new_state Single Sexp in ignore (String.fold input ~init:Automaton_stack.empty ~f:(fun stack ch -> feed state ch stack) : Automaton_stack.t); let old_state = old_parser_cont_state state in [%sexp Cont (old_state : Old_parser_cont_state.t)] in if Sexp.equal sexplib parsexp then ( Caml.print_string "same\n"; print_s [%sexp (parsexp : Sexp.t)]) else ( Caml.print_string "FAILURE\n"; print_s [%sexp ~~(sexplib : Sexp.t)]; print_s [%sexp ~~(parsexp : Sexp.t)]) ;; let%expect_test _ = test_cont_state " "; [%expect {| same (Cont Parsing_toplevel_whitespace) |}]; test_cont_state "\r"; [%expect {| same (Cont Parsing_nested_whitespace) |}]; test_cont_state "\"toto"; [%expect {| same (Cont Parsing_atom) |}]; test_cont_state "#"; [%expect {| same (Cont Parsing_atom) |}]; test_cont_state "#| toto"; [%expect {| same (Cont Parsing_block_comment) |}]; test_cont_state "#| \"bla"; [%expect {| same (Cont Parsing_block_comment) |}]; test_cont_state "#; toto"; [%expect {| same (Cont Parsing_sexp_comment) |}]; test_cont_state "; toto"; [%expect {| same (Cont Parsing_toplevel_whitespace) |}]; test_cont_state "("; [%expect {| same (Cont Parsing_list) |}]; test_cont_state "#; ("; [%expect {| same (Cont Parsing_sexp_comment) |}]; test_cont_state "#; #|"; [%expect {| same (Cont Parsing_sexp_comment) |}]; test_cont_state "#;\r"; [%expect {| same (Cont Parsing_sexp_comment) |}] ;; parsexp-0.14.1/test/test_sexplib_vs_parsexp.mli000066400000000000000000000000551376171340200217240ustar00rootroot00000000000000(*_ This signature is deliberately empty. *)