aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-09 23:58:27 -0500
committerJoel Martin <github@martintribe.org>2014-04-09 23:58:27 -0500
commita34b02006527d28db5df5c6553be804770b81f79 (patch)
tree526fe400e5a8c34b32a3d93439197db09c7f84ad
parentedc3b0640f1b773e185550448e2086279f7b1a7f (diff)
downloadmal-a34b02006527d28db5df5c6553be804770b81f79.tar.gz
mal-a34b02006527d28db5df5c6553be804770b81f79.zip
Fix metadata on functions.
- Don't use metadata to store ast, env, params data. - In Clojure, store metadata on the :meta key of the real metadata. This also allows using any datatype as metadata.
-rw-r--r--clojure/src/core.clj14
-rw-r--r--clojure/src/step0_repl.clj5
-rw-r--r--clojure/src/step1_read_print.clj2
-rw-r--r--clojure/src/step2_eval.clj2
-rw-r--r--clojure/src/step3_env.clj2
-rw-r--r--clojure/src/step4_if_fn_do.clj2
-rw-r--r--clojure/src/step5_tco.clj13
-rw-r--r--clojure/src/step6_file.clj11
-rw-r--r--clojure/src/step7_quote.clj11
-rw-r--r--clojure/src/step8_macros.clj11
-rw-r--r--clojure/src/step9_interop.clj11
-rw-r--r--clojure/src/stepA_more.clj11
-rw-r--r--docs/TODO5
-rw-r--r--js/step5_tco.js6
-rw-r--r--js/step6_file.js6
-rw-r--r--js/step7_quote.js6
-rw-r--r--js/step8_macros.js6
-rw-r--r--js/step9_interop.js6
-rw-r--r--js/stepA_more.js6
-rw-r--r--js/types.js14
-rw-r--r--php/step5_tco.php8
-rw-r--r--php/step6_file.php8
-rw-r--r--php/step7_quote.php8
-rw-r--r--php/step8_macros.php8
-rw-r--r--php/step9_interop.php8
-rw-r--r--php/stepA_more.php8
-rw-r--r--php/types.php25
-rw-r--r--ps/core.ps2
-rw-r--r--python/core.py5
-rw-r--r--python/mal_types.py15
-rw-r--r--python/step5_tco.py7
-rw-r--r--python/step6_file.py7
-rw-r--r--python/step7_quote.py7
-rw-r--r--python/step8_macros.py7
-rw-r--r--python/step9_interop.py7
-rw-r--r--python/stepA_more.py7
-rw-r--r--tests/stepA_more.mal37
37 files changed, 184 insertions, 140 deletions
diff --git a/clojure/src/core.clj b/clojure/src/core.clj
index 23dfc55..27599c0 100644
--- a/clojure/src/core.clj
+++ b/clojure/src/core.clj
@@ -4,6 +4,16 @@
(defn mal_throw [obj]
(throw (ex-info "mal exception" {:data obj})))
+;; Metadata
+;; - store metadata at :meta key of the real metadata
+(defn mal_with_meta [obj m]
+ (let [new-meta (assoc (meta obj) :meta m)]
+ (with-meta obj new-meta)))
+
+(defn mal_meta [obj]
+ (:meta (meta obj)))
+
+
;; Atoms
(defn atom? [atm]
(= (type atm) clojure.lang.Atom))
@@ -54,8 +64,8 @@
['apply apply]
['map #(doall (map %1 %2))]
- ['with-meta with-meta]
- ['meta meta]
+ ['with-meta mal_with_meta]
+ ['meta mal_meta]
['atom atom]
['atom? atom?]
['deref deref]
diff --git a/clojure/src/step0_repl.clj b/clojure/src/step0_repl.clj
index 7a050c7..f6201dd 100644
--- a/clojure/src/step0_repl.clj
+++ b/clojure/src/step0_repl.clj
@@ -12,13 +12,12 @@
(eval (read-string ast)))
;; print
-(defn PRINT [exp]
- exp)
+(defn PRINT [exp] exp)
;; repl
(defn rep [strng] (PRINT (EVAL (READ strng), {})))
-(defn -main [& args]
+(defn -main [& args]
(loop []
(let [line (readline/readline "user> ")]
(when line
diff --git a/clojure/src/step1_read_print.clj b/clojure/src/step1_read_print.clj
index 31b2ac6..f15131a 100644
--- a/clojure/src/step1_read_print.clj
+++ b/clojure/src/step1_read_print.clj
@@ -19,7 +19,7 @@
;; repl
(defn rep
[strng]
- (PRINT (EVAL (READ strng), {})))
+ (PRINT (EVAL (READ strng) {})))
(defn -main [& args]
(loop []
diff --git a/clojure/src/step2_eval.clj b/clojure/src/step2_eval.clj
index 581bf3f..c34a1ae 100644
--- a/clojure/src/step2_eval.clj
+++ b/clojure/src/step2_eval.clj
@@ -46,7 +46,7 @@
'/ /})
(defn rep
[strng]
- (PRINT (EVAL (READ strng), repl-env)))
+ (PRINT (EVAL (READ strng) repl-env)))
(defn -main [& args]
(loop []
diff --git a/clojure/src/step3_env.clj b/clojure/src/step3_env.clj
index 449bf79..7358b49 100644
--- a/clojure/src/step3_env.clj
+++ b/clojure/src/step3_env.clj
@@ -55,7 +55,7 @@
(def repl-env (env/env))
(defn rep
[strng]
- (PRINT (EVAL (READ strng), repl-env)))
+ (PRINT (EVAL (READ strng) repl-env)))
(defn _ref [k,v] (env/env-set repl-env k v))
(_ref '+ +)
diff --git a/clojure/src/step4_if_fn_do.clj b/clojure/src/step4_if_fn_do.clj
index b36f482..d332a14 100644
--- a/clojure/src/step4_if_fn_do.clj
+++ b/clojure/src/step4_if_fn_do.clj
@@ -71,7 +71,7 @@
(def repl-env (env/env))
(defn rep
[strng]
- (PRINT (EVAL (READ strng), repl-env)))
+ (PRINT (EVAL (READ strng) repl-env)))
(defn _ref [k,v] (env/env-set repl-env k v))
diff --git a/clojure/src/step5_tco.clj b/clojure/src/step5_tco.clj
index 7739029..f4f0107 100644
--- a/clojure/src/step5_tco.clj
+++ b/clojure/src/step5_tco.clj
@@ -58,11 +58,12 @@
(recur a2 env)))
'fn*
- ^{:expression a2
- :environment env
- :parameters a1}
- (fn [& args]
- (EVAL a2 (env/env env a1 args)))
+ (with-meta
+ (fn [& args]
+ (EVAL a2 (env/env env a1 args)))
+ {:expression a2
+ :environment env
+ :parameters a1})
;; apply
(let [el (eval-ast ast env)
@@ -80,7 +81,7 @@
(def repl-env (env/env))
(defn rep
[strng]
- (PRINT (EVAL (READ strng), repl-env)))
+ (PRINT (EVAL (READ strng) repl-env)))
(defn _ref [k,v] (env/env-set repl-env k v))
diff --git a/clojure/src/step6_file.clj b/clojure/src/step6_file.clj
index a65b741..46bab16 100644
--- a/clojure/src/step6_file.clj
+++ b/clojure/src/step6_file.clj
@@ -58,11 +58,12 @@
(recur a2 env)))
'fn*
- ^{:expression a2
- :environment env
- :parameters a1}
- (fn [& args]
- (EVAL a2 (env/env env a1 args)))
+ (with-meta
+ (fn [& args]
+ (EVAL a2 (env/env env a1 args)))
+ {:expression a2
+ :environment env
+ :parameters a1})
;; apply
(let [el (eval-ast ast env)
diff --git a/clojure/src/step7_quote.clj b/clojure/src/step7_quote.clj
index e68a4cc..5e58e42 100644
--- a/clojure/src/step7_quote.clj
+++ b/clojure/src/step7_quote.clj
@@ -81,11 +81,12 @@
(recur a2 env)))
'fn*
- ^{:expression a2
- :environment env
- :parameters a1}
- (fn [& args]
- (EVAL a2 (env/env env a1 args)))
+ (with-meta
+ (fn [& args]
+ (EVAL a2 (env/env env a1 args)))
+ {:expression a2
+ :environment env
+ :parameters a1})
;; apply
(let [el (eval-ast ast env)
diff --git a/clojure/src/step8_macros.clj b/clojure/src/step8_macros.clj
index ed5638b..605e9d6 100644
--- a/clojure/src/step8_macros.clj
+++ b/clojure/src/step8_macros.clj
@@ -107,11 +107,12 @@
(recur a2 env)))
'fn*
- ^{:expression a2
- :environment env
- :parameters a1}
- (fn [& args]
- (EVAL a2 (env/env env a1 args)))
+ (with-meta
+ (fn [& args]
+ (EVAL a2 (env/env env a1 args)))
+ {:expression a2
+ :environment env
+ :parameters a1})
;; apply
(let [el (eval-ast ast env)
diff --git a/clojure/src/step9_interop.clj b/clojure/src/step9_interop.clj
index da37574..2fae3ca 100644
--- a/clojure/src/step9_interop.clj
+++ b/clojure/src/step9_interop.clj
@@ -110,11 +110,12 @@
(recur a2 env)))
'fn*
- ^{:expression a2
- :environment env
- :parameters a1}
- (fn [& args]
- (EVAL a2 (env/env env a1 args)))
+ (with-meta
+ (fn [& args]
+ (EVAL a2 (env/env env a1 args)))
+ {:expression a2
+ :environment env
+ :parameters a1})
;; apply
(let [el (eval-ast ast env)
diff --git a/clojure/src/stepA_more.clj b/clojure/src/stepA_more.clj
index 77b8cd7..30eb8a6 100644
--- a/clojure/src/stepA_more.clj
+++ b/clojure/src/stepA_more.clj
@@ -124,11 +124,12 @@
(recur a2 env)))
'fn*
- ^{:expression a2
- :environment env
- :parameters a1}
- (fn [& args]
- (EVAL a2 (env/env env a1 args)))
+ (with-meta
+ (fn [& args]
+ (EVAL a2 (env/env env a1 args)))
+ {:expression a2
+ :environment env
+ :parameters a1})
;; apply
(let [el (eval-ast ast env)
diff --git a/docs/TODO b/docs/TODO
index 6ff581c..3e068d7 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -80,10 +80,11 @@ Future Implementations:
* JavaScript
* Java
* PHP
- - C#
+ * C#
* Python
- C++
- Ruby
+ - http://www.ruby-doc.org/stdlib-1.9.3/libdoc/readline/rdoc/Readline.html
* C
- Objective-C
- Perl
@@ -116,8 +117,6 @@ Future Implementations:
- https://github.com/tpope/timl
- Common Lisp
- Rust
-
- - Tier 4
- M (OpenM/MUMPS)
- Factor (Stack-based)
diff --git a/js/step5_tco.js b/js/step5_tco.js
index d61e243..9ba7a98 100644
--- a/js/step5_tco.js
+++ b/js/step5_tco.js
@@ -69,9 +69,9 @@ function _EVAL(ast, env) {
return types._function(EVAL, Env, a2, env, a1);
default:
var el = eval_ast(ast, env), f = el[0], meta = f.__meta__;
- if (meta && meta.exp) {
- ast = meta.exp;
- env = new Env(meta.env, meta.params, el.slice(1));
+ if (f.__ast__) {
+ ast = f.__ast__;
+ env = f.__gen_env__(el.slice(1));
} else {
return f.apply(f, el.slice(1));
}
diff --git a/js/step6_file.js b/js/step6_file.js
index 7bbb1b4..ab4ba2f 100644
--- a/js/step6_file.js
+++ b/js/step6_file.js
@@ -69,9 +69,9 @@ function _EVAL(ast, env) {
return types._function(EVAL, Env, a2, env, a1);
default:
var el = eval_ast(ast, env), f = el[0], meta = f.__meta__;
- if (meta && meta.exp) {
- ast = meta.exp;
- env = new Env(meta.env, meta.params, el.slice(1));
+ if (f.__ast__) {
+ ast = f.__ast__;
+ env = f.__gen_env__(el.slice(1));
} else {
return f.apply(f, el.slice(1));
}
diff --git a/js/step7_quote.js b/js/step7_quote.js
index 60ae0e8..3125083 100644
--- a/js/step7_quote.js
+++ b/js/step7_quote.js
@@ -89,9 +89,9 @@ function _EVAL(ast, env) {
return types._function(EVAL, Env, a2, env, a1);
default:
var el = eval_ast(ast, env), f = el[0], meta = f.__meta__;
- if (meta && meta.exp) {
- ast = meta.exp;
- env = new Env(meta.env, meta.params, el.slice(1));
+ if (f.__ast__) {
+ ast = f.__ast__;
+ env = f.__gen_env__(el.slice(1));
} else {
return f.apply(f, el.slice(1));
}
diff --git a/js/step8_macros.js b/js/step8_macros.js
index 5e39b5b..190cadc 100644
--- a/js/step8_macros.js
+++ b/js/step8_macros.js
@@ -113,9 +113,9 @@ function _EVAL(ast, env) {
return types._function(EVAL, Env, a2, env, a1);
default:
var el = eval_ast(ast, env), f = el[0], meta = f.__meta__;
- if (meta && meta.exp) {
- ast = meta.exp;
- env = new Env(meta.env, meta.params, el.slice(1));
+ if (f.__ast__) {
+ ast = f.__ast__;
+ env = f.__gen_env__(el.slice(1));
} else {
return f.apply(f, el.slice(1));
}
diff --git a/js/step9_interop.js b/js/step9_interop.js
index 8aa8281..0fd7044 100644
--- a/js/step9_interop.js
+++ b/js/step9_interop.js
@@ -119,9 +119,9 @@ function _EVAL(ast, env) {
return types._function(EVAL, Env, a2, env, a1);
default:
var el = eval_ast(ast, env), f = el[0], meta = f.__meta__;
- if (meta && meta.exp) {
- ast = meta.exp;
- env = new Env(meta.env, meta.params, el.slice(1));
+ if (f.__ast__) {
+ ast = f.__ast__;
+ env = f.__gen_env__(el.slice(1));
} else {
return f.apply(f, el.slice(1));
}
diff --git a/js/stepA_more.js b/js/stepA_more.js
index c37668a..6a2b949 100644
--- a/js/stepA_more.js
+++ b/js/stepA_more.js
@@ -130,9 +130,9 @@ function _EVAL(ast, env) {
return types._function(EVAL, Env, a2, env, a1);
default:
var el = eval_ast(ast, env), f = el[0], meta = f.__meta__;
- if (meta && meta.exp) {
- ast = meta.exp;
- env = new Env(meta.env, meta.params, el.slice(1));
+ if (f.__ast__) {
+ ast = f.__ast__;
+ env = f.__gen_env__(el.slice(1));
} else {
return f.apply(f, el.slice(1));
}
diff --git a/js/types.js b/js/types.js
index 6d7de0f..889e154 100644
--- a/js/types.js
+++ b/js/types.js
@@ -100,14 +100,14 @@ function _symbol_Q(obj) { return obj instanceof Symbol; }
// Functions
-function _function(Eval, Env, exp, env, params) {
- var f = function() {
- // TODO: figure out why this throws with 'and' macro
- //throw new Error("Attempt to invoke mal function directly");
- return Eval(exp, new Env(env, params, arguments));
+function _function(Eval, Env, ast, env, params) {
+ var fn = function() {
+ return Eval(ast, new Env(env, params, arguments));
};
- f.__meta__ = {exp: exp, env: env, params: params};
- return f;
+ fn.__meta__ = null;
+ fn.__ast__ = ast;
+ fn.__gen_env__ = function(args) { return new Env(env, params, args); };
+ return fn;
}
function _function_Q(obj) { return typeof obj == "function"; }
Function.prototype.clone = function() {
diff --git a/php/step5_tco.php b/php/step5_tco.php
index 0bf55ee..cd4787e 100644
--- a/php/step5_tco.php
+++ b/php/step5_tco.php
@@ -72,16 +72,14 @@ function MAL_EVAL($ast, $env) {
break;
case "fn*":
return _function('MAL_EVAL', 'native',
- _hash_map('exp', $ast[2],
- 'env', $env,
- 'params', $ast[1]));
+ $ast[2], $env, $ast[1]);
default:
$el = eval_ast($ast, $env);
$f = $el[0];
$args = array_slice($el->getArrayCopy(), 1);
if ($f->type === 'native') {
- $ast = $f->meta['exp'];
- $env = new Env($f->meta['env'], $f->meta['params'], $args);
+ $ast = $f->ast;
+ $env = $f->gen_env($args);
} else {
return $f->apply($args);
}
diff --git a/php/step6_file.php b/php/step6_file.php
index 965ff88..95b3982 100644
--- a/php/step6_file.php
+++ b/php/step6_file.php
@@ -72,16 +72,14 @@ function MAL_EVAL($ast, $env) {
break;
case "fn*":
return _function('MAL_EVAL', 'native',
- _hash_map('exp', $ast[2],
- 'env', $env,
- 'params', $ast[1]));
+ $ast[2], $env, $ast[1]);
default:
$el = eval_ast($ast, $env);
$f = $el[0];
$args = array_slice($el->getArrayCopy(), 1);
if ($f->type === 'native') {
- $ast = $f->meta['exp'];
- $env = new Env($f->meta['env'], $f->meta['params'], $args);
+ $ast = $f->ast;
+ $env = $f->gen_env($args);
} else {
return $f->apply($args);
}
diff --git a/php/step7_quote.php b/php/step7_quote.php
index 450f2b5..8c407c6 100644
--- a/php/step7_quote.php
+++ b/php/step7_quote.php
@@ -95,16 +95,14 @@ function MAL_EVAL($ast, $env) {
break;
case "fn*":
return _function('MAL_EVAL', 'native',
- _hash_map('exp', $ast[2],
- 'env', $env,
- 'params', $ast[1]));
+ $ast[2], $env, $ast[1]);
default:
$el = eval_ast($ast, $env);
$f = $el[0];
$args = array_slice($el->getArrayCopy(), 1);
if ($f->type === 'native') {
- $ast = $f->meta['exp'];
- $env = new Env($f->meta['env'], $f->meta['params'], $args);
+ $ast = $f->ast;
+ $env = $f->gen_env($args);
} else {
return $f->apply($args);
}
diff --git a/php/step8_macros.php b/php/step8_macros.php
index 3dea855..c6c7173 100644
--- a/php/step8_macros.php
+++ b/php/step8_macros.php
@@ -120,16 +120,14 @@ function MAL_EVAL($ast, $env) {
break;
case "fn*":
return _function('MAL_EVAL', 'native',
- _hash_map('exp', $ast[2],
- 'env', $env,
- 'params', $ast[1]));
+ $ast[2], $env, $ast[1]);
default:
$el = eval_ast($ast, $env);
$f = $el[0];
$args = array_slice($el->getArrayCopy(), 1);
if ($f->type === 'native') {
- $ast = $f->meta['exp'];
- $env = new Env($f->meta['env'], $f->meta['params'], $args);
+ $ast = $f->ast;
+ $env = $f->gen_env($args);
} else {
return $f->apply($args);
}
diff --git a/php/step9_interop.php b/php/step9_interop.php
index a699109..3debdc4 100644
--- a/php/step9_interop.php
+++ b/php/step9_interop.php
@@ -122,16 +122,14 @@ function MAL_EVAL($ast, $env) {
break;
case "fn*":
return _function('MAL_EVAL', 'native',
- _hash_map('exp', $ast[2],
- 'env', $env,
- 'params', $ast[1]));
+ $ast[2], $env, $ast[1]);
default:
$el = eval_ast($ast, $env);
$f = $el[0];
$args = array_slice($el->getArrayCopy(), 1);
if ($f->type === 'native') {
- $ast = $f->meta['exp'];
- $env = new Env($f->meta['env'], $f->meta['params'], $args);
+ $ast = $f->ast;
+ $env = $f->gen_env($args);
} else {
return $f->apply($args);
}
diff --git a/php/stepA_more.php b/php/stepA_more.php
index 4b8a270..7478ee8 100644
--- a/php/stepA_more.php
+++ b/php/stepA_more.php
@@ -140,16 +140,14 @@ function MAL_EVAL($ast, $env) {
break;
case "fn*":
return _function('MAL_EVAL', 'native',
- _hash_map('exp', $ast[2],
- 'env', $env,
- 'params', $ast[1]));
+ $ast[2], $env, $ast[1]);
default:
$el = eval_ast($ast, $env);
$f = $el[0];
$args = array_slice($el->getArrayCopy(), 1);
if ($f->type === 'native') {
- $ast = $f->meta['exp'];
- $env = new Env($f->meta['env'], $f->meta['params'], $args);
+ $ast = $f->ast;
+ $env = $f->gen_env($args);
} else {
return $f->apply($args);
}
diff --git a/php/types.php b/php/types.php
index fa57266..e3df3ac 100644
--- a/php/types.php
+++ b/php/types.php
@@ -59,31 +59,42 @@ class FunctionClass {
public $func = NULL;
public $type = 'native'; // 'native' or 'platform'
public $meta = NULL;
+ public $ast = NULL;
+ public $env = NULL;
+ public $params = NULL;
public $ismacro = False;
- public function __construct($func, $type, $meta=NULL, $ismacro=False) {
+ public function __construct($func, $type,
+ $ast, $env, $params, $ismacro=False) {
$this->func = $func;
$this->type = $type;
- $this->meta = $meta;
+ $this->ast = $ast;
+ #print_r($ast);
+ $this->env = $env;
+ $this->params = $params;
$this->ismacro = $ismacro;
}
public function __invoke() {
$args = func_get_args();
if ($this->type === 'native') {
- $fn_env = new Env($this->meta['env'],
- $this->meta['params'], $args);
+ $fn_env = new Env($this->env,
+ $this->params, $args);
$evalf = $this->func;
- return $evalf($this->meta['exp'], $fn_env);
+ return $evalf($this->ast, $fn_env);
} else {
return call_user_func_array($this->func, $args);
}
}
+ public function gen_env($args) {
+ return new Env($this->env, $this->params, $args);
+ }
public function apply($args) {
return call_user_func_array(array(&$this, '__invoke'),$args);
}
}
-function _function($func, $type='platform', $meta=NULL, $ismacro=False) {
- return new FunctionClass($func, $type, $meta, $ismacro);
+function _function($func, $type='platform',
+ $ast=NULL, $env=NULL, $params=NULL, $ismacro=False) {
+ return new FunctionClass($func, $type, $ast, $env, $params, $ismacro);
}
function _function_Q($obj) { return $obj instanceof FunctionClass; }
diff --git a/ps/core.ps b/ps/core.ps
index 35f2b19..afda426 100644
--- a/ps/core.ps
+++ b/ps/core.ps
@@ -172,7 +172,7 @@ end } def
% [obj] -> meta -> meta
/meta {
- 0 _nth /meta get
+ 0 _nth dup /meta known { /meta get }{ null } ifelse
} def
diff --git a/python/core.py b/python/core.py
index 28d9c5e..5e2ef75 100644
--- a/python/core.py
+++ b/python/core.py
@@ -85,7 +85,10 @@ def mapf(f, lst): return List(map(f, lst))
# Metadata functions
def with_meta(obj, meta):
- new_obj = copy.copy(obj)
+ if type(obj) == type(lambda x:x):
+ new_obj = obj.__copy__()
+ else:
+ new_obj = copy.copy(obj)
new_obj.__meta__ = meta
return new_obj
diff --git a/python/mal_types.py b/python/mal_types.py
index 15e4b6b..74409c9 100644
--- a/python/mal_types.py
+++ b/python/mal_types.py
@@ -38,11 +38,16 @@ def _symbol(str): return Symbol(str)
def _symbol_Q(exp): return type(exp) == Symbol
# Functions
-def _function(Eval, Env, exp, env, params):
- def f(*args):
- return Eval(exp, Env(env, params, args))
- f.__meta__ = {"exp": exp, "env": env, "params": params}
- return f
+def _function(Eval, Env, ast, env, params):
+ def gen_fn():
+ def fn(*args):
+ return Eval(ast, Env(env, params, args))
+ fn.__meta__ = None
+ fn.__ast__ = ast
+ fn.__gen_env__ = lambda args: Env(env, params, args)
+ fn.__copy__ = gen_fn
+ return fn
+ return gen_fn()
def _function_Q(f): return type(f) == type(function_Q)
# lists
diff --git a/python/step5_tco.py b/python/step5_tco.py
index 4335a96..d9d34bc 100644
--- a/python/step5_tco.py
+++ b/python/step5_tco.py
@@ -65,10 +65,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
diff --git a/python/step6_file.py b/python/step6_file.py
index 9e0b8cd..f3847d2 100644
--- a/python/step6_file.py
+++ b/python/step6_file.py
@@ -65,10 +65,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
diff --git a/python/step7_quote.py b/python/step7_quote.py
index 3ed6965..f57dc0a 100644
--- a/python/step7_quote.py
+++ b/python/step7_quote.py
@@ -87,10 +87,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
diff --git a/python/step8_macros.py b/python/step8_macros.py
index 6e2bd45..5d9151a 100644
--- a/python/step8_macros.py
+++ b/python/step8_macros.py
@@ -107,10 +107,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
diff --git a/python/step9_interop.py b/python/step9_interop.py
index 66a8c50..521a3c2 100644
--- a/python/step9_interop.py
+++ b/python/step9_interop.py
@@ -116,10 +116,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
diff --git a/python/stepA_more.py b/python/stepA_more.py
index 7c6a5da..21c1641 100644
--- a/python/stepA_more.py
+++ b/python/stepA_more.py
@@ -127,10 +127,9 @@ def EVAL(ast, env):
else:
el = eval_ast(ast, env)
f = el[0]
- if hasattr(f, '__meta__') and f.__meta__.has_key("exp"):
- m = f.__meta__
- ast = m['exp']
- env = Env(m['env'], m['params'], el[1:])
+ if hasattr(f, '__ast__'):
+ ast = f.__ast__
+ env = f.__gen_env__(el[1:])
else:
return f(*el[1:])
diff --git a/tests/stepA_more.mal b/tests/stepA_more.mal
index 456a092..54faa19 100644
--- a/tests/stepA_more.mal
+++ b/tests/stepA_more.mal
@@ -226,12 +226,18 @@
(meta [1 2 3])
;=>nil
+(meta (fn* (a) a))
+;=>nil
+
(with-meta [1 2 3] {"a" 1})
;=>[1 2 3]
(meta (with-meta [1 2 3] {"a" 1}))
;=>{"a" 1}
+(meta (with-meta [1 2 3] "abc"))
+;=>"abc"
+
(meta (with-meta (list 1 2 3) {"a" 1}))
;=>{"a" 1}
@@ -242,16 +248,23 @@
;;;(meta (with-meta (atom 7) {"a" 1}))
;;;;=>{"a" 1}
-(def! lst (with-meta [4 5 6] {"b" 2}))
+(def! l-wm (with-meta [4 5 6] {"b" 2}))
;=>[4 5 6]
+(meta l-wm)
+;=>{"b" 2}
+
+(meta (with-meta l-wm {"new_meta" 123}))
+;=>{"new_meta" 123}
+(meta l-wm)
+;=>{"b" 2}
+
(def! f-wm (with-meta (fn* [a] (+ 1 a)) {"abc" 1}))
(meta f-wm)
;=>{"abc" 1}
-(meta (with-meta f-wm "new_meta"))
-;=>"new_meta"
-
+(meta (with-meta f-wm {"new_meta" 123}))
+;=>{"new_meta" 123}
(meta f-wm)
;=>{"abc" 1}
@@ -260,6 +273,22 @@
(meta f-wm2)
;=>{"abc" 1}
+;;
+;; Make sure closures and metadata co-exist
+(def! gen-plusX (fn* (x) (with-meta (fn* (b) (+ x b)) {"meta" 1})))
+(def! plus7 (gen-plusX 7))
+(def! plus8 (gen-plusX 8))
+(plus7 8)
+;=>15
+(meta plus7)
+;=>{"meta" 1}
+(meta plus8)
+;=>{"meta" 1}
+(meta (with-meta plus7 {"meta" 2}))
+;=>{"meta" 2}
+(meta plus8)
+;=>{"meta" 1}
+
;;
;; Testing atoms