madlisp/src/Reader.php

112 lines
3.1 KiB
PHP
Raw Normal View History

2020-05-28 10:10:00 +00:00
<?php
2020-12-14 01:49:07 +00:00
/**
* MadLisp language
* @link http://madlisp.com/
* @copyright Copyright (c) 2020 Pekka Laiho
*/
2020-05-28 10:10:00 +00:00
namespace MadLisp;
class Reader
{
2020-06-04 02:10:48 +00:00
public function read(array $tokens)
2020-05-28 10:10:00 +00:00
{
2020-06-04 11:27:47 +00:00
if (empty($tokens)) {
return null;
}
2020-05-28 10:10:00 +00:00
$index = 0;
2020-06-04 02:10:48 +00:00
return $this->readForm($tokens, $index);
2020-05-28 10:10:00 +00:00
}
private function readForm(array $tokens, int &$index)
{
2020-05-31 04:50:53 +00:00
if ($tokens[$index] == "'") {
return $this->readSpecialForm($tokens, $index, 'quote');
} elseif ($tokens[$index] == "`") {
return $this->readSpecialForm($tokens, $index, 'quasiquote');
} elseif ($tokens[$index] == "~") {
return $this->readSpecialForm($tokens, $index, 'unquote');
2020-05-31 04:50:53 +00:00
} elseif ($tokens[$index] == '(') {
2020-05-28 10:10:00 +00:00
return $this->readList($tokens, $index);
2020-05-31 04:34:24 +00:00
} elseif ($tokens[$index] == '[') {
return $this->readVector($tokens, $index);
} elseif ($tokens[$index] == '{') {
return $this->readHash($tokens, $index);
2020-05-28 10:10:00 +00:00
} else {
return $this->readAtom($tokens, $index);
}
}
private function readSpecialForm(array $tokens, int &$index, string $symbol)
{
$index++;
$contents = [new Symbol($symbol)];
if ($index < count($tokens) && !in_array($tokens[$index], [')', ']', '}'])) {
$contents[] = $this->readForm($tokens, $index);
}
return new MList($contents);
}
2020-05-28 10:10:00 +00:00
private function readList(array $tokens, int &$index): MList
2020-05-31 04:34:24 +00:00
{
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
2020-05-28 10:10:00 +00:00
{
$result = [];
// start tag
$index++;
2020-05-31 04:34:24 +00:00
while ($tokens[$index] != $endTag) {
2020-05-28 10:10:00 +00:00
$result[] = $this->readForm($tokens, $index);
}
// end tag
$index++;
2020-05-31 04:34:24 +00:00
return $result;
2020-05-28 10:10:00 +00:00
}
private function readAtom(array $tokens, int &$index)
{
$a = $tokens[$index++];
if ($a === 'true') {
return true;
} elseif ($a === 'false') {
return false;
} elseif ($a === 'null') {
return null;
} elseif (substr($a, 0, 1) === '"') {
2020-12-15 11:28:02 +00:00
// Remove quotes around string.
//
// Hopefully this should work correctly with Unicode strings as well,
// because we just want to remove one byte from beginning and end,
// so mb_substr should not be needed?
return substr($a, 1, -1);
2020-05-28 10:10:00 +00:00
} elseif (is_numeric($a)) {
if (filter_var($a, FILTER_VALIDATE_INT) !== false) {
return intval($a);
} else {
return floatval($a);
}
} else {
return new Symbol($a);
}
}
}