protected fun to_json_by_append: String do
var buffer = new RopeBuffer
append_json(buffer)
- return buffer.write_to_string
+ 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
end
redef class Text
redef fun append_json(buffer) do
buffer.add '\"'
- for i in [0..self.length[ do
+ for i in [0 .. self.length[ do
var char = self[i]
if char == '\\' then
buffer.append "\\\\"
buffer.append "\\\""
else if char == '\/' then
buffer.append "\\/"
- else if char < 16.ascii then
+ 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 if char == 0x0C.ascii then
+ else if char == 0x0C.code_point then
buffer.append "\\f"
- else if char == 0x08.ascii then
+ else if char == 0x08.code_point then
buffer.append "\\b"
else
- buffer.append "\\u000{char.ascii.to_hex}"
+ buffer.append char.escape_to_utf16
end
- else if char < ' ' then
- buffer.append "\\u00{char.ascii.to_hex}"
else
buffer.add char
end
# Encode `self` in JSON.
#
- # assert "\t\"http://example.com\"\r\n\0\\".to_json ==
- # "\"\\t\\\"http:\\/\\/example.com\\\"\\r\\n\\u0000\\\\\""
+ # ~~~
+ # assert "\t\"http://example.com\"\r\n\0\\".to_json ==
+ # "\"\\t\\\"http:\\/\\/example.com\\\"\\r\\n\\u0000\\\\\""
+ # ~~~
redef fun to_json do return to_json_by_append
# Parse `self` as JSON.
# 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
# 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)
# 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\"\}"
+ # ~~~
+ # 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}," +
# 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" +
- # "\}"
+ # ~~~
+ # 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}," +
redef class Nstring
# The represented string.
private fun to_nit_string: String do
- var res = new FlatBuffer
+ var res = new Buffer
var i = 1
while i < text.length - 1 do
var char = text[i]
i += 1
char = text[i]
if char == 'b' then
- char = 0x08.ascii
+ char = 0x08.code_point
else if char == 'f' then
- char = 0x0C.ascii
+ char = 0x0C.code_point
else if char == 'n' then
char = '\n'
else if char == 'r' then
else if char == 't' then
char = '\t'
else if char == 'u' then
- var code = text.substring(i + 1, 4).to_hex
- # TODO UTF-16 escaping is not supported yet.
- if code >= 128 then
- char = '?'
- else
- char = code.ascii
+ var escape = new Buffer
+ escape.append "\\u"
+ var code = text.substring(i + 1, 4)
+ escape.append code
+ var hx = code.to_hex
+ if hx >= 0xD800 and hx <= 0xDFFF then
+ var lostr = text.substring(i + 7, 4)
+ if lostr.length < 4 then
+ escape.clear
+ escape.append "\\uFFFD"
+ else
+ escape.append "\\u"
+ escape.append lostr
+ end
+ i += 6
end
i += 4
+ char = escape.from_utf16_escape
end
# `"`, `/` or `\` => Keep `char` as-is.
end
res.add char
i += 1
end
- return res.write_to_string
+ return res.to_s
end
end