c82a24084dab2717beaeee2aa2982829a5bdbc4d
1 # You may obtain a copy of the License at
3 # http://www.apache.org/licenses/LICENSE-2.0
5 # Unless required by applicable law or agreed to in writing, software
6 # distributed under the License is distributed on an "AS IS" BASIS,
7 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 # See the License for the specific language governing permissions and
9 # limitations under the License.
11 # Introduce base classes and services for JSON handling.
15 private import json
::json_parser
16 private import json
::json_lexer
18 # Something that can be translated to JSON
20 # Get the JSON representation of `self`
21 fun to_json
: String is abstract
28 var res
= new FlatBuffer
30 for i
in [0..self.length
[ do
35 else if char
== '\"' then
38 else if char == '\/' then
41 else if char == '\n' then
44 else if char == '\r' then
47 else if char == '\t' then
54 return res.write_to_string
61 redef fun to_json do return self.to_s
67 redef fun to_json do return self.to_s
73 redef fun to_json do return self.to_s
76 # A JSON Object representation that behaves like a `Map`
79 super Map[String, nullable Jsonable]
81 private var map = new HashMap[String, nullable Jsonable]
83 # Create an empty `JsonObject`
85 # var obj = new JsonObject
89 # Init the JSON Object from a Nit `Map`
91 # var map = new HashMap[String, String]
94 # var obj = new JsonObject.from(map)
95 # assert obj.length == 2
96 # assert obj["foo"] == "bar"
97 # assert obj["goo"] == "baz"
98 init from(items: Map[String, nullable Jsonable]) do
99 for k, v in items do map[k] = v
102 redef fun [](key) do return map[key]
103 redef fun []=(key, value) do map[key] = value
104 redef fun clear do map.clear
105 redef fun has_key(key) do return map.has_key(key)
106 redef fun is_empty do return map.is_empty
107 redef fun iterator do return map.iterator
108 redef fun keys do return map.keys
109 redef fun values do return map.values
110 redef fun length do return map.length
112 # Advanced query to get a value within `self` or its children.
114 # A query is composed of the keys to each object seperated by '.'.
116 # REQUIRE `self.has_key(query)`
118 # var obj1 = new JsonObject
119 # obj1["baz"] = "foobarbaz"
120 # var obj2 = new JsonObject
122 # var obj3 = new JsonObject
124 # assert obj3.get("foo.bar.baz") == "foobarbaz"
125 fun get(query: String): nullable Jsonable do
126 var keys = query.split(".").reversed
132 while not keys.is_empty do
134 assert node isa JsonObject and node.has_key(key)
140 # Create an empty `JsonObject`
142 # var obj = new JsonObject
144 # assert obj.to_json == "\{\"foo\": \"bar\"\}"
146 var tpl = new Array[String]
148 var vals = new Array[String]
151 vals.add "{k.to_json}: null"
153 vals.add "{k.to_json}: {v.to_json}"
156 tpl.add vals.join(",")
161 redef fun to_s do return to_json
164 # A JSON Array representation that behaves like a `Sequence`
167 super Sequence[nullable Jsonable]
169 private var array = new Array[nullable Jsonable]
173 # init the JSON Array from a Nit `Collection`
174 init from(items: Collection[nullable Jsonable]) do
178 redef fun [](key) do return array[key]
179 redef fun []=(key, value) do array[key] = value
180 redef fun clear do array.clear
181 redef fun insert(item, index) do array.insert(item, index)
182 redef fun is_empty do return array.is_empty
183 redef fun iterator do return array.iterator
184 redef fun length do return array.length
185 redef fun pop do return array.pop
186 redef fun push(value) do array.push(value)
187 redef fun remove_at(index) do array.remove_at(index)
188 redef fun shift do return array.shift
189 redef fun unshift(e) do array.unshift(e)
192 var tpl = new Array[String]
194 var vals = new Array[String]
202 tpl.add vals.join(",")
207 redef fun to_s do return to_json
210 # An error in JSON format that can be returned by tools using JSON like parsers.
212 # var error = new JsonError("ErrorCode", "ErrorMessage")
213 # assert error.to_s == "ErrorCode: ErrorMessage"
214 # assert error.to_json == "\{\"error\": \"ErrorCode\", \"message\": \"ErrorMessage\"\}"
225 var tpl = new Array[String]
227 tpl.add "\"error\": {error.to_json}, "
228 tpl.add "\"message\": {message.to_json}"
233 redef fun to_s do return "{error}: {message}"
239 private fun to_nit_object: nullable Jsonable is abstract
242 redef class Nvalue_number
243 redef fun to_nit_object
245 var text = n_number.text
246 if text.chars.has('.') or text.chars.has('e
') or text.chars.has('E
') then return text.to_f
251 redef class Nvalue_string
252 redef fun to_nit_object do return n_string.to_nit_string
255 redef class Nvalue_true
256 redef fun to_nit_object do return true
259 redef class Nvalue_false
260 redef fun to_nit_object do return false
263 redef class Nvalue_null
264 redef fun to_nit_object do return null
268 # FIXME support \n, etc.
269 fun to_nit_string: String do
270 var res = new FlatBuffer
272 for i in [1..text.length-2] do
278 if char == '\\
' and i < text.length - 2 then
279 if text[i + 1] == '\\
' then
284 if text[i + 1] == '\
"' then
289 if text[i + 1] == '/' then
294 if text[i + 1] == 'n
' then
299 if text[i + 1] == 'r
' then
304 if text[i + 1] == 't
' then
312 return res.write_to_string
316 redef class Nvalue_object
317 redef fun to_nit_object
319 var obj = new JsonObject
320 var members = n_members
321 if members != null then
322 var pairs = members.pairs
323 for pair in pairs do obj[pair.name] = pair.value
330 fun pairs: Array[Npair] is abstract
333 redef class Nmembers_tail
336 var arr = n_members.pairs
342 redef class Nmembers_head
343 redef fun pairs do return [n_pair]
347 fun name: String do return n_string.to_nit_string
348 fun value: nullable Jsonable do return n_value.to_nit_object
351 redef class Nvalue_array
352 redef fun to_nit_object
354 var arr = new JsonArray
355 var elements = n_elements
356 if elements != null then
357 var items = elements.items
358 for item in items do arr.add(item.to_nit_object)
364 redef class Nelements
365 fun items: Array[Nvalue] is abstract
368 redef class Nelements_tail
371 var items = n_elements.items
377 redef class Nelements_head
378 redef fun items do return [n_value]
382 # Parse a JSON String as Jsonable entities
384 # Example with `JsonObject`"
386 # var obj = "\{\"foo\": \{\"bar\": true, \"goo\": [1, 2, 3]\}\}".to_jsonable
387 # assert obj isa JsonObject
388 # assert obj["foo"] isa JsonObject
389 # assert obj["foo"].as(JsonObject)["bar"] == true
391 # Example with `JsonArray`
393 # var arr = "[1, 2, 3]".to_jsonable
394 # assert arr isa JsonArray
395 # assert arr.length == 3
396 # assert arr.first == 1
397 # assert arr.last == 3
399 # Example with `String`
401 # var str = "\"foo, bar, baz\"".to_jsonable
402 # assert str isa String
403 # assert str == "foo, bar, baz"
405 # Malformed JSON input returns a `JsonError` object
407 # var bad = "\{foo: \"bar\"\}".to_jsonable
408 # assert bad isa JsonError
409 # assert bad.error == "JsonLexerError"
410 fun to_jsonable: nullable Jsonable
412 var lexer = new Lexer_json(to_s)
413 var parser = new Parser_json
414 var tokens = lexer.lex
415 parser.tokens.add_all(tokens)
416 var root_node = parser.parse
417 if root_node isa NStart then
418 return root_node.n_0.to_nit_object
419 else if root_node isa NLexerError then
420 var pos = root_node.position
421 var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
422 return new JsonError("JsonLexerError", msg)
423 else if root_node isa NParserError then
424 var pos = root_node.position
425 var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
426 return new JsonError("JsonParsingError", msg)