aboutsummaryrefslogtreecommitdiff
path: root/php
diff options
context:
space:
mode:
Diffstat (limited to 'php')
-rw-r--r--php/core.php8
-rw-r--r--php/env.php8
-rw-r--r--php/printer.php4
-rw-r--r--php/reader.php2
-rw-r--r--php/step3_env.php14
-rw-r--r--php/step4_if_fn_do.php8
-rw-r--r--php/step5_tco.php8
-rw-r--r--php/step6_file.php12
-rw-r--r--php/step7_quote.php12
-rw-r--r--php/step8_macros.php20
-rw-r--r--php/step9_try.php22
-rw-r--r--php/stepA_interop.php20
-rw-r--r--php/types.php7
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 {