Skip to content

Commit

Permalink
Merge pull request #5 from preprocess/feature/new-sigil
Browse files Browse the repository at this point in the history
New sigil
  • Loading branch information
assertchris authored Sep 10, 2018
2 parents 3e2161a + 08efc57 commit f7da823
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 108 deletions.
11 changes: 9 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
"type": "pre-macro",
"name": "pre/short-closures",
"license": "MIT",
"autoload": {
"files": [
"source/functions.php"
]
},
"require": {
"pre/plugin": "^0.10.0"
"pre/plugin": "^0.11.0"
},
"require-dev": {
"phpunit/phpunit": "^5.0|^6.0"
},
"extra": {
"macros": ["source/macros.yay"]
"macros": [
"source/macros.yay"
]
}
}
31 changes: 31 additions & 0 deletions source/functions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Pre\ShortClosures;

use Yay\Ast;

function closure($ast, $implicit = false) {
if ($implicit) {
$defined = [(string) $ast->{"functionArgumentName"} => true];
} else {
$defined = [];

foreach ($ast->{"functionArguments"} as $node) {
$defined[(string) $node["functionArgument"]["functionArgumentName"]] = true;
}
}

$scoped = [];
$scope = new \Yay\Ast("scope");

foreach ($ast->{"* body"}->tokens() as $token) {
$name = $token->value();

if ($name !== '$this' && $token->is(T_VARIABLE) && !isset($scoped[$name]) && !isset($defined[$name])) {
$scope->push(new \Yay\Ast("var", $token));
$scoped[(string) $token] = true;
}
}

$ast->append($scope);
}
176 changes: 89 additions & 87 deletions source/macros.yay
Original file line number Diff line number Diff line change
@@ -1,101 +1,103 @@
<?php

