diff options
| author | Joel Martin <github@martintribe.org> | 2015-03-02 21:33:10 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-03-02 21:33:10 -0600 |
| commit | 835fb7d8b06e2b44792a97ac89994658bf6d00af (patch) | |
| tree | 578f67726ab9e3ce5fcbc50220e9761a66c5ddf1 /php | |
| parent | 6b72e6078a7d505ecf9d711eb4a16fc4dfac36b6 (diff) | |
| parent | 8a98ef9a3f3a6b6d05d02dc305a0c886c907e0f3 (diff) | |
| download | mal-835fb7d8b06e2b44792a97ac89994658bf6d00af.tar.gz mal-835fb7d8b06e2b44792a97ac89994658bf6d00af.zip | |
Merge branch 'master' into gh-pages
Conflicts:
.gitignore
Diffstat (limited to 'php')
| -rw-r--r-- | php/Makefile | 2 | ||||
| -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 (renamed from php/stepA_more.php) | 24 | ||||
| -rw-r--r-- | php/stepA_mal.php (renamed from php/step9_interop.php) | 54 | ||||
| -rw-r--r-- | php/tests/stepA_mal.mal | 25 | ||||
| -rw-r--r-- | php/types.php | 7 |
15 files changed, 139 insertions, 69 deletions
diff --git a/php/Makefile b/php/Makefile index 9b91421..659e89c 100644 --- a/php/Makefile +++ b/php/Makefile @@ -2,7 +2,7 @@ TESTS = SOURCES_BASE = readline.php types.php reader.php printer.php -SOURCES_LISP = env.php core.php stepA_more.php +SOURCES_LISP = env.php core.php stepA_mal.php SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) .PHONY: stats tests $(TESTS) 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/stepA_more.php b/php/step9_try.php index f38656f..0470763 100644 --- a/php/stepA_more.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,11 +105,9 @@ 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*": - return eval($ast[1]); case "try*": $a1 = $ast[1]; $a2 = $ast[2]; @@ -174,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)))))))"); @@ -198,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/step9_interop.php b/php/stepA_mal.php index d4a59c7..1dc3b04 100644 --- a/php/step9_interop.php +++ b/php/stepA_mal.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,11 +105,41 @@ 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*": - return eval($ast[1]); + $res = eval($ast[1]); + switch (gettype($res)) { + case "array": + if ($res !== array_values($res)) { + $new_res = _hash_map(); + $new_res->exchangeArray($res); + return $new_res; + } else { + return call_user_func_array('_list', $res); + } + default: + return $res; + } + case "try*": + $a1 = $ast[1]; + $a2 = $ast[2]; + if ($a2[0]->value === "catch*") { + try { + return MAL_EVAL($a1, $env); + } catch (Error $e) { + $catch_env = new Env($env, array($a2[1]), + array($e->obj)); + return MAL_EVAL($a2[2], $catch_env); + } catch (Exception $e) { + $catch_env = new Env($env, array($a2[1]), + array($e->getMessage())); + return MAL_EVAL($a2[2], $catch_env); + } + } else { + return MAL_EVAL($a1, $env); + } case "do": eval_ast($ast->slice(1, -1), $env); $ast = $ast[count($ast)-1]; @@ -156,18 +186,19 @@ 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)))))))"); @@ -179,6 +210,7 @@ if (count($argv) > 1) { } // repl loop +rep("(println (str \"Mal [\" *host-language* \"]\"))"); do { try { $line = mal_readline("user> "); diff --git a/php/tests/stepA_mal.mal b/php/tests/stepA_mal.mal new file mode 100644 index 0000000..15f8a94 --- /dev/null +++ b/php/tests/stepA_mal.mal @@ -0,0 +1,25 @@ +;; Testing basic php interop + +(php* "return 7;") +;=>7 + +(php* "return '7';") +;=>"7" + +(php* "return array(7,8,9);") +;=>(7 8 9) + +(php* "return array(\"abc\" => 789);") +;=>{"abc" 789} + +(php* "print \"hello\n\";") +; hello +;=>nil + +(php* "global $foo; $foo=8;") +(php* "global $foo; return $foo;") +;=>8 + +(php* "global $f; $f = function($v) { return 1+$v; };") +(php* "global $f; return array_map($f, array(1,2,3));") +;=>(2 3 4) 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 { |
