Current section

Files

Jump to
gserde src internal deserializer.gleam
Raw

src/internal/deserializer.gleam

import common.{decoder_name_of_t}
import glance
import gleam/int
import gleam/io
import gleam/list
import gleam/option
import gleam/string
import internal/codegen/statements as gens
import internal/codegen/types as t
import internal/path.{basename}
import request.{type Request, Request}
fn quote(str) {
"\"" <> str <> "\""
}
fn gen_decoder(typ) {
case typ {
glance.NamedType(_location, name, module, parameters) -> {
case name {
"List" -> {
let assert Ok(t0) = list.first(parameters)
gens.call("decode.list", [gen_decoder(t0)])
}
"Option" -> {
let assert Ok(t0) = list.first(parameters)
gens.call("decode.optional", [gen_decoder(t0)])
}
_ -> {
case module {
option.None -> {
gens.VarPrimitive("decode." <> string.lowercase(name))
}
option.Some(module_str) -> {
gens.VarPrimitive(
module_str <> "_json." <> decoder_name_of_t(name) <> "()",
)
}
}
}
}
}
glance.TupleType(_location, elements) -> {
gens.Block(
list.flatten([
elements
|> list.index_map(fn(element, i) {
gens.UseExpr(
"el" <> int.to_string(i),
gens.call("decode.field", [gens.IntVal(i), gen_decoder(element)]),
)
}),
[
gens.call("decode.success", [
gens.TupleVal(
elements
|> list.index_map(fn(_element, i) {
gens.VarPrimitive("el" <> int.to_string(i))
}),
),
]),
],
]),
)
}
x -> {
io.println_error(string.inspect(#("warning: unsupported decoding", x)))
gens.Direct("todo")
}
}
}
fn gen_root_decoder(req) {
let Request(
src_module_name: src_module_name,
type_name: type_name,
variant: variant,
..,
) = req
let decoder_fn_name = decoder_name_of_t(type_name)
[
gens.Function(
decoder_fn_name,
[],
list.flatten([
list.map(req.variant.fields, fn(field) {
case field {
glance.LabelledVariantField(_, label) -> {
gens.UseExpr(
label,
gens.call("decode.field", [
gens.VarPrimitive(quote(label)),
gen_decoder(field.item),
]),
)
}
glance.UnlabelledVariantField(_) ->
panic as "variants must be labelled"
}
}),
[
gens.call("decode.success", [
gens.call(
basename(src_module_name) <> "." <> variant.name,
list.map(req.variant.fields, fn(field) {
case field {
glance.LabelledVariantField(_, label) ->
gens.VarPrimitive(label)
glance.UnlabelledVariantField(_) ->
panic as "variants must be labelled"
}
}),
),
]),
],
]),
),
gens.Function(
"from_string",
[gens.arg_typed("json_str", t.AnonymousType("String"))],
[
gens.call("json.parse", [
gens.VarPrimitive("json_str"),
gens.call(decoder_fn_name, []),
]),
],
),
]
}
pub fn to(req: Request) {
gen_root_decoder(req)
|> list.map(gens.generate)
|> string.join(with: "\n")
}