Skip to content

Commit

Permalink
feat: support prepending to lists
Browse files Browse the repository at this point in the history
  • Loading branch information
BrewingWeasel committed Nov 16, 2024
1 parent fb0b51c commit efb0a8e
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- added support for prepending to lists [x, ..xs]

## v0.2.1 - 2024-11-13

- added support for or (|) in case expressions
Expand Down
52 changes: 43 additions & 9 deletions src/gleamgen/expression.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ type InternalExpression(type_) {
StrLiteral(String)
BoolLiteral(Bool)
NilLiteral
ListLiteral(List(Expression(types.Unchecked)))
ListLiteral(
prepending: List(Expression(types.Unchecked)),
initial: Option(Expression(types.Unchecked)),
)
TupleLiteral(List(Expression(types.Unchecked)))
Ident(String)
Todo(Option(String))
Expand Down Expand Up @@ -59,7 +62,7 @@ pub fn nil() -> Expression(Nil) {

pub fn list(value: List(Expression(t))) -> Expression(List(t)) {
Expression(
ListLiteral(value |> list.map(to_unchecked)),
ListLiteral(value |> list.map(to_unchecked), None),
value
|> list.first()
|> result.map(type_)
Expand All @@ -68,6 +71,23 @@ pub fn list(value: List(Expression(t))) -> Expression(List(t)) {
)
}

pub fn list_prepend(
prepending: List(Expression(t)),
original: Expression(List(t)),
) -> Expression(List(t)) {
Expression(
ListLiteral(
prepending: prepending |> list.map(to_unchecked),
initial: Some(original |> to_unchecked()),
),
prepending
|> list.first()
|> result.map(type_)
|> result.lazy_unwrap(fn() { types.unchecked() })
|> types.list(),
)
}

pub fn tuple1(arg1: Expression(a)) -> Expression(#(a)) {
Expression(TupleLiteral([arg1 |> to_unchecked()]), types.tuple1(type_(arg1)))
}
Expand Down Expand Up @@ -641,7 +661,8 @@ pub fn render(
BoolLiteral(True) -> doc.from_string("True")
BoolLiteral(False) -> doc.from_string("False")
NilLiteral -> doc.from_string("Nil")
ListLiteral(values) -> render_list(values, context)
ListLiteral(values, initial_list) ->
render_list(values, initial_list, context)
TupleLiteral(values) -> render_tuple(values, context)
Ident(value) -> doc.from_string(value)
Todo(as_string) -> render_panicking_expression("todo", as_string)
Expand Down Expand Up @@ -722,19 +743,32 @@ fn render_tuple(values, context) {
|> doc.prepend(doc.from_string("#"))
}

fn render_list(values, context) {
fn render_list(values, initial_list, context) {
let comma = doc.concat([doc.from_string(","), doc.space])
let trailing_comma = doc.break("", ",")

let open_paren = doc.concat([doc.from_string("["), doc.soft_break])
let close_paren = doc.concat([trailing_comma, doc.from_string("]")])
let #(ending, trailing_comma) = case initial_list {
Some(initial) -> #(
doc.concat([
doc.from_string(","),
doc.space,
doc.from_string(".."),
render(initial, context).doc,
]),
doc.soft_break,
)
None -> #(doc.empty, doc.break("", ","))
}

let open_bracket = doc.concat([doc.from_string("["), doc.soft_break])
let close_bracket = doc.concat([trailing_comma, doc.from_string("]")])

values
|> list.map(fn(x) { render(x, context).doc })
|> doc.join(with: comma)
|> doc.prepend(open_paren)
|> doc.prepend(open_bracket)
|> doc.append(ending)
|> doc.nest(2)
|> doc.append(close_paren)
|> doc.append(close_bracket)
|> doc.group
}

Expand Down
68 changes: 68 additions & 0 deletions test/gleamgen_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,74 @@ pub fn simple_tuple_test() {
|> should.equal("#(3, \"hello\", True)")
}

pub fn simple_list_test() {
expression.list([expression.string("hello"), expression.string("hi")])
|> expression.render(render.default_context())
|> render.to_string()
|> should.equal("[\"hello\", \"hi\"]")
}

pub fn simple_list_prepending_test() {
expression.list_prepend(
[expression.string("hello"), expression.string("hi")],
expression.list([expression.string("yo")]),
)
|> expression.render(render.default_context())
|> render.to_string()
|> should.equal("[\"hello\", \"hi\", ..[\"yo\"]]")
}

pub fn multiline_list_prepending_test() {
expression.list_prepend(
[
expression.string("hello but much, much, much, much longer so it breaks"),
expression.string("hello but much, much, much, much longer so it breaks"),
],
expression.list([expression.string("yo")]),
)
|> expression.render(render.default_context())
|> render.to_string()
|> should.equal(
"[
\"hello but much, much, much, much longer so it breaks\",
\"hello but much, much, much, much longer so it breaks\",
..[\"yo\"]
]",
)
}

pub fn long_list_test() {
expression.list([
expression.list([
expression.string("hello"),
expression.string("hello"),
expression.string("hello"),
expression.string("hello"),
expression.string("hello but much, much, much, much longer so it breaks"),
]),
expression.list([
expression.string("hi"),
expression.string("hi"),
expression.string("hi"),
expression.string("hi"),
]),
])
|> expression.render(render.default_context())
|> render.to_string()
|> should.equal(
"[
[
\"hello\",
\"hello\",
\"hello\",
\"hello\",
\"hello but much, much, much, much longer so it breaks\",
],
[\"hi\", \"hi\", \"hi\", \"hi\"],
]",
)
}

pub fn long_tuple_test() {
expression.tuple9(
expression.int(3),
Expand Down

0 comments on commit efb0a8e

Please sign in to comment.