Skip to content

es should only print %closures that it can parse #229

@jpco

Description

@jpco

There is a mismatch in how es parses %closures and how it prints them.

%closures are parsed exactly the same way as let, local, and for statements: they are special kinds of command, which are only parsed specially when placed in head position.

However, %closures are printed like special thunks or lambdas, where they are treated as specific kinds of words.

This mismatch produces the following unhappiness:

; let (a = b) th = {~ $a b}
; let (a = c) echo if $th {echo $a}
if %closure(a=b){~ $a b} %closure(a=c){echo $a}
; if %closure(a=b){~ $a b} %closure(a=c){echo $a}
%closure:1: syntax error

I think this is wrong; in principle, es shouldn't print commands in a way that it can't parse them back in. So I think there are two possible ways to fix this:

  1. Parse %closure as a word so that es understands it anywhere in a command
  2. Format %closure in a way that works as a command

Initially I assumed option 1 was the only real fix, since (as in the above example) it's very possible to have a single command with multiple incompatible closures over different terms. However, in theory you can do option 2, if you wrap things in enough thunks, such that the above problematic command becomes

if {%closure(a=b){~ $a b}} {%closure(a=c){echo $a}}

We could then make this read even nicer in my opinion if we got rid of the %closure syntax completely and just used let:

if {let(a=b){~ $a b}} {let(a=c){echo $a}}

Of course, this would be a backwards-incompatible change, as we'd be removing a previously valid syntax from the shell.

The first option would also be slightly backwards-incompatible. Since we'd be changing %closure() from a command construct to a word construct, commands like %closure(a=b)echo $a would parse differently than they do now.

I've hacked up both of these options. The first option seems to work fine, even with a pretty quick-and-dirty implementation, though I do think it's a little bit ugly; a similarly quick hack of the second option seems to cause mysterious segfaults, due potentially to subtleties with %closure that I don't understand.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions