diff --git a/.gitmodules b/.gitmodules
index 19d4dc1e..e6bec3c7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "contrib/library/text/parser/json"]
- path = contrib/library/text/parser/json
- url = https://github.com/Eiffel-World/json.git
[submodule "contrib/ise_library/cURL"]
path = contrib/ise_library/cURL
url = https://github.com/EiffelSoftware/mirror-Eiffel-cURL.git
diff --git a/contrib/library/text/parser/json b/contrib/library/text/parser/json
deleted file mode 160000
index c873d62e..00000000
--- a/contrib/library/text/parser/json
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c873d62efa58ab1da3223cebd8e4f4670b24cd72
diff --git a/contrib/library/text/parser/json/History.txt b/contrib/library/text/parser/json/History.txt
new file mode 100644
index 00000000..10ff48c6
--- /dev/null
+++ b/contrib/library/text/parser/json/History.txt
@@ -0,0 +1,26 @@
+History file for EJSON
+======================
+
+team: ""
+date: "2011-07-06"
+revision: "0.3.0"
+
+
++++++++++++++++++++++Important Changes since 0.2.0 version++++++++++++++++++++++++++++++++++++++++++++++
+
+*Updated skip_white_spaces, now check %U and %T codes
+
+*Undo changes to is_a_valid_number, because it's doesn't follow the
+JSON spec. Tests : fail13.json, fail29.json and fail30.json are valid
+with this implementation, so we go back to the previous
+implementation.
+
+*Added autotest test suite
+
+*Added getest based test program
+
+*Updated Eiffel configuration file, updated to the new clusters
+
+*Added converters and factory classes
+
+*Added new top level directories; library, test, build and example
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/License.txt b/contrib/library/text/parser/json/License.txt
new file mode 100644
index 00000000..24c06993
--- /dev/null
+++ b/contrib/library/text/parser/json/License.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/Readme.txt b/contrib/library/text/parser/json/Readme.txt
new file mode 100644
index 00000000..bd8ce28d
--- /dev/null
+++ b/contrib/library/text/parser/json/Readme.txt
@@ -0,0 +1,97 @@
+Readme file for eJSON
+=====================
+
+team: "Javier Velilla,Jocelyn Fiat, Paul Cohen"
+date: "$Date$"
+revision: "$Revision$"
+
+1. Introduction
+---------------
+
+eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing
+with the JSON format. The objective of the library is to provide two basic
+features Eiffel2JSON and JSON2Eiffel.
+
+2. Legal stuff
+--------------
+
+eJSON is copyrighted by the author Javier Velilla and others. It is licensed
+under the MIT License. See the file license.txt in the same directory as this
+readme file.
+
+3. Versioning scheme
+--------------------
+
+eJSON version numbers has the form:
+
+ «major number».«minor number».«patch level»
+
+eJSON will retain the major number 0 as long as it has beta status. A change in
+major number indicates that a release is not backward compatible. A change in
+minor number indicates that a release is backward compatible (within that major
+number) but that new useful features may have been added. A change in patch
+level simply indicates that the release contains bug fixes for the previous
+release. Note that as long as eJSON is in beta status (0.Y.Z) backward
+compatibility is not guranteed for changes in minor numbers!
+
+4. Documentation
+---------------
+
+Currently the only documentation on eJSON is available at:
+
+ http://ejson.origo.ethz.ch/wiki/user_guide
+
+5. Requirements and installation
+--------------------------------
+
+EJSON requires that you have:
+
+1. Gobo 3.9 installed or later
+2. One of the following compiler combinations installed:
+ * ISE Eiffel 6.5 or later.
+ * gec [try to test]
+ * tecomp [try to test]
+
+eJSON probably works fine with other versions of the above compilers.
+There are no known platform dependencies (Windows, Linux).
+
+To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate
+place on your hard disk. There are no requirements on environment variables or
+registry variables.
+
+To verify that everything works you should compile the example programs and/or
+the test program.
+
+6. Contents of eJSON
+--------------------
+
+All directory names below are relative to the root directory of your ejson
+installation.
+
+Directory Description
+--------- -----------
+doc Contains the eJSON.pdf documentation file.
+examples Contains the two example programs.
+ejson Contains the actual eJSON library classes.
+test Contains a test program for eJSON.
+
+7. Contacting the Team
+----------------------
+
+Contact the team:
+
+ Javier Velilla «javier.hector@gmail.com»
+ Paul Cohen «paco@seibostudios.se»
+ Jocelyn Fiat «jfiat@eiffel.com»
+
+8. Releases
+-----------
+
+For more information on what was changed in each release look in the file
+history.txt.
+
+Version Date Description
+------- ---- -----------
+0.3.0 2011-07-06 JSON Factory Converters
+0.2.0 2010-02-07 Adapted to EiffelStudio 6.4 or later, supports void-safety
+0.1.0 2010-02-07 First release, Adapted to SmartEiffel 1.2r7 and EiffelStudio 6.2 or previous
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/library/extras/file/json_file_reader.e b/contrib/library/text/parser/json/library/extras/file/json_file_reader.e
new file mode 100644
index 00000000..3629c475
--- /dev/null
+++ b/contrib/library/text/parser/json/library/extras/file/json_file_reader.e
@@ -0,0 +1,38 @@
+note
+ description: "Objects that ..."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ JSON_FILE_READER
+
+feature -- Access
+
+ read_json_from (a_path: STRING): detachable STRING
+ local
+ l_file: PLAIN_TEXT_FILE
+ template_content: STRING
+ l_last_string: detachable STRING
+ do
+ create l_file.make (a_path)
+ -- We perform several checks until we make a real attempt to open the file.
+ if not l_file.exists then
+ print ("error: '" + a_path + "' does not exist%N")
+ else
+ if not l_file.is_readable then
+ print ("error: '" + a_path + "' is not readable.%N")
+ else
+ l_file.open_read
+ create template_content.make_empty
+ l_file.read_stream (l_file.count)
+ l_last_string := l_file.last_string
+ check l_last_string /= Void end -- implied by postcondition of `l_file.read_stream'
+ template_content.append (l_last_string.string)
+ Result := template_content
+ l_file.close
+ end
+ end
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/extras/visitor/json_visitor.e b/contrib/library/text/parser/json/library/extras/visitor/json_visitor.e
new file mode 100644
index 00000000..bf2f583e
--- /dev/null
+++ b/contrib/library/text/parser/json/library/extras/visitor/json_visitor.e
@@ -0,0 +1,59 @@
+note
+ description:
+
+ "JSON Visitor"
+
+ pattern: "Visitor"
+ author: "Javier Velilla"
+ license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+
+deferred class
+ JSON_VISITOR
+
+feature -- Visitor Pattern
+
+ visit_json_array (a_json_array: JSON_ARRAY)
+ -- Visit `a_json_array'.
+ require
+ a_json_array_not_void: a_json_array /= Void
+ deferred
+ end
+
+ visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
+ -- Visit `a_json_boolean'.
+ require
+ a_json_boolean_not_void: a_json_boolean /= Void
+ deferred
+ end
+
+ visit_json_null (a_json_null: JSON_NULL)
+ -- Visit `a_json_null'.
+ require
+ a_json_null_not_void: a_json_null /= Void
+ deferred
+ end
+
+ visit_json_number (a_json_number: JSON_NUMBER)
+ -- Visit `a_json_number'.
+ require
+ a_json_number_not_void: a_json_number /= Void
+ deferred
+ end
+
+ visit_json_object (a_json_object: JSON_OBJECT)
+ -- Visit `a_json_object'.
+ require
+ a_json_object_not_void: a_json_object /= Void
+ deferred
+ end
+
+ visit_json_string (a_json_string: JSON_STRING)
+ -- Visit `a_json_string'.
+ require
+ a_json_string_not_void: a_json_string /= Void
+ deferred
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/extras/visitor/print_json_visitor.e b/contrib/library/text/parser/json/library/extras/visitor/print_json_visitor.e
new file mode 100644
index 00000000..6fa64558
--- /dev/null
+++ b/contrib/library/text/parser/json/library/extras/visitor/print_json_visitor.e
@@ -0,0 +1,102 @@
+note
+ description: "PRINT_JSON_VISITOR Generates the JSON-String for a JSON_VALUE"
+ author: "jvelilla"
+ date: "2008/08/24"
+ revision: "0.1"
+
+class
+ PRINT_JSON_VISITOR
+
+inherit
+ JSON_VISITOR
+
+create make
+
+feature -- Initialization
+
+ make
+ -- Create a new instance
+ do
+ create to_json.make_empty
+ end
+
+feature -- Access
+
+ to_json: STRING
+ -- JSON representation
+
+feature -- Visitor Pattern
+
+ visit_json_array (a_json_array: JSON_ARRAY)
+ -- Visit `a_json_array'.
+ local
+ value: JSON_VALUE
+ l_json_array: ARRAYED_LIST [JSON_VALUE]
+ do
+ l_json_array:=a_json_array.array_representation
+ to_json.append ("[")
+ from
+ l_json_array.start
+ until
+ l_json_array.off
+ loop
+ value := l_json_array.item
+ value.accept (Current)
+ l_json_array.forth
+ if not l_json_array.after then
+ to_json.append(",")
+ end
+ end
+ to_json.append ("]")
+ end
+
+ visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
+ -- Visit `a_json_boolean'.
+ do
+ to_json.append (a_json_boolean.item.out)
+ end
+
+ visit_json_null (a_json_null: JSON_NULL)
+ -- Visit `a_json_null'.
+ do
+ to_json.append ("null")
+ end
+
+ visit_json_number (a_json_number: JSON_NUMBER)
+ -- Visit `a_json_number'.
+ do
+ to_json.append (a_json_number.item)
+ end
+
+ visit_json_object (a_json_object: JSON_OBJECT)
+ -- Visit `a_json_object'.
+ local
+ l_pairs: HASH_TABLE[JSON_VALUE,JSON_STRING]
+ do
+ l_pairs := a_json_object.map_representation
+ to_json.append ("{")
+ from
+ l_pairs.start
+ until
+ l_pairs.off
+ loop
+ l_pairs.key_for_iteration.accept (Current)
+ to_json.append (":")
+ l_pairs.item_for_iteration.accept (Current)
+ l_pairs.forth
+ if not l_pairs.after then
+ to_json.append (",")
+ end
+ end
+ to_json.append ("}")
+ end
+
+ visit_json_string (a_json_string: JSON_STRING)
+ -- Visit `a_json_string'.
+ do
+ to_json.append ("%"")
+ to_json.append (a_json_string.item)
+ to_json.append ("%"")
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/gobo/converters/json_ds_hash_table_converter.e b/contrib/library/text/parser/json/library/gobo/converters/json_ds_hash_table_converter.e
new file mode 100644
index 00000000..e2532c57
--- /dev/null
+++ b/contrib/library/text/parser/json/library/gobo/converters/json_ds_hash_table_converter.e
@@ -0,0 +1,81 @@
+note
+ description: "A JSON converter for DS_HASH_TABLE [ANY, HASHABLE]"
+ author: "Paul Cohen"
+ date: "$Date: $"
+ revision: "$Revision: $"
+ file: "$HeadURL: $"
+
+class JSON_DS_HASH_TABLE_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create object.make (0)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: DS_HASH_TABLE [ANY, HASHABLE]
+
+feature -- Conversion
+
+ from_json (j: like value): detachable like object
+ local
+ keys: ARRAY [JSON_STRING]
+ i: INTEGER
+ h: HASHABLE
+ a: ANY
+ do
+ keys := j.current_keys
+ create Result.make (keys.count)
+ from
+ i := 1
+ until
+ i > keys.count
+ loop
+ h ?= json.object (keys [i], void)
+ check h /= Void end
+ a := json.object (j.item (keys [i]), Void)
+ Result.put (a, h)
+ i := i + 1
+ end
+ end
+
+ to_json (o: like object): like value
+ local
+ c: DS_HASH_TABLE_CURSOR [ANY, HASHABLE]
+ js: JSON_STRING
+ jv: JSON_VALUE
+ failed: BOOLEAN
+ do
+ create Result.make
+ from
+ c := o.new_cursor
+ c.start
+ until
+ c.after
+ loop
+ create js.make_json (c.key.out)
+ jv := json.value (c.item)
+ if jv /= Void then
+ Result.put (jv, js)
+ else
+ failed := True
+ end
+ c.forth
+ end
+ if failed then
+ Result := Void
+ end
+ end
+
+end -- class JSON_DS_HASH_TABLE_CONVERTER
diff --git a/contrib/library/text/parser/json/library/gobo/converters/json_ds_linked_list_converter.e b/contrib/library/text/parser/json/library/gobo/converters/json_ds_linked_list_converter.e
new file mode 100644
index 00000000..bf1aa516
--- /dev/null
+++ b/contrib/library/text/parser/json/library/gobo/converters/json_ds_linked_list_converter.e
@@ -0,0 +1,62 @@
+note
+ description: "A JSON converter for DS_LINKED_LIST [ANY]"
+ author: "Paul Cohen"
+ date: "$Date: $"
+ revision: "$Revision: $"
+ file: "$HeadURL: $"
+
+class JSON_DS_LINKED_LIST_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create object.make
+ end
+
+feature -- Access
+
+ value: JSON_ARRAY
+
+ object: DS_LINKED_LIST [ANY]
+
+feature -- Conversion
+
+ from_json (j: like value): detachable like object
+ local
+ i: INTEGER
+ do
+ create Result.make
+ from
+ i := 1
+ until
+ i > j.count
+ loop
+ Result.put_last (json.object (j [i], Void))
+ i := i + 1
+ end
+ end
+
+ to_json (o: like object): like value
+ local
+ c: DS_LIST_CURSOR [ANY]
+ do
+ create Result.make_array
+ from
+ c := o.new_cursor
+ c.start
+ until
+ c.after
+ loop
+ Result.add (json.value (c.item))
+ c.forth
+ end
+ end
+
+end -- class JSON_DS_LINKED_LIST_CONVERTER
diff --git a/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e b/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e
new file mode 100644
index 00000000..ccc33432
--- /dev/null
+++ b/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e
@@ -0,0 +1,32 @@
+note
+ description: "[
+ Shared factory class for creating JSON objects. Maps JSON
+ objects to Gobo DS_HASH_TABLEs and JSON arrays to Gobo
+ DS_LINKED_LISTs. Use non-conforming inheritance from this
+ class to ensure that your classes share the same
+ JSON_FACTORY instance.
+ ]"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: $"
+
+class SHARED_GOBO_EJSON
+
+feature
+
+ json: EJSON
+ -- A shared EJSON instance with default converters for
+ -- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE]
+ local
+ jllc: JSON_DS_LINKED_LIST_CONVERTER
+ jhtc: JSON_DS_HASH_TABLE_CONVERTER
+ once
+ create Result
+ create jllc.make
+ Result.add_converter (jllc)
+ create jhtc.make
+ Result.add_converter (jhtc)
+ end
+
+end -- class SHARED_GOBO_EJSON
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/library/json-safe.ecf b/contrib/library/text/parser/json/library/json-safe.ecf
new file mode 100644
index 00000000..b957513f
--- /dev/null
+++ b/contrib/library/text/parser/json/library/json-safe.ecf
@@ -0,0 +1,28 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+ ^/gobo$
+ ^/kernel$
+ ^/extras$
+
+
+
+
+
+
diff --git a/contrib/library/text/parser/json/library/json.ecf b/contrib/library/text/parser/json/library/json.ecf
new file mode 100644
index 00000000..ee954e09
--- /dev/null
+++ b/contrib/library/text/parser/json/library/json.ecf
@@ -0,0 +1,28 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+ ^/gobo$
+ ^/kernel$
+ ^/extras$
+
+
+
+
+
+
diff --git a/contrib/library/text/parser/json/library/json.rc b/contrib/library/text/parser/json/library/json.rc
new file mode 100644
index 00000000..d3f5a12f
--- /dev/null
+++ b/contrib/library/text/parser/json/library/json.rc
@@ -0,0 +1 @@
+
diff --git a/contrib/library/text/parser/json/library/json_gobo_extension.ecf b/contrib/library/text/parser/json/library/json_gobo_extension.ecf
new file mode 100644
index 00000000..dd5f9b75
--- /dev/null
+++ b/contrib/library/text/parser/json/library/json_gobo_extension.ecf
@@ -0,0 +1,17 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+
+
+
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_converter.e
new file mode 100644
index 00000000..bae2bd9c
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_converter.e
@@ -0,0 +1,36 @@
+note
+ description: "A JSON converter"
+ author: "Paul Cohen"
+ date: "$Date: $"
+ revision: "$Revision: $"
+ file: "$HeadURL: $"
+
+deferred class JSON_CONVERTER
+
+inherit
+ SHARED_EJSON
+
+feature -- Access
+
+ object: ANY
+ -- Eiffel object
+ deferred
+ end
+
+feature -- Conversion
+
+ from_json (j: attached like to_json): detachable like object
+ -- Convert from JSON value.
+ -- Returns Void if unable to convert
+ deferred
+ end
+
+ to_json (o: like object): detachable JSON_VALUE
+ -- Convert to JSON value
+ deferred
+ end
+
+invariant
+ has_eiffel_object: object /= Void -- An empty object must be created at creation time!
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e
new file mode 100644
index 00000000..8ce5260e
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e
@@ -0,0 +1,88 @@
+note
+ description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: $"
+
+class JSON_HASH_TABLE_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create object.make (0)
+ end
+
+feature -- Access
+
+ object: HASH_TABLE [ANY, HASHABLE]
+
+feature -- Conversion
+
+ from_json (j: attached like to_json): like object
+ local
+ keys: ARRAY [JSON_STRING]
+ i: INTEGER
+ h: detachable HASHABLE
+ jv: detachable JSON_VALUE
+ a: detachable ANY
+ do
+ keys := j.current_keys
+ create Result.make (keys.count)
+ from
+ i := 1
+ until
+ i > keys.count
+ loop
+ h ?= json.object (keys [i], void)
+ check h /= Void end
+ jv := j.item (keys [i])
+ if jv /= Void then
+ a := json.object (jv, Void)
+ if a /= Void then
+ Result.put (a, h)
+ else
+ check a_attached: a /= Void end
+ end
+ else
+ check j_has_item: False end
+ end
+ i := i + 1
+ end
+ end
+
+ to_json (o: like object): detachable JSON_OBJECT
+ local
+ c: HASH_TABLE_ITERATION_CURSOR [ANY, HASHABLE]
+ js: JSON_STRING
+ jv: detachable JSON_VALUE
+ failed: BOOLEAN
+ do
+ create Result.make
+ from
+ c := o.new_cursor
+ until
+ c.after
+ loop
+ create js.make_json (c.key.out)
+ jv := json.value (c.item)
+ if jv /= Void then
+ Result.put (jv, js)
+ else
+ failed := True
+ end
+ c.forth
+ end
+ if failed then
+ Result := Void
+ end
+ end
+
+end -- class JSON_HASH_TABLE_CONVERTER
diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e
new file mode 100644
index 00000000..bcc41e49
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e
@@ -0,0 +1,63 @@
+note
+ description: "A JSON converter for LINKED_LIST [ANY]"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: $"
+
+class JSON_LINKED_LIST_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create object.make
+ end
+
+feature -- Access
+
+ object: LINKED_LIST [detachable ANY]
+
+feature -- Conversion
+
+ from_json (j: like to_json): detachable like object
+ local
+ i: INTEGER
+ do
+ create Result.make
+ from
+ i := 1
+ until
+ i > j.count
+ loop
+ Result.extend (json.object (j [i], Void))
+ i := i + 1
+ end
+ end
+
+ to_json (o: like object): JSON_ARRAY
+ local
+ c: ITERATION_CURSOR [detachable ANY]
+ do
+ create Result.make_array
+ from
+ c := o.new_cursor
+ until
+ c.after
+ loop
+ if attached json.value (c.item) as v then
+ Result.add (v)
+ else
+ check attached_value: False end
+ end
+ c.forth
+ end
+ end
+
+end -- class JSON_LINKED_LIST_CONVERTER
diff --git a/contrib/library/text/parser/json/library/kernel/ejson.e b/contrib/library/text/parser/json/library/kernel/ejson.e
new file mode 100644
index 00000000..de9058d5
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/ejson.e
@@ -0,0 +1,268 @@
+note
+ description: "Core factory class for creating JSON objects and corresponding Eiffel objects."
+ author: "Paul Cohen"
+ date: "$Date: $"
+ revision: "$Revision: $"
+ file: "$HeadURL: $"
+
+class EJSON
+
+inherit
+ EXCEPTIONS
+
+feature -- Access
+
+ value (an_object: detachable ANY): detachable JSON_VALUE
+ -- JSON value from Eiffel object. Raises an "eJSON exception" if
+ -- unable to convert value.
+ local
+ i: INTEGER
+ ja: JSON_ARRAY
+ do
+ -- Try to convert from basic Eiffel types. Note that we check with
+ -- `conforms_to' since the client may have subclassed the base class
+ -- that these basic types are derived from.
+ if an_object = Void then
+ create {JSON_NULL} Result
+ elseif attached {BOOLEAN} an_object as b then
+ create {JSON_BOOLEAN} Result.make_boolean (b)
+ elseif attached {INTEGER_8} an_object as i8 then
+ create {JSON_NUMBER} Result.make_integer (i8)
+ elseif attached {INTEGER_16} an_object as i16 then
+ create {JSON_NUMBER} Result.make_integer (i16)
+ elseif attached {INTEGER_32} an_object as i32 then
+ create {JSON_NUMBER} Result.make_integer (i32)
+ elseif attached {INTEGER_64} an_object as i64 then
+ create {JSON_NUMBER} Result.make_integer (i64)
+ elseif attached {NATURAL_8} an_object as n8 then
+ create {JSON_NUMBER} Result.make_natural (n8)
+ elseif attached {NATURAL_16} an_object as n16 then
+ create {JSON_NUMBER} Result.make_natural (n16)
+ elseif attached {NATURAL_32} an_object as n32 then
+ create {JSON_NUMBER} Result.make_natural (n32)
+ elseif attached {NATURAL_64} an_object as n64 then
+ create {JSON_NUMBER} Result.make_natural (n64)
+ elseif attached {REAL_32} an_object as r32 then
+ create {JSON_NUMBER} Result.make_real (r32)
+ elseif attached {REAL_64} an_object as r64 then
+ create {JSON_NUMBER} Result.make_real (r64)
+ elseif attached {ARRAY [detachable ANY]} an_object as a then
+ create ja.make_array
+ from
+ i := a.lower
+ until
+ i > a.upper
+ loop
+ if attached value (a @ i) as v then
+ ja.add (v)
+ else
+ check value_attached: False end
+ end
+ i := i + 1
+ end
+ Result := ja
+ elseif attached {CHARACTER_8} an_object as c8 then
+ create {JSON_STRING} Result.make_json (c8.out)
+ elseif attached {CHARACTER_32} an_object as c32 then
+ create {JSON_STRING} Result.make_json (c32.out)
+
+ elseif attached {STRING_8} an_object as s8 then
+ create {JSON_STRING} Result.make_json (s8)
+ elseif attached {STRING_32} an_object as s32 then
+ create {JSON_STRING} Result.make_json (s32.as_string_8) -- FIXME: need correct convertion/encoding here ...
+ end
+
+ if Result = Void then
+ -- Now check the converters
+ if an_object /= Void and then attached converter_for (an_object) as jc then
+ Result := jc.to_json (an_object)
+ else
+ raise (exception_failed_to_convert_to_json (an_object))
+ end
+ end
+ end
+
+ object (a_value: detachable JSON_VALUE; base_class: detachable STRING): detachable ANY
+ -- Eiffel object from JSON value. If `base_class' /= Void an eiffel
+ -- object based on `base_class' will be returned. Raises an "eJSON
+ -- exception" if unable to convert value.
+ local
+ i: INTEGER
+ ll: LINKED_LIST [detachable ANY]
+ t: HASH_TABLE [detachable ANY, STRING_GENERAL]
+ keys: ARRAY [JSON_STRING]
+ do
+ if a_value = Void then
+ Result := Void
+ else
+ if base_class = Void then
+ if a_value = Void then
+ Result := Void
+ elseif attached {JSON_NULL} a_value then
+ Result := Void
+ elseif attached {JSON_BOOLEAN} a_value as jb then
+ Result := jb.item
+ elseif attached {JSON_NUMBER} a_value as jn then
+ if jn.item.is_integer_8 then
+ Result := jn.item.to_integer_8
+ elseif jn.item.is_integer_16 then
+ Result := jn.item.to_integer_16
+ elseif jn.item.is_integer_32 then
+ Result := jn.item.to_integer_32
+ elseif jn.item.is_integer_64 then
+ Result := jn.item.to_integer_64
+ elseif jn.item.is_natural_64 then
+ Result := jn.item.to_natural_64
+ elseif jn.item.is_double then
+ Result := jn.item.to_double
+ end
+ elseif attached {JSON_STRING} a_value as js then
+ create {STRING_32} Result.make_from_string (js.unescaped_string_32)
+ elseif attached {JSON_ARRAY} a_value as ja then
+ from
+ create ll.make
+ i := 1
+ until
+ i > ja.count
+ loop
+ ll.extend (object (ja [i], Void))
+ i := i + 1
+ end
+ Result := ll
+ elseif attached {JSON_OBJECT} a_value as jo then
+ keys := jo.current_keys
+ create t.make (keys.count)
+ from
+ i := keys.lower
+ until
+ i > keys.upper
+ loop
+ if attached {STRING_GENERAL} object (keys [i], Void) as s then
+ t.put (object (jo.item (keys [i]), Void), s)
+ end
+ i := i + 1
+ end
+ Result := t
+ end
+ else
+ if converters.has_key (base_class) and then attached converters.found_item as jc then
+ Result := jc.from_json (a_value)
+ else
+ raise (exception_failed_to_convert_to_eiffel (a_value, base_class))
+ end
+ end
+ end
+ end
+
+ object_from_json (json: STRING; base_class: detachable STRING): detachable ANY
+ -- Eiffel object from JSON representation. If `base_class' /= Void an
+ -- Eiffel object based on `base_class' will be returned. Raises an
+ -- "eJSON exception" if unable to convert value.
+ require
+ json_not_void: json /= Void
+ local
+ jv: detachable JSON_VALUE
+ do
+ json_parser.set_representation (json)
+ jv := json_parser.parse
+ if jv /= Void then
+ Result := object (jv, base_class)
+ end
+ end
+
+ converter_for (an_object: ANY): detachable JSON_CONVERTER
+ -- Converter for objects. Returns Void if none found.
+ require
+ an_object_not_void: an_object /= Void
+ do
+ if converters.has_key (an_object.generator) then
+ Result := converters.found_item
+ end
+ end
+
+ json_reference (s: STRING): JSON_OBJECT
+ -- A JSON (Dojo style) reference object using `s' as the
+ -- reference value. The caller is responsable for ensuring
+ -- the validity of `s' as a json reference.
+ require
+ s_not_void: s /= Void
+ local
+ js_key, js_value: JSON_STRING
+ do
+ create Result.make
+ create js_key.make_json ("$ref")
+ create js_value.make_json (s)
+ Result.put (js_value, js_key)
+ end
+
+ json_references (l: LIST [STRING]): JSON_ARRAY
+ -- A JSON array of JSON (Dojo style) reference objects using the
+ -- strings in `l' as reference values. The caller is responsable
+ -- for ensuring the validity of all strings in `l' as json
+ -- references.
+ require
+ l_not_void: l /= Void
+ local
+ c: ITERATION_CURSOR [STRING]
+ do
+ create Result.make_array
+ from
+ c := l.new_cursor
+ until
+ c.after
+ loop
+ Result.add (json_reference (c.item))
+ c.forth
+ end
+ end
+
+feature -- Change
+
+ add_converter (jc: JSON_CONVERTER)
+ -- Add the converter `jc'.
+ require
+ jc_not_void: jc /= Void
+ do
+ converters.force (jc, jc.object.generator)
+ ensure
+ has_converter: converter_for (jc.object) /= Void
+ end
+
+feature {NONE} -- Implementation
+
+ converters: HASH_TABLE [JSON_CONVERTER, STRING]
+ -- Converters hashed by generator (base class)
+ once
+ create Result.make (10)
+ end
+
+feature {NONE} -- Implementation (Exceptions)
+
+ exception_prefix: STRING = "eJSON exception: "
+
+ exception_failed_to_convert_to_eiffel (a_value: JSON_VALUE; base_class: detachable STRING): STRING
+ -- Exception message for failing to convert a JSON_VALUE to an instance of `a'.
+ do
+ Result := exception_prefix + "Failed to convert JSON_VALUE to an Eiffel object: " + a_value.generator
+ if base_class /= Void then
+ Result.append (" -> " + base_class)
+ end
+ end
+
+ exception_failed_to_convert_to_json (an_object: detachable ANY): STRING
+ -- Exception message for failing to convert `a' to a JSON_VALUE.
+ do
+ Result := exception_prefix + "Failed to convert Eiffel object to a JSON_VALUE"
+ if an_object /= Void then
+ Result := ": " + an_object.generator
+ end
+ end
+
+feature {NONE} -- Implementation (JSON parser)
+
+ json_parser: JSON_PARSER
+ once
+ create Result.make_parser ("")
+ end
+
+end -- class EJSON
diff --git a/contrib/library/text/parser/json/library/kernel/json_array.e b/contrib/library/text/parser/json/library/kernel/json_array.e
new file mode 100644
index 00000000..dc51e1cb
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_array.e
@@ -0,0 +1,141 @@
+note
+ description: "[
+ JSON_ARRAY represent an array in JSON.
+ An array in JSON is an ordered set of names.
+ Examples
+ array
+ []
+ [elements]
+ ]"
+
+ author: "Javier Velilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+
+class
+ JSON_ARRAY
+
+inherit
+ JSON_VALUE
+
+ DEBUG_OUTPUT
+
+create
+ make_array
+
+feature {NONE} -- Initialization
+
+ make_array
+ -- Initialize JSON Array
+ do
+ create values.make (10)
+ end
+
+feature -- Access
+
+ i_th alias "[]" (i: INTEGER): JSON_VALUE
+ -- Item at `i'-th position
+ require
+ is_valid_index: valid_index (i)
+ do
+ Result := values.i_th (i)
+ end
+
+ representation: STRING
+ local
+ i: INTEGER
+ do
+ Result := "["
+ from
+ i := 1
+ until
+ i > count
+ loop
+ Result.append (i_th (i).representation)
+ i := i + 1
+ if i <= count then
+ Result.append_character (',')
+ end
+ end
+ Result.append_character (']')
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_json_array' procedure on `a_visitor'.)
+ do
+ a_visitor.visit_json_array (Current)
+ end
+
+feature -- Mesurement
+
+ count: INTEGER
+ -- Number of items.
+ do
+ Result := values.count
+ end
+
+feature -- Status report
+
+ valid_index (i: INTEGER): BOOLEAN
+ -- Is `i' a valid index?
+ do
+ Result := (1 <= i) and (i <= count)
+ end
+
+feature -- Change Element
+
+ add (value: JSON_VALUE)
+ require
+ value_not_null: value /= void
+ do
+ values.extend (value)
+ ensure
+ has_new_value: old values.count + 1 = values.count and
+ values.has (value)
+ end
+
+feature -- Report
+
+ hash_code: INTEGER
+ -- Hash code value
+ do
+ from
+ values.start
+ Result := values.item.hash_code
+ until
+ values.off
+ loop
+ Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code
+ values.forth
+ end
+ Result := Result \\ values.count
+ end
+
+feature -- Conversion
+
+ array_representation: ARRAYED_LIST [JSON_VALUE]
+ -- Representation as a sequences of values
+ do
+ Result := values
+ end
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ Result := count.out
+ end
+
+feature {NONE} -- Implementation
+
+ values: ARRAYED_LIST [JSON_VALUE]
+ -- Value container
+
+invariant
+ value_not_void: values /= Void
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/json_boolean.e b/contrib/library/text/parser/json/library/kernel/json_boolean.e
new file mode 100644
index 00000000..32e7634a
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_boolean.e
@@ -0,0 +1,61 @@
+note
+ description: "JSON Truth values"
+ author: "Javier Velilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+
+class
+ JSON_BOOLEAN
+
+inherit
+ JSON_VALUE
+
+create
+ make_boolean
+
+feature {NONE} -- Initialization
+
+ make_boolean (an_item: BOOLEAN)
+ --Initialize.
+ do
+ item := an_item
+ end
+
+feature -- Access
+
+ item: BOOLEAN
+ -- Content
+
+ hash_code: INTEGER
+ -- Hash code value
+ do
+ Result := item.hash_code
+ end
+
+ representation: STRING
+ do
+ if item then
+ Result := "true"
+ else
+ Result := "false"
+ end
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_json_boolean' procedure on `a_visitor'.)
+ do
+ a_visitor.visit_json_boolean (Current)
+ end
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ Result := item.out
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/json_null.e b/contrib/library/text/parser/json/library/kernel/json_null.e
new file mode 100644
index 00000000..176b7d38
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_null.e
@@ -0,0 +1,47 @@
+note
+ description: "JSON Null Values"
+ author: "Javier Velilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+
+class
+ JSON_NULL
+
+inherit
+ JSON_VALUE
+
+feature --Access
+
+ hash_code: INTEGER
+ -- Hash code value
+ do
+ Result := null_value.hash_code
+ end
+
+ representation: STRING
+ do
+ Result := "null"
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_element_a' procedure on `a_visitor'.)
+ do
+ a_visitor.visit_json_null (Current)
+ end
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ Result := null_value
+ end
+
+feature {NONE}-- Implementation
+
+ null_value: STRING = "null"
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/json_number.e b/contrib/library/text/parser/json/library/kernel/json_number.e
new file mode 100644
index 00000000..69b5011e
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_number.e
@@ -0,0 +1,99 @@
+note
+
+ description: "JSON Numbers, octal and hexadecimal formats are not used."
+ author: "Javier Velilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+ license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
+
+class
+ JSON_NUMBER
+
+inherit
+ JSON_VALUE
+ redefine
+ is_equal
+ end
+
+create
+ make_integer,
+ make_natural,
+ make_real
+
+feature {NONE} -- initialization
+
+ make_integer (an_argument: INTEGER_64)
+ -- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'.
+ do
+ item := an_argument.out
+ numeric_type := INTEGER_TYPE
+ end
+
+ make_natural (an_argument: NATURAL_64)
+ -- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'.
+ do
+ item := an_argument.out
+ numeric_type := NATURAL_TYPE
+ end
+
+ make_real (an_argument: DOUBLE)
+ -- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'.
+ do
+ item := an_argument.out
+ numeric_type := DOUBLE_TYPE
+ end
+
+feature -- Access
+
+ item: STRING
+ -- Content
+
+ hash_code: INTEGER
+ --Hash code value
+ do
+ Result := item.hash_code
+ end
+
+ representation: STRING
+ do
+ Result := item
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_json_number' procedure on `a_visitor'.)
+ do
+ a_visitor.visit_json_number (Current)
+ end
+
+feature -- Status
+
+ is_equal (other: like Current): BOOLEAN
+ -- Is `other' attached to an object of the same type
+ -- as current object and identical to it?
+ do
+ Result := item.is_equal (other.item)
+ end
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ Result := item
+ end
+
+feature -- Implementation
+
+ INTEGER_TYPE: INTEGER = 1
+ DOUBLE_TYPE: INTEGER = 2
+ NATURAL_TYPE: INTEGER = 3
+
+ numeric_type: INTEGER
+
+invariant
+ item_not_void: item /= Void
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/json_object.e b/contrib/library/text/parser/json/library/kernel/json_object.e
new file mode 100644
index 00000000..ba0ad5b5
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_object.e
@@ -0,0 +1,160 @@
+note
+
+ description: "[
+ An JSON_OBJECT represent an object in JSON.
+ An object is an unordered set of name/value pairs
+
+ Examples:
+
+ object
+ {}
+ {"key","value"}
+
+ ]"
+ author: "Javier Velilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+ license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
+
+class
+ JSON_OBJECT
+
+inherit
+ JSON_VALUE
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ -- Initialize
+ do
+ create object.make (10)
+ end
+
+feature -- Change Element
+
+ put (value: detachable JSON_VALUE; key: JSON_STRING)
+ -- Assuming there is no item of key `key',
+ -- insert `value' with `key'.
+ require
+ key_not_present: not has_key (key)
+ local
+ l_value: detachable JSON_VALUE
+ do
+ l_value := value
+ if l_value = Void then
+ create {JSON_NULL} l_value
+ end
+ object.extend (l_value, key)
+ end
+
+feature -- Access
+
+ has_key (key: JSON_STRING): BOOLEAN
+ -- has the JSON_OBJECT contains a specific key 'key'.
+ do
+ Result := object.has (key)
+ end
+
+ has_item (value: JSON_VALUE): BOOLEAN
+ -- has the JSON_OBJECT contain a specfic item 'value'
+ do
+ Result := object.has_item (value)
+ end
+
+ item (key: JSON_STRING): detachable JSON_VALUE
+ -- the json_value associated with a key.
+ do
+ Result := object.item (key)
+ end
+
+ current_keys: ARRAY [JSON_STRING]
+ -- array containing actually used keys
+ do
+ Result := object.current_keys
+ end
+
+ representation: STRING
+ local
+ t: HASH_TABLE [JSON_VALUE, JSON_STRING]
+ do
+ Result := "{"
+ from
+ t := map_representation
+ t.start
+ until
+ t.after
+ loop
+ Result.append (t.key_for_iteration.representation)
+ Result.append (":")
+ Result.append (t.item_for_iteration.representation)
+ t.forth
+ if not t.after then
+ Result.append_character (',')
+ end
+ end
+ Result.append_character ('}')
+ end
+
+feature -- Status report
+
+ is_empty: BOOLEAN
+ -- Is empty object?
+ do
+ Result := object.is_empty
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_json_object' procedure on `a_visitor'.)
+ do
+ a_visitor.visit_json_object (Current)
+ end
+
+feature -- Conversion
+
+ map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING]
+ --A representation that maps keys to values
+ do
+ Result := object
+ end
+
+feature -- Report
+
+ hash_code: INTEGER
+ -- Hash code value
+ do
+ from
+ object.start
+ Result := object.item_for_iteration.hash_code
+ until
+ object.off
+ loop
+ Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code
+ object.forth
+ end
+ -- Ensure it is a positive value.
+ Result := Result.hash_code
+ end
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ Result := object.count.out
+ end
+
+feature {NONE} -- Implementation
+
+ object: HASH_TABLE [JSON_VALUE, JSON_STRING]
+ -- Value container
+
+invariant
+ object_not_null: object /= Void
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/json_string.e b/contrib/library/text/parser/json/library/kernel/json_string.e
new file mode 100644
index 00000000..ccd8e60d
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_string.e
@@ -0,0 +1,329 @@
+note
+
+ description: "[
+ A JSON_STRING represent a string in JSON.
+ A string is a collection of zero or more Unicodes characters, wrapped in double
+ quotes, using blackslash espaces.
+ ]"
+
+ author: "Javier Velilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+ license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
+
+
+class
+ JSON_STRING
+
+inherit
+ JSON_VALUE
+ redefine
+ is_equal
+ end
+
+create
+ make_json,
+ make_json_from_string_32,
+ make_with_escaped_json
+
+convert
+ make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
+ make_json_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32})
+
+feature {NONE} -- Initialization
+
+ make_json (s: READABLE_STRING_8)
+ -- Initialize.
+ require
+ item_not_void: s /= Void
+ do
+ make_with_escaped_json (escaped_json_string (s))
+ end
+
+ make_json_from_string_32 (s: READABLE_STRING_32)
+ -- Initialize from STRING_32 `s'.
+ require
+ item_not_void: s /= Void
+ do
+ make_with_escaped_json (escaped_json_string_32 (s))
+ end
+
+ make_with_escaped_json (s: READABLE_STRING_8)
+ -- Initialize with an_item already escaped
+ require
+ item_not_void: s /= Void
+ do
+ item := s
+ end
+
+feature -- Access
+
+ item: STRING
+ -- Contents with escaped entities if any
+
+ unescaped_string_8: STRING_8
+ -- Unescaped string from `item'
+ local
+ s: like item
+ i, n: INTEGER
+ c: CHARACTER
+ do
+ s := item
+ n := s.count
+ create Result.make (n)
+ from i := 1 until i > n loop
+ c := s[i]
+ if c = '\' then
+ if i < n then
+ inspect s[i+1]
+ when '\' then
+ Result.append_character ('\')
+ i := i + 2
+ when '%"' then
+ Result.append_character ('%"')
+ i := i + 2
+ when 'n' then
+ Result.append_character ('%N')
+ i := i + 2
+ when 'r' then
+ Result.append_character ('%R')
+ i := i + 2
+ when 'u' then
+ --| Leave unicode \uXXXX unescaped
+ Result.append_character ('\')
+ i := i + 1
+ else
+ Result.append_character ('\')
+ i := i + 1
+ end
+ else
+ Result.append_character ('\')
+ i := i + 1
+ end
+ else
+ Result.append_character (c)
+ i := i + 1
+ end
+ end
+ end
+
+ unescaped_string_32: STRING_32
+ -- Unescaped string 32 from `item'
+ local
+ s: like item
+ i, n: INTEGER
+ c: CHARACTER
+ hex: STRING
+ do
+ s := item
+ n := s.count
+ create Result.make (n)
+ from i := 1 until i > n loop
+ c := s[i]
+ if c = '\' then
+ if i < n then
+ inspect s[i+1]
+ when '\' then
+ Result.append_character ('\')
+ i := i + 2
+ when '%"' then
+ Result.append_character ('%"')
+ i := i + 2
+ when 'n' then
+ Result.append_character ('%N')
+ i := i + 2
+ when 'r' then
+ Result.append_character ('%R')
+ i := i + 2
+ when 'u' then
+ hex := s.substring (i+2, i+2+4 - 1)
+ if hex.count = 4 then
+ Result.append_code (hexadecimal_to_natural_32 (hex))
+ end
+ i := i + 2 + 4
+ else
+ Result.append_character ('\')
+ i := i + 1
+ end
+ else
+ Result.append_character ('\')
+ i := i + 1
+ end
+ else
+ Result.append_character (c.to_character_32)
+ i := i + 1
+ end
+ end
+ end
+
+ representation: STRING
+ -- String representation of `item' with escaped entities if any
+ do
+ create Result.make (item.count + 2)
+ Result.append_character ('%"')
+ Result.append (item)
+ Result.append_character ('%"')
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_json_string' procedure on `a_visitor'.)
+ do
+ a_visitor.visit_json_string (Current)
+ end
+
+feature -- Comparison
+
+ is_equal (other: like Current): BOOLEAN
+ -- Is JSON_STRING made of same character sequence as `other'
+ -- (possibly with a different capacity)?
+ do
+ Result := item.same_string (other.item)
+ end
+
+feature -- Change Element
+
+ append (a_string: STRING)
+ -- Add a_string
+ require
+ a_string_not_void: a_string /= Void
+ do
+ item.append_string (a_string)
+ end
+
+feature -- Status report
+
+ hash_code: INTEGER
+ -- Hash code value
+ do
+ Result := item.hash_code
+ end
+
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ Result := item
+ end
+
+feature {NONE} -- Implementation
+
+ is_hexadecimal (s: READABLE_STRING_8): BOOLEAN
+ -- Is `s' an hexadecimal value?
+ do
+ Result := across s as scur all scur.item.is_hexa_digit end
+ end
+
+ hexadecimal_to_natural_32 (s: READABLE_STRING_8): NATURAL_32
+ -- Hexadecimal string `s' converted to NATURAL_32 value
+ require
+ s_not_void: s /= Void
+ is_hexadecimal: is_hexadecimal (s)
+ local
+ i, nb: INTEGER
+ char: CHARACTER
+ do
+ nb := s.count
+
+ if nb >= 2 and then s.item (2) = 'x' then
+ i := 3
+ else
+ i := 1
+ end
+
+ from
+ until
+ i > nb
+ loop
+ Result := Result * 16
+ char := s.item (i)
+ if char >= '0' and then char <= '9' then
+ Result := Result + (char |-| '0').to_natural_32
+ else
+ Result := Result + (char.lower |-| 'a' + 10).to_natural_32
+ end
+ i := i + 1
+ end
+ end
+
+ escaped_json_string (s: READABLE_STRING_8): STRING_8
+ -- JSON string with '"' and '\' characters escaped
+ require
+ s_not_void: s /= Void
+ local
+ i, n: INTEGER
+ c: CHARACTER_8
+ do
+ n := s.count
+ create Result.make (n + n // 10)
+ from i := 1 until i > n loop
+ c := s.item (i)
+ inspect c
+ when '%"' then Result.append_string ("\%"")
+ when '\' then Result.append_string ("\\")
+ when '%R' then Result.append_string ("\r")
+ when '%N' then Result.append_string ("\n")
+ else
+ Result.extend (c)
+ end
+ i := i + 1
+ end
+ end
+
+ escaped_json_string_32 (s: READABLE_STRING_32): STRING_8
+ -- JSON string with '"' and '\' characters and unicode escaped
+ require
+ s_not_void: s /= Void
+ local
+ i, j, n: INTEGER
+ uc: CHARACTER_32
+ c: CHARACTER_8
+ h: STRING_8
+ do
+ n := s.count
+ create Result.make (n + n // 10)
+ from i := 1 until i > n loop
+ uc := s.item (i)
+ if uc.is_character_8 then
+ c := uc.to_character_8
+ inspect c
+ when '%"' then Result.append_string ("\%"")
+ when '\' then Result.append_string ("\\")
+ when '%R' then Result.append_string ("\r")
+ when '%N' then Result.append_string ("\n")
+ else
+ Result.extend (c)
+ end
+ else
+ Result.append ("\u")
+ h := uc.code.to_hex_string
+ -- Remove first 0 and keep 4 hexa digit
+ from
+ j := 1
+ until
+ h.count = 4 or (j <= h.count and then h.item (j) /= '0')
+ loop
+ j := j + 1
+ end
+ h := h.substring (j, h.count)
+
+ from
+ until
+ h.count >= 4
+ loop
+ h.prepend_integer (0)
+ end
+ check h.count = 4 end
+ Result.append (h)
+ end
+ i := i + 1
+ end
+ end
+
+invariant
+ item_not_void: item /= Void
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/json_value.e b/contrib/library/text/parser/json/library/kernel/json_value.e
new file mode 100644
index 00000000..bbf47c7c
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/json_value.e
@@ -0,0 +1,43 @@
+note
+ description:"[
+ JSON_VALUE represent a value in JSON.
+ A value can be
+ * a string in double quotes
+ * a number
+ * boolean value(true, false )
+ * null
+ * an object
+ * an array
+ ]"
+ author: "Javier Velilla"
+ date: "2008/05/19"
+ revision: "Revision 0.1"
+ license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
+
+
+deferred class
+ JSON_VALUE
+
+inherit
+ HASHABLE
+
+ DEBUG_OUTPUT
+
+feature -- Access
+
+ representation: STRING
+ -- UTF-8 encoded Unicode string representation of Current
+ deferred
+ end
+
+feature -- Visitor pattern
+
+ accept (a_visitor: JSON_VISITOR)
+ -- Accept `a_visitor'.
+ -- (Call `visit_*' procedure on `a_visitor'.)
+ require
+ a_visitor_not_void: a_visitor /= Void
+ deferred
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/scanner/json_parser.e b/contrib/library/text/parser/json/library/kernel/scanner/json_parser.e
new file mode 100644
index 00000000..3eaa7388
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/scanner/json_parser.e
@@ -0,0 +1,513 @@
+note
+
+ description: "Parse serialized JSON data"
+ author: "jvelilla"
+ date: "2008/08/24"
+ revision: "Revision 0.1"
+
+class
+ JSON_PARSER
+
+inherit
+ JSON_READER
+ JSON_TOKENS
+
+create
+ make_parser
+
+feature {NONE} -- Initialize
+
+ make_parser (a_json: STRING)
+ -- Initialize.
+ require
+ json_not_empty: a_json /= Void and then not a_json.is_empty
+ do
+ make (a_json)
+ is_parsed := True
+ create errors.make
+ end
+
+feature -- Status report
+
+ is_parsed: BOOLEAN
+ -- Is parsed?
+
+ errors: LINKED_LIST [STRING]
+ -- Current errors
+
+ current_errors: STRING
+ -- Current errors as string
+ do
+ create Result.make_empty
+ from
+ errors.start
+ until
+ errors.after
+ loop
+ Result.append_string (errors.item + "%N")
+ errors.forth
+ end
+ end
+
+feature -- Element change
+
+ report_error (e: STRING)
+ -- Report error `e'
+ require
+ e_not_void: e /= Void
+ do
+ errors.force (e)
+ end
+
+feature -- Commands
+
+ parse_json: detachable JSON_VALUE
+ -- Parse JSON data `representation'
+ -- start ::= object | array
+ do
+ if is_valid_start_symbol then
+ Result := parse
+ if extra_elements then
+ is_parsed := False
+ end
+ else
+ is_parsed := False
+ report_error ("Syntax error unexpected token, expecting `{' or `['")
+ end
+ end
+
+ parse: detachable JSON_VALUE
+ -- Parse JSON data `representation'
+ local
+ c: CHARACTER
+ do
+ if is_parsed then
+ skip_white_spaces
+ c := actual
+ inspect c
+ when j_OBJECT_OPEN then
+ Result := parse_object
+ when j_STRING then
+ Result := parse_string
+ when j_ARRAY_OPEN then
+ Result := parse_array
+ else
+ if c.is_digit or c = j_MINUS then
+ Result := parse_number
+ elseif is_null then
+ Result := create {JSON_NULL}
+ next
+ next
+ next
+ elseif is_true then
+ Result := create {JSON_BOOLEAN}.make_boolean (True)
+ next
+ next
+ next
+ elseif is_false then
+ Result := create {JSON_BOOLEAN}.make_boolean (False)
+ next
+ next
+ next
+ next
+ else
+ is_parsed := False
+ report_error ("JSON is not well formed in parse")
+ Result := Void
+ end
+ end
+ end
+ ensure
+ is_parsed_implies_result_not_void: is_parsed implies Result /= Void
+ end
+
+ parse_object: JSON_OBJECT
+ -- object
+ -- {}
+ -- {"key" : "value" [,]}
+ local
+ has_more: BOOLEAN
+ l_json_string: detachable JSON_STRING
+ l_value: detachable JSON_VALUE
+ do
+ create Result.make
+ -- check if is an empty object {}
+ next
+ skip_white_spaces
+ if actual = j_OBJECT_CLOSE then
+ --is an empty object
+ else
+ -- a complex object {"key" : "value"}
+ previous
+ from has_more := True until not has_more loop
+ next
+ skip_white_spaces
+ l_json_string := parse_string
+ next
+ skip_white_spaces
+ if actual = ':' then
+ next
+ skip_white_spaces
+ else
+ is_parsed := False
+ report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
+ has_more := False
+ end
+
+ l_value := parse
+ if is_parsed and then (l_value /= Void and l_json_string /= Void) then
+ Result.put (l_value, l_json_string)
+ next
+ skip_white_spaces
+ if actual = j_OBJECT_CLOSE then
+ has_more := False
+ elseif actual /= ',' then
+ has_more := False
+ is_parsed := False
+ report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
+ end
+ else
+ has_more := False
+ -- explain the error
+ end
+ end
+ end
+ end
+
+ parse_string: detachable JSON_STRING
+ -- Parsed string
+ local
+ has_more: BOOLEAN
+ l_json_string: STRING
+ l_unicode: STRING
+ c: like actual
+ do
+ create l_json_string.make_empty
+ if actual = j_STRING then
+ from
+ has_more := True
+ until
+ not has_more
+ loop
+ next
+ c := actual
+ if c = j_STRING then
+ has_more := False
+ elseif c = '%H' then
+ next
+ c := actual
+ if c = 'u' then
+ create l_unicode.make_from_string ("\u")
+ l_unicode.append (read_unicode)
+ c := actual
+ if is_valid_unicode (l_unicode) then
+ l_json_string.append (l_unicode)
+ else
+ has_more := False
+ is_parsed := False
+ report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
+ end
+ elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
+ has_more := False
+ is_parsed := False
+ report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
+ else
+ l_json_string.append_character ('\')
+ l_json_string.append_character (c)
+ end
+ else
+ if is_special_character (c) and c /= '/' then
+ has_more := False
+ is_parsed := False
+ report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
+ else
+ l_json_string.append_character (c)
+ end
+ end
+ end
+ create Result.make_with_escaped_json (l_json_string)
+ else
+ Result := Void
+ end
+ end
+
+ parse_array: JSON_ARRAY
+ -- array
+ -- []
+ -- [elements [,]]
+ local
+ flag: BOOLEAN
+ l_value: detachable JSON_VALUE
+ c: like actual
+ do
+ create Result.make_array
+ --check if is an empty array []
+ next
+ skip_white_spaces
+ if actual = j_array_close then
+ --is an empty array
+ else
+ previous
+ from
+ flag := True
+ until
+ not flag
+ loop
+ next
+ skip_white_spaces
+ l_value := parse
+ if is_parsed and then l_value /= Void then
+ Result.add (l_value)
+ next
+ skip_white_spaces
+ c := actual
+ if c = j_ARRAY_CLOSE then
+ flag := False
+ elseif c /= ',' then
+ flag := False
+ is_parsed := False
+ report_error ("Array is not well formed JSON, found [" + c.out + " ]")
+ end
+ else
+ flag := False
+ report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
+ end
+ end
+ end
+ end
+
+ parse_number: detachable JSON_NUMBER
+ -- Parsed number
+ local
+ sb: STRING
+ flag: BOOLEAN
+ is_integer: BOOLEAN
+ c: like actual
+ do
+ create sb.make_empty
+ sb.append_character (actual)
+
+ from
+ flag := True
+ until
+ not flag
+ loop
+ next
+ c := actual
+ if not has_next or is_close_token (c)
+ or c = ',' or c = '%N' or c = '%R'
+ then
+ flag := False
+ previous
+ else
+ sb.append_character (c)
+ end
+ end
+
+ if is_valid_number (sb) then
+ if sb.is_integer then
+ create Result.make_integer (sb.to_integer)
+ is_integer := True
+ elseif sb.is_double and not is_integer then
+ create Result.make_real (sb.to_double)
+ end
+ else
+ is_parsed := False
+ report_error ("Expected a number, found: [ " + sb + " ]")
+ end
+ end
+
+ is_null: BOOLEAN
+ -- Word at index represents null?
+ local
+ l_null: STRING
+ l_string: STRING
+ do
+ l_null := null_id
+ l_string := json_substring (index,index + l_null.count - 1)
+ if l_string.is_equal (l_null) then
+ Result := True
+ end
+ end
+
+ is_false: BOOLEAN
+ -- Word at index represents false?
+ local
+ l_false: STRING
+ l_string: STRING
+ do
+ l_false := false_id
+ l_string := json_substring (index, index + l_false.count - 1)
+ if l_string.is_equal (l_false) then
+ Result := True
+ end
+ end
+
+ is_true: BOOLEAN
+ -- Word at index represents true?
+ local
+ l_true: STRING
+ l_string: STRING
+ do
+ l_true := true_id
+ l_string := json_substring (index,index + l_true.count - 1)
+ if l_string.is_equal (l_true) then
+ Result := True
+ end
+ end
+
+ read_unicode: STRING
+ -- Read unicode and return value
+ local
+ i: INTEGER
+ do
+ create Result.make_empty
+ from
+ i := 1
+ until
+ i > 4 or not has_next
+ loop
+ next
+ Result.append_character (actual)
+ i := i + 1
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ is_valid_number (a_number: STRING): BOOLEAN
+ -- is 'a_number' a valid number based on this regular expression
+ -- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
+ local
+ s: detachable STRING
+ c: CHARACTER
+ i,n: INTEGER
+ do
+ create s.make_empty
+ n := a_number.count
+ if n = 0 then
+ Result := False
+ else
+ Result := True
+ i := 1
+ --| "-?"
+ c := a_number[i]
+ if c = '-' then
+ s.extend (c); i := i + 1; c := a_number[i]
+ end
+ --| "0|[1-9]\d*
+ if c.is_digit then
+ if c = '0' then
+ --| "0"
+ s.extend (c); i := i + 1; c := a_number[i]
+ else
+ --| "[1-9]"
+ s.extend (c); i := i + 1; c := a_number[i]
+ --| "\d*"
+ from until i > n or not c.is_digit loop
+ s.extend (c); i := i + 1; c := a_number[i]
+ end
+ end
+ end
+ end
+ if Result then
+ --| "(\.\d+)?"
+ if c = '.' then
+ --| "\.\d+" = "\.\d\d*"
+ s.extend (c); i := i + 1; c := a_number[i]
+ if c.is_digit then
+ from until i > n or not c.is_digit loop
+ s.extend (c); i := i + 1; c := a_number[i]
+ end
+ else
+ Result := False --| expecting digit
+ end
+ end
+ end
+ if Result then --| "(?:[eE][+-]?\d+)?\b"
+ if c = 'e' or c = 'E' then
+ --| "[eE][+-]?\d+"
+ s.extend (c); i := i + 1; c := a_number[i]
+ if c = '+' or c = '-' then
+ s.extend (c); i := i + 1; c := a_number[i]
+ end
+ if c.is_digit then
+ from until i > n or not c.is_digit loop
+ s.extend (c); i := i + 1; c := a_number[i]
+ end
+ else
+ Result := False --| expecting digit
+ end
+ end
+ end
+ if Result then --| "\b"
+ from until i > n or not c.is_space loop
+ s.extend (c); i := i + 1; c := a_number[i]
+ end
+ Result := i > n and then s.same_string (a_number)
+ end
+ end
+
+ is_valid_unicode (a_unicode: STRING): BOOLEAN
+ -- is 'a_unicode' a valid unicode based on this regular expression
+ -- "\\u[0-9a-fA-F]{4}"
+ local
+ i: INTEGER
+ do
+ if
+ a_unicode.count = 6 and then
+ a_unicode[1] = '\' and then
+ a_unicode[2] = 'u'
+ then
+ from
+ Result := True
+ i := 3
+ until
+ i > 6 or Result = False
+ loop
+ inspect a_unicode[i]
+ when '0'..'9', 'a'..'f', 'A'..'F' then
+ else
+ Result := False
+ end
+ i := i + 1
+ end
+ end
+ end
+
+ extra_elements: BOOLEAN
+ -- has more elements?
+ local
+ c: like actual
+ do
+ if has_next then
+ next
+ end
+ from
+ c := actual
+ until
+ c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
+ loop
+ next
+ end
+ Result := has_next
+ end
+
+ is_valid_start_symbol : BOOLEAN
+ -- expecting `{' or `[' as start symbol
+ do
+ if attached representation as s and then s.count > 0 then
+ Result := s[1] = '{' or s[1] = '['
+ end
+ end
+
+feature {NONE} -- Constants
+
+ false_id: STRING = "false"
+
+ true_id: STRING = "true"
+
+ null_id: STRING = "null"
+
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/scanner/json_reader.e b/contrib/library/text/parser/json/library/kernel/scanner/json_reader.e
new file mode 100644
index 00000000..112857bd
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/scanner/json_reader.e
@@ -0,0 +1,118 @@
+note
+ description: "Objects that ..."
+ author: "jvelilla"
+ date: "2008/08/24"
+ revision: "0.1"
+
+class
+ JSON_READER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_json: STRING)
+ -- Initialize Reader
+ do
+ set_representation (a_json)
+ end
+
+feature -- Commands
+
+ set_representation (a_json: STRING)
+ -- Set `representation'.
+ do
+ a_json.left_adjust
+ a_json.right_adjust
+ representation := a_json
+ index := 1
+ end
+
+ read: CHARACTER
+ -- Read character
+ do
+ if not representation.is_empty then
+ Result := representation.item (index)
+ end
+ end
+
+ next
+ -- Move to next index
+ require
+ has_more_elements: has_next
+ do
+ index := index + 1
+ ensure
+ incremented: old index + 1 = index
+ end
+
+ previous
+ -- Move to previous index
+ require
+ not_is_first: has_previous
+ do
+ index := index - 1
+ ensure
+ incremented: old index - 1 = index
+ end
+
+ skip_white_spaces
+ -- Remove white spaces
+ local
+ c: like actual
+ do
+ from
+ c := actual
+ until
+ (c /= ' ' and c /= '%N' and c /= '%R' and c /= '%U' and c /= '%T' ) or not has_next
+ loop
+ next
+ c := actual
+ end
+ end
+
+ json_substring (start_index, end_index: INTEGER_32): STRING
+ -- JSON representation between `start_index' and `end_index'
+ do
+ Result := representation.substring (start_index, end_index)
+ end
+
+feature -- Status report
+
+ has_next: BOOLEAN
+ -- Has a next character?
+ do
+ Result := index <= representation.count
+ end
+
+ has_previous: BOOLEAN
+ -- Has a previous character?
+ do
+ Result := index >= 1
+ end
+
+feature -- Access
+
+ representation: STRING
+ -- Serialized representation of the original JSON string
+
+feature {NONE} -- Implementation
+
+ actual: CHARACTER
+ -- Current character or '%U' if none
+ do
+ if index > representation.count then
+ Result := '%U'
+ else
+ Result := representation.item (index)
+ end
+ end
+
+ index: INTEGER
+ -- Actual index
+
+invariant
+ representation_not_void: representation /= Void
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/scanner/json_tokens.e b/contrib/library/text/parser/json/library/kernel/scanner/json_tokens.e
new file mode 100644
index 00000000..db8dd9df
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/scanner/json_tokens.e
@@ -0,0 +1,77 @@
+note
+ description: ""
+ author: "jvelilla"
+ date: "2008/08/24"
+ revision: "0.1"
+
+class
+ JSON_TOKENS
+
+feature -- Access
+
+ j_OBJECT_OPEN: CHARACTER = '{'
+ j_ARRAY_OPEN: CHARACTER = '['
+ j_OBJECT_CLOSE: CHARACTER = '}'
+ j_ARRAY_CLOSE: CHARACTER = ']'
+
+ j_STRING: CHARACTER = '"'
+ j_PLUS: CHARACTER = '+'
+ j_MINUS: CHARACTER = '-'
+ j_DOT: CHARACTER = '.'
+
+feature -- Status report
+
+ is_open_token (c: CHARACTER): BOOLEAN
+ -- Characters which open a type
+ do
+ inspect c
+ when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then
+ Result := True
+ else
+
+ end
+ end
+
+ is_close_token (c: CHARACTER): BOOLEAN
+ -- Characters which close a type
+ do
+ inspect c
+ when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then
+ Result := True
+ else
+
+ end
+ end
+
+ is_special_character (c: CHARACTER): BOOLEAN
+ -- Control Characters
+ -- %F Form feed
+ -- %H backslasH
+ -- %N Newline
+ -- %R carriage Return
+ -- %T horizontal Tab
+ -- %B Backspace
+ -- / Solidus
+ -- " Quotation
+ do
+ inspect c
+ when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then
+ Result := True
+ else
+
+ end
+ end
+
+ is_special_control (c: CHARACTER): BOOLEAN
+ --Control Characters
+ -- \b\f\n\r\t
+ do
+ inspect c
+ when 'b', 'f', 'n', 'r', 't' then
+ Result := True
+ else
+
+ end
+ end
+
+end
diff --git a/contrib/library/text/parser/json/library/kernel/shared_ejson.e b/contrib/library/text/parser/json/library/kernel/shared_ejson.e
new file mode 100644
index 00000000..d08a6766
--- /dev/null
+++ b/contrib/library/text/parser/json/library/kernel/shared_ejson.e
@@ -0,0 +1,32 @@
+note
+ description: "[
+ Shared factory class for creating JSON objects. Maps JSON
+ objects to ELKS HASH_TABLEs and JSON arrays to ELKS
+ LINKED_LISTs. Use non-conforming inheritance from this
+ class to ensure that your classes share the same
+ JSON_FACTORY instance.
+ ]"
+ author: "Paul Cohen"
+ date: "$Date: $"
+ revision: "$Revision: $"
+ file: "$HeadURL: $"
+
+class SHARED_EJSON
+
+feature
+
+ json: EJSON
+ -- A shared EJSON instance with default converters for
+ -- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE]
+ local
+ jllc: JSON_LINKED_LIST_CONVERTER
+ jhtc: JSON_HASH_TABLE_CONVERTER
+ once
+ create Result
+ create jllc.make
+ Result.add_converter (jllc)
+ create jhtc.make
+ Result.add_converter (jhtc)
+ end
+
+end -- class SHARED_EJSON
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/application.e b/contrib/library/text/parser/json/test/autotest/test_suite/application.e
new file mode 100644
index 00000000..77d42fe7
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/application.e
@@ -0,0 +1,24 @@
+note
+ description : "test_suite application root class"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ APPLICATION
+
+inherit
+ ARGUMENTS
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ -- Run application.
+ do
+ --| Add your code here
+ print ("Hello Eiffel World!%N")
+ end
+
+end
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/author.e b/contrib/library/text/parser/json/test/autotest/test_suite/author.e
new file mode 100644
index 00000000..9df55bf7
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/author.e
@@ -0,0 +1,24 @@
+class AUTHOR
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: STRING_32)
+ do
+ set_name (a_name)
+ end
+
+feature -- Access
+
+ name: STRING_32
+
+feature -- Status setting
+
+ set_name (a_name: STRING_32)
+ do
+ name := a_name
+ end
+
+end -- class AUTHOR
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/book.e b/contrib/library/text/parser/json/test/autotest/test_suite/book.e
new file mode 100644
index 00000000..414036db
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/book.e
@@ -0,0 +1,40 @@
+class BOOK
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_title: STRING_32; an_author: AUTHOR; an_isbn: STRING_32)
+ do
+ set_title (a_title)
+ set_author (an_author)
+ set_isbn (an_isbn)
+ end
+
+feature -- Access
+
+ title: STRING_32
+
+ isbn: STRING_32
+
+ author: AUTHOR
+
+feature -- Status setting
+
+ set_title (a_title: STRING_32)
+ do
+ title := a_title
+ end
+
+ set_author (an_author: AUTHOR)
+ do
+ author := an_author
+ end
+
+ set_isbn (an_isbn: STRING_32)
+ do
+ isbn := an_isbn
+ end
+
+end -- class BOOK
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/book_collection.e b/contrib/library/text/parser/json/test/autotest/test_suite/book_collection.e
new file mode 100644
index 00000000..5ee0b0dd
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/book_collection.e
@@ -0,0 +1,80 @@
+class BOOK_COLLECTION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: STRING_32)
+ do
+ set_name (a_name)
+ create book_index.make (10)
+ end
+
+feature -- Access
+
+ name: STRING_32
+
+ books: LIST [BOOK]
+ do
+ from
+ create {LINKED_LIST [BOOK]} Result.make
+ book_index.start
+ until
+ book_index.after
+ loop
+ Result.append (book_index.item_for_iteration)
+ book_index.forth
+ end
+ end
+
+ books_by_author (an_author: STRING_32): detachable LIST [BOOK]
+ do
+ if book_index.has (an_author) then
+ Result := book_index @ an_author
+ else
+ create {LINKED_LIST [BOOK]} Result.make
+ end
+ end
+
+feature -- Status setting
+
+ set_name (a_name: STRING_32)
+ do
+ name := a_name
+ end
+
+ add_book (a_book: BOOK)
+ local
+ l: detachable LIST [BOOK]
+ do
+ if book_index.has (a_book.author.name) then
+ l := book_index.at ( a_book.author.name )
+ else
+ create {LINKED_LIST [BOOK]} l.make
+ book_index.put (l, a_book.author.name)
+ end
+ if attached l as la then
+ la.force (a_book)
+ end
+
+ end
+
+ add_books (book_list: like books)
+
+ do
+ from
+ book_list.start
+ until
+ book_list.after
+ loop
+ add_book (book_list.item)
+ book_list.forth
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ book_index: HASH_TABLE [LIST [BOOK], STRING_32]
+
+end -- class BOOK_COLLECTION
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail1.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail1.json
new file mode 100644
index 00000000..6216b865
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail1.json
@@ -0,0 +1 @@
+"A JSON payload should be an object or array, not a string."
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail10.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail10.json
new file mode 100644
index 00000000..5d8c0047
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail10.json
@@ -0,0 +1 @@
+{"Extra value after close": true} "misplaced quoted value"
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail11.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail11.json
new file mode 100644
index 00000000..76eb95b4
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail11.json
@@ -0,0 +1 @@
+{"Illegal expression": 1 + 2}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail12.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail12.json
new file mode 100644
index 00000000..77580a45
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail12.json
@@ -0,0 +1 @@
+{"Illegal invocation": alert()}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail13.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail13.json
new file mode 100644
index 00000000..379406b5
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail13.json
@@ -0,0 +1 @@
+{"Numbers cannot have leading zeroes": 013}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail14.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail14.json
new file mode 100644
index 00000000..0ed366b3
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail14.json
@@ -0,0 +1 @@
+{"Numbers cannot be hex": 0x14}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail15.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail15.json
new file mode 100644
index 00000000..fc8376b6
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail15.json
@@ -0,0 +1 @@
+["Illegal backslash escape: \x15"]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail16.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail16.json
new file mode 100644
index 00000000..3fe21d4b
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail16.json
@@ -0,0 +1 @@
+[\naked]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail17.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail17.json
new file mode 100644
index 00000000..62b9214a
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail17.json
@@ -0,0 +1 @@
+["Illegal backslash escape: \017"]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail18.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail18.json
new file mode 100644
index 00000000..edac9271
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail18.json
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail19.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail19.json
new file mode 100644
index 00000000..3b9c46fa
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail19.json
@@ -0,0 +1 @@
+{"Missing colon" null}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail2.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail2.json
new file mode 100644
index 00000000..6b7c11e5
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail2.json
@@ -0,0 +1 @@
+["Unclosed array"
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail20.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail20.json
new file mode 100644
index 00000000..27c1af3e
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail20.json
@@ -0,0 +1 @@
+{"Double colon":: null}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail21.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail21.json
new file mode 100644
index 00000000..62474573
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail21.json
@@ -0,0 +1 @@
+{"Comma instead of colon", null}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail22.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail22.json
new file mode 100644
index 00000000..a7752581
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail22.json
@@ -0,0 +1 @@
+["Colon instead of comma": false]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail23.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail23.json
new file mode 100644
index 00000000..494add1c
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail23.json
@@ -0,0 +1 @@
+["Bad value", truth]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail24.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail24.json
new file mode 100644
index 00000000..caff239b
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail24.json
@@ -0,0 +1 @@
+['single quote']
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail25.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail25.json
new file mode 100644
index 00000000..8b7ad23e
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail25.json
@@ -0,0 +1 @@
+[" tab character in string "]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail26.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail26.json
new file mode 100644
index 00000000..845d26a6
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail26.json
@@ -0,0 +1 @@
+["tab\ character\ in\ string\ "]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail27.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail27.json
new file mode 100644
index 00000000..6b01a2ca
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail27.json
@@ -0,0 +1,2 @@
+["line
+break"]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail28.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail28.json
new file mode 100644
index 00000000..621a0101
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail28.json
@@ -0,0 +1,2 @@
+["line\
+break"]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail29.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail29.json
new file mode 100644
index 00000000..47ec421b
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail29.json
@@ -0,0 +1 @@
+[0e]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail3.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail3.json
new file mode 100644
index 00000000..168c81eb
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail3.json
@@ -0,0 +1 @@
+{unquoted_key: "keys must be quoted"}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail30.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail30.json
new file mode 100644
index 00000000..8ab0bc4b
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail30.json
@@ -0,0 +1 @@
+[0e+]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail31.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail31.json
new file mode 100644
index 00000000..1cce602b
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail31.json
@@ -0,0 +1 @@
+[0e+-1]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail32.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail32.json
new file mode 100644
index 00000000..45cba739
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail32.json
@@ -0,0 +1 @@
+{"Comma instead if closing brace": true,
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail33.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail33.json
new file mode 100644
index 00000000..ca5eb19d
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail33.json
@@ -0,0 +1 @@
+["mismatch"}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail4.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail4.json
new file mode 100644
index 00000000..9de168bf
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail4.json
@@ -0,0 +1 @@
+["extra comma",]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail5.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail5.json
new file mode 100644
index 00000000..ddf3ce3d
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail5.json
@@ -0,0 +1 @@
+["double extra comma",,]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail6.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail6.json
new file mode 100644
index 00000000..ed91580e
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail6.json
@@ -0,0 +1 @@
+[ , "<-- missing value"]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail7.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail7.json
new file mode 100644
index 00000000..8a96af3e
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail7.json
@@ -0,0 +1 @@
+["Comma after the close"],
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail8.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail8.json
new file mode 100644
index 00000000..b28479c6
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail8.json
@@ -0,0 +1 @@
+["Extra close"]]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail9.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail9.json
new file mode 100644
index 00000000..5815574f
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail9.json
@@ -0,0 +1 @@
+{"Extra comma": true,}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e
new file mode 100644
index 00000000..ec734045
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e
@@ -0,0 +1,54 @@
+note
+ description: "A JSON converter for AUTHOR"
+ author: "Paul Cohen"
+ date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $"
+ revision: "$Revision: 82 $"
+ file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_author_converter.e $"
+
+class JSON_AUTHOR_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ local
+ ucs: STRING_32
+ do
+ create ucs.make_from_string ("")
+ create object.make (ucs)
+ end
+
+feature -- Access
+
+ object: AUTHOR
+
+feature -- Conversion
+
+ from_json (j: like to_json): detachable like object
+ local
+ ucs: detachable STRING_32
+ do
+ ucs ?= json.object (j.item (name_key), Void)
+ check ucs /= Void end
+ create Result.make (ucs)
+ end
+
+ to_json (o: like object): JSON_OBJECT
+ do
+ create Result.make
+ Result.put (json.value (o.name), name_key)
+ end
+
+feature {NONE} -- Implementation
+
+ name_key: JSON_STRING
+ once
+ create Result.make_json ("name")
+ end
+
+end -- class JSON_AUTHOR_CONVERTER
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e
new file mode 100644
index 00000000..06b33cd0
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e
@@ -0,0 +1,79 @@
+note
+ description: "A JSON converter for BOOK_COLLECTION"
+ author: "Paul Cohen"
+ date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $"
+ revision: "$Revision: 82 $"
+ file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_collection_converter.e $"
+
+class JSON_BOOK_COLLECTION_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ local
+ ucs: STRING_32
+ do
+ create ucs.make_from_string ("")
+ create object.make (ucs)
+ end
+
+feature -- Access
+
+ object: BOOK_COLLECTION
+
+feature -- Conversion
+
+ from_json (j: like to_json): detachable like object
+ local
+ ucs: detachable STRING_32
+ ll: LINKED_LIST [BOOK]
+ b: detachable BOOK
+ ja: detachable JSON_ARRAY
+ i: INTEGER
+ do
+ ucs ?= json.object (j.item (name_key), Void)
+ check ucs /= Void end
+ create Result.make (ucs)
+ ja ?= j.item (books_key)
+ check ja /= Void end
+ from
+ i := 1
+ create ll.make
+ until
+ i > ja.count
+ loop
+ b ?= json.object (ja [i], "BOOK")
+ check b /= Void end
+ ll.force (b)
+ i := i + 1
+ end
+ check ll /= Void end
+ Result.add_books (ll)
+ end
+
+ to_json (o: like object): JSON_OBJECT
+ do
+ create Result.make
+ Result.put (json.value (o.name), name_key)
+ Result.put (json.value (o.books), books_key)
+ end
+
+feature {NONE} -- Implementation
+
+ name_key: JSON_STRING
+ once
+ create Result.make_json ("name")
+ end
+
+ books_key: JSON_STRING
+ once
+ create Result.make_json ("books")
+ end
+
+end -- class JSON_BOOK_COLLECTION_CONVERTER
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e
new file mode 100644
index 00000000..e355149f
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e
@@ -0,0 +1,73 @@
+note
+ description: "A JSON converter for BOOK"
+ author: "Paul Cohen"
+ date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $"
+ revision: "$Revision: 82 $"
+ file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_converter.e $"
+
+class JSON_BOOK_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ local
+ ucs: STRING_32
+ a: AUTHOR
+ do
+ create ucs.make_from_string ("")
+ create a.make (ucs)
+ create object.make (ucs, a, ucs)
+ end
+
+feature -- Access
+
+ object: BOOK
+
+feature -- Conversion
+
+ from_json (j: like to_json): detachable like object
+ local
+ ucs1, ucs2: detachable STRING_32
+ a: detachable AUTHOR
+ do
+ ucs1 ?= json.object (j.item (title_key), Void)
+ check ucs1 /= Void end
+ ucs2 ?= json.object (j.item (isbn_key), Void)
+ check ucs2 /= Void end
+ a ?= json.object (j.item (author_key), "AUTHOR")
+ check a /= Void end
+ create Result.make (ucs1, a, ucs2)
+ end
+
+ to_json (o: like object): JSON_OBJECT
+ do
+ create Result.make
+ Result.put (json.value (o.title), title_key)
+ Result.put (json.value (o.isbn), isbn_key)
+ Result.put (json.value (o.author), author_key)
+ end
+
+feature {NONE} -- Implementation
+
+ title_key: JSON_STRING
+ once
+ create Result.make_json ("title")
+ end
+
+ isbn_key: JSON_STRING
+ once
+ create Result.make_json ("isbn")
+ end
+
+ author_key: JSON_STRING
+ once
+ create Result.make_json ("author")
+ end
+
+end -- class JSON_BOOK_CONVERTER
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_menu_example.txt b/contrib/library/text/parser/json/test/autotest/test_suite/json_menu_example.txt
new file mode 100644
index 00000000..bce42e86
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_menu_example.txt
@@ -0,0 +1,11 @@
+{"menu": {
+ "id": "file",
+ "value": "File",
+ "popup": {
+ "menuitem": [
+ {"value": "New", "onclick": "CreateNewDoc()"},
+ {"value": "Open", "onclick": "OpenDoc()"},
+ {"value": "Close", "onclick": "CloseDoc()"}
+ ]
+ }
+}}
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/pass1.json b/contrib/library/text/parser/json/test/autotest/test_suite/pass1.json
new file mode 100644
index 00000000..70e26854
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/pass1.json
@@ -0,0 +1,58 @@
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E66,
+ "zero": 0,
+ "one": 1,
+ "space": " ",
+ "quote": "\"",
+ "backslash": "\\",
+ "controls": "\b\f\n\r\t",
+ "slash": "/ & \/",
+ "alpha": "abcdefghijklmnopqrstuvwyz",
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+ "digit": "0123456789",
+ "0123456789": "digit",
+ "special": "`1~!@#$%^&*()_+-={':[,]}|;.>?",
+ "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "address": "50 St. James Street",
+ "url": "http://www.JSON.org/",
+ "comment": "// /* */": " ",
+ " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "" \u0022 %22 0x22 034 "",
+ "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+ },
+ 0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,2e+00,2e-00
+,"rosebud"]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/pass2.json b/contrib/library/text/parser/json/test/autotest/test_suite/pass2.json
new file mode 100644
index 00000000..d3c63c7a
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/pass2.json
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/pass3.json b/contrib/library/text/parser/json/test/autotest/test_suite/pass3.json
new file mode 100644
index 00000000..4528d51f
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/pass3.json
@@ -0,0 +1,6 @@
+{
+ "JSON Test Pattern pass3": {
+ "The outermost value": "must be an object or array.",
+ "In this test": "It is an object."
+ }
+}
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_ds.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_ds.e
new file mode 100644
index 00000000..1cccd4b1
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_ds.e
@@ -0,0 +1,74 @@
+class TEST_DS
+
+inherit
+ SHARED_EJSON
+ rename default_create as shared_default_create end
+ EQA_TEST_SET
+ select default_create end
+
+
+feature -- Test
+
+ test_linked_list_converter
+ local
+ jc: JSON_LINKED_LIST_CONVERTER
+ l: LINKED_LIST [STRING]
+ l2: detachable LINKED_LIST [detachable ANY]
+ s: STRING
+ jv: detachable JSON_VALUE
+ do
+ create jc.make
+ json.add_converter (jc)
+ create l.make
+ s := "foo"
+ l.force (s)
+ s := "bar"
+ l.force (s)
+ jv := json.value (l)
+ assert ("jv /= Void", jv /= Void)
+ if attached jv as l_jv then
+ s := jv.representation
+ l2 ?= json.object (jv, "LINKED_LIST")
+ assert ("l2 /= Void", l2 /= Void)
+ end
+ end
+
+ test_hash_table_converter
+ local
+ tc: JSON_HASH_TABLE_CONVERTER
+ t: HASH_TABLE [STRING, STRING]
+ t2: detachable HASH_TABLE [ANY, HASHABLE]
+ s: STRING
+ ucs_key, ucs_value: detachable STRING_32
+ jv: detachable JSON_VALUE
+ do
+ create tc.make
+ json.add_converter (tc)
+ create t.make (2)
+ t.put ("foo", "1")
+ t.put ("bar", "2")
+ jv := json.value (t)
+ assert ("jv /= Void", jv /= Void)
+ if attached jv as l_jv then
+ s := l_jv.representation
+ t2 ?= json.object (l_jv, "HASH_TABLE")
+ assert ("t2 /= Void", t2 /= Void)
+ end
+ create ucs_key.make_from_string ("1")
+ if attached t2 as l_t2 then
+ ucs_value ?= t2 @ ucs_key
+ assert ("ucs_value /= Void", ucs_value /= Void)
+ if attached ucs_value as l_ucs_value then
+ assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.string.is_equal ("foo"))
+ end
+ create ucs_key.make_from_string ("2")
+ ucs_value ?= t2 @ ucs_key
+ assert ("ucs_value /= Void", ucs_value /= Void)
+ if attached ucs_value as l_ucs_value then
+ assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.string.is_equal ("bar"))
+ end
+
+ end
+ end
+
+end -- class TEST_DS
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e
new file mode 100644
index 00000000..d2faa7e1
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e
@@ -0,0 +1,822 @@
+class TEST_JSON_CORE
+
+inherit
+ SHARED_EJSON
+ rename default_create as shared_default_create end
+ EQA_TEST_SET
+ select default_create end
+
+feature -- Test
+
+ test_json_number_and_integer
+ local
+ i: INTEGER
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i := 42
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i)
+ assert ("jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (i) as l_jn then
+ assert ("l_jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ else
+ assert ("json.value (i) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation-> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_8 since the value is 42
+ jrep := "42"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
+ assert ("l_i8 = 42", l_i8 = 42)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_8", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_8
+ local
+ i8: INTEGER_8
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i8 := 42
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i8)
+ assert ("jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (i8) as l_jn then
+ assert ("l_jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ else
+ assert ("json.value (i8) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_8 since the value is 42
+ jrep := "42"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
+ assert ("l_i8 = 42", l_i8 = 42)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_8", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_16
+ local
+ i16: INTEGER_16
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i16 := 300
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i16)
+ assert ("jn.representation.same_string (%"300%")", jn.representation.same_string ("300"))
+ -- Eiffel value -> JSON with factory
+ if attached {JSON_NUMBER} json.value (i16) as l_jn then
+ assert ("l_jn.representation.same_string (%"300%")", l_jn.representation.same_string ("300"))
+ else
+ assert ("json.value (i16) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_16 since the value is 300
+ jrep := "300"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_16} json.object (jn, Void) as l_i16 then
+ assert ("l_i16 = 300", l_i16 = 300)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_16", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_32
+ local
+ i32: INTEGER_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i32 := 100000
+ -- Eiffel value -> JSON representation -> JSON value
+ create jn.make_integer (i32)
+ assert ("jn.representation.same_string (%"100000%")", jn.representation.same_string ("100000"))
+ -- Eiffel value -> JSON representation -> JSON value with factory
+ if attached {JSON_NUMBER} json.value (i32) as l_jn then
+ assert ("l_jn.representation.same_string (%"100000%")", l_jn.representation.same_string ("100000"))
+ else
+ assert ("json.value (i32) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 100000
+ jrep := "100000"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_32} json.object (jn, Void) as l_i32 then
+ assert ("l_i32 = 100000", l_i32 = 100000)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_32", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_64
+ local
+ i64: INTEGER_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i64 := 42949672960
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i64)
+ assert ("jn.representation.same_string (%"42949672960%")", jn.representation.same_string ("42949672960"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (i64) as l_jn then
+ assert ("l_jn.representation.same_string (%"42949672960%")", l_jn.representation.same_string ("42949672960"))
+ else
+ assert ("json.value (i64) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 42949672960
+ jrep := "42949672960"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_64} json.object (jn, Void) as l_i64 then
+ assert ("l_i64 = 42949672960", l_i64 = 42949672960)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_natural_8
+ local
+ n8: NATURAL_8
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n8 := 200
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n8)
+ assert ("jn.representation.same_string (%"200%")", jn.representation.same_string ("200"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (n8) as l_jn then
+ assert ("l_jn.representation.same_string (%"200%")", l_jn.representation.same_string ("200"))
+ else
+ assert ("json.value (n8) is a JSON_NUMBER}", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_16 since the value is 200
+ jrep := "200"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_16} json.object (jn, Void) as i16 then
+ assert ("i16 = 200", i16 = 200)
+ else
+ assert ("json.object (jn, Void) is an INTEGER_16", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_natural_16
+ local
+ n16: NATURAL_16
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n16 := 32768
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n16)
+ assert ("jn.representation.same_string (%"32768%")", jn.representation.same_string ("32768"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (n16) as l_jn then
+ assert ("l_jn.representation.same_string (%"32768%")", l_jn.representation.same_string ("32768"))
+ else
+ assert ("json.value (n16) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 32768
+ jrep := "32768"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_32} json.object (jn, Void) as i32 then
+ assert ("i32 = 32768", i32 = 32768)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_32", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_natural_32
+ local
+ n32: NATURAL_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n32 := 2147483648
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n32)
+ assert ("jn.representation.same_string (%"2147483648%")", jn.representation.same_string ("2147483648"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached json.value (n32) as l_jn then
+ assert ("l_jn.representation.same_string (%"2147483648%")", l_jn.representation.same_string ("2147483648"))
+ else
+ assert ("json.value (n32) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_64 since the value is 2147483648
+ jrep := "2147483648"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_64} json.object (jn, Void) as i64 then
+ assert ("i64 = 2147483648", i64 = 2147483648)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_large_integers
+ local
+ jrep: STRING
+ n64: NATURAL_64
+ jn: JSON_NUMBER
+ parser: JSON_PARSER
+ do
+ n64 := 9223372036854775808
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n64)
+ assert ("jn.representation.same_string (%"9223372036854775808%")", jn.representation.same_string ("9223372036854775808"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (n64) as l_jn then
+ assert ("l_jn.representation.same_string (%"9223372036854775808%")", l_jn.representation.same_string ("9223372036854775808"))
+ else
+ assert ("json.value (n64) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 42949672960
+ jrep := "9223372036854775808" -- 1 higher than largest positive number that can be represented by INTEGER 64
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {NATURAL_64} json.object (jn, Void) as l_n64 then
+ assert ("l_n64 = 9223372036854775808", l_n64 = 9223372036854775808)
+ else
+ assert ("json.object (jn, Void) is a NATURAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_eiffel_real
+ local
+ r: REAL
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r := 3.14
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r)
+ assert ("jn.representation.same_string (%"3.1400001049041748%")", jn.representation.same_string ("3.1400001049041748"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (r) as l_jn then
+ assert ("l_jn.representation.same_string (%"3.1400001049041748%")", l_jn.representation.same_string ("3.1400001049041748"))
+ else
+ assert ("json.value (r) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will always return a REAL_64 if the value
+ -- of the JSON number is a floating point number
+ jrep := "3.14"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {REAL_64} json.object (jn, Void) as r64 then
+ assert ("3.14 <= r64 and r64 <= 3.141", 3.14 <= r64 and r64 <= 3.141)
+ else
+ assert ("json.object (jn, Void) is a REAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_eiffel_real_32
+ local
+ r32: REAL_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r32 := 3.14
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r32)
+ assert ("jn.representation.same_string (%"3.1400001049041748%")", jn.representation.same_string ("3.1400001049041748"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (r32) as l_jn then
+ assert ("l_jn.representation.same_string (%"3.1400001049041748%")", l_jn.representation.same_string ("3.1400001049041748"))
+ else
+ assert ("json.value (r32) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "3.1400001049041748"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {REAL_64} json.object (l_jn, Void) as r64 then
+ assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748)
+ else
+ assert ("json.object (l_jn, Void) is a REAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_eiffel_real_64
+ local
+ r64: REAL_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r64 := 3.1415926535897931
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r64)
+ assert ("jn.representation.same_string (%"3.1415926535897931%")", jn.representation.same_string ("3.1415926535897931"))
+
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (r64) as l_jn then
+ assert ("l_jn.representation.same_string (%"3.1415926535897931%")", l_jn.representation.same_string ("3.1415926535897931"))
+ else
+ assert ("json.value (r64) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "3.1415926535897931"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {REAL_64} json.object (jn, Void) as l_r64 then
+ assert ("l_r64 = 3.1415926535897931", l_r64 = 3.1415926535897931)
+ else
+ assert ("json.object (jn, Void) is a REAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_boolean
+ local
+ parser: JSON_PARSER
+ jb: JSON_BOOLEAN
+ b: BOOLEAN
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ b := True
+ create jb.make_boolean (b)
+ assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_BOOLEAN} json.value (b) as l_jb then
+ assert ("l_jb.representation.same_string (%"true%")", l_jb.representation.same_string ("true"))
+ else
+ assert ("l_jb /= Void", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ create parser.make_parser ("true")
+ if attached {JSON_BOOLEAN} parser.parse as l_jb then
+ if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
+ assert ("l_b = True", l_b = True)
+ else
+ assert ("json.object (l_jb, Void) is BOOLEAN", False)
+ end
+ else
+ assert ("parser.parse is a JSON_BOOLEAN", False)
+ end
+
+ -- Eiffel value -> JSON value -> JSON representation
+ b := False
+ create jb.make_boolean (b)
+ assert ("jb.representation.same_string (%"false%")", jb.representation.same_string ("false"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_BOOLEAN} json.value (b) as l_jb then
+ assert ("l_jb.representation.same_string (%"false%")", l_jb.representation.same_string ("false"))
+ else
+ assert ("json.value (b) is a JSON_BOOLEAN", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ create parser.make_parser ("false")
+ if attached {JSON_BOOLEAN} parser.parse as l_jb then
+ if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
+ assert ("l_b = False", l_b = False)
+ else
+ assert ("json.object (l_jb, Void) is a BOOLEAN", False)
+ end
+ else
+ assert ("parser.parse is a JSON_BOOLEAN", False)
+ end
+ end
+
+ test_json_null
+ local
+ a: detachable ANY
+ dummy_object: STRING
+ jn: detachable JSON_NULL
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"%"null%"%")", jn.representation.is_equal ("null"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (Void)
+ assert ("jn /= Void", jn /= Void)
+ if attached jn as l_jn then
+ assert ("jn.representation.is_equal (%"null%")", l_jn.representation.is_equal ("null"))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "null"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ create dummy_object.make_empty
+ a := dummy_object
+ a ?= json.object (jn, Void)
+ assert ("a = Void", a = Void)
+ end
+
+ test_json_string_and_character
+ local
+ c: CHARACTER
+ js: detachable JSON_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ c := 'a'
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (c.out)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (c)
+ assert ("js /= Void", js /= Void)
+ if attached js as l_js then
+ assert ("js.representation.is_equal (%"%"a%"%")", l_js.representation.is_equal ("%"a%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"a%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ if attached {STRING_32} json.object (js, Void) as ucs then
+ assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a"))
+ end
+
+ end
+
+ test_json_string_and_string
+ local
+ s: STRING
+ js: detachable JSON_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ s := "foobar"
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (s)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (s)
+ assert ("js /= Void", js /= Void)
+ if attached js as l_js then
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foobar%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ if attached {STRING_32} json.object (js, Void) as l_ucs then
+ assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar"))
+ end
+ end
+
+ test_json_string_and_uc_string
+ local
+ js: detachable JSON_STRING
+ ucs: detachable STRING_32
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ create ucs.make_from_string ("foobar")
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (ucs)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (ucs)
+ assert ("js /= Void", js /= Void)
+ if attached js as l_js then
+ assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.is_equal ("%"foobar%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foobar%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ ucs := Void
+ ucs ?= json.object (js, Void)
+ if attached ucs as l_ucs then
+ assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar"))
+ end
+ end
+
+ test_json_string_and_special_characters
+ local
+ js: detachable JSON_STRING
+ s: detachable STRING_8
+ ucs: detachable STRING_32
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ create s.make_from_string ("foo\bar")
+ create js.make_json (s)
+
+ assert ("js.representation.same_string (%"%"foo\\bar%"%")", js.representation.same_string ("%"foo\\bar%""))
+
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (s)
+ assert ("js /= Void", js /= Void)
+ if js /= Void then
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.same_string ("%"foo\\bar%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foo\\bar%""
+ create parser.make_parser (jrep)
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ ucs ?= json.object (js, Void)
+ if ucs /= Void then
+ assert ("ucs.same_string (%"foo\bar%")", ucs.same_string ("foo\bar"))
+ end
+
+ jrep := "%"foo\\bar%""
+ create parser.make_parser (jrep)
+ if attached {JSON_STRING} parser.parse as jstring then
+ assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string_8.same_string ("foo\bar"))
+ end
+
+ create js.make_json_from_string_32 ({STRING_32}"%/20320/%/22909/")
+ assert ("escaping unicode string32 %"%%/20320/%%/22909/%" %"\u4F60\u597D%"", js.item.same_string ("\u4F60\u597D"))
+
+ jrep := "%"\u4F60\u597D%"" --| Ni hao
+ create parser.make_parser (jrep)
+ if attached {JSON_STRING} parser.parse as jstring then
+ assert ("same unicode string32 %"%%/20320/%%/22909/%"", jstring.unescaped_string_32.same_string ({STRING_32}"%/20320/%/22909/"))
+ end
+ end
+
+ test_json_array
+ local
+ ll: LINKED_LIST [INTEGER_8]
+ ll2: detachable LINKED_LIST [detachable ANY]
+ ja: detachable JSON_ARRAY
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ create ll.make
+ ll.extend (0)
+ ll.extend (1)
+ ll.extend (1)
+ ll.extend (2)
+ ll.extend (3)
+ ll.extend (5)
+ -- Note: Currently there is no simple way of creating a JSON_ARRAY
+ -- from an LINKED_LIST.
+ create ja.make_array
+ from
+ ll.start
+ until
+ ll.after
+ loop
+ create jn.make_integer (ll.item)
+ ja.add (jn)
+ ll.forth
+ end
+ assert ("ja /= Void", ja /= Void)
+ assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ ja := Void
+ ja ?= json.value (ll)
+ assert ("ja /= Void", ja /= Void)
+ if attached ja as l_ja then
+ assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", l_ja.representation.is_equal ("[0,1,1,2,3,5]"))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- it means we will get an LINKED_LIST [ANY] containing the INTEGER_8
+ -- values 0, 1, 1, 2, 3, 5
+ jrep := "[0,1,1,2,3,5]"
+ create parser.make_parser (jrep)
+ ja := Void
+ ja ?= parser.parse
+ assert ("ja /= Void", ja /= Void)
+ ll2 ?= json.object (ja, Void)
+ assert ("ll2 /= Void", ll2 /= Void)
+ --ll.compare_objects
+ --ll2.compare_objects
+ if attached ll2 as l_ll2 then
+ assert ("ll2.is_equal (ll)", l_ll2.is_equal (ll))
+ end
+
+ end
+
+ test_json_object
+ local
+ t, t2: detachable HASH_TABLE [detachable ANY, STRING_GENERAL]
+ i: INTEGER
+ ucs_key, ucs: STRING_32
+ a: ARRAY [INTEGER]
+ jo: detachable JSON_OBJECT
+ jn: JSON_NUMBER
+ js_key, js: JSON_STRING
+ ja: JSON_ARRAY
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ -- Note: Currently there is now way of creating a JSON_OBJECT from
+ -- a HASH_TABLE, so we do it manually.
+ -- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]}
+ create jo.make
+ create js_key.make_json ("name")
+ create js.make_json ("foobar")
+ jo.put (js, js_key)
+ create js_key.make_json ("size")
+ create jn.make_integer (42)
+ jo.put (jn, js_key)
+ create js_key.make_json ("contents")
+ create ja.make_array
+ create jn.make_integer (0)
+ ja.add (jn)
+ create jn.make_integer (1)
+ ja.add (jn)
+ create jn.make_integer (1)
+ ja.add (jn)
+ create jn.make_integer (2)
+ ja.add (jn)
+ create jn.make_integer (3)
+ ja.add (jn)
+ create jn.make_integer (5)
+ ja.add (jn)
+ jo.put (ja, js_key)
+ assert ("jo /= Void", jo /= Void)
+ assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ create t.make (3)
+ create ucs_key.make_from_string ("name")
+ create ucs.make_from_string ("foobar")
+ t.put (ucs, ucs_key)
+ create ucs_key.make_from_string ("size")
+ i := 42
+ t.put (i, ucs_key)
+ create ucs_key.make_from_string ("contents")
+ a := <<0, 1, 1, 2, 3, 5>>
+ t.put (a, ucs_key)
+ jo := Void
+ jo ?= json.value (t)
+ assert ("jo /= Void", jo /= Void)
+ if attached jo as l_jo then
+ assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", l_jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
+ end
+ -- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation
+ jrep := "{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"
+ create parser.make_parser (jrep)
+ jo := Void
+ jo ?= parser.parse
+ assert ("jo /= Void", jo /= Void)
+ t2 ?= json.object (jo, Void)
+ assert ("t2 /= Void", t2 /= Void)
+ jo ?= json.value (t2)
+ assert ("jo /= Void", jo /= Void)
+ if attached jo as l_jo then
+ assert ("jrep.is_equal (jo.representation)", jrep.is_equal (jo.representation))
+ end
+
+ end
+
+ test_json_failed_json_conversion
+ -- Test converting an Eiffel object to JSON that is based on a class
+ -- for which no JSON converter has been registered.
+ local
+ gv: OPERATING_ENVIRONMENT
+ jv: detachable JSON_VALUE
+ exception: BOOLEAN
+ do
+ if not exception then
+ create gv
+ jv := json.value (gv)
+ else
+ assert ("exceptions.is_developer_exception", json.is_developer_exception)
+-- assert ("exceptions.is_developer_exception_of_name", json.is_developer_exception_of_name ("eJSON exception: Failed to convert Eiffel object to a JSON_VALUE: OPERATING_ENVIRONMENT"))
+ end
+ rescue
+ exception := True
+ retry
+ end
+
+ test_json_failed_eiffel_conversion
+ -- Test converting from a JSON value to an Eiffel object based on a
+ -- class for which no JSON converter has been registered.
+ local
+ gv : detachable OPERATING_ENVIRONMENT
+ jo: JSON_OBJECT
+ exception: BOOLEAN
+ do
+ if not exception then
+ create jo.make
+ gv ?= json.object (jo, "OPERATING_ENVIRONMENT")
+ else
+ assert ("exceptions.is_developer_exception", json.is_developer_exception)
+-- assert ("exceptions.is_developer_exception_of_name", json.is_developer_exception_of_name ("eJSON exception: Failed to convert JSON_VALUE to an Eiffel object: JSON_OBJECT -> OPERATING_ENVIRONMENT"))
+
+ end
+ rescue
+ exception := True
+ retry
+ end
+
+end -- class TEST_JSON_CORE
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_custom_classes.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_custom_classes.e
new file mode 100644
index 00000000..fc7957bc
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_custom_classes.e
@@ -0,0 +1,42 @@
+class TEST_JSON_CUSTOM_CLASSES
+
+inherit
+ SHARED_EJSON
+ rename default_create as shared_default_create end
+ EQA_TEST_SET
+ select default_create end
+feature -- Test
+
+ test_custom_classes
+ local
+ bc: detachable BOOK_COLLECTION
+ jbc: JSON_BOOK_CONVERTER
+ jbcc: JSON_BOOK_COLLECTION_CONVERTER
+ jac: JSON_AUTHOR_CONVERTER
+ jo: detachable JSON_OBJECT
+ parser: JSON_PARSER
+ jrep: STRING
+ do
+ create jbc.make
+ json.add_converter (jbc)
+ create jbcc.make
+ json.add_converter (jbcc)
+ create jac.make
+ json.add_converter (jac)
+ jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"
+ create parser.make_parser (jrep)
+ jo := Void
+ jo ?= parser.parse
+ assert ("jo /= Void", jo /= Void)
+ bc := Void
+ bc ?= json.object (jo, "BOOK_COLLECTION")
+ assert ("bc /= Void", bc /= Void)
+ jo ?= json.value (bc)
+ assert ("jo /= Void", jo /= Void)
+ if attached jo as l_jo then
+ assert ("JSON representation is correct", l_jo.representation.same_string ("{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"))
+ end
+
+ end
+
+end -- class TEST_JSON_CUSTOM_CLASS
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_suite.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_suite.e
new file mode 100644
index 00000000..812fb391
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_suite.e
@@ -0,0 +1,514 @@
+note
+ description: "[
+ Eiffel tests that can be executed by testing tool.
+ ]"
+ author: "EiffelStudio test wizard"
+ date: "$Date$"
+ revision: "$Revision$"
+ testing: "type/manual"
+
+class
+ TEST_JSON_SUITE
+
+inherit
+ EQA_TEST_SET
+ redefine
+ on_prepare
+ end
+
+feature {NONE} -- Events
+
+ on_prepare
+ --
+ do
+ create file_reader
+ end
+
+feature -- Tests Pass
+
+ test_json_pass1
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("pass1.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("pass1.json",parse_json.is_parsed = True)
+ end
+ end
+
+ test_json_pass2
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("pass2.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("pass2.json",parse_json.is_parsed = True)
+ end
+ end
+
+ test_json_pass3
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("pass3.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("pass3.json",parse_json.is_parsed = True)
+ end
+ end
+
+feature -- Tests Failures
+ test_json_fail1
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail1.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail1.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail2
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail2.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail2.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail3
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail3.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail3.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail4
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail4.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail4.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail5
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail5.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail5.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail6
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail6.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail6.json",parse_json.is_parsed = False )
+ end
+ end
+
+ test_json_fail7
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail7.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail7.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail8
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail8.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail8.json",parse_json.is_parsed = False )
+ end
+ end
+
+
+ test_json_fail9
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail9.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail9.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail10
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail10.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail10.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail11
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail11.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail11.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail12
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail12.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail12.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail13
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail13.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail13.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail14
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail14.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail14.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail15
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail15.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail15.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail16
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail16.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail16.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail17
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail17.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail17.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail18
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail18.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail18.json",parse_json.is_parsed = True)
+ end
+ end
+
+ test_json_fail19
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail19.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail19.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail20
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail20.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail20.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail21
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail21.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail21.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail22
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail22.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail22.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail23
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail23.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail23.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail24
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail24.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail24.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail25
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail25.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail25.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail26
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail26.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail26.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail27
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail27.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail27.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail28
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail28.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail28.json",parse_json.is_parsed = False)
+ end
+ end
+
+
+ test_json_fail29
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail29.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail29.json",parse_json.is_parsed = False )
+ end
+ end
+
+
+ test_json_fail30
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail30.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail30.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail31
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail31.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail31.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail32
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail32.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail32.json",parse_json.is_parsed = False)
+ end
+ end
+
+ test_json_fail33
+ --
+ local
+ parse_json: like new_json_parser
+ do
+ if attached json_file_from ("fail33.json") as json_file then
+ parse_json := new_json_parser (json_file)
+ json_value := parse_json.parse_json
+ assert ("fail33.json",parse_json.is_parsed = False)
+ end
+ end
+
+feature -- JSON_FROM_FILE
+
+ file_reader: JSON_FILE_READER
+
+ json_value: detachable JSON_VALUE
+
+ json_file_from (fn: STRING): detachable STRING
+ do
+ Result := file_reader.read_json_from (test_dir + fn)
+ assert ("File contains json data", Result /= Void)
+ end
+
+ new_json_parser (a_string: STRING): JSON_PARSER
+ do
+ create Result.make_parser (a_string)
+ end
+
+ test_dir: STRING
+ local
+ i: INTEGER
+ do
+ Result := (create {EXECUTION_ENVIRONMENT}).current_working_directory
+ Result.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
+ -- The should looks like
+ -- ..json\test\autotest\test_suite\EIFGENs\test_suite\Testing\execution\TEST_JSON_SUITE.test_json_fail1\..\..\..\..\..\fail1.json
+ from
+ i := 5
+ until
+ i = 0
+ loop
+ Result.append_character ('.')
+ Result.append_character ('.')
+ Result.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
+ i := i - 1
+ end
+-- Result := "/home/jvelilla/work/project/Eiffel/ejson_dev/trunk/test/autotest/test_suite/"
+ end
+
+invariant
+ file_reader /= Void
+
+end
+
+
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_suite-safe.ecf b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite-safe.ecf
new file mode 100644
index 00000000..00552058
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite-safe.ecf
@@ -0,0 +1,18 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+
+
+
diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_suite.ecf b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite.ecf
new file mode 100644
index 00000000..f24d3ed4
--- /dev/null
+++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite.ecf
@@ -0,0 +1,19 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+
+
+
+
diff --git a/contrib/library/text/parser/json/test/getest/author.e b/contrib/library/text/parser/json/test/getest/author.e
new file mode 100644
index 00000000..81906d7d
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/author.e
@@ -0,0 +1,24 @@
+class AUTHOR
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: UC_STRING) is
+ do
+ set_name (a_name)
+ end
+
+feature -- Access
+
+ name: UC_STRING
+
+feature -- Status setting
+
+ set_name (a_name: UC_STRING) is
+ do
+ name := a_name
+ end
+
+end -- class AUTHOR
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/book.e b/contrib/library/text/parser/json/test/getest/book.e
new file mode 100644
index 00000000..e896c31a
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/book.e
@@ -0,0 +1,40 @@
+class BOOK
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_title: UC_STRING; an_author: AUTHOR; an_isbn: UC_STRING) is
+ do
+ set_title (a_title)
+ set_author (an_author)
+ set_isbn (an_isbn)
+ end
+
+feature -- Access
+
+ title: UC_STRING
+
+ isbn: UC_STRING
+
+ author: AUTHOR
+
+feature -- Status setting
+
+ set_title (a_title: UC_STRING) is
+ do
+ title := a_title
+ end
+
+ set_author (an_author: AUTHOR) is
+ do
+ author := an_author
+ end
+
+ set_isbn (an_isbn: UC_STRING) is
+ do
+ isbn := an_isbn
+ end
+
+end -- class BOOK
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/book_collection.e b/contrib/library/text/parser/json/test/getest/book_collection.e
new file mode 100644
index 00000000..816d6894
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/book_collection.e
@@ -0,0 +1,82 @@
+class BOOK_COLLECTION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: UC_STRING) is
+ do
+ set_name (a_name)
+ create book_index.make (10)
+ end
+
+feature -- Access
+
+ name: UC_STRING
+
+ books: DS_LIST [BOOK] is
+ local
+ c: DS_HASH_TABLE_CURSOR [DS_LIST [BOOK], UC_STRING]
+ do
+ from
+ create {DS_LINKED_LIST [BOOK]} Result.make
+ c := book_index.new_cursor
+ c.start
+ until
+ c.after
+ loop
+ Result.append_last (c.item)
+ c.forth
+ end
+ end
+
+ books_by_author (an_author: UC_STRING): DS_LIST [BOOK] is
+ do
+ if book_index.has (an_author) then
+ Result := book_index @ an_author
+ else
+ create {DS_LINKED_LIST [BOOK]} Result.make
+ end
+ end
+
+feature -- Status setting
+
+ set_name (a_name: UC_STRING) is
+ do
+ name := a_name
+ end
+
+ add_book (a_book: BOOK) is
+ local
+ l: DS_LIST [BOOK]
+ do
+ if book_index.has (a_book.author.name) then
+ l := book_index @ a_book.author.name
+ else
+ create {DS_LINKED_LIST [BOOK]} l.make
+ book_index.put (l, a_book.author.name)
+ end
+ l.put_last (a_book)
+ end
+
+ add_books (book_list: like books) is
+ local
+ c: DS_LIST_CURSOR [BOOK]
+ do
+ from
+ c := book_list.new_cursor
+ c.start
+ until
+ c.after
+ loop
+ add_book (c.item)
+ c.forth
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ book_index: DS_HASH_TABLE [DS_LIST [BOOK], UC_STRING]
+
+end -- class BOOK_COLLECTION
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/ec_compile.bat b/contrib/library/text/parser/json/test/getest/ec_compile.bat
new file mode 100644
index 00000000..1d90e40c
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/ec_compile.bat
@@ -0,0 +1,11 @@
+echo Compiling ejson_test (finalized)
+ecb -finalize -c_compile -config ejson_test.ecf -batch -clean > NUL 2>&1
+IF %ERRORLEVEL% EQU -1 goto ERROR
+copy EIFGENs\ejson_test\F_code\ejson_test.exe ejson_test.exe
+goto EOF
+
+:ERROR
+echo Error occurred during ejson_test compilation
+goto EOF
+
+:EOF
diff --git a/contrib/library/text/parser/json/test/getest/ec_compile.sh b/contrib/library/text/parser/json/test/getest/ec_compile.sh
new file mode 100755
index 00000000..08dcd613
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/ec_compile.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+echo "ec -finalize -c_compile -config ejson_test.ecf > /dev/null 2>&1"
+ec -finalize -c_compile -config ejson_test.ecf > /dev/null 2>&1
+cp EIFGENs/ejson_test/F_code/ejson_test .
diff --git a/contrib/library/text/parser/json/test/getest/ejson_test-win.cfg b/contrib/library/text/parser/json/test/getest/ejson_test-win.cfg
new file mode 100644
index 00000000..9c905c21
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/ejson_test-win.cfg
@@ -0,0 +1,17 @@
+-- Gobo test (getest) configuration file for eJSON
+
+test
+ ejson_test
+
+default
+ class ("TEST_[A-Z0-9_]*")
+ feature ("test_[a-z0-9_]*")
+ prefix ("X")
+ testgen ("TESTGEN")
+ compile ("ec_compile.bat")
+ execute ("ejson_test.exe")
+
+cluster
+ test_dir: "."
+
+end
diff --git a/contrib/library/text/parser/json/test/getest/ejson_test.cfg b/contrib/library/text/parser/json/test/getest/ejson_test.cfg
new file mode 100644
index 00000000..078526ac
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/ejson_test.cfg
@@ -0,0 +1,17 @@
+-- Gobo test (getest) configuration file for eJSON
+
+test
+ ejson_test
+
+default
+ class ("TEST_[A-Z0-9_]*")
+ feature ("test_[a-z0-9_]*")
+ prefix ("X")
+ testgen ("TESTGEN")
+ compile ("./ec_compile.sh")
+ execute ("./ejson_test")
+
+cluster
+ test_dir: "."
+
+end
diff --git a/contrib/library/text/parser/json/test/getest/ejson_test.ecf b/contrib/library/text/parser/json/test/getest/ejson_test.ecf
new file mode 100644
index 00000000..d302b746
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/ejson_test.ecf
@@ -0,0 +1,21 @@
+
+
+
+
+
+ //.svn
+ /cvs$
+ /EIFGENs$
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/library/text/parser/json/test/getest/json_author_converter.e b/contrib/library/text/parser/json/test/getest/json_author_converter.e
new file mode 100644
index 00000000..39458cd3
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/json_author_converter.e
@@ -0,0 +1,56 @@
+indexing
+ description: "A JSON converter for AUTHOR"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_author_converter.e $"
+
+class JSON_AUTHOR_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make is
+ local
+ ucs: UC_STRING
+ do
+ create ucs.make_from_string ("")
+ create object.make (ucs)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: AUTHOR
+
+feature -- Conversion
+
+ from_json (j: like value): like object is
+ local
+ ucs: UC_STRING
+ do
+ ucs ?= json.object (j.item (name_key), Void)
+ check ucs /= Void end
+ create Result.make (ucs)
+ end
+
+ to_json (o: like object): like value is
+ do
+ create Result.make
+ Result.put (json.value (o.name), name_key)
+ end
+
+feature {NONE} -- Implementation
+
+ name_key: JSON_STRING is
+ once
+ create Result.make_json ("name")
+ end
+
+end -- class JSON_AUTHOR_CONVERTER
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/json_book_collection_converter.e b/contrib/library/text/parser/json/test/getest/json_book_collection_converter.e
new file mode 100644
index 00000000..4a56163a
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/json_book_collection_converter.e
@@ -0,0 +1,81 @@
+indexing
+ description: "A JSON converter for BOOK_COLLECTION"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_collection_converter.e $"
+
+class JSON_BOOK_COLLECTION_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make is
+ local
+ ucs: UC_STRING
+ do
+ create ucs.make_from_string ("")
+ create object.make (ucs)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: BOOK_COLLECTION
+
+feature -- Conversion
+
+ from_json (j: like value): like object is
+ local
+ ucs: UC_STRING
+ ll: DS_LINKED_LIST [BOOK]
+ b: BOOK
+ ja: JSON_ARRAY
+ i: INTEGER
+ do
+ ucs ?= json.object (j.item (name_key), Void)
+ check ucs /= Void end
+ create Result.make (ucs)
+ ja ?= j.item (books_key)
+ check ja /= Void end
+ from
+ i := 1
+ create ll.make
+ until
+ i > ja.count
+ loop
+ b ?= json.object (ja [i], "BOOK")
+ check b /= Void end
+ ll.put_last (b)
+ i := i + 1
+ end
+ check ll /= Void end
+ Result.add_books (ll)
+ end
+
+ to_json (o: like object): like value is
+ do
+ create Result.make
+ Result.put (json.value (o.name), name_key)
+ Result.put (json.value (o.books), books_key)
+ end
+
+feature {NONE} -- Implementation
+
+ name_key: JSON_STRING is
+ once
+ create Result.make_json ("name")
+ end
+
+ books_key: JSON_STRING is
+ once
+ create Result.make_json ("books")
+ end
+
+end -- class JSON_BOOK_COLLECTION_CONVERTER
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/json_book_converter.e b/contrib/library/text/parser/json/test/getest/json_book_converter.e
new file mode 100644
index 00000000..e3e61367
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/json_book_converter.e
@@ -0,0 +1,75 @@
+indexing
+ description: "A JSON converter for BOOK"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+ file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_converter.e $"
+
+class JSON_BOOK_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make is
+ local
+ ucs: UC_STRING
+ a: AUTHOR
+ do
+ create ucs.make_from_string ("")
+ create a.make (ucs)
+ create object.make (ucs, a, ucs)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: BOOK
+
+feature -- Conversion
+
+ from_json (j: like value): like object is
+ local
+ ucs1, ucs2: UC_STRING
+ a: AUTHOR
+ do
+ ucs1 ?= json.object (j.item (title_key), Void)
+ check ucs1 /= Void end
+ ucs2 ?= json.object (j.item (isbn_key), Void)
+ check ucs2 /= Void end
+ a ?= json.object (j.item (author_key), "AUTHOR")
+ check a /= Void end
+ create Result.make (ucs1, a, ucs2)
+ end
+
+ to_json (o: like object): like value is
+ do
+ create Result.make
+ Result.put (json.value (o.title), title_key)
+ Result.put (json.value (o.isbn), isbn_key)
+ Result.put (json.value (o.author), author_key)
+ end
+
+feature {NONE} -- Implementation
+
+ title_key: JSON_STRING is
+ once
+ create Result.make_json ("title")
+ end
+
+ isbn_key: JSON_STRING is
+ once
+ create Result.make_json ("isbn")
+ end
+
+ author_key: JSON_STRING is
+ once
+ create Result.make_json ("author")
+ end
+
+end -- class JSON_BOOK_CONVERTER
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/readme.txt b/contrib/library/text/parser/json/test/getest/readme.txt
new file mode 100644
index 00000000..56294420
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/readme.txt
@@ -0,0 +1,10 @@
+To compile and run the test program do as follows:
+
+1. Make sure you have a compiled version of getest in your PATH.
+
+2. In this dircetory, run the command:
+
+ $ getest --verbose --ise ejson_test.cfg
+
+
+Note: on Windows, you should use ejson_test-win.cfg
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/test_ds.e b/contrib/library/text/parser/json/test/getest/test_ds.e
new file mode 100644
index 00000000..88bf0d81
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/test_ds.e
@@ -0,0 +1,71 @@
+class TEST_DS
+
+inherit
+ SHARED_GOBO_EJSON
+
+ TS_TEST_CASE
+
+create
+ make_default
+
+feature {NONE} -- Initialization
+
+ make is
+ -- Create test object.
+ do
+ end
+
+feature -- Test
+
+ test_ds_linked_list_converter is
+ local
+ jc: JSON_DS_LINKED_LIST_CONVERTER
+ l: DS_LINKED_LIST [STRING]
+ l2: DS_LINKED_LIST [ANY]
+ s: STRING
+ jv: JSON_VALUE
+ do
+ create jc.make
+ json.add_converter (jc)
+ create l.make
+ s := "foo"
+ l.put_last (s)
+ s := "bar"
+ l.put_last (s)
+ jv := json.value (l)
+ assert ("jv /= Void", jv /= Void)
+ s := jv.representation
+ l2 ?= json.object (jv, "DS_LINKED_LIST")
+ assert ("l2 /= Void", l2 /= Void)
+ end
+
+ test_ds_hash_table_converter is
+ local
+ tc: JSON_DS_HASH_TABLE_CONVERTER
+ t: DS_HASH_TABLE [STRING, STRING]
+ t2: DS_HASH_TABLE [ANY, HASHABLE]
+ s: STRING
+ ucs_key, ucs_value: UC_STRING
+ jv: JSON_VALUE
+ do
+ create tc.make
+ json.add_converter (tc)
+ create t.make (2)
+ t.put ("foo", "1")
+ t.put ("bar", "2")
+ jv := json.value (t)
+ assert ("jv /= Void", jv /= Void)
+ s := jv.representation
+ t2 ?= json.object (jv, "DS_HASH_TABLE")
+ assert ("t2 /= Void", t2 /= Void)
+ create ucs_key.make_from_string ("1")
+ ucs_value ?= t2 @ ucs_key
+ assert ("ucs_value /= Void", ucs_value /= Void)
+ assert ("ucs_value.string.is_equal (%"foo%")", ucs_value.string.is_equal ("foo"))
+ create ucs_key.make_from_string ("2")
+ ucs_value ?= t2 @ ucs_key
+ assert ("ucs_value /= Void", ucs_value /= Void)
+ assert ("ucs_value.string.is_equal (%"bar%")", ucs_value.string.is_equal ("bar"))
+ end
+
+end -- class TEST_DS
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/test_json_core.e b/contrib/library/text/parser/json/test/getest/test_json_core.e
new file mode 100644
index 00000000..3396d17e
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/test_json_core.e
@@ -0,0 +1,703 @@
+class TEST_JSON_CORE
+
+inherit
+ TS_TEST_CASE
+ SHARED_EJSON
+
+create
+ make_default
+
+feature {NONE} -- Initialization
+
+ make is
+ -- Create test object.
+ do
+ end
+
+feature -- Test
+
+ test_json_number_and_integer is
+ local
+ i: INTEGER
+ i8: INTEGER_8
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i := 42
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn := Void
+ jn ?= json.value (i)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42"))
+ -- JSON representation-> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_8 since the value is 42
+ jrep := "42"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i8 := 0
+ i8 ?= json.object (jn, Void)
+ assert ("i8 = 42", i8 = 42)
+ end
+
+ test_json_number_and_integer_8 is
+ local
+ i8: INTEGER_8
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i8 := 42
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i8)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn := Void
+ jn ?= json.value (i8)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_8 since the value is 42
+ jrep := "42"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i8 := 0
+ i8 ?= json.object (jn, Void)
+ assert ("i8 = 42", i8 = 42)
+ end
+
+ test_json_number_and_integer_16 is
+ local
+ i16: INTEGER_16
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i16 := 300
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i16)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"300%")", jn.representation.is_equal ("300"))
+ -- Eiffel value -> JSON with factory
+ jn := Void
+ jn ?= json.value (i16)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"300%")", jn.representation.is_equal ("300"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_16 since the value is 300
+ jrep := "300"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i16 := 0
+ i16 ?= json.object (jn, Void)
+ assert ("i16 = 300", i16 = 300)
+ end
+
+ test_json_number_and_integer_32 is
+ local
+ i32: INTEGER_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i32 := 100000
+ -- Eiffel value -> JSON representation -> JSON value
+ create jn.make_integer (i32)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"100000%")", jn.representation.is_equal ("100000"))
+ -- Eiffel value -> JSON representation -> JSON value with factory
+ jn := Void
+ jn ?= json.value (i32)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"100000%")", jn.representation.is_equal ("100000"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 100000
+ jrep := "100000"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i32 := 0
+ i32 ?= json.object (jn, Void)
+ assert ("i32 = 100000", i32 = 100000)
+ end
+
+ test_json_number_and_integer_64 is
+ local
+ i64: INTEGER_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i64 := 42949672960
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i64)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"42949672960%")", jn.representation.is_equal ("42949672960"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn := Void
+ jn ?= json.value (i64)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"42949672960%")", jn.representation.is_equal ("42949672960"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 42949672960
+ jrep := "42949672960"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i64 := 0
+ i64 ?= json.object (jn, Void)
+ assert ("i64 = 42949672960", i64 = 42949672960)
+ end
+
+ test_json_number_and_natural_8 is
+ local
+ n8: NATURAL_8
+ i16: INTEGER_16
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n8 := 200
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n8)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"200%")", jn.representation.is_equal ("200"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn := Void
+ jn ?= json.value (n8)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"200%")", jn.representation.is_equal ("200"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_16 since the value is 200
+ jrep := "200"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i16 := 0
+ i16 ?= json.object (jn, Void)
+ assert ("i16 = 200", i16 = 200)
+ end
+
+ test_json_number_and_natural_16 is
+ local
+ n16: NATURAL_16
+ i32: INTEGER_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n16 := 32768
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n16)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"32768%")", jn.representation.is_equal ("32768"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn := Void
+ jn ?= json.value (n16)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"32768%")", jn.representation.is_equal ("32768"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 32768
+ jrep := "32768"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i32 := 0
+ i32 ?= json.object (jn, Void)
+ assert ("i32 = 32768", i32 = 32768)
+ end
+
+ test_json_number_and_natural_32 is
+ local
+ n32: NATURAL_32
+ i64: INTEGER_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n32 := 2147483648
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n32)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"2147483648%")", jn.representation.is_equal ("2147483648"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn := Void
+ jn ?= json.value (n32)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"2147483648%")", jn.representation.is_equal ("2147483648"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_64 since the value is 2147483648
+ jrep := "2147483648"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ i64 := 0
+ i64 ?= json.object (jn, Void)
+ assert ("i64 = 2147483648", i64 = 2147483648)
+ end
+
+ test_json_number_and_large_integers is
+ local
+ jrep: STRING
+ jn: JSON_NUMBER
+ n64: NATURAL_64
+ parser: JSON_PARSER
+ do
+ n64 := 9223372036854775808
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n64)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"9223372036854775808%")", jn.representation.is_equal ("9223372036854775808"))
+ jn := Void
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (n64)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"9223372036854775808%")", jn.representation.is_equal ("9223372036854775808"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 42949672960
+ jrep := "9223372036854775808" -- 1 higher than largest positive number that can be represented by INTEGER 64
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ n64 := 0
+ n64 ?= json.object (jn, Void)
+ end
+
+ test_json_number_and_eiffel_real is
+ local
+ r: REAL
+ r64: REAL_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r := 3.14
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (r)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will always return a REAL_64 if the value
+ -- of the JSON number is a floating point number
+ jrep := "3.14"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ r64 := 0
+ r64 ?= json.object (jn, Void)
+ assert ("r64 = 3.1400000000000001", r64 = 3.1400000000000001)
+ end
+
+ test_json_number_and_eiffel_real_32 is
+ local
+ r32: REAL_32
+ r64: REAL_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r32 := 3.14
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r32)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (r32)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748"))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "3.1400001049041748"
+ create parser.make_parser (jrep)
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ r64 := 0
+ r64 ?= json.object (jn, Void)
+ assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748)
+ end
+
+ test_json_number_and_eiffel_real_64 is
+ local
+ r64: REAL_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r64 := 3.1415926535897931
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r64)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"3.1415926535897931%")", jn.representation.is_equal ("3.1415926535897931"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (r64)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"3.1415926535897931%")", jn.representation.is_equal ("3.1415926535897931"))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "3.1415926535897931"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ r64 := 0
+ r64 ?= json.object (jn, Void)
+ assert ("r64 = 3.1415926535897931", r64 = 3.1415926535897931)
+ end
+
+ test_json_boolean is
+ local
+ b: BOOLEAN
+ jb: JSON_BOOLEAN
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ b := True
+ -- Eiffel value -> JSON value -> JSON representation
+ create jb.make_boolean (b)
+ assert ("jb /= Void", jb /= Void)
+ assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jb ?= json.value (b)
+ assert ("jb /= Void", jb /= Void)
+ assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true"))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "true"
+ create parser.make_parser (jrep)
+ jb := Void
+ jb ?= parser.parse
+ assert ("jb /= Void", jb /= Void)
+ b := False
+ b ?= json.object (jb, Void)
+ assert ("b = True", b = True)
+
+ b := False
+ -- Eiffel value -> JSON value -> JSON representation
+ create jb.make_boolean (b)
+ assert ("jb /= Void", jb /= Void)
+ assert ("jb.representation.is_equal (%"false%")", jb.representation.is_equal ("false"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jb ?= json.value (b)
+ assert ("jb /= Void", jb /= Void)
+ assert ("jb.representation.is_equal (%"false%")", jb.representation.is_equal ("false"))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "false"
+ create parser.make_parser (jrep)
+ jb := Void
+ jb ?= parser.parse
+ assert ("jb /= Void", jb /= Void)
+ b := True
+ b ?= json.object (jb, Void)
+ assert ("b = False", b = False)
+ end
+
+ test_json_null is
+ local
+ a: ANY
+ dummy_object: STRING
+ jn: JSON_NULL
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"%"null%"%")", jn.representation.is_equal ("null"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (Void)
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"null%")", jn.representation.is_equal ("null"))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "null"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ create dummy_object.make_empty
+ a := dummy_object
+ a ?= json.object (jn, Void)
+ assert ("a = Void", a = Void)
+ end
+
+ test_json_string_and_character is
+ local
+ c: CHARACTER
+ js: JSON_STRING
+ ucs: UC_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ c := 'a'
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (c.out)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (c)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%""))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"a%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ ucs ?= json.object (js, Void)
+ assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a"))
+ end
+
+ test_json_string_and_string is
+ local
+ s: STRING
+ js: JSON_STRING
+ ucs: UC_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ s := "foobar"
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (s)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (s)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foobar%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ ucs ?= json.object (js, Void)
+ assert ("ucs.string.is_equal (%"foobar%")", ucs.string.is_equal ("foobar"))
+ end
+
+ test_json_string_and_uc_string is
+ local
+ js: JSON_STRING
+ ucs: UC_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ create ucs.make_from_string ("foobar")
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (ucs)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (ucs)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foobar%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ ucs := Void
+ ucs ?= json.object (js, Void)
+ assert ("ucs.string.is_equal (%"foobar%")", ucs.string.is_equal ("foobar"))
+ end
+
+ test_json_array is
+ local
+ ll: LINKED_LIST [INTEGER_8]
+ ll2: LINKED_LIST [ANY]
+ ja: JSON_ARRAY
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ i, n: INTEGER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ create ll.make
+ ll.extend (0)
+ ll.extend (1)
+ ll.extend (1)
+ ll.extend (2)
+ ll.extend (3)
+ ll.extend (5)
+ -- Note: Currently there is no simple way of creating a JSON_ARRAY
+ -- from an LINKED_LIST.
+ create ja.make_array
+ from
+ ll.start
+ until
+ ll.after
+ loop
+ create jn.make_integer (ll.item)
+ ja.add (jn)
+ ll.forth
+ end
+ assert ("ja /= Void", ja /= Void)
+ assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ ja := Void
+ ja ?= json.value (ll)
+ assert ("ja /= Void", ja /= Void)
+ assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]"))
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- it means we will get an LINKED_LIST [ANY] containing the INTEGER_8
+ -- values 0, 1, 1, 2, 3, 5
+ jrep := "[0,1,1,2,3,5]"
+ create parser.make_parser (jrep)
+ ja := Void
+ ja ?= parser.parse
+ assert ("ja /= Void", ja /= Void)
+ ll2 ?= json.object (ja, Void)
+ assert ("ll2 /= Void", ll2 /= Void)
+ --ll.compare_objects
+ --ll2.compare_objects
+ assert ("ll2.is_equal (ll)", ll2.is_equal (ll))
+ end
+
+ test_json_object is
+ local
+ t, t2: HASH_TABLE [ANY, UC_STRING]
+ i: INTEGER
+ ucs_key, ucs: UC_STRING
+ a: ARRAY [INTEGER]
+ jo: JSON_OBJECT
+ jn: JSON_NUMBER
+ js_key, js: JSON_STRING
+ ja: JSON_ARRAY
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ -- Note: Currently there is now way of creating a JSON_OBJECT from
+ -- a DS_HASH_TABLE, so we do it manually.
+ -- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]}
+ create jo.make
+ create js_key.make_json ("name")
+ create js.make_json ("foobar")
+ jo.put (js, js_key)
+ create js_key.make_json ("size")
+ create jn.make_integer (42)
+ jo.put (jn, js_key)
+ create js_key.make_json ("contents")
+ create ja.make_array
+ create jn.make_integer (0)
+ ja.add (jn)
+ create jn.make_integer (1)
+ ja.add (jn)
+ create jn.make_integer (1)
+ ja.add (jn)
+ create jn.make_integer (2)
+ ja.add (jn)
+ create jn.make_integer (3)
+ ja.add (jn)
+ create jn.make_integer (5)
+ ja.add (jn)
+ jo.put (ja, js_key)
+ assert ("jo /= Void", jo /= Void)
+ assert ("jo.representation.is_equal (%"{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}%")", jo.representation.is_equal ("{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ create t.make (3)
+ create ucs_key.make_from_string ("name")
+ create ucs.make_from_string ("foobar")
+ t.put (ucs, ucs_key)
+ create ucs_key.make_from_string ("size")
+ i := 42
+ t.put (i, ucs_key)
+ create ucs_key.make_from_string ("contents")
+ a := <<0, 1, 1, 2, 3, 5>>
+ t.put (a, ucs_key)
+ jo := Void
+ jo ?= json.value (t)
+ assert ("jo /= Void", jo /= Void)
+ assert ("jo.representation.is_equal (%"{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}%")", jo.representation.is_equal ("{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}"))
+ -- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation
+ jrep := "{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}"
+ create parser.make_parser (jrep)
+ jo := Void
+ jo ?= parser.parse
+ assert ("jo /= Void", jo /= Void)
+ t2 ?= json.object (jo, Void)
+ assert ("t2 /= Void", t2 /= Void)
+ jo ?= json.value (t2)
+ assert ("jo /= Void", jo /= Void)
+ assert ("jrep.is_equal (jo.representation)", jrep.is_equal (jo.representation))
+ end
+
+ test_json_failed_json_conversion is
+ -- Test converting an Eiffel object to JSON that is based on a class
+ -- for which no JSON converter has been registered.
+ local
+ gv: KL_GOBO_VERSION
+ jv: JSON_VALUE
+ exception: BOOLEAN
+ do
+ if not exception then
+ create gv
+ jv := json.value (gv)
+ else
+ assert ("exceptions.is_developer_exception", exceptions.is_developer_exception)
+ assert ("exceptions.is_developer_exception_of_name", exceptions.is_developer_exception_of_name ("eJSON exception: Failed to convert Eiffel object to a JSON_VALUE: KL_GOBO_VERSION"))
+ end
+ rescue
+ exception := True
+ retry
+ end
+
+ test_json_failed_eiffel_conversion is
+ -- Test converting from a JSON value to an Eiffel object based on a
+ -- class for which no JSON converter has been registered.
+ local
+ gv: KL_GOBO_VERSION
+ jo: JSON_OBJECT
+ exception: BOOLEAN
+ do
+ if not exception then
+ create jo.make
+ gv ?= json.object (jo, "KL_GOBO_VERSION")
+ else
+ assert ("exceptions.is_developer_exception", exceptions.is_developer_exception)
+ assert ("exceptions.is_developer_exception_of_name", exceptions.is_developer_exception_of_name ("eJSON exception: Failed to convert JSON_VALUE to an Eiffel object: JSON_OBJECT -> KL_GOBO_VERSION"))
+ end
+ rescue
+ exception := True
+ retry
+ end
+
+end -- class TEST_JSON_CORE
\ No newline at end of file
diff --git a/contrib/library/text/parser/json/test/getest/test_json_custom_classes.e b/contrib/library/text/parser/json/test/getest/test_json_custom_classes.e
new file mode 100644
index 00000000..e9d99d26
--- /dev/null
+++ b/contrib/library/text/parser/json/test/getest/test_json_custom_classes.e
@@ -0,0 +1,49 @@
+class TEST_JSON_CUSTOM_CLASSES
+
+inherit
+ SHARED_EJSON
+
+ TS_TEST_CASE
+
+create
+ make_default
+
+feature {NONE} -- Initialization
+
+ make is
+ -- Create test object.
+ do
+ end
+
+feature -- Test
+
+ test_custom_classes is
+ local
+ bc: BOOK_COLLECTION
+ jbc: JSON_BOOK_CONVERTER
+ jbcc: JSON_BOOK_COLLECTION_CONVERTER
+ jac: JSON_AUTHOR_CONVERTER
+ jo: JSON_OBJECT
+ parser: JSON_PARSER
+ jrep: STRING
+ do
+ create jbc.make
+ json.add_converter (jbc)
+ create jbcc.make
+ json.add_converter (jbcc)
+ create jac.make
+ json.add_converter (jac)
+ jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"
+ create parser.make_parser (jrep)
+ jo := Void
+ jo ?= parser.parse
+ assert ("jo /= Void", jo /= Void)
+ bc := Void
+ bc ?= json.object (jo, "BOOK_COLLECTION")
+ assert ("bc /= Void", bc /= Void)
+ jo ?= json.value (bc)
+ assert ("jo /= Void", jo /= Void)
+ assert ("JSON representation is correct", jo.representation.is_equal ("{%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}],%"name%":%"Test collection%"}"))
+ end
+
+end -- class TEST_JSON_CUSTOM_CLASS
diff --git a/contrib/library/text/parser/json/test/run_autotest.bat b/contrib/library/text/parser/json/test/run_autotest.bat
new file mode 100644
index 00000000..c1eb1eaf
--- /dev/null
+++ b/contrib/library/text/parser/json/test/run_autotest.bat
@@ -0,0 +1,27 @@
+@echo off
+setlocal
+set TMP_EC_SCRIPT_FILENAME=%~dp0.tmp_ec_scripting
+
+cd %~dp0autotest\test_suite
+set TMP_EC_CMD=ec -config test_suite-safe.ecf -target test_suite -batch
+
+echo # Fresh Compilation
+%TMP_EC_CMD% -batch -clean -freeze -c_compile -project_path . > %~dp0autotest.compile.log 2>&1
+
+rem Build scripting for freeze + testing
+rem ------------------------------------
+rem Testing
+echo T > %TMP_EC_SCRIPT_FILENAME%
+rem Execute
+echo e >> %TMP_EC_SCRIPT_FILENAME%
+rem Quit
+echo Q >> %TMP_EC_SCRIPT_FILENAME%
+
+echo # Execute test_suite
+type %TMP_EC_SCRIPT_FILENAME% | %TMP_EC_CMD% -loop 1> :NULL 2> %~dp0autotest.testing.log
+type %~dp0autotest.testing.log
+
+cd %~dp0
+
+del %TMP_EC_SCRIPT_FILENAME%
+endlocal