new classes for functions, not finished

This commit is contained in:
Pekka Laiho 2020-05-31 17:50:29 +07:00
parent c3c5934c57
commit cc9fa06117
8 changed files with 133 additions and 85 deletions

View File

@ -14,9 +14,9 @@ function ml_get_lisp(): array
$env = new MadLisp\Env(); $env = new MadLisp\Env();
$core = new MadLisp\Lib\Core(); (new MadLisp\Lib\Math())->register($env);
$core->register($env);
/*
$env->set('eval', function (...$args) use ($eval, $env) { $env->set('eval', function (...$args) use ($eval, $env) {
$results = $eval->eval($args, $env); $results = $eval->eval($args, $env);
return $results[count($results) - 1]; return $results[count($results) - 1];
@ -26,6 +26,7 @@ function ml_get_lisp(): array
$printer->print($args); $printer->print($args);
return null; return null;
}); });
*/
return [$lisp, $env]; return [$lisp, $env];
} }

44
src/CoreFunc.php Normal file
View File

@ -0,0 +1,44 @@
<?php
namespace MadLisp;
use Closure;
class CoreFunc extends Func
{
protected string $name;
protected string $doc;
protected int $minArgs;
protected int $maxArgs;
public function __construct(string $name, string $doc, int $minArgs, int $maxArgs, Closure $closure)
{
$this->name = $name;
$this->doc = $doc;
$this->minArgs = $minArgs;
$this->maxArgs = $maxArgs;
$this->closure = $closure;
}
public function call(array $args)
{
$this->validateArgs(count($args));
return parent::call($args);
}
private function validateArgs(int $count)
{
if ($this->minArgs >= 0 && $count < $this->minArgs) {
if ($this->minArgs == $this->maxArgs) {
throw new MadLispException(sprintf("%s requires exactly %s argument%s", $this->name, $this->minArgs,
$this->minArgs == 1 ? '' : 's'));
} else {
throw new MadLispException(sprintf("%s requires at least %s argument%s", $this->name, $this->minArgs,
$this->minArgs == 1 ? '' : 's'));
}
} elseif ($this->maxArgs >= 0 && $count > $this->maxArgs) {
throw new MadLispException(sprintf("%s requires at most %s argument%s", $this->name, $this->maxArgs,
$this->maxArgs == 1 ? '' : 's'));
}
}
}

View File

@ -1,8 +1,6 @@
<?php <?php
namespace MadLisp; namespace MadLisp;
use Closure;
class Evaller class Evaller
{ {
public function eval(array $expressions, Env $env): array public function eval(array $expressions, Env $env): array
@ -150,10 +148,10 @@ class Evaller
// Call first argument as function // Call first argument as function
$func = $ast->get(0); $func = $ast->get(0);
if (!($func instanceof Closure)) { if (!($func instanceof Func)) {
throw new MadLispException("first item of list is not function"); throw new MadLispException("first item of list is not function");
} }
$args = array_slice($ast->getData(), 1); $args = array_slice($ast->getData(), 1);
return $func(...$args); return $func->call($args);
} }
} }

24
src/Func.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace MadLisp;
use Closure;
abstract class Func
{
protected Closure $closure;
public function __construct(Closure $closure)
{
$this->closure = $closure;
}
public function getClosure(): Closure
{
return $this->closure;
}
public function call(array $args)
{
return ($this->closure)(...$args);
}
}

View File

@ -1,8 +1,8 @@
<?php <?php
namespace MadLisp\Lib; namespace MadLisp\Lib;
use Closure;
use MadLisp\Env; use MadLisp\Env;
use MadLisp\Func;
use MadLisp\Hash; use MadLisp\Hash;
use MadLisp\MadLispException; use MadLisp\MadLispException;
use MadLisp\MList; use MadLisp\MList;
@ -13,72 +13,8 @@ class Core implements ILib
{ {
public function register(Env $env): void public function register(Env $env): void
{ {
// logic
$env->set('or', function (...$args) {
// return first true
for ($i = 0; $i < count($args) - 1; $i++) {
if ($args[$i] == true) {
return $args[$i];
}
}
// return last
return $args[count($args) - 1];
});
$env->set('and', function (...$args) {
// return first false
for ($i = 0; $i < count($args) - 1; $i++) {
if ($args[$i] == false) {
return $args[$i];
}
}
// return last
return $args[count($args) - 1];
});
$env->set('not', fn ($a) => !$a);
// arithmetic // arithmetic
$env->set('+', function (...$args) {
return array_sum($args);
});
$env->set('-', function (...$args) {
$result = $args[0] ?? null;
for ($i = 1; $i < count($args); $i++) {
$result -= $args[$i];
}
return $result;
});
$env->set('*', function (...$args) {
$result = $args[0] ?? null;
for ($i = 1; $i < count($args); $i++) {
$result *= $args[$i];
}
return $result;
});
$env->set('/', function (...$args) {
$result = $args[0] ?? null;
for ($i = 1; $i < count($args); $i++) {
$result /= $args[$i];
}
return $result;
});
$env->set('%', function (...$args) {
$result = $args[0] ?? null;
for ($i = 1; $i < count($args); $i++) {
$result %= $args[$i];
}
return $result;
});
// comparison // comparison
$env->set('=', fn ($a, $b) => $a == $b); $env->set('=', fn ($a, $b) => $a == $b);
@ -91,7 +27,7 @@ class Core implements ILib
// types // types
$env->set('type?', function ($a) { $env->set('type?', function ($a) {
if ($a instanceof Closure) { if ($a instanceof Func) {
return 'function'; return 'function';
} elseif ($a instanceof MList) { } elseif ($a instanceof MList) {
return 'list'; return 'list';
@ -112,7 +48,7 @@ class Core implements ILib
} }
}); });
$env->set('fn?', fn ($a) => $a instanceof Closure); $env->set('fn?', fn ($a) => $a instanceof Func);
$env->set('list?', fn ($a) => $a instanceof MList); $env->set('list?', fn ($a) => $a instanceof MList);
$env->set('hash?', fn ($a) => $a instanceof Hash); $env->set('hash?', fn ($a) => $a instanceof Hash);
$env->set('sym?', fn ($a) => $a instanceof Symbol); $env->set('sym?', fn ($a) => $a instanceof Symbol);
@ -124,14 +60,5 @@ class Core implements ILib
$env->set('float?', fn ($a) => is_float($a)); $env->set('float?', fn ($a) => is_float($a));
$env->set('str?', fn ($a) => is_string($a)); $env->set('str?', fn ($a) => is_string($a));
// collections
$env->set('list', function (...$args) {
return new MList($args);
});
$env->set('hash', function (...$args) {
return Util::makeHash($args);
});
} }
} }

49
src/Lib/Math.php Normal file
View File

@ -0,0 +1,49 @@
<?php
namespace MadLisp\Lib;
use MadLisp\CoreFunc;
use MadLisp\Env;
class Math implements ILib
{
public function register(Env $env): void
{
// Basic arithmetic
$env->set('+', new CoreFunc('+', 'Return the sum of all arguments.', 2, -1,
function (...$args) {
return array_sum($args);
}
));
$env->set('-', new CoreFunc('-', 'Subtract the other arguments from the first.', 2, -1,
function (...$args) {
return array_reduce(array_slice($args, 1), fn ($a, $b) => $a - $b, $args[0]);
}
));
$env->set('*', new CoreFunc('*', 'Multiply the arguments.', 2, -1,
function (...$args) {
return array_reduce(array_slice($args, 1), fn ($a, $b) => $a * $b, $args[0]);
}
));
$env->set('/', new CoreFunc('/', 'Divide the arguments.', 2, -1,
function (...$args) {
return array_reduce(array_slice($args, 1), fn ($a, $b) => $a / $b, $args[0]);
}
));
$env->set('//', new CoreFunc('//', 'Divide the arguments using integer division.', 2, -1,
function (...$args) {
return array_reduce(array_slice($args, 1), fn ($a, $b) => intdiv($a, $b), $args[0]);
}
));
$env->set('%', new CoreFunc('%', 'Calculate the modulo of arguments.', 2, -1,
function (...$args) {
return array_reduce(array_slice($args, 1), fn ($a, $b) => $a % $b, $args[0]);
}
));
}
}

View File

@ -1,8 +1,6 @@
<?php <?php
namespace MadLisp; namespace MadLisp;
use Closure;
class Printer class Printer
{ {
public function print(array $items): void public function print(array $items): void
@ -14,7 +12,7 @@ class Printer
private function doPrint($a): string private function doPrint($a): string
{ {
if ($a instanceof Closure) { if ($a instanceof Func) {
return '<function>'; return '<function>';
} elseif ($a instanceof MList) { } elseif ($a instanceof MList) {
return '(' . implode(' ', array_map(fn ($b) => $this->doPrint($b), $a->getData())) . ')'; return '(' . implode(' ', array_map(fn ($b) => $this->doPrint($b), $a->getData())) . ')';

7
src/UserFunc.php Normal file
View File

@ -0,0 +1,7 @@
<?php
namespace MadLisp;
class UserFunc extends Func
{
}