From b2cff1d0b73ab30dedce620719eb134c40df302b Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 18 Oct 2021 22:31:44 -0400 Subject: [PATCH] prepare for 3.6 --- CHANGELOG.md | 13 +++++ containers-data.opam | 2 +- containers-thread.opam | 2 +- containers.opam | 2 +- src/core/CCIO.mli | 10 ++-- src/core/CCOption.mli | 2 +- src/core/CCOrd.mli | 4 +- src/core/CCParse.mli | 108 ++++++++++++++++++++--------------------- 8 files changed, 78 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d97d3d9ff..687660ebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 3.6 + +- rename `CCOpt` to `CCOption` and deprecate `CCOpt` +- add iterator functions to `CCIO` +- `CCOrd`: add `poly`, deprecate `compare` +- add `CCIO.File.walk_iter` +- `CCParse`: heavy refactoring, many new functions + * backtracking by default + * add `slice` and the ability to recurse on them + * expose Position module, add `or_`, `both`, `lookahead`, `U.bool` + * example Sexpr parser, and a test + * example and test of an IRC log parser + ## 3.5 - add `CCHash.map` and `CCHash.bytes` diff --git a/containers-data.opam b/containers-data.opam index f79e53ab9..7eab3a458 100644 --- a/containers-data.opam +++ b/containers-data.opam @@ -1,5 +1,5 @@ opam-version: "2.0" -version: "3.5" +version: "3.6" author: "Simon Cruanes" maintainer: "simon.cruanes.2007@m4x.org" synopsis: "A set of advanced datatypes for containers" diff --git a/containers-thread.opam b/containers-thread.opam index cab02dc06..d13c57517 100644 --- a/containers-thread.opam +++ b/containers-thread.opam @@ -1,5 +1,5 @@ opam-version: "2.0" -version: "3.5" +version: "3.6" author: "Simon Cruanes" maintainer: "simon.cruanes.2007@m4x.org" license: "BSD-2-Clause" diff --git a/containers.opam b/containers.opam index 419f11c33..14dc7f527 100644 --- a/containers.opam +++ b/containers.opam @@ -1,6 +1,6 @@ opam-version: "2.0" name: "containers" -version: "3.5" +version: "3.6" author: "Simon Cruanes" maintainer: "simon.cruanes.2007@m4x.org" license: "BSD-2-Clause" diff --git a/src/core/CCIO.mli b/src/core/CCIO.mli index c0d8efb5b..dfeffd135 100644 --- a/src/core/CCIO.mli +++ b/src/core/CCIO.mli @@ -80,7 +80,7 @@ val read_chunks_seq : ?size:int -> in_channel -> string Seq.t val read_chunks_iter : ?size:int -> in_channel -> string iter (** Read the channel's content into chunks of size at most [size] - @since NEXT_RELEASE *) + @since 3.6 *) val read_line : in_channel -> string option (** Read a line from the channel. Returns [None] if the input is terminated. @@ -99,7 +99,7 @@ val read_lines_seq : in_channel -> string Seq.t val read_lines_iter : in_channel -> string iter (** Read all lines. - @since NEXT_RELEASE *) + @since 3.6 *) val read_lines_l : in_channel -> string list (** Read all lines into a list. *) @@ -146,7 +146,7 @@ val write_lines : out_channel -> string gen -> unit val write_lines_iter : out_channel -> string iter -> unit (** Write every string on the output, followed by "\n". - @since NEXT_RELEASE *) + @since 3.6 *) val write_lines_seq : out_channel -> string Seq.t -> unit (** Write every string on the output, followed by "\n". @@ -265,7 +265,7 @@ module File : sig val walk_iter : t -> walk_item iter (** Like {!walk} but with an imperative iterator. - @since NEXT_RELEASE *) + @since 3.6 *) val walk_l : t -> walk_item list (** Like {!walk} but returns a list (therefore it's eager and might @@ -274,7 +274,7 @@ module File : sig val walk_seq : t -> walk_item Seq.t (** Like {!walk} but returns a Seq - @since NEXT_RELEASE *) + @since 3.6 *) val show_walk_item : walk_item -> string diff --git a/src/core/CCOption.mli b/src/core/CCOption.mli index 22b8e31f5..8ae501184 100644 --- a/src/core/CCOption.mli +++ b/src/core/CCOption.mli @@ -3,7 +3,7 @@ (** Options This module replaces `CCOpt`. - @since NEXT_RELEASE *) + @since 3.6 *) type +'a t = 'a option diff --git a/src/core/CCOrd.mli b/src/core/CCOrd.mli index 11c816ba5..c4e2fed78 100644 --- a/src/core/CCOrd.mli +++ b/src/core/CCOrd.mli @@ -9,12 +9,12 @@ type 'a t = 'a -> 'a -> int val poly : 'a t (** Polymorphic "magic" comparison. Use with care, as it will fail on some types. - @since NEXT_RELEASE *) + @since 3.6 *) val compare : 'a t [@@deprecated "use CCOrd.poly instead, this name is too general"] (** Polymorphic "magic" comparison. - @deprecated since NEXT_RELEASE in favor of {!poly}. The reason is that + @deprecated since 3.6 in favor of {!poly}. The reason is that [compare] is easily shadowed, can shadow other comparators, and is just generally not very descriptive. *) diff --git a/src/core/CCParse.mli b/src/core/CCParse.mli index 274d4852a..25c6a6aef 100644 --- a/src/core/CCParse.mli +++ b/src/core/CCParse.mli @@ -67,7 +67,7 @@ type position (** {2 Positions in input} - @since NEXT_RELEASE *) + @since 3.6 *) module Position : sig type t = position @@ -85,11 +85,11 @@ module Position : sig end (** {2 Errors} - @since NEXT_RELEASE *) + @since 3.6 *) module Error : sig type t (** A parse error. - @since NEXT_RELEASE *) + @since 3.6 *) val position : t -> position (** Returns position of the error *) @@ -123,7 +123,7 @@ type 'a t (** The abstract type of parsers that return a value of type ['a] (or fail). @raise ParseError in case of failure. - @since NEXT_RELEASE the type is private. + @since 3.6 the type is private. *) val return : 'a -> 'a t @@ -141,19 +141,19 @@ val map3 : ('a -> 'b -> 'c -> 'd) -> 'a t -> 'b t -> 'c t -> 'd t val bind : ('a -> 'b t) -> 'a t -> 'b t (** [bind f p] results in a new parser which behaves as [p] then, in case of success, applies [f] to the result. - @since NEXT_RELEASE + @since 3.6 *) val ap : ('a -> 'b) t -> 'a t -> 'b t (** Applicative. - @since NEXT_RELEASE *) + @since 3.6 *) val eoi : unit t (** Expect the end of input, fails otherwise. *) val empty : unit t (** Succeed with [()]. - @since NEXT_RELEASE *) + @since 3.6 *) val fail : string -> 'a t (** [fail msg] fails with the given message. It can trigger a backtrack. *) @@ -163,7 +163,7 @@ val failf: ('a, unit, string, 'b t) format4 -> 'a val fail_lazy : (unit -> string) -> 'a t (** Like {!fail}, but only produce an error message on demand. - @since NEXT_RELEASE *) + @since 3.6 *) val parsing : string -> 'a t -> 'a t (** [parsing s p] behaves the same as [p], with the information that @@ -176,24 +176,24 @@ val set_error_message : string -> 'a t -> 'a t (** [set_error_message msg p] behaves like [p], but if [p] fails, [set_error_message msg p] fails with [msg] instead and at the current position. The internal error message of [p] is just discarded. - @since NEXT_RELEASE *) + @since 3.6 *) val with_pos : 'a t -> ('a * position) t (** [with_pos p] behaves like [p], but returns the (starting) position along with [p]'s result. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val any_char : char t (** [any_char] parses any character. It still fails if the end of input was reached. - @since NEXT_RELEASE *) + @since 3.6 *) val any_char_n : int -> string t (** [any_char_n len] parses exactly [len] characters from the input. Fails if the input doesn't contain at least [len] chars. - @since NEXT_RELEASE *) + @since 3.6 *) val char : char -> char t (** [char c] parses the character [c] and nothing else. *) @@ -215,10 +215,10 @@ type slice not at line 1. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) (** Functions on slices. - @since NEXT_RELEASE *) + @since 3.6 *) module Slice : sig type t = slice @@ -243,13 +243,13 @@ val recurse : slice -> 'a t -> 'a t the slice. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val set_current_slice : slice -> unit t (** [set_current_slice slice] replaces the parser's state with [slice]. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val chars_fold : f:('acc -> char -> @@ -273,7 +273,7 @@ val chars_fold : It can also be useful as a base component for a lexer. @return a pair of the final accumular, and the slice matched by the fold. - @since NEXT_RELEASE *) + @since 3.6 *) val chars_fold_transduce : f:('acc -> char -> @@ -289,22 +289,22 @@ val chars_fold_transduce : - new case [`Yield (acc, c)] adds [c] to the returned string and continues parsing with [acc]. - @since NEXT_RELEASE *) + @since 3.6 *) val take : int -> slice t (** [take len] parses exactly [len] characters from the input. Fails if the input doesn't contain at least [len] chars. - @since NEXT_RELEASE *) + @since 3.6 *) val take_if : (char -> bool) -> slice t (** [take_if f] takes characters as long as they satisfy the predicate [f]. - @since NEXT_RELEASE *) + @since 3.6 *) val take1_if : ?descr:string -> (char -> bool) -> slice t (** [take1_if f] takes characters as long as they satisfy the predicate [f]. Fails if no character satisfies [f]. @param descr describes what kind of character was expected, in case of error - @since NEXT_RELEASE *) + @since 3.6 *) val char_if : ?descr:string -> (char -> bool) -> char t (** [char_if f] parses a character [c] if [f c = true]. @@ -363,7 +363,7 @@ val string : string -> string t val exact : string -> string t (** Alias to {!string}. - @since NEXT_RELEASE *) + @since 3.6 *) val many : 'a t -> 'a list t (** [many p] parses [p] repeatedly, until [p] fails, and @@ -374,21 +374,21 @@ val optional : _ t -> unit t succeeded or failed. Cannot fail itself. It consumes input if [p] succeeded (as much as [p] consumed), but consumes not input if [p] failed. - @since NEXT_RELEASE *) + @since 3.6 *) val try_ : 'a t -> 'a t [@@deprecated "plays no role anymore, just replace [try foo] with [foo]"] (** [try_ p] is just like [p] (it used to play a role in backtracking semantics but no more). - @deprecated since NEXT_RELEASE it can just be removed. See {!try_opt} if you want + @deprecated since 3.6 it can just be removed. See {!try_opt} if you want to detect failure. *) val try_opt : 'a t -> 'a option t (** [try_opt p] tries to parse using [p], and return [Some x] if [p] succeeded with [x] (and consumes what [p] consumed). Otherwise it returns [None] and consumes nothing. This cannot fail. - @since NEXT_RELEASE *) + @since 3.6 *) val many_until : until:_ t -> 'a t -> 'a list t (** [many_until ~until p] parses as many [p] as it can until @@ -399,7 +399,7 @@ val many_until : until:_ t -> 'a t -> 'a list t {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val try_or : 'a t -> f:('a -> 'b t) -> else_:'b t -> 'b t (** [try_or p1 ~f ~else_:p2] attempts to parse [x] using [p1], @@ -407,7 +407,7 @@ val try_or : 'a t -> f:('a -> 'b t) -> else_:'b t -> 'b t If [p1] fails, then it becomes [p2]. This can be useful if [f] is expensive but only ever works if [p1] matches (e.g. after an opening parenthesis or some sort of prefix). - @since NEXT_RELEASE + @since 3.6 *) val try_or_l : @@ -429,16 +429,16 @@ val try_or_l : @param msg error message if all options fail {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val or_ : 'a t -> 'a t -> 'a t (** [or_ p1 p2] tries to parse [p1], and if it fails, tries [p2] from the same position. - @since NEXT_RELEASE *) + @since 3.6 *) val both : 'a t -> 'b t -> ('a * 'b) t (** [both a b] parses [a], then [b], then returns the pair of their results. - @since NEXT_RELEASE *) + @since 3.6 *) val many1 : 'a t -> 'a list t (** [many1 p] is like [many p] excepts it fails if the @@ -454,7 +454,7 @@ val sep : by:_ t -> 'a t -> 'a list t val sep_until: until:_ t -> by:_ t -> 'a t -> 'a list t (** Same as {!sep} but stop when [until] parses successfully. - @since NEXT_RELEASE *) + @since 3.6 *) val sep1 : by:_ t -> 'a t -> 'a list t (** [sep1 ~by p] parses a non empty list of [p], separated by [by]. *) @@ -463,7 +463,7 @@ val lookahead : 'a t -> 'a t (** [lookahead p] behaves like [p], except it doesn't consume any input. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val lookahead_ignore : 'a t -> unit t (** [lookahead_ignore p] tries to parse input with [p], @@ -472,25 +472,25 @@ val lookahead_ignore : 'a t -> unit t whether [p] succeeds, e.g. in {!try_or_l}. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val fix : ('a t -> 'a t) -> 'a t (** Fixpoint combinator. *) val line : slice t (** Parse a line, ['\n'] excluded, and position the cursor after the ['\n']. - @since NEXT_RELEASE *) + @since 3.6 *) val line_str : string t (** [line_str] is [line >|= Slice.to_string]. It parses the next line and turns the slice into a string. The state points to the character immediately after the ['\n'] character. - @since NEXT_RELEASE *) + @since 3.6 *) val each_line : 'a t -> 'a list t (** [each_line p] runs [p] on each line of the input. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val split_1 : on_char:char -> (slice * slice option) t (** [split_1 ~on_char] looks for [on_char] in the input, and returns a @@ -506,14 +506,14 @@ val split_1 : on_char:char -> (slice * slice option) t The parser is now positioned at the end of the input. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val split_list : on_char:char -> slice list t (** [split_list ~on_char] splits the input on all occurrences of [on_char], returning a list of slices. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val split_list_at_most : on_char:char -> int -> slice list t (** [split_list_at_most ~on_char n] applies [split_1 ~on_char] at most @@ -522,24 +522,24 @@ val split_list_at_most : on_char:char -> int -> slice list t amount of work done by {!split_list}. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val split_2 : on_char:char -> (slice * slice) t (** [split_2 ~on_char] splits the input into exactly 2 fields, and fails if the split yields less or more than 2 items. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val split_3 : on_char:char -> (slice * slice * slice) t (** See {!split_2} {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val split_4 : on_char:char -> (slice * slice * slice * slice) t (** See {!split_2} {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val each_split : on_char:char -> 'a t -> 'a list t (** [split_list_map ~on_char p] uses [split_list ~on_char] to split @@ -554,7 +554,7 @@ val each_split : on_char:char -> 'a t -> 'a list t basically [each_split ~on_char:'\n' p]. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) val all : slice t (** [all] returns all the unconsumed input as a slice, and consumes it. @@ -563,20 +563,20 @@ val all : slice t Note that [lookahead all] can be used to {i peek} at the rest of the input without consuming anything. - @since NEXT_RELEASE *) + @since 3.6 *) val all_str : string t (** [all_str] accepts all the remaining chars and extracts them into a string. Similar to {!all} but with a string. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) (* TODO val trim : slice t (** [trim] is like {!all}, but removes whitespace on the left and right. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) *) val memo : 'a t -> 'a t @@ -641,7 +641,7 @@ module Infix : sig val (|||) : 'a t -> 'b t -> ('a * 'b) t (** Alias to {!both}. [a ||| b] parses [a], then [b], then returns the pair of their results. - @since NEXT_RELEASE *) + @since 3.6 *) (** Let operators on OCaml >= 4.08.0, nothing otherwise @since 2.8 *) @@ -654,7 +654,7 @@ include module type of Infix val stringify_result : 'a or_error -> ('a, string) result (** Turn a {!Error.t}-oriented result into a more basic string result. - @since NEXT_RELEASE *) + @since 3.6 *) val parse_string : 'a t -> string -> ('a, string) result (** Parse a string using the parser. *) @@ -695,29 +695,29 @@ module U : sig val in_paren : 'a t -> 'a t (** [in_paren p] parses an opening "(",[p] , and then ")". - @since NEXT_RELEASE *) + @since 3.6 *) val in_parens_opt : 'a t -> 'a t (** [in_parens_opt p] parses [p] in an arbitrary number of nested parenthesis (possibly 0). - @since NEXT_RELEASE *) + @since 3.6 *) val option : 'a t -> 'a option t (** [option p] parses "Some " into [Some x] if [p] parses "" into [x], and parses "None" into [None]. - @since NEXT_RELEASE *) + @since 3.6 *) val hexa_int : int t (** Parse an int int hexadecimal format. Accepts an optional [0x] prefix, and ignores capitalization. - @since NEXT_RELEASE *) + @since 3.6 *) val word : string t (** Non empty string of alpha num, start with alpha. *) val bool : bool t (** Accepts "true" or "false" - @since NEXT_RELEASE *) + @since 3.6 *) (* TODO: quoted string *) @@ -734,7 +734,7 @@ end (** Debugging utils. {b EXPERIMENTAL} - @since NEXT_RELEASE *) + @since 3.6 *) module Debug_ : sig val trace_fail : string -> 'a t -> 'a t (** [trace_fail name p] behaves like [p], but prints the error message of [p]