fix: use by reference in anonymous functions (#10)

This commit is contained in:
Saif Eddin Gmati 2022-12-03 00:20:09 +01:00 committed by Ryan Chandler
parent 848da45855
commit 6c27fc8599
5 changed files with 1374 additions and 1 deletions

View File

@ -48,6 +48,8 @@ impl Parser {
while state.current.kind != TokenKind::RightParen {
let mut by_ref = false;
if state.current.kind == TokenKind::Ampersand {
state.next();
by_ref = true;
}

View File

@ -47,7 +47,7 @@ impl State {
let mut iter = tokens.into_iter();
Self {
stack: VecDeque::new(),
stack: VecDeque::with_capacity(3),
current: iter.next().unwrap_or_default(),
peek: iter.next().unwrap_or_default(),
iter,

309
tests/0178/ast.txt Normal file
View File

@ -0,0 +1,309 @@
[
Declare {
declares: [
DeclareItem {
key: Identifier {
name: "strict_types",
},
value: LiteralInteger {
i: 1,
},
},
],
body: [],
},
Namespace {
name: "Psl\Internal",
body: [
Noop,
Use {
uses: [
Use {
name: Identifier {
name: "Closure",
},
alias: None,
},
],
kind: Normal,
},
Use {
uses: [
Use {
name: Identifier {
name: "Psl\Str",
},
alias: None,
},
],
kind: Normal,
},
Use {
uses: [
Use {
name: Identifier {
name: "restore_error_handler",
},
alias: None,
},
],
kind: Function,
},
Use {
uses: [
Use {
name: Identifier {
name: "set_error_handler",
},
alias: None,
},
],
kind: Function,
},
Function {
name: Identifier {
name: "box",
},
params: [
Param {
name: Variable {
name: "fun",
},
type: Some(
Identifier(
Identifier {
name: "Closure",
},
),
),
variadic: false,
default: None,
flags: [],
by_ref: false,
},
],
body: [
Expression {
expr: Infix {
lhs: Variable {
name: "last_message",
},
op: Assign,
rhs: Null,
},
},
Expression {
expr: Call {
target: Identifier {
name: "set_error_handler",
},
args: [
Arg {
name: None,
value: Closure {
params: [
Param {
name: Variable {
name: "_type",
},
type: Some(
Integer,
),
variadic: false,
default: None,
flags: [],
by_ref: false,
},
Param {
name: Variable {
name: "message",
},
type: Some(
String,
),
variadic: false,
default: None,
flags: [],
by_ref: false,
},
],
uses: [
ClosureUse {
var: Variable {
name: "last_message",
},
by_ref: true,
},
],
return_type: None,
body: [
Expression {
expr: Infix {
lhs: Variable {
name: "last_message",
},
op: Assign,
rhs: Variable {
name: "message",
},
},
},
],
static: true,
by_ref: false,
},
unpack: false,
},
],
},
},
If {
condition: Infix {
lhs: Infix {
lhs: Null,
op: NotIdentical,
rhs: Variable {
name: "last_message",
},
},
op: And,
rhs: Call {
target: Identifier {
name: "Str\contains",
},
args: [
Arg {
name: None,
value: Variable {
name: "last_message",
},
unpack: false,
},
Arg {
name: None,
value: LiteralString {
value: "): ",
},
unpack: false,
},
],
},
},
then: [
Expression {
expr: Infix {
lhs: Variable {
name: "last_message",
},
op: Assign,
rhs: Call {
target: Identifier {
name: "Str\after",
},
args: [
Arg {
name: None,
value: Call {
target: Identifier {
name: "Str\lowercase",
},
args: [
Arg {
name: None,
value: Variable {
name: "last_message",
},
unpack: false,
},
],
},
unpack: false,
},
Arg {
name: None,
value: LiteralString {
value: "): ",
},
unpack: false,
},
],
},
},
},
],
else_ifs: [],
else: None,
},
Try {
body: [
Expression {
expr: Infix {
lhs: Variable {
name: "value",
},
op: Assign,
rhs: Call {
target: Variable {
name: "fun",
},
args: [],
},
},
},
Expression {
expr: Infix {
lhs: Variable {
name: "result",
},
op: Assign,
rhs: Array {
items: [
ArrayItem {
key: None,
value: Variable {
name: "value",
},
unpack: false,
},
ArrayItem {
key: None,
value: Variable {
name: "last_message",
},
unpack: false,
},
],
},
},
},
Return {
value: Some(
Variable {
name: "result",
},
),
},
],
catches: [],
finally: Some(
[
Expression {
expr: Call {
target: Identifier {
name: "restore_error_handler",
},
args: [],
},
},
],
),
},
],
return_type: Some(
Array,
),
by_ref: false,
},
],
},
]

61
tests/0178/code.php Normal file
View File

@ -0,0 +1,61 @@
<?php
// The following code was taken from of PSL.
//
// https://github.com/azjezz/psl/blob/657ce9888be47cee49418989420b83661f7cf1c4/src/Psl/Internal/box.php
//
// Code subject to the MIT license (https://github.com/azjezz/psl/blob/657ce9888be47cee49418989420b83661f7cf1c4/LICENSE).
//
// Copyright (c) 2019-2022 Saif Eddin Gmati <azjezz@protonmail.com>
declare(strict_types=1);
namespace Psl\Internal;
use Closure;
use Psl\Str;
use function restore_error_handler;
use function set_error_handler;
/**
* @template T
*
* @param (Closure(): T) $fun
*
* @return array{0: T, 1: ?string}
*
* @internal
*
* @psalm-suppress MissingThrowsDocblock
*/
function box(Closure $fun): array
{
$last_message = null;
/** @psalm-suppress InvalidArgument */
set_error_handler(static function (int $_type, string $message) use (&$last_message) {
$last_message = $message;
});
/**
* @var string|null $last_message
*/
if (null !== $last_message && Str\contains($last_message, '): ')) {
$last_message = Str\after(
Str\lowercase($last_message),
// how i feel toward PHP error handling:
'): '
);
}
try {
$value = $fun();
/** @var array{0: T, 1: ?string} $result */
$result = [$value, $last_message];
return $result;
} finally {
restore_error_handler();
}
}

1001
tests/0178/tokens.txt Normal file

File diff suppressed because it is too large Load Diff