madlisp/src/LispFactory.php

126 lines
4.3 KiB
PHP
Raw Normal View History

2020-06-17 10:24:15 +00:00
<?php
namespace MadLisp;
class LispFactory
{
public function make(array $coreLibs = [], array $userLibs = []): Lisp
2020-06-17 10:24:15 +00:00
{
$tokenizer = new Tokenizer();
$reader = new Reader();
$printer = new Printer();
$eval = new Evaller($tokenizer, $reader, $printer);
// Root environment
$env = new Env('root');
// Register special constants
$env->set('__FILE__', null);
$env->set('__DIR__', null);
2020-06-17 10:24:15 +00:00
// Register core functions
2020-12-05 01:42:56 +00:00
$env->set('debug', new CoreFunc('debug', 'Toggle debug mode.', 0, 0,
function () use ($eval) {
$val = !$eval->getDebug();
$eval->setDebug($val);
return $val;
}
));
2020-06-17 10:24:15 +00:00
$env->set('doc', new CoreFunc('doc', 'Get documentation for a function.', 1, 1,
function ($a) {
if ($a instanceof Func) {
return $a->getDoc();
}
throw new MadLispException('first argument to doc is not function');
}
));
2020-10-18 03:24:18 +00:00
$env->set('loop', new CoreFunc('loop', 'Call the given function repeatedly in a loop until it returns false.', 1, -1,
function (Func $f, ...$args) {
do {
$result = $f->call($args);
} while ($result);
return $result;
}
));
2020-10-24 03:02:50 +00:00
$env->set('meta', new CoreFunc('meta', 'Read meta information of an entity.', 2, 2,
function ($obj, $attribute) {
if ($obj instanceof Env) {
if ($attribute == 'name') {
return $obj->getFullName();
} elseif ($attribute == 'parent') {
return $obj->getParent();
} else {
throw new MadLispException('unknown attribute for meta');
}
2020-12-05 01:13:17 +00:00
} elseif ($obj instanceof UserFunc) {
if ($attribute == 'args') {
return $obj->getBindings();
} elseif ($attribute == 'body') {
return $obj->getAst();
} elseif ($attribute == 'code') {
return new MList([new Symbol('fn'), $obj->getBindings(), $obj->getAst()]);
} else {
throw new MadLispException('unknown attribute for meta');
}
2020-10-24 03:02:50 +00:00
} else {
throw new MadLispException('unknown entity for meta');
}
}
));
2020-06-17 10:24:15 +00:00
$env->set('read', new CoreFunc('read', 'Read string as code.', 1, 1,
fn (string $a) => $reader->read($tokenizer->tokenize($a))
));
$env->set('print', new CoreFunc('print', 'Print argument. Give second argument as true to show strings in readable format.', 1, 2,
function ($a, bool $readable = false) use ($printer) {
$printer->print($a, $readable);
return null;
}
));
$env->set('error', new CoreFunc('error', 'Throw an exception using argument (string) as message.', 1, 1,
function (string $error) {
throw new MadLispException($error);
}
));
2020-10-17 07:47:30 +00:00
$env->set('exit', new CoreFunc('exit', 'Terminate the script with given exit code.', 0, 1,
2020-12-05 01:13:17 +00:00
function (int $status = 0) {
2020-10-17 07:47:30 +00:00
exit($status);
}
));
2020-06-17 10:24:15 +00:00
// Register core libraries
(new Lib\Collections())->register($env);
(new Lib\Compare())->register($env);
2020-06-19 12:09:07 +00:00
(new Lib\Database())->register($env);
2020-06-20 03:33:15 +00:00
(new Lib\Http())->register($env);
2020-06-17 10:24:15 +00:00
(new Lib\IO())->register($env);
2020-06-19 03:50:44 +00:00
(new Lib\Json())->register($env);
2020-06-17 10:24:15 +00:00
(new Lib\Math())->register($env);
2020-10-18 07:33:27 +00:00
(new Lib\Regex())->register($env);
2020-06-17 10:24:15 +00:00
(new Lib\Strings())->register($env);
(new Lib\Time())->register($env);
(new Lib\Types())->register($env);
// Register additional libs for root env
foreach ($coreLibs as $lib) {
2020-06-17 10:24:15 +00:00
$lib->register($env);
}
// User environment
$env = new Env('user', $env);
// Register additional libs for user env
foreach ($userLibs as $lib) {
$lib->register($env);
}
2020-06-17 10:24:15 +00:00
return new Lisp($tokenizer, $reader, $eval, $printer, $env);
}
}