add support for userfuncs to meta

This commit is contained in:
Pekka Laiho 2020-12-05 08:13:17 +07:00
parent 5bb2b458b3
commit 1ece3649bc
3 changed files with 22 additions and 6 deletions

View File

@ -159,7 +159,7 @@ class Evaller
return $this->eval($astData[2], $newEnv);
};
return new UserFunc($closure, $astData[2], $env, $bindings);
return new UserFunc($closure, $astData[2], $env, $astData[1]);
} elseif ($symbolName == 'if') {
if ($astLength < 3 || $astLength > 4) {
throw new MadLispException("if requires 2 or 3 arguments");

View File

@ -47,6 +47,16 @@ class LispFactory
} else {
throw new MadLispException('unknown attribute for meta');
}
} elseif ($obj instanceof UserFunc) {
if ($attribute == 'args') {
return $obj->getBindings();
} elseif ($attribute == 'body') {
return $obj->getAst();
} elseif ($attribute == 'code') {
return new MList([new Symbol('fn'), $obj->getBindings(), $obj->getAst()]);
} else {
throw new MadLispException('unknown attribute for meta');
}
} else {
throw new MadLispException('unknown entity for meta');
}
@ -71,7 +81,7 @@ class LispFactory
));
$env->set('exit', new CoreFunc('exit', 'Terminate the script with given exit code.', 0, 1,
function ($status = 0) {
function (int $status = 0) {
exit($status);
}
));

View File

@ -7,9 +7,9 @@ class UserFunc extends Func
{
protected $ast;
protected Env $tempEnv;
protected array $bindings;
protected Seq $bindings;
public function __construct(Closure $closure, $ast, Env $tempEnv, array $bindings)
public function __construct(Closure $closure, $ast, Env $tempEnv, Seq $bindings)
{
parent::__construct($closure, null);
@ -23,12 +23,18 @@ class UserFunc extends Func
return $this->ast;
}
public function getBindings(): Seq
{
return $this->bindings;
}
public function getEnv(array $args)
{
$newEnv = new Env('apply', $this->tempEnv);
for ($i = 0; $i < count($this->bindings); $i++) {
$newEnv->set($this->bindings[$i]->getName(), $args[$i] ?? null);
$bindings = $this->bindings->getData();
for ($i = 0; $i < count($bindings); $i++) {
$newEnv->set($bindings[$i]->getName(), $args[$i] ?? null);
}
return $newEnv;