add Vector, other improvements

This commit is contained in:
Pekka Laiho 2020-05-31 11:34:24 +07:00
parent 5869b2f483
commit 9e03179650
9 changed files with 94 additions and 61 deletions

View File

@ -22,11 +22,9 @@ class Evaller
// Lookup symbol from env // Lookup symbol from env
return $env->get($ast->getName()); return $env->get($ast->getName());
} elseif ($ast instanceof MList) { } elseif ($ast instanceof MList) {
$results = []; return new MList(array_map(fn ($a) => $this->doEval($a, $env), $ast->getData()));
foreach ($ast->getData() as $val) { } elseif ($ast instanceof Vector) {
$results[] = $this->doEval($val, $env); return new Vector(array_map(fn ($a) => $this->doEval($a, $env), $ast->getData()));
}
return new MList($results);
} elseif ($ast instanceof Hash) { } elseif ($ast instanceof Hash) {
$results = []; $results = [];
foreach ($ast->getData() as $key => $val) { foreach ($ast->getData() as $key => $val) {

View File

@ -4,9 +4,10 @@ namespace MadLisp\Lib;
use Closure; use Closure;
use MadLisp\Env; use MadLisp\Env;
use MadLisp\Hash; use MadLisp\Hash;
use MadLisp\MadLispException;
use MadLisp\MList; use MadLisp\MList;
use MadLisp\Symbol; use MadLisp\Symbol;
use MadLisp\MadLispException; use MadLisp\Util;
class Core implements ILib class Core implements ILib
{ {
@ -130,24 +131,7 @@ class Core implements ILib
}); });
$env->set('hash', function (...$args) { $env->set('hash', function (...$args) {
if (count($args) % 2 == 1) { return Util::makeHash($args);
throw new MadLispException('uneven number of arguments for hash');
}
$data = [];
for ($i = 0; $i < count($args) - 1; $i += 2) {
$key = $args[$i];
$val = $args[$i + 1];
if (!is_string($key)) {
throw new MadLispException('invalid key for hash (not string)');
}
$data[$key] = $val;
}
return new Hash($data);
}); });
} }
} }

View File

@ -1,7 +1,7 @@
<?php <?php
namespace MadLisp; namespace MadLisp;
class MList extends Collection class MList extends Seq
{ {
public function get(int $index) public function get(int $index)
{ {

View File

@ -7,51 +7,34 @@ class Printer
{ {
public function print(array $items): void public function print(array $items): void
{ {
for ($i = 0; $i < count($items); $i++) { $strings = array_map(fn ($a) => $this->doPrint($a), $items);
if ($i > 0) {
print(' '); print(implode(' ', $strings));
}
$this->doPrint($items[$i]);
}
} }
private function doPrint($a): void private function doPrint($a): string
{ {
if ($a instanceof Closure) { if ($a instanceof Closure) {
print('<function>'); return '<function>';
} elseif ($a instanceof MList) { } elseif ($a instanceof MList) {
print('('); return '(' . implode(' ', array_map(fn ($b) => $this->doPrint($b), $a->getData())) . ')';
for ($i = 0; $i < $a->count(); $i++) { } elseif ($a instanceof Vector) {
if ($i > 0) { return '[' . implode(' ', array_map(fn ($b) => $this->doPrint($b), $a->getData())) . ']';
print(' ');
}
$this->doPrint($a->get($i));
}
print(')');
} elseif ($a instanceof Hash) { } elseif ($a instanceof Hash) {
print('{'); return '{' . implode(' ', array_map(fn ($key, $val) => $this->doPrint($key) . ':' . $this->doPrint($val),
$keys = array_keys($a->getData()); array_keys($a->getData()), array_values($a->getData()))) . '}';
for ($i = 0; $i < count($keys); $i++) {
if ($i > 0) {
print(' ');
}
$this->doPrint($keys[$i]);
print(':');
$this->doPrint($a->get($keys[$i]));
}
print('}');
} elseif ($a instanceof Symbol) { } elseif ($a instanceof Symbol) {
print($a->getName()); return $a->getName();
} elseif ($a === true) { } elseif ($a === true) {
print('true'); return 'true';
} elseif ($a === false) { } elseif ($a === false) {
print('false'); return 'false';
} elseif ($a === null) { } elseif ($a === null) {
print('null'); return 'null';
} elseif (is_string($a)) { } elseif (is_string($a)) {
print('"' . $a . '"'); return '"' . $a . '"';
} else { } else {
print($a); return $a;
} }
} }
} }

View File

@ -19,26 +19,46 @@ class Reader
{ {
if ($tokens[$index] == '(') { if ($tokens[$index] == '(') {
return $this->readList($tokens, $index); return $this->readList($tokens, $index);
} elseif ($tokens[$index] == '[') {
return $this->readVector($tokens, $index);
} elseif ($tokens[$index] == '{') {
return $this->readHash($tokens, $index);
} else { } else {
return $this->readAtom($tokens, $index); return $this->readAtom($tokens, $index);
} }
} }
private function readList(array $tokens, int &$index): MList private function readList(array $tokens, int &$index): MList
{
return new MList($this->readCollection($tokens, $index, ')'));
}
private function readVector(array $tokens, int &$index): Vector
{
return new Vector($this->readCollection($tokens, $index, ']'));
}
private function readHash(array $tokens, int &$index): Hash
{
$contents = $this->readCollection($tokens, $index, '}');
return Util::makeHash($contents);
}
private function readCollection(array $tokens, int &$index, string $endTag): array
{ {
$result = []; $result = [];
// start tag // start tag
$index++; $index++;
while ($tokens[$index] != ')') { while ($tokens[$index] != $endTag) {
$result[] = $this->readForm($tokens, $index); $result[] = $this->readForm($tokens, $index);
} }
// end tag // end tag
$index++; $index++;
return new MList($result); return $result;
} }
private function readAtom(array $tokens, int &$index) private function readAtom(array $tokens, int &$index)

7
src/Seq.php Normal file
View File

@ -0,0 +1,7 @@
<?php
namespace MadLisp;
abstract class Seq extends Collection
{
}

View File

@ -28,7 +28,7 @@ class Tokenizer
// Inside string, add all characters // Inside string, add all characters
$current .= $c; $current .= $c;
// Stop at double quote // Stop at first double quote
if ($c == '"') { if ($c == '"') {
$addCurrent(); $addCurrent();
$isString = false; $isString = false;

27
src/Util.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace MadLisp;
class Util
{
public static function makeHash(array $args): Hash
{
if (count($args) % 2 == 1) {
throw new MadLispException('uneven number of arguments for hash');
}
$data = [];
for ($i = 0; $i < count($args) - 1; $i += 2) {
$key = $args[$i];
$val = $args[$i + 1];
if (!is_string($key)) {
throw new MadLispException('invalid key for hash (not string)');
}
$data[$key] = $val;
}
return new Hash($data);
}
}

14
src/Vector.php Normal file
View File

@ -0,0 +1,14 @@
<?php
namespace MadLisp;
class Vector extends Seq
{
public function get(int $index)
{
if ($this->has($index)) {
return $this->data[$index];
}
throw new MadLispException("vector does not contain index $index");
}
}