madlisp/src/Evaller.php

59 lines
1.3 KiB
PHP
Raw Normal View History

2020-05-28 10:10:00 +00:00
<?php
namespace MadLisp;
use Closure;
class Evaller
{
public function eval(array $expressions, Env $env): array
{
$results = [];
foreach ($expressions as $expr) {
$results[] = $this->doEval($expr, $env);
}
return $results;
}
2020-05-28 12:41:41 +00:00
public function evalAst($ast, Env $env)
2020-05-28 10:10:00 +00:00
{
2020-05-28 12:41:41 +00:00
if ($ast instanceof Symbol) {
// Lookup symbol from env
return $env->get($ast->getName());
} elseif ($ast instanceof MList) {
// Eval contents and return new list
$results = array_map(fn ($a) => $this->doEval($a, $env), $ast->getData());
return new MList($results);
}
2020-05-28 10:10:00 +00:00
2020-05-28 12:41:41 +00:00
return $ast;
}
2020-05-28 10:10:00 +00:00
2020-05-28 12:41:41 +00:00
public function doEval($ast, Env $env)
{
// Not list
if (!($ast instanceof MList)) {
return $this->evalAst($ast, $env);
}
2020-05-28 10:10:00 +00:00
2020-05-28 12:41:41 +00:00
// Empty list
if ($ast->count() == 0) {
return $ast;
}
2020-05-28 10:10:00 +00:00
2020-05-28 12:41:41 +00:00
// Get new evaluated list
$ast = $this->evalAst($ast, $env);
2020-05-28 10:10:00 +00:00
2020-05-28 12:41:41 +00:00
$first = $ast->get(0);
2020-05-28 10:10:00 +00:00
2020-05-28 12:41:41 +00:00
if (!($first instanceof Closure)) {
throw new MadLispException("first item of list is not function");
2020-05-28 10:10:00 +00:00
}
2020-05-28 12:41:41 +00:00
$args = array_slice($ast->getData(), 1);
return $first(...$args);
2020-05-28 10:10:00 +00:00
}
}