improve eval, add env/quote

This commit is contained in:
Pekka Laiho 2020-05-28 13:59:36 +07:00
parent adc6ab99c3
commit 2acdde303a
4 changed files with 31 additions and 17 deletions

View File

@ -9,7 +9,7 @@ while (true) {
try { try {
$lisp->rep($input, $env); $lisp->rep($input, $env);
} catch (MadLispException $ex) { } catch (MadLisp\MadLispException $ex) {
print('error: ' . $ex->getMessage()); print('error: ' . $ex->getMessage());
} }

View File

@ -149,8 +149,5 @@ class Core implements ILib
return new Hash($data); return new Hash($data);
}); });
// for debugging!
$env->set('eval', fn ($a) => ml_eval($a, $env));
} }
} }

View File

@ -99,19 +99,35 @@ class Lisp
public function eval($expr, Env $env) public function eval($expr, Env $env)
{ {
if ($expr instanceof MList && $expr->count() > 0) { if ($expr instanceof MList && $expr->count() > 0) {
// Evaluate list contents $first = $expr->get(0);
$results = array_map(fn ($a) => $this->eval($a, $env), $expr->getData());
$fn = $results[0]; if ($first instanceof Symbol) {
// Special built-in features
if ($first->getName() == 'env') {
return $env;
} elseif ($first->getName() == 'quote') {
if ($expr->count() != 2) {
throw new MadLispException("quote requires exactly 1 argument");
}
if ($fn instanceof Closure) { return $expr->get(1);
// If the first item is a function, call it }
$args = array_slice($results, 1);
return $fn(...$args); // Normal symbol, fetch from env
} else { $first = $env->get($first->getName());
// Otherwise return new list with evaluated contents
return new MList($results);
} }
if (!($first instanceof Closure)) {
throw new MadLispException("first argument of list is not function");
}
$args = array_slice($expr->getData(), 1);
// Evaluate args
$args = array_map(fn ($a) => $this->eval($a, $env), $args);
// Call func and return result
return $first(...$args);
} elseif ($expr instanceof Hash) { } elseif ($expr instanceof Hash) {
// Hash: return new hash with all items evaluated // Hash: return new hash with all items evaluated
$items = []; $items = [];
@ -120,9 +136,10 @@ class Lisp
} }
return new Hash($items); return new Hash($items);
} elseif ($expr instanceof Symbol) { } elseif ($expr instanceof Symbol) {
return $env->get($expr->name()); return $env->get($expr->getName());
} }
// Return the expression unchanged
return $expr; return $expr;
} }
@ -145,7 +162,7 @@ class Lisp
} }
$result = '{' . implode(' ', $items) . '}'; $result = '{' . implode(' ', $items) . '}';
} elseif ($a instanceof Symbol) { } elseif ($a instanceof Symbol) {
$result = $a->name(); $result = $a->getName();
} elseif ($a === true) { } elseif ($a === true) {
$result = 'true'; $result = 'true';
} elseif ($a === false) { } elseif ($a === false) {

View File

@ -10,7 +10,7 @@ class Symbol
$this->name = $name; $this->name = $name;
} }
public function name(): string public function getName(): string
{ {
return $this->name; return $this->name;
} }