Copyright (C) 2016, 2017, 2018, 2019, 2020, 2021  Stefan Vargyas

This file is part of Json-Type.

Json-Type is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Json-Type is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Json-Type.  If not, see <http://www.gnu.org/licenses/>.

--------------------------------------------------------------------------------

Type Definitions Specification
==============================

A type definition is comprised of a text subsuming to the JSON specification
[1, 2], adding to it one extra clause: the arguments of JSON objects within
a type definition are required to form an *ordered* collection of name/value
pairs (as opposed to the specification [1], where the collection of name/value
pairs composing an object is *unordered*).

There are precisely three categories of type definitions:

  (F1) the JSON string values:

         `"type"', `"null"', `"boolean"', `"number"', `"string"', `"object"',
         and `"array"';

  (F2) the JSON object values of form:

         `{ "plain": $value }',

       where $value is allowed to be only `null' or of JSON type boolean, number
       or string;

  (F3) the JSON object values of form:

       (a) `{ "type": "object", "args": [ $arg* ] }',

       (b) `{ "type": "dict", "args": [ $arg* ] }', or

           `{ "type": "dict", "args": [ $arg* ], "expr": "$expr" }'

            where $arg is of form:

           `{ "name": $string, "type": $type }',

            and $expr obeys the following rules:

                (i) syntactical rules:

                      expr : bits ( "||" bits )*
                           ;
                      bits : term ( "|" term )*
                           ;
                      term : prim ( [ "&" ] prim )*
                           ;
                      prim : "~" prim
                           | "(" bits ")"
                           | KEY
                           | NUM
                           ;

               (ii) lexical rules: 

                      KEY  : "`" ( [^`] | "``" )+ "`"
                           | [a-zA-Z_][0-9a-zA-Z_]*
                           ;
                      NUM  : [01]
                           ;

            KEY must also obey the lexical rules of making valid JSON strings;

       (c) `{ "type": "array", "args": $type }',

       (d) `{ "type": "array", "args": [ $type* ] }', or

       (e) `{ "type": "list", "args": [ $type* ] }',

       where $string is any string and $type is any type.

Each of the string values listed by point (F1) is exempted from being a type when
occurring as value associated to the key `"plain"' of objects of form (F2), to
the key `"name"' of objects of form (F3.a) or (F3.b) or to the key `"expr"' of
objects of form (F3.b). In such cases, the string values are to be interpreted
as proper values.

The meaning of each of the constructs above is defined as follows:

  (M1) The types of form (F1) have the meaning defined by the following table:

         type         matching value
         ----         --------------
         `"type"'     any JSON value
         `"null"'     the JSON `null' value
         `"boolean"'  the JSON `false' and `true' values
         `"number"'   any JSON number value
         `"string"'   any JSON string value
         `"object"'   any JSON object value
         `"array"'    any JSON array value

  (M2) A JSON value matches a given type of form (F2) if and only if its JSON
       type is the same as the JSON type of the value specified by the type and
       if the given JSON value is equal with the value specified by the type.

  (M3) (a) A JSON value matches a given type of form (F3.a) if and only if:

         * it is an JSON object, and
         * has the number of arguments as specified by the type, and
         * in the order specified by the type, each argument name is equal with
           the corresponding name specified by the type, and
         * in the order specified by the type, each argument value matches the
           corresponding argument type specified by the type.

       (b) A JSON value matches a given type of form (F3.b) if and only if:

         * it is an JSON object, and
         * irrespective of the order in which the arguments are specified in
           the type, each object argument name corresponds to one specified by
           the type, and appears at most once amongst the object arguments, and
         * each object argument value matches the corresponding argument type
           specified by the type.

         When the given type specifies an expression `"$expr"', the keys of the
         matched JSON value shall also satisfy the constraints defined by $expr
         in the following sense:

         The rules (F3.b.i) and (F3.b.ii) are defining a set of bit sets, or
         equally, a set of subsets of keys specified by the type:

         (1) each of the expressions of form $bits, $term, $prim, $KEY and
             $NUM defines a bit set of cardinality $N -- where $N is the
             the number of keys specified by the type -- as follows:

              [NUM] when $NUM is 0, the bit set has all its bits equal to 0,
                    when $NUM is 1, the bit set has all its bits equal to 1;

              [KEY] the bit set has all the bits reset, except for the $k-th
                    one, where $k is the index of key $KEY in the ordered set
                    of keys of the array `[ $arg* ]' of the defining type;

             [prim] when $prim is of form `~$prim_0', then the resulting bit
                    set has all the bits of $prim_0 bit set reversed; for each
                    of the other three forms of $prim, the resulting bit set
                    is identical with the originating one;

             [term] when $term is of form `$prim_0 ... [&] $prim_n', for
                    some n >= 0, the resulting bit set is obtained by the
                    bitwise AND of all the bit sets corresponding to $prim_k,
                    for all k such that 0 <= k <= n; in particular, when n is
                    0, the resulting bit set is simply the one corresponding
                    to $prim_0;
                 
             [bits] when $bits is of form `$term_0 ... | $term_n', for
                    some n >= 0, the resulting bit set is obtained by the
                    bitwise OR of all the bit sets corresponding to $term_k,
                    for all k such that 0 <= k <= n; in particular, when n is
                    0, the resulting bit set is simply the one corresponding
                    to $term_0;

         (2) each $expr expression of form `$bits_0 ... || $bits_n' defines
             a set of cardinality n + 1 of bit sets, with the k-th bit set
             corresponding to $bits_k, for each k such that 0 <= k <= n;

         The constraints imposed by an expression $expr are satisfied by the set
         of keys $keys of the matching JSON value if and only if there is at
         least one bit set $bitset in the set of bit sets attached to $expr,
         such that $keys is including the *subset* $bitset of the set of keys
         $KEYS specified by the type. (The key set $bitset is the subset of
         $KEYS for which the bit set $bitset is its characteristic function.)

       (c) A JSON value matches a given type of form (F3.c) if and only if:

         * it is an JSON array with zero or more number of arguments, and
         * each argument value matches the type specified.

       (d) A JSON value matches a given type of form (F3.d) if and only if:

         * it is an JSON array, and
         * has the number of arguments specified by the type, and
         * in the order specified by the type, each argument value matches the
           corresponding argument type specified by the type.

       (e) A JSON value matches a given type of form (F3.e) if and only if it
           matches one of the argument types specified by the type.


References
----------

[1] The JavaScript Object Notation (JSON) Data Interchange Format
    https://tools.ietf.org/html/rfc7159

[2] Standard ECMA-404: The JSON Data Interchange Format
    http://www.ecma-international.org/publications/standards/Ecma-404.htm
    http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf


