├── docs ├── reparse │ ├── Reparse │ │ ├── .dune-keep │ │ ├── Make │ │ │ ├── Let_syntax │ │ │ │ ├── index.html │ │ │ │ └── Let_syntax │ │ │ │ │ └── index.html │ │ │ ├── argument-1-Input │ │ │ │ └── index.html │ │ │ └── Infix │ │ │ │ └── index.html │ │ ├── String │ │ │ ├── Let_syntax │ │ │ │ ├── index.html │ │ │ │ └── Let_syntax │ │ │ │ │ └── index.html │ │ │ └── Infix │ │ │ │ └── index.html │ │ ├── module-type-PARSER │ │ │ ├── Let_syntax │ │ │ │ ├── index.html │ │ │ │ └── Let_syntax │ │ │ │ │ └── index.html │ │ │ └── Infix │ │ │ │ └── index.html │ │ ├── index.html │ │ └── module-type-INPUT │ │ │ └── index.html │ └── index.html ├── reparse-lwt │ ├── Reparse_lwt │ │ ├── .dune-keep │ │ ├── index.html │ │ └── Stream │ │ │ ├── Let_syntax │ │ │ ├── index.html │ │ │ └── Let_syntax │ │ │ │ └── index.html │ │ │ └── Infix │ │ │ └── index.html │ └── index.html ├── index.html ├── highlight.pack.js └── odoc.css ├── dune ├── examples ├── dune ├── calc.ml └── json.ml ├── lib └── dune ├── Makefile ├── dune-project ├── lwt ├── dune ├── reparse_lwt.mli └── reparse_lwt.ml ├── lwt-unix ├── dune ├── reparse_lwt_unix.mli └── reparse_lwt_unix.ml ├── tests ├── dune ├── run.ml ├── test_input_parsers.ml ├── test_boolean_parsers.ml ├── test_parser.ml ├── test_alternative_parsers.ml └── test_string_parsers.ml ├── .ocamlformat ├── .gitignore ├── reparse-lwt-unix.opam ├── reparse-lwt.opam ├── reparse.opam ├── CHANGES.md ├── README.md └── LICENSE /docs/reparse/Reparse/.dune-keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/reparse-lwt/Reparse_lwt/.dune-keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dune: -------------------------------------------------------------------------------- 1 | (mdx 2 | (files README.md) 3 | (packages reparse)) 4 | -------------------------------------------------------------------------------- /examples/dune: -------------------------------------------------------------------------------- 1 | (executables 2 | (names calc json) 3 | (libraries reparse)) 4 | -------------------------------------------------------------------------------- /lib/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name reparse) 3 | (public_name reparse) 4 | (libraries cstruct)) 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | dune b @doc 3 | cp -R _build/default/_doc/_html/* docs/ 4 | 5 | .PHONY: all 6 | 7 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.9) 2 | 3 | (name reparse) 4 | 5 | (version 3.1.0) 6 | 7 | (using mdx 0.1) 8 | -------------------------------------------------------------------------------- /lwt/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name reparse_lwt) 3 | (public_name reparse-lwt) 4 | (libraries reparse lwt cstruct)) 5 | -------------------------------------------------------------------------------- /lwt-unix/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name reparse_lwt_unix) 3 | (public_name reparse-lwt-unix) 4 | (libraries reparse cstruct lwt lwt.unix)) 5 | -------------------------------------------------------------------------------- /tests/dune: -------------------------------------------------------------------------------- 1 | (test 2 | (name run) 3 | (libraries cstruct lwt lwt.unix popper reparse reparse-lwt reparse-lwt-unix) 4 | (preprocess 5 | (pps ppx_deriving.show ppx_deriving.ord ppx_deriving_popper))) 6 | -------------------------------------------------------------------------------- /.ocamlformat: -------------------------------------------------------------------------------- 1 | profile = ocamlformat 2 | module-item-spacing=compact 3 | sequence-blank-line=preserve-one 4 | single-case=compact 5 | break-cases = fit 6 | parse-docstrings = true 7 | wrap-comments = true 8 | 9 | -------------------------------------------------------------------------------- /tests/run.ml: -------------------------------------------------------------------------------- 1 | let () = Printexc.record_backtrace true 2 | 3 | let () = 4 | Popper.suite 5 | [ ("String", Test_string_parsers.suite) 6 | ; ("Alternative", Test_alternative_parsers.suite) 7 | ; ("Boolean", Test_boolean_parsers.suite) 8 | ; ("Input", Test_input_parsers.suite) ] 9 | |> Popper.run 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.annot 3 | *.cmo 4 | *.cma 5 | *.cmi 6 | *.a 7 | *.o 8 | *.cmx 9 | *.cmxs 10 | *.cmxa 11 | 12 | # ocamlbuild working directory 13 | _build/ 14 | 15 | # ocamlbuild targets 16 | *.byte 17 | *.native 18 | 19 | # oasis generated files 20 | setup.data 21 | setup.log 22 | 23 | # Merlin configuring file for Vim and Emacs 24 | .merlin 25 | 26 | *.install 27 | node_modules/ 28 | _build 29 | _esy 30 | _release 31 | *.byte 32 | *.native 33 | *.installlmerlin 34 | node_modules/ 35 | _build 36 | _esy 37 | _release 38 | *.byte 39 | *.native 40 | *.install 41 | .ionide 42 | *.swp 43 | .vscode 44 | .nvimlog 45 | -------------------------------------------------------------------------------- /lwt/reparse_lwt.mli: -------------------------------------------------------------------------------- 1 | (*------------------------------------------------------------------------- 2 | * Copyright (c) 2020, 2021 Bikal Gurung. All rights reserved. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | * 8 | * %%NAME%% %%VERSION%% 9 | *-------------------------------------------------------------------------*) 10 | 11 | module Stream : sig 12 | include Reparse.PARSER with type 'a promise = 'a Lwt.t 13 | 14 | val create_input : char Lwt_stream.t -> input 15 | end 16 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | index 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |

OCaml package documentation

13 |
    14 |
  1. reparse 3.0.0
  2. 15 |
  3. reparse-lwt 3.0.0
  4. 16 |
17 |
18 |
19 | 20 | -------------------------------------------------------------------------------- /reparse-lwt-unix.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "3.1.0" 3 | synopsis: "Reparse lwt-unix based input support" 4 | description: "Reparse lwt-unix based input support" 5 | maintainer: ["Bikal Lem"] 6 | authors: ["Bikal Lem "] 7 | license: "MPL-2.0" 8 | homepage: "https://github.com/lemaetech/reparse" 9 | bug-reports: "https://github.com/lemaetech/reparse/issues" 10 | depends: [ 11 | "dune" {>= "2.9"} 12 | "ocaml" {>= "4.10.0"} 13 | "lwt" {>= "5.4.1"} 14 | "cstruct" {>= "6.0.0"} 15 | "reparse" {= version} 16 | "odoc" {with-doc} 17 | ] 18 | build: [ 19 | ["dune" "subst"] {dev} 20 | [ 21 | "dune" 22 | "build" 23 | "-p" 24 | name 25 | "-j" 26 | jobs 27 | "@install" 28 | "@doc" {with-doc} 29 | ] 30 | ] 31 | dev-repo: "git+https://github.com/lemaetech/reparse.git" 32 | -------------------------------------------------------------------------------- /reparse-lwt.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "3.1.0" 3 | synopsis: "Reparse Lwt_stream.t input support" 4 | description: "char Lwt_stream.t parsing support for 'reparse'" 5 | maintainer: ["Bikal Lem"] 6 | authors: ["Bikal Lem "] 7 | license: "MPL-2.0" 8 | homepage: "https://github.com/lemaetech/reparse" 9 | bug-reports: "https://github.com/lemaetech/reparse/issues" 10 | depends: [ 11 | "dune" {>= "2.9"} 12 | "ocaml" {>= "4.10.0"} 13 | "lwt" {>= "5.4.1"} 14 | "cstruct" {>= "6.0.0"} 15 | "reparse" {= version} 16 | "odoc" {with-doc} 17 | ] 18 | build: [ 19 | ["dune" "subst"] {dev} 20 | [ 21 | "dune" 22 | "build" 23 | "-p" 24 | name 25 | "-j" 26 | jobs 27 | "@install" 28 | "@doc" {with-doc} 29 | ] 30 | ] 31 | dev-repo: "git+https://github.com/lemaetech/reparse.git" 32 | -------------------------------------------------------------------------------- /docs/reparse/index.html: -------------------------------------------------------------------------------- 1 | 2 | index (reparse.index)

reparse index

Library reparse

The entry point of this library is the module: Reparse.

-------------------------------------------------------------------------------- /lwt-unix/reparse_lwt_unix.mli: -------------------------------------------------------------------------------- 1 | (*------------------------------------------------------------------------- 2 | * Copyright (c) 2020, 2021 Bikal Gurung. All rights reserved. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | * 8 | * %%NAME%% %%VERSION%% 9 | *-------------------------------------------------------------------------*) 10 | 11 | (** [Fd] is a [Lwt_unix.file_descr] input based [Reparse] parser. *) 12 | module Fd : sig 13 | include Reparse.PARSER with type 'a promise = 'a Lwt.t 14 | 15 | val create_input : Lwt_unix.file_descr -> input 16 | end 17 | 18 | (** [Channel] is a [Lwt_io.input_channel] input based [Reparse] parser. *) 19 | module Channel : sig 20 | include Reparse.PARSER with type 'a promise = 'a Lwt.t 21 | 22 | val create_input : Lwt_io.input_channel -> input 23 | end 24 | -------------------------------------------------------------------------------- /reparse.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "3.1.0" 3 | synopsis: "Recursive descent parsing library for ocaml" 4 | description: 5 | "Monadic, recursive descent based, parser construction library for ocaml. Comprehensively documented and tested" 6 | maintainer: ["Bikal Lem"] 7 | authors: ["Bikal Lem "] 8 | license: "MPL-2.0" 9 | homepage: "https://github.com/lemaetech/reparse" 10 | bug-reports: "https://github.com/lemaetech/reparse/issues" 11 | depends: [ 12 | "dune" {>= "2.9"} 13 | "ocaml" {>= "4.10.0"} 14 | "cstruct" {>= "6.0.0"} 15 | "mdx" {with-test} 16 | "popper" {with-test} 17 | "ppx_deriving_popper" {with-test} 18 | "ppx_deriving" {with-test} 19 | "odoc" {with-doc} 20 | ] 21 | build: [ 22 | ["dune" "subst"] {dev} 23 | [ 24 | "dune" 25 | "build" 26 | "-p" 27 | name 28 | "-j" 29 | jobs 30 | "@install" 31 | "@doc" {with-doc} 32 | ] 33 | ] 34 | dev-repo: "git+https://github.com/lemaetech/reparse.git" 35 | -------------------------------------------------------------------------------- /docs/reparse-lwt/index.html: -------------------------------------------------------------------------------- 1 | 2 | index (reparse-lwt.index)

reparse-lwt index

Library reparse-lwt

The entry point of this library is the module: Reparse_lwt.

-------------------------------------------------------------------------------- /docs/reparse-lwt/Reparse_lwt/index.html: -------------------------------------------------------------------------------- 1 | 2 | Reparse_lwt (reparse-lwt.Reparse_lwt)

Module Reparse_lwt

module Stream : sig ... end
-------------------------------------------------------------------------------- /lwt/reparse_lwt.ml: -------------------------------------------------------------------------------- 1 | (*------------------------------------------------------------------------- 2 | * Copyright (c) 2020, 2021 Bikal Gurung. All rights reserved. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | * 8 | * %%NAME%% %%VERSION%% 9 | *-------------------------------------------------------------------------*) 10 | 11 | module Promise = struct 12 | type 'a t = 'a Lwt.t 13 | 14 | let return = Lwt.return 15 | let bind f p = Lwt.bind p f 16 | let catch = Lwt.catch 17 | end 18 | 19 | module Stream = struct 20 | module Input = 21 | Reparse.Make_buffered_input 22 | (Promise) 23 | (struct 24 | type t = char Lwt_stream.t 25 | type 'a promise = 'a Lwt.t 26 | 27 | let read_char t = 28 | let open Lwt.Infix in 29 | Lwt_stream.get t 30 | >|= function 31 | | Some c -> 32 | let cs = Cstruct.create 1 in 33 | Cstruct.set_char cs 0 c ; `Cstruct cs 34 | | None -> `Eof 35 | 36 | let read t ~len = 37 | let open Lwt.Infix in 38 | if len = 1 then read_char t 39 | else 40 | Lwt_stream.nget len t 41 | >|= fun chars -> 42 | let len'' = List.length chars in 43 | if len'' > 0 then 44 | `Cstruct 45 | (chars |> List.to_seq |> String.of_seq |> Cstruct.of_string) 46 | else `Eof 47 | end) 48 | 49 | include Reparse.Make (Promise) (Input) 50 | 51 | let create_input stream = Input.create stream 52 | end 53 | -------------------------------------------------------------------------------- /tests/test_input_parsers.ml: -------------------------------------------------------------------------------- 1 | module Make_test (P : Test_parser.TEST_PARSER) = struct 2 | open Test_parser.Make_helper (P) 3 | 4 | let trim_input_buffer = 5 | let p = 6 | P.( 7 | string_cs "hello" *> trim_input_buffer 8 | <* string_cs " world" *> trim_input_buffer) 9 | in 10 | let inp () = P.of_string "hello world" in 11 | Popper.( 12 | suite 13 | [ ( "value is ()" 14 | , test (fun () -> equal unit_result_comparator (P.run p inp) (Ok ())) 15 | ) 16 | ; pos_test p 11 inp 17 | ; last_trimmed_pos_test p 11 inp ]) 18 | 19 | let advance = 20 | let p = P.advance 6 in 21 | let inp () = P.of_string "hello world" in 22 | Popper.( 23 | suite 24 | [ ( "value is ()" 25 | , test (fun () -> equal unit_result_comparator (P.run p inp) (Ok ())) 26 | ) 27 | ; pos_test p 6 inp 28 | ; last_trimmed_pos_test p 0 inp 29 | ; ( "value is world" 30 | , test (fun () -> 31 | let p = P.(advance 6 *> string_cs "world") in 32 | equal string_result_comparator (P.run p inp) (Ok "world") ) ) ]) 33 | 34 | let suites = 35 | Popper.suite [("trim_input_buffer", trim_input_buffer); ("advance", advance)] 36 | end 37 | 38 | let suite = 39 | let module String = Make_test (Test_parser.String) in 40 | let module Lwt_stream = Make_test (Test_parser.Lwt_stream) in 41 | let module Lwt_fd = Make_test (Test_parser.Lwt_fd) in 42 | let module Lwt_channel = Make_test (Test_parser.Lwt_channel) in 43 | Popper.suite 44 | [ ("Reparse.String", String.suites) 45 | ; ("Reparse_lwt.Stream", Lwt_stream.suites) 46 | ; ("Reparse_lwt_unix.Fd", Lwt_fd.suites) 47 | ; ("Reparse_lwt_unix.Channel", Lwt_channel.suites) ] 48 | -------------------------------------------------------------------------------- /lwt-unix/reparse_lwt_unix.ml: -------------------------------------------------------------------------------- 1 | (*------------------------------------------------------------------------- 2 | * Copyright (c) 2020, 2021 Bikal Gurung. All rights reserved. 3 | * 4 | * This Source Code Form is subject to the terms of the Mozilla Public 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this 6 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 7 | * 8 | * %%NAME%% %%VERSION%% 9 | *-------------------------------------------------------------------------*) 10 | 11 | open Lwt.Infix 12 | 13 | module Promise = struct 14 | type 'a t = 'a Lwt.t 15 | 16 | let return = Lwt.return 17 | let bind f p = Lwt.bind p f 18 | let catch = Lwt.catch 19 | end 20 | 21 | module type READER = sig 22 | type t 23 | 24 | val read_into_bigstring : 25 | t -> Cstruct.buffer -> off:int -> len:int -> int Lwt.t 26 | end 27 | 28 | module Make_parser (Reader : READER) = struct 29 | module Input = 30 | Reparse.Make_buffered_input 31 | (Promise) 32 | (struct 33 | type t = Reader.t 34 | type 'a promise = 'a Lwt.t 35 | 36 | let read t ~len = 37 | let buf = Cstruct.create len in 38 | Reader.read_into_bigstring t buf.buffer ~off:0 ~len 39 | >|= fun read_count -> 40 | if read_count <= 0 then `Eof 41 | else if read_count < len then `Cstruct (Cstruct.sub buf 0 read_count) 42 | else `Cstruct buf 43 | end) 44 | 45 | include Reparse.Make (Promise) (Input) 46 | end 47 | 48 | module Fd = struct 49 | module Reader = struct 50 | type t = Lwt_unix.file_descr 51 | 52 | let read_into_bigstring t buf ~off ~len = Lwt_bytes.read t buf off len 53 | end 54 | 55 | include Make_parser (Reader) 56 | 57 | let create_input file_descr = Input.create file_descr 58 | end 59 | 60 | module Channel = struct 61 | module Reader = struct 62 | type t = Lwt_io.input_channel 63 | 64 | let read_into_bigstring t buf ~off ~len = 65 | Lwt_io.read_into_bigstring t buf off len 66 | end 67 | 68 | include Make_parser (Reader) 69 | 70 | let create_input channel = Input.create channel 71 | end 72 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ## v3.1.0 (Unreleased) 2 | 3 | - Add `unsafe_take_cstruct_exact` and `unsafe_take_cstruct_ne` parsers. 4 | - `PARSER.parse` function now takes `?pos` parameter and returns `pos` along with the parsed value. This allows creating pull based parsers. 5 | - Expose `Promise` module. 6 | 7 | ## v3.0.1 2021-06-29 8 | 9 | - Fix `take_while` 10 | 11 | ## v3.0.0 2021-06-23 UK 12 | 13 | - Overhaul parser implementation - use functor based implementation. Introduce, `Make_buffered_input`, `Make_unbuffered_input` and `Make` functors. 14 | - Remove `reparse-unix` package 15 | - Remove base dependency 16 | - Facilitate IO promise monads such as `Lwt` and `Async` 17 | - Add package `reparse-lwt` which defines `Lwt_stream.t` as one of the input sources. 18 | - Add package 'reparse-lwt-unix' which defines `Lwt_unix.file_descr` and `Lwt_io.input_channel` as parser input sources. 19 | 20 | ## v2.1.0 2021-04-06 UK 21 | 22 | This release has backwards incompatible changes. 23 | 24 | - Infix functions are now available in `Parser` module itself. 25 | - Add support for let operators - `let+`, `let*` ,`and+` and `and*`. 26 | - `bind` and `map` function are now labelled following `base` library 27 | dependency convention. 28 | - Items in `all_unit` are now `unit t` rather than `_ t` following monad 29 | combinator convention in `base` library dependency. 30 | - `pure` is now deprecated. Use `return` instead. This is to stay consistent 31 | with monad conventions in `base` library dependency. 32 | - `>|=` is deprecated. Use `>>|` instead. This is to stay consistent with monad 33 | conventions in `base` library dependency. 34 | - Removed `map4` function. 35 | - Add support for `ppx_let`. 36 | - Deprecate `Parser` module. Use `Reparse` instead. 37 | 38 | ## v2.0.0 2020-11-09 UK 39 | 40 | - Rewrite the whole package to use exceptions rather than `result` type 41 | - Adds many more parsing combinators 42 | - Adds comprehensive unit tests 43 | - Adds comprehensive documentation, host documentation and add links in repo home page 44 | - Adds abstraction for input source 45 | - Provides unix file source and string input source 46 | - Adds separate package `reparse-unix` for unix file input 47 | - Adds calc.ml and json.ml in examples. 48 | 49 | ## v1.2.0 2020-09-13 UK 50 | 51 | - Remove Result and underlying monad 52 | - Remove sexplib0, bigstringaf 53 | - Prune basic parsers 54 | 55 | ## v1.0.2 2020-07-30 UK 56 | 57 | - Add string_if parser. 58 | 59 | ## v1.0.1 2020-07-30 UK 60 | 61 | - Add sexp_of_error. 62 | 63 | ## v1.0.0 2020-07-23 Reading, UK 64 | 65 | - First release. 66 | -------------------------------------------------------------------------------- /docs/reparse/Reparse/Make/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse.Reparse.Make.Let_syntax)

Module Make.Let_syntax

ppx_let syntax support module.

val return : 'a -> 'a t
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
module Let_syntax : sig ... end
-------------------------------------------------------------------------------- /docs/reparse/Reparse/String/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse.Reparse.String.Let_syntax)

Module String.Let_syntax

ppx_let syntax support module.

val return : 'a -> 'a t
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
module Let_syntax : sig ... end
-------------------------------------------------------------------------------- /docs/reparse/Reparse/module-type-PARSER/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse.Reparse.PARSER.Let_syntax)

Module PARSER.Let_syntax

ppx_let syntax support module.

val return : 'a -> 'a t
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
module Let_syntax : sig ... end
-------------------------------------------------------------------------------- /docs/reparse-lwt/Reparse_lwt/Stream/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse-lwt.Reparse_lwt.Stream.Let_syntax)

Module Stream.Let_syntax

ppx_let syntax support module.

val return : 'a -> 'a t
val (>>|) : 'a t -> ('a -> 'b) -> 'b t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
module Let_syntax : sig ... end
-------------------------------------------------------------------------------- /tests/test_boolean_parsers.ml: -------------------------------------------------------------------------------- 1 | module Make_test (P : Test_parser.TEST_PARSER) = struct 2 | open Test_parser.Make_helper (P) 3 | open P.Infix 4 | 5 | let not_ = 6 | let p = P.(not_ (string_cs "hello")) in 7 | let p2 = P.(not_ (string_cs "world")) in 8 | let inp () = P.of_string "world" in 9 | Popper.( 10 | suite 11 | [ ( "value is ()" 12 | , test (fun () -> equal unit_result_comparator (P.run p inp) (Ok ())) 13 | ) 14 | ; pos_test p 0 inp 15 | ; last_trimmed_pos_test p 0 inp 16 | ; ( "fail" 17 | , test (fun () -> 18 | equal unit_result_comparator (P.run p2 inp) 19 | (Error "[not_] expected failure but succeeded") ) ) 20 | ; ( "pos is error" 21 | , test (fun () -> 22 | let p = p2 *> P.pos in 23 | equal int_result_comparator (P.run p inp) 24 | (Error "[not_] expected failure but succeeded") ) ) ]) 25 | 26 | let is = 27 | let p = P.(is (string_cs "hello")) in 28 | let p2 = P.(is (string_cs "world")) in 29 | let inp () = P.of_string "hello" in 30 | Popper.( 31 | suite 32 | [ ( "value is true" 33 | , test (fun () -> 34 | equal bool_result_comparator (P.run p inp) (Ok true) ) ) 35 | ; pos_test p 0 inp 36 | ; last_trimmed_pos_test p 0 inp 37 | ; ( "value is false" 38 | , test (fun () -> 39 | equal bool_result_comparator (P.run p2 inp) (Ok false) ) ) 40 | ; pos_test p2 0 inp 41 | ; last_trimmed_pos_test p2 0 inp ]) 42 | 43 | let is_not = 44 | let p = P.(is_not (string_cs "hello")) in 45 | let p2 = P.(is_not (string_cs "world")) in 46 | let inp () = P.of_string "world" in 47 | Popper.( 48 | suite 49 | [ ( "value is true" 50 | , test (fun () -> 51 | equal bool_result_comparator (P.run p inp) (Ok true) ) ) 52 | ; pos_test p 0 inp 53 | ; last_trimmed_pos_test p 0 inp 54 | ; ( "value is false" 55 | , test (fun () -> 56 | equal bool_result_comparator (P.run p2 inp) (Ok false) ) ) 57 | ; pos_test p2 0 inp 58 | ; last_trimmed_pos_test p2 0 inp ]) 59 | 60 | let suites = Popper.suite [("not_", not_); ("is", is); ("is_not", is_not)] 61 | end 62 | 63 | let suite = 64 | let module String = Make_test (Test_parser.String) in 65 | let module Lwt_stream = Make_test (Test_parser.Lwt_stream) in 66 | let module Lwt_fd = Make_test (Test_parser.Lwt_fd) in 67 | let module Lwt_channel = Make_test (Test_parser.Lwt_channel) in 68 | Popper.suite 69 | [ ("Reparse.String", String.suites) 70 | ; ("Reparse_lwt.Stream", Lwt_stream.suites) 71 | ; ("Reparse_lwt_unix.Fd", Lwt_fd.suites) 72 | ; ("Reparse_lwt_unix.Channel", Lwt_channel.suites) ] 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Reparse 2 | 3 | Reparse is a monadic, recursive descent based, comprehensive parser construction library for ocaml. 4 | 5 | [Reparse Documentation](https://lemaetech.co.uk/reparse/) 6 | 7 | ## Getting Started 8 | 9 | ``` 10 | $ opam install reparse 11 | ``` 12 | 13 | Add `reparse` to dune, 14 | 15 | ``` 16 | (executable # or library 17 | (name hello_world) 18 | (public_name hello_world) 19 | (libraries reparse)) 20 | ``` 21 | 22 | ## Example - Calculator 23 | 24 | A **calculator** is the `hello world` of parsers. Here is an implementation in `Reparse` which supports `+,-,*` and `/` operations. 25 | 26 | ```ocaml 27 | # #require "reparse";; 28 | ``` 29 | 30 | ```ocaml 31 | open Reparse.String 32 | 33 | type expr = 34 | | Int of int 35 | | Add of expr * expr 36 | | Sub of expr * expr 37 | | Mult of expr * expr 38 | | Div of expr * expr 39 | 40 | let skip_spaces = skip space 41 | 42 | let binop : 'a t -> char -> 'b t -> ('a -> 'b -> 'c) -> 'c t = 43 | fun exp1 op exp2 f -> 44 | (exp1, skip_spaces *> char op <* skip_spaces, exp2) 45 | <$$$> fun e1 _ e2 -> f e1 e2 46 | 47 | let integer : expr t = 48 | let+ d = skip_spaces *> digits <* skip_spaces in 49 | Int (int_of_string d) 50 | 51 | let factor : expr t -> expr t = 52 | fun expr -> 53 | any [ char '(' *> skip_spaces *> expr <* skip_spaces <* char ')'; integer ] 54 | 55 | let term : expr t -> expr t = 56 | fun factor -> 57 | recur (fun term -> 58 | let mult = binop factor '*' term (fun e1 e2 -> Mult (e1, e2)) in 59 | let div = binop factor '/' term (fun e1 e2 -> Div (e1, e2)) in 60 | mult <|> div <|> factor) 61 | 62 | let expr : expr t = 63 | recur (fun expr -> 64 | let factor = factor expr in 65 | let term = term factor in 66 | let add = binop term '+' expr (fun e1 e2 -> Add (e1, e2)) in 67 | let sub = binop term '-' expr (fun e1 e2 -> Sub (e1, e2)) in 68 | any [ add; sub; term ] "expr") 69 | 70 | let rec eval : expr -> int = function 71 | | Int i -> i 72 | | Add (e1, e2) -> eval e1 + eval e2 73 | | Sub (e1, e2) -> eval e1 - eval e2 74 | | Mult (e1, e2) -> eval e1 * eval e2 75 | | Div (e1, e2) -> eval e1 / eval e2 76 | ``` 77 | 78 | ```ocaml 79 | # let ast = parse (create_input_from_string "1*2-4+3") expr ;; 80 | val ast : (expr * int, string) result = 81 | Ok (Sub (Mult (Int 1, Int 2), Add (Int 4, Int 3)), 7) 82 | 83 | # eval @@ Result.get_ok (parse (create_input_from_string "12+1*10") expr);; 84 | Line 1, characters 9-72: 85 | Error: This expression has type expr * int 86 | but an expression was expected of type expr 87 | ``` 88 | 89 | ## More Examples 90 | 91 | - [HTTP Multipart](https://github.com/lemaetech/http-multipart-formdata/blob/master/src/http_multipart_formdata.ml) 92 | - [RFC 8259 JSON parser](https://github.com/lemaetech/reparse/blob/master/examples/json.ml) 93 | - [HTML5 parser](https://github.com/lemaetech/pp_html/blob/master/src/pp_html.ml) 94 | 95 | -------------------------------------------------------------------------------- /examples/calc.ml: -------------------------------------------------------------------------------- 1 | (** An implementation of a calculator. 2 | 3 | The expression grammar is defined by the following BNF grammar: 4 | 5 | {v 6 | ::= "+" 7 | | 8 | ::= "*" 9 | | 10 | ::= "(" ")" 11 | | integer 12 | v} 13 | 14 | Sample toplevel (utop/ocaml) inputs: 15 | 16 | {v 17 | parse "123";; 18 | parse "123 - 123";; 19 | parse "123+123";; 20 | parse "123*123";; 21 | parse "123*123 - 23*234";; 22 | v} *) 23 | 24 | open Reparse.String 25 | 26 | type expr = 27 | | Int of int 28 | | Add of expr * expr 29 | | Sub of expr * expr 30 | | Mult of expr * expr 31 | | Div of expr * expr 32 | 33 | let skip_spaces = skip space 34 | 35 | let binop : 'a t -> char -> 'b t -> ('a -> 'b -> 'c) -> 'c t = 36 | fun exp1 op exp2 f -> 37 | (exp1, skip_spaces *> char op <* skip_spaces, exp2) 38 | <$$$> fun e1 _ e2 -> f e1 e2 39 | 40 | let integer : expr t = 41 | let+ d = skip_spaces *> digits <* skip_spaces in 42 | Int (int_of_string d) 43 | 44 | let factor : expr t -> expr t = 45 | fun expr -> 46 | any [char '(' *> skip_spaces *> expr <* skip_spaces <* char ')'; integer] 47 | 48 | let term : expr t -> expr t = 49 | fun factor -> 50 | recur (fun term -> 51 | let mult = binop factor '*' term (fun e1 e2 -> Mult (e1, e2)) in 52 | let div = binop factor '/' term (fun e1 e2 -> Div (e1, e2)) in 53 | mult <|> div <|> factor ) 54 | 55 | let expr : expr t = 56 | recur (fun expr -> 57 | let factor = factor expr in 58 | let term = term factor in 59 | let add = binop term '+' expr (fun e1 e2 -> Add (e1, e2)) in 60 | let sub = binop term '-' expr (fun e1 e2 -> Sub (e1, e2)) in 61 | any [add; sub; term] "expr" ) 62 | 63 | let rec eval : expr -> int = function 64 | | Int i -> i 65 | | Add (e1, e2) -> eval e1 + eval e2 66 | | Sub (e1, e2) -> eval e1 - eval e2 67 | | Mult (e1, e2) -> eval e1 * eval e2 68 | | Div (e1, e2) -> eval e1 / eval e2 69 | 70 | (* Test AST *) 71 | let r = 72 | let actual = parse (create_input_from_string "1*2-4+3") expr in 73 | let expected = Ok (Sub (Mult (Int 1, Int 2), Add (Int 4, Int 3)), 7) in 74 | Bool.equal (expected = actual) true 75 | 76 | (* Run and test the evaluator. *) 77 | let exp_result = 78 | let v = 79 | let expr, _ = 80 | Result.get_ok (parse (create_input_from_string "12+1*10") expr) 81 | in 82 | eval expr 83 | in 84 | Int.equal 22 v 85 | 86 | (*------------------------------------------------------------------------- 87 | * Copyright (c) 2020 Bikal Gurung. All rights reserved. 88 | * 89 | * This Source Code Form is subject to the terms of the Mozilla Public 90 | * License, v. 2.0. If a copy of the MPL was not distributed with this 91 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 92 | * 93 | * %%NAME%% %%VERSION%% 94 | *-------------------------------------------------------------------------*) 95 | -------------------------------------------------------------------------------- /tests/test_parser.ml: -------------------------------------------------------------------------------- 1 | module type TEST_PARSER = sig 2 | include Reparse.PARSER 3 | 4 | val of_string : string -> input promise 5 | val run : 'a t -> (unit -> input promise) -> ('a, string) result 6 | end 7 | 8 | module String : TEST_PARSER = struct 9 | include Reparse.String 10 | 11 | let of_string = create_input_from_string 12 | 13 | let run p i = 14 | match parse (i ()) p with Ok (x, _) -> Ok x | Error _ as e -> e 15 | end 16 | 17 | module Lwt_stream : TEST_PARSER = struct 18 | include Reparse_lwt.Stream 19 | 20 | let of_string s = Lwt.return (create_input (Lwt_stream.of_string s)) 21 | 22 | let run p inp = 23 | Lwt.Infix.(inp () >>= fun inp -> parse inp p) 24 | |> Lwt_main.run 25 | |> function Ok (x, _) -> Ok x | Error _ as e -> e 26 | end 27 | 28 | module Lwt_fd : TEST_PARSER = struct 29 | include Reparse_lwt_unix.Fd 30 | 31 | let of_string s = 32 | let tmpfile_name, tmpfile_oc = Filename.open_temp_file "test" "lwt_fd" in 33 | output_string tmpfile_oc s ; 34 | close_out tmpfile_oc ; 35 | Lwt.Infix.( 36 | Lwt_unix.(openfile tmpfile_name [O_RDONLY] 0o640) 37 | >|= fun fd -> create_input fd) 38 | 39 | let run p inp = 40 | Lwt.Infix.(inp () >>= fun inp -> parse inp p) 41 | |> Lwt_main.run 42 | |> function Ok (x, _) -> Ok x | Error _ as e -> e 43 | end 44 | 45 | module Lwt_channel : TEST_PARSER = struct 46 | include Reparse_lwt_unix.Channel 47 | 48 | let of_string s = 49 | Lwt_io.(of_bytes ~mode:Input (Lwt_bytes.of_string s)) 50 | |> create_input |> Lwt.return 51 | 52 | let run p inp = 53 | Lwt.Infix.(inp () >>= fun inp -> parse inp p) 54 | |> Lwt_main.run 55 | |> function Ok (x, _) -> Ok x | Error _ as e -> e 56 | end 57 | 58 | module Make_helper (P : TEST_PARSER) = struct 59 | type int_result = (int, string) result [@@deriving show, ord, popper] 60 | type string_result = (string, string) result [@@deriving show, ord, popper] 61 | 62 | type string_opt_result = (string option, string) result 63 | [@@deriving show, ord, popper] 64 | 65 | type char_result = (char, string) result [@@deriving show, ord, popper] 66 | 67 | type char_opt_result = (char option, string) result 68 | [@@deriving show, ord, popper] 69 | 70 | type unit_result = (unit, string) result [@@deriving show, ord, popper] 71 | type bool_result = (bool, string) result [@@deriving show, ord, popper] 72 | 73 | type int_opt_result = (int option, string) result 74 | [@@deriving show, ord, popper] 75 | 76 | open P.Infix 77 | 78 | let pos_test p pos inp = 79 | ( Format.sprintf "pos is %d" pos 80 | , Popper.( 81 | test (fun () -> 82 | let p = p *> P.pos in 83 | equal int_result_comparator (P.run p inp) (Ok pos) )) ) 84 | 85 | let last_trimmed_pos_test p pos inp = 86 | ( Format.asprintf "last_trimmed_pos is %d" pos 87 | , Popper.( 88 | test (fun () -> 89 | let p = p *> P.last_trimmed_pos in 90 | equal int_result_comparator (P.run p inp) (Ok pos) )) ) 91 | 92 | let buffer_size_test p sz inp = 93 | let pp_int_opt fmt = Format.pp_print_option Format.pp_print_int fmt in 94 | ( Format.asprintf "buffer size is %a" pp_int_opt sz 95 | , Popper.( 96 | test (fun () -> 97 | let p = p *> P.input_buffer_size in 98 | equal int_opt_result_comparator (P.run p inp) (Ok sz) )) ) 99 | 100 | let empty () = P.of_string "" 101 | end 102 | -------------------------------------------------------------------------------- /tests/test_alternative_parsers.ml: -------------------------------------------------------------------------------- 1 | module Make_test (P : Test_parser.TEST_PARSER) = struct 2 | open Test_parser.Make_helper (P) 3 | open P.Infix 4 | 5 | let any = 6 | let p = P.(any [string_cs "c"; string_cs "h"]) in 7 | let p2 = P.(any [string_cs "hello"; take_string 11]) in 8 | let p3 = P.(any [take_string 2; string_cs "hello"]) in 9 | let inp () = P.of_string "hello" in 10 | Popper.( 11 | suite 12 | [ ( {|value is "h"|} 13 | , test (fun () -> 14 | equal string_result_comparator (P.run p inp) (Ok "h") ) ) 15 | ; pos_test p 1 inp 16 | ; last_trimmed_pos_test p 0 inp 17 | ; ( "fail" 18 | , test (fun () -> 19 | let p = P.(any [string_cs "a"; string_cs "b"]) in 20 | equal string_result_comparator (P.run p inp) 21 | (Error "[any] all parsers failed") ) ) 22 | ; ( {|first success value is "hello"|} 23 | , test (fun () -> 24 | equal string_result_comparator (P.run p2 inp) (Ok "hello") ) ) 25 | ; pos_test p2 5 inp 26 | ; last_trimmed_pos_test p2 0 inp 27 | ; ( {|first success value is "he"|} 28 | , test (fun () -> 29 | equal string_result_comparator (P.run p3 inp) (Ok "he") ) ) 30 | ; pos_test p3 2 inp 31 | ; last_trimmed_pos_test p3 0 inp ]) 32 | 33 | let alt = 34 | let p = P.(alt (string_cs "world") (string_cs "hello")) in 35 | let p2 = P.(alt (string_cs "world") (string_cs "how")) in 36 | let inp () = P.of_string "hello" in 37 | Popper.( 38 | suite 39 | [ ( "value is hello" 40 | , test (fun () -> 41 | equal string_result_comparator (P.run p inp) (Ok "hello") ) ) 42 | ; pos_test p 5 inp 43 | ; last_trimmed_pos_test p 0 inp 44 | ; ( "fail" 45 | , test (fun () -> 46 | equal string_result_comparator (P.run p2 inp) 47 | (Error {|[string_cs] "how"|}) ) ) 48 | ; ( "pos is fail" 49 | , test (fun () -> 50 | let p = p2 *> P.pos in 51 | equal int_result_comparator (P.run p inp) 52 | (Error {|[string_cs] "how"|}) ) ) 53 | ; ( "last_trimmed_pos is fail" 54 | , test (fun () -> 55 | let p = p2 *> P.last_trimmed_pos in 56 | equal int_result_comparator (P.run p inp) 57 | (Error {|[string_cs] "how"|}) ) ) ]) 58 | 59 | let optional = 60 | let p = P.(optional (string_cs "hello")) in 61 | let inp () = P.of_string "hello" in 62 | let inp2 () = P.of_string "world" in 63 | Popper.( 64 | suite 65 | [ ( {|value is 'Some "hello"']|} 66 | , test (fun () -> 67 | equal string_opt_result_comparator (P.run p inp) 68 | (Ok (Some "hello")) ) ) 69 | ; pos_test p 5 inp 70 | ; last_trimmed_pos_test p 0 inp 71 | ; ( {|value is 'None'|} 72 | , test (fun () -> 73 | equal string_opt_result_comparator (P.run p inp2) (Ok None) ) ) 74 | ; pos_test p 0 inp2 75 | ; last_trimmed_pos_test p 0 inp2 76 | ; ( {|value when eof is 'None'|} 77 | , test (fun () -> 78 | equal string_opt_result_comparator (P.run p empty) (Ok None) ) 79 | ) ]) 80 | 81 | let suites = Popper.suite [("any", any); ("alt", alt); ("optional", optional)] 82 | end 83 | 84 | let suite = 85 | let module String = Make_test (Test_parser.String) in 86 | let module Lwt_stream = Make_test (Test_parser.Lwt_stream) in 87 | let module Lwt_fd = Make_test (Test_parser.Lwt_fd) in 88 | let module Lwt_channel = Make_test (Test_parser.Lwt_channel) in 89 | Popper.suite 90 | [ ("Reparse.String", String.suites) 91 | ; ("Reparse_lwt.Stream", Lwt_stream.suites) 92 | ; ("Reparse_lwt_unix.Fd", Lwt_fd.suites) 93 | ; ("Reparse_lwt_unix.Channel", Lwt_channel.suites) ] 94 | -------------------------------------------------------------------------------- /docs/reparse/Reparse/index.html: -------------------------------------------------------------------------------- 1 | 2 | Reparse (reparse.Reparse)

Module Reparse

Overview

Parser provides functions and types to construct robust, performant and reusable parsers. At the core is a type Reparse.PARSER.t which represents a constructed parser definition. A parser Reparse.PARSER.t is defined by composing together one or more parsers or Reparse.ts via usage of parser operators.

An instance of Reparse.PARSER.t represents an un-evaluated parser. Use Reparse.PARSER.parse function to evaluate it.

Reparse.INPUT represents a generalization of data input to Reparse.parse. Implement the interface to create new input types.

Parser functions are broadly organized into following categories:

  • Monadic parsers
  • Char/String parsers
  • Alternate parsers
  • Boolean parsers
  • Repetition parsers
  • RFC 5234 parsers
  • Others
module type PARSER = sig ... end
module type INPUT = sig ... end
module Make (Input : INPUT) : PARSER with type 'a promise = 'a Input.promise with type input = Input.t

A functor to create parsers based on the given Input module.

module String : sig ... end

A parser when the input is a string.

-------------------------------------------------------------------------------- /docs/reparse/Reparse/module-type-INPUT/index.html: -------------------------------------------------------------------------------- 1 | 2 | INPUT (reparse.Reparse.INPUT)

Module type Reparse.INPUT

type t

Represents the input.

type 'a promise

Represents an input promise.

val return : 'a -> 'a promise
val bind : ('a -> 'b promise) -> 'a promise -> 'b promise
val commit : t -> pos:int -> unit promise

commit t ~pos ensures that the parser will not backtrack on input t beyond pos.

val get : t -> pos:int -> len:int -> [ `Cstruct of Cstruct.t | `Eof ] promise

get t ~pos ~len returns `String s where String.length s <= len or `Eof if EOI is reached.

val get_unbuffered : t -> pos:int -> len:int -> [ `Cstruct of Cstruct.t | `Eof ] promise

get_unbuffered t ~pos ~len similar to get t ~pos ~len except it doesn't buffer the taken len bytes.

val committed_pos : t -> int promise
-------------------------------------------------------------------------------- /docs/reparse/Reparse/Make/argument-1-Input/index.html: -------------------------------------------------------------------------------- 1 | 2 | Input (reparse.Reparse.Make.1-Input)

Parameter Make.1-Input

type t

Represents the input.

type 'a promise

Represents an input promise.

val return : 'a -> 'a promise
val bind : ('a -> 'b promise) -> 'a promise -> 'b promise
val commit : t -> pos:int -> unit promise

commit t ~pos ensures that the parser will not backtrack on input t beyond pos.

val get : t -> pos:int -> len:int -> [ `Cstruct of Cstruct.t | `Eof ] promise

get t ~pos ~len returns `String s where String.length s <= len or `Eof if EOI is reached.

val get_unbuffered : t -> pos:int -> len:int -> [ `Cstruct of Cstruct.t | `Eof ] promise

get_unbuffered t ~pos ~len similar to get t ~pos ~len except it doesn't buffer the taken len bytes.

val committed_pos : t -> int promise
-------------------------------------------------------------------------------- /examples/json.ml: -------------------------------------------------------------------------------- 1 | (** Implement JSON parser as defined at https://tools.ietf.org/html/rfc8259. 2 | 3 | Assumes UTF-8 character encoding. However, it doesn't do any validation. 4 | 5 | Note: It is unknown if the parser fully conforms to RFC 8259 as no testing, 6 | validation is done. The RFC is used mainly as a guidance and the sample is 7 | meant to demonstrate parser construction using reparse rather than a 8 | production grade parser. 9 | 10 | Sample top_level inputs; 11 | 12 | {v 13 | parse "true";; parse "false";; 14 | parse "null";; parse "123";; 15 | parse "123.345";; 16 | parse "123e123";; 17 | parse "123.33E123";; 18 | parse {|{"field1":123,"field2": "value2"}|};; 19 | parse {|{"field1":[123,"hello",-123.23], "field2":123} |};; 20 | parse {|{"field1":123, "field2":123} |};; 21 | parse {|[123,"hello",-123.23, 123.33e13, 123E23] |};; 22 | v} *) 23 | 24 | open Reparse.String 25 | 26 | type value = 27 | | Object of (string * value) list 28 | | Array of value list 29 | | Number of 30 | {negative: bool; int: string; frac: string option; exponent: string option} 31 | | String of string 32 | | False 33 | | True 34 | | Null 35 | 36 | let ws = 37 | skip (char_if (function ' ' | '\t' | '\n' | '\r' -> true | _ -> false)) 38 | 39 | let struct_char c = ws *> char c <* ws 40 | let null_value = ws *> string_cs "null" *> ws *> return Null 41 | let false_value = ws *> string_cs "false" *> ws *> return False 42 | let true_value = ws *> string_cs "true" *> ws *> return True 43 | 44 | let number_value = 45 | let* negative = 46 | optional (char '-') >>| function Some '-' -> true | _ -> false 47 | in 48 | let* int = 49 | let digits1_to_9 = char_if (function '1' .. '9' -> true | _ -> false) in 50 | let num = 51 | map2 52 | (fun first_ch digits -> Format.sprintf "%c%s" first_ch digits) 53 | digits1_to_9 digits 54 | in 55 | any [string_cs "0"; num] 56 | in 57 | let* frac = optional (char '.' *> digits) in 58 | let+ exponent = 59 | optional 60 | (let* e = char 'E' <|> char 'e' in 61 | let* sign = optional (char '-' <|> char '+') in 62 | let sign = 63 | match sign with Some c -> Format.sprintf "%c" c | None -> "" 64 | in 65 | let+ digits = digits in 66 | Format.sprintf "%c%s%s" e sign digits ) 67 | in 68 | Number {negative; int; frac; exponent} 69 | 70 | let string = 71 | let escaped = 72 | let ch = 73 | char '\\' 74 | *> char_if (function 75 | | '"' | '\\' | '/' | 'b' | 'f' | 'n' | 'r' | 't' -> true 76 | | _ -> false ) 77 | >>| Format.sprintf "\\%c" 78 | in 79 | let hex4digit = 80 | let+ hex = 81 | string_cs "\\u" *> take ~at_least:4 ~up_to:4 hex_digit 82 | >>= string_of_chars 83 | in 84 | Format.sprintf "\\u%s" hex 85 | in 86 | any [ch; hex4digit] 87 | in 88 | let unescaped = 89 | take_while ~while_:(is_not (any [char '\\'; control; dquote])) any_char 90 | >>= string_of_chars 91 | in 92 | let+ str = dquote *> take (any [escaped; unescaped]) <* dquote in 93 | String.concat "" str 94 | 95 | let string_value = string >>| fun s -> String s 96 | 97 | let json_value = 98 | recur (fun value -> 99 | let value_sep = struct_char ',' in 100 | let object_value = 101 | let member = 102 | let* nm = string <* struct_char ':' in 103 | let+ v = value in 104 | (nm, v) 105 | in 106 | let+ object_value = 107 | struct_char '{' *> take member ~sep_by:value_sep <* struct_char '}' 108 | in 109 | Object object_value 110 | in 111 | let array_value = 112 | let+ vals = 113 | struct_char '[' *> take value ~sep_by:value_sep <* struct_char ']' 114 | in 115 | Array vals 116 | in 117 | any 118 | [ object_value 119 | ; array_value 120 | ; number_value 121 | ; string_value 122 | ; false_value 123 | ; true_value 124 | ; null_value ] ) 125 | 126 | let parse s = parse s json_value 127 | 128 | (*------------------------------------------------------------------------- * 129 | Copyright (c) 2020 Bikal Gurung. All rights reserved. * * This Source Code 130 | Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a 131 | copy of the MPL was not distributed with this * file, You can obtain one at 132 | https://mozilla.org/MPL/2.0/. * * %%NAME%% %%VERSION%% 133 | *-------------------------------------------------------------------------*) 134 | -------------------------------------------------------------------------------- /docs/reparse/Reparse/Make/Let_syntax/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse.Reparse.Make.Let_syntax.Let_syntax)

Module Let_syntax.Let_syntax

val return : 'a -> 'a t
val map : 'a t -> f:('a -> 'b) -> 'b t
val bind : 'a t -> f:('a -> 'b t) -> 'b t
val both : 'a t -> 'b t -> ('a * 'b) t
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
val map4 : 'a t -> 'b t -> 'c t -> 'd t -> f:('a -> 'b -> 'c -> 'd -> 'e) -> 'e t
-------------------------------------------------------------------------------- /docs/reparse/Reparse/String/Let_syntax/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse.Reparse.String.Let_syntax.Let_syntax)

Module Let_syntax.Let_syntax

val return : 'a -> 'a t
val map : 'a t -> f:('a -> 'b) -> 'b t
val bind : 'a t -> f:('a -> 'b t) -> 'b t
val both : 'a t -> 'b t -> ('a * 'b) t
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
val map4 : 'a t -> 'b t -> 'c t -> 'd t -> f:('a -> 'b -> 'c -> 'd -> 'e) -> 'e t
-------------------------------------------------------------------------------- /docs/reparse/Reparse/module-type-PARSER/Let_syntax/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse.Reparse.PARSER.Let_syntax.Let_syntax)

Module Let_syntax.Let_syntax

val return : 'a -> 'a t
val map : 'a t -> f:('a -> 'b) -> 'b t
val bind : 'a t -> f:('a -> 'b t) -> 'b t
val both : 'a t -> 'b t -> ('a * 'b) t
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
val map4 : 'a t -> 'b t -> 'c t -> 'd t -> f:('a -> 'b -> 'c -> 'd -> 'e) -> 'e t
-------------------------------------------------------------------------------- /docs/reparse-lwt/Reparse_lwt/Stream/Let_syntax/Let_syntax/index.html: -------------------------------------------------------------------------------- 1 | 2 | Let_syntax (reparse-lwt.Reparse_lwt.Stream.Let_syntax.Let_syntax)

Module Let_syntax.Let_syntax

val return : 'a -> 'a t
val map : 'a t -> f:('a -> 'b) -> 'b t
val bind : 'a t -> f:('a -> 'b t) -> 'b t
val both : 'a t -> 'b t -> ('a * 'b) t
val map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c t
val map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd t
val map4 : 'a t -> 'b t -> 'c t -> 'd t -> f:('a -> 'b -> 'c -> 'd -> 'e) -> 'e t
-------------------------------------------------------------------------------- /tests/test_string_parsers.ml: -------------------------------------------------------------------------------- 1 | module Make_test (P : Test_parser.TEST_PARSER) = struct 2 | open Test_parser.Make_helper (P) 3 | open P.Infix 4 | 5 | let peek_char = 6 | let p = P.peek_char in 7 | let inp () = P.of_string "hello world" in 8 | Popper.( 9 | suite 10 | [ ( "value is 'h'" 11 | , test (fun () -> equal char_result_comparator (P.run p inp) (Ok 'h')) 12 | ) 13 | ; pos_test p 0 inp 14 | ; last_trimmed_pos_test p 0 inp 15 | ; ( "fail on eof" 16 | , test (fun () -> 17 | equal char_result_comparator (P.run p empty) 18 | (Error "[peek_char] pos:0 eof") ) ) ]) 19 | 20 | let peek_char_opt = 21 | let p = P.peek_char_opt in 22 | let inp () = P.of_string "hello world" in 23 | Popper.( 24 | suite 25 | [ ( "value is 'h'" 26 | , test (fun () -> 27 | equal char_opt_result_comparator (P.run p inp) (Ok (Some 'h')) ) 28 | ) 29 | ; pos_test p 0 inp 30 | ; last_trimmed_pos_test p 0 inp 31 | ; ( "fail on eof" 32 | , test (fun () -> 33 | equal char_opt_result_comparator (P.run p empty) (Ok None) ) ) 34 | ]) 35 | 36 | let peek_string = 37 | let p = P.peek_string 5 in 38 | let inp () = P.of_string "hello" in 39 | Popper.( 40 | suite 41 | [ ( "value is \"hello\"" 42 | , test (fun () -> 43 | equal string_result_comparator (P.run p inp) (Ok "hello") ) ) 44 | ; pos_test p 0 inp 45 | ; last_trimmed_pos_test p 0 inp ]) 46 | 47 | let any_char = 48 | let p = P.any_char in 49 | let inp () = P.of_string "hello" in 50 | Popper.( 51 | suite 52 | [ ( "value is 'h'" 53 | , test (fun () -> equal char_result_comparator (P.run p inp) (Ok 'h')) 54 | ) 55 | ; pos_test p 1 inp 56 | ; last_trimmed_pos_test p 0 inp 57 | ; ( "fail on eof" 58 | , test (fun () -> 59 | equal char_result_comparator (P.run p empty) 60 | (Error "[any_char] pos:0 eof") ) ) ]) 61 | 62 | let unsafe_any_char = 63 | let p = P.unsafe_any_char in 64 | let inp () = P.of_string "hello" in 65 | let p2 = 66 | (P.unsafe_any_char, P.unsafe_any_char, P.unsafe_any_char) 67 | <$$$> (fun c1 c2 c3 -> List.to_seq [c1; c2; c3] |> String.of_seq) 68 | >>= fun s -> P.trim_input_buffer $> s 69 | in 70 | Popper.( 71 | suite 72 | [ ( "value is 'h'" 73 | , test (fun () -> equal char_result_comparator (P.run p inp) (Ok 'h')) 74 | ) 75 | ; pos_test p 1 inp 76 | ; last_trimmed_pos_test p 0 inp 77 | ; ( "fail on eof" 78 | , test (fun () -> 79 | equal char_result_comparator (P.run p empty) 80 | (Error "[unsafe_any_char] pos:0 eof") ) ) 81 | ; ( {|value is "hel"|} 82 | , test (fun () -> 83 | equal string_result_comparator (P.run p2 inp) (Ok "hel") ) ) 84 | ; pos_test p2 3 inp 85 | ; last_trimmed_pos_test p2 3 inp ]) 86 | 87 | let char = 88 | let p = P.char 'h' in 89 | let inp () = P.of_string "hello" in 90 | Popper.( 91 | suite 92 | [ ( "value is 'h'" 93 | , test (fun () -> equal char_result_comparator (P.run p inp) (Ok 'h')) 94 | ) 95 | ; pos_test p 1 inp 96 | ; last_trimmed_pos_test p 0 inp 97 | ; ( "fail on 'c'" 98 | , test (fun () -> 99 | let p = P.char 'c' in 100 | equal char_result_comparator (P.run p inp) 101 | (Error "[char] pos:0, expected 'c', got 'h'") ) ) ]) 102 | 103 | let char_if = 104 | let p = P.char_if (fun c -> Char.equal 'h' c) in 105 | let inp () = P.of_string "hello" in 106 | Popper.( 107 | suite 108 | [ ( "value is 'h'" 109 | , test (fun () -> equal char_result_comparator (P.run p inp) (Ok 'h')) 110 | ) 111 | ; pos_test p 1 inp 112 | ; last_trimmed_pos_test p 0 inp 113 | ; ( "fail on 'c'" 114 | , test (fun () -> 115 | let p = P.char_if (fun c -> Char.equal 'c' c) in 116 | equal char_result_comparator (P.run p inp) 117 | (Error "[char_if] pos:0 'h'") ) ) ]) 118 | 119 | let string_cs = 120 | let p = P.string_cs "hello" in 121 | let inp () = P.of_string "hello world" in 122 | Popper.( 123 | suite 124 | [ ( "value is 'hello'" 125 | , test (fun () -> 126 | equal string_result_comparator (P.run p inp) (Ok "hello") ) ) 127 | ; pos_test p 5 inp 128 | ; last_trimmed_pos_test p 0 inp 129 | ; ( "fail" 130 | , test (fun () -> 131 | let p = P.string_cs "bye" in 132 | equal string_result_comparator (P.run p inp) 133 | (Error "[string_cs] \"bye\"") ) ) 134 | ; ( "case sensitive" 135 | , test (fun () -> 136 | let inp () = P.of_string "HELLO world" in 137 | equal string_result_comparator (P.run p inp) 138 | (Error {|[string_cs] "hello"|}) ) ) ]) 139 | 140 | let string_ci = 141 | let p = P.string_ci "hello" in 142 | let inp () = P.of_string "HELLO world" in 143 | Popper.( 144 | suite 145 | [ ( "value is 'hello'" 146 | , test (fun () -> 147 | equal string_result_comparator (P.run p inp) (Ok "hello") ) ) 148 | ; pos_test p 5 inp 149 | ; last_trimmed_pos_test p 0 inp 150 | ; ( "fail" 151 | , test (fun () -> 152 | let p = P.string_ci "bye" in 153 | equal string_result_comparator (P.run p inp) 154 | (Error "[string_ci] \"bye\"") ) ) 155 | ; ( "case sensitive" 156 | , test (fun () -> 157 | let inp () = P.of_string "hello world" in 158 | equal string_result_comparator (P.run p inp) (Ok "hello") ) ) ]) 159 | 160 | let string_of_chars = 161 | let p = P.string_of_chars ['h'; 'e'; 'l'; 'l'; 'o'] in 162 | Popper.( 163 | suite 164 | [ ( "value is 'hello'" 165 | , test (fun () -> 166 | equal string_result_comparator (P.run p empty) (Ok "hello") ) ) 167 | ; pos_test p 0 empty 168 | ; last_trimmed_pos_test p 0 empty ]) 169 | 170 | let take_string = 171 | let p = P.take_string 5 in 172 | let inp () = P.of_string "hello world" in 173 | Popper.( 174 | suite 175 | [ ( Format.sprintf "value is \"%s\"" "hello" 176 | , test (fun () -> 177 | equal string_result_comparator (P.run p inp) (Ok "hello") ) ) 178 | ; pos_test p 5 inp 179 | ; last_trimmed_pos_test p 0 inp 180 | ; ( "fail on eof" 181 | , test (fun () -> 182 | equal string_result_comparator (P.run p empty) 183 | (Error "pos:0, n:5 eof") ) ) ]) 184 | 185 | let cstruct_result_comparator = 186 | let cstruct = 187 | Popper.Comparator.make Cstruct.compare (fun fmt t -> 188 | Format.fprintf fmt "[%d,%d](%d)" t.off t.len 189 | (Bigarray_compat.Array1.dim t.buffer) ) 190 | in 191 | Popper.Comparator.(result ~ok:cstruct ~error:string) 192 | 193 | let take_cstruct = 194 | let p = P.take_cstruct 5 in 195 | let inp () = P.of_string "hello world" in 196 | Popper.( 197 | suite 198 | [ ( "value is 'hello'" 199 | , test (fun () -> 200 | equal cstruct_result_comparator (P.run p inp) 201 | (Ok (Cstruct.of_string "hello")) ) ) 202 | ; pos_test p 5 inp 203 | ; last_trimmed_pos_test p 0 inp 204 | ; ( "fail on eof" 205 | , test (fun () -> 206 | let p = P.take_cstruct 12 in 207 | equal cstruct_result_comparator (P.run p inp) 208 | (Error "pos:0, n:12 not enough input") ) ) ]) 209 | 210 | let unsafe_take_cstruct = 211 | let p = P.unsafe_take_cstruct 5 in 212 | let inp () = P.of_string "hello world" in 213 | let p2 = 214 | (P.unsafe_take_cstruct 6, P.unsafe_take_cstruct 5) 215 | <$$> fun a b -> Cstruct.append a b 216 | in 217 | Popper.( 218 | suite 219 | [ ( "value is 'hello'" 220 | , test (fun () -> 221 | equal cstruct_result_comparator (P.run p inp) 222 | (Ok (Cstruct.of_string "hello")) ) ) 223 | ; pos_test p 5 inp 224 | ; last_trimmed_pos_test p 0 inp 225 | ; ( "fail" 226 | , test (fun () -> 227 | let p = P.unsafe_take_cstruct 12 in 228 | equal cstruct_result_comparator (P.run p inp) 229 | (Error "[unsafe_take_cstruct] pos:0, n:12 not enough input") ) 230 | ) 231 | ; ( "value is 'hello world'" 232 | , test (fun () -> 233 | equal cstruct_result_comparator (P.run p2 inp) 234 | (Ok (Cstruct.of_string "hello world")) ) ) 235 | ; pos_test p2 11 inp 236 | ; last_trimmed_pos_test p2 0 inp 237 | ; ( "value is 'hello world hello'" 238 | , test (fun () -> 239 | let p = 240 | ( P.take_cstruct 6 241 | , P.unsafe_take_cstruct 6 242 | , P.unsafe_take_cstruct 5 ) 243 | <$$$> fun a b c -> 244 | let a = Cstruct.append a b in 245 | Cstruct.append a c 246 | in 247 | let inp () = P.of_string "hello world hello" in 248 | equal cstruct_result_comparator (P.run p inp) 249 | (Ok (Cstruct.of_string "hello world hello")) ) ) ]) 250 | 251 | let unsafe_take_cstruct_ne = 252 | let p = P.unsafe_take_cstruct_ne 5 in 253 | let inp () = P.of_string "hello world" in 254 | let p2 = 255 | (P.unsafe_take_cstruct_ne 6, P.unsafe_take_cstruct_ne 5) 256 | <$$> fun a b -> Cstruct.append a b 257 | in 258 | Popper.( 259 | suite 260 | [ ( "value is 'hello'" 261 | , test (fun () -> 262 | equal cstruct_result_comparator (P.run p inp) 263 | (Ok (Cstruct.of_string "hello")) ) ) 264 | ; pos_test p 5 inp 265 | ; last_trimmed_pos_test p 0 inp 266 | ; ( "value is hello world" 267 | , test (fun () -> 268 | let p = P.unsafe_take_cstruct_ne 20 in 269 | equal cstruct_result_comparator (P.run p inp) 270 | (Ok (Cstruct.of_string "hello world")) ) ) 271 | ; ( "value is 'hello world'" 272 | , test (fun () -> 273 | equal cstruct_result_comparator (P.run p2 inp) 274 | (Ok (Cstruct.of_string "hello world")) ) ) 275 | ; pos_test p2 11 inp 276 | ; last_trimmed_pos_test p2 0 inp 277 | ; ( "value is 'hello world hello'" 278 | , test (fun () -> 279 | let p = 280 | ( P.take_cstruct 6 281 | , P.unsafe_take_cstruct_ne 6 282 | , P.unsafe_take_cstruct_ne 5 ) 283 | <$$$> fun a b c -> 284 | let a = Cstruct.append a b in 285 | Cstruct.append a c 286 | in 287 | let inp () = P.of_string "hello world hello" in 288 | equal cstruct_result_comparator (P.run p inp) 289 | (Ok (Cstruct.of_string "hello world hello")) ) ) ]) 290 | 291 | let suites = 292 | Popper.suite 293 | [ ("peek_char", peek_char) 294 | ; ("peek_char_opt", peek_char_opt) 295 | ; ("peek_string", peek_string) 296 | ; ("any_char", any_char) 297 | ; ("unsafe_any_char", unsafe_any_char) 298 | ; ("char", char) 299 | ; ("char_if", char_if) 300 | ; ("string_cs", string_cs) 301 | ; ("string_ci", string_ci) 302 | ; ("string_of_chars", string_of_chars) 303 | ; ("take_string", take_string) 304 | ; ("take_cstruct", take_cstruct) 305 | ; ("unsafe_take_cstruct", unsafe_take_cstruct) 306 | ; ("unsafe_take_cstruct_ne", unsafe_take_cstruct_ne) ] 307 | end 308 | 309 | let suite = 310 | let module String = Make_test (Test_parser.String) in 311 | let module Lwt_stream = Make_test (Test_parser.Lwt_stream) in 312 | let module Lwt_fd = Make_test (Test_parser.Lwt_fd) in 313 | let module Lwt_channel = Make_test (Test_parser.Lwt_channel) in 314 | Popper.suite 315 | [ ("Reparse.String", String.suites) 316 | ; ("Reparse_lwt.Stream", Lwt_stream.suites) 317 | ; ("Reparse_lwt_unix.Fd", Lwt_fd.suites) 318 | ; ("Reparse_lwt_unix.Channel", Lwt_channel.suites) ] 319 | -------------------------------------------------------------------------------- /docs/highlight.pack.js: -------------------------------------------------------------------------------- 1 | /*! highlight.js v9.15.8 | BSD3 License | git.io/hljslicense */ 2 | !function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(a){var f=[],u=Object.keys,N={},c={},n=/^(no-?highlight|plain|text)$/i,s=/\blang(?:uage)?-([\w-]+)\b/i,t=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,r={case_insensitive:"cI",lexemes:"l",contains:"c",keywords:"k",subLanguage:"sL",className:"cN",begin:"b",beginKeywords:"bK",end:"e",endsWithParent:"eW",illegal:"i",excludeBegin:"eB",excludeEnd:"eE",returnBegin:"rB",returnEnd:"rE",relevance:"r",variants:"v",IDENT_RE:"IR",UNDERSCORE_IDENT_RE:"UIR",NUMBER_RE:"NR",C_NUMBER_RE:"CNR",BINARY_NUMBER_RE:"BNR",RE_STARTERS_RE:"RSR",BACKSLASH_ESCAPE:"BE",APOS_STRING_MODE:"ASM",QUOTE_STRING_MODE:"QSM",PHRASAL_WORDS_MODE:"PWM",C_LINE_COMMENT_MODE:"CLCM",C_BLOCK_COMMENT_MODE:"CBCM",HASH_COMMENT_MODE:"HCM",NUMBER_MODE:"NM",C_NUMBER_MODE:"CNM",BINARY_NUMBER_MODE:"BNM",CSS_NUMBER_MODE:"CSSNM",REGEXP_MODE:"RM",TITLE_MODE:"TM",UNDERSCORE_TITLE_MODE:"UTM",COMMENT:"C",beginRe:"bR",endRe:"eR",illegalRe:"iR",lexemesRe:"lR",terminators:"t",terminator_end:"tE"},b="",h={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};function _(e){return e.replace(/&/g,"&").replace(//g,">")}function E(e){return e.nodeName.toLowerCase()}function v(e,n){var t=e&&e.exec(n);return t&&0===t.index}function l(e){return n.test(e)}function g(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function R(e){var a=[];return function e(n,t){for(var r=n.firstChild;r;r=r.nextSibling)3===r.nodeType?t+=r.nodeValue.length:1===r.nodeType&&(a.push({event:"start",offset:t,node:r}),t=e(r,t),E(r).match(/br|hr|img|input/)||a.push({event:"stop",offset:t,node:r}));return t}(e,0),a}function i(e){if(r&&!e.langApiRestored){for(var n in e.langApiRestored=!0,r)e[n]&&(e[r[n]]=e[n]);(e.c||[]).concat(e.v||[]).forEach(i)}}function m(o){function s(e){return e&&e.source||e}function c(e,n){return new RegExp(s(e),"m"+(o.cI?"i":"")+(n?"g":""))}!function n(t,e){if(!t.compiled){if(t.compiled=!0,t.k=t.k||t.bK,t.k){function r(t,e){o.cI&&(e=e.toLowerCase()),e.split(" ").forEach(function(e){var n=e.split("|");a[n[0]]=[t,n[1]?Number(n[1]):1]})}var a={};"string"==typeof t.k?r("keyword",t.k):u(t.k).forEach(function(e){r(e,t.k[e])}),t.k=a}t.lR=c(t.l||/\w+/,!0),e&&(t.bK&&(t.b="\\b("+t.bK.split(" ").join("|")+")\\b"),t.b||(t.b=/\B|\b/),t.bR=c(t.b),t.endSameAsBegin&&(t.e=t.b),t.e||t.eW||(t.e=/\B|\b/),t.e&&(t.eR=c(t.e)),t.tE=s(t.e)||"",t.eW&&e.tE&&(t.tE+=(t.e?"|":"")+e.tE)),t.i&&(t.iR=c(t.i)),null==t.r&&(t.r=1),t.c||(t.c=[]),t.c=Array.prototype.concat.apply([],t.c.map(function(e){return function(n){return n.v&&!n.cached_variants&&(n.cached_variants=n.v.map(function(e){return g(n,{v:null},e)})),n.cached_variants||n.eW&&[g(n)]||[n]}("self"===e?t:e)})),t.c.forEach(function(e){n(e,t)}),t.starts&&n(t.starts,e);var i=t.c.map(function(e){return e.bK?"\\.?(?:"+e.b+")\\.?":e.b}).concat([t.tE,t.i]).map(s).filter(Boolean);t.t=i.length?c(function(e,n){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i')+n+(t?"":b):n}function o(){E+=null!=l.sL?function(){var e="string"==typeof l.sL;if(e&&!N[l.sL])return _(g);var n=e?C(l.sL,g,!0,f[l.sL]):O(g,l.sL.length?l.sL:void 0);return 0")+'"');return g+=n,n.length||1}var s=B(e);if(!s)throw new Error('Unknown language: "'+e+'"');m(s);var a,l=t||s,f={},E="";for(a=l;a!==s;a=a.parent)a.cN&&(E=c(a.cN,"",!0)+E);var g="",R=0;try{for(var d,p,M=0;l.t.lastIndex=M,d=l.t.exec(n);)p=r(n.substring(M,d.index),d[0]),M=d.index+p;for(r(n.substr(M)),a=l;a.parent;a=a.parent)a.cN&&(E+=b);return{r:R,value:E,language:e,top:l}}catch(e){if(e.message&&-1!==e.message.indexOf("Illegal"))return{r:0,value:_(n)};throw e}}function O(t,e){e=e||h.languages||u(N);var r={r:0,value:_(t)},a=r;return e.filter(B).filter(M).forEach(function(e){var n=C(e,t,!1);n.language=e,n.r>a.r&&(a=n),n.r>r.r&&(a=r,r=n)}),a.language&&(r.second_best=a),r}function d(e){return h.tabReplace||h.useBR?e.replace(t,function(e,n){return h.useBR&&"\n"===e?"
":h.tabReplace?n.replace(/\t/g,h.tabReplace):""}):e}function o(e){var n,t,r,a,i,o=function(e){var n,t,r,a,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=s.exec(i))return B(t[1])?t[1]:"no-highlight";for(n=0,r=(i=i.split(/\s+/)).length;n/g,"\n"):n=e,i=n.textContent,r=o?C(o,i,!0):O(i),(t=R(n)).length&&((a=document.createElementNS("http://www.w3.org/1999/xhtml","div")).innerHTML=r.value,r.value=function(e,n,t){var r=0,a="",i=[];function o(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){a+=""}function s(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var l=o();if(a+=_(t.substring(r,l[0].offset)),r=l[0].offset,l===e){for(i.reverse().forEach(u);s(l.splice(0,1)[0]),(l=o())===e&&l.length&&l[0].offset===r;);i.reverse().forEach(c)}else"start"===l[0].event?i.push(l[0].node):i.pop(),s(l.splice(0,1)[0])}return a+_(t.substr(r))}(t,R(a),i)),r.value=d(r.value),e.innerHTML=r.value,e.className=function(e,n,t){var r=n?c[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}(e.className,o,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function p(){if(!p.called){p.called=!0;var e=document.querySelectorAll("pre code");f.forEach.call(e,o)}}function B(e){return e=(e||"").toLowerCase(),N[e]||N[c[e]]}function M(e){var n=B(e);return n&&!n.disableAutodetect}return a.highlight=C,a.highlightAuto=O,a.fixMarkup=d,a.highlightBlock=o,a.configure=function(e){h=g(h,e)},a.initHighlighting=p,a.initHighlightingOnLoad=function(){addEventListener("DOMContentLoaded",p,!1),addEventListener("load",p,!1)},a.registerLanguage=function(n,e){var t=N[n]=e(a);i(t),t.aliases&&t.aliases.forEach(function(e){c[e]=n})},a.listLanguages=function(){return u(N)},a.getLanguage=B,a.autoDetection=M,a.inherit=g,a.IR=a.IDENT_RE="[a-zA-Z]\\w*",a.UIR=a.UNDERSCORE_IDENT_RE="[a-zA-Z_]\\w*",a.NR=a.NUMBER_RE="\\b\\d+(\\.\\d+)?",a.CNR=a.C_NUMBER_RE="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",a.BNR=a.BINARY_NUMBER_RE="\\b(0b[01]+)",a.RSR=a.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",a.BE=a.BACKSLASH_ESCAPE={b:"\\\\[\\s\\S]",r:0},a.ASM=a.APOS_STRING_MODE={cN:"string",b:"'",e:"'",i:"\\n",c:[a.BE]},a.QSM=a.QUOTE_STRING_MODE={cN:"string",b:'"',e:'"',i:"\\n",c:[a.BE]},a.PWM=a.PHRASAL_WORDS_MODE={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},a.C=a.COMMENT=function(e,n,t){var r=a.inherit({cN:"comment",b:e,e:n,c:[]},t||{});return r.c.push(a.PWM),r.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),r},a.CLCM=a.C_LINE_COMMENT_MODE=a.C("//","$"),a.CBCM=a.C_BLOCK_COMMENT_MODE=a.C("/\\*","\\*/"),a.HCM=a.HASH_COMMENT_MODE=a.C("#","$"),a.NM=a.NUMBER_MODE={cN:"number",b:a.NR,r:0},a.CNM=a.C_NUMBER_MODE={cN:"number",b:a.CNR,r:0},a.BNM=a.BINARY_NUMBER_MODE={cN:"number",b:a.BNR,r:0},a.CSSNM=a.CSS_NUMBER_MODE={cN:"number",b:a.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},a.RM=a.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[a.BE,{b:/\[/,e:/\]/,r:0,c:[a.BE]}]},a.TM=a.TITLE_MODE={cN:"title",b:a.IR,r:0},a.UTM=a.UNDERSCORE_TITLE_MODE={cN:"title",b:a.UIR,r:0},a.METHOD_GUARD={b:"\\.\\s*"+a.UIR,r:0},a});hljs.registerLanguage("ocaml",function(e){return{aliases:["ml"],k:{keyword:"and as assert asr begin class constraint do done downto else end exception external for fun function functor if in include inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method mod module mutable new object of open! open or private rec sig struct then to try type val! val virtual when while with parser value",built_in:"array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit in_channel out_channel ref",literal:"true false"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:"\\[(\\|\\|)?\\]|\\(\\)",r:0},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"type",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*",r:0},e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}});hljs.registerLanguage("reasonml",function(r){var e="~?[a-z$_][0-9a-zA-Z$_]*",a="`?[A-Z$_][0-9a-zA-Z$_]*",c="("+["||","&&","++","**","+.","*","/","*.","/.","...","|>"].map(function(r){return r.split("").map(function(r){return"\\"+r}).join("")}).join("|")+"|==|===)",n="\\s+"+c+"\\s+",t={keyword:"and as asr assert begin class constraint do done downto else end exception externalfor fun function functor if in include inherit initializerland lazy let lor lsl lsr lxor match method mod module mutable new nonrecobject of open or private rec sig struct then to try type val virtual when while with",built_in:"array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 ref string unit ",literal:"true false"},i="\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",s={cN:"number",r:0,v:[{b:i},{b:"\\(\\-"+i+"\\)"}]},b={cN:"operator",r:0,b:c},o=[{cN:"identifier",r:0,b:e},b,s],l=[r.QSM,b,{cN:"module",b:"\\b"+a,rB:!0,e:".",c:[{cN:"identifier",b:a,r:0}]}],u=[{cN:"module",b:"\\b"+a,rB:!0,e:".",r:0,c:[{cN:"identifier",b:a,r:0}]}],_={cN:"function",r:0,k:t,v:[{b:"\\s(\\(\\.?.*?\\)|"+e+")\\s*=>",e:"\\s*=>",rB:!0,r:0,c:[{cN:"params",v:[{b:e},{b:"~?[a-z$_][0-9a-zA-Z$_]*(s*:s*[a-z$_][0-9a-z$_]*((s*('?[a-z$_][0-9a-z$_]*s*(,'?[a-z$_][0-9a-z$_]*)*)?s*))?)?(s*:s*[a-z$_][0-9a-z$_]*((s*('?[a-z$_][0-9a-z$_]*s*(,'?[a-z$_][0-9a-z$_]*)*)?s*))?)?"},{b:/\(\s*\)/}]}]},{b:"\\s\\(\\.?[^;\\|]*\\)\\s*=>",e:"\\s=>",rB:!0,r:0,c:[{cN:"params",r:0,v:[{b:e,e:"(,|\\n|\\))",r:0,c:[b,{cN:"typing",b:":",e:"(,|\\n)",rB:!0,r:0,c:u}]}]}]},{b:"\\(\\.\\s"+e+"\\)\\s*=>"}]};l.push(_);var N={cN:"constructor",b:a+"\\(",e:"\\)",i:"\\n",k:t,c:[r.QSM,b,{cN:"params",b:"\\b"+e}]},d={cN:"pattern-match",b:"\\|",rB:!0,k:t,e:"=>",r:0,c:[N,b,{r:0,cN:"constructor",b:a}]},z={cN:"module-access",k:t,rB:!0,v:[{b:"\\b("+a+"\\.)+"+e},{b:"\\b("+a+"\\.)+\\(",e:"\\)",rB:!0,c:[_,{b:"\\(",e:"\\)",skip:!0}].concat(l)},{b:"\\b("+a+"\\.)+{",e:"}"}],c:l};return u.push(z),{aliases:["re"],k:t,i:"(:\\-|:=|\\${|\\+=)",c:[r.C("/\\*","\\*/",{i:"^(\\#,\\/\\/)"}),{cN:"character",b:"'(\\\\[^']+|[^'])'",i:"\\n",r:0},r.QSM,{cN:"literal",b:"\\(\\)",r:0},{cN:"literal",b:"\\[\\|",e:"\\|\\]",r:0,c:o},{cN:"literal",b:"\\[",e:"\\]",r:0,c:o},N,{cN:"operator",b:n,i:"\\-\\->",r:0},s,r.CLCM,d,_,{cN:"module-def",b:"\\bmodule\\s+"+e+"\\s+"+a+"\\s+=\\s+{",e:"}",rB:!0,k:t,r:0,c:[{cN:"module",r:0,b:a},{b:"{",e:"}",skip:!0}].concat(l)},z]}}); -------------------------------------------------------------------------------- /docs/reparse/Reparse/Make/Infix/index.html: -------------------------------------------------------------------------------- 1 | 2 | Infix (reparse.Reparse.Make.Infix)

Module Make.Infix

val (>>=) : 'a t -> ('a -> 'b t) -> 'b t

p >>= f returns a new parser b where,

  • a is the parsed value of p
  • b is f a Also known as bind operation.

Examples

module P = Reparse.String
  3 | open P
  4 | 
  5 | ;;
  6 | let f a = P.pure (Char.code a) in
  7 | let p = P.char 'h' in
  8 | let p = p >>= f in
  9 | let v = P.parse_string p "hello" in
 10 | v = 104
val (>>|) : 'a t -> ('a -> 'b) -> 'b t

p >>| f returns a new parser encapsulating value b where,

  • a is the parsed value of p.
  • b is f a. Also known as map operation.

Examples

module P = Reparse.String
 11 | open P
 12 | 
 13 | ;;
 14 | let f a = Char.code a in
 15 | let p = P.char 'h' in
 16 | let p = p >>| f in
 17 | let v = P.parse_string p "hello" in
 18 | v = 104
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t

pf <*> q returns a new parser encapsulating value b where

  • pf and q are evaluated sequentially in order as given.
  • f is the parsed value of pf
  • a is the parsed value of q
  • b is f a Also known as Applicative operation.

Examples

module P = Reparse
 19 | open P
 20 | 
 21 | ;;
 22 | let f a = a + 2 in
 23 | let pf = P.pure f in
 24 | let q = P.pure 2 in
 25 | let p = pf <*> q in
 26 | let v = P.parse_string p "hello" in
 27 | v = 4
val (<$>) : ('a -> 'b) -> 'a t -> 'b t

f <$> p is return f <*> p.

val (<$) : 'a -> 'b t -> 'a t

v <$ p replaces the parse value of p with v.

Examples

module P = Reparse.String
 28 | open P
 29 | 
 30 | ;;
 31 | let v = "hello" in
 32 | let p = P.char 'h' in
 33 | let p = v <$ p in
 34 | let v2 = P.parse_string p "hello" in
 35 | v2 = "hello"
val ($>) : 'a t -> 'b -> 'b t

p $> v is inverse of v <$ p.

val (*>) : _ t -> 'b t -> 'b t

p *> q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of q.
  • The parsed value of p is discarded. Also known as discard left.

Examples

module P = Reparse.String
 36 | open P
 37 | 
 38 | ;;
 39 | let p = P.string "world" in
 40 | let q = P.pure "hello" in
 41 | let p = p *> q in
 42 | let v = P.parse_string p "world" in
 43 | v = "hello"
val (<*) : 'a t -> _ t -> 'a t

p <* q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of p.
  • The parsed value of q is discarded. Also know as discard_right.

Examples

module P = Reparse.String
 44 | open P
 45 | 
 46 | ;;
 47 | let p = P.string "world" in
 48 | let q = P.pure "hello" in
 49 | let p = p <* q in
 50 | let v = P.parse_string p "world" in
 51 | v = "world"
val (<|>) : 'a t -> 'a t -> 'a t

p <|> q returns a parser encapsulating value a where,

  • p,q are evaluated sequentially in order as given.
  • a is the parsed value of p if p is successful
  • a is the parsed value of q if p is a failure and q is a success.
  • If both - p and q - fails, then the parser fails.

Examples

p fails and q succeeds, therefore we return q's parsed value 'w'

module P = Reparse.String
 52 | open P
 53 | 
 54 | ;;
 55 | let p = P.char 'h' in
 56 | let q = P.char 'w' in
 57 | let p = p <|> q in
 58 | let v = P.parse_string p "world" in
 59 | v = 'w'

p succeeds therefore we return its parsed value 'h'

let p = P.char 'h' in
 60 | let q = P.char 'w' in
 61 | let p = p <|> q in
 62 | let v = P.parse_string p "hello" in
 63 | v = 'h'

The parser fails if both p and q fails.

let p = P.char 'h' in
 64 | let q = P.char 'w' in
 65 | let p = p <|> q in
 66 | let v =
 67 |   try
 68 |     let _ = P.parse_string p "" in
 69 |     false
 70 |   with
 71 |   | _ -> true
 72 | in
 73 | v = true
val let* : 'a t -> ('a -> 'b t) -> 'b t

let* is a let syntax binding for Reparse.Infix.((>>=))

Examples

module P = Reparse.String
 74 | open P
 75 | 
 76 | ;;
 77 | let p =
 78 |   let* a = P.pure 5 in
 79 |   let total = a + 5 in
 80 |   P.pure total
 81 | in
 82 | let v = P.parse_string p "" in
 83 | v = 10
val and* : 'a t -> 'b t -> ('a * 'b) t
val let+ : 'a t -> ('a -> 'b) -> 'b t

let* is a let syntax binding for Reparse.((>|=))

Examples

module P = Reparse.String
 84 | open P
 85 | 
 86 | ;;
 87 | let p =
 88 |   let+ a = P.pure 5 in
 89 |   let total = a + 5 in
 90 |   total
 91 | in
 92 | let v = P.parse_string p "" in
 93 | v = 10
val and+ : 'a t -> 'b t -> ('a * 'b) t
val (<?>) : 'a t -> string -> 'a t

p <?> err_msg parses p to value a and returns a new parser encapsulating a. If p is a failure, then it fails with error message err_msg. Often used as a last choice in <|>, e.g. a <|> b <|> c <?> "expected a b c".

Examples

module P = Reparse.String
 94 | open P
 95 | 
 96 | ;;
 97 | let p = P.char 'h' <|> P.char 'w' in
 98 | let err_msg = "[error]" in
 99 | let p = p <?> err_msg in
100 | let v =
101 |   try
102 |     let _ = P.parse_string p "" in
103 |     false
104 |   with
105 |   | P.Parser
106 |       { offset = 0
107 |       ; line_number = 0
108 |       ; column_number = 0
109 |       ; msg = "[error]"
110 |       } ->
111 |     true
112 |   | _ -> false
113 | in
114 | v = true
-------------------------------------------------------------------------------- /docs/reparse/Reparse/String/Infix/index.html: -------------------------------------------------------------------------------- 1 | 2 | Infix (reparse.Reparse.String.Infix)

Module String.Infix

val (>>=) : 'a t -> ('a -> 'b t) -> 'b t

p >>= f returns a new parser b where,

  • a is the parsed value of p
  • b is f a Also known as bind operation.

Examples

module P = Reparse.String
  3 | open P
  4 | 
  5 | ;;
  6 | let f a = P.pure (Char.code a) in
  7 | let p = P.char 'h' in
  8 | let p = p >>= f in
  9 | let v = P.parse_string p "hello" in
 10 | v = 104
val (>>|) : 'a t -> ('a -> 'b) -> 'b t

p >>| f returns a new parser encapsulating value b where,

  • a is the parsed value of p.
  • b is f a. Also known as map operation.

Examples

module P = Reparse.String
 11 | open P
 12 | 
 13 | ;;
 14 | let f a = Char.code a in
 15 | let p = P.char 'h' in
 16 | let p = p >>| f in
 17 | let v = P.parse_string p "hello" in
 18 | v = 104
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t

pf <*> q returns a new parser encapsulating value b where

  • pf and q are evaluated sequentially in order as given.
  • f is the parsed value of pf
  • a is the parsed value of q
  • b is f a Also known as Applicative operation.

Examples

module P = Reparse
 19 | open P
 20 | 
 21 | ;;
 22 | let f a = a + 2 in
 23 | let pf = P.pure f in
 24 | let q = P.pure 2 in
 25 | let p = pf <*> q in
 26 | let v = P.parse_string p "hello" in
 27 | v = 4
val (<$>) : ('a -> 'b) -> 'a t -> 'b t

f <$> p is return f <*> p.

val (<$) : 'a -> 'b t -> 'a t

v <$ p replaces the parse value of p with v.

Examples

module P = Reparse.String
 28 | open P
 29 | 
 30 | ;;
 31 | let v = "hello" in
 32 | let p = P.char 'h' in
 33 | let p = v <$ p in
 34 | let v2 = P.parse_string p "hello" in
 35 | v2 = "hello"
val ($>) : 'a t -> 'b -> 'b t

p $> v is inverse of v <$ p.

val (*>) : _ t -> 'b t -> 'b t

p *> q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of q.
  • The parsed value of p is discarded. Also known as discard left.

Examples

module P = Reparse.String
 36 | open P
 37 | 
 38 | ;;
 39 | let p = P.string "world" in
 40 | let q = P.pure "hello" in
 41 | let p = p *> q in
 42 | let v = P.parse_string p "world" in
 43 | v = "hello"
val (<*) : 'a t -> _ t -> 'a t

p <* q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of p.
  • The parsed value of q is discarded. Also know as discard_right.

Examples

module P = Reparse.String
 44 | open P
 45 | 
 46 | ;;
 47 | let p = P.string "world" in
 48 | let q = P.pure "hello" in
 49 | let p = p <* q in
 50 | let v = P.parse_string p "world" in
 51 | v = "world"
val (<|>) : 'a t -> 'a t -> 'a t

p <|> q returns a parser encapsulating value a where,

  • p,q are evaluated sequentially in order as given.
  • a is the parsed value of p if p is successful
  • a is the parsed value of q if p is a failure and q is a success.
  • If both - p and q - fails, then the parser fails.

Examples

p fails and q succeeds, therefore we return q's parsed value 'w'

module P = Reparse.String
 52 | open P
 53 | 
 54 | ;;
 55 | let p = P.char 'h' in
 56 | let q = P.char 'w' in
 57 | let p = p <|> q in
 58 | let v = P.parse_string p "world" in
 59 | v = 'w'

p succeeds therefore we return its parsed value 'h'

let p = P.char 'h' in
 60 | let q = P.char 'w' in
 61 | let p = p <|> q in
 62 | let v = P.parse_string p "hello" in
 63 | v = 'h'

The parser fails if both p and q fails.

let p = P.char 'h' in
 64 | let q = P.char 'w' in
 65 | let p = p <|> q in
 66 | let v =
 67 |   try
 68 |     let _ = P.parse_string p "" in
 69 |     false
 70 |   with
 71 |   | _ -> true
 72 | in
 73 | v = true
val let* : 'a t -> ('a -> 'b t) -> 'b t

let* is a let syntax binding for Reparse.Infix.((>>=))

Examples

module P = Reparse.String
 74 | open P
 75 | 
 76 | ;;
 77 | let p =
 78 |   let* a = P.pure 5 in
 79 |   let total = a + 5 in
 80 |   P.pure total
 81 | in
 82 | let v = P.parse_string p "" in
 83 | v = 10
val and* : 'a t -> 'b t -> ('a * 'b) t
val let+ : 'a t -> ('a -> 'b) -> 'b t

let* is a let syntax binding for Reparse.((>|=))

Examples

module P = Reparse.String
 84 | open P
 85 | 
 86 | ;;
 87 | let p =
 88 |   let+ a = P.pure 5 in
 89 |   let total = a + 5 in
 90 |   total
 91 | in
 92 | let v = P.parse_string p "" in
 93 | v = 10
val and+ : 'a t -> 'b t -> ('a * 'b) t
val (<?>) : 'a t -> string -> 'a t

p <?> err_msg parses p to value a and returns a new parser encapsulating a. If p is a failure, then it fails with error message err_msg. Often used as a last choice in <|>, e.g. a <|> b <|> c <?> "expected a b c".

Examples

module P = Reparse.String
 94 | open P
 95 | 
 96 | ;;
 97 | let p = P.char 'h' <|> P.char 'w' in
 98 | let err_msg = "[error]" in
 99 | let p = p <?> err_msg in
100 | let v =
101 |   try
102 |     let _ = P.parse_string p "" in
103 |     false
104 |   with
105 |   | P.Parser
106 |       { offset = 0
107 |       ; line_number = 0
108 |       ; column_number = 0
109 |       ; msg = "[error]"
110 |       } ->
111 |     true
112 |   | _ -> false
113 | in
114 | v = true
-------------------------------------------------------------------------------- /docs/reparse/Reparse/module-type-PARSER/Infix/index.html: -------------------------------------------------------------------------------- 1 | 2 | Infix (reparse.Reparse.PARSER.Infix)

Module PARSER.Infix

val (>>=) : 'a t -> ('a -> 'b t) -> 'b t

p >>= f returns a new parser b where,

  • a is the parsed value of p
  • b is f a Also known as bind operation.

Examples

module P = Reparse.String
  3 | open P
  4 | 
  5 | ;;
  6 | let f a = P.pure (Char.code a) in
  7 | let p = P.char 'h' in
  8 | let p = p >>= f in
  9 | let v = P.parse_string p "hello" in
 10 | v = 104
val (>>|) : 'a t -> ('a -> 'b) -> 'b t

p >>| f returns a new parser encapsulating value b where,

  • a is the parsed value of p.
  • b is f a. Also known as map operation.

Examples

module P = Reparse.String
 11 | open P
 12 | 
 13 | ;;
 14 | let f a = Char.code a in
 15 | let p = P.char 'h' in
 16 | let p = p >>| f in
 17 | let v = P.parse_string p "hello" in
 18 | v = 104
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t

pf <*> q returns a new parser encapsulating value b where

  • pf and q are evaluated sequentially in order as given.
  • f is the parsed value of pf
  • a is the parsed value of q
  • b is f a Also known as Applicative operation.

Examples

module P = Reparse
 19 | open P
 20 | 
 21 | ;;
 22 | let f a = a + 2 in
 23 | let pf = P.pure f in
 24 | let q = P.pure 2 in
 25 | let p = pf <*> q in
 26 | let v = P.parse_string p "hello" in
 27 | v = 4
val (<$>) : ('a -> 'b) -> 'a t -> 'b t

f <$> p is return f <*> p.

val (<$) : 'a -> 'b t -> 'a t

v <$ p replaces the parse value of p with v.

Examples

module P = Reparse.String
 28 | open P
 29 | 
 30 | ;;
 31 | let v = "hello" in
 32 | let p = P.char 'h' in
 33 | let p = v <$ p in
 34 | let v2 = P.parse_string p "hello" in
 35 | v2 = "hello"
val ($>) : 'a t -> 'b -> 'b t

p $> v is inverse of v <$ p.

val (*>) : _ t -> 'b t -> 'b t

p *> q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of q.
  • The parsed value of p is discarded. Also known as discard left.

Examples

module P = Reparse.String
 36 | open P
 37 | 
 38 | ;;
 39 | let p = P.string "world" in
 40 | let q = P.pure "hello" in
 41 | let p = p *> q in
 42 | let v = P.parse_string p "world" in
 43 | v = "hello"
val (<*) : 'a t -> _ t -> 'a t

p <* q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of p.
  • The parsed value of q is discarded. Also know as discard_right.

Examples

module P = Reparse.String
 44 | open P
 45 | 
 46 | ;;
 47 | let p = P.string "world" in
 48 | let q = P.pure "hello" in
 49 | let p = p <* q in
 50 | let v = P.parse_string p "world" in
 51 | v = "world"
val (<|>) : 'a t -> 'a t -> 'a t

p <|> q returns a parser encapsulating value a where,

  • p,q are evaluated sequentially in order as given.
  • a is the parsed value of p if p is successful
  • a is the parsed value of q if p is a failure and q is a success.
  • If both - p and q - fails, then the parser fails.

Examples

p fails and q succeeds, therefore we return q's parsed value 'w'

module P = Reparse.String
 52 | open P
 53 | 
 54 | ;;
 55 | let p = P.char 'h' in
 56 | let q = P.char 'w' in
 57 | let p = p <|> q in
 58 | let v = P.parse_string p "world" in
 59 | v = 'w'

p succeeds therefore we return its parsed value 'h'

let p = P.char 'h' in
 60 | let q = P.char 'w' in
 61 | let p = p <|> q in
 62 | let v = P.parse_string p "hello" in
 63 | v = 'h'

The parser fails if both p and q fails.

let p = P.char 'h' in
 64 | let q = P.char 'w' in
 65 | let p = p <|> q in
 66 | let v =
 67 |   try
 68 |     let _ = P.parse_string p "" in
 69 |     false
 70 |   with
 71 |   | _ -> true
 72 | in
 73 | v = true
val let* : 'a t -> ('a -> 'b t) -> 'b t

let* is a let syntax binding for Reparse.Infix.((>>=))

Examples

module P = Reparse.String
 74 | open P
 75 | 
 76 | ;;
 77 | let p =
 78 |   let* a = P.pure 5 in
 79 |   let total = a + 5 in
 80 |   P.pure total
 81 | in
 82 | let v = P.parse_string p "" in
 83 | v = 10
val and* : 'a t -> 'b t -> ('a * 'b) t
val let+ : 'a t -> ('a -> 'b) -> 'b t

let* is a let syntax binding for Reparse.((>|=))

Examples

module P = Reparse.String
 84 | open P
 85 | 
 86 | ;;
 87 | let p =
 88 |   let+ a = P.pure 5 in
 89 |   let total = a + 5 in
 90 |   total
 91 | in
 92 | let v = P.parse_string p "" in
 93 | v = 10
val and+ : 'a t -> 'b t -> ('a * 'b) t
val (<?>) : 'a t -> string -> 'a t

p <?> err_msg parses p to value a and returns a new parser encapsulating a. If p is a failure, then it fails with error message err_msg. Often used as a last choice in <|>, e.g. a <|> b <|> c <?> "expected a b c".

Examples

module P = Reparse.String
 94 | open P
 95 | 
 96 | ;;
 97 | let p = P.char 'h' <|> P.char 'w' in
 98 | let err_msg = "[error]" in
 99 | let p = p <?> err_msg in
100 | let v =
101 |   try
102 |     let _ = P.parse_string p "" in
103 |     false
104 |   with
105 |   | P.Parser
106 |       { offset = 0
107 |       ; line_number = 0
108 |       ; column_number = 0
109 |       ; msg = "[error]"
110 |       } ->
111 |     true
112 |   | _ -> false
113 | in
114 | v = true
-------------------------------------------------------------------------------- /docs/reparse-lwt/Reparse_lwt/Stream/Infix/index.html: -------------------------------------------------------------------------------- 1 | 2 | Infix (reparse-lwt.Reparse_lwt.Stream.Infix)

Module Stream.Infix

val (>>=) : 'a t -> ('a -> 'b t) -> 'b t

p >>= f returns a new parser b where,

  • a is the parsed value of p
  • b is f a Also known as bind operation.

Examples

module P = Reparse.String
  3 | open P
  4 | 
  5 | ;;
  6 | let f a = P.pure (Char.code a) in
  7 | let p = P.char 'h' in
  8 | let p = p >>= f in
  9 | let v = P.parse_string p "hello" in
 10 | v = 104
val (>>|) : 'a t -> ('a -> 'b) -> 'b t

p >>| f returns a new parser encapsulating value b where,

  • a is the parsed value of p.
  • b is f a. Also known as map operation.

Examples

module P = Reparse.String
 11 | open P
 12 | 
 13 | ;;
 14 | let f a = Char.code a in
 15 | let p = P.char 'h' in
 16 | let p = p >>| f in
 17 | let v = P.parse_string p "hello" in
 18 | v = 104
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t

pf <*> q returns a new parser encapsulating value b where

  • pf and q are evaluated sequentially in order as given.
  • f is the parsed value of pf
  • a is the parsed value of q
  • b is f a Also known as Applicative operation.

Examples

module P = Reparse
 19 | open P
 20 | 
 21 | ;;
 22 | let f a = a + 2 in
 23 | let pf = P.pure f in
 24 | let q = P.pure 2 in
 25 | let p = pf <*> q in
 26 | let v = P.parse_string p "hello" in
 27 | v = 4
val (<$>) : ('a -> 'b) -> 'a t -> 'b t

f <$> p is return f <*> p.

val (<$) : 'a -> 'b t -> 'a t

v <$ p replaces the parse value of p with v.

Examples

module P = Reparse.String
 28 | open P
 29 | 
 30 | ;;
 31 | let v = "hello" in
 32 | let p = P.char 'h' in
 33 | let p = v <$ p in
 34 | let v2 = P.parse_string p "hello" in
 35 | v2 = "hello"
val ($>) : 'a t -> 'b -> 'b t

p $> v is inverse of v <$ p.

val (*>) : _ t -> 'b t -> 'b t

p *> q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of q.
  • The parsed value of p is discarded. Also known as discard left.

Examples

module P = Reparse.String
 36 | open P
 37 | 
 38 | ;;
 39 | let p = P.string "world" in
 40 | let q = P.pure "hello" in
 41 | let p = p *> q in
 42 | let v = P.parse_string p "world" in
 43 | v = "hello"
val (<*) : 'a t -> _ t -> 'a t

p <* q returns a parser encapsulating value a where,

  • p, q are evaluated sequentially in order as given.
  • a is parsed value of p.
  • The parsed value of q is discarded. Also know as discard_right.

Examples

module P = Reparse.String
 44 | open P
 45 | 
 46 | ;;
 47 | let p = P.string "world" in
 48 | let q = P.pure "hello" in
 49 | let p = p <* q in
 50 | let v = P.parse_string p "world" in
 51 | v = "world"
val (<|>) : 'a t -> 'a t -> 'a t

p <|> q returns a parser encapsulating value a where,

  • p,q are evaluated sequentially in order as given.
  • a is the parsed value of p if p is successful
  • a is the parsed value of q if p is a failure and q is a success.
  • If both - p and q - fails, then the parser fails.

Examples

p fails and q succeeds, therefore we return q's parsed value 'w'

module P = Reparse.String
 52 | open P
 53 | 
 54 | ;;
 55 | let p = P.char 'h' in
 56 | let q = P.char 'w' in
 57 | let p = p <|> q in
 58 | let v = P.parse_string p "world" in
 59 | v = 'w'

p succeeds therefore we return its parsed value 'h'

let p = P.char 'h' in
 60 | let q = P.char 'w' in
 61 | let p = p <|> q in
 62 | let v = P.parse_string p "hello" in
 63 | v = 'h'

The parser fails if both p and q fails.

let p = P.char 'h' in
 64 | let q = P.char 'w' in
 65 | let p = p <|> q in
 66 | let v =
 67 |   try
 68 |     let _ = P.parse_string p "" in
 69 |     false
 70 |   with
 71 |   | _ -> true
 72 | in
 73 | v = true
val let* : 'a t -> ('a -> 'b t) -> 'b t

let* is a let syntax binding for Reparse.Infix.((>>=))

Examples

module P = Reparse.String
 74 | open P
 75 | 
 76 | ;;
 77 | let p =
 78 |   let* a = P.pure 5 in
 79 |   let total = a + 5 in
 80 |   P.pure total
 81 | in
 82 | let v = P.parse_string p "" in
 83 | v = 10
val and* : 'a t -> 'b t -> ('a * 'b) t
val let+ : 'a t -> ('a -> 'b) -> 'b t

let* is a let syntax binding for Reparse.((>|=))

Examples

module P = Reparse.String
 84 | open P
 85 | 
 86 | ;;
 87 | let p =
 88 |   let+ a = P.pure 5 in
 89 |   let total = a + 5 in
 90 |   total
 91 | in
 92 | let v = P.parse_string p "" in
 93 | v = 10
val and+ : 'a t -> 'b t -> ('a * 'b) t
val (<?>) : 'a t -> string -> 'a t

p <?> err_msg parses p to value a and returns a new parser encapsulating a. If p is a failure, then it fails with error message err_msg. Often used as a last choice in <|>, e.g. a <|> b <|> c <?> "expected a b c".

Examples

module P = Reparse.String
 94 | open P
 95 | 
 96 | ;;
 97 | let p = P.char 'h' <|> P.char 'w' in
 98 | let err_msg = "[error]" in
 99 | let p = p <?> err_msg in
100 | let v =
101 |   try
102 |     let _ = P.parse_string p "" in
103 |     false
104 |   with
105 |   | P.Parser
106 |       { offset = 0
107 |       ; line_number = 0
108 |       ; column_number = 0
109 |       ; msg = "[error]"
110 |       } ->
111 |     true
112 |   | _ -> false
113 | in
114 | v = true
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /docs/odoc.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /* Copyright (c) 2016 The odoc contributors. All rights reserved. 3 | Distributed under the ISC license, see terms at the end of the file. 4 | odoc 2.0.0-beta4 */ 5 | 6 | /* Fonts */ 7 | @import url('https://fonts.googleapis.com/css?family=Fira+Mono:400,500'); 8 | @import url('https://fonts.googleapis.com/css?family=Noticia+Text:400,400i,700'); 9 | @import url('https://fonts.googleapis.com/css?family=Fira+Sans:400,400i,500,500i,600,600i,700,700i'); 10 | 11 | :root, 12 | .light:root { 13 | --main-background: #FFFFFF; 14 | 15 | --color: #333333; 16 | --link-color: #2C94BD; 17 | --anchor-hover: #555; 18 | --anchor-color: #d5d5d5; 19 | --xref-shadow: #cc6666; 20 | --header-shadow: #ddd; 21 | --by-name-version-color: #aaa; 22 | --by-name-nav-link-color: #222; 23 | --target-background: rgba(187, 239, 253, 0.3); 24 | --target-shadow: rgba(187, 239, 253, 0.8); 25 | --pre-border-color: #eee; 26 | --code-background: #f6f8fa; 27 | 28 | --li-code-background: #f6f8fa; 29 | --li-code-color: #0d2b3e; 30 | --toc-color: #1F2D3D; 31 | --toc-before-color: #777; 32 | --toc-background: #f6f8fa; 33 | --toc-list-border: #ccc; 34 | 35 | --spec-summary-border-color: #5c9cf5; 36 | --spec-summary-background: var(--code-background); 37 | --spec-summary-hover-background: #ebeff2; 38 | --spec-details-after-background: rgba(0, 4, 15, 0.05); 39 | --spec-details-after-shadow: rgba(204, 204, 204, 0.53); 40 | } 41 | 42 | .dark:root { 43 | --main-background: #202020; 44 | --code-background: #222; 45 | --line-numbers-background: rgba(0, 0, 0, 0.125); 46 | --navbar-background: #202020; 47 | 48 | --color: #bebebe; 49 | --dirname-color: #666; 50 | --underline-color: #444; 51 | --visited-color: #002800; 52 | --visited-number-color: #252; 53 | --unvisited-color: #380000; 54 | --unvisited-number-color: #622; 55 | --somevisited-color: #303000; 56 | --highlight-color: #303e3f; 57 | --line-number-color: rgba(230, 230, 230, 0.3); 58 | --unvisited-margin-color: #622; 59 | --border: #333; 60 | --navbar-border: #333; 61 | --code-color: #ccc; 62 | 63 | --li-code-background: #373737; 64 | --li-code-color: #999; 65 | --toc-color: #777; 66 | --toc-background: #252525; 67 | 68 | --hljs-link: #999; 69 | --hljs-keyword: #cda869; 70 | --hljs-regexp: #f9ee98; 71 | --hljs-title: #dcdcaa; 72 | --hljs-type: #ac885b; 73 | --hljs-meta: #82aaff; 74 | --hljs-variable: #cf6a4c; 75 | } 76 | 77 | @media (prefers-color-scheme: dark) { 78 | :root { 79 | --main-background: #202020; 80 | --code-background: #333; 81 | --line-numbers-background: rgba(0, 0, 0, 0.125); 82 | --navbar-background: #202020; 83 | 84 | --meter-unvisited-color: #622; 85 | --meter-visited-color: #252; 86 | --meter-separator-color: black; 87 | 88 | --color: #bebebe; 89 | --dirname-color: #666; 90 | --underline-color: #444; 91 | --visited-color: #002800; 92 | --visited-number-color: #252; 93 | --unvisited-color: #380000; 94 | --unvisited-number-color: #622; 95 | --somevisited-color: #303000; 96 | --highlight-color: #303e3f; 97 | --line-number-color: rgba(230, 230, 230, 0.3); 98 | --unvisited-margin-color: #622; 99 | --border: #333; 100 | --navbar-border: #333; 101 | --code-color: #ccc; 102 | --by-name-nav-link-color: var(--color); 103 | 104 | --li-code-background: #373737; 105 | --li-code-color: #999; 106 | --toc-color: #777; 107 | --toc-before-color: #777; 108 | --toc-background: #252525; 109 | --toc-list-border: #ccc; 110 | --spec-summary-hover-background: #ebeff2; 111 | --spec-details-after-background: rgba(0, 4, 15, 0.05); 112 | --spec-details-after-shadow: rgba(204, 204, 204, 0.53); 113 | 114 | --hljs-link: #999; 115 | --hljs-keyword: #cda869; 116 | --hljs-regexp: #f9ee98; 117 | --hljs-title: #dcdcaa; 118 | --hljs-type: #ac885b; 119 | --hljs-meta: #82aaff; 120 | --hljs-variable: #cf6a4c; 121 | } 122 | } 123 | 124 | /* Reset a few things. */ 125 | 126 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 127 | margin: 0; 128 | padding: 0; 129 | border: 0; 130 | font: inherit; 131 | vertical-align: baseline; 132 | 133 | } 134 | 135 | table { 136 | border-collapse: collapse; 137 | border-spacing: 0; 138 | } 139 | 140 | *, *:before, *:after { 141 | box-sizing: border-box; 142 | } 143 | 144 | html { 145 | font-size: 15px; 146 | } 147 | 148 | body { 149 | text-align: left; 150 | background: #FFFFFF; 151 | color: var(--color); 152 | background-color: var(--main-background); 153 | } 154 | 155 | body { 156 | max-width: 90ex; 157 | margin-left: calc(10vw + 20ex); 158 | margin-right: 4ex; 159 | margin-top: 20px; 160 | margin-bottom: 50px; 161 | font-family: "Noticia Text", Georgia, serif; 162 | line-height: 1.5; 163 | } 164 | 165 | header { 166 | margin-bottom: 30px; 167 | } 168 | 169 | nav { 170 | font-family: "Fira Sans", Helvetica, Arial, sans-serif; 171 | } 172 | 173 | /* Basic markup elements */ 174 | 175 | b, strong { 176 | font-weight: bold; 177 | } 178 | 179 | i { 180 | font-style: italic; 181 | } 182 | 183 | em, i em.odd{ 184 | font-style: italic; 185 | } 186 | 187 | em.odd, i em { 188 | font-style: normal; 189 | } 190 | 191 | sup { 192 | vertical-align: super; 193 | } 194 | 195 | sub { 196 | vertical-align: sub; 197 | } 198 | 199 | sup, sub { 200 | font-size: 12px; 201 | line-height: 0; 202 | margin-left: 0.2ex; 203 | } 204 | 205 | pre { 206 | margin-top: 0.8em; 207 | margin-bottom: 1.2em; 208 | } 209 | 210 | p, ul, ol { 211 | margin-top: 0.5em; 212 | margin-bottom: 1em; 213 | } 214 | ul, ol { 215 | list-style-position: outside 216 | } 217 | 218 | ul>li { 219 | margin-left: 22px; 220 | } 221 | 222 | ol>li { 223 | margin-left: 27.2px; 224 | } 225 | 226 | li>*:first-child { 227 | margin-top: 0 228 | } 229 | 230 | /* Text alignements, this should be forbidden. */ 231 | 232 | .left { 233 | text-align: left; 234 | } 235 | 236 | .right { 237 | text-align: right; 238 | } 239 | 240 | .center { 241 | text-align: center; 242 | } 243 | 244 | /* Links and anchors */ 245 | 246 | a { 247 | text-decoration: none; 248 | color: var(--link-color); 249 | } 250 | 251 | a:hover { 252 | box-shadow: 0 1px 0 0 var(--link-color); 253 | } 254 | 255 | /* Linked highlight */ 256 | *:target { 257 | background-color: var(--target-background) !important; 258 | box-shadow: 0 0px 0 1px var(--target-shadow) !important; 259 | border-radius: 1px; 260 | } 261 | 262 | *:hover > a.anchor { 263 | visibility: visible; 264 | } 265 | 266 | a.anchor:before { 267 | content: "#"; 268 | } 269 | 270 | a.anchor:hover { 271 | box-shadow: none; 272 | text-decoration: none; 273 | color: var(--anchor-hover); 274 | } 275 | 276 | a.anchor { 277 | visibility: hidden; 278 | position: absolute; 279 | /* top: 0px; */ 280 | /* margin-left: -3ex; */ 281 | margin-left: -1.3em; 282 | font-weight: normal; 283 | font-style: normal; 284 | padding-right: 0.4em; 285 | padding-left: 0.4em; 286 | /* To remain selectable */ 287 | color: var(--anchor-color); 288 | } 289 | 290 | .spec > a.anchor { 291 | margin-left: -2.3em; 292 | padding-right: 0.9em; 293 | } 294 | 295 | .xref-unresolved { 296 | color: #2C94BD; 297 | } 298 | .xref-unresolved:hover { 299 | box-shadow: 0 1px 0 0 var(--xref-shadow); 300 | } 301 | 302 | /* Section and document divisions. 303 | Until at least 4.03 many of the modules of the stdlib start at .h7, 304 | we restart the sequence there like h2 */ 305 | 306 | h1, h2, h3, h4, h5, h6, .h7, .h8, .h9, .h10 { 307 | font-family: "Fira Sans", Helvetica, Arial, sans-serif; 308 | font-weight: 400; 309 | margin: 0.5em 0 0.5em 0; 310 | padding-top: 0.1em; 311 | line-height: 1.2; 312 | overflow-wrap: break-word; 313 | } 314 | 315 | h1 { 316 | font-weight: 500; 317 | font-size: 2.441em; 318 | margin-top: 1.214em; 319 | } 320 | 321 | h1 { 322 | font-weight: 500; 323 | font-size: 1.953em; 324 | box-shadow: 0 1px 0 0 var(--header-shadow); 325 | } 326 | 327 | h2 { 328 | font-size: 1.563em; 329 | } 330 | 331 | h3 { 332 | font-size: 1.25em; 333 | } 334 | 335 | small, .font_small { 336 | font-size: 0.8em; 337 | } 338 | 339 | h1 code, h1 tt { 340 | font-size: inherit; 341 | font-weight: inherit; 342 | } 343 | 344 | h2 code, h2 tt { 345 | font-size: inherit; 346 | font-weight: inherit; 347 | } 348 | 349 | h3 code, h3 tt { 350 | font-size: inherit; 351 | font-weight: inherit; 352 | } 353 | 354 | h3 code, h3 tt { 355 | font-size: inherit; 356 | font-weight: inherit; 357 | } 358 | 359 | h4 { 360 | font-size: 1.12em; 361 | } 362 | 363 | /* Comment delimiters, hidden but accessible to screen readers and 364 | selected for copy/pasting */ 365 | 366 | /* Taken from bootstrap */ 367 | /* See also https://stackoverflow.com/a/27769435/4220738 */ 368 | .comment-delim { 369 | position: absolute; 370 | width: 1px; 371 | height: 1px; 372 | padding: 0; 373 | margin: -1px; 374 | overflow: hidden; 375 | clip: rect(0, 0, 0, 0); 376 | white-space: nowrap; 377 | border: 0; 378 | } 379 | 380 | /* Preformatted and code */ 381 | 382 | tt, code, pre { 383 | font-family: "Fira Mono", courier; 384 | font-weight: 400; 385 | } 386 | 387 | pre { 388 | padding: 0.1em; 389 | border: 1px solid var(--pre-border-color); 390 | border-radius: 5px; 391 | overflow-x: auto; 392 | } 393 | 394 | p code, 395 | li code { 396 | background-color: var(--li-code-background); 397 | color: var(--li-code-color); 398 | border-radius: 3px; 399 | padding: 0 0.3ex; 400 | } 401 | 402 | p a > code { 403 | color: var(--link-color); 404 | } 405 | 406 | /* Code blocks (e.g. Examples) */ 407 | 408 | pre code { 409 | font-size: 0.893rem; 410 | } 411 | 412 | /* Code lexemes */ 413 | 414 | .keyword { 415 | font-weight: 500; 416 | } 417 | 418 | .arrow { white-space: nowrap } 419 | 420 | /* Module member specification */ 421 | 422 | .spec { 423 | background-color: var(--spec-summary-background); 424 | border-radius: 3px; 425 | border-left: 4px solid var(--spec-summary-border-color); 426 | border-right: 5px solid transparent; 427 | padding: 0.35em 0.5em; 428 | } 429 | 430 | div.spec, .def-doc { 431 | margin-bottom: 20px; 432 | } 433 | 434 | .spec.type .variant { 435 | margin-left: 2ch; 436 | } 437 | .spec.type .variant p { 438 | margin: 0; 439 | font-style: italic; 440 | } 441 | .spec.type .record { 442 | margin-left: 2ch; 443 | } 444 | .spec.type .record p { 445 | margin: 0; 446 | font-style: italic; 447 | } 448 | 449 | div.def { 450 | margin-top: 0; 451 | text-indent: -2ex; 452 | padding-left: 2ex; 453 | } 454 | 455 | div.def+div.def-doc { 456 | margin-left: 1ex; 457 | margin-top: 2.5px 458 | } 459 | 460 | div.def-doc>*:first-child { 461 | margin-top: 0; 462 | } 463 | 464 | /* Collapsible inlined include and module */ 465 | 466 | .odoc-include details { 467 | position: relative; 468 | } 469 | 470 | .odoc-include details:after { 471 | z-index: -100; 472 | display: block; 473 | content: " "; 474 | position: absolute; 475 | border-radius: 0 1ex 1ex 0; 476 | right: -20px; 477 | top: 1px; 478 | bottom: 1px; 479 | width: 15px; 480 | background: var(--spec-details-after-background, rgba(0, 4, 15, 0.05)); 481 | box-shadow: 0 0px 0 1px var(--spec-details-after-shadow, rgba(204, 204, 204, 0.53)); 482 | } 483 | 484 | .odoc-include summary { 485 | position: relative; 486 | margin-bottom: 20px; 487 | cursor: pointer; 488 | outline: none; 489 | } 490 | 491 | .odoc-include summary:hover { 492 | background-color: var(--spec-summary-hover-background); 493 | } 494 | 495 | /* FIXME: Does not work in Firefox. */ 496 | .odoc-include summary::-webkit-details-marker { 497 | color: #888; 498 | transform: scaleX(-1); 499 | position: absolute; 500 | top: calc(50% - 5px); 501 | height: 11px; 502 | right: -29px; 503 | } 504 | 505 | /* Records and variants FIXME */ 506 | 507 | div.def table { 508 | text-indent: 0em; 509 | padding: 0; 510 | margin-left: -2ex; 511 | } 512 | 513 | td.def { 514 | padding-left: 2ex; 515 | } 516 | 517 | td.def-doc *:first-child { 518 | margin-top: 0em; 519 | } 520 | 521 | /* Lists of @tags */ 522 | 523 | .at-tags { list-style-type: none; margin-left: -3ex; } 524 | .at-tags li { padding-left: 3ex; text-indent: -3ex; } 525 | .at-tags .at-tag { text-transform: capitalize } 526 | 527 | /* Lists of modules */ 528 | 529 | .modules { list-style-type: none; margin-left: -3ex; } 530 | .modules li { padding-left: 3ex; text-indent: -3ex; margin-top: 5px } 531 | .modules .synopsis { padding-left: 1ch; } 532 | 533 | /* Odig package index */ 534 | 535 | .packages { list-style-type: none; margin-left: -3ex; } 536 | .packages li { padding-left: 3ex; text-indent: -3ex } 537 | .packages li a.anchor { padding-right: 0.5ch; padding-left: 3ch; } 538 | .packages .version { font-size: 10px; color: var(--by-name-version-color); } 539 | .packages .synopsis { padding-left: 1ch } 540 | 541 | .by-name nav a { 542 | text-transform: uppercase; 543 | font-size: 18px; 544 | margin-right: 1ex; 545 | color: var(--by-name-nav-link-color,); 546 | display: inline-block; 547 | } 548 | 549 | .by-tag nav a { 550 | margin-right: 1ex; 551 | color: var(--by-name-nav-link-color); 552 | display: inline-block; 553 | } 554 | 555 | .by-tag ol { list-style-type: none; } 556 | .by-tag ol.tags li { margin-left: 1ch; display: inline-block } 557 | .by-tag td:first-child { text-transform: uppercase; } 558 | 559 | /* Odig package page */ 560 | 561 | .package nav { 562 | display: inline; 563 | font-size: 14px; 564 | font-weight: normal; 565 | } 566 | 567 | .package .version { 568 | font-size: 14px; 569 | } 570 | 571 | .package.info { 572 | margin: 0; 573 | } 574 | 575 | .package.info td:first-child { 576 | font-style: italic; 577 | padding-right: 2ex; 578 | } 579 | 580 | .package.info ul { 581 | list-style-type: none; 582 | display: inline; 583 | margin: 0; 584 | } 585 | 586 | .package.info li { 587 | display: inline-block; 588 | margin: 0; 589 | margin-right: 1ex; 590 | } 591 | 592 | #info-authors li, #info-maintainers li { 593 | display: block; 594 | } 595 | 596 | /* Sidebar and TOC */ 597 | 598 | .odoc-toc:before { 599 | display: block; 600 | content: "Contents"; 601 | text-transform: uppercase; 602 | font-size: 1em; 603 | margin: 1.414em 0 0.5em; 604 | font-weight: 500; 605 | color: var(--toc-before-color); 606 | line-height: 1.2; 607 | } 608 | 609 | .odoc-toc { 610 | position: fixed; 611 | top: 0px; 612 | bottom: 0px; 613 | left: 0px; 614 | max-width: 30ex; 615 | min-width: 26ex; 616 | width: 20%; 617 | background: var(--toc-background); 618 | overflow: auto; 619 | color: var(--toc-color); 620 | padding-left: 2ex; 621 | padding-right: 2ex; 622 | } 623 | 624 | .odoc-toc ul li a { 625 | font-family: "Fira Sans", sans-serif; 626 | font-size: 0.95em; 627 | color: var(--color); 628 | font-weight: 400; 629 | line-height: 1.6em; 630 | display: block; 631 | } 632 | 633 | .odoc-toc ul li a:hover { 634 | box-shadow: none; 635 | text-decoration: underline; 636 | } 637 | 638 | /* First level titles */ 639 | 640 | .odoc-toc>ul>li>a { 641 | font-weight: 500; 642 | } 643 | 644 | .odoc-toc li ul { 645 | margin: 0px; 646 | } 647 | 648 | .odoc-toc ul { 649 | list-style-type: none; 650 | } 651 | 652 | .odoc-toc ul li { 653 | margin: 0; 654 | } 655 | .odoc-toc>ul>li { 656 | margin-bottom: 0.3em; 657 | } 658 | 659 | .odoc-toc ul li li { 660 | border-left: 1px solid var(--toc-list-border); 661 | margin-left: 5px; 662 | padding-left: 12px; 663 | } 664 | 665 | /* Mobile adjustements. */ 666 | 667 | @media only screen and (max-width: 95ex) { 668 | .odoc-content { 669 | margin: auto; 670 | padding: 2em; 671 | } 672 | .odoc-toc { 673 | position: static; 674 | width: auto; 675 | min-width: unset; 676 | max-width: unset; 677 | border: none; 678 | padding: 0.2em 1em; 679 | border-radius: 5px; 680 | } 681 | } 682 | 683 | /* Print adjustements. */ 684 | 685 | @media print { 686 | body { 687 | color: black; 688 | background: white; 689 | } 690 | body nav:first-child { 691 | visibility: hidden; 692 | } 693 | } 694 | 695 | /* Syntax highlighting (based on github-gist) */ 696 | 697 | .hljs { 698 | display: block; 699 | background: var(--code-background); 700 | padding: 0.5em; 701 | color: var(--color); 702 | overflow-x: auto; 703 | } 704 | 705 | .hljs-comment, 706 | .hljs-meta { 707 | color: #969896; 708 | } 709 | 710 | .hljs-string, 711 | .hljs-variable, 712 | .hljs-template-variable, 713 | .hljs-strong, 714 | .hljs-emphasis, 715 | .hljs-quote { 716 | color: #df5000; 717 | } 718 | 719 | .hljs-keyword, 720 | .hljs-selector-tag { 721 | color: #a71d5d; 722 | } 723 | 724 | .hljs-type, 725 | .hljs-class .hljs-title { 726 | color: #458; 727 | font-weight: 500; 728 | } 729 | 730 | .hljs-literal, 731 | .hljs-symbol, 732 | .hljs-bullet, 733 | .hljs-attribute { 734 | color: #0086b3; 735 | } 736 | 737 | .hljs-section, 738 | .hljs-name { 739 | color: #63a35c; 740 | } 741 | 742 | .hljs-tag { 743 | color: #333333; 744 | } 745 | 746 | .hljs-attr, 747 | .hljs-selector-id, 748 | .hljs-selector-class, 749 | .hljs-selector-attr, 750 | .hljs-selector-pseudo { 751 | color: #795da3; 752 | } 753 | 754 | .hljs-addition { 755 | color: #55a532; 756 | background-color: #eaffea; 757 | } 758 | 759 | .hljs-deletion { 760 | color: #bd2c00; 761 | background-color: #ffecec; 762 | } 763 | 764 | .hljs-link { 765 | text-decoration: underline; 766 | } 767 | 768 | /*--------------------------------------------------------------------------- 769 | Copyright (c) 2016 The odoc contributors 770 | 771 | Permission to use, copy, modify, and/or distribute this software for any 772 | purpose with or without fee is hereby granted, provided that the above 773 | copyright notice and this permission notice appear in all copies. 774 | 775 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 776 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 777 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 778 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 779 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 780 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 781 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 782 | ---------------------------------------------------------------------------*/ 783 | --------------------------------------------------------------------------------