function quasiquote($ast) { if (!is_pair($ast)) { return _list(_symbol("quote"), $ast); } elseif (_symbol_Q($ast[0]) && $ast[0]->value === 'unquote') { return $ast[1]; } elseif (is_pair($ast[0]) && _symbol_Q($ast[0][0]) && $ast[0][0]->value === 'splice-unquote') { return _list(_symbol("concat"), $ast[0][1], quasiquote($ast->slice(1))); } else { return _list(_symbol("cons"), quasiquote($ast[0]), quasiquote($ast->slice(1))); } }
$repl_env = new Env(NULL); function rep($str) { global $repl_env; return MAL_PRINT(MAL_EVAL(READ($str), $repl_env)); } $repl_env->set(_symbol('+'), function ($a, $b) { return intval($a + $b, 10); }); $repl_env->set(_symbol('-'), function ($a, $b) { return intval($a - $b, 10); }); $repl_env->set(_symbol('*'), function ($a, $b) { return intval($a * $b, 10); }); $repl_env->set(_symbol('/'), function ($a, $b) { return intval($a / $b, 10); }); // repl loop do { try { $line = mal_readline("user> "); if ($line === NULL) { break; } if ($line !== "") { print rep($line) . "\n"; } } catch (BlankException $e) { continue; } catch (Exception $e) {
} // print function MAL_PRINT($exp) { return _pr_str($exp, True); } // repl $repl_env = new Env(NULL); function rep($str) { global $repl_env; return MAL_PRINT(MAL_EVAL(READ($str), $repl_env)); } // core.php: defined using PHP foreach ($core_ns as $k => $v) { $repl_env->set(_symbol($k), _function($v)); } // core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); // repl loop do { try { $line = mal_readline("user> "); if ($line === NULL) { break; } if ($line !== "") { print rep($line) . "\n"; } } catch (BlankException $e) { continue;
global $repl_env; return MAL_PRINT(MAL_EVAL(READ($str), $repl_env)); } // core.php: defined using PHP foreach ($core_ns as $k => $v) { $repl_env->set(_symbol($k), _function($v)); } $repl_env->set(_symbol('eval'), _function(function ($ast) { global $repl_env; return MAL_EVAL($ast, $repl_env); })); $_argv = _list(); for ($i = 2; $i < count($argv); $i++) { $_argv->append($argv[$i]); } $repl_env->set(_symbol('*ARGV*'), $_argv); // core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); if (count($argv) > 1) { rep('(load-file "' . $argv[1] . '")'); exit(0); } // repl loop do { try { $line = mal_readline("user> "); if ($line === NULL) { break; } if ($line !== "") {
function read_form($reader) { $token = $reader->peek(); switch ($token) { case '\'': $reader->next(); return _list(_symbol('quote'), read_form($reader)); case '`': $reader->next(); return _list(_symbol('quasiquote'), read_form($reader)); case '~': $reader->next(); return _list(_symbol('unquote'), read_form($reader)); case '~@': $reader->next(); return _list(_symbol('splice-unquote'), read_form($reader)); case '^': $reader->next(); $meta = read_form($reader); return _list(_symbol('with-meta'), read_form($reader), $meta); case '@': $reader->next(); return _list(_symbol('deref'), read_form($reader)); case ')': throw new Exception("unexpected ')'"); case '(': return read_list($reader); case ']': throw new Exception("unexpected ']'"); case '[': return read_list($reader, '_vector', '[', ']'); case '}': throw new Exception("unexpected '}'"); case '{': return read_hash_map($reader); default: return read_atom($reader); } }