# See the License for the specific language governing permissions and
# limitations under the License.
-import json
+import json::static
var text = args.first.to_path.read_all
var json = text.parse_json
ios-release: $(shell nitls -M src/client/ios.nit) ios/AppIcon.appiconset/Contents.json
mkdir -p bin/
- nitc -o bin/benitlux.app src/client/ios.nit -D benitlux_rest_server_uri=http://$(SERVER)/
+ nitc -o bin/benitlux.app src/client/ios.nit \
+ -D benitlux_rest_server_uri=http://xymus.net/benitlux/ --release \
+ --compile-dir nit_compile
ios/AppIcon.appiconset/Contents.json: art/icon.svg
mkdir -p ios
import app::data_store
import app::http_request
import android::aware
-import json::serialization
+import json
import benitlux_model
import translations
import nitcorn
import nitcorn::restful
-private import json::serialization
+private import json
import benitlux_model
import benitlux_db
module model::descriptions
import json::static
+import json
# Documentation associated to an entity.
#
# Is the documentation empty?
fun is_empty: Bool do return content.is_empty
- redef fun to_json do return content.to_json
- redef fun append_json(b) do content.append_json(b)
+ redef fun serialize_to(v) do content.serialize_to v
+ redef fun accept_json_serializer(v) do content.serialize_to v
end
# A `Jsonable` array of strings.
abstract class Compound
super Entity
- # Set the declared visibility (the proctection) of the compound.
+ # Set the declared visibility (the protection) of the compound.
fun visibility=(visibility: String) do
self["visibility"] = visibility
end
# Declare an inner namespace.
#
- # Note: Althought Doxygen indicates that the name is optional,
+ # Note: Although Doxygen indicates that the name is optional,
# declarations with an empty name are not supported yet, except for the root
# namespace. For the root namespace, both arguments are empty.
#
# Declare an inner class.
#
- # Note: Althought Doxygen indicates that both arguments are optional,
+ # Note: Although Doxygen indicates that both arguments are optional,
# declarations with an empty ID are not supported yet.
#
# Parameters:
self.labels.add("MGroup")
end
- redef fun declare_namespace(id: String, full_name: String) do
+ redef fun declare_namespace(id, full_name) do
inner_namespaces.add new NamespaceRef(id, full_name)
end
module location
import json::static
+import json
# A location inside a source file.
class Location
# The one-based column index of the last character.
var column_end: Int = 1 is writable
- redef fun to_s: String do
+ redef fun to_s do
+ var path = path
var file_part = "/dev/null:"
- if path != null and path.length > 0 then file_part = "{path.as(not null)}:"
+ if path != null and path.length > 0 then file_part = "{path}:"
return "{file_part}{line_start},{column_start}--{line_end},{column_end}"
end
- redef fun to_json do return to_s.to_json
+ redef fun serialize_to(v) do to_s.serialize_to v
+ redef fun accept_json_serializer(v) do to_s.serialize_to v
end
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import model::descriptions
-
-# Copied from the documentation of `Documentation`.
-
-var doc = new Documentation
-
-doc.brief_description = "Do something."
-doc.detailed_description = ["Do not lunch a rocket."]
-assert doc.brief_description == "Do something."
-assert doc.detailed_description == ["Do not lunch a rocket."]
-assert doc.to_json == """["Do something.","Do not lunch a rocket."]"""
-
-doc.brief_description = ""
-doc.detailed_description = ["The answer is `42`."]
-assert doc.brief_description == "The answer is `42`."
-assert doc.detailed_description == ["The answer is `42`."]
-assert doc.to_json == """["The answer is `42`."]"""
-
-doc.detailed_description = ["The answer is `42`."]
-doc.brief_description = ""
-assert doc.brief_description == "The answer is `42`."
-assert doc.detailed_description == ["The answer is `42`."]
-assert doc.to_json == """["The answer is `42`."]"""
-
-doc.detailed_description = new Array[String]
-doc.brief_description = ""
-assert doc.is_empty
-assert doc.brief_description == ""
-assert doc.detailed_description == new Array[String]
-assert doc.to_json == "[]"
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import model::member
-
-# Copied from the documentation of `Member::resolve_introducer`.
-
-var g = new ProjectGraph("foo")
-var m1 = new Attribute(g)
-var m2 = new Attribute(g)
-var m3 = new Attribute(g)
-
-m1.model_id = "1"
-m1.put_in_graph
-m2.reimplement("1")
-m2.put_in_graph
-assert m1.resolve_introducer == m1.introducer
-assert m2.resolve_introducer == m1.introducer
-
-m3.model_id = "3"
-m3.reimplement("3")
-m3.put_in_graph
-assert m3.resolve_introducer == null
json["reward"].as(Int))
end
- redef fun to_json do
+ redef fun to_json_object do
var json = super
json["id"] = id
json["name"] = name
time = new ISODate.from_string(json["time"].as(String))
end
- redef fun to_json do
+ redef fun to_json_object do
var json = new JsonObject
json["internal_id"] = internal_id.to_s
json["kind"] = kind
fun key: String is abstract
# Saves `self` in db.
- fun save do game.db.collection(collection_name).save(to_json)
+ fun save do game.db.collection(collection_name).save(to_json_object)
# Json representation of `self`.
- fun to_json: JsonObject do
+ fun to_json_object: JsonObject do
var json = new JsonObject
json["_id"] = key
return json
# Used to load entities from saved data.
fun from_json(json: JsonObject) do end
- redef fun to_json do
+ redef fun to_json_object do
var json = super
json["name"] = name
return json
end
# Erase all saved data for this game.
- fun clear do db.collection(collection_name).remove(to_json)
+ fun clear do db.collection(collection_name).remove(to_json_object)
# Verbosity level used fo stdout.
#
nitcoins = json["nitcoins"].as(Int)
end
- redef fun to_json do
+ redef fun to_json_object do
var json = super
json["game"] = game.key
json["name"] = name
for k, v in values do self[k] = v.as(Int)
end
- redef fun to_json do
+ redef fun to_json_object do
var obj = super
obj["period"] = period
obj["owner"] = owner.key
var a3 = new Achievement(game, "test_id3", "test_name", "test_desc", 15)
game.add_achievement(a1)
game.add_achievement(a2)
- game.db.collection("achievements").insert(a3.to_json)
+ game.db.collection("achievements").insert(a3.to_json_object)
var ok = [a1.id, a2.id]
var res = game.load_achievements
assert res.length == 2
var event3 = new GameEvent(game, "test_kind", new JsonObject)
game.add_event(event1)
game.add_event(event2)
- game.db.collection("events").insert(event3.to_json)
+ game.db.collection("events").insert(event3.to_json_object)
var ok = [event1.internal_id, event2.internal_id]
var res = game.load_events
assert res.length == 2
var db = gen_test_db
var game = load_game("Morriar/nit", db)
var event = new GameEvent(game, "test_kind", new JsonObject)
- assert event.to_json["kind"] == "test_kind"
+ assert event.to_json_object["kind"] == "test_kind"
end
fun test_init_from_json do
var player1 = new Player(game, "Morriar")
var player2 = new Player(ogame, "privat")
- game.db.collection("players").insert(player1.to_json)
- ogame.db.collection("players").insert(player2.to_json)
+ game.db.collection("players").insert(player1.to_json_object)
+ ogame.db.collection("players").insert(player2.to_json_object)
assert game.load_player("privat") == null
assert game.load_player("Morriar").name == "Morriar"
var player1 = new Player(game, "Morriar")
var player2 = new Player(ogame, "privat")
var player3 = new Player(game, "xymus")
- game.db.collection("players").insert(player1.to_json)
- ogame.db.collection("players").insert(player2.to_json)
- game.db.collection("players").insert(player3.to_json)
+ game.db.collection("players").insert(player1.to_json_object)
+ ogame.db.collection("players").insert(player2.to_json_object)
+ game.db.collection("players").insert(player3.to_json_object)
var players = game.load_players
var ok = ["Morriar", "xymus"]
import refund_base
import json::static
+import json
redef class RefundProcessor
fun write_output(str: String, file: String) do
var ofs = new FileWriter.open(file)
ofs.write(str)
+ ofs.write("\n")
ofs.close
end
exit 1
end
- redef fun show_stats do print load_stats.to_json.to_pretty_json
+ redef fun show_stats do print load_stats.to_json_object.to_pretty_json
redef fun load_stats do
# If no stats found, return a new object
end
redef fun save_stats(stats) do
- write_output(stats.to_json.to_pretty_json, stats_file)
+ write_output(stats.to_json_object.to_pretty_json, stats_file)
end
end
end
# Outputs `self` as a JSON string.
- fun to_json: JsonObject do
+ fun to_json_object: JsonObject do
var obj = new JsonObject
for k, v in self do obj[k] = v
return obj
{
- "message": "Wrong input file (Unexpected Eof; is acceptable instead: value)"
+ "message": "Wrong input file (Empty JSON)"
}
{
- "message": "Wrong input file (Unexpected Eof; is acceptable instead: members, pair)"
+ "message": "Wrong input file (Malformed JSON object)"
}
import popcorn
import shibuqam
-import json::serialization
+import json
redef class HttpRequest
# percent decoded get or post parameter.
redef class User
super Jsonable
- redef fun to_json do return serialize_to_json(plain=true)
end
# Information about an authenticated used stored on the server to be given to the client.
import mnit::linux
import linux::audio
-import json::serialization
+import json
import client
module action
import nitcorn
-import json::serialization
+import json
import model
import database
module push
import nitcorn
-import json::serialization
+import json
import model
import database
import app::http_request
import app::data_store
import android::aware
-import json::serialization
+import json
import model
# SEE: <http://rosettacode.org/wiki/JSON>
module json_output
+import json::static
import json
var str = """{
module bundle
import serialization
-import json::serialization
+import json
import platform
import activities
import dalvik
import android::bundle
import serialization
-private import json::serialization
+private import json
in "Java" `{
import android.content.Intent;
import dalvik
import serialization
-private import json::serialization
+private import json
in "Java" `{
import android.content.SharedPreferences;
import app_base
import pthreads
-import json::serialization
+import json
import linux::http_request is conditional(linux)
import android::http_request is conditional(android)
module api
import github_curl
-intrude import json::serialization
+intrude import json::serialization_read
# Client to Github API
#
# Github page url.
var html_url: nullable String is writable
-
- redef fun to_json do return serialize_to_json
end
# A Github user
redef class ISODate
super Jsonable
serialize
-
- redef fun to_json do return serialize_to_json
end
# JsonDeserializer specific for Github objects.
module events
import api
-intrude import json::serialization
+intrude import json
# Github event stub.
class GithubEvent
# Repo where this event occured.
var repo: Repo is writable
-
- redef fun to_json do return serialize_to_json
end
# Triggered when a commit comment is created.
import curl
import json::static
+import json
# Specific Curl that know hot to talk to the github API
class GithubCurl
json["message"] = message.to_json
end
- redef fun to_json do
- return json.to_json
- end
+ redef fun serialize_to(v) do json.serialize_to v
redef fun to_s do return "[{name}] {super}"
end
import app::data_store
import cocoa::foundation
-private import json::serialization
+private import json
redef class App
redef var data_store = new UserDefaultView
--- /dev/null
+read and write JSON formatted text
+
+These services can be useful to communicate with a remote server or client,
+save data locally or even debug and understand the structure of a Nit object.
+There is a single API to write JSON, and three API to read depending on the use case.
+
+# Write JSON
+
+Writing Nit objects to JSON format can be useful to communicate with a remote service,
+save data locally or even debug and understand the structure of an object.
+There is two related services to write JSON object, the method
+`serialize_to_json` and the object `JsonSerializer`.
+The method `serialize_to_json` is actually a shortcut to `JsonSerializer`, both
+share the same features.
+
+## Write plain JSON
+
+Passing the argument `plain=true` to `serialize_to_json` generates plain and clean JSON.
+This format is non-Nit program, it cannot be fully deserialized back to Nit objects.
+The argument `pretty=true` generates JSON for humans, with more spaces and line breaks.
+
+The Nit objects to write must subclass `Serializable` and implement its services.
+Most classes from the `core` library are already supported, including collections, numeric values, etc.
+For your local objects, you can annotate them with `serialize` to automate subclassing
+`Serializable` and the implementation of its services.
+
+### Example
+
+~~~
+class Person
+ serialize
+
+ var name: String
+ var year_of_birth: Int
+ var next_of_kin: nullable Person
+end
+
+var bob = new Person("Bob", 1986)
+assert bob.serialize_to_json(pretty=true, plain=true) == """
+{
+ "name": "Bob",
+ "year_of_birth": 1986,
+ "next_of_kin": null
+}"""
+
+var alice = new Person("Alice", 1978, bob)
+assert alice.serialize_to_json(pretty=true, plain=true) == """
+{
+ "name": "Alice",
+ "year_of_birth": 1978,
+ "next_of_kin": {
+ "name": "Bob",
+ "year_of_birth": 1986,
+ "next_of_kin": null
+ }
+}"""
+
+# You can also build JSON objects as a `Map`
+var charlie = new Map[String, nullable Serializable]
+charlie["name"] = "Charlie"
+charlie["year_of_birth"] = 1968
+charlie["next_of_kin"] = alice
+assert charlie.serialize_to_json(pretty=true, plain=true) == """
+{
+ "name": "Charlie",
+ "year_of_birth": 1968,
+ "next_of_kin": {
+ "name": "Alice",
+ "year_of_birth": 1978,
+ "next_of_kin": {
+ "name": "Bob",
+ "year_of_birth": 1986,
+ "next_of_kin": null
+ }
+ }
+}"""
+~~~
+
+## Write JSON with metadata
+
+By default, `serialize_to_json` and `JsonSerializer` include metadate in the generated JSON.
+This metadata is used by `JsonDeserializer` when reading the JSON code to recreate
+the Nit object with the exact original type.
+The metadata allows to avoid repeating an object and its resolves cycles in the serialized objects.
+
+For more information on Nit serialization, see: ../serialization/README.md
+
+
+# Read JSON
+
+There are a total of 3 API to read JSON:
+* `JsonDeserializer` reads JSON to recreate complex Nit objects (discussed here),
+* the module `json::dynamic` provides an easy API to explore JSON objects,
+* the module `json::static` offers a low-level service to parse JSON and create basic Nit objects.
+
+The class `JsonDeserializer` reads JSON code to recreate objects.
+It can use the metadata in the JSON code, to recreate precise Nit objects.
+Otherwise, JSON objects are recreated to simple Nit types: `Map`, `Array`, etc.
+Errors are reported to the attribute `JsonDeserializer::errors`.
+
+The type to recreate is either declared or inferred:
+
+1. The JSON object defines a `__class` key with the name of the Nit class as value.
+ This attribute is generated by the `JsonSerializer` with other metadata,
+ it can also be specified by other external tools.
+2. A refinement of `JsonDeserializer::class_name_heuristic` identifies the Nit class.
+3. If all else fails, `JsonDeserializer` uses the static type of the attribute,
+ or the type name passed to `deserialize`.
+
+The method `from_json_string` is a shortcut to `JsonDeserializer` which prints
+errors to the console. It is fit only for small scripts and other quick and dirty usage.
+
+### Example
+
+~~~
+class Triangle
+ serialize
+
+ var corners = new Array[Point]
+ redef var to_s is serialize_as("name")
+end
+
+class Point
+ serialize
+
+ var x: Int
+ var y: Int
+end
+
+# Metadata on each JSON object tells the deserializer what is its Nit type,
+# and it supports special types such as generic collections.
+var json_with_metadata = """{
+ "__class": "Triangle",
+ "corners": {"__class": "Array[Point]",
+ "__items": [{"__class": "Point", "x": 0, "y": 0},
+ {"__class": "Point", "x": 3, "y": 0},
+ {"__class": "Point", "x": 2, "y": 2}]},
+ "name": "some triangle"
+}"""
+
+var deserializer = new JsonDeserializer(json_with_metadata)
+var object = deserializer.deserialize
+assert deserializer.errors.is_empty
+assert object != null
+
+# However most non-Nit services won't add the metadata and instead produce plain JSON.
+# Without a "__class", the deserializer relies on `class_name_heuristic` and the static type.
+# The type of the root object to deserialize can be specified by an argument passed to `deserialize`.
+var plain_json = """{
+ "corners": [{"x": 0, "y": 0},
+ {"x": 3, "y": 0},
+ {"x": 2, "y": 2}],
+ "name": "the same triangle"
+}"""
+
+deserializer = new JsonDeserializer(plain_json)
+object = deserializer.deserialize("Triangle")
+assert deserializer.errors.is_empty # If false, `object` is invalid
+~~~
+
+### Missing attributes and default values
+
+When reading JSON, some attributes expected by Nit classes may be missing.
+The JSON object may come from an external API using optional attributes or
+from a previous version of your program without the attributes.
+When an attribute is not found, the deserialization engine acts in one of three ways:
+
+1. If the attribute has a default value or if it is annotated by `lazy`,
+ the engine leave the attribute to the default value. No error is raised.
+2. If the static type of the attribute is nullable, the engine sets
+ the attribute to `null`. No error is raised.
+3. Otherwise, the engine raises an error and does not set the attribute.
+ The caller must check for `errors` and must not read from the attribute.
+
+~~~
+class MyConfig
+ serialize
+
+ var width: Int # Must be in JSON or an error is raised
+ var height = 4
+ var volume_level = 8 is lazy
+ var player_name: nullable String
+ var tmp_dir: nullable String = "/tmp" is lazy
+end
+
+# ---
+# JSON object with all expected attributes -> OK
+var plain_json = """
+{
+ "width": 11,
+ "height": 22,
+ "volume_level": 33,
+ "player_name": "Alice",
+ "tmp_dir": null
+}"""
+var deserializer = new JsonDeserializer(plain_json)
+var obj = deserializer.deserialize("MyConfig")
+
+assert deserializer.errors.is_empty
+assert obj isa MyConfig
+assert obj.width == 11
+assert obj.height == 22
+assert obj.volume_level == 33
+assert obj.player_name == "Alice"
+assert obj.tmp_dir == null
+
+# ---
+# JSON object missing optional attributes -> OK
+plain_json = """
+{
+ "width": 11
+}"""
+deserializer = new JsonDeserializer(plain_json)
+obj = deserializer.deserialize("MyConfig")
+
+assert deserializer.errors.is_empty
+assert obj isa MyConfig
+assert obj.width == 11
+assert obj.height == 4
+assert obj.volume_level == 8
+assert obj.player_name == null
+assert obj.tmp_dir == "/tmp"
+
+# ---
+# JSON object missing the mandatory attribute -> Error
+plain_json = """
+{
+ "player_name": "Bob",
+}"""
+deserializer = new JsonDeserializer(plain_json)
+obj = deserializer.deserialize("MyConfig")
+
+# There's an error, `obj` is partial
+assert deserializer.errors.length == 1
+
+# Still, we can access valid attributes
+assert obj isa MyConfig
+assert obj.player_name == "Bob"
+~~~
# Ill-formed JSON.
class JsonParseError
super Error
+ serialize
# The location of the error in the original text.
var position: nullable Position
# This file is part of NIT ( http://www.nitlanguage.org ).
#
-# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
-# Copyright 2014 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
-#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# See the License for the specific language governing permissions and
# limitations under the License.
-# Libraries to manipulate JSON strings.
-#
-# Both `dynamic` and `static` modules provide at least a method to parse a
-# value written in JSON, but only `static` provide a method to translate a
-# value into JSON.
-#
-# The `dynamic` module provides a simple interface to get information
-# from a JSON document. You must be careful as all services are provided on
-# each nodes and a wrongful use can `abort`.
-#
-# The `static` module provides a common interface for anything that can be
-# translated into a JSON document. The provided parsing method return a
-# nullable Nit object that must then be type-checked before it can be used.
+# Read and write JSON formatted text using the standard serialization services
module json
-import static
-import dynamic
+import serialization_write
+import serialization_read
+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Handles serialization and deserialization of objects to/from JSON
-#
-# ## Writing JSON with metadata
-#
-# `JsonSerializer` write Nit objects that subclass `Serializable` to JSON,
-# and `JsonDeserializer` can read them. They both use metadata added to the
-# generated JSON to recreate the Nit instances with the exact original type.
-#
-# For more information on Nit serialization, see: ../serialization/README.md
-#
-# ## Writing plain JSON
-#
-# The attribute `JsonSerializer::plain_json` triggers generating plain and
-# clean JSON. This format is easier to read for an human and a non-Nit program,
-# but it cannot be fully deserialized. It can still be read by services from
-# `json::static` and `json::dynamic`.
-#
-# A shortcut to these writing services is provided by `Serializable::serialize_to_json`.
-#
-# ### Usage Example
-#
-# ~~~nitish
-# import json::serialization
-#
-# class Person
-# serialize
-#
-# var name: String
-# var year_of_birth: Int
-# var next_of_kin: nullable Person
-# end
-#
-# var bob = new Person("Bob", 1986)
-# var alice = new Person("Alice", 1978, bob)
-#
-# assert bob.serialize_to_json(pretty=true, plain=true) == """
-#{
-# "name": "Bob",
-# "year_of_birth": 1986,
-# "next_of_kin": null
-#}"""
-#
-# assert alice.serialize_to_json(pretty=true, plain=true) == """
-#{
-# "name": "Alice",
-# "year_of_birth": 1978,
-# "next_of_kin": {
-# "name": "Bob",
-# "year_of_birth": 1986,
-# "next_of_kin": null
-# }
-#}"""
-# ~~~
-#
-# ## Read JSON to create Nit objects
-#
-# The `JsonDeserializer` supports reading JSON code with or without metadata.
-# It can create Nit objects from a remote service returning JSON data
-# or to read local configuration files as Nit objects.
-# However, it needs to know which Nit class to recreate from each JSON object.
-# The class is either declared or inferred:
-#
-# 1. The JSON object defines a `__class` key with the name of the Nit class as value.
-# This attribute is generated by the `JsonSerializer` with other metadata,
-# it can also be specified by other external tools.
-# 2. A refinement of `JsonDeserializer::class_name_heuristic` identifies the Nit class.
-# 3. If all else fails, `JsonDeserializer` uses the static type of the attribute.
-#
-# ### Usage Example
-#
-# ~~~nitish
-# import json::serialization
-#
-# class Triangle
-# serialize
-#
-# var corners = new Array[Point]
-# redef var to_s is serialize_as("name")
-# end
-#
-# class Point
-# serialize
-#
-# var x: Int
-# var y: Int
-# end
-#
-# # Metadata on each JSON object tells the deserializer what is its Nit type,
-# # and it supports special types such as generic collections.
-# var json_with_metadata = """{
-# "__class": "Triangle",
-# "corners": {"__class": "Array[Point]",
-# "__items": [{"__class": "Point", "x": 0, "y": 0},
-# {"__class": "Point", "x": 3, "y": 0},
-# {"__class": "Point", "x": 2, "y": 2}]},
-# "name": "some triangle"
-# }"""
-#
-# var deserializer = new JsonDeserializer(json_with_metadata)
-# var object = deserializer.deserialize
-# assert deserializer.errors.is_empty
-# assert object != null
-# print object
-#
-# # However most non-Nit services won't add the metadata and instead produce plain JSON.
-# # Without a "__class", the deserializer relies on `class_name_heuristic` and the static type.
-# # The type of the root object to deserialize can be specified by calling
-# # its deserialization constructor `from_deserializer`.
-# var plain_json = """{
-# "corners": [{"x": 0, "y": 0},
-# {"x": 3, "y": 0},
-# {"x": 2, "y": 2}],
-# "name": "the same triangle"
-# }"""
-#
-# deserializer = new JsonDeserializer(plain_json)
-# object = new Triangle.from_deserializer(deserializer)
-# assert deserializer.errors.is_empty # If false, `obj` is invalid
-# print object
-# ~~~
-#
-# ### Missing attributes and default values
-#
-# When reading JSON, some attributes expected by Nit classes may be missing.
-# The JSON object may come from an external API using optional attributes or
-# from a previous version of your program without the attributes.
-# When an attribute is not found, the deserialization engine acts in one of three ways:
-#
-# 1. If the attribute has a default value or if it is annotated by `lazy`,
-# the engine leave the attribute to the default value. No error is raised.
-# 2. If the static type of the attribute is nullable, the engine sets
-# the attribute to `null`. No error is raised.
-# 3. Otherwise, the engine raises an error and does not set the attribute.
-# The caller must check for `errors` and must not read from the attribute.
-#
-# ~~~nitish
-# import json::serialization
-#
-# class MyConfig
-# serialize
-#
-# var width: Int # Must be in JSON or an error is raised
-# var height = 4
-# var volume_level = 8 is lazy
-# var player_name: nullable String
-# var tmp_dir: nullable String = "/tmp" is lazy
-# end
-#
-# # ---
-# # JSON object with all expected attributes -> OK
-# var plain_json = """
-# {
-# "width": 11,
-# "height": 22,
-# "volume_level": 33,
-# "player_name": "Alice",
-# "tmp_dir": null
-# }"""
-# var deserializer = new JsonDeserializer(plain_json)
-# var obj = new MyConfig.from_deserializer(deserializer)
-#
-# assert deserializer.errors.is_empty
-# assert obj.width == 11
-# assert obj.height == 22
-# assert obj.volume_level == 33
-# assert obj.player_name == "Alice"
-# assert obj.tmp_dir == null
-#
-# # ---
-# # JSON object missing optional attributes -> OK
-# plain_json = """
-# {
-# "width": 11
-# }"""
-# deserializer = new JsonDeserializer(plain_json)
-# obj = new MyConfig.from_deserializer(deserializer)
-#
-# assert deserializer.errors.is_empty
-# assert obj.width == 11
-# assert obj.height == 4
-# assert obj.volume_level == 8
-# assert obj.player_name == null
-# assert obj.tmp_dir == "/tmp"
-#
-# # ---
-# # JSON object missing the mandatory attribute -> Error
-# plain_json = """
-# {
-# "player_name": "Bob",
-# }"""
-# deserializer = new JsonDeserializer(plain_json)
-# obj = new MyConfig.from_deserializer(deserializer)
-#
-# # There's an error, `obj` is partial
-# assert deserializer.errors.length == 1
-#
-# # Still, we can access valid attributes
-# assert obj.player_name == "Bob"
-# ~~~
-module serialization
-
-import ::serialization::caching
-private import ::serialization::engine_tools
-private import static
-private import string_parser
-
-# Serializer of Nit objects to Json string.
-class JsonSerializer
- super CachingSerializer
-
- # Target writing stream
- var stream: Writer
-
- # Write plain JSON? Standard JSON without metadata for deserialization
- #
- # If `false`, the default, serialize to support deserialization:
- #
- # * Write metadata, including the types of the serialized objects so they can
- # be deserialized to their original form using `JsonDeserializer`.
- # * Use references when an object has already been serialized so to not duplicate it.
- # * Support cycles in references.
- # * Preserve the Nit `Char` type as an object because it does not exist in JSON.
- # * The generated JSON is standard and can be read by non-Nit programs.
- # However, some Nit types are not represented by the simplest possible JSON representation.
- # With the added metadata, it can be complex to read.
- #
- # If `true`, serialize for other programs:
- #
- # * Nit objects are serialized to pure and standard JSON so they can
- # be easily read by non-Nit programs and humans.
- # * Nit objects are serialized for every references, so they can be duplicated.
- # It is easier to read but it creates a larger output.
- # * Does not support cycles, will replace the problematic references by `null`.
- # * Does not serialize the metadata needed to deserialize the objects
- # back to regular Nit objects.
- # * Keys of Nit `HashMap` are converted to their string representation using `to_s`.
- var plain_json = false is writable
-
- # Write pretty JSON for human eyes?
- #
- # Toggles skipping lines between attributes of an object and
- # properly indent the written JSON.
- var pretty_json = false is writable
-
- # Current indentation level used for writing `pretty_json`
- private var indent_level = 0
-
- # List of the current open objects, the first is the main target of the serialization
- #
- # Used only when `plain_json == true` to detect cycles in serialization.
- private var open_objects = new Array[Object]
-
- # Has the first attribute of the current object already been serialized?
- #
- # Used only when `plain_json == true`.
- private var first_attribute = false
-
- redef fun serialize(object)
- do
- if object == null then
- stream.write "null"
- else
- if plain_json then
- for o in open_objects do
- if object.is_same_serialized(o) then
- # Cycle, can't be managed in plain json
- warn "Cycle detected in serialized object, replacing reference with 'null'."
- stream.write "null"
- return
- end
- end
-
- open_objects.add object
- end
-
- first_attribute = true
- object.accept_json_serializer self
- first_attribute = false
-
- if plain_json then open_objects.pop
- end
- end
-
- redef fun serialize_attribute(name, value)
- do
- if not plain_json or not first_attribute then
- stream.write ","
- first_attribute = false
- end
-
- new_line_and_indent
- stream.write "\""
- stream.write name
- stream.write "\": "
- super
- end
-
- redef fun serialize_reference(object)
- do
- if not plain_json and cache.has_object(object) then
- # if already serialized, add local reference
- var id = cache.id_for(object)
- stream.write "\{"
- indent_level += 1
- new_line_and_indent
- stream.write "\"__kind\": \"ref\", \"__id\": "
- stream.write id.to_s
- indent_level -= 1
- new_line_and_indent
- stream.write "\}"
- else
- # serialize here
- serialize object
- end
- end
-
- # Write a new line and indent it, only if `pretty_json`
- private fun new_line_and_indent
- do
- if pretty_json then
- stream.write "\n"
- for i in indent_level.times do stream.write "\t"
- end
- end
-end
-
-# Deserializer from a Json string.
-class JsonDeserializer
- super CachingDeserializer
-
- # Json text to deserialize from.
- private var text: Text
-
- # Root json object parsed from input text.
- private var root: nullable Object is noinit
-
- # Depth-first path in the serialized object tree.
- private var path = new Array[Map[String, nullable Object]]
-
- # Names of the attributes from the root to the object currently being deserialized
- var attributes_path = new Array[String]
-
- # Last encountered object reference id.
- #
- # See `id_to_object`.
- var just_opened_id: nullable Int = null
-
- init do
- var root = text.parse_json
- if root isa Map[String, nullable Object] then path.add(root)
- self.root = root
- end
-
- redef fun deserialize_attribute(name, static_type)
- do
- if path.is_empty then
- # The was a parsing error or the root is not an object
- if not root isa Error then
- errors.add new Error("Deserialization Error: parsed JSON value is not an object.")
- end
- deserialize_attribute_missing = false
- return null
- end
-
- var current = path.last
-
- if not current.keys.has(name) then
- # Let the generated code / caller of `deserialize_attribute` raise the missing attribute error
- deserialize_attribute_missing = true
- return null
- end
-
- var value = current[name]
-
- attributes_path.add name
- var res = convert_object(value, static_type)
- attributes_path.pop
-
- deserialize_attribute_missing = false
- return res
- end
-
- # This may be called multiple times by the same object from constructors
- # in different nclassdef
- redef fun notify_of_creation(new_object)
- do
- var id = just_opened_id
- if id == null then return # Register `new_object` only once
- cache[id] = new_object
- end
-
- # Convert the simple JSON `object` to a Nit object
- private fun convert_object(object: nullable Object, static_type: nullable String): nullable Object
- do
- if object isa JsonParseError then
- errors.add object
- return null
- end
-
- if object isa Map[String, nullable Object] then
- var kind = null
- if object.keys.has("__kind") then
- kind = object["__kind"]
- end
-
- # ref?
- if kind == "ref" then
- if not object.keys.has("__id") then
- errors.add new Error("Serialization Error: JSON object reference does not declare a `__id`.")
- return object
- end
-
- var id = object["__id"]
- if not id isa Int then
- errors.add new Error("Serialization Error: JSON object reference declares a non-integer `__id`.")
- return object
- end
-
- if not cache.has_id(id) then
- errors.add new Error("Serialization Error: JSON object reference has an unknown `__id`.")
- return object
- end
-
- return cache.object_for(id)
- end
-
- # obj?
- if kind == "obj" or kind == null then
- var id = null
- if object.keys.has("__id") then
- id = object["__id"]
-
- if not id isa Int then
- errors.add new Error("Serialization Error: JSON object declaration declares a non-integer `__id`.")
- return object
- end
-
- if cache.has_id(id) then
- errors.add new Error("Serialization Error: JSON object with `__id` {id} is deserialized twice.")
- # Keep going
- end
- end
-
- var class_name = object.get_or_null("__class")
- if class_name == null then
- # Fallback to custom heuristic
- class_name = class_name_heuristic(object)
-
- if class_name == null and static_type != null then
- # Fallack to the static type, strip the `nullable` prefix
- var prefix = "nullable "
- if static_type.has(prefix) then
- class_name = static_type.substring_from(prefix.length)
- else class_name = static_type
- end
- end
-
- if class_name == null then
- errors.add new Error("Serialization Error: JSON object declaration does not declare a `__class`.")
- return object
- end
-
- if not class_name isa String then
- errors.add new Error("Serialization Error: JSON object declaration declares a non-string `__class`.")
- return object
- end
-
- # advance on path
- path.push object
-
- just_opened_id = id
- var value = deserialize_class(class_name)
- just_opened_id = null
-
- # revert on path
- path.pop
-
- return value
- end
-
- # char?
- if kind == "char" then
- if not object.keys.has("__val") then
- errors.add new Error("Serialization Error: JSON `char` object does not declare a `__val`.")
- return object
- end
-
- var val = object["__val"]
-
- if not val isa String or val.is_empty then
- errors.add new Error("Serialization Error: JSON `char` object does not declare a single char in `__val`.")
- return object
- end
-
- return val.chars.first
- end
-
- errors.add new Error("Serialization Error: JSON object has an unknown `__kind`.")
- return object
- end
-
- # Simple JSON array without serialization metadata
- if object isa Array[nullable Object] then
- # Can we use the static type?
- if static_type != null then
- var prefix = "nullable "
- var class_name = if static_type.has(prefix) then
- static_type.substring_from(prefix.length)
- else static_type
-
- opened_array = object
- var value = deserialize_class(class_name)
- opened_array = null
- return value
- end
-
- # This branch should rarely be used:
- # when an array is the root object which is accepted but illegal in standard JSON,
- # or in strange custom deserialization hacks.
-
- var array = new Array[nullable Object]
- var types = new HashSet[String]
- var has_nullable = false
- for e in object do
- var res = convert_object(e)
- array.add res
-
- if res != null then
- types.add res.class_name
- else has_nullable = true
- end
-
- if types.length == 1 then
- var array_type = types.first
-
- var typed_array
- if array_type == "ASCIIFlatString" or array_type == "UnicodeFlatString" then
- if has_nullable then
- typed_array = new Array[nullable FlatString]
- else typed_array = new Array[FlatString]
- else if array_type == "Int" then
- if has_nullable then
- typed_array = new Array[nullable Int]
- else typed_array = new Array[Int]
- else if array_type == "Float" then
- if has_nullable then
- typed_array = new Array[nullable Float]
- else typed_array = new Array[Float]
- else
- # TODO support all array types when we separate the constructor
- # `from_deserializer` from the filling of the items.
-
- if not has_nullable then
- typed_array = new Array[Object]
- else
- # Unsupported array type, return as `Array[nullable Object]`
- return array
- end
- end
-
- assert typed_array isa Array[nullable Object]
-
- # Copy item to the new array
- for e in array do typed_array.add e
- return typed_array
- end
-
- # Uninferrable type, return as `Array[nullable Object]`
- return array
- end
-
- return object
- end
-
- # Current array open for deserialization, used by `SimpleCollection::from_deserializer`
- private var opened_array: nullable Array[nullable Object] = null
-
- redef fun deserialize
- do
- errors.clear
- return convert_object(root)
- end
-
- # User customizable heuristic to infer the name of the Nit class to deserialize `json_object`
- #
- # This method is called only when deserializing an object without the metadata `__class`.
- # Use the content of `json_object` to identify what Nit class it should be deserialized into.
- # Or use `self.attributes_path` indicating where the deserialized object will be stored,
- # is is less reliable as some objects don't have an associated attribute:
- # the root/first deserialized object and collection elements.
- #
- # Return the class name as a `String` when it can be inferred,
- # or `null` when the class name cannot be found.
- #
- # If a valid class name is returned, `json_object` will then be deserialized normally.
- # So it must contain the attributes of the corresponding class, as usual.
- #
- # ~~~nitish
- # class MyData
- # serialize
- #
- # var data: String
- # end
- #
- # class MyError
- # serialize
- #
- # var error: String
- # var related_data: MyData
- # end
- #
- # class MyJsonDeserializer
- # super JsonDeserializer
- #
- # redef fun class_name_heuristic(json_object)
- # do
- # # Infer the Nit class from the content of the JSON object.
- # if json_object.keys.has("error") then return "MyError"
- # if json_object.keys.has("data") then return "MyData"
- #
- # # Infer the Nit class from the attribute where it will be stored.
- # # This line duplicates a previous line, and would only apply when
- # # `MyData` is within a `MyError`.
- # if attributes_path.not_empty and attributes_path.last == "related_data" then return "MyData"
- #
- # return null
- # end
- # end
- #
- # var json = """{"data": "some data"}"""
- # var deserializer = new MyJsonDeserializer(json)
- # var deserialized = deserializer.deserialize
- # assert deserialized isa MyData
- #
- # json = """{"error": "some error message",
- # "related_data": {"data": "some other data"}"""
- # deserializer = new MyJsonDeserializer(json)
- # deserialized = deserializer.deserialize
- # assert deserialized isa MyError
- # ~~~
- protected fun class_name_heuristic(json_object: Map[String, nullable Object]): nullable String
- do
- return null
- end
-end
-
-redef class Text
-
- # Deserialize a `nullable Object` from this JSON formatted string
- #
- # Warning: Deserialization errors are reported with `print_error` and
- # may be returned as a partial object or as `null`.
- #
- # This method is not appropriate when errors need to be handled programmatically,
- # manually use a `JsonDeserializer` in such cases.
- fun from_json_string: nullable Object
- do
- var deserializer = new JsonDeserializer(self)
- var res = deserializer.deserialize
- if deserializer.errors.not_empty then
- print_error "Deserialization Errors: {deserializer.errors.join(", ")}"
- end
- return res
- end
-
- redef fun accept_json_serializer(v) do v.stream.write(to_json)
-end
-
-redef class Serializable
-
- # Serialize `self` to JSON
- #
- # Set `plain = true` to generate standard JSON, without deserialization metadata.
- # Use this option if the generated JSON will be read by other programs or humans.
- # Use the default, `plain = false`, if the JSON is to be deserialized by a Nit program.
- #
- # Set `pretty = true` to generate pretty JSON for human eyes.
- # Use the default, `pretty = false`, to generate minified JSON.
- #
- # This method should not be refined by subclasses,
- # instead `accept_json_serializer` can customize the serialization of an object.
- #
- # See: `JsonSerializer`
- fun serialize_to_json(plain, pretty: nullable Bool): String
- do
- var stream = new StringWriter
- var serializer = new JsonSerializer(stream)
- serializer.plain_json = plain or else false
- serializer.pretty_json = pretty or else false
- serializer.serialize self
- stream.close
- return stream.to_s
- end
-
- # Refinable service to customize the serialization of this class to JSON
- #
- # This method can be refined to customize the serialization by either
- # writing pure JSON directly on the stream `v.stream` or
- # by using other services of `JsonSerializer`.
- #
- # Most of the time, it is preferable to refine the method `core_serialize_to`
- # which is used by all the serialization engines, not just JSON.
- protected fun accept_json_serializer(v: JsonSerializer)
- do
- var id = v.cache.new_id_for(self)
- v.stream.write "\{"
- v.indent_level += 1
- if not v.plain_json then
- v.new_line_and_indent
- v.stream.write "\"__kind\": \"obj\", \"__id\": "
- v.stream.write id.to_s
- v.stream.write ", \"__class\": \""
- v.stream.write class_name
- v.stream.write "\""
- end
- core_serialize_to(v)
-
- v.indent_level -= 1
- v.new_line_and_indent
- v.stream.write "\}"
- end
-end
-
-redef class Int
- redef fun accept_json_serializer(v) do v.stream.write to_s
-end
-
-redef class Float
- redef fun accept_json_serializer(v) do v.stream.write to_s
-end
-
-redef class Bool
- redef fun accept_json_serializer(v) do v.stream.write to_s
-end
-
-redef class Char
- redef fun accept_json_serializer(v)
- do
- if v.plain_json then
- to_s.accept_json_serializer v
- else
- v.stream.write "\{\"__kind\": \"char\", \"__val\": "
- to_s.accept_json_serializer v
- v.stream.write "\}"
- end
- end
-end
-
-redef class NativeString
- redef fun accept_json_serializer(v) do to_s.accept_json_serializer(v)
-end
-
-redef class Collection[E]
- # Utility to serialize a normal Json array
- private fun serialize_to_pure_json(v: JsonSerializer)
- do
- v.stream.write "["
- v.indent_level += 1
- var is_first = true
- for e in self do
- if is_first then
- is_first = false
- else v.stream.write ","
- v.new_line_and_indent
-
- if not v.try_to_serialize(e) then
- assert e != null # null would have been serialized
- v.warn("element of type {e.class_name} is not serializable.")
- end
- end
- v.indent_level -= 1
- v.new_line_and_indent
- v.stream.write "]"
- end
-end
-
-redef class SimpleCollection[E]
- redef fun accept_json_serializer(v)
- do
- # Register as pseudo object
- if not v.plain_json then
- var id = v.cache.new_id_for(self)
- v.stream.write """{"""
- v.indent_level += 1
- v.new_line_and_indent
- v.stream.write """"__kind": "obj", "__id": """
- v.stream.write id.to_s
- v.stream.write """, "__class": """"
- v.stream.write class_name
- v.stream.write """","""
- v.new_line_and_indent
- v.stream.write """"__items": """
-
- core_serialize_to v
- end
-
- serialize_to_pure_json v
-
- if not v.plain_json then
- v.indent_level -= 1
- v.new_line_and_indent
- v.stream.write "\}"
- end
- end
-
- redef init from_deserializer(v)
- do
- super
- if v isa JsonDeserializer then
- v.notify_of_creation self
- init
-
- var open_array: nullable SequenceRead[nullable Object] = v.opened_array
- if open_array == null then
- # With metadata
- var arr = v.path.last.get_or_null("__items")
- if not arr isa SequenceRead[nullable Object] then
- # If there is nothing, we consider that it is an empty collection.
- if arr != null then v.errors.add new Error("Deserialization Error: invalid format in {self.class_name}")
- return
- end
- open_array = arr
- end
-
- # Try to get the name of the single parameter type assuming it is E.
- # This does not work in non-generic subclasses,
- # when the first parameter is not E, or
- # when there is more than one parameter. (The last one could be fixed)
- var class_name = class_name
- var items_type = null
- var bracket_index = class_name.index_of('[')
- if bracket_index != -1 then
- var start = bracket_index + 1
- var ending = class_name.last_index_of(']')
- items_type = class_name.substring(start, ending-start)
- end
-
- # Fill array
- for o in open_array do
- var obj = v.convert_object(o, items_type)
- if obj isa E then
- add obj
- else v.errors.add new AttributeTypeError(self, "items", obj, "E")
- end
- end
- end
-end
-
-redef class Map[K, V]
- redef fun accept_json_serializer(v)
- do
- # Register as pseudo object
- var id = v.cache.new_id_for(self)
-
- v.stream.write "\{"
- v.indent_level += 1
-
- if v.plain_json then
- var first = true
- for key, val in self do
- if not first then
- v.stream.write ","
- else first = false
- v.new_line_and_indent
-
- var k = key or else "null"
- k.to_s.accept_json_serializer v
- v.stream.write ": "
- if not v.try_to_serialize(val) then
- assert val != null # null would have been serialized
- v.warn("element of type {val.class_name} is not serializable.")
- v.stream.write "null"
- end
- end
- else
- v.new_line_and_indent
- v.stream.write """"__kind": "obj", "__id": """
- v.stream.write id.to_s
- v.stream.write """, "__class": """"
- v.stream.write class_name
- v.stream.write """", "__length": """
- v.stream.write length.to_s
-
- v.stream.write ","
- v.new_line_and_indent
- v.stream.write """"__keys": """
- keys.serialize_to_pure_json v
-
- v.stream.write ","
- v.new_line_and_indent
- v.stream.write """"__values": """
- values.serialize_to_pure_json v
-
- core_serialize_to v
- end
-
- v.indent_level -= 1
- v.new_line_and_indent
- v.stream.write "\}"
- end
-
- redef init from_deserializer(v)
- do
- super
-
- if v isa JsonDeserializer then
- v.notify_of_creation self
- init
-
- var length = v.deserialize_attribute("__length")
- var keys = v.path.last.get_or_null("__keys")
- var values = v.path.last.get_or_null("__values")
-
- # Length is optional
- if length == null and keys isa SequenceRead[nullable Object] then length = keys.length
-
- # Consistency check
- if not length isa Int or length < 0 or
- not keys isa SequenceRead[nullable Object] or
- not values isa SequenceRead[nullable Object] or
- keys.length != values.length or length != keys.length then
-
- # If there is nothing or length == 0, we consider that it is an empty Map.
- if (length != null and length != 0) or keys != null or values != null then
- v.errors.add new Error("Deserialization Error: invalid format in {self.class_name}")
- end
- return
- end
-
- for i in length.times do
- var key = v.convert_object(keys[i])
- var value = v.convert_object(values[i])
-
- if not key isa K then
- v.errors.add new AttributeTypeError(self, "keys", key, "K")
- continue
- end
-
- if not value isa V then
- v.errors.add new AttributeTypeError(self, "values", value, "V")
- continue
- end
-
- if has_key(key) then
- v.errors.add new Error("Deserialization Error: duplicated key '{key or else "null"}' in {self.class_name}, previous value overwritten")
- end
-
- self[key] = value
- end
- end
- end
-end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to read JSON: `from_json_string` and `JsonDeserializer`
+module serialization_read
+
+import ::serialization::caching
+private import ::serialization::engine_tools
+private import static
+private import string_parser
+
+# Deserializer from a Json string.
+class JsonDeserializer
+ super CachingDeserializer
+
+ # Json text to deserialize from.
+ private var text: Text
+
+ # Root json object parsed from input text.
+ private var root: nullable Object is noinit
+
+ # Depth-first path in the serialized object tree.
+ private var path = new Array[Map[String, nullable Object]]
+
+ # Names of the attributes from the root to the object currently being deserialized
+ var attributes_path = new Array[String]
+
+ # Last encountered object reference id.
+ #
+ # See `id_to_object`.
+ var just_opened_id: nullable Int = null
+
+ init do
+ var root = text.parse_json
+ if root isa Map[String, nullable Object] then path.add(root)
+ self.root = root
+ end
+
+ redef fun deserialize_attribute(name, static_type)
+ do
+ if path.is_empty then
+ # The was a parsing error or the root is not an object
+ if not root isa Error then
+ errors.add new Error("Deserialization Error: parsed JSON value is not an object.")
+ end
+ deserialize_attribute_missing = false
+ return null
+ end
+
+ var current = path.last
+
+ if not current.keys.has(name) then
+ # Let the generated code / caller of `deserialize_attribute` raise the missing attribute error
+ deserialize_attribute_missing = true
+ return null
+ end
+
+ var value = current[name]
+
+ attributes_path.add name
+ var res = convert_object(value, static_type)
+ attributes_path.pop
+
+ deserialize_attribute_missing = false
+ return res
+ end
+
+ # This may be called multiple times by the same object from constructors
+ # in different nclassdef
+ redef fun notify_of_creation(new_object)
+ do
+ var id = just_opened_id
+ if id == null then return # Register `new_object` only once
+ cache[id] = new_object
+ end
+
+ # Convert the simple JSON `object` to a Nit object
+ private fun convert_object(object: nullable Object, static_type: nullable String): nullable Object
+ do
+ if object isa JsonParseError then
+ errors.add object
+ return null
+ end
+
+ if object isa Map[String, nullable Object] then
+ var kind = null
+ if object.keys.has("__kind") then
+ kind = object["__kind"]
+ end
+
+ # ref?
+ if kind == "ref" then
+ if not object.keys.has("__id") then
+ errors.add new Error("Serialization Error: JSON object reference does not declare a `__id`.")
+ return object
+ end
+
+ var id = object["__id"]
+ if not id isa Int then
+ errors.add new Error("Serialization Error: JSON object reference declares a non-integer `__id`.")
+ return object
+ end
+
+ if not cache.has_id(id) then
+ errors.add new Error("Serialization Error: JSON object reference has an unknown `__id`.")
+ return object
+ end
+
+ return cache.object_for(id)
+ end
+
+ # obj?
+ if kind == "obj" or kind == null then
+ var id = null
+ if object.keys.has("__id") then
+ id = object["__id"]
+
+ if not id isa Int then
+ errors.add new Error("Serialization Error: JSON object declaration declares a non-integer `__id`.")
+ return object
+ end
+
+ if cache.has_id(id) then
+ errors.add new Error("Serialization Error: JSON object with `__id` {id} is deserialized twice.")
+ # Keep going
+ end
+ end
+
+ var class_name = object.get_or_null("__class")
+ if class_name == null then
+ # Fallback to custom heuristic
+ class_name = class_name_heuristic(object)
+
+ if class_name == null and static_type != null then
+ # Fallack to the static type, strip the `nullable` prefix
+ var prefix = "nullable "
+ if static_type.has(prefix) then
+ class_name = static_type.substring_from(prefix.length)
+ else class_name = static_type
+ end
+ end
+
+ if class_name == null then
+ errors.add new Error("Serialization Error: JSON object declaration does not declare a `__class`.")
+ return object
+ end
+
+ if not class_name isa String then
+ errors.add new Error("Serialization Error: JSON object declaration declares a non-string `__class`.")
+ return object
+ end
+
+ # advance on path
+ path.push object
+
+ just_opened_id = id
+ var value = deserialize_class(class_name)
+ just_opened_id = null
+
+ # revert on path
+ path.pop
+
+ return value
+ end
+
+ # char?
+ if kind == "char" then
+ if not object.keys.has("__val") then
+ errors.add new Error("Serialization Error: JSON `char` object does not declare a `__val`.")
+ return object
+ end
+
+ var val = object["__val"]
+
+ if not val isa String or val.is_empty then
+ errors.add new Error("Serialization Error: JSON `char` object does not declare a single char in `__val`.")
+ return object
+ end
+
+ return val.chars.first
+ end
+
+ errors.add new Error("Serialization Error: JSON object has an unknown `__kind`.")
+ return object
+ end
+
+ # Simple JSON array without serialization metadata
+ if object isa Array[nullable Object] then
+ # Can we use the static type?
+ if static_type != null then
+ var prefix = "nullable "
+ var class_name = if static_type.has(prefix) then
+ static_type.substring_from(prefix.length)
+ else static_type
+
+ opened_array = object
+ var value = deserialize_class(class_name)
+ opened_array = null
+ return value
+ end
+
+ # This branch should rarely be used:
+ # when an array is the root object which is accepted but illegal in standard JSON,
+ # or in strange custom deserialization hacks.
+
+ var array = new Array[nullable Object]
+ var types = new HashSet[String]
+ var has_nullable = false
+ for e in object do
+ var res = convert_object(e)
+ array.add res
+
+ if res != null then
+ types.add res.class_name
+ else has_nullable = true
+ end
+
+ if types.length == 1 then
+ var array_type = types.first
+
+ var typed_array
+ if array_type == "ASCIIFlatString" or array_type == "UnicodeFlatString" then
+ if has_nullable then
+ typed_array = new Array[nullable FlatString]
+ else typed_array = new Array[FlatString]
+ else if array_type == "Int" then
+ if has_nullable then
+ typed_array = new Array[nullable Int]
+ else typed_array = new Array[Int]
+ else if array_type == "Float" then
+ if has_nullable then
+ typed_array = new Array[nullable Float]
+ else typed_array = new Array[Float]
+ else
+ # TODO support all array types when we separate the constructor
+ # `from_deserializer` from the filling of the items.
+
+ if not has_nullable then
+ typed_array = new Array[Object]
+ else
+ # Unsupported array type, return as `Array[nullable Object]`
+ return array
+ end
+ end
+
+ assert typed_array isa Array[nullable Object]
+
+ # Copy item to the new array
+ for e in array do typed_array.add e
+ return typed_array
+ end
+
+ # Uninferrable type, return as `Array[nullable Object]`
+ return array
+ end
+
+ return object
+ end
+
+ # Current array open for deserialization, used by `SimpleCollection::from_deserializer`
+ private var opened_array: nullable Array[nullable Object] = null
+
+ redef fun deserialize
+ do
+ errors.clear
+ return convert_object(root)
+ end
+
+ # User customizable heuristic to infer the name of the Nit class to deserialize `json_object`
+ #
+ # This method is called only when deserializing an object without the metadata `__class`.
+ # Use the content of `json_object` to identify what Nit class it should be deserialized into.
+ # Or use `self.attributes_path` indicating where the deserialized object will be stored,
+ # is is less reliable as some objects don't have an associated attribute:
+ # the root/first deserialized object and collection elements.
+ #
+ # Return the class name as a `String` when it can be inferred,
+ # or `null` when the class name cannot be found.
+ #
+ # If a valid class name is returned, `json_object` will then be deserialized normally.
+ # So it must contain the attributes of the corresponding class, as usual.
+ #
+ # ~~~
+ # class MyData
+ # serialize
+ #
+ # var data: String
+ # end
+ #
+ # class MyError
+ # serialize
+ #
+ # var error: String
+ # var related_data: MyData
+ # end
+ #
+ # class MyJsonDeserializer
+ # super JsonDeserializer
+ #
+ # redef fun class_name_heuristic(json_object)
+ # do
+ # # Infer the Nit class from the content of the JSON object.
+ # if json_object.keys.has("error") then return "MyError"
+ # if json_object.keys.has("data") then return "MyData"
+ #
+ # # Infer the Nit class from the attribute where it will be stored.
+ # # This line duplicates a previous line, and would only apply when
+ # # `MyData` is within a `MyError`.
+ # if attributes_path.not_empty and attributes_path.last == "related_data" then return "MyData"
+ #
+ # return null
+ # end
+ # end
+ #
+ # var json = """{"data": "some data"}"""
+ # var deserializer = new MyJsonDeserializer(json)
+ # var deserialized = deserializer.deserialize
+ # assert deserializer.errors.is_empty
+ # assert deserialized isa MyData
+ #
+ # json = """{"error": "some error message",
+ # "related_data": {"data": "some other data"}}"""
+ # deserializer = new MyJsonDeserializer(json)
+ # deserialized = deserializer.deserialize
+ # assert deserializer.errors.is_empty
+ # assert deserialized isa MyError
+ # ~~~
+ protected fun class_name_heuristic(json_object: Map[String, nullable Object]): nullable String
+ do
+ return null
+ end
+end
+
+redef class Text
+
+ # Deserialize a `nullable Object` from this JSON formatted string
+ #
+ # Warning: Deserialization errors are reported with `print_error` and
+ # may be returned as a partial object or as `null`.
+ #
+ # This method is not appropriate when errors need to be handled programmatically,
+ # manually use a `JsonDeserializer` in such cases.
+ fun from_json_string: nullable Object
+ do
+ var deserializer = new JsonDeserializer(self)
+ var res = deserializer.deserialize
+ if deserializer.errors.not_empty then
+ print_error "Deserialization Errors: {deserializer.errors.join(", ")}"
+ end
+ return res
+ end
+end
+
+redef class SimpleCollection[E]
+ redef init from_deserializer(v)
+ do
+ super
+ if v isa JsonDeserializer then
+ v.notify_of_creation self
+ init
+
+ var open_array: nullable SequenceRead[nullable Object] = v.opened_array
+ if open_array == null then
+ # With metadata
+ var arr = v.path.last.get_or_null("__items")
+ if not arr isa SequenceRead[nullable Object] then
+ # If there is nothing, we consider that it is an empty collection.
+ if arr != null then v.errors.add new Error("Deserialization Error: invalid format in {self.class_name}")
+ return
+ end
+ open_array = arr
+ end
+
+ # Try to get the name of the single parameter type assuming it is E.
+ # This does not work in non-generic subclasses,
+ # when the first parameter is not E, or
+ # when there is more than one parameter. (The last one could be fixed)
+ var class_name = class_name
+ var items_type = null
+ var bracket_index = class_name.index_of('[')
+ if bracket_index != -1 then
+ var start = bracket_index + 1
+ var ending = class_name.last_index_of(']')
+ items_type = class_name.substring(start, ending-start)
+ end
+
+ # Fill array
+ for o in open_array do
+ var obj = v.convert_object(o, items_type)
+ if obj isa E then
+ add obj
+ else v.errors.add new AttributeTypeError(self, "items", obj, "E")
+ end
+ end
+ end
+end
+
+redef class Map[K, V]
+ redef init from_deserializer(v)
+ do
+ super
+
+ if v isa JsonDeserializer then
+ v.notify_of_creation self
+ init
+
+ var length = v.deserialize_attribute("__length")
+ var keys = v.path.last.get_or_null("__keys")
+ var values = v.path.last.get_or_null("__values")
+
+ # Length is optional
+ if length == null and keys isa SequenceRead[nullable Object] then length = keys.length
+
+ # Consistency check
+ if not length isa Int or length < 0 or
+ not keys isa SequenceRead[nullable Object] or
+ not values isa SequenceRead[nullable Object] or
+ keys.length != values.length or length != keys.length then
+
+ # If there is nothing or length == 0, we consider that it is an empty Map.
+ if (length != null and length != 0) or keys != null or values != null then
+ v.errors.add new Error("Deserialization Error: invalid format in {self.class_name}")
+ end
+ return
+ end
+
+ for i in length.times do
+ var key = v.convert_object(keys[i])
+ var value = v.convert_object(values[i])
+
+ if not key isa K then
+ v.errors.add new AttributeTypeError(self, "keys", key, "K")
+ continue
+ end
+
+ if not value isa V then
+ v.errors.add new AttributeTypeError(self, "values", value, "V")
+ continue
+ end
+
+ if has_key(key) then
+ v.errors.add new Error("Deserialization Error: duplicated key '{key or else "null"}' in {self.class_name}, previous value overwritten")
+ end
+
+ self[key] = value
+ end
+ end
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to write Nit objects to JSON strings: `serialize_to_json` and `JsonSerializer`
+module serialization_write
+
+import ::serialization::caching
+private import ::serialization::engine_tools
+
+# Serializer of Nit objects to Json string.
+class JsonSerializer
+ super CachingSerializer
+
+ # Target writing stream
+ var stream: Writer
+
+ # Write plain JSON? Standard JSON without metadata for deserialization
+ #
+ # If `false`, the default, serialize to support deserialization:
+ #
+ # * Write metadata, including the types of the serialized objects so they can
+ # be deserialized to their original form using `JsonDeserializer`.
+ # * Use references when an object has already been serialized so to not duplicate it.
+ # * Support cycles in references.
+ # * Preserve the Nit `Char` type as an object because it does not exist in JSON.
+ # * The generated JSON is standard and can be read by non-Nit programs.
+ # However, some Nit types are not represented by the simplest possible JSON representation.
+ # With the added metadata, it can be complex to read.
+ #
+ # If `true`, serialize for other programs:
+ #
+ # * Nit objects are serialized to pure and standard JSON so they can
+ # be easily read by non-Nit programs and humans.
+ # * Nit objects are serialized for every references, so they can be duplicated.
+ # It is easier to read but it creates a larger output.
+ # * Does not support cycles, will replace the problematic references by `null`.
+ # * Does not serialize the metadata needed to deserialize the objects
+ # back to regular Nit objects.
+ # * Keys of Nit `HashMap` are converted to their string representation using `to_s`.
+ var plain_json = false is writable
+
+ # Write pretty JSON for human eyes?
+ #
+ # Toggles skipping lines between attributes of an object and
+ # properly indent the written JSON.
+ var pretty_json = false is writable
+
+ # Current indentation level used for writing `pretty_json`
+ private var indent_level = 0
+
+ # List of the current open objects, the first is the main target of the serialization
+ #
+ # Used only when `plain_json == true` to detect cycles in serialization.
+ private var open_objects = new Array[Object]
+
+ # Has the first attribute of the current object already been serialized?
+ #
+ # Used only when `plain_json == true`.
+ private var first_attribute = false
+
+ redef fun serialize(object)
+ do
+ if object == null then
+ stream.write "null"
+ else
+ if plain_json then
+ for o in open_objects do
+ if object.is_same_serialized(o) then
+ # Cycle, can't be managed in plain json
+ warn "Cycle detected in serialized object, replacing reference with 'null'."
+ stream.write "null"
+ return
+ end
+ end
+
+ open_objects.add object
+ end
+
+ first_attribute = true
+ object.accept_json_serializer self
+ first_attribute = false
+
+ if plain_json then open_objects.pop
+ end
+ end
+
+ redef fun serialize_attribute(name, value)
+ do
+ if not plain_json or not first_attribute then
+ stream.write ","
+ first_attribute = false
+ end
+
+ new_line_and_indent
+ stream.write "\""
+ stream.write name
+ stream.write "\":"
+ if pretty_json then stream.write " "
+ super
+ end
+
+ redef fun serialize_reference(object)
+ do
+ if not plain_json and cache.has_object(object) then
+ # if already serialized, add local reference
+ var id = cache.id_for(object)
+ stream.write "\{"
+ indent_level += 1
+ new_line_and_indent
+ stream.write "\"__kind\": \"ref\", \"__id\": "
+ stream.write id.to_s
+ indent_level -= 1
+ new_line_and_indent
+ stream.write "\}"
+ else
+ # serialize here
+ serialize object
+ end
+ end
+
+ # Write a new line and indent it, only if `pretty_json`
+ private fun new_line_and_indent
+ do
+ if pretty_json then
+ stream.write "\n"
+ for i in indent_level.times do stream.write "\t"
+ end
+ end
+end
+
+redef class Text
+
+ redef fun accept_json_serializer(v)
+ do
+ v.stream.write "\""
+ for i in [0 .. self.length[ do
+ var char = self[i]
+ if char == '\\' then
+ v.stream.write "\\\\"
+ else if char == '\"' then
+ v.stream.write "\\\""
+ else if char < ' ' then
+ if char == '\n' then
+ v.stream.write "\\n"
+ else if char == '\r' then
+ v.stream.write "\\r"
+ else if char == '\t' then
+ v.stream.write "\\t"
+ else
+ v.stream.write char.escape_to_utf16
+ end
+ else
+ v.stream.write char.to_s
+ end
+ end
+ v.stream.write "\""
+ end
+end
+
+redef class Serializable
+
+ # Serialize `self` to JSON
+ #
+ # Set `plain = true` to generate standard JSON, without deserialization metadata.
+ # Use this option if the generated JSON will be read by other programs or humans.
+ # Use the default, `plain = false`, if the JSON is to be deserialized by a Nit program.
+ #
+ # Set `pretty = true` to generate pretty JSON for human eyes.
+ # Use the default, `pretty = false`, to generate minified JSON.
+ #
+ # This method should not be refined by subclasses,
+ # instead `accept_json_serializer` can customize the serialization of an object.
+ #
+ # See: `JsonSerializer`
+ fun serialize_to_json(plain, pretty: nullable Bool): String
+ do
+ var stream = new StringWriter
+ var serializer = new JsonSerializer(stream)
+ serializer.plain_json = plain or else false
+ serializer.pretty_json = pretty or else false
+ serializer.serialize self
+ stream.close
+ return stream.to_s
+ end
+
+ # Serialize `self` to plain JSON
+ #
+ # Compatibility alias for `serialize_to_json(plain=true)`.
+ fun to_json: String do return serialize_to_json(plain=true)
+
+ # Serialize `self` to plain pretty JSON
+ #
+ # Compatibility alias for `serialize_to_json(plain=true, pretty=true)`.
+ fun to_pretty_json: String do return serialize_to_json(plain=true, pretty=true)
+
+ # Refinable service to customize the serialization of this class to JSON
+ #
+ # This method can be refined to customize the serialization by either
+ # writing pure JSON directly on the stream `v.stream` or
+ # by using other services of `JsonSerializer`.
+ #
+ # Most of the time, it is preferable to refine the method `core_serialize_to`
+ # which is used by all the serialization engines, not just JSON.
+ protected fun accept_json_serializer(v: JsonSerializer)
+ do
+ var id = v.cache.new_id_for(self)
+ v.stream.write "\{"
+ v.indent_level += 1
+ if not v.plain_json then
+ v.new_line_and_indent
+ v.stream.write "\"__kind\": \"obj\", \"__id\": "
+ v.stream.write id.to_s
+ v.stream.write ", \"__class\": \""
+ v.stream.write class_name
+ v.stream.write "\""
+ end
+ core_serialize_to(v)
+
+ v.indent_level -= 1
+ v.new_line_and_indent
+ v.stream.write "\}"
+ end
+end
+
+redef class Int
+ redef fun accept_json_serializer(v) do v.stream.write to_s
+end
+
+redef class Float
+ redef fun accept_json_serializer(v) do v.stream.write to_s
+end
+
+redef class Bool
+ redef fun accept_json_serializer(v) do v.stream.write to_s
+end
+
+redef class Char
+ redef fun accept_json_serializer(v)
+ do
+ if v.plain_json then
+ to_s.accept_json_serializer v
+ else
+ v.stream.write "\{\"__kind\": \"char\", \"__val\": "
+ to_s.accept_json_serializer v
+ v.stream.write "\}"
+ end
+ end
+end
+
+redef class NativeString
+ redef fun accept_json_serializer(v) do to_s.accept_json_serializer(v)
+end
+
+redef class Collection[E]
+ # Utility to serialize a normal Json array
+ private fun serialize_to_pure_json(v: JsonSerializer)
+ do
+ v.stream.write "["
+ var is_first = true
+ for e in self do
+ if is_first then
+ is_first = false
+ else
+ v.stream.write ","
+ if v.pretty_json then v.stream.write " "
+ end
+
+ if not v.try_to_serialize(e) then
+ assert e != null # null would have been serialized
+ v.warn("element of type {e.class_name} is not serializable.")
+ end
+ end
+ v.stream.write "]"
+ end
+end
+
+redef class SimpleCollection[E]
+ redef fun accept_json_serializer(v)
+ do
+ # Register as pseudo object
+ if not v.plain_json then
+ var id = v.cache.new_id_for(self)
+ v.stream.write """{"""
+ v.indent_level += 1
+ v.new_line_and_indent
+ v.stream.write """"__kind": "obj", "__id": """
+ v.stream.write id.to_s
+ v.stream.write """, "__class": """"
+ v.stream.write class_name
+ v.stream.write """","""
+ v.new_line_and_indent
+ v.stream.write """"__items": """
+
+ core_serialize_to v
+ end
+
+ serialize_to_pure_json v
+
+ if not v.plain_json then
+ v.indent_level -= 1
+ v.new_line_and_indent
+ v.stream.write "\}"
+ end
+ end
+end
+
+redef class Map[K, V]
+ redef fun accept_json_serializer(v)
+ do
+ # Register as pseudo object
+ var id = v.cache.new_id_for(self)
+
+ v.stream.write "\{"
+ v.indent_level += 1
+
+ if v.plain_json then
+ var first = true
+ for key, val in self do
+ if not first then
+ v.stream.write ","
+ else first = false
+ v.new_line_and_indent
+
+ var k = key or else "null"
+ k.to_s.accept_json_serializer v
+ v.stream.write ":"
+ if v.pretty_json then v.stream.write " "
+ if not v.try_to_serialize(val) then
+ assert val != null # null would have been serialized
+ v.warn("element of type {val.class_name} is not serializable.")
+ v.stream.write "null"
+ end
+ end
+ else
+ v.new_line_and_indent
+ v.stream.write """"__kind": "obj", "__id": """
+ v.stream.write id.to_s
+ v.stream.write """, "__class": """"
+ v.stream.write class_name
+ v.stream.write """", "__length": """
+ v.stream.write length.to_s
+
+ v.stream.write ","
+ v.new_line_and_indent
+ v.stream.write """"__keys": """
+ keys.serialize_to_pure_json v
+
+ v.stream.write ","
+ v.new_line_and_indent
+ v.stream.write """"__values": """
+ values.serialize_to_pure_json v
+
+ core_serialize_to v
+ end
+
+ v.indent_level -= 1
+ v.new_line_and_indent
+ v.stream.write "\}"
+ end
+end
# See the License for the specific language governing permissions and
# limitations under the License.
-# Static interface to get Nit objects from a Json string.
+# Static interface to read Nit objects from JSON strings
#
-# `Text::parse_json` returns an equivalent Nit object from
-# the Json source. This object can then be type checked by the usual
-# languages features (`isa` and `as`).
+# `Text::parse_json` returns a simple Nit object from the JSON source.
+# This object can then be type checked as usual with `isa` and `as`.
module static
import error
# Something that can be translated to JSON.
interface Jsonable
- # Encode `self` in JSON.
- #
- # This is a recursive method which can be refined by any subclasses.
- # To write any `Serializable` object to JSON, see `serialize_to_json`.
- #
- # SEE: `append_json`
- fun to_json: String is abstract
-
- # Use `append_json` to implement `to_json`.
- #
- # Therefore, one that redefine `append_json` may use the following
- # redefinition to link `to_json` and `append_json`:
- #
- # ~~~nitish
- # redef fun to_json do return to_json_by_append
- # ~~~
- #
- # Note: This is not the default implementation of `to_json` in order to
- # avoid cyclic references between `append_json` and `to_json` when none are
- # implemented.
- protected fun to_json_by_append: String do
- var buffer = new FlatBuffer
- append_json(buffer)
- return buffer.to_s
- end
-
- # Append the JSON representation of `self` to the specified buffer.
- #
- # SEE: `to_json`
- fun append_json(buffer: Buffer) do buffer.append(to_json)
-
- # Pretty print JSON string.
- #
- # ~~~
- # var obj = new JsonObject
- # obj["foo"] = 1
- # obj["bar"] = true
- # var arr = new JsonArray
- # arr.add 2
- # arr.add false
- # arr.add "baz"
- # obj["baz"] = arr
- # var res = obj.to_pretty_json
- # var exp = """{
- # \t"foo": 1,
- # \t"bar": true,
- # \t"baz": [2, false, "baz"]
- # }\n"""
- # assert res == exp
- # ~~~
- fun to_pretty_json: String do
- var res = new FlatBuffer
- pretty_json_visit(res, 0)
- res.add '\n'
- return res.to_s
- end
-
- private fun pretty_json_visit(buffer: FlatBuffer, indent: Int) is abstract
+ super Serializable
end
redef class Text
# assert "\\\"string\\\"".json_need_escape
protected fun json_need_escape: Bool do return has('\\')
- redef fun append_json(buffer) do
- buffer.add '\"'
- for i in [0 .. self.length[ do
- var char = self[i]
- if char == '\\' then
- buffer.append "\\\\"
- else if char == '\"' then
- buffer.append "\\\""
- else if char < ' ' then
- if char == '\n' then
- buffer.append "\\n"
- else if char == '\r' then
- buffer.append "\\r"
- else if char == '\t' then
- buffer.append "\\t"
- else
- buffer.append char.escape_to_utf16
- end
- else
- buffer.add char
- end
- end
- buffer.add '\"'
- end
-
# Escapes `self` from a JSON string to a Nit string
#
# assert "\\\"string\\\"".json_to_nit_string == "\"string\""
return res.to_s
end
-
- # Encode `self` in JSON.
- #
- # ~~~
- # assert "\t\"http://example.com\"\r\n\0\\".to_json ==
- # "\"\\t\\\"http://example.com\\\"\\r\\n\\u0000\\\\\""
- # ~~~
- redef fun to_json do
- var b = new FlatBuffer.with_capacity(byte_length)
- append_json(b)
- return b.to_s
- end
-
# Parse `self` as JSON.
#
# If `self` is not a valid JSON document or contains an unsupported escape
end
end
-redef class Buffer
-
- # Append the JSON representation of `jsonable` to `self`.
- #
- # Append `"null"` for `null`.
- private fun append_json_of(jsonable: nullable Jsonable) do
- if jsonable isa Jsonable then
- append jsonable.to_json
- else
- append "null"
- end
- end
-end
-
redef class Int
super Jsonable
-
- # Encode `self` in JSON.
- #
- # assert 0.to_json == "0"
- # assert (-42).to_json == "-42"
- redef fun to_json do return self.to_s
end
redef class Float
super Jsonable
-
- # Encode `self` in JSON.
- #
- # Note: Because this method use `to_s`, it may lose precision.
- #
- # ~~~
- # # Will not work as expected.
- # # assert (-0.0).to_json == "-0.0"
- #
- # assert (.5).to_json == "0.5"
- # assert (0.0).to_json == "0.0"
- # ~~~
- redef fun to_json do return self.to_s
end
redef class Bool
super Jsonable
-
- # Encode `self` in JSON.
- #
- # assert true.to_json == "true"
- # assert false.to_json == "false"
- redef fun to_json do return self.to_s
end
# A map that can be translated into a JSON object.
interface JsonMapRead[K: String, V: nullable Jsonable]
super MapRead[K, V]
super Jsonable
-
- redef fun append_json(buffer) do
- buffer.append "\{"
- var it = iterator
- if it.is_ok then
- append_json_entry(it, buffer)
- while it.is_ok do
- buffer.append ","
- append_json_entry(it, buffer)
- end
- end
- it.finish
- buffer.append "\}"
- end
-
- # Encode `self` in JSON.
- #
- # var obj = new JsonObject
- # obj["foo"] = "bar"
- # assert obj.to_json == "\{\"foo\":\"bar\"\}"
- # obj = new JsonObject
- # obj["baz"] = null
- # assert obj.to_json == "\{\"baz\":null\}"
- redef fun to_json do return to_json_by_append
-
- redef fun pretty_json_visit(buffer, indent) do
- buffer.append "\{\n"
- indent += 1
- var i = 0
- for k, v in self do
- buffer.append "\t" * indent
- buffer.append "\"{k}\": "
- if v isa JsonObject or v isa JsonArray then
- v.pretty_json_visit(buffer, indent)
- else
- buffer.append v.to_json
- end
- if i < length - 1 then
- buffer.append ","
- end
- buffer.append "\n"
- i += 1
- end
- indent -= 1
- buffer.append "\t" * indent
- buffer.append "\}"
- end
-
- private fun append_json_entry(iterator: MapIterator[String, nullable Jsonable],
- buffer: Buffer) do
- buffer.append iterator.key.to_json
- buffer.append ":"
- buffer.append_json_of(iterator.item)
- iterator.next
- end
end
# A JSON Object.
class JsonSequenceRead[E: nullable Jsonable]
super Jsonable
super SequenceRead[E]
-
- redef fun append_json(buffer) do
- buffer.append "["
- var it = iterator
- if it.is_ok then
- append_json_entry(it, buffer)
- while it.is_ok do
- buffer.append ","
- append_json_entry(it, buffer)
- end
- end
- it.finish
- buffer.append "]"
- end
-
- # Encode `self` in JSON.
- #
- # var arr = new JsonArray.with_items("foo", null)
- # assert arr.to_json == "[\"foo\",null]"
- # arr.pop
- # assert arr.to_json =="[\"foo\"]"
- # arr.pop
- # assert arr.to_json =="[]"
- redef fun to_json do return to_json_by_append
-
- redef fun pretty_json_visit(buffer, indent) do
- buffer.append "\["
- var i = 0
- for v in self do
- if v isa JsonObject or v isa JsonArray then
- v.pretty_json_visit(buffer, indent)
- else
- buffer.append v.to_json
- end
- if i < length - 1 then buffer.append ", "
- i += 1
- end
- buffer.append "\]"
- end
-
- private fun append_json_entry(iterator: Iterator[nullable Jsonable],
- buffer: Buffer) do
- buffer.append_json_of(iterator.item)
- iterator.next
- end
end
# A JSON array.
redef class JsonParseError
super Jsonable
-
- # Get the JSON representation of `self`.
- #
- # ~~~
- # var err = new JsonParseError("foo", new Position(1, 2, 3, 4, 5, 6))
- # assert err.to_json == "\{\"error\":\"JsonParseError\"," +
- # "\"position\":\{" +
- # "\"pos_start\":1,\"pos_end\":2," +
- # "\"line_start\":3,\"line_end\":4," +
- # "\"col_start\":5,\"col_end\":6" +
- # "\},\"message\":\"foo\"\}"
- # ~~~
- redef fun to_json do
- return "\{\"error\":\"JsonParseError\"," +
- "\"position\":{position.to_json}," +
- "\"message\":{message.to_json}\}"
- end
-
- redef fun pretty_json_visit(buf, indents) do
- buf.clear
- buf.append(to_json)
- end
end
redef class Position
super Jsonable
-
- # Get the JSON representation of `self`.
- #
- # ~~~
- # var pos = new Position(1, 2, 3, 4, 5, 6)
- # assert pos.to_json == "\{" +
- # "\"pos_start\":1,\"pos_end\":2," +
- # "\"line_start\":3,\"line_end\":4," +
- # "\"col_start\":5,\"col_end\":6" +
- # "\}"
- # ~~~
- redef fun to_json do
- return "\{\"pos_start\":{pos_start},\"pos_end\":{pos_end}," +
- "\"line_start\":{line_start},\"line_end\":{line_end}," +
- "\"col_start\":{col_start},\"col_end\":{col_end}\}"
- end
end
################################################################################
module store
import static
+import json
# A JsonStore can save and load json data from file system.
class JsonStore
end
redef class JsonParseError
+ serialize
# Location of the error in source
var location: nullable Location = null
-
- # Get the JSON representation of `self`.
- #
- # ~~~
- # var err = new JsonParseError("foo", new Position(1, 2, 3, 4, 5, 6))
- # assert err.to_json == "Parsing error: foo"
- # ~~~
- redef fun to_json do
- var l = location
- var m = message
- return if l == null then "Parsing error: {m}" else "Parsing error at {l}: {m}"
- end
-
- redef fun to_s do return to_json
end
import app::data_store
private import xdg_basedir
private import sqlite3
-private import json::serialization
+private import json
redef class App
redef var data_store = new LinuxStore
int di;
md5_init(&state);
- md5_append(&state, (const md5_byte_t *)self, strlen(self));
+ md5_append(&state, (const md5_byte_t *)self, (int)strlen(self));
md5_finish(&state, digest);
for (di = 0; di < 16; ++di)
# ~~~
module mongodb
+import json::static
import json
private import native_mongodb
import c
intrude import core::text::flat
import serialization
-private import json::serialization
+private import json
in "C Header" `{
#include <mpi.h>
module curl_json
import json::static
+import json
intrude import curl
# An abstract request that defines most of the standard options for Neo4j REST API
module neo4j::error
import json::static
+import json
# An error thrown by the `neo4j` API.
#
# var error = new NeoError("ErrorMessage", "ErrorName")
-# assert error.to_json == "\{\"error\":\"ErrorName\",\"message\":\"ErrorMessage\"\}"
+# assert error.to_json == """{"message":"ErrorMessage","cause":null,"error":"ErrorName"}"""
class NeoError
super Error
super Jsonable
+ serialize
# The name of the error.
#
# Used to programmatically distinguish this kind of error from others.
- var name: String
-
- redef fun to_json do
- return "\{\"error\":{name.to_json},\"message\":{message.to_json}\}"
- end
+ var name: String is serialize_as "error"
redef fun to_s do return "[{name}] {super}"
end
end
end
- redef fun to_json do return to_json_by_append
-
- # Append the JSON representation of `self` to the specified buffer.
- #
- # For a description of the format, see `JsonGraphStore`.
- #
- # SEE: `to_json`
- redef fun append_json(b) do
- b.append "\{\"nodes\":["
- append_entities_json(nodes, b)
- b.append "],\"edges\":["
- append_entities_json(edges, b)
- b.append "]\}"
+ redef fun accept_json_serializer(v) do
+ v.stream.write "\{\"nodes\":["
+ append_entities_json(nodes, v)
+ v.stream.write "],\"edges\":["
+ append_entities_json(edges, v)
+ v.stream.write "]\}"
end
# Encode `self` in JSON.
#
# For a description of the format, see `JsonGraphStore`.
- #
- # SEE: `append_json`
- private fun append_entities_json(entities: Collection[NeoEntity],
- b: Buffer) do
+ private fun append_entities_json(entities: Collection[NeoEntity], v: JsonSerializer) do
var i = entities.iterator
if i.is_ok then
- i.item.append_json_for(self, b)
+ i.item.append_json_for(self, v)
i.next
for entity in i do
- b.add ','
- entity.append_json_for(self, b)
+ v.stream.write ","
+ entity.append_json_for(self, v)
end
end
end
redef class NeoEntity
# Append the JSON representation of the entity to the specified buffer.
- fun append_json_for(graph: NeoGraph, buffer: Buffer) is abstract
+ fun append_json_for(graph: NeoGraph, v: JsonSerializer) is abstract
end
# Make `NeoNode` `Jsonable`.
properties.add_all(json_properties)
end
- redef fun to_json do return to_json_by_append
-
- # Append the JSON representation of the node to the specified buffer.
- #
- # SEE: `JsonGraph`
- redef fun append_json(b) do
- b.append "\{\"labels\":["
+ redef fun accept_json_serializer(v) do
+ v.stream.write "\{\"labels\":["
var i = labels.iterator
if i.is_ok then
- i.item.append_json(b)
+ i.item.serialize_to v
i.next
for lab in i do
- b.add ','
- lab.append_json(b)
+ v.stream.write ","
+ lab.serialize_to v
end
end
- b.append "],\"properties\":"
- properties.append_json(b)
- b.add '}'
+ v.stream.write "],\"properties\":"
+ properties.serialize_to v
+ v.stream.write "}"
end
redef fun to_s do return to_json
# Append the JSON representation of the node to the specified buffer.
- redef fun append_json_for(graph, buffer) do
- append_json(buffer)
+ redef fun append_json_for(graph, v) do
+ accept_json_serializer v
end
end
# Append the JSON representation of the relationship to the specified buffer.
#
# Use the IDs specfied by `graph.nodes`.
- redef fun append_json_for(graph, buffer) do
- buffer.append "\{\"type\":"
- rel_type.as(not null).append_json(buffer)
- buffer.append ",\"properties\":"
- properties.append_json(buffer)
- buffer.append ",\"from\":"
- graph.nodes.id_of(from).append_json(buffer)
- buffer.append ",\"to\":"
- graph.nodes.id_of(to).append_json(buffer)
- buffer.append "}"
+ redef fun append_json_for(graph, v) do
+ v.stream.write "\{\"type\":"
+ rel_type.as(not null).serialize_to(v)
+ v.stream.write ",\"properties\":"
+ properties.serialize_to(v)
+ v.stream.write ",\"from\":"
+ graph.nodes.id_of(from).serialize_to(v)
+ v.stream.write ",\"to\":"
+ graph.nodes.id_of(to).serialize_to(v)
+ v.stream.write "}"
end
end
# Runtime library required by parsers and lexers generated by nitcc
module nitcc_runtime
+import serialization
+
# A abstract parser engine generated by nitcc
abstract class Parser
# The list of tokens
# A position into a input stream
# Used to give position to tokens
class Position
+ serialize
+
var pos_start: Int
var pos_end: Int
var line_start: Int
module restful is new_annotation(restful)
import nitcorn
-import json::serialization
+import json
# Action with `restful` methods
class RestfulAction
# Simple base for hand-made parsers of all kinds
module parser_base
+import serialization
+
# Basic facilities for common parser operations on String sources
class StringProcessor
# Source document to parse
# Information about the location of an entity in a source document
class Location
+ serialize
+
# Line in which the element is described
var line: Int
# Offset in the line at which the element is positioned
module pop_handlers
import pop_routes
+import json::static
import json
# Class handler for a route.
# redef fun to_s do return title
# redef fun ==(o) do return o isa SELF and id == o.id
# redef fun hash do return id.hash
-# redef fun to_json do return serialize_to_json
# end
#
# # We then need to subclass the `MongoRepository` to provide Book specific services.
import popcorn::pop_config
import serialization
-import json::serialization
+import json
import mongodb::queries
redef class AppConfig
redef fun hash do return id.hash
redef fun to_s do return id
- redef fun to_json do return serialize_to_json
end
# JsonObject can be used as a `RepositoryQuery`.
# ~~~
module pop_validation
-import json
+import json::static
# The base class of all validators
abstract class DocumentValidator
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
# Returns the validation result as a pretty formated string
fun to_pretty_string: String do
fun equal(other: NativePthread): Bool `{ return pthread_equal(*self, *other); `}
- fun kill(signal: Int) `{ pthread_kill(*self, signal); `}
+ fun kill(signal: Int) `{ pthread_kill(*self, (int)signal); `}
end
private extern class NativePthreadAttr in "C" `{ pthread_attr_t * `}
from the `json_serialization` module.
~~~
-import json_serialization
+import json
import user_credentials
# Data to be serialized and deserialized
import doc_base
import html_templates::html_model # FIXME maybe this phase should depend on `html_render`
private import json::static
+private import json
# Generate the index for then Nitdoc QuickSearch field.
#
var buffer = new Buffer
tpl.add buffer
buffer.append "var nitdocQuickSearchRawList="
- table.append_json buffer
+ buffer.append table.to_json
buffer.append ";"
return tpl
end
# A QuickSearch result.
private class QuickSearchResult
super Jsonable
+ serialize
# The text of the link.
var txt: String
# The destination of the link.
var url: String
-
- redef fun to_json do
- return "\{\"txt\":{txt.to_json},\"url\":{url.to_json}\}"
- end
end
import doc_base
import html::bootstrap
-import json::static
+import json
# A label with a text content.
class DocHTMLLabel
# Crawler on the nitweb web API
module nitwebcrawl
-import json
+import json::static
# Download a HTTP resource
fun curl(url: String): String do
module model_json
import model::model_collect
+import json::static
import json
import loader
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
# Return `self` as a JsonObject with references.
#
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
redef class Location
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
redef class MVisibility
super Jsonable
- redef fun to_json do return to_s.to_json
+ redef fun serialize_to(v) do to_s.serialize_to(v)
end
redef class MPackage
# Compile with `xcodebuild`
#
# TODO support more than the iPhone and the simulator.
+ var compile_mode = if release then "Release" else "Debug"
var args = ["sh", "-c", "cd {ios_project_root}; " +
- "xcodebuild -target '{project_name}' " +
+ "xcodebuild -quiet -target '{project_name}' " +
"-destination 'platform=iOS Simulator,name=iPhone' " +
- "-configuration {if release then "Release" else "Debug"} " +
+ "-configuration {compile_mode} " +
"ONLY_ACTIVE_ARCH=NO "+
"-sdk iphonesimulator build"]
toolcontext.exec_and_check(args, "iOS project error")
# Move compiled app to destination
- if outfile.file_exists then outfile.rmdir
- args = ["mv", "{ios_project_root}/build/Debug-iphonesimulator/{project_name}.app", outfile]
+ if outfile.file_exists then
+ var error = outfile.rmdir
+ if error != null then
+ print_error error
+ exit 1
+ end
+ end
+
+ args = ["mv", "{ios_project_root}/build/{compile_mode}-iphonesimulator/{project_name}.app", outfile]
toolcontext.exec_and_check(args, "iOS project error")
end
end
proc_which.wait
var res = proc_which.status
if res != 0 then
- print "{error}: executable \"{prog}\" not found"
+ print_error "{error}: executable \"{prog}\" not found"
exit 1
end
proc.wait
res = proc.status
if res != 0 then
- print "{error}: execution of \"{prog} {args.join(" ")}\" failed"
+ print_error "{error}: execution of \"{prog} {args.join(" ")}\" failed"
exit 1
end
end
redef class Person
super Jsonable
- redef fun to_json do
- var obj = new JsonObject
- obj["name"] = name
- obj["email"] = email
- obj["page"] = page
- obj["hash"] = (email or else "").md5.to_lower
- return obj.to_json
+ redef fun core_serialize_to(v) do
+ v.serialize_attribute("name", name)
+ v.serialize_attribute("email", email)
+ v.serialize_attribute("page", page)
+ v.serialize_attribute("hash", (email or else "").md5.to_lower)
end
end
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
# Rating value of a MEntity
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
redef class Metric
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
redef class IntMetric
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
# Fullname representation that can be used to build decorated links
class Namespace
super Array[nullable NSEntity]
super NSEntity
+ serialize
redef fun to_s do return self.join("")
- redef fun to_json do return (new JsonArray.from(self)).to_json
+ redef fun serialize_to(v) do to_a.serialize_to(v)
end
# Something that goes in a Namespace
# an infinite loop.
class NSRef
super NSEntity
+ serialize
# The mentity to link to/
var mentity: MEntity
- redef fun to_json do
+ redef fun serialize_to(v) do
var obj = new JsonObject
obj["web_url"] = mentity.web_url
obj["api_url"] = mentity.api_url
obj["name"] = mentity.name
- return obj.to_json
+ obj.serialize_to(v)
end
end
return obj
end
- redef fun to_json do return json.to_json
+ redef fun serialize_to(v) do json.serialize_to(v)
end
emscripten
ui_test
readline
+postgres
out/hello_ios.bin/LaunchScreen.storyboardc/Info.plist
out/hello_ios.bin/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
out/hello_ios.bin/PkgInfo
+out/hello_ios.bin/_CodeSignature
+out/hello_ios.bin/_CodeSignature/CodeResources
out/hello_ios.bin/hello_ios
"blue": [1, 2],
"ocean": ["fishy", "salty"]
}
-
<A: true a 0.123 1234 asdf false p4ssw0rd>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null}
# Back in Nit:
<A: true a 0.123 1234 asdf false p4ssw0rd>
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"}
# Back in Nit:
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null},"b": {"__kind": "obj", "__id": 2, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null},"b":{"__kind": "obj", "__id": 2, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Back in Nit:
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
<- false p4ssw0rd> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "new line ->\n<-","n": null,"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"new line ->\n<-","n":null,"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
# Back in Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<E: a: hello, 1234, 123.4; b: hella, 2345, 234.5>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "E","a": {"__kind": "obj", "__id": 1, "__class": "Array","__items": ["hello",1234,123.4]},"b": {"__kind": "obj", "__id": 2, "__class": "Array","__items": ["hella",2345,234.5]}}
+{"__kind": "obj", "__id": 0, "__class": "E","a":{"__kind": "obj", "__id": 1, "__class": "Array","__items": ["hello",1234,123.4]},"b":{"__kind": "obj", "__id": 2, "__class": "Array","__items": ["hella",2345,234.5]}}
# Back in Nit:
<E: a: hello, 1234, 123.4; b: hella, 2345, 234.5>
<E: 2222>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "F","n": 2222}
+{"__kind": "obj", "__id": 0, "__class": "F","n":2222}
# Back in Nit:
null
<E: 33.33>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "F","n": 33.33}
+{"__kind": "obj", "__id": 0, "__class": "F","n":33.33}
# Back in Nit:
null
<G: hs: -1, 0; s: one, two; hm: one. 1, two. 2; am: three. 3, four. 4>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "G","hs": {"__kind": "obj", "__id": 1, "__class": "HashSet","__items": [-1,0]},"s": {"__kind": "obj", "__id": 2, "__class": "ArraySet","__items": ["one","two"]},"hm": {"__kind": "obj", "__id": 3, "__class": "HashMap", "__length": 2,"__keys": ["one","two"],"__values": [1,2]},"am": {"__kind": "obj", "__id": 4, "__class": "ArrayMap", "__length": 2,"__keys": ["three","four"],"__values": ["3","4"]}}
+{"__kind": "obj", "__id": 0, "__class": "G","hs":{"__kind": "obj", "__id": 1, "__class": "HashSet","__items": [-1,0]},"s":{"__kind": "obj", "__id": 2, "__class": "ArraySet","__items": ["one","two"]},"hm":{"__kind": "obj", "__id": 3, "__class": "HashMap", "__length": 2,"__keys": ["one","two"],"__values": [1,2]},"am":{"__kind": "obj", "__id": 4, "__class": "ArrayMap", "__length": 2,"__keys": ["three","four"],"__values": ["3","4"]}}
# Back in Nit:
<G: hs: ; s: ; hm: ; am: >
"__kind": "obj", "__id": 0, "__class": "E",
"a": {
"__kind": "obj", "__id": 1, "__class": "Array",
- "__items": [
- "hello",
- 1234,
- 123.4
- ]
+ "__items": ["hello", 1234, 123.4]
},
"b": {
"__kind": "obj", "__id": 2, "__class": "Array",
- "__items": [
- "hella",
- 2345,
- 234.5
- ]
+ "__items": ["hella", 2345, 234.5]
}
}
"__kind": "obj", "__id": 0, "__class": "G",
"hs": {
"__kind": "obj", "__id": 1, "__class": "HashSet",
- "__items": [
- -1,
- 0
- ]
+ "__items": [-1, 0]
},
"s": {
"__kind": "obj", "__id": 2, "__class": "ArraySet",
- "__items": [
- "one",
- "two"
- ]
+ "__items": ["one", "two"]
},
"hm": {
"__kind": "obj", "__id": 3, "__class": "HashMap", "__length": 2,
- "__keys": [
- "one",
- "two"
- ],
- "__values": [
- 1,
- 2
- ]
+ "__keys": ["one", "two"],
+ "__values": [1, 2]
},
"am": {
"__kind": "obj", "__id": 4, "__class": "ArrayMap", "__length": 2,
- "__keys": [
- "three",
- "four"
- ],
- "__values": [
- "3",
- "4"
- ]
+ "__keys": ["three", "four"],
+ "__values": ["3", "4"]
}
}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]}},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]}},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]}},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]}},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef"}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef"},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","ffff": 6.789,"bbbb": false,"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","ffff":6.789,"bbbb":false,"d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef"}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef"},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "\tf\"\r\\/","ffff": 6.789,"bbbb": false,"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"\tf\"\r\\/","ffff":6.789,"bbbb":false,"d":{"__kind": "ref", "__id": 0}}
"Zip": "94085",
"Country": "US"
}]
-
<A: true a 0.123 1234 asdf false p4ssw0rd>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null}
# Back in Nit:
<A: true a 0.123 1234 asdf false p4ssw0rd>
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"}
# Back in Nit:
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null},"b": {"__kind": "obj", "__id": 2, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null},"b":{"__kind": "obj", "__id": 2, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Back in Nit:
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
<- false p4ssw0rd> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "new line ->\n<-","n": null,"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"new line ->\n<-","n":null,"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
# Back in Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<A: true a 0.123 1234 asdf false p4ssw0rd>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null}
# Back in Nit:
<A: true a 0.123 1234 asdf false p4ssw0rd>
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"}
# Back in Nit:
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null},"b": {"__kind": "obj", "__id": 2, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null},"b":{"__kind": "obj", "__id": 2, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Back in Nit:
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
<- false p4ssw0rd> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"serialization_specific_name": "new line ->\n<-","n": null,"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"serialization_specific_name":"new line ->\n<-","n":null,"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
# Back in Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<E: a: hello, 1234, 123.4; b: hella, 2345, 234.5>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "E","a": {"__kind": "obj", "__id": 1, "__class": "Array[Object]","__items": ["hello",1234,123.4]},"b": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Serializable]","__items": ["hella",2345,234.5]}}
+{"__kind": "obj", "__id": 0, "__class": "E","a":{"__kind": "obj", "__id": 1, "__class": "Array[Object]","__items": ["hello",1234,123.4]},"b":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Serializable]","__items": ["hella",2345,234.5]}}
# Back in Nit:
<E: a: hello, 1234, 123.4; b: hella, 2345, 234.5>
<E: 2222>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "F[Int]","n": 2222}
+{"__kind": "obj", "__id": 0, "__class": "F[Int]","n":2222}
# Back in Nit:
<E: 2222>
<E: 33.33>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "F[Float]","n": 33.33}
+{"__kind": "obj", "__id": 0, "__class": "F[Float]","n":33.33}
# Back in Nit:
<E: 33.33>
<G: hs: -1, 0; s: one, two; hm: one. 1, two. 2; am: three. 3, four. 4>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "G","hs": {"__kind": "obj", "__id": 1, "__class": "HashSet[Int]","__items": [-1,0]},"s": {"__kind": "obj", "__id": 2, "__class": "ArraySet[String]","__items": ["one","two"]},"hm": {"__kind": "obj", "__id": 3, "__class": "HashMap[String, Int]", "__length": 2,"__keys": ["one","two"],"__values": [1,2]},"am": {"__kind": "obj", "__id": 4, "__class": "ArrayMap[String, String]", "__length": 2,"__keys": ["three","four"],"__values": ["3","4"]}}
+{"__kind": "obj", "__id": 0, "__class": "G","hs":{"__kind": "obj", "__id": 1, "__class": "HashSet[Int]","__items": [-1,0]},"s":{"__kind": "obj", "__id": 2, "__class": "ArraySet[String]","__items": ["one","two"]},"hm":{"__kind": "obj", "__id": 3, "__class": "HashMap[String, Int]", "__length": 2,"__keys": ["one","two"],"__values": [1,2]},"am":{"__kind": "obj", "__id": 4, "__class": "ArrayMap[String, String]", "__length": 2,"__keys": ["three","four"],"__values": ["3","4"]}}
# Back in Nit:
<G: hs: -1, 0; s: one, two; hm: one. 1, two. 2; am: three. 3, four. 4>
<A: true a 0.123 1234 asdf false p4ssw0rd>
# Json:
-{"b": true,"c": "a","f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null}
+{"b":true,"c":"a","f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null}
# Nit:
<B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>
# Json:
-{"b": false,"c": "b","f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"}
+{"b":false,"c":"b","f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false p4ssw0rd> <B: <A: false b 123.123 2345 hjkl true p4ssw0rd> 1111 qwer>>
# Json:
-{"a": {"b": true,"c": "a","f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null},"b": {"b": false,"c": "b","f": 123.123,"i": 2345,"serialization_specific_name": "hjkl","n": 12,"ii": 1111,"ss": "qwer"},"aa": {"b": true,"c": "a","f": 0.123,"i": 1234,"serialization_specific_name": "asdf","n": null}}
+{"a":{"b":true,"c":"a","f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null},"b":{"b":false,"c":"b","f":123.123,"i":2345,"serialization_specific_name":"hjkl","n":12,"ii":1111,"ss":"qwer"},"aa":{"b":true,"c":"a","f":0.123,"i":1234,"serialization_specific_name":"asdf","n":null}}
Serialization warning: Cycle detected in serialized object, replacing reference with 'null'.
# Nit:
<- false p4ssw0rd> 1111 f"\r\/> true>
# Json:
-{"b": false,"c": "b","f": 123.123,"i": 2345,"serialization_specific_name": "new line ->\n<-","n": null,"ii": 1111,"ss": "\tf\"\r\\/","d": null}
+{"b":false,"c":"b","f":123.123,"i":2345,"serialization_specific_name":"new line ->\n<-","n":null,"ii":1111,"ss":"\tf\"\r\\/","d":null}
# Nit:
<E: a: hello, 1234, 123.4; b: hella, 2345, 234.5>
# Json:
-{"a": ["hello",1234,123.4],"b": ["hella",2345,234.5]}
+{"a":["hello",1234,123.4],"b":["hella",2345,234.5]}
# Nit:
<E: 2222>
# Json:
-{"n": 2222}
+{"n":2222}
# Nit:
<E: 33.33>
# Json:
-{"n": 33.33}
+{"n":33.33}
# Nit:
<G: hs: -1, 0; s: one, two; hm: one. 1, two. 2; am: three. 3, four. 4>
# Json:
-{"hs": [-1,0],"s": ["one","two"],"hm": {"one": 1,"two": 2},"am": {"three": "3","four": "4"}}
+{"hs":[-1,0],"s":["one","two"],"hm":{"one":1,"two":2},"am":{"three":"3","four":"4"}}
"__kind": "obj", "__id": 0, "__class": "E",
"a": {
"__kind": "obj", "__id": 1, "__class": "Array[Object]",
- "__items": [
- "hello",
- 1234,
- 123.4
- ]
+ "__items": ["hello", 1234, 123.4]
},
"b": {
"__kind": "obj", "__id": 2, "__class": "Array[nullable Serializable]",
- "__items": [
- "hella",
- 2345,
- 234.5
- ]
+ "__items": ["hella", 2345, 234.5]
}
}
"__kind": "obj", "__id": 0, "__class": "G",
"hs": {
"__kind": "obj", "__id": 1, "__class": "HashSet[Int]",
- "__items": [
- -1,
- 0
- ]
+ "__items": [-1, 0]
},
"s": {
"__kind": "obj", "__id": 2, "__class": "ArraySet[String]",
- "__items": [
- "one",
- "two"
- ]
+ "__items": ["one", "two"]
},
"hm": {
"__kind": "obj", "__id": 3, "__class": "HashMap[String, Int]", "__length": 2,
- "__keys": [
- "one",
- "two"
- ],
- "__values": [
- 1,
- 2
- ]
+ "__keys": ["one", "two"],
+ "__values": [1, 2]
},
"am": {
"__kind": "obj", "__id": 4, "__class": "ArrayMap[String, String]", "__length": 2,
- "__keys": [
- "three",
- "four"
- ],
- "__values": [
- "3",
- "4"
- ]
+ "__keys": ["three", "four"],
+ "__values": ["3", "4"]
}
}
# Json:
{
- "a": [
- "hello",
- 1234,
- 123.4
- ],
- "b": [
- "hella",
- 2345,
- 234.5
- ]
+ "a": ["hello", 1234, 123.4],
+ "b": ["hella", 2345, 234.5]
}
# Nit:
# Json:
{
- "hs": [
- -1,
- 0
- ],
- "s": [
- "one",
- "two"
- ],
+ "hs": [-1, 0],
+ "s": ["one", "two"],
"hm": {
"one": 1,
"two": 2
# Nit: <MyClass i:123 s:hello f:123.456 a:[one, two] o:<null>>
# JSON: not valid json
-# Errors: 'Parsing error at line 1, position 1: Error: bad JSON entity'
+# Errors: 'Error: bad JSON entity'
# Nit: null
"beer": "test",
"name": "Gaëa"
}
-
out/test_platform_ios.bin/LaunchScreen.storyboardc/Info.plist
out/test_platform_ios.bin/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
out/test_platform_ios.bin/PkgInfo
+out/test_platform_ios.bin/_CodeSignature
+out/test_platform_ios.bin/_CodeSignature/CodeResources
out/test_platform_ios.bin/test_platform_ios
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"b": true,"c": "a","f": 0.123,"i": 1234,"s": "asdf","n": null,"array": [88,"hello",null]}
+{"b":true,"c":"a","f":0.123,"i":1234,"s":"asdf","n":null,"array":[88,"hello",null]}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"b": false,"c": "b","f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": [88,"hello",null],"ii": 1111,"ss": "qwer"}
+{"b":false,"c":"b","f":123.123,"i":2345,"s":"hjkl","n":12,"array":[88,"hello",null],"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"a": {"b": true,"c": "a","f": 0.123,"i": 1234,"s": "asdf","n": null,"array": [88,"hello",null]},"b": {"b": false,"c": "b","f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": [88,"hello",null],"ii": 1111,"ss": "qwer"},"aa": {"b": true,"c": "a","f": 0.123,"i": 1234,"s": "asdf","n": null,"array": [88,"hello",null]}}
+{"a":{"b":true,"c":"a","f":0.123,"i":1234,"s":"asdf","n":null,"array":[88,"hello",null]},"b":{"b":false,"c":"b","f":123.123,"i":2345,"s":"hjkl","n":12,"array":[88,"hello",null],"ii":1111,"ss":"qwer"},"aa":{"b":true,"c":"a","f":0.123,"i":1234,"s":"asdf","n":null,"array":[88,"hello",null]}}
Serialization warning: Cycle detected in serialized object, replacing reference with 'null'.
# Nit:
<- false> 1111 f"\r\/> true>
# Json:
-{"b": false,"c": "b","f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": [88,"hello",null],"ii": 1111,"ss": "\tf\"\r\\/","d": null}
+{"b":false,"c":"b","f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":[88,"hello",null],"ii":1111,"ss":"\tf\"\r\\/","d":null}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef"}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer"}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer"}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer"},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef"},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer"},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "\tf\"\r\\/","d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"\tf\"\r\\/","d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]}}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]}},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii": 1111,"ss": "\tf\"\r\\/","ffff": 6.789,"bbbb": false,"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"ii":1111,"ss":"\tf\"\r\\/","ffff":6.789,"bbbb":false,"d":{"__kind": "ref", "__id": 0}}
<A: true a 0.123 1234 asdf false>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"}
+{"__kind": "obj", "__id": 0, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef"}
# Nit:
<B: <A: false b 123.123 2345 hjkl true> 1111 qwer>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false}
+{"__kind": "obj", "__id": 0, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false}
# Nit:
<C: <A: true a 0.123 1234 asdf false> <B: <A: false b 123.123 2345 hjkl true> 1111 qwer>>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "C","a": {"__kind": "obj", "__id": 1, "__class": "A","b": true,"c": {"__kind": "char", "__val": "a"},"f": 0.123,"i": 1234,"s": "asdf","n": null,"array": {"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef"},"b": {"__kind": "obj", "__id": 3, "__class": "B","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "hjkl","n": 12,"array": {"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "qwer","ffff": 6.789,"bbbb": false},"aa": {"__kind": "ref", "__id": 1}}
+{"__kind": "obj", "__id": 0, "__class": "C","a":{"__kind": "obj", "__id": 1, "__class": "A","b":true,"c":{"__kind": "char", "__val": "a"},"f":0.123,"i":1234,"s":"asdf","n":null,"array":{"__kind": "obj", "__id": 2, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef"},"b":{"__kind": "obj", "__id": 3, "__class": "B","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"hjkl","n":12,"array":{"__kind": "obj", "__id": 4, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"qwer","ffff":6.789,"bbbb":false},"aa":{"__kind": "ref", "__id": 1}}
# Nit:
<D: <B: <A: false b 123.123 2345 new line ->
<- false> 1111 f"\r\/> true>
# Json:
-{"__kind": "obj", "__id": 0, "__class": "D","b": false,"c": {"__kind": "char", "__val": "b"},"f": 123.123,"i": 2345,"s": "new line ->\n<-","n": null,"array": {"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii": 6789,"sss": "redef","ii": 1111,"ss": "\tf\"\r\\/","ffff": 6.789,"bbbb": false,"d": {"__kind": "ref", "__id": 0}}
+{"__kind": "obj", "__id": 0, "__class": "D","b":false,"c":{"__kind": "char", "__val": "b"},"f":123.123,"i":2345,"s":"new line ->\n<-","n":null,"array":{"__kind": "obj", "__id": 1, "__class": "Array[nullable Object]","__items": [88,"hello",null]},"iii":6789,"sss":"redef","ii":1111,"ss":"\tf\"\r\\/","ffff":6.789,"bbbb":false,"d":{"__kind": "ref", "__id": 0}}
# limitations under the License.
import test_deserialization
-import json::serialization
+import json
#alt1# import test_deserialization_serial
#alt3# import test_deserialization_serial
# See the License for the specific language governing permissions and
# limitations under the License.
-import json::serialization
+import json
import json::static
class MyData
# See the License for the specific language governing permissions and
# limitations under the License.
-import json::serialization
+import json
import json::static
class MyClass
# See the License for the specific language governing permissions and
# limitations under the License.
+import json::static
import json
var str = """{
#alt2#module test_serialization_alt2 is serialize
import serialization
-import json::serialization
+import json
# Simple class
class A