Open lucaswerkmeister opened 4 years ago
If this was only about Z56/negate, then I could probably make the parser recognize the function call in the implementation relatively easily. It doesn’t make very much sense to call an eneyj function with zero arguments, so if the parser doesn’t see any ZabcKi or Ki arguments, it can probably just guess that any other ZxyzKi key in the JSON (other than basic keys like Z1Ki or Z7Ki) is actually an argument. That works for the Z56/negate implementation, where all the other keys are indeed arguments (Z31K1...Z31K3); but that won’t be enough to support this strange “call different functions with different arguments” case, hence the question whether that needs to be supported at all.
No, I think you're asking the right question. To the best of my memory, this is not an intentional pattern. I have somewhere in my Todo list "go and clean up the if functions", because ... there was a bit of experimenting with different implementations of the if function. In short, no, this is just a mistake. A validator should have caught that.
Thanks for reporting! I'll keep this open until it is fixed.
Alright, thanks! Then I’ll just make the GraalEneyj parser look a bit harder for arguments for now :)
GraalEneyj is getting closer to calling the native Z56/negate function, but the issue I’m encountering now is a little odd. The native (non-code) implementation of Z56/negate looks like this:
That is, call Z104/if_boolean with the first argument as the condition, Z55/false as the consequent, and Z54/true as the alternative.
negate(x) => x ? false : true
. The function being called, Z104/if_booolean, is a Z9/reference to the Z31/if function.I assume that in eneyj, this is done more or less by placing Z31K1...Z31K3 in some kind of “stack” of contexts, and when Z31 is ultimately called, it “walks” up this stack until it finds its arguments (Z31K1...Z31K3). (At some point in between, alpha conversion happens, see also #3.) But in GraalEneyj, function calls are (currently) parsed rather differently: we recognize a Z7/function_call at parse time, collect the function being called (Z7K1/function) and all of its arguments (either K1...Kn, or, if the Z7K1/function is a reference Zabc, ZabcK1...ZabcKn), and then have a purely positional function call with n argument nodes in the AST. This means that the above Z56/negate implementation can’t be parsed: since the parser doesn’t know the relationship between Z104/if_boolean and Z31/if, it has no idea that Z31K1...Z31K3 are argument to the function calls and not just arbitrary JSON keys, and Z104 / Z31 will ultimately be called with no arguments.
I’m sure it’s possible to make GraalEneyj support this pattern, and it can probably be made efficient, too, if you know a bit more about Truffle than I do at the moment (mumble mumble frame slots mumble mumble). My question is basically, do I need to support this, or can I avoid it 😆
One curious consequence of the eneyj behavior is that a function can call another function with different arguments (probably even with a different number of arguments), depending on that function’s identity. Consider the following anonymous function:
This function receives one argument, and calls it as a function. If that function is Z36/value, it will be called with Z28/project_name; if it’s Z56/negate, it will see Z54/true as the single argument; otherwise, it will see no arguments and the result will be a lambda (the unapplied function, but having lost its identity).
Observe (the three inputs differ only at the very end):
Is this a feature? Is this something we actually want?