Skip to content

Instantly share code, notes, and snippets.

@Crell

Crell/pfa.md Secret

Last active May 26, 2021 14:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Crell/ead27e7319e41ba98b166aba89fcd7e8 to your computer and use it in GitHub Desktop.
Save Crell/ead27e7319e41ba98b166aba89fcd7e8 to your computer and use it in GitHub Desktop.
PFA logic

Interpreting a PFA call

  • Is there at least one ? or ... , Then it's a PFA and will create a closure.
  • Loop
    • If the current position is a value, bind it to that position in the function call.
    • If the current position is an expression, evaluate that as normal and bind the resulting value.
    • If the current position is a ?, copy the parameter from underlying function (name, type, nullability, reference flag, attributes, and variadicness). If there are no more parameters to copy, break. (This allows pre-filling all arguments with a single ? at the end.)
    • Else break
  • Loop
    • If the current position is a named argument, bind that value to the corresponding parameter in the function call.
    • Else break
  • If the current position is a ..., copy all remaining parameters from the underlying function, including a variadic.
  • Is the result you get now an invalid looking function call? (Variadics before other things, etc.) If so, error out.
  • Return the resulting closure.

Examples

//Given:
function stuff(int $i, string $s, float $f, Point $p, int $m = 0) {}

// Each of these blocks contain equivalent statements.

stuff(?, ?, ?, ?, ?);
stuff(?, ?, ...);
stuff(...);
fn(int $i, string $s, float $f, Point $p, int $m = 0) => stuff($i, $s, $f, $p, $m = 0);

stuff(1, 'hi', ?, ?, ?);
stuff(1, 'hi', ...);
fn(float $f, Point $p, int $m = 0) => stuff(1, 'hi, $f, $p, $m = 0);

stuff(1, ?, 3.5, ?, ?);
stuff(1, ?, 3.5, ...);
fn(string $s, Point $p, int $m = 0) => stuff(1, $s, 3.5, $p, $m = 0);

stuff(?, ?, ?, ?, 5);
fn(int $i, string $s, float $f, Point $p) => stuff($i, $s, $f, $p, 5);

stuff(?, ?, ?, ?); // Not accounting for an optional argument means it will always get its default value.
fn(int $i, string $s, float $f, Point $p) => stuff($i, $s, $f, $p);

stuff(?, ?, f: 3.5, p: $point);
stuff(?, ?, p: $point, f: 3.5);
fn(int $i, string $s) => stuff($i, $s, f: 3.5, p: $point);

stuff(?, ?, f: 3.5, p: $point, ...);
fn(int $i, string $s, int $m = 0) => stuff($i, $s, 3.5, $point, $m);

// And the following are all errors, for the reasons given:

// Insufficient parameters.
stuff(?);

// Parameter $i used more than once.
stuff(?, ?, 3.5, $point, i: 5);

// Positional argument used after named argument.
stuff(i:1, ?, ?, ?, ?);

// Cannot use placeholder on named arguments.
stuff(1, ?, 3.5, p: ?);

// Cannot use positional placeholder after named argument.
// (But the variadic would work, I think? Only if feasible.)
stuff(?, ?, ?, p: $point, ?);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment