simplify code

This commit is contained in:
Pekka Laiho 2020-06-04 09:10:48 +07:00
parent 3463024a07
commit 437bf252c5
4 changed files with 43 additions and 64 deletions

View File

@ -3,38 +3,7 @@ namespace MadLisp;
class Evaller
{
public function eval(array $expressions, Env $env): array
{
$results = [];
foreach ($expressions as $expr) {
$results[] = $this->doEval($expr, $env);
}
return $results;
}
public function evalAst($ast, Env $env)
{
if ($ast instanceof Symbol) {
// Lookup symbol from env
return $env->get($ast->getName());
} elseif ($ast instanceof MList) {
return new MList(array_map(fn ($a) => $this->doEval($a, $env), $ast->getData()));
} elseif ($ast instanceof Vector) {
return new Vector(array_map(fn ($a) => $this->doEval($a, $env), $ast->getData()));
} elseif ($ast instanceof Hash) {
$results = [];
foreach ($ast->getData() as $key => $val) {
$results[$key] = $this->doEval($val, $env);
}
return new Hash($results);
}
return $ast;
}
public function doEval($ast, Env $env)
public function eval($ast, Env $env)
{
// Not list or empty list
if (!($ast instanceof MList)) {
@ -54,7 +23,7 @@ class Evaller
throw new MadLispException("first argument to def is not symbol");
}
$value = $this->doEval($ast->get(2), $env);
$value = $this->eval($ast->get(2), $env);
return $env->set($ast->get(1)->getName(), $value);
} elseif ($ast->get(0)->getName() == 'do') {
if ($ast->count() < 2) {
@ -91,19 +60,19 @@ class Evaller
$newEnv->set($bindings[$i]->getName(), $args[$i] ?? null);
}
return $this->doEval($ast->get(2), $newEnv);
return $this->eval($ast->get(2), $newEnv);
});
} elseif ($ast->get(0)->getName() == 'if') {
if ($ast->count() < 3 || $ast->count() > 4) {
throw new MadLispException("if requires 2 or 3 arguments");
}
$result = $this->doEval($ast->get(1), $env);
$result = $this->eval($ast->get(1), $env);
if ($result == true) {
return $this->doEval($ast->get(2), $env);
return $this->eval($ast->get(2), $env);
} elseif ($ast->count() == 4) {
return $this->doEval($ast->get(3), $env);
return $this->eval($ast->get(3), $env);
} else {
return null;
}
@ -131,11 +100,11 @@ class Evaller
throw new MadLispException("binding key for let is not symbol");
}
$val = $this->doEval($bindings[$i + 1], $newEnv);
$val = $this->eval($bindings[$i + 1], $newEnv);
$newEnv->set($key->getName(), $val);
}
return $this->doEval($ast->get(2), $newEnv);
return $this->eval($ast->get(2), $newEnv);
} elseif ($ast->get(0)->getName() == 'quote') {
if ($ast->count() != 2) {
throw new MadLispException("quote requires exactly 1 argument");
@ -156,4 +125,24 @@ class Evaller
$args = array_slice($ast->getData(), 1);
return $func->call($args);
}
private function evalAst($ast, Env $env)
{
if ($ast instanceof Symbol) {
// Lookup symbol from env
return $env->get($ast->getName());
} elseif ($ast instanceof MList) {
return new MList(array_map(fn ($a) => $this->eval($a, $env), $ast->getData()));
} elseif ($ast instanceof Vector) {
return new Vector(array_map(fn ($a) => $this->eval($a, $env), $ast->getData()));
} elseif ($ast instanceof Hash) {
$results = [];
foreach ($ast->getData() as $key => $val) {
$results[$key] = $this->eval($val, $env);
}
return new Hash($results);
}
return $ast;
}
}

View File

@ -20,11 +20,11 @@ class Lisp
{
$tokens = $this->tokenizer->tokenize($input);
$expressions = $this->reader->read($tokens);
$expr = $this->reader->read($tokens);
$results = $this->eval->eval($expressions, $env);
$result = $this->eval->eval($expr, $env);
$this->printer->print($results);
$this->printer->print($result);
}
public function register(Env $env): void
@ -39,19 +39,17 @@ class Lisp
}
));
$env->set('eval', new CoreFunc('eval', 'Evaluate arguments.', 1, -1,
function (...$args) use ($env) {
$results = $this->eval->eval($args, $env);
// Return last evaluated value
return $results[count($results) - 1];
}
$env->set('read', new CoreFunc('read', 'Read string as code.', 1, 1,
fn (string $a) => $this->reader->read($this->tokenizer->tokenize($a))
));
$env->set('print', new CoreFunc('print', 'Print arguments.', 1, -1,
function (...$args) {
$this->printer->print($args);
$env->set('eval', new CoreFunc('eval', 'Evaluate argument.', 1, 1,
fn ($a) => $this->eval->eval($a, $env)
));
$env->set('print', new CoreFunc('print', 'Print argument.', 1, 1,
function ($a) {
$this->printer->print($a);
return null;
}
));

View File

@ -3,11 +3,9 @@ namespace MadLisp;
class Printer
{
public function print(array $items): void
public function print($ast): void
{
$strings = array_map(fn ($a) => $this->doPrint($a), $items);
print(implode(' ', $strings));
print($this->doPrint($ast));
}
private function doPrint($a): string

View File

@ -3,16 +3,10 @@ namespace MadLisp;
class Reader
{
public function read(array $tokens): array
public function read(array $tokens)
{
$result = [];
$index = 0;
while ($index < count($tokens)) {
$result[] = $this->readForm($tokens, $index);
}
return $result;
return $this->readForm($tokens, $index);
}
private function readForm(array $tokens, int &$index)