class_name Json static func stringify(value: Variant, allow_eval: bool = false) -> String: var ser = Json.Serializer.new(allow_eval) Serde.serialize(ser, value, allow_eval) return ser.output static func parse_string(value: String, into: Variant = null, allow_eval: bool = false) -> Variant: var de = Json.Deserializer.from_string(value) if into != null and into.has_method(Serde.DeserializeMethod): return into.call(Serde.DeserializeMethod, de) else: return de.deserialize_any(Serde.GenericVisitor.new()) class SerializeSeq extends Serde.SerializeSeq: var ser: Json.Serializer var first: bool = true func _init(ser: Json.Serializer) -> void: self.ser = ser ser.write('[') func serialize_element(value: Variant) -> Result: if not first: ser.write(',') first = false Serde.serialize(ser, value, ser.allow_eval) return Result.Unit func end() -> Result: ser.write(']') return Result.Unit class SerializeMap extends Serde.SerializeMap: var ser: Json.Serializer var first: bool = true func _init(ser: Json.Serializer) -> void: self.ser = ser ser.write('{') func serialize_key(value: Variant) -> Result: if not first: ser.write(',') first = false Serde.serialize(ser, value, ser.allow_eval) return Result.Unit func serialize_value(value: Variant) -> Result: ser.write(':') Serde.serialize(ser, value, ser.allow_eval) return Result.Unit func end() -> Result: ser.write('}') return Result.Unit class Serializer extends Serde.Serializer: var output: String var allow_eval: bool func _init(allow_eval: bool = false) -> void: self.allow_eval = allow_eval func write(value: String) -> Result: output += value return Result.Unit func write_string(value: Variant) -> Result: return write(str(value)) func serialize_nil() -> Result: return write("null") func serialize_bool(value: bool) -> Result: return write_string(value) func serialize_int(value: int): return write_string(value) func serialize_float(value: float) -> Result: return write_string(value) func serialize_string(value: String): return write('"%s"' % value) func serialize_seq(_len: int): return Json.SerializeSeq.new(self) func serialize_dict(_len: int): return Json.SerializeMap.new(self) func serialize_object(_name: StringName, len: int): return serialize_dict(len) class Parser extends RefCounted: var de: Json.Deserializer var iter: PeekableIter func _init(de: Json.Deserializer) -> void: self.de = de iter = de._iter static func eq(a: Variant, b: Variant) -> bool: return a == b static func _join(value: Array) -> String: return "".join(value) static func _collect(results: Array[Result]) -> Result: return Result.collect_ok(results).map(_join) func any() -> Result: match iter.peek(): var x when x.is_some(): return Result.ok(iter.next().unwrap()) _: return Result.err(Error.new("eof")) func char(ch: String) -> Result: match iter.peek(): var x when x.filter(eq.bind(ch)).is_some(): return Result.ok(iter.next().unwrap()) var x: return Result.err(Error.new('expecting "%s", got "%s"' % [ch, x.unwrap()])) func str(value: String) -> Result: for i in range(0, value.length()): var ch = self.char(value[i]) if ch.is_err(): return ch return Result.ok(value) func any_of(parsers: Array[Callable]) -> Result: for parser in parsers: var result = parser.call() if result.is_ok(): return result return Result.err(Error.new('none of the provided parsers matched input')) func all_of(parsers: Array) -> Result: var results: Array[String] = [] for parser in parsers: match parser.call(): var x when x.is_ok(): results.append(x.unwrap()) var x: return x return Result.ok(results) func many(parser: Callable, limit: int = 1000) -> Result: var results: Array[String] = [] var value = parser.call() while value.is_ok() and limit > 0: results.append(value.unwrap()) value = parser.call() limit -= 1 if limit <= 0: return Result.err(Error.new("executed too many times (%s)" % limit)) elif len(results) == 0: return Result.err(Error.new("many matched nothing")) else: return Result.ok(results) func until(parser: Callable) -> Result: return many( func (): match parser.call(): var x when x.is_err(): return any() _: return Result.err(null) ) func negate(parser: Callable) -> Result: match parser.call(): var x when x.is_ok(): return Result.err('negated parser passed with value "%s"' % x.unwrap()) _: return Result.Unit func skip(parser: Callable) -> Result: return parser.call().chain(func(_v: Variant) -> Result: return Result.ok('')) func any_char(chars: String) -> Result: for ch in chars: if self.char(ch).is_ok(): return Result.ok(ch) return Result.err(Error.new('expected any of "%s"' % chars)) func optional(parser: Callable, default_value: Variant = '') -> Result.Ok: match parser.call(): var x when x.is_ok(): return x _: return Result.ok(default_value) func ws() -> Result: return any_char(' \t') func skip_ws() -> Result: return skip(many.bind(ws)) func parse_sign() -> Result: return any_char('+-') func parse_digit() -> Result: return any_char('1234567890') func parse_digits() -> Result: return many(parse_digit).map("".join) func parse_integer() -> Result: if self.char('0').is_ok(): return Result.ok(0) var sign = optional(parse_sign) var digits = parse_digits() return _collect([sign, digits]) func parse_exponent() -> Result: var e = any_char('eE') var sign = optional(parse_sign) var digits = parse_digits() return _collect([e, sign, digits]) func parse_fractional() -> Result: var point = self.char('.') var digits = parse_digits() var exp = optional(parse_exponent) return _collect([point, digits, exp]) func parse_float() -> Result: var integer = parse_integer() var fractional = optional(parse_fractional) return _collect([integer, fractional]) func parse_string() -> Result: var quote = char.bind('"') var slash = self.char.bind('\\') var unescaped_quote = all_of.bind([negate.bind(slash), quote]) var open = skip(quote) var str_value = until(unescaped_quote).map(_join) return _collect([open, str_value]) class SeqAccess extends Serde.SeqAccess: var de: Json.Deserializer var first: bool = true var parser: Parser: get: return de._parser func _init(de: Json.Deserializer) -> void: self.de = de func next_element() -> Result: parser.skip_ws() if parser.char(']').is_ok(): return Result.ok(Option.Unit) if not first and parser.char(',').is_err(): return Result.err(Error.new('expected comma')) first = false parser.skip_ws() return de.deserialize_any(Serde.GenericVisitor.new()).map(Option.some) class MapAccess extends Serde.MapAccess: var de: Json.Deserializer var first: bool = true var iter: PeekableIter: get: return de._iter var parser: Parser: get: return de._parser func _init(de: Json.Deserializer) -> void: self.de = de func next_key() -> Result: parser.skip_ws() if iter.peek().filter(Parser.eq.bind('}')).is_some(): return Result.ok(Option.Unit) if not first: var comma = parser.char(',') if comma.is_err(): return comma first = false parser.skip_ws() var key = de.deserialize_any(Serde.GenericVisitor.new()).map(Option.some) return key func next_value() -> Result: parser.skip_ws() var colon = parser.char(':') if colon.is_err(): return colon parser.skip_ws() return de.deserialize_any(Serde.GenericVisitor.new()).map(Option.some) class Deserializer extends Serde.Deserializer: var _input: String var _iter: PeekableIter var _parser: Parser func _init(value: String) -> void: _input = value _iter = ListIterator.new(_input, RangeIterator.new(0, len(_input))).into_peekable() _parser = Parser.new(self) static func from_string(value: String) -> Json.Deserializer: return Json.Deserializer.new(value) func deserialize_any(visitor: Visitor): var next = _iter.peek() if next.is_none(): return Result.err(Error.new("eof")) match next.unwrap(): 'n': return deserialize_nil(visitor) 't', 'f': return deserialize_bool(visitor) '"': return deserialize_string(visitor) '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return deserialize_float(visitor) '[': return deserialize_seq(visitor) '{': return deserialize_dict(visitor) var x: return Result.err(Error.new('unexpected character "%s" at position %s' % [x, 0])) func deserialize_nil(visitor: Visitor): _parser.skip_ws() match _parser.str('null'): var x when x.is_ok(): return Result.ok(visitor.visit_nil()) var x: return x func deserialize_bool(visitor: Visitor): _parser.skip_ws() return _parser.any_of([_parser.str.bind('true'), _parser.str.bind('false')]).map(visitor.visit_bool) func deserialize_int(visitor: Visitor): _parser.skip_ws() return _parser.parse_integer().chain(Convert.FromString.to_int).map(visitor.visit_int) func deserialize_float(visitor: Visitor): _parser.skip_ws() return _parser.parse_float().chain(Convert.FromString.to_float).map(visitor.visit_float) func deserialize_string(visitor: Visitor): _parser.skip_ws() return _parser.parse_string().map(visitor.visit_string) func _deserialize_complex(open: Callable, close: Callable, on_success: Callable): _parser.skip_ws() var open_result = open.call() if open_result.is_err(): return open_result var value = on_success.call() var close_result = close.call() if close_result.is_err(): return close_result return Result.ok(value) func deserialize_seq(visitor: Visitor): var open = _parser.char.bind('[') var close = _parser.char.bind(']') var visit = func() -> Variant: return visitor.visit_seq(Json.SeqAccess.new(self)) return _deserialize_complex(open, close, visit) func deserialize_dict(visitor: Visitor): var open = _parser.char.bind('{') var close = _parser.char.bind('}') var visit = func() -> Variant: return visitor.visit_dict(Json.MapAccess.new(self)) return _deserialize_complex(open, close, visit) func deserialize_object(_name: StringName, _fields: Array[StringName], visitor: Visitor): return deserialize_dict(visitor)