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 $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') { } elseif ($symbolName == 'if') {
if ($astLength < 3 || $astLength > 4) { if ($astLength < 3 || $astLength > 4) {
throw new MadLispException("if requires 2 or 3 arguments"); throw new MadLispException("if requires 2 or 3 arguments");

View File

@ -47,6 +47,16 @@ class LispFactory
} else { } else {
throw new MadLispException('unknown attribute for meta'); 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 { } else {
throw new MadLispException('unknown entity for meta'); 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, $env->set('exit', new CoreFunc('exit', 'Terminate the script with given exit code.', 0, 1,
function ($status = 0) { function (int $status = 0) {
exit($status); exit($status);
} }
)); ));

View File

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