Skip to content

Commit 6763ada

Browse files
committed
Merge branch 'premek-main'
2 parents 3cb9480 + 31fff38 commit 6763ada

10 files changed

Lines changed: 145 additions & 104 deletions

File tree

gleam.toml

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,22 @@ version = "1.2.1"
77
description = "gleam codegen for serialization and deserialization"
88
licences = ["MIT"]
99
repository = { type = "github", user = "cdaringe", repo = "gserde" }
10-
internal_modules = [
11-
"internal",
12-
"internal/*",
13-
]
10+
internal_modules = ["internal", "internal/*"]
1411
# links = [{ title = "Website", href = "https://gleam.run" }]
1512
#
1613
# For a full reference of all the available options, you can have a look at
1714
# https://gleam.run/writing-gleam/gleam-toml/.
1815

1916
[dependencies]
2017
gleam_stdlib = "~> 0.34 or ~> 1.0"
21-
glance = "~> 0.8"
22-
simplifile = "~> 1.2"
23-
fswalk = "~> 2.0"
18+
glance = ">= 6.0.0"
19+
simplifile = ">= 2.3.1 and < 3.0.0"
20+
fswalk = ">= 3.1.0 and < 4.0.0"
2421
shellout = "~> 1.5"
25-
dot_env = "~> 0.2"
22+
dot_env = ">= 1.2.0 and < 2.0.0"
2623
justin = "~> 1.0"
24+
gleam_yielder = ">= 1.1.0 and < 2.0.0"
25+
gleam_json = ">= 3.1.0 and < 4.0.0"
2726

2827
[dev-dependencies]
2928
gleeunit = "~> 1.0"
30-
gleam_json = ">= 0.0.0 and < 2.0.0"
31-

manifest.toml

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,30 @@
22
# You typically do not need to edit this file
33

44
packages = [
5-
{ name = "dot_env", version = "0.2.4", build_tools = ["gleam"], requirements = ["gleam_stdlib", "simplifile"], otp_app = "dot_env", source = "hex", outer_checksum = "FFAC6F89A2BB6896A10128E5850496C372821BFDB807C837A1404BEBDD1AB2B9" },
6-
{ name = "fswalk", version = "2.0.2", build_tools = ["gleam"], requirements = ["simplifile", "dot_env", "gleam_community_path", "gleam_stdlib"], otp_app = "fswalk", source = "hex", outer_checksum = "5D8E9C34C4C1BF3E65A79A292FE98B4AD35E525D18BB068518359687FA7BD1EB" },
7-
{ name = "glance", version = "0.8.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "ACF09457E8B564AD7A0D823DAFDD326F58263C01ACB0D432A9BEFDEDD1DA8E73" },
5+
{ name = "dot_env", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "simplifile"], otp_app = "dot_env", source = "hex", outer_checksum = "F2B4815F1B5AF8F20A6EADBB393E715C4C35203EBD5BE8200F766EA83A0B18DE" },
6+
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
7+
{ name = "fswalk", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_community_path", "gleam_stdlib", "gleam_yielder", "simplifile"], otp_app = "fswalk", source = "hex", outer_checksum = "579530173EE64EDDF53CE02D21171E4CC0CB4F1D34DAA829D32B6009CD8E6FD5" },
8+
{ name = "glance", version = "6.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "49E0ED4793BB3F56C3E5ED00528D70CAE21D263F70A735604124B95C5F62E2DB" },
89
{ name = "gleam_community_path", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_path", source = "hex", outer_checksum = "916C2829E2ED81036BBA180CFD5E8633D05E25C304FDF6E3BC8A048459B89725" },
9-
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
10-
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
11-
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
12-
{ name = "glexer", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE" },
10+
{ name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
11+
{ name = "gleam_stdlib", version = "0.67.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "6CE3E4189A8B8EC2F73AB61A2FBDE49F159D6C9C61C49E3B3082E439F260D3D0" },
12+
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
13+
{ name = "gleeunit", version = "1.9.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "DA9553CE58B67924B3C631F96FE3370C49EB6D6DC6B384EC4862CC4AAA718F3C" },
14+
{ name = "glexer", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "splitter"], otp_app = "glexer", source = "hex", outer_checksum = "40A1FB0919FA080AD6C5809B4C7DBA545841CAAC8168FACDFA0B0667C22475CC" },
1315
{ name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
14-
{ name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" },
15-
{ name = "simplifile", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "EB9AA8E65E5C1E3E0FDCFC81BC363FD433CB122D7D062750FFDF24DE4AC40116" },
16-
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
16+
{ name = "shellout", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "1BDC03438FEB97A6AF3E396F4ABEB32BECF20DF2452EC9A8C0ACEB7BDDF70B14" },
17+
{ name = "simplifile", version = "2.3.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "957E0E5B75927659F1D2A1B7B75D7B9BA96FAA8D0C53EA71C4AD9CD0C6B848F6" },
18+
{ name = "splitter", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "splitter", source = "hex", outer_checksum = "3DFD6B6C49E61EDAF6F7B27A42054A17CFF6CA2135FF553D0CB61C234D281DD0" },
1719
]
1820

1921
[requirements]
20-
dot_env = { version = "~> 0.2" }
21-
fswalk = { version = "~> 2.0" }
22-
glance = { version = "~> 0.8" }
23-
gleam_json = { version = ">= 0.0.0 and < 2.0.0" }
22+
dot_env = { version = ">= 1.2.0 and < 2.0.0" }
23+
fswalk = { version = ">= 3.1.0 and < 4.0.0" }
24+
glance = { version = ">= 6.0.0" }
25+
gleam_json = { version = ">= 3.1.0 and < 4.0.0" }
2426
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
27+
gleam_yielder = { version = ">= 1.1.0 and < 2.0.0" }
2528
gleeunit = { version = "~> 1.0" }
26-
justin = { version = "~> 1.0"}
29+
justin = { version = "~> 1.0" }
2730
shellout = { version = "~> 1.5" }
28-
simplifile = { version = "~> 1.2" }
31+
simplifile = { version = ">= 2.3.1 and < 3.0.0" }

src/ast.gleam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import gleam/list
33
import gleam/string
44
import request.{type Request}
55

6-
pub fn get_import_path_from_mod_name(module_str: String, req: Request) {
6+
pub fn get_import_path_from_mod_name(module_str: String, req: Request) -> String {
77
list.find_map(in: req.module.imports, with: fn(imp) {
88
let full_module_str = imp.definition.module
99
case

src/common.gleam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import justin
44
pub fn decoder_name_of_t(raw_name: String) -> String {
55
let snake_name = justin.snake_case(raw_name)
66
let name = case string.ends_with(snake_name, "_json") {
7-
True -> string.drop_right(snake_name, 5)
7+
True -> string.drop_end(snake_name, 5)
88
False -> raw_name
99
}
1010
"get_decoder_" <> name

src/gserde.gleam

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import dot_env/env
2-
import evil.{expect}
32
import fswalk
43
import glance
54
import gleam/bool
65
import gleam/io
76
import gleam/list
87
import gleam/result
98
import gleam/string
9+
import gleam/yielder
1010
import internal/deserializer
1111
import internal/serializer
1212
import request.{type Request, Request}
@@ -40,17 +40,20 @@ pub fn main() {
4040
}
4141
fswalk.builder()
4242
|> fswalk.with_path("src")
43-
|> fswalk.with_entry_filter(fn(it) {
44-
string.ends_with(it.filename, ".gleam") && fswalk.only_files(it)
45-
})
4643
|> fswalk.walk
47-
|> fswalk.map(fn(v) { expect(v, "failed to walk").filename })
48-
|> fswalk.each(fn(f) { process_single(f, is_debug) })
44+
|> yielder.map(fn(res) {
45+
let assert Ok(entry) = res as "failed to walk"
46+
entry
47+
})
48+
|> yielder.filter(fn(entry) {
49+
string.ends_with(entry.filename, ".gleam") && !entry.stat.is_directory
50+
})
51+
|> yielder.each(fn(entry) { process_single(entry.filename, is_debug) })
4952
}
5053

5154
pub fn process_single(src_filename: String, is_debug) {
5255
bool.guard(!is_debug, Nil, fn() {
53-
io.debug(#("Processing", src_filename))
56+
echo #("Processing", src_filename)
5457
Nil
5558
})
5659

@@ -66,7 +69,7 @@ pub fn process_single(src_filename: String, is_debug) {
6669
let assert Ok(parsed) =
6770
glance.module(code)
6871
|> result.map_error(fn(err) {
69-
io.debug(err)
72+
io.print_error(string.inspect(err))
7073
panic
7174
})
7275

@@ -94,7 +97,6 @@ pub fn process_single(src_filename: String, is_debug) {
9497
)
9598
})
9699
})
97-
98100
let filecontent =
99101
list.map(requests, gen)
100102
|> list.map(fn(it) { it.1 })
@@ -106,8 +108,9 @@ pub fn process_single(src_filename: String, is_debug) {
106108
simplifile.write(
107109
to: dest_filename,
108110
contents: [
111+
"// This file was generated using gserde",
109112
"import gleam/json",
110-
"import gleam/dynamic",
113+
"import gleam/dynamic/decode",
111114
"import " <> src_module_name,
112115
filecontent,
113116
]

src/internal/codegen/modules.gleam

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,26 @@ pub fn empty() -> Mod {
1818
}
1919

2020
pub fn add_functions(mod: Mod, functions: List(GleamStatement)) -> Mod {
21-
Mod(..mod, functions: list.concat([mod.functions, functions]))
21+
Mod(..mod, functions: list.flatten([mod.functions, functions]))
2222
}
2323

2424
pub fn add_imports(mod: Mod, imports: List(String)) -> Mod {
25-
Mod(..mod, imports: list.concat([mod.imports, imports]))
25+
Mod(..mod, imports: list.flatten([mod.imports, imports]))
2626
}
2727

2828
pub fn merge(m1: Mod, m2: Mod) {
2929
Mod(
3030
name: m1.name,
31-
functions: list.concat([m1.functions, m2.functions]),
32-
types: list.concat([m1.types, m2.types]),
33-
imports: list.concat([m1.imports, m2.imports])
31+
functions: list.flatten([m1.functions, m2.functions]),
32+
types: list.flatten([m1.types, m2.types]),
33+
imports: list.flatten([m1.imports, m2.imports])
3434
|> set.from_list
3535
|> set.to_list,
3636
)
3737
}
3838

3939
pub fn to_string(m: Mod) {
40-
list.concat([
40+
list.flatten([
4141
list.map(m.imports, fn(i) { "import " <> i }),
4242
list.map(m.types, t.generate_type_def),
4343
list.map(m.functions, gens.generate),

src/internal/codegen/statements.gleam

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub type GleamStatement {
1313
TupleVal(items: List(GleamStatement))
1414
VariantVal(name: String, fields: List(GleamStatement))
1515
VarPrimitive(name: String)
16+
Block(items: List(GleamStatement))
1617
Comparison(GleamStatement, ComparisonOperator, GleamStatement)
1718
CaseStatement(guards: List(GleamStatement), clauses: List(Clause))
1819
Function(
@@ -29,6 +30,8 @@ pub type GleamStatement {
2930

3031
Multiply(terms: List(GleamStatement))
3132

33+
UseExpr(name: String, statement: GleamStatement)
34+
3235
Direct(string: String)
3336
}
3437

@@ -208,6 +211,12 @@ pub fn generate(stmt: GleamStatement) -> String {
208211
|> map(generate)
209212
|> join(", ")
210213
<> ")"
214+
Block(statements) ->
215+
"{\n"
216+
<> statements
217+
|> map(generate)
218+
|> join("\n")
219+
<> "}"
211220
VarPrimitive(name) -> name
212221
Comparison(stmt1, op, stmt2) ->
213222
generate(stmt1)
@@ -273,6 +282,7 @@ pub fn generate(stmt: GleamStatement) -> String {
273282
|> map(generate)
274283
|> join(" * ")
275284

285+
UseExpr(name, stmt) -> "use " <> name <> " <- " <> generate(stmt)
276286
Direct(string) -> string
277287
}
278288
}

src/internal/deserializer.gleam

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import common.{decoder_name_of_t}
2-
import evil.{expect}
32
import glance
43
import gleam/int
5-
import gleam/io
64
import gleam/list
75
import gleam/option
86
import gleam/string
@@ -15,22 +13,22 @@ fn quote(str) {
1513
"\"" <> str <> "\""
1614
}
1715

18-
fn gen_decoder(typ, req: Request) {
16+
fn gen_decoder(typ) {
1917
case typ {
20-
glance.NamedType(name, module_name, parameters) -> {
18+
glance.NamedType(_location, name, module, parameters) -> {
2119
case name {
2220
"List" -> {
23-
let assert Ok(t0) = list.at(parameters, 0)
24-
gens.call("dynamic.list", [gen_decoder(t0, req)])
21+
let assert Ok(t0) = list.first(parameters)
22+
gens.call("decode.list", [gen_decoder(t0)])
2523
}
2624
"Option" -> {
27-
let assert Ok(t0) = list.at(parameters, 0)
28-
gens.call("dynamic.optional", [gen_decoder(t0, req)])
25+
let assert Ok(t0) = list.first(parameters)
26+
gens.call("decode.optional", [gen_decoder(t0)])
2927
}
3028
_ -> {
31-
case module_name {
29+
case module {
3230
option.None -> {
33-
gens.VarPrimitive("dynamic." <> string.lowercase(name))
31+
gens.VarPrimitive("decode." <> string.lowercase(name))
3432
}
3533
option.Some(module_str) -> {
3634
gens.VarPrimitive(
@@ -41,19 +39,33 @@ fn gen_decoder(typ, req: Request) {
4139
}
4240
}
4341
}
44-
glance.TupleType(parts) -> {
45-
let m_tuple =
46-
list.length(of: parts)
47-
|> int.to_string
48-
gens.call(
49-
"dynamic.tuple" <> string.lowercase(m_tuple),
50-
parts
51-
|> list.map(fn(part) { gen_decoder(part, req) }),
42+
glance.TupleType(_location, elements) -> {
43+
gens.Block(
44+
list.flatten([
45+
elements
46+
|> list.index_map(fn(element, i) {
47+
gens.UseExpr(
48+
"el" <> int.to_string(i),
49+
gens.call("decode.field", [gens.IntVal(i), gen_decoder(element)]),
50+
)
51+
}),
52+
53+
[
54+
gens.call("decode.success", [
55+
gens.TupleVal(
56+
elements
57+
|> list.index_map(fn(_element, i) {
58+
gens.VarPrimitive("el" <> int.to_string(i))
59+
}),
60+
),
61+
]),
62+
],
63+
]),
5264
)
5365
}
5466
x -> {
55-
io.debug(#("warning: unsupported decoding", x))
56-
gens.VarPrimitive("dynamic.toodoo")
67+
echo #("warning: unsupported decoding", x)
68+
gens.Direct("todo")
5769
}
5870
}
5971
}
@@ -65,33 +77,51 @@ fn gen_root_decoder(req) {
6577
variant: variant,
6678
..,
6779
) = req
68-
let n_str =
69-
list.length(of: variant.fields)
70-
|> int.to_string
7180

7281
let decoder_fn_name = decoder_name_of_t(type_name)
7382

7483
[
75-
gens.Function(decoder_fn_name, [], [
76-
gens.call("dynamic.decode" <> n_str, [
77-
gens.VarPrimitive(basename(src_module_name) <> "." <> variant.name),
78-
..list.map(req.variant.fields, fn(field) {
79-
gens.call("dynamic.field", [
80-
gens.VarPrimitive(
81-
option.to_result(field.label, Nil)
82-
|> expect("@todo/panic variants must be labeled")
83-
|> quote,
84+
gens.Function(
85+
decoder_fn_name,
86+
[],
87+
list.flatten([
88+
list.map(req.variant.fields, fn(field) {
89+
case field {
90+
glance.LabelledVariantField(_, label) -> {
91+
gens.UseExpr(
92+
label,
93+
gens.call("decode.field", [
94+
gens.VarPrimitive(quote(label)),
95+
gen_decoder(field.item),
96+
]),
97+
)
98+
}
99+
glance.UnlabelledVariantField(_) ->
100+
panic as "variants must be labelled"
101+
}
102+
}),
103+
[
104+
gens.call("decode.success", [
105+
gens.call(
106+
basename(src_module_name) <> "." <> variant.name,
107+
list.map(req.variant.fields, fn(field) {
108+
case field {
109+
glance.LabelledVariantField(_, label) ->
110+
gens.VarPrimitive(label)
111+
glance.UnlabelledVariantField(_) ->
112+
panic as "variants must be labelled"
113+
}
114+
}),
84115
),
85-
gen_decoder(field.item, req),
86-
])
87-
})
116+
]),
117+
],
88118
]),
89-
]),
119+
),
90120
gens.Function(
91121
"from_string",
92122
[gens.arg_typed("json_str", t.AnonymousType("String"))],
93123
[
94-
gens.call("json.decode", [
124+
gens.call("json.parse", [
95125
gens.VarPrimitive("json_str"),
96126
gens.call(decoder_fn_name, []),
97127
]),

0 commit comments

Comments
 (0)