class Json
class Json
lib/json.tya:2
Json parses and formats JSON values.
Source
# Json parses and formats JSON values.
class Json
# Json.value stores instance state.
# @type Nil
value: nil
# Json.dump formats a Tya value as JSON text.
# @param value String value value.
# @return String the resulting value.
static dump: value ->
Json(nil).dump(value)
# Json.parse parses JSON text into Tya values.
# @param text String text value.
# @return Any the resulting value.
static parse: text ->
Json(nil).parse(text)
# Json.initialize stores a value or JSON text.
# @param value String value value.
# @return Self the initialized object.
initialize: value = nil ->
self.value = value
# dump is a compatibility alias for stringify.
# @param value String value value.
# @return String the resulting value.
dump: value = nil ->
self.stringify(value)
# Json.emit provides the json/Json standard library operation.
# @param value String value value.
# @param indent Any indent value.
# @param level Any level value.
# @return Any the resulting value.
emit: value, indent, level ->
if value.class == Nil
return "null"
if value.class == Boolean
if value
return "true"
return "false"
if value.class == Number
return value.to_s()
if value.class == String
return Json(nil).escape_string(value)
if value.class == Array
n = value.len()
if n == 0
return "[]"
out = "["
i = 0
while i < n
if i > 0
out = out + ","
out = out + Json(nil).pad(indent, level + 1)
out = out + Json(nil).emit(value[i], indent, level + 1)
i = i + 1
out = out + Json(nil).pad(indent, level)
return out + "]"
if value.class == Dict
names = value.keys()
n = names.len()
if n == 0
return "{{}}"
out = "{{"
i = 0
while i < n
if i > 0
out = out + ","
out = out + Json(nil).pad(indent, level + 1)
key_name = names[i]
out = out + Json(nil).escape_string(key_name) + ":"
if indent > 0
out = out + " "
out = out + Json(nil).emit(value[key_name], indent, level + 1)
i = i + 1
out = out + Json(nil).pad(indent, level)
return out + "}}"
raise error("json.dump: unsupported value kind")
# Json.escape_string provides the json/Json standard library operation.
# @param text String text value.
# @return String the resulting value.
escape_string: text ->
n = Json(nil).text_len(text)
out = "\""
i = 0
while i < n
c = text[i]
code = ord(c)
if c == "\""
out = out + "\\\""
elseif c == "\\"
out = out + "\\\\"
else
if c == "\n"
out = out + "\\n"
elseif c == "\t"
out = out + "\\t"
else
if code == 13
out = out + "\\r"
elseif code == 8
out = out + "\\b"
else
if code == 12
out = out + "\\f"
elseif code < 32
hi_d = code / 16.to_i()
lo_d = code % 16
hi = chr(48 + hi_d)
if hi_d >= 10
hi = chr(55 + hi_d)
lo = chr(48 + lo_d)
if lo_d >= 10
lo = chr(55 + lo_d)
out = out + "\\u00" + hi + lo
else
out = out + c
i = i + 1
out + "\""
# Json.expect provides the json/Json standard library operation.
# @param state Any state value.
# @param ch Any ch value.
# @return Any the resulting value.
expect: state, ch ->
Json(nil).skip_ws(state)
p = state["pos"]
if p >= state["len"] or state["src"][p] != ch
raise error("json.parse: expected '{ch}'")
state["pos"] = p + 1
# Json.hex_value provides the json/Json standard library operation.
# @param c Any c value.
# @return Any the resulting value.
hex_value: c ->
code = ord(c)
if code >= 48 and code <= 57
return code - 48
if code >= 65 and code <= 70
return code - 55
if code >= 97 and code <= 102
return code - 87
raise error("json.parse: invalid hex digit")
# Json.is_digit provides the json/Json standard library operation.
# @param c Any c value.
# @return Boolean the resulting value.
is_digit: c ->
code = ord(c)
code >= 48 and code <= 57
# Json.pad provides the json/Json standard library operation.
# @param indent Any indent value.
# @param level Any level value.
# @return Any the resulting value.
pad: indent, level ->
if indent <= 0
return ""
out = "\n"
spaces = ""
k = 0
while k < indent
spaces = spaces + " "
k = k + 1
k = 0
while k < level
out = out + spaces
k = k + 1
out
# parse converts JSON text into Tya arrays, dictionaries, strings, numbers, booleans, and nil.
# Raises when the input is not valid JSON.
# @param text String text value.
# @return Any the resulting value.
parse: text = nil ->
if text == nil
text = self.value
state = { src: text, pos: 0, len: Json(nil).text_len(text) }
v = Json(nil).parse_value(state)
Json(nil).skip_ws(state)
if state["pos"] < state["len"]
raise error("json.parse: trailing characters")
v
# Json.parse_array provides the json/Json standard library operation.
# @param state Any state value.
# @return Array the resulting value.
parse_array: state ->
Json(nil).expect(state, "[")
out = []
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "]"
state["pos"] = p + 1
return out
first = true
while true
if not first
Json(nil).expect(state, ",")
first = false
v = Json(nil).parse_value(state)
out.push(v)
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "]"
state["pos"] = p + 1
return out
# Json.parse_number provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
parse_number: state ->
p = state["pos"]
src = state["src"]
n = state["len"]
start = p
if src[p] == "-"
p = p + 1
while p < n and Json(nil).is_digit(src[p])
p = p + 1
is_float = false
if p < n and src[p] == "."
is_float = true
p = p + 1
while p < n and Json(nil).is_digit(src[p])
p = p + 1
if p < n and (src[p] == "e" or src[p] == "E")
is_float = true
p = p + 1
if p < n and (src[p] == "+" or src[p] == "-")
p = p + 1
while p < n and Json(nil).is_digit(src[p])
p = p + 1
text = ""
k = start
while k < p
text = text + src[k]
k = k + 1
state["pos"] = p
if is_float
return text.to_f()
text.to_i()
# Json.parse_object provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
parse_object: state ->
Json(nil).expect(state, "{{")
out = {}
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "}}"
state["pos"] = p + 1
return out
first = true
while true
if not first
Json(nil).expect(state, ",")
first = false
Json(nil).skip_ws(state)
key = Json(nil).parse_string(state)
Json(nil).expect(state, ":")
value = Json(nil).parse_value(state)
out[key] = value
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "}}"
state["pos"] = p + 1
return out
# Json.parse_string provides the json/Json standard library operation.
# @param state Any state value.
# @return String the resulting value.
parse_string: state ->
p = state["pos"]
src = state["src"]
n = state["len"]
if p >= n or src[p] != "\""
raise error("json.parse: expected string")
p = p + 1
out = ""
while p < n
c = src[p]
if c == "\""
state["pos"] = p + 1
return out
if c == "\\"
if p + 1 >= n
raise error("json.parse: truncated escape")
e = src[p + 1]
if e == "\""
out = out + "\""
elseif e == "\\"
out = out + "\\"
else
if e == "/"
out = out + "/"
elseif e == "n"
out = out + "\n"
else
if e == "t"
out = out + "\t"
elseif e == "r"
out = out + chr(13)
else
if e == "b"
out = out + chr(8)
elseif e == "f"
out = out + chr(12)
else
if e == "u"
if p + 5 >= n
raise error("json.parse: truncated unicode escape")
h1 = Json(nil).hex_value(src[p + 2])
h2 = Json(nil).hex_value(src[p + 3])
h3 = Json(nil).hex_value(src[p + 4])
h4 = Json(nil).hex_value(src[p + 5])
code = h1 * 4096 + h2 * 256 + h3 * 16 + h4
out = out + Json(nil).utf8_encode(code)
p = p + 4
else
raise error("json.parse: invalid escape")
p = p + 2
else
out = out + c
p = p + 1
raise error("json.parse: unterminated string")
# Json.parse_value provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
parse_value: state ->
Json(nil).skip_ws(state)
p = state["pos"]
if p >= state["len"]
raise error("json.parse: unexpected end of input")
src = state["src"]
c = src[p]
if c == "{{"
return Json(nil).parse_object(state)
if c == "["
return Json(nil).parse_array(state)
if c == "\""
return Json(nil).parse_string(state)
if c == "t"
if (
p + 4 <= state["len"] and src[p + 1] == "r" and src[p + 2] == "u" and src[p + 3] == "e"
)
state["pos"] = p + 4
return true
raise error("json.parse: invalid token")
if c == "f"
if (
p + 5 <= state["len"] and src[p + 1] == "a" and src[p + 2] == "l" and src[p + 3] == "s" and src[p + 4] == "e"
)
state["pos"] = p + 5
return false
raise error("json.parse: invalid token")
if c == "n"
if (
p + 4 <= state["len"] and src[p + 1] == "u" and src[p + 2] == "l" and src[p + 3] == "l"
)
state["pos"] = p + 4
return nil
raise error("json.parse: invalid token")
if c == "-" or Json(nil).is_digit(c)
return Json(nil).parse_number(state)
raise error("json.parse: unexpected character")
# Json.skip_ws provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
skip_ws: state ->
n = state["len"]
p = state["pos"]
src = state["src"]
while p < n
c = src[p]
if c != " " and c != "\t" and c != "\n" and c != chr(13)
state["pos"] = p
return nil
p = p + 1
state["pos"] = p
# stringify converts Tya arrays, dictionaries, strings, numbers, booleans, and nil to JSON text.
# Raises when a value cannot be represented as JSON.
# @param value String value value.
# @return String the resulting value.
stringify: value = nil ->
if value == nil
value = self.value
Json(nil).emit(value, 0, 0)
# Json.text_len counts string indexes, independent of byte length.
# @param text String text value.
# @return String the resulting value.
text_len: text ->
i = 0
while text[i] != nil
i = i + 1
i
# Json.utf8_encode provides the json/Json standard library operation.
# @param code Int code value.
# @return Any the resulting value.
utf8_encode: code ->
if code < 128
return chr(code)
if code < 2048
b1 = 192 + code / 64.to_i()
b2 = 128 + code % 64
return chr(b1) + chr(b2)
b1 = 224 + code / 4096.to_i()
b2 = 128 + code % 4096 / 64.to_i()
b3 = 128 + code % 64
chr(b1) + chr(b2) + chr(b3)
Instance Variables
value
Json.value
lib/json.tya:5
Json.value stores instance state.
Source
# Json.value stores instance state.
# @type Nil
value: nil
Static Methods
dump
static Json.dump(value)
lib/json.tya:10
Json.dump formats a Tya value as JSON text.
Source
# Json.dump formats a Tya value as JSON text.
# @param value String value value.
# @return String the resulting value.
static dump: value ->
Json(nil).dump(value)
parse
static Json.parse(text)
lib/json.tya:16
Json.parse parses JSON text into Tya values.
Source
# Json.parse parses JSON text into Tya values.
# @param text String text value.
# @return Any the resulting value.
static parse: text ->
Json(nil).parse(text)
Methods
dump
Json.dump(value = nil)
lib/json.tya:28
dump is a compatibility alias for stringify.
Source
# dump is a compatibility alias for stringify.
# @param value String value value.
# @return String the resulting value.
dump: value = nil ->
self.stringify(value)
emit
Json.emit(value, indent, level)
lib/json.tya:36
Json.emit provides the json/Json standard library operation.
Source
# Json.emit provides the json/Json standard library operation.
# @param value String value value.
# @param indent Any indent value.
# @param level Any level value.
# @return Any the resulting value.
emit: value, indent, level ->
if value.class == Nil
return "null"
if value.class == Boolean
if value
return "true"
return "false"
if value.class == Number
return value.to_s()
if value.class == String
return Json(nil).escape_string(value)
if value.class == Array
n = value.len()
if n == 0
return "[]"
out = "["
i = 0
while i < n
if i > 0
out = out + ","
out = out + Json(nil).pad(indent, level + 1)
out = out + Json(nil).emit(value[i], indent, level + 1)
i = i + 1
out = out + Json(nil).pad(indent, level)
return out + "]"
if value.class == Dict
names = value.keys()
n = names.len()
if n == 0
return "{{}}"
out = "{{"
i = 0
while i < n
if i > 0
out = out + ","
out = out + Json(nil).pad(indent, level + 1)
key_name = names[i]
out = out + Json(nil).escape_string(key_name) + ":"
if indent > 0
out = out + " "
out = out + Json(nil).emit(value[key_name], indent, level + 1)
i = i + 1
out = out + Json(nil).pad(indent, level)
return out + "}}"
raise error("json.dump: unsupported value kind")
escape_string
Json.escape_string(text)
lib/json.tya:85
Json.escape_string provides the json/Json standard library operation.
Source
# Json.escape_string provides the json/Json standard library operation.
# @param text String text value.
# @return String the resulting value.
escape_string: text ->
n = Json(nil).text_len(text)
out = "\""
i = 0
while i < n
c = text[i]
code = ord(c)
if c == "\""
out = out + "\\\""
elseif c == "\\"
out = out + "\\\\"
else
if c == "\n"
out = out + "\\n"
elseif c == "\t"
out = out + "\\t"
else
if code == 13
out = out + "\\r"
elseif code == 8
out = out + "\\b"
else
if code == 12
out = out + "\\f"
elseif code < 32
hi_d = code / 16.to_i()
lo_d = code % 16
hi = chr(48 + hi_d)
if hi_d >= 10
hi = chr(55 + hi_d)
lo = chr(48 + lo_d)
if lo_d >= 10
lo = chr(55 + lo_d)
out = out + "\\u00" + hi + lo
else
out = out + c
i = i + 1
out + "\""
expect
Json.expect(state, ch)
lib/json.tya:128
Json.expect provides the json/Json standard library operation.
Source
# Json.expect provides the json/Json standard library operation.
# @param state Any state value.
# @param ch Any ch value.
# @return Any the resulting value.
expect: state, ch ->
Json(nil).skip_ws(state)
p = state["pos"]
if p >= state["len"] or state["src"][p] != ch
raise error("json.parse: expected '{ch}'")
state["pos"] = p + 1
hex_value
Json.hex_value(c)
lib/json.tya:138
Json.hex_value provides the json/Json standard library operation.
Source
# Json.hex_value provides the json/Json standard library operation.
# @param c Any c value.
# @return Any the resulting value.
hex_value: c ->
code = ord(c)
if code >= 48 and code <= 57
return code - 48
if code >= 65 and code <= 70
return code - 55
if code >= 97 and code <= 102
return code - 87
raise error("json.parse: invalid hex digit")
initialize
Json.initialize(value = nil)
lib/json.tya:22
Json.initialize stores a value or JSON text.
Source
# Json.initialize stores a value or JSON text.
# @param value String value value.
# @return Self the initialized object.
initialize: value = nil ->
self.value = value
is_digit
Json.is_digit(c)
lib/json.tya:151
Json.is_digit provides the json/Json standard library operation.
Source
# Json.is_digit provides the json/Json standard library operation.
# @param c Any c value.
# @return Boolean the resulting value.
is_digit: c ->
code = ord(c)
code >= 48 and code <= 57
pad
Json.pad(indent, level)
lib/json.tya:159
Json.pad provides the json/Json standard library operation.
Source
# Json.pad provides the json/Json standard library operation.
# @param indent Any indent value.
# @param level Any level value.
# @return Any the resulting value.
pad: indent, level ->
if indent <= 0
return ""
out = "\n"
spaces = ""
k = 0
while k < indent
spaces = spaces + " "
k = k + 1
k = 0
while k < level
out = out + spaces
k = k + 1
out
parse
Json.parse(text = nil)
lib/json.tya:178
parse converts JSON text into Tya arrays, dictionaries, strings, numbers, booleans, and nil. Raises when the input is not valid JSON.
Source
# parse converts JSON text into Tya arrays, dictionaries, strings, numbers, booleans, and nil.
# Raises when the input is not valid JSON.
# @param text String text value.
# @return Any the resulting value.
parse: text = nil ->
if text == nil
text = self.value
state = { src: text, pos: 0, len: Json(nil).text_len(text) }
v = Json(nil).parse_value(state)
Json(nil).skip_ws(state)
if state["pos"] < state["len"]
raise error("json.parse: trailing characters")
v
parse_array
Json.parse_array(state)
lib/json.tya:191
Json.parse_array provides the json/Json standard library operation.
Source
# Json.parse_array provides the json/Json standard library operation.
# @param state Any state value.
# @return Array the resulting value.
parse_array: state ->
Json(nil).expect(state, "[")
out = []
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "]"
state["pos"] = p + 1
return out
first = true
while true
if not first
Json(nil).expect(state, ",")
first = false
v = Json(nil).parse_value(state)
out.push(v)
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "]"
state["pos"] = p + 1
return out
parse_number
Json.parse_number(state)
lib/json.tya:215
Json.parse_number provides the json/Json standard library operation.
Source
# Json.parse_number provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
parse_number: state ->
p = state["pos"]
src = state["src"]
n = state["len"]
start = p
if src[p] == "-"
p = p + 1
while p < n and Json(nil).is_digit(src[p])
p = p + 1
is_float = false
if p < n and src[p] == "."
is_float = true
p = p + 1
while p < n and Json(nil).is_digit(src[p])
p = p + 1
if p < n and (src[p] == "e" or src[p] == "E")
is_float = true
p = p + 1
if p < n and (src[p] == "+" or src[p] == "-")
p = p + 1
while p < n and Json(nil).is_digit(src[p])
p = p + 1
text = ""
k = start
while k < p
text = text + src[k]
k = k + 1
state["pos"] = p
if is_float
return text.to_f()
text.to_i()
parse_object
Json.parse_object(state)
lib/json.tya:250
Json.parse_object provides the json/Json standard library operation.
Source
# Json.parse_object provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
parse_object: state ->
Json(nil).expect(state, "{{")
out = {}
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "}}"
state["pos"] = p + 1
return out
first = true
while true
if not first
Json(nil).expect(state, ",")
first = false
Json(nil).skip_ws(state)
key = Json(nil).parse_string(state)
Json(nil).expect(state, ":")
value = Json(nil).parse_value(state)
out[key] = value
Json(nil).skip_ws(state)
p = state["pos"]
if p < state["len"] and state["src"][p] == "}}"
state["pos"] = p + 1
return out
parse_string
Json.parse_string(state)
lib/json.tya:277
Json.parse_string provides the json/Json standard library operation.
Source
# Json.parse_string provides the json/Json standard library operation.
# @param state Any state value.
# @return String the resulting value.
parse_string: state ->
p = state["pos"]
src = state["src"]
n = state["len"]
if p >= n or src[p] != "\""
raise error("json.parse: expected string")
p = p + 1
out = ""
while p < n
c = src[p]
if c == "\""
state["pos"] = p + 1
return out
if c == "\\"
if p + 1 >= n
raise error("json.parse: truncated escape")
e = src[p + 1]
if e == "\""
out = out + "\""
elseif e == "\\"
out = out + "\\"
else
if e == "/"
out = out + "/"
elseif e == "n"
out = out + "\n"
else
if e == "t"
out = out + "\t"
elseif e == "r"
out = out + chr(13)
else
if e == "b"
out = out + chr(8)
elseif e == "f"
out = out + chr(12)
else
if e == "u"
if p + 5 >= n
raise error("json.parse: truncated unicode escape")
h1 = Json(nil).hex_value(src[p + 2])
h2 = Json(nil).hex_value(src[p + 3])
h3 = Json(nil).hex_value(src[p + 4])
h4 = Json(nil).hex_value(src[p + 5])
code = h1 * 4096 + h2 * 256 + h3 * 16 + h4
out = out + Json(nil).utf8_encode(code)
p = p + 4
else
raise error("json.parse: invalid escape")
p = p + 2
else
out = out + c
p = p + 1
raise error("json.parse: unterminated string")
parse_value
Json.parse_value(state)
lib/json.tya:335
Json.parse_value provides the json/Json standard library operation.
Source
# Json.parse_value provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
parse_value: state ->
Json(nil).skip_ws(state)
p = state["pos"]
if p >= state["len"]
raise error("json.parse: unexpected end of input")
src = state["src"]
c = src[p]
if c == "{{"
return Json(nil).parse_object(state)
if c == "["
return Json(nil).parse_array(state)
if c == "\""
return Json(nil).parse_string(state)
if c == "t"
if (
p + 4 <= state["len"] and src[p + 1] == "r" and src[p + 2] == "u" and src[p + 3] == "e"
)
state["pos"] = p + 4
return true
raise error("json.parse: invalid token")
if c == "f"
if (
p + 5 <= state["len"] and src[p + 1] == "a" and src[p + 2] == "l" and src[p + 3] == "s" and src[p + 4] == "e"
)
state["pos"] = p + 5
return false
raise error("json.parse: invalid token")
if c == "n"
if (
p + 4 <= state["len"] and src[p + 1] == "u" and src[p + 2] == "l" and src[p + 3] == "l"
)
state["pos"] = p + 4
return nil
raise error("json.parse: invalid token")
if c == "-" or Json(nil).is_digit(c)
return Json(nil).parse_number(state)
raise error("json.parse: unexpected character")
skip_ws
Json.skip_ws(state)
lib/json.tya:376
Json.skip_ws provides the json/Json standard library operation.
Source
# Json.skip_ws provides the json/Json standard library operation.
# @param state Any state value.
# @return Any the resulting value.
skip_ws: state ->
n = state["len"]
p = state["pos"]
src = state["src"]
while p < n
c = src[p]
if c != " " and c != "\t" and c != "\n" and c != chr(13)
state["pos"] = p
return nil
p = p + 1
state["pos"] = p
stringify
Json.stringify(value = nil)
lib/json.tya:392
stringify converts Tya arrays, dictionaries, strings, numbers, booleans, and nil to JSON text. Raises when a value cannot be represented as JSON.
Source
# stringify converts Tya arrays, dictionaries, strings, numbers, booleans, and nil to JSON text.
# Raises when a value cannot be represented as JSON.
# @param value String value value.
# @return String the resulting value.
stringify: value = nil ->
if value == nil
value = self.value
Json(nil).emit(value, 0, 0)
text_len
Json.text_len(text)
lib/json.tya:400
Json.text_len counts string indexes, independent of byte length.
Source
# Json.text_len counts string indexes, independent of byte length.
# @param text String text value.
# @return String the resulting value.
text_len: text ->
i = 0
while text[i] != nil
i = i + 1
i
utf8_encode
Json.utf8_encode(code)
lib/json.tya:409
Json.utf8_encode provides the json/Json standard library operation.
Source
# Json.utf8_encode provides the json/Json standard library operation.
# @param code Int code value.
# @return Any the resulting value.
utf8_encode: code ->
if code < 128
return chr(code)
if code < 2048
b1 = 192 + code / 64.to_i()
b2 = 128 + code % 64
return chr(b1) + chr(b2)
b1 = 224 + code / 4096.to_i()
b2 = 128 + code % 4096 / 64.to_i()
b3 = 128 + code % 64
chr(b1) + chr(b2) + chr(b3)