eval according to example

This commit is contained in:
Pekka Laiho 2020-05-28 19:41:41 +07:00
parent 80faff86f5
commit 773f195f37

View File

@ -16,64 +16,43 @@ class Evaller
return $results; return $results;
} }
public function doEval($expr, Env $env) public function evalAst($ast, Env $env)
{ {
if ($expr instanceof MList && $expr->count() > 0) { if ($ast instanceof Symbol) {
$first = $expr->get(0); // Lookup symbol from env
return $env->get($ast->getName());
if ($first instanceof Symbol) { } elseif ($ast instanceof MList) {
// Special built-in features // Eval contents and return new list
if ($first->getName() == 'env') { $results = array_map(fn ($a) => $this->doEval($a, $env), $ast->getData());
return $env; return new MList($results);
} elseif ($first->getName() == 'quote') {
if ($expr->count() != 2) {
throw new MadLispException("quote requires exactly 1 argument");
} }
return $expr->get(1); return $ast;
} elseif ($first->getName() == 'if') {
if ($expr->count() != 4) {
throw new MadLispException("if requires exactly 3 arguments");
} }
// Eval condition public function doEval($ast, Env $env)
$result = $this->doEval($expr->get(1), $env); {
// Not list
// Eval true or false branch and return it if (!($ast instanceof MList)) {
if ($result == true) { return $this->evalAst($ast, $env);
return $this->doEval($expr->get(2), $env);
} else {
return $this->doEval($expr->get(3), $env);
}
} }
// Normal symbol, fetch from env // Empty list
$first = $env->get($first->getName()); if ($ast->count() == 0) {
return $ast;
} }
// Get new evaluated list
$ast = $this->evalAst($ast, $env);
$first = $ast->get(0);
if (!($first instanceof Closure)) { if (!($first instanceof Closure)) {
throw new MadLispException("first argument of list is not function"); throw new MadLispException("first item of list is not function");
} }
$args = array_slice($expr->getData(), 1); $args = array_slice($ast->getData(), 1);
// Evaluate args
$args = array_map(fn ($a) => $this->doEval($a, $env), $args);
// Call func and return result
return $first(...$args); return $first(...$args);
} elseif ($expr instanceof Hash) {
// Hash: return new hash with all items evaluated
$items = [];
foreach ($expr->getData() as $key => $val) {
$items[$key] = $this->doEval($val, $env);
}
return new Hash($items);
} elseif ($expr instanceof Symbol) {
return $env->get($expr->getName());
}
// Return the expression unchanged
return $expr;
} }
} }