Skip to content

Commit

Permalink
Fix metadata on functions.
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
kanaka committed Apr 10, 2014
1 parent edc3b06 commit a34b020
Show file tree
Hide file tree
Showing 37 changed files with 183 additions and 139 deletions.
14 changes: 12 additions & 2 deletions clojure/src/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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]
Expand Down
5 changes: 2 additions & 3 deletions clojure/src/step0_repl.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion clojure/src/step1_read_print.clj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
;; repl
(defn rep
[strng]
(PRINT (EVAL (READ strng), {})))
(PRINT (EVAL (READ strng) {})))

(defn -main [& args]
(loop []
Expand Down
2 changes: 1 addition & 1 deletion clojure/src/step2_eval.clj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
'/ /})
(defn rep
[strng]
(PRINT (EVAL (READ strng), repl-env)))
(PRINT (EVAL (READ strng) repl-env)))

(defn -main [& args]
(loop []
Expand Down
2 changes: 1 addition & 1 deletion clojure/src/step3_env.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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 '+ +)
Expand Down
2 changes: 1 addition & 1 deletion clojure/src/step4_if_fn_do.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
13 changes: 7 additions & 6 deletions clojure/src/step5_tco.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))

Expand Down
11 changes: 6 additions & 5 deletions clojure/src/step6_file.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions clojure/src/step7_quote.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions clojure/src/step8_macros.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions clojure/src/step9_interop.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions clojure/src/stepA_more.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions docs/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -116,8 +117,6 @@ Future Implementations:
- https://github.com/tpope/timl
- Common Lisp
- Rust

- Tier 4
- M (OpenM/MUMPS)
- Factor (Stack-based)

Expand Down
6 changes: 3 additions & 3 deletions js/step5_tco.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
6 changes: 3 additions & 3 deletions js/step6_file.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
6 changes: 3 additions & 3 deletions js/step7_quote.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
6 changes: 3 additions & 3 deletions js/step8_macros.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
6 changes: 3 additions & 3 deletions js/step9_interop.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
6 changes: 3 additions & 3 deletions js/stepA_more.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
14 changes: 7 additions & 7 deletions js/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
8 changes: 3 additions & 5 deletions php/step5_tco.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 3 additions & 5 deletions php/step6_file.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 3 additions & 5 deletions php/step7_quote.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 3 additions & 5 deletions php/step8_macros.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit a34b020

Please sign in to comment.