wryun / es-shell

es: a shell with higher-order functions
http://wryun.github.io/es-shell/
Other
313 stars 26 forks source link

parsing invalid primitive produces erratic behaviour #5

Closed wryun closed 1 month ago

wryun commented 12 years ago

Reproduce: $&. (include the full-stop)

Either es works, quits, or produces the message: es panic: eval: bad closure node kind 3

jpco commented 8 months ago

Ahh, I finally got a repro of this. $&. doesn't work for me but $&foo. (or any other word besides foo) does. I've been assuming that something like echo $&. would also fail and I was wrong about that, since this is an evaluation error, rather than a (simple) parse error.

The panic happens in eval() because $&foo. gets parsed as $&foo^. (in lisptrees terms, (concat (prim foo) (word "."))). eval() doesn't expect a tree of nConcat (I believe the expectation is that those should have been glommed away already). Interestingly, if you do something like $&foo^bar, something actually reasonable happens (that is, it complains about unknown primitive: foobar).

Aha, it looks like the difference comes from getclosure() as called in eval.c:427. At this point, the shell tries to parse a string term of the form $&foo. or $&foobar. The latter just gets parsed as a regular primitive called foobar. The former, thanks to the magic of free carets, gets parsed as a concatenation of $&foo and .. (You also get this bug with $&foo! or $&foo/).

The best fix I can think of at the moment is to add a case nConcat to the switch at line 379 where we assert that the car of the nConcat is an nPrim and then throw an error that what we have is isn't actually valid primitive. I don't feel satisfied about this fix -- it has the vibe of a band-aid "solution" -- but I get quickly dizzy in the glom/eval/walk call stack, so I can't come up with any other behaviors that trigger this. It might just be a symptom of primitives being all three of 1. a word that's fussy to parse, 2. free-caret-able, and 3. evaluated in eval() rather than walk().

jpco commented 8 months ago

I also don't totally understand why this might be flaky (the crashing case crashes 100% of the time for me). Perhaps the command isn't always parsed in the same way? My repro gloms the nConcat tree to a list containing "$&foo." back to an nConcat tree, which is kind of weird and circuitous -- maybe that isn't always how that flow happens.

(Maybe that's the bug in itself? Maybe (concat (prim foo) (word ".")) shouldn't get glommed into a string term "$&foo." at all?)

jpco commented 1 month ago

I checked out the Aug. 21, 2012 version of es and found the same behavior as I've already observed here -- no problem with $&., and failures 100% of the time with $&a.. I was looking to see if there were two separate bugs, but I guess not. Chalk it up to differences in surrounding OS or something :shrug:

I don't love the fix I've prepared because I keep wanting to find a solution that feels more "fundamental", but I honestly can't come up with anything.