Go to file
2024-09-16 18:30:36 +02:00
tests Escape sequence interpreter 2024-09-14 14:53:27 +02:00
.dir-locals.el Complete rewrite 2024-09-14 10:43:36 +02:00
.envrc Register srfi-180 as a feature 2024-09-16 18:30:36 +02:00
LICENSE Complete rewrite 2024-09-14 10:43:36 +02:00
README.org Escape sequence interpreter 2024-09-14 14:53:27 +02:00
srfi-180.egg Register srfi-180 as a feature 2024-09-16 18:30:36 +02:00
srfi-180.impl.scm Escape sequence interpreter 2024-09-14 14:53:27 +02:00
srfi-180.org Register srfi-180 as a feature 2024-09-16 18:30:36 +02:00
srfi-180.release-info Register srfi-180 as a feature 2024-09-16 18:30:36 +02:00
srfi-180.scm Register srfi-180 as a feature 2024-09-16 18:30:36 +02:00

SRFI-180

Dependencies

Main dependencies:

Egg Description
srfi-34 Exception Handling
srfi-35 Exception Types
srfi-158 Generators

Test dependencies:

Egg Description
test The de-facto standard test egg

API

Exceptions

This library defines an SRFI-35 exception type &json-error that gets raised when invalid tokens are encountered. The exception type has a field json-invalid-token that contains the offending token.

  (define-condition-type &json-error &error
    json-error?
    (json-error-reason json-error-reason)
    (json-invalid-token json-invalid-token))

Parameters

This library offers the following configuration parameters:

Parameter Default Description
json-nesting-depth-limit +inf.0 the maximum nesting depth of JSON that can be read.
json-number-of-character-limit +inf.0 the maximum length of JSON input that can be read.

Predicates

For some reason, this SRFI includes a predicate to check for JSON null values:

  (define (json-null? obj) (eq? obj 'null))

Reading JSON

json-generator

(json-generator [port-or-generator]) → generator

Streaming event-based JSON reader. PORT-OR-GENERATOR default value is the value returned by current-input-port. It must be a textual input port or a generator of characters. json-generator returns a generator of Scheme objects, each of which must be one of:

  • 'array-start symbol denoting that an array should be constructed.
  • 'array-end symbol denoting that the construction of the array for which the last 'array-start was generated and not closed is finished.
  • 'object-start symbol denoting that an object should be constructed. The object's key-value pairs are emitted in sequence like those in a property list (plist) where keys are strings. That is, the generation of a key is always followed by the generation of a value. Otherwise, the JSON would be invalid and json-generator would raise an error.
  • 'object-end symbol denoting that the construction of the object for which the last 'object-start was generated and not closed is finished.
  • the symbol 'null
  • boolean
  • number
  • string

In the case where nesting of arrays or objects reaches the value returned by the parameter json-nesting-depth-limit, the generator must raise an object that satisfies the predicate json-error?.

In cases where the JSON is invalid, the generator returned by json-generator should raise an object that satisfies the predicate json-error?.

Otherwise, if PORT-OR-GENERATOR contains valid JSON text, the generator returned by json-generator must yield an end-of-file object in two situations:

  • The first time the generator returned by json-generator is called, it returns an object that is a boolean, a number, a string or the symbol 'null.
  • The first time the generator returned by json-generator is called, it returns a symbol that is not the symbol 'null. When the underlying JSON text is valid, it should be the symbol starting a structure: 'object-start or 'array-start. The end-of-file object is generated when that structure is finished.

In other words, the generator returned by json-generator will parse at most one JSON value or one top-level structure. If PORT is not finished, as in the case of JSON lines, the user should call json-generator again with the same PORT-OR-GENERATOR.

Examples
  (call-with-input-string "42 101 1337" (lambda (port) (generator->list (json-generator port))))
  (42)
  (call-with-input-string "[42] 101 1337" (lambda (port) (generator->list (json-generator port))))
  (array-start 42 array-end)

json-fold

(json-fold proc array-start array-end object-start object-end seed [port-or-generator])

Fundamental JSON iterator.

json-fold will read the JSON text from PORT-OR-GENERATOR, which has (current-input-port) as its default value. json-fold will call the procedures passed as argument:

  • (PROC obj seed) is called when a JSON value is generated or a complete JSON structure is read. PROC should return the new seed that will be used to iterate over the rest of the generator. Termination is described below.
  • (OBJECT-START seed) is called with a seed and should return a seed that will be used as the seed of the iteration over the key and values of that object.
  • (OBJECT-END seed) is called with a seed and should return a new seed that is the result of the iteration over a JSON object.

ARRAY-START and ARRAY-END take the same arguments, and have similar behavior, but are called for iterating on JSON arrays. json-fold must return the seed when:

  • PORT-OR-GENERATOR yields an object that satisfies the predicate eof-object?
  • All structures, array or object, that were started have ended. The returned object is (PROC obj SEED) where obj is the object returned by ARRAY-END or OBJECT-END

json-read

(json-read [port-or-generator]) → object

JSON reader procedure. PORT-OR-GENERATOR must be a textual input port or a generator of characters. The default value of PORT-OR-GENERATOR is the value returned by the procedure current-input-port. The returned value is a Scheme object. json-read must return only the first toplevel JSON value or structure. When there are multiple toplevel values or structures in PORT-OR-GENERATOR, the user should call json-read several times to read all of it.

The mapping between JSON types and Scheme objects is the following:

  • null → the symbol 'null
  • true#t
  • false#f
  • number → number
  • string → string
  • array → vector
  • object → association list with keys that are symbols

In the case where nesting of arrays or objects reaches the value returned by the parameter json-nesting-depth-limit, json-read must raise an object that satisfies the predicate json-error?

json-lines-read

(json-lines-read [port-or-generator]) → generator

JSON reader of jsonlines or ndjson. As its first and only argument, it takes a generator of characters or a textual input port whose default value is the value returned by current-input-port. It will return a generator of Scheme objects as specified in json-read.

json-sequence-read

(json-sequence-read [port-or-generator]) → generator

JSON reader of JSON Text Sequences (RFC 7464). As its first and only argument, it takes a generator of characters or a textual input port whose default value is the value returned by current-input-port. It will return a generator of Scheme objects as specified in json-read.

json-accumulator

(json-accumulator port-or-accumulator) → procedure

Streaming event-based JSON writer. PORT-OR-ACCUMULATOR must be a textual output port or an accumulator that accepts characters and strings. It returns an accumulator procedure that accepts Scheme objects as its first and only argument and that follows the same protocol as described in json-generator. Any deviation from the protocol must raise an error that satisfies json-error?. In particular, objects and arrays must be properly nested.

Mind the fact that most JSON parsers have a nesting limit that is not documented by the standard. Even if you can produce arbitrarily nested JSON with this library, you might not be able to read it with another library.

json-write

(json-write obj [port-or-accumulator]) → unspecified

JSON writer procedure. PORT-OR-ACCUMULATOR must be a textual output port, or an accumulator that accepts characters and strings. The default value of PORT-OR-ACCUMULATOR is the value returned by the procedure current-output-port. The value returned by json-write is unspecified.

json-write will validate that OBJ can be serialized into JSON before writing to PORT. An error that satisfies json-error? is raised in the case where OBJ is not an object or a composition of the following types:

  • symbol 'null
  • boolean
  • number. Must be integers or inexact rationals. (That is, they must not be complex, infinite, NaN, or exact rationals that are not integers.)
  • string
  • vector
  • association list with keys as symbols

About this egg

Source

The source is available at https://gitea.lyrion.ch/Chicken/srfi-180.

Author

Daniel Ziltener

Version History

1.5.1 Escape sequences
1.5.0 Reimplementation
1.0.0 Reference Implementation

License

  Copyright (C) 2022 Daniel Ziltener

  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      ,* Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      ,* Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      ,* Neither the name of the <organization> nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.