///|
let json_methods : Map[String, RuntimeFunction] = {
  "stringify": json_stringify_fn,
  "array": json_array_fn,
  "boolean": json_boolean_fn,
  "null": json_null_fn,
  "number": json_number_fn,
  "object": json_object_fn,
  "string": json_string_fn,
}

///|
let json_stringify_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Json(value), .. }] => String(value.stringify())
    _ => Unit
  }
}

///|
let json_array_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Array(value), .. }] =>
      Json(Json::array(value.map(i => if i is Json(i) { i } else { panic() })))
    _ => Unit
  }
}

///|
let json_boolean_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Bool(value), .. }] => Json(Json::boolean(value))
    _ => Unit
  }
}

///|
let json_null_fn : RuntimeFunction = _ctx => Json(Json::null())

///|
let json_number_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Double(value), .. }] => Json(Json::number(value))
    _ => Unit
  }
}

///|
let json_object_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: Map(value), .. }] =>
      Json(
        Json::object(
          value
          .to_array()
          .map(i => {
            if i is (String(key), Json(json)) {
              (key, json)
            } else {
              panic()
            }
          })
          |> Map::from_array,
        ),
      )
    _ => Unit
  }
}

///|
let json_string_fn : RuntimeFunction = ctx => {
  match ctx.args {
    [{ val: String(value), .. }] => Json(Json::string(value))
    _ => Unit
  }
}