macro ·recursion {
·chain(
·token("("),
·optional(
·ls(
·chain(
·optional(·either(
·ns(),
·token(T_ARRAY),
·token(T_CALLABLE)
))·argType,
·token(T_VARIABLE)·argName,
·optional(·token("="))·argAssignmentEq,
·optional(·either(
·ns(),
·token(T_CONSTANT_ENCAPSED_STRING),
·token(T_LNUMBER),
·token(T_DNUMBER),
·token(T_STRING),
·chain(
·token("["), ·layer(), ·token("]")
)
))·argAssignmentVal
)·arg,
·token(",")
)
)·args,
·token(")"),
·optional(
·chain(
·token(":"),
·either(
·ns(),
·token(T_ARRAY),
·token(T_CALLABLE)
)
)
)·returnType,
·token(T_DOUBLE_ARROW),
·token("{"),
·layer()·body,
·token("}"),
·_()·scope,
·_()·simple
)
$(macro :recursion) {
$(chain(
buffer("("),
functionArguments(),
buffer(")"),
functionReturn(),
buffer("~>"),
buffer("{"),
layer() as body,
buffer("}"),
_() as scope
))
} >> function($ast) {
$defined = [];

foreach ($ast->{"·args"} as $node) {
$name = (string) $node["·arg"]["·argName"];
$defined[$name] = true;
}

$bound = false;
$scope = new \Yay\Ast("·scope");

$pushed = [];

foreach ($ast->{"·body"} as $token) {
$name = $token->value();
return \Pre\ShortClosures\closure($ast, $implicit = false);
} >> {$$(trim(
$(scope ? {
[$(scope ... (, ) {$(var) = $(var) ?? null}), "fn" => function($(functionArguments ... (, ) { $$(functionArgument($(functionArgument))) })) use ($(scope ... (, ) {&$(var)}))$$(functionReturn($(functionReturn))) {
$$(trim($(body)))
}]["fn"]
})

if (!$token->is(T_VARIABLE)) {
continue;
$(scope ! {
function($(functionArguments ... (, ) { $$(functionArgument($(functionArgument))) }))$$(functionReturn($(functionReturn))) {
$$(trim($(body)))
}
})
))}

if (isset($defined[$name]) || isset($pushed[$name])) {
continue;
}
$(macro :recursion) {
$(chain(
buffer("("),
functionArguments(),
buffer(")"),
functionReturn(),
buffer("~>"),
expression() as body,
_() as scope
))
} >> function($ast) {
return \Pre\ShortClosures\closure($ast, $implicit = false);
} >> {$$(trim(
$(scope ? {
[$(scope ... (, ) {$(var) = $(var) ?? null}), "fn" => function($(functionArguments ... (, ) { $$(functionArgument($(functionArgument))) })) use ($(scope ... (, ) {&$(var)}))$$(functionReturn($(functionReturn))) {
return $$(trim($(body)));
}]["fn"]
})

if (substr($name, 1) === "this") {
continue;
$(scope ! {
function($(functionArguments ... (, ) { $$(functionArgument($(functionArgument))) }))$$(functionReturn($(functionReturn))) {
return $$(trim($(body)));
}
})
))}

$scope->push(new \Yay\Ast("·var", $token));
$pushed[$name] = true;
$bound = true;
}
$(macro :recursion) {
$(chain(
token(T_VARIABLE) as functionArgumentName,
buffer("~>"),
expression() as body,
_() as scope
))
} >> function($ast) {
return \Pre\ShortClosures\closure($ast, $implicit = true);
} >> {$$(trim(
$(scope ? {
[$(scope ... (, ) {$(var) = $(var) ?? null}), "fn" => function($(functionArgumentName)) use ($(scope ... (, ) {&$(var)})) {
return $$(trim($(body)));
}]["fn"]
})

if ($bound) {
$ast->append($scope);
} else {
$simple = new \Yay\Ast("·simple");
$simple->push(new \Yay\Ast());
$(scope ! {
function($(functionArgumentName)) {
return $$(trim($(body)));
}
})
))}

$ast->append($simple);
}
} >> {··trim(
·scope ?·{
[·scope ···(, ) { ·var = ·var ?? null}, "fn" => ··trim(function (·args ···(, ) {··trim(·arg ··· { ·argType ·argName ·argAssignmentEq ·argAssignmentVal } )}) use (··trim(·scope ···(, ) {&·var})) ·returnType) {
··trim(·body)
$(macro :recursion) {
$(chain(
token(T_VARIABLE) as functionArgumentName,
buffer("~>"),
token("{"),
layer() as body,
token("}"),
_() as scope
))
} >> function($ast) {
return \Pre\ShortClosures\closure($ast, $implicit = true);
} >> {$$(trim(
$(scope ? {
[$(scope ... (, ) {$(var) = $(var) ?? null}), "fn" => function($(functionArgumentName)) use ($(scope ... (, ) {&$(var)})) {
$$(trim($(body)))
}]["fn"]
}
})

·simple ?·{
··trim(function (·args ···(, ) {··trim(·arg ··· { ·argType ·argName ·argAssignmentEq ·argAssignmentVal } )}) ·returnType) {
··trim(·body)
$(scope ! {
function($(functionArgumentName)) {
$$(trim($(body)))
}
}
)}
})
))}
1 change: 1 addition & 0 deletions tests/MacroTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static function specs()

$files = [
__DIR__ . "/specs/arg-type-callable.spec",
__DIR__ . "/specs/expression-bodies.spec",
__DIR__ . "/specs/recursion.spec",
__DIR__ . "/specs/return-type-array.spec",
__DIR__ . "/specs/return-type-callable.spec",
Expand Down
2 changes: 1 addition & 1 deletion tests/specs/arg-type-callable.spec
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$fn = (callable $x) => { return $x(); };
$fn = (callable $x) ~> { return $x(); };

~~~

Expand Down
39 changes: 39 additions & 0 deletions tests/specs/expression-bodies.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
$fn = ($x = 0) ~> $x + 1;

~~~

$fn = function ($x = 0) {
return $x+1;
};

---

array_map((int $n, float $m) ~> $n + $m, $array1, $array2);

~~~

array_map(function (int $n, float $m) {
return $n+$m;
}, $array1, $array2);

---

$fn = $x ~> $x + 1;

~~~

$fn = function ($x) {
return $x+1;
};

---

array_map($a ~> {
return strtoupper($a);
}, $array1);

~~~

array_map(function ($a) {
return strtoupper($a);
}, $array1);
12 changes: 6 additions & 6 deletions tests/specs/recursion.spec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
$cb = () => {
return () => {
return () => {
$cb = () ~> {
return () ~> {
return () ~> {
return "hello world";
};
};
Expand All @@ -21,9 +21,9 @@ $cb = function () {
$foo = "hello";
$bar = "world";

$cb = () => {
return () => {
return () => {
$cb = () ~> {
return () ~> {
return () ~> {
print $foo . $bar;
};
};
Expand Down
4 changes: 2 additions & 2 deletions tests/specs/return-type-array.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$fn = ($x) :array => { return explode(', ', $x); };
$fn = ($x): array ~> { return explode(', ', $x); };

~~~

$fn = function ($x) :array {
$fn = function ($x): array {
return explode(', ', $x);
};
4 changes: 2 additions & 2 deletions tests/specs/return-type-callable.spec
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
$fn = ($x) :callable => { return () => { return $x; }; };
$fn = ($x): callable ~> { return () ~> { return $x; }; };

~~~

$fn = function ($x) :callable {
$fn = function ($x): callable {
return [$x = $x ?? null, "fn" => function () use (&$x) {
return $x;
}]["fn"];
Expand Down
4 changes: 2 additions & 2 deletions tests/specs/return-type-object.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$fn = ($x) :SomeClass => { return new SomeClass($x); };
$fn = ($x): SomeClass ~> { return new SomeClass($x); };

~~~

$fn = function ($x) :SomeClass {
$fn = function ($x): SomeClass {
return new SomeClass($x);
};
4 changes: 2 additions & 2 deletions tests/specs/return-type-string.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$fn = ($x) :string => { return $x . 'x'; };
$fn = ($x): string ~> { return $x . 'x'; };

~~~

$fn = function ($x) :string {
$fn = function ($x): string {
return $x . 'x';
};
4 changes: 2 additions & 2 deletions tests/specs/return-type-void.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$fn = ($x) :void => { error_log($x); };
$fn = ($x): void ~> { error_log($x); };

~~~

$fn = function ($x) :void {
$fn = function ($x): void {
error_log($x);
};
4 changes: 2 additions & 2 deletions tests/specs/short-closures.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class Fixture
{
public function foo($end, $thing)
{
return ($name) => {
return ($name) ~> {
$this->something();
return "hello {$name}{$end}{$thing}";
};
Expand All @@ -24,7 +24,7 @@ class Fixture

---

$thing = (array $args = []) => {
$thing = (array $args = []) ~> {
print_r($args);
};

Expand Down

0 comments on commit f7da823

Please sign in to comment.