mirror of
https://github.com/peklaiho/madlisp.git
synced 2024-11-26 07:04:27 +00:00
let and eval
This commit is contained in:
parent
c1224fb66f
commit
01e5c4b198
@ -1,22 +1,26 @@
|
||||
<?php
|
||||
require('vendor/autoload.php');
|
||||
|
||||
function ml_get_env(): MadLisp\Env
|
||||
{
|
||||
$env = new MadLisp\Env();
|
||||
|
||||
$core = new MadLisp\Lib\Core();
|
||||
$core->register($env);
|
||||
|
||||
return $env;
|
||||
}
|
||||
|
||||
function ml_get_lisp(): MadLisp\Lisp
|
||||
function ml_get_lisp(): array
|
||||
{
|
||||
$tokenizer = new MadLisp\Tokenizer();
|
||||
$reader = new MadLisp\Reader();
|
||||
$eval = new MadLisp\Evaller();
|
||||
$printer = new MadLisp\Printer();
|
||||
|
||||
return new MadLisp\Lisp($tokenizer, $reader, $eval, $printer);
|
||||
$lisp = new MadLisp\Lisp($tokenizer, $reader, $eval, $printer);
|
||||
|
||||
// environment
|
||||
|
||||
$env = new MadLisp\Env();
|
||||
|
||||
$core = new MadLisp\Lib\Core();
|
||||
$core->register($env);
|
||||
|
||||
$env->set('eval', function (...$args) use ($eval, $env) {
|
||||
$results = $eval->eval($args, $env);
|
||||
return $results[count($results) - 1];
|
||||
});
|
||||
|
||||
return [$lisp, $env];
|
||||
}
|
||||
|
3
repl.php
3
repl.php
@ -1,8 +1,7 @@
|
||||
<?php
|
||||
require('bootstrap.php');
|
||||
|
||||
$env = ml_get_env();
|
||||
$lisp = ml_get_lisp();
|
||||
list($lisp, $env) = ml_get_lisp();
|
||||
|
||||
while (true) {
|
||||
$input = readline('> ');
|
||||
|
@ -21,8 +21,9 @@ class Env extends Hash
|
||||
throw new MadLispException("symbol $key not defined in env");
|
||||
}
|
||||
|
||||
public function set(string $key, $value): void
|
||||
public function set(string $key, $value)
|
||||
{
|
||||
$this->data[$key] = $value;
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
@ -40,21 +40,56 @@ class Evaller
|
||||
|
||||
public function doEval($ast, Env $env)
|
||||
{
|
||||
// Not list
|
||||
// Not list or empty list
|
||||
if (!($ast instanceof MList)) {
|
||||
return $this->evalAst($ast, $env);
|
||||
}
|
||||
|
||||
// Empty list
|
||||
if ($ast->count() == 0) {
|
||||
} elseif ($ast->count() == 0) {
|
||||
return $ast;
|
||||
}
|
||||
|
||||
$first = $ast->get(0);
|
||||
|
||||
// Handle special keywords
|
||||
if ($first instanceof Symbol) {
|
||||
if ($first->getName() == 'quote') {
|
||||
if ($ast->get(0) instanceof Symbol) {
|
||||
if ($ast->get(0)->getName() == 'def') {
|
||||
if ($ast->count() != 3) {
|
||||
throw new MadLispException("def requires exactly 2 arguments");
|
||||
}
|
||||
|
||||
if (!($ast->get(1) instanceof Symbol)) {
|
||||
throw new MadLispException("first argument to def is not symbol");
|
||||
}
|
||||
|
||||
$value = $this->doEval($ast->get(2), $env);
|
||||
return $env->set($ast->get(1)->getName(), $value);
|
||||
} elseif ($ast->get(0)->getName() == 'let') {
|
||||
if ($ast->count() != 3) {
|
||||
throw new MadLispException("let requires exactly 2 arguments");
|
||||
}
|
||||
|
||||
if (!($ast->get(1) instanceof MList)) {
|
||||
throw new MadLispException("first argument to let is not list");
|
||||
}
|
||||
|
||||
$bindings = $ast->get(1)->getData();
|
||||
|
||||
if (count($bindings) % 2 == 1) {
|
||||
throw new MadLispException("uneven number of bindings for let");
|
||||
}
|
||||
|
||||
$newEnv = new Env($env);
|
||||
|
||||
for ($i = 0; $i < count($bindings) - 1; $i += 2) {
|
||||
$key = $bindings[$i];
|
||||
|
||||
if (!($key instanceof Symbol)) {
|
||||
throw new MadLispException("binding key for let is not symbol");
|
||||
}
|
||||
|
||||
$val = $this->doEval($bindings[$i + 1], $newEnv);
|
||||
$newEnv->set($key->getName(), $val);
|
||||
}
|
||||
|
||||
return $this->doEval($ast->get(2), $newEnv);
|
||||
} elseif ($ast->get(0)->getName() == 'quote') {
|
||||
if ($ast->count() != 2) {
|
||||
throw new MadLispException("quote requires exactly 1 argument");
|
||||
}
|
||||
@ -66,14 +101,12 @@ class Evaller
|
||||
// Get new evaluated list
|
||||
$ast = $this->evalAst($ast, $env);
|
||||
|
||||
$first = $ast->get(0);
|
||||
|
||||
if (!($first instanceof Closure)) {
|
||||
// Call first argument as function
|
||||
$func = $ast->get(0);
|
||||
if (!($func instanceof Closure)) {
|
||||
throw new MadLispException("first item of list is not function");
|
||||
}
|
||||
|
||||
$args = array_slice($ast->getData(), 1);
|
||||
|
||||
return $first(...$args);
|
||||
return $func(...$args);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user