mirror of
https://github.com/peklaiho/madlisp.git
synced 2024-11-26 07:04:27 +00:00
add support for variable arguments using &
This commit is contained in:
parent
ed2738c91a
commit
16808c7ff9
@ -241,9 +241,7 @@ class Evaller
|
|||||||
$closure = function (...$args) use ($bindings, $env, $astData, $depth) {
|
$closure = function (...$args) use ($bindings, $env, $astData, $depth) {
|
||||||
$newEnv = new Env('closure', $env);
|
$newEnv = new Env('closure', $env);
|
||||||
|
|
||||||
for ($i = 0; $i < count($bindings); $i++) {
|
Util::bindArguments($newEnv, $bindings, $args);
|
||||||
$newEnv->set($bindings[$i]->getName(), $args[$i] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->eval($astData[2], $newEnv, $depth + 1);
|
return $this->eval($astData[2], $newEnv, $depth + 1);
|
||||||
};
|
};
|
||||||
|
@ -38,10 +38,7 @@ class UserFunc extends Func
|
|||||||
{
|
{
|
||||||
$newEnv = new Env('apply', $this->tempEnv);
|
$newEnv = new Env('apply', $this->tempEnv);
|
||||||
|
|
||||||
$bindings = $this->bindings->getData();
|
Util::bindArguments($newEnv, $this->bindings->getData(), $args);
|
||||||
for ($i = 0; $i < count($bindings); $i++) {
|
|
||||||
$newEnv->set($bindings[$i]->getName(), $args[$i] ?? null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $newEnv;
|
return $newEnv;
|
||||||
}
|
}
|
||||||
|
16
src/Util.php
16
src/Util.php
@ -9,6 +9,22 @@ namespace MadLisp;
|
|||||||
|
|
||||||
class Util
|
class Util
|
||||||
{
|
{
|
||||||
|
public static function bindArguments(Env $env, array $bindings, array $args): void
|
||||||
|
{
|
||||||
|
for ($i = 0; $i < count($bindings); $i++) {
|
||||||
|
if ($bindings[$i]->getName() == '&') {
|
||||||
|
if ($i < count($bindings) - 1) {
|
||||||
|
$env->set($bindings[$i + 1]->getName(), new Vector(array_slice($args, $i)));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new MadLispException('no binding after &');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$env->set($bindings[$i]->getName(), $args[$i] ?? null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function makeHash(array $args): Hash
|
public static function makeHash(array $args): Hash
|
||||||
{
|
{
|
||||||
if (count($args) % 2 == 1) {
|
if (count($args) % 2 == 1) {
|
||||||
|
@ -7,12 +7,74 @@
|
|||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
use MadLisp\Env;
|
||||||
use MadLisp\Hash;
|
use MadLisp\Hash;
|
||||||
use MadLisp\MadLispException;
|
use MadLisp\MadLispException;
|
||||||
|
use MadLisp\Symbol;
|
||||||
use MadLisp\Util;
|
use MadLisp\Util;
|
||||||
|
use MadLisp\Vector;
|
||||||
|
|
||||||
class UtilTest extends TestCase
|
class UtilTest extends TestCase
|
||||||
{
|
{
|
||||||
|
public function testBindArguments()
|
||||||
|
{
|
||||||
|
$env = new Env('env');
|
||||||
|
|
||||||
|
Util::bindArguments($env, [
|
||||||
|
new Symbol('a'),
|
||||||
|
new Symbol('b')
|
||||||
|
], [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(['a' => 1, 'b' => 2], $env->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBindArgumentsVariable()
|
||||||
|
{
|
||||||
|
$env = new Env('env');
|
||||||
|
|
||||||
|
Util::bindArguments($env, [
|
||||||
|
new Symbol('a'),
|
||||||
|
new Symbol('b'),
|
||||||
|
new Symbol('&'),
|
||||||
|
new Symbol('c')
|
||||||
|
], [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = $env->getData();
|
||||||
|
$this->assertCount(3, $data);
|
||||||
|
$this->assertSame(1, $data['a']);
|
||||||
|
$this->assertSame(2, $data['b']);
|
||||||
|
$vec = $data['c'];
|
||||||
|
$this->assertInstanceOf(Vector::class, $vec);
|
||||||
|
$this->assertSame([3, 4], $vec->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBindArgumentsVariableInvalid()
|
||||||
|
{
|
||||||
|
$this->expectException(MadLispException::class);
|
||||||
|
$this->expectExceptionMessage('no binding after &');
|
||||||
|
|
||||||
|
$env = new Env('env');
|
||||||
|
|
||||||
|
Util::bindArguments($env, [
|
||||||
|
new Symbol('a'),
|
||||||
|
new Symbol('b'),
|
||||||
|
new Symbol('&')
|
||||||
|
], [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function testMakeHash()
|
public function testMakeHash()
|
||||||
{
|
{
|
||||||
$hash = Util::makeHash(['a', 1, 'b', 2]);
|
$hash = Util::makeHash(['a', 1, 'b', 2]);
|
||||||
|
Loading…
Reference in New Issue
Block a user