diff options
Diffstat (limited to 'php')
| -rw-r--r-- | php/core.php | 8 | ||||
| -rw-r--r-- | php/env.php | 8 | ||||
| -rw-r--r-- | php/printer.php | 4 | ||||
| -rw-r--r-- | php/reader.php | 2 | ||||
| -rw-r--r-- | php/step3_env.php | 14 | ||||
| -rw-r--r-- | php/step4_if_fn_do.php | 8 | ||||
| -rw-r--r-- | php/step5_tco.php | 8 | ||||
| -rw-r--r-- | php/step6_file.php | 12 | ||||
| -rw-r--r-- | php/step7_quote.php | 12 | ||||
| -rw-r--r-- | php/step8_macros.php | 20 | ||||
| -rw-r--r-- | php/step9_try.php | 22 | ||||
| -rw-r--r-- | php/stepA_interop.php | 20 | ||||
| -rw-r--r-- | php/types.php | 7 |
13 files changed, 80 insertions, 65 deletions
diff --git a/php/core.php b/php/core.php index 4cb4667..96129b1 100644 --- a/php/core.php +++ b/php/core.php @@ -97,7 +97,11 @@ function concat() { } function nth($seq, $idx) { - return $seq[$idx]; + if ($idx < $seq->count()) { + return $seq[$idx]; + } else { + throw new Exception("nth: index out of range"); + } } function first($seq) { @@ -177,6 +181,8 @@ $core_ns = array( 'false?'=> function ($a) { return _false_Q($a); }, 'symbol'=> function () { return call_user_func_array('_symbol', func_get_args()); }, 'symbol?'=> function ($a) { return _symbol_Q($a); }, + 'keyword'=> function () { return call_user_func_array('_keyword', func_get_args()); }, + 'keyword?'=> function ($a) { return _keyword_Q($a); }, 'string?'=> function ($a) { return _string_Q($a); }, 'pr-str'=> function () { return call_user_func_array('pr_str', func_get_args()); }, diff --git a/php/env.php b/php/env.php index 61bedaf..a660d3b 100644 --- a/php/env.php +++ b/php/env.php @@ -31,7 +31,7 @@ class Env { } } public function find($key) { - if (array_key_exists($key, $this->data)) { + if (array_key_exists($key->value, $this->data)) { return $this; } elseif ($this->outer) { return $this->outer->find($key); @@ -40,15 +40,15 @@ class Env { } } public function set($key, $value) { - $this->data[$key] = $value; + $this->data[$key->value] = $value; return $value; } public function get($key) { $env = $this->find($key); if (!$env) { - throw new Exception("'" . $key . "' not found"); + throw new Exception("'" . $key->value . "' not found"); } else { - return $env->data[$key]; + return $env->data[$key->value]; } } } diff --git a/php/printer.php b/php/printer.php index 3839931..130d31b 100644 --- a/php/printer.php +++ b/php/printer.php @@ -23,7 +23,9 @@ function _pr_str($obj, $print_readably=True) { } return "{" . implode(" ", $ret) . "}"; } elseif (is_string($obj)) { - if ($print_readably) { + if (strpos($obj, chr(0x7f)) === 0) { + return ":".substr($obj,1); + } elseif ($print_readably) { $obj = preg_replace('/"/', '\\"', preg_replace('/\\\\/', '\\\\\\\\', $obj)); return '"' . $obj . '"'; } else { diff --git a/php/reader.php b/php/reader.php index 83e0cff..ed9063f 100644 --- a/php/reader.php +++ b/php/reader.php @@ -40,6 +40,8 @@ function read_atom($reader) { $str = substr($token, 1, -1); $str = preg_replace('/\\\\"/', '"', $str); return $str; + } elseif ($token[0] === ":") { + return _keyword(substr($token,1)); } elseif ($token === "nil") { return NULL; } elseif ($token === "true") { diff --git a/php/step3_env.php b/php/step3_env.php index 6585fe7..a31c298 100644 --- a/php/step3_env.php +++ b/php/step3_env.php @@ -14,7 +14,7 @@ function READ($str) { // eval function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -46,12 +46,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } return MAL_EVAL($ast[2], $let_env); default: @@ -73,10 +73,10 @@ function rep($str) { return MAL_PRINT(MAL_EVAL(READ($str), $repl_env)); } -$repl_env->set('+', function ($a, $b) { return intval($a + $b,10); }); -$repl_env->set('-', function ($a, $b) { return intval($a - $b,10); }); -$repl_env->set('*', function ($a, $b) { return intval($a * $b,10); }); -$repl_env->set('/', 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_env->set(_symbol('/'), function ($a, $b) { return intval($a / $b,10); }); // repl loop do { diff --git a/php/step4_if_fn_do.php b/php/step4_if_fn_do.php index 1e88c6a..7266261 100644 --- a/php/step4_if_fn_do.php +++ b/php/step4_if_fn_do.php @@ -15,7 +15,7 @@ function READ($str) { // eval function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -47,12 +47,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } return MAL_EVAL($ast[2], $let_env); case "do": @@ -93,7 +93,7 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } // core.mal: defined using the language itself diff --git a/php/step5_tco.php b/php/step5_tco.php index 88557b5..a3785cf 100644 --- a/php/step5_tco.php +++ b/php/step5_tco.php @@ -15,7 +15,7 @@ function READ($str) { // eval function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -49,12 +49,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } $ast = $ast[2]; $env = $let_env; @@ -105,7 +105,7 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } // core.mal: defined using the language itself diff --git a/php/step6_file.php b/php/step6_file.php index 1e83c28..a27acb8 100644 --- a/php/step6_file.php +++ b/php/step6_file.php @@ -15,7 +15,7 @@ function READ($str) { // eval function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -49,12 +49,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } $ast = $ast[2]; $env = $let_env; @@ -105,16 +105,16 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } -$repl_env->set('eval', _function(function($ast) { +$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('*ARGV*', $_argv); +$repl_env->set(_symbol('*ARGV*'), $_argv); // core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); diff --git a/php/step7_quote.php b/php/step7_quote.php index 07d3d2a..37903d0 100644 --- a/php/step7_quote.php +++ b/php/step7_quote.php @@ -34,7 +34,7 @@ function quasiquote($ast) { function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -68,12 +68,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } $ast = $ast[2]; $env = $let_env; @@ -129,16 +129,16 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } -$repl_env->set('eval', _function(function($ast) { +$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('*ARGV*', $_argv); +$repl_env->set(_symbol('*ARGV*'), $_argv); // core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); diff --git a/php/step8_macros.php b/php/step8_macros.php index aacf33e..c7e0175 100644 --- a/php/step8_macros.php +++ b/php/step8_macros.php @@ -35,13 +35,13 @@ function quasiquote($ast) { function is_macro_call($ast, $env) { return is_pair($ast) && _symbol_Q($ast[0]) && - $env->find($ast[0]->value) && - $env->get($ast[0]->value)->ismacro; + $env->find($ast[0]) && + $env->get($ast[0])->ismacro; } function macroexpand($ast, $env) { while (is_macro_call($ast, $env)) { - $mac = $env->get($ast[0]->value); + $mac = $env->get($ast[0]); $args = array_slice($ast->getArrayCopy(),1); $ast = $mac->apply($args); } @@ -50,7 +50,7 @@ function macroexpand($ast, $env) { function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -87,12 +87,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } $ast = $ast[2]; $env = $let_env; @@ -105,7 +105,7 @@ function MAL_EVAL($ast, $env) { case "defmacro!": $func = MAL_EVAL($ast[2], $env); $func->ismacro = true; - return $env->set($ast[1]->value, $func); + return $env->set($ast[1], $func); case "macroexpand": return macroexpand($ast[1], $env); case "do": @@ -154,16 +154,16 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } -$repl_env->set('eval', _function(function($ast) { +$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('*ARGV*', $_argv); +$repl_env->set(_symbol('*ARGV*'), $_argv); // core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); diff --git a/php/step9_try.php b/php/step9_try.php index 9343dea..0470763 100644 --- a/php/step9_try.php +++ b/php/step9_try.php @@ -35,13 +35,13 @@ function quasiquote($ast) { function is_macro_call($ast, $env) { return is_pair($ast) && _symbol_Q($ast[0]) && - $env->find($ast[0]->value) && - $env->get($ast[0]->value)->ismacro; + $env->find($ast[0]) && + $env->get($ast[0])->ismacro; } function macroexpand($ast, $env) { while (is_macro_call($ast, $env)) { - $mac = $env->get($ast[0]->value); + $mac = $env->get($ast[0]); $args = array_slice($ast->getArrayCopy(),1); $ast = $mac->apply($args); } @@ -50,7 +50,7 @@ function macroexpand($ast, $env) { function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -87,12 +87,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } $ast = $ast[2]; $env = $let_env; @@ -105,7 +105,7 @@ function MAL_EVAL($ast, $env) { case "defmacro!": $func = MAL_EVAL($ast[2], $env); $func->ismacro = true; - return $env->set($ast[1]->value, $func); + return $env->set($ast[1], $func); case "macroexpand": return macroexpand($ast[1], $env); case "try*": @@ -172,19 +172,18 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } -$repl_env->set('eval', _function(function($ast) { +$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('*ARGV*', $_argv); +$repl_env->set(_symbol('*ARGV*'), $_argv); // core.mal: defined using the language itself -rep("(def! *host-language* \"php\")"); rep("(def! not (fn* (a) (if a false true)))"); rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"); @@ -196,7 +195,6 @@ if (count($argv) > 1) { } // repl loop -rep("(println (str \"Mal [\" *host-language* \"]\"))"); do { try { $line = mal_readline("user> "); diff --git a/php/stepA_interop.php b/php/stepA_interop.php index f38656f..8c67c66 100644 --- a/php/stepA_interop.php +++ b/php/stepA_interop.php @@ -35,13 +35,13 @@ function quasiquote($ast) { function is_macro_call($ast, $env) { return is_pair($ast) && _symbol_Q($ast[0]) && - $env->find($ast[0]->value) && - $env->get($ast[0]->value)->ismacro; + $env->find($ast[0]) && + $env->get($ast[0])->ismacro; } function macroexpand($ast, $env) { while (is_macro_call($ast, $env)) { - $mac = $env->get($ast[0]->value); + $mac = $env->get($ast[0]); $args = array_slice($ast->getArrayCopy(),1); $ast = $mac->apply($args); } @@ -50,7 +50,7 @@ function macroexpand($ast, $env) { function eval_ast($ast, $env) { if (_symbol_Q($ast)) { - return $env->get($ast->value); + return $env->get($ast); } elseif (_sequential_Q($ast)) { if (_list_Q($ast)) { $el = _list(); @@ -87,12 +87,12 @@ function MAL_EVAL($ast, $env) { switch ($a0v) { case "def!": $res = MAL_EVAL($ast[2], $env); - return $env->set($ast[1]->value, $res); + return $env->set($ast[1], $res); case "let*": $a1 = $ast[1]; $let_env = new Env($env); for ($i=0; $i < count($a1); $i+=2) { - $let_env->set($a1[$i]->value, MAL_EVAL($a1[$i+1], $let_env)); + $let_env->set($a1[$i], MAL_EVAL($a1[$i+1], $let_env)); } $ast = $ast[2]; $env = $let_env; @@ -105,7 +105,7 @@ function MAL_EVAL($ast, $env) { case "defmacro!": $func = MAL_EVAL($ast[2], $env); $func->ismacro = true; - return $env->set($ast[1]->value, $func); + return $env->set($ast[1], $func); case "macroexpand": return macroexpand($ast[1], $env); case "php*": @@ -174,16 +174,16 @@ function rep($str) { // core.php: defined using PHP foreach ($core_ns as $k=>$v) { - $repl_env->set($k, _function($v)); + $repl_env->set(_symbol($k), _function($v)); } -$repl_env->set('eval', _function(function($ast) { +$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('*ARGV*', $_argv); +$repl_env->set(_symbol('*ARGV*'), $_argv); // core.mal: defined using the language itself rep("(def! *host-language* \"php\")"); diff --git a/php/types.php b/php/types.php index e3df3ac..fa87197 100644 --- a/php/types.php +++ b/php/types.php @@ -53,6 +53,13 @@ class SymbolClass { function _symbol($name) { return new SymbolClass($name); } function _symbol_Q($obj) { return ($obj instanceof SymbolClass); } +// Keywords +function _keyword($name) { return chr(0x7f).$name; } +function _keyword_Q($obj) { + return is_string($obj) && strpos($obj, chr(0x7f)) === 0; +} + + // Functions class FunctionClass { |
