Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better function call syntax for Pancake #994

Merged
merged 27 commits into from
May 18, 2024
Merged

Conversation

IlmariReissumies
Copy link
Member

This commit revamps the function call syntax of Pancake to make it more intuitive. Previously two kinds of function calls were accepted as declarations:

fun f() {
  var x = 5;
  g(); // tail call
  x = g(); // assigning call (formerly and confusingly known as "returning call")
  return 0
}

This syntax is confusing --- the tail call will immediately return from f() , causing the second call to g() to be never evaluated, contrary to programmer intuition.

In the new style, we allow (and distinguish for purposes of compilation) four kinds of calls:

fun f() {
  var 1 x = g(); // declaring call
  g(); //stand-alone call
  x = g(); // assigning call
  return g(); // tail call
}

Declaring calls, unlike other calls, cannot have exception handlers; if g() above raises an exception, this would leave x uninitialised. Note that declaring calls need a shape annotation on the variable, because in general the shape of the return value is not statically known. (I initially tried adding this annotation on the function declaration instead, but this incorrectly assumes it is always statically known which function is being called).

Stand-alone calls have their return values ignored, but unlike tail calls, won't cause the callee to also return.

Tail calls have the return in front of them; hopefully that way nobody will be surprised when they return :)

Make tail calls be of the form

  return f();

...where they used to be of the form

  f();

Previously, if one wrote something like this:

  fun main() {
    f();
    f();
  }

  fun f() { ... }

...then the second call to f will never be executed,
because the tail call eats up the stack frame and makes main return
whatever the first call returned. This is confusing.

Stand-alone function calls are still allowed, but parse to
returning calls that save the return value in the variable "";
this should always be fresh since nothing parses to an empty variable.
DecCall is intended to support the following pattern:

  x = f(e1,...,en)

Call (SOME(NONE, _)) is intended to support stand-alone calls,
i.e. returning calls whose arguments are ignored
It's confusing that

  return f();

parses to TailCall, not RetCall
I first expected to need shape annotations on functions, but
this is a dead end: function pointers make it so that we cannot
statically determine which function is being called.

Instead I've put shape annotations on the declaring calls themselves.
At some point in the future we should probably make declarations
available (mandatory or optional) on all declarations.
The cheats left are not trivial, but it's looking doable.
Declaring calls belong with the blocks
@IlmariReissumies IlmariReissumies merged commit a3ee588 into master May 18, 2024
1 check passed
@IlmariReissumies IlmariReissumies deleted the pan_funexps branch May 18, 2024 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant