Skip to content

Commit

Permalink
Support fn_capture as lambda.
Browse files Browse the repository at this point in the history
I think it's safe to make it always a lambda.

Python expressions never cross line boundaries, including in Lambdas.

In general, this means that not all gleam expressions can map to python
expressions (consider case->match, where match is a statement in python,
not an expression). But I *think* it means that any expression that can
map to a python expression can be wrapped in a lambda like this.

The parens make it so the expression is self-contained and you can call
it.
  • Loading branch information
dusty-phillips committed Aug 21, 2024
1 parent b71aac1 commit c5c602d
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 28 deletions.
12 changes: 12 additions & 0 deletions src/generator.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ fn generate_expression(expression: python.Expression) {
))
|> string_builder.append(")")

python.Lambda(arguments, body) -> {
string_builder.from_string("(lambda ")
|> string_builder.append_builder(generator_helpers.generate_plural(
arguments,
generate_expression,
", ",
))
|> string_builder.append(": ")
|> string_builder.append_builder(generate_expression(body))
|> string_builder.append(")")
}

python.Call(function, arguments) ->
string_builder.new()
|> string_builder.append_builder(generate_expression(function))
Expand Down
1 change: 1 addition & 0 deletions src/python.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub type Expression {
Not(Expression)
Panic(Expression)
Todo(Expression)
Lambda(args: List(Expression), body: Expression)
List(elements: List(Expression))
ListWithRest(elements: List(Expression), rest: Expression)
TupleIndex(tuple: Expression, index: Int)
Expand Down
45 changes: 18 additions & 27 deletions src/transformer.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,21 @@ fn transform_expression(expression: glance.Expression) -> python.Expression {
)
}

glance.FnCapture(label, function, arguments_before, arguments_after) -> {
let argument_expressions =
list.concat([
arguments_before,
[glance.Field(label, glance.Variable("fn_capture"))],
arguments_after,
])
|> list.map(transform_call_argument)

python.Lambda(
[python.Variable("fn_capture")],
python.Call(transform_expression(function), argument_expressions),
)
}

glance.Tuple(expressions) ->
expressions
|> list.map(transform_expression)
Expand All @@ -134,35 +149,12 @@ fn transform_expression(expression: glance.Expression) -> python.Expression {
glance.FieldAccess(container: expression, label:) ->
python.FieldAccess(transform_expression(expression), label)

glance.BinaryOperator(glance.Pipe, left, glance.Variable(function)) -> {
// simple pipe left |> foo
python.Call(python.Variable(function), [
glance.BinaryOperator(glance.Pipe, left, right) -> {
python.Call(transform_expression(right), [
python.UnlabelledField(transform_expression(left)),
])
}

glance.BinaryOperator(
glance.Pipe,
left,
glance.FnCapture(
label,
glance.Variable(function),
arguments_before,
arguments_after,
),
) -> {
let argument_expressions =
list.concat([
arguments_before,
[glance.Field(label, left)],
arguments_after,
])
|> list.map(transform_call_argument)
python.Call(python.Variable(function), argument_expressions)
}
glance.BinaryOperator(glance.Pipe, _, right) -> {
panic as "I don't know how to handle this structure of pipe"
}
glance.BinaryOperator(name, left, right) ->
transform_binop(name, left, right)

Expand All @@ -187,8 +179,7 @@ fn transform_expression(expression: glance.Expression) -> python.Expression {
glance.BitString(_) as expr
| glance.Block(_) as expr
| glance.Case(_, _) as expr
| glance.Fn(_, _, _) as expr
| glance.FnCapture(_, _, _, _) as expr -> {
| glance.Fn(_, _, _) as expr -> {
pprint.debug(expr)
todo as "Several expressions are not implemented yet"
}
Expand Down
18 changes: 17 additions & 1 deletion test/expression_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ pub fn capture_pipe_test() {
"from gleam_builtins import *
def main():
return println(\"a\", \"foo\", \"b\")",
return (lambda fn_capture: println(\"a\", fn_capture, \"b\"))(\"foo\")",
)
}

Expand Down Expand Up @@ -539,6 +539,22 @@ def main():
)
}

pub fn fn_capture_test() {
"fn main() {
let x = foo(\"a\", _, \"b\")
x(\"c\")
}"
|> macabre.compile
|> should.be_ok
|> should.equal(
"from gleam_builtins import *
def main():
x = (lambda fn_capture: foo(\"a\", fn_capture, \"b\"))
return x(\"c\")",
)
}

pub fn record_update_test() {
"pub type Foo {
Bar(a: Int, b: String)
Expand Down

0 comments on commit c5c602d

Please sign in to comment.