[Pkg-ocaml-maint-commits] [sexplib310] 01/09: Imported Upstream version 113.33.00
Stéphane Glondu
glondu at moszumanska.debian.org
Thu Jul 28 14:12:40 UTC 2016
This is an automated email from the git hooks/post-receive script.
glondu pushed a commit to branch master
in repository sexplib310.
commit 3155175bbde3d42d93d0e91d193b3d2835cbc89b
Author: Stephane Glondu <steph at glondu.net>
Date: Sat Jul 23 10:40:01 2016 +0200
Imported Upstream version 113.33.00
---
CHANGES.md | 40 +++++
README.md | 478 ---------------------------------------------------
README.org | 105 +++++++++++
_oasis | 2 +-
src/macro.ml | 31 +++-
src/pre_sexp.ml | 48 +++++-
test/test_macros.mli | 1 -
7 files changed, 215 insertions(+), 490 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index fcfa49f..11e81fa 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,43 @@
+## 113.33.00
+
+- Changes `Sexp.to_string` to escape all non-ASCII characters.
+
+ Previously chars >= 127 are escaped or not depending on:
+ 1. other character in the string
+ 2. the system
+ 3. environment variable settings
+
+ (2) and (3) are because `String.escaped` from the stdlib uses the C
+ function `isprint` which is locale and OS dependent.
+
+ This can cause invalid UTF-8 sequence to be printed by sexplib, which
+ is annoying:
+
+ https://github.com/janestreet/sexplib/issues/18
+
+ Starting with this release, sexplib:
+ 1. copies the `String.escaped` function of OCaml 4.03 which escapes
+ all non-ascii characters
+ 2. make sure we escape the string when it contains characters >= 127
+
+- Clean up the documentation for sexplib, modernizing it to include
+ `ppx_sexp_conv`, and breaking up the documentation between sexplib and
+ `ppx_sexp_conv`. Also changed the formatting to use org-mode, so it
+ will render properly on github. Markdown doesn't render well by
+ default, unless you use quite different conventions about linebeaks.
+
+- In sexp macro library, avoid returning success when there is any error
+ reading a sexp. In particular, this prevents
+
+ sexp resolve <(echo '(:use x)')
+
+ from silently succeeding.
+
+ Also, now we no longer read an included file multiple times.
+ This lets even crazy stuff like this to work:
+
+ $ echo 'hi ' | sexp resolve <(echo '((:include /dev/stdin) (:include /dev/stdin))')
+
## 113.24.00
- Switch code in `lib` subdir to ppx-style.
diff --git a/README.md b/README.md
deleted file mode 100644
index 381f669..0000000
--- a/README.md
+++ /dev/null
@@ -1,478 +0,0 @@
-Sexplib - S-Expressions with Type Converters for OCaml
-======================================================
-
----------------------------------------------------------------------------
-
-What is Sexplib?
-----------------
-
-This [OCaml](http://www.ocaml.org) library contains functionality for
-parsing and pretty-printing S-expressions. In addition to that it contains a
-preprocessing module for Camlp4 which can be used to automatically generate
-code from type definitions for efficiently converting OCaml-values to
-S-expressions and vice versa.
-
-In combination with the parsing and pretty-printing functionality this
-frees users from having to write their own I/O-routines for data structures
-they define. The tight integration with the OCaml type system also allows
-for automatically verifying complex semantic properties when converting from
-S-expressions to OCaml values. Possible errors during automatic conversions
-from S-expressions to OCaml-values are reported in human-readable ways
-with exact location information. The library also offers functionality for
-extracting and replacing sub-expressions in S-expressions.
-
-Usage
------
-
-Make sure you have installed the required `type_conv` package on your
-system, too. It should be obtainable at the same site as `sexplib`.
-
-The API (`.mli`-files) in the `sexplib` library directory (`lib`)
-is fully documented, and HTML-documentation can be built from it on
-installation. The documentation for the latest release can also be found
-[online](http://mmottl.bitbucket.org/projects/sexplib/api/).
-
-Module `Sexp` contains all I/O-functions for S-expressions, module
-`Conv` helper functions for converting OCaml-values of standard types
-to S-expressions. Module `Path` supports sub-expression extraction and
-substitution.
-
-Module `syntax/pa_sexp_conv.ml` contains the extensions for the
-Camlp4-preprocessor. It adds the following three new constructs to the
-language:
-
- :::ocaml
- with sexp
- with sexp_of
- with of_sexp
-
-The first one implies the last two statements. When using these constructs
-right after a type definition, function definitions will be automatically
-generated which perform S-expression conversions. For example, consider
-the following type definition:
-
- :::ocaml
- type t = A | B with sexp
-
-The above will generate the functions `sexp_of_t` and `t_of_sexp`.
-The preprocessor also supports automatic addition of conversion functions
-to signatures. Just add "`with sexp`" to the type in a signature, and the
-appropriate function signatures will be generated.
-
-Converters for standard types (`int`, `list`, `Hashtbl.t`, etc.) become
-visible to the macro-generated code by opening the standard module before
-their first use in a type definition. Users will therefore usually want to
-place the following at the top of their files:
-
- :::ocaml
- open Sexplib.Std
-
-See the file `lib_test/conv_test.ml` for an example application. It also
-demonstrates how to extract and substitute sub-expressions.
-
-### Compiling and linking
-
-To compile a file you will have to add preprocessing flags to the compiler
-invocation. For example for file `foo.ml`:
-
- :::sh
- ocamlc -pp "camlp4o -I {path to type_conv} \
- -I {path to sexplib} pa_type_conv.cmo pa_sexp_conv.cmo" \
- -I {path to sexplib} foo.ml
-
-If you are using [OCamlMakefile](http://bitbucket.org/mmottl/ocaml-makefile),
-just put the following line at the top of the file, assuming you have installed
-both `type_conv` and `sexplib` with ocamlfind. The comment must start at
-the beginning of the line, and you must not break lines (here broken for
-readability only):
-
- :::ocaml
- (*pp camlp4o -I `ocamlfind query type_conv` \
- -I `ocamlfind query sexplib` \
- pa_type_conv.cmo pa_sexp_conv.cmo *)
-
-In the linking stage you will only have to link with `sexplib`. E.g. when
-using `OCamlMakefile`, just add `sexplib` to the `PACKS`-variable.
-
-Users of the OCaml tool
-[findlib](http://projects.camlcity.org/projects/findlib.html) for compiling
-and linking OCaml files have an easier time: they just need to add `sexplib`
-to the list of packages to make S-expression functionality available.
-Adding `sexplib.syntax`, too, will make sure that files that use the type
-conversion feature will be preprocessed correctly.
-
-You may choose to place the macro `TYPE_CONV_PATH`, which takes a string
-argument, at the top of files to be preprocessed if you want to force a
-particular module path for error messages generated by `sexplib`. This may
-become necessary if modules are packed into a library at a later stage and
-if error messages generated by Sexplib need to refer to this location to
-help pinpoint the associated type.
-
-Syntax Specification of S-expressions
--------------------------------------
-
-### Lexical conventions of S-expression
-
-Whitespace, which consists of space, newline, horizontal tab, and form feed,
-is ignored unless within an OCaml-string, where it is treated according
-to OCaml-conventions. The left parenthesis opens a new list, the right one
-closes it again. Lists can be empty. The double quote denotes the beginning
-and end of a string following the lexical conventions of OCaml (see the
-[OCaml-manual](http://www.ocaml.org/pub/docs/manual-ocaml) for details).
-All characters other than double quotes, left- and right parentheses,
-whitespace, carriage return, and comment-introducing characters or sequences
-(see next paragraph) are considered part of a contiguous string.
-
-A line comment is introduced using a semicolon, which comments out all
-text up to the end of the next newline character. The sequence "`#;`"
-introduces an S-expression comment. This means that the next S-expression,
-which must be syntactically correct and may be an atom (quoted or unquoted)
-or list, following this two-character sequence will be ignored. Whitespace
-or other comments between this sequence and the subsequent S-expression
-are ignored. Block comments are opened with "`#|`" and closed with "`|#`".
-They can be nested and require that double-quotes within the block balance
-and contain syntactically correct OCaml-strings, similar to quoted atoms.
-These OCaml-strings may contain comment characters without causing parsing
-problems.
-
-### Grammar of S-expressions
-
-S-expressions are either strings (= atoms) or lists. The lists can
-recursively contain further S-expressions or be empty, and must be balanced,
-i.e. parentheses must match.
-
-### Examples
-
- :::scheme
- this_is_an_atom_123'&^%! ; this is a comment
- "another atom in an OCaml-string \"string in a string\" \123"
-
- ; empty list follows below
- ()
-
- ; a more complex example
- (
- (
- list in a list ; comment within a list
- (list in a list in a list)
- 42 is the answer to all questions
- #; (this S-expression
- (has been commented out)
- )
- #| Block comments #| can be "nested" |# |#
- )
- )
-
-### Conversion of basic OCaml-values
-
-Basic OCaml-values like the unit-value, integers (in all representations),
-floats, strings, and booleans are represented in S-expression syntax the
-same way as in OCaml. Strings may also appear without quotes if this does
-not clash with the lexical conventions for S-expressions.
-
-### Conversion of OCaml-tuples
-
-OCaml-tuples are simple lists of values in the same order as in the tuple.
-E.g. (OCaml representation followed by S-expression after arrow):
-
- :::ocaml
- (3.14, "foo", "bar bla", 27) <===> (3.14 foo "bar bla" 27)
-
-### Conversion of OCaml-records
-
-OCaml-records are represented as lists of pairs in S-expression syntax.
-Each pair consists of the name of the record field (first element), and its
-value (second element). E.g.:
-
- :::ocaml
- {
- foo = 3;
- bar = "some string";
- }
- <===>
- (
- (foo 3)
- (bar "some string")
- )
-
-Type specifications of records allow the use of a special type `sexp_option`
-which indicates that a record field should be optional. E.g.:
-
- :::ocaml
- type t =
- {
- x : int option;
- y : int sexp_option;
- } with sexp
-
-The type `sexp_option` is equivalent to ordinary options, but is treated
-specially by the code generator. The above would lead to the following
-equivalences of values and S-expressions:
-
- :::ocaml
- {
- x = Some 1;
- y = Some 2;
- }
- <===>
- (
- (x (some 1))
- (y 2)
- )
-
-And:
-
- :::ocaml
- {
- x = None;
- y = None;
- }
- <===>
- (
- (x none)
- )
->>
-
- Note how `sexp_option` allows you to leave away record fields that should
-default to `None`. It is also unnecessary (and actually wrong) now to write
-down such a value as an option, i.e. the `some`-tag must be dropped if the
-field should be defined.
-
-The types `sexp_list`, `sexp_array`, and `sexp_bool` can be used in ways
-similar to the type `sexp_option`. They assume the empty list, empty array,
-and false value respectively as default values.
-
-More complex default values can be specified explicitly using several
-constructs, e.g.:
-
- :::ocaml
- let z_test v = v > 42
-
- type t =
- {
- x : int with default(42);
- y : int with default(3), sexp_drop_default;
- z : int with default(3), sexp_drop_if(z_test);
- } with sexp
-
-The `default` record field extension above is supported by the underlying
-preprocessor library `type_conv` and specifies the intended default value for
-a record field in its argument. Sexplib will use this information to generate
-code which will set this record field to the default value if an S-expression
-omits this field. If a record is converted to an S-expression, record fields
-with default values will be emitted as usual. Specifying `sexp_drop_default`
-will add a test for polymorphic equality to the generated code such that a
-record field containing its default value will be suppressed in the resulting
-S-expression. This option requires the presence of a default value.
-
-`sexp_drop_if` on the other hand does not require a default. Its argument
-must be a function, which will receive the current record value. If the
-result of this function is `true`, then the record field will be suppressed
-in the resulting S-expression.
-
-The above extensions can be quite creatively used together with manifest
-types, functors, and first-class modules to make the emission of record
-fields or the definition of their default values configurable at runtime.
-
-### Conversion of sum types
-
-Constant constructors in sum types are represented as strings. Constructors
-with arguments are represented as lists, the first element being the
-constructor name, the rest being its arguments. Constructors may also
-be started in lowercase in S-expressions, but will always be converted to
-uppercase when converting from OCaml-values.
-
-For example:
-
- :::ocaml
- type t = A | B of int * float * t with sexp
-
- B (42, 3.14, B (-1, 2.72, A)) <===> (B 42 3.14 (B -1 2.72 A))
-
-The above example also demonstrates recursion in data structures.
-
-### Conversion of variant types
-
-The conversion of polymorphic variants is almost the same as with sum types.
-The notable difference is that variant constructors must always start with
-an either lower- or uppercase character, matching the way it was specified
-in the type definition. This is because OCaml also distinguishes between
-upper- and lowercase variant constructors. Note that type specifications
-containing unions of variant types are also supported by the S-expression
-converter, for example as in:
-
- :::ocaml
- type ab = [ `A | `B ] with sexp
- type cd = [ `C | `D ] with sexp
- type abcd = [ ab | cd ] with sexp
-
-### Conversion of OCaml-lists and arrays
-
-OCaml-lists and arrays are straightforwardly represented as S-expression lists.
-
-### Conversion of option types
-
-The option type is converted like ordinary polymorphic sum types, i.e.:
-
- :::ocaml
- None <===> none
- Some value <===> (some value)
-
-There is a deprecated version of the syntax in which values of option type
-are represented as lists in S-expressions:
-
- :::ocaml
- None <===> ()
- Some value <===> (value)
-
-Reading of the old-style S-expression syntax for option values is
-only supported if the reference `Conv.read_old_option_format` is set
-to `true` (currently the default, which may change). A conversion
-exception is raised otherwise. The old format will be written only if
-`Conv.write_old_option_format` is true (also currently the default).
-Reading of the new format is always supported.
-
-### Conversion of polymorphic values
-
-There is nothing special about polymorphic values as long as there are
-conversion functions for the type parameters. E.g.:
-
- :::ocaml
- type 'a t = A | B of 'a with sexp
- type foo = int t with sexp
-
-In the above case the conversion functions will behave as if `foo` had been
-defined as a monomorphic version of `t` with `'a` replaced by `int` on the
-right hand side.
-
-If a data structure is indeed polymorphic and you want to convert it, you will
-have to supply the conversion functions for the type parameters at runtime.
-If you wanted to convert a value of type `'a t` as in the above example,
-you would have to write something like this:
-
- :::ocaml
- sexp_of_t sexp_of_a v
-
-where `sexp_of_a`, which may also be named differently in this particular
-case, is a function that converts values of type `'a` to an S-expression.
-Types with more than one parameter require passing conversion functions for
-those parameters in the order of their appearance on the left hand side of
-the type definition.
-
-
-### Conversion of abstract data types
-
-If you want to convert an abstract data type to an S-expression, you will
-have to roll your own conversion functions, which should produce or accept
-values of type `Sexp.t`. If you want to make use of your abstract type
-within definitions of other types, make sure that you call your conversion
-function appropriately: it should be in the same scope as the typename,
-and must be named `sexp_of_{typename}`.
-
-It is possible to make use of internal representations, too, of course.
-In that case you may need to shadow the generated `*_of_sexp` function with a
-version that calls the generated one, but performs required semantic checks
-on the resulting value to guarantee that it does not violate properties of
-the abstract data type. For example:
-
- :::ocaml
- type pos_int = int with sexp
-
- let pos_int_of_sexp sexp =
- let n = pos_int_of_sexp sexp in
- if n >= 0 then n
- else raise (Of_sexp_error (Failure "pos_int: number not positive", sexp))
-
-A nice perk of `sexplib` is that using the `Of_sexp_error`-exception
-will allow you to accurately pinpoint type errors in large S-expressions.
-The file loading functions described further below will exploit this feature.
-
-### Conversion of hash tables
-
-Hash tables, which are abstract values in OCaml, are represented as association
-lists, i.e. lists of key-value pairs, e.g.:
-
- :::scheme
- ((foo 42) (bar 3))
-
-Reading in the above S-expression as hash table mapping strings to integers
-(`(string, int) Hashtbl.t`) will map `foo` to `42` and `bar` to `3`.
-
-Note that the order of elements in the list may matter, because the
-OCaml-implementation of hash tables keeps duplicates. Bindings will be
-inserted into the hash table in the order of appearance. Therefore, the
-last binding of a key will be the "visible" one, the others are "hidden".
-See the OCaml-documentation on hash tables for details.
-
-Note, too, that polymorphic equality may not hold between conversions.
-You will have to use a function implementing logical equality for that purpose.
-
-### Conversion of opaque values
-
-Opaque values are ones for which we do not want to perform conversions.
-This may be, because we do not have S-expression converters for them, or
-because we do not want to apply them in a particular type context. e.g. to
-hide large, unimportant parts of configurations. To prevent the preprocessor
-from generating calls to converters, simply apply the qualifier `sexp_opaque`
-as if it were a type constructor, e.g.:
-
- :::ocaml
- type foo = int * stuff sexp_opaque with sexp
-
-Thus, there is no need to specify converters for type `stuff`, and if there
-are any, they will not be used in this particular context. Needless to say,
-it is not possible to convert such an S-expression back to the original value.
-Here is an example conversion:
-
- :::ocaml
- (42, some_stuff) ===> (42 <opaque>)
-
-### Conversion of exceptions
-
-S-expression converters for exceptions can be automatically registered using
-the "`with sexp`" macro, e.g.:
-
- :::ocaml
- module M = struct
- exception Foo of int with sexp
- end
-
-Such exceptions will be translated in a similar way as sum types, but their
-constructor will be prefixed with the fully qualified module path (here:
-`M.Foo`) so as to be able to discriminate between them without problems.
-
-The user can then easily convert an exception matching the above one to
-an S-expression using `sexp_of_exn`. User-defined conversion functions
-can be registered, too, by calling `add_exn_converter`. This should make
-it very convenient for users to catch arbitrary exceptions escaping their
-program and pretty-printing them, including all arguments, as S-expressions.
-The library already contains mappings for all known exceptions that can
-escape functions in the OCaml standard library.
-
-I/O and Type Conversions
-------------------------
-
-There are multiple ways of performing I/O with S-expressions. If exact
-error locations are required when type conversions fail, S-expressions need
-to be parsed with location annotations. The associated parser is slower,
-however, and needs more memory. In most cases users may therefore want to
-use functions like `load_sexp_conv` or `load_sexp_conv_exn`, which load
-S-expressions from files and convert them. They initially read the file
-without location annotations for performance reasons. Only if conversions
-fail, the file will be reparsed with location annotations. Type errors
-can then be reported accurately with file name, line number, column, and
-file position.
-
----------------------------------------------------------------------------
-
-Contact Information and Contributing
-------------------------------------
-
-In the case of bugs, feature requests, contributions and similar, please
-contact the maintainers:
-
- * Jane Street Capital, LLC <opensource at janestreet.com>
-
-Up-to-date information should be available at:
-* <https://github.com/janestreet/sexplib>
-* <https://bitbucket.org/janestreet/sexplib>
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..a1ca2a3
--- /dev/null
+++ b/README.org
@@ -0,0 +1,105 @@
+* Sexplib - S-Expressions for OCaml
+
+=sexplib= contains functionality for parsing and pretty-printing
+s-expressions. S-expressions are defined by the following type:
+
+#+begin_src ocaml
+type sexp = Atom of string | List of sexp list
+#+end_src
+
+and are rendered as parenthesized lists of strings, /e.g./ =(This (is
+an) (s expression))=.
+
+This library is often used in conjunction with =ppx_sexp_conv=, a
+syntax extension which generates code from type definitions for
+efficiently converting OCaml-values to s-expressions and vice versa.
+
+Together, these two libraries make it easy and convenient to convert
+your OCaml values to and from a human-readable serializable form,
+without the tedium of having to write your own converters.
+
+The library also offers functionality for extracting and replacing
+sub-expressions in s-expressions. Here, we'll only document =sexplib=
+proper. If you want to know more about the way in which OCaml types
+are mapped on to s-expressions, you should look at the documentation
+for =ppx_sexp_conv=.
+
+** Lexical conventions of s-expression
+
+Whitespace, which consists of space, newline, horizontal tab, and form
+feed, is ignored unless within an OCaml-string, where it is treated
+according to OCaml-conventions. The left parenthesis opens a new
+list, the right one closes it again. Lists can be empty. The double
+quote denotes the beginning and end of a string following the lexical
+conventions of OCaml (see the [[http://www.ocaml.org/pub/docs/manual-ocaml][OCaml-manual]] for details). All
+characters other than double quotes, left- and right parentheses,
+whitespace, carriage return, and comment-introducing characters or
+sequences (see next paragraph) are considered part of a contiguous
+string.
+
+** Comments
+
+There are three kinds of comments:
+
+- _line comments_ are introduced with =;=, and end at the newline.
+- _sexp comments_ are introduced with =#;=, and end at the end of the
+ following s-expression
+- _block comments_ are introduced with =#|= and end with =|#=. These
+ can be nested, and double-quotes within them must be balanced and be
+ lexically correct OCaml strings.
+
+** Grammar of s-expressions
+
+s-expressions are either strings (= atoms) or lists. The lists can
+recursively contain further s-expressions or be empty, and must be
+balanced, /i.e./ parentheses must match.
+
+** Examples
+
+#+begin_src scheme
+ this_is_an_atom_123'&^%! ; this is a comment
+ "another atom in an OCaml-string \"string in a string\" \123"
+
+ ; empty list follows below
+ ()
+
+ ; a more complex example
+ (
+ (
+ list in a list ; comment within a list
+ (list in a list in a list)
+ 42 is the answer to all questions
+ #; (this S-expression
+ (has been commented out)
+ )
+ #| Block comments #| can be "nested" |# |#
+ )
+ )
+#+end_src
+
+** I/O and Type Conversions
+
+There are multiple ways of performing I/O with s-expressions. If
+exact error locations are required when type conversions fail,
+s-expressions need to be parsed with location annotations. The
+associated parser is slower, however, and needs more memory. In most
+cases users may therefore want to use functions like =load_sexp_conv=
+or =load_sexp_conv_exn=, which load s-expressions from files and
+convert them. They initially read the file without location
+annotations for performance reasons. Only if conversions fail, the
+file will be reparsed with location annotations. Type errors can then
+be reported accurately with file name, line number, column, and file
+position.
+
+** Custom converters
+
+In addition to the converters provided automatically by
+=ppx_sexp_conv=, it's possible to write one's own sexp-converter. For
+such converters to be available by other automatically generated
+converters, it should follow the convention of being defined in the
+same scope as the type, and should be named =sexp_of_[type]= and
+=[type_of_sexp]=.
+
+You must report failures by raising the =Of_sexp_error=-exception so
+that then =sexplib='s tools for pinpointing the location of type
+errors within an s-expression file will work properly.
diff --git a/_oasis b/_oasis
index 7024a6c..683ca82 100644
--- a/_oasis
+++ b/_oasis
@@ -2,7 +2,7 @@ OASISFormat: 0.4
OCamlVersion: >= 4.02.3
FindlibVersion: >= 1.3.2
Name: sexplib
-Version: 113.24.00
+Version: 113.33.00
Synopsis: Library for serializing OCaml values to and from S-expressions
Authors: Jane Street Group, LLC <opensource at janestreet.com>
Copyrights: (C) 2005-2016 Jane Street Group LLC <opensource at janestreet.com>
diff --git a/src/macro.ml b/src/macro.ml
index 7058730..e7dcaee 100644
--- a/src/macro.ml
+++ b/src/macro.ml
@@ -59,6 +59,8 @@ module List = struct
| Some x -> Some x
| None -> find_map ~f xs
+ let exists ~f xs = List.exists f xs
+
let rec find_a_dup = function
| [] -> None
| x :: xs ->
@@ -254,10 +256,14 @@ module Loader (S : Sexp_loader) = struct
let rec load visited file =
if List.mem file visited
then raise (Include_loop_detected file);
- S.load_sexps file
- >>= fun ts ->
- file_contents := (file, ts) :: !file_contents;
- M.List.iter ts ~f:(load_includes (file :: visited) file)
+ if List.mem file (List.map ~f:fst !file_contents)
+ then M.return ()
+ else begin
+ S.load_sexps file
+ >>= fun ts ->
+ file_contents := (file, ts) :: !file_contents;
+ M.List.iter ts ~f:(load_includes (file :: visited) file)
+ end
and load_includes visited file = function
| Sexp.List [Sexp.Atom ":include"; Sexp.Atom include_file] ->
let include_file = make_absolute_path ~with_respect_to:file include_file in
@@ -365,12 +371,23 @@ module Loader (S : Sexp_loader) = struct
load_all_includes file
>>= fun file_contents ->
try M.return (expand_and_convert ~multiple (`Fast file_contents) file f)
- with Of_sexp_error _ ->
+ with Of_sexp_error _ as original_exn ->
begin
load_all_annotated_includes file_contents
>>= fun annotated_file_contents ->
- M.return (expand_and_convert
- ~multiple (`Find_error annotated_file_contents) file f);
+ let result =
+ (expand_and_convert
+ ~multiple (`Find_error annotated_file_contents) file f)
+ in
+ if List.exists result ~f:(function
+ | `Result _ -> false
+ | `Error _ -> true)
+ then
+ M.return result
+ else
+ (* Avoid returning success in the case there was an error.
+ This can be bad e.g. when reading the input from a pipe. *)
+ raise original_exn
end
let load_sexps_conv file f = load ~multiple:true file f
diff --git a/src/pre_sexp.ml b/src/pre_sexp.ml
index d8751fe..4ee6dd6 100644
--- a/src/pre_sexp.ml
+++ b/src/pre_sexp.ml
@@ -27,12 +27,54 @@ let must_escape str =
| '"' | '(' | ')' | ';' | '\\' -> true
| '|' -> ix > 0 && let next = ix - 1 in str.[next] = '#' || loop next
| '#' -> ix > 0 && let next = ix - 1 in str.[next] = '|' || loop next
- | c -> c <= ' ' || ix > 0 && loop (ix - 1)
+ | '\000' .. '\032' | '\127' .. '\255' -> true
+ | _ -> ix > 0 && loop (ix - 1)
in
loop (len - 1)
+let escaped s =
+ let open Bytes in
+ let n = ref 0 in
+ for i = 0 to length s - 1 do
+ n := !n +
+ (match unsafe_get s i with
+ | '\"' | '\\' | '\n' | '\t' | '\r' | '\b' -> 2
+ | ' ' .. '~' -> 1
+ | _ -> 4)
+ done;
+ if !n = length s then copy s else begin
+ let s' = create !n in
+ n := 0;
+ for i = 0 to length s - 1 do
+ begin match unsafe_get s i with
+ | ('\"' | '\\') as c ->
+ unsafe_set s' !n '\\'; incr n; unsafe_set s' !n c
+ | '\n' ->
+ unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'n'
+ | '\t' ->
+ unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 't'
+ | '\r' ->
+ unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'r'
+ | '\b' ->
+ unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'b'
+ | (' ' .. '~') as c -> unsafe_set s' !n c
+ | c ->
+ let a = Char.code c in
+ unsafe_set s' !n '\\';
+ incr n;
+ unsafe_set s' !n (Char.chr (48 + a / 100));
+ incr n;
+ unsafe_set s' !n (Char.chr (48 + (a / 10) mod 10));
+ incr n;
+ unsafe_set s' !n (Char.chr (48 + a mod 10));
+ end;
+ incr n
+ done;
+ s'
+ end
+
let esc_str str =
- let estr = String.escaped str in
+ let estr = escaped str in
let elen = String.length estr in
let res = String.create (elen + 2) in
String.blit estr 0 res 1 elen;
@@ -66,7 +108,7 @@ let pp_hum_maybe_esc_str ppf str =
let rec loop index =
let next_newline = index_of_newline str index in
let next_line = get_substring str index next_newline in
- pp_print_string ppf (String.escaped next_line);
+ pp_print_string ppf (escaped next_line);
match next_newline with
| None -> ()
| Some newline_index ->
diff --git a/test/test_macros.mli b/test/test_macros.mli
index 7a68989..31d3b71 100644
--- a/test/test_macros.mli
+++ b/test/test_macros.mli
@@ -1,5 +1,4 @@
open Sexplib
-open Sexplib.Conv
module type Load = sig
val load_sexp_conv_exn : string -> (Sexp.t -> 'a) -> 'a
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ocaml-maint/packages/sexplib310.git
More information about the Pkg-ocaml-maint-commits
mailing list