diff --git a/src/Evaller.php b/src/Evaller.php index 49e7b7e..60b8380 100644 --- a/src/Evaller.php +++ b/src/Evaller.php @@ -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; + } } diff --git a/src/Lisp.php b/src/Lisp.php index 05cde8d..0dd9063 100644 --- a/src/Lisp.php +++ b/src/Lisp.php @@ -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; } )); diff --git a/src/Printer.php b/src/Printer.php index d6ca9e9..e1b4d95 100644 --- a/src/Printer.php +++ b/src/Printer.php @@ -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 diff --git a/src/Reader.php b/src/Reader.php index 9724255..5f27410 100644 --- a/src/Reader.php +++ b/src/Reader.php @@ -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)