diff options
| author | Joel Martin <github@martintribe.org> | 2014-12-18 20:33:49 -0600 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-09 16:16:50 -0600 |
| commit | b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c (patch) | |
| tree | f4d977ed220e9a3f665cfbf4f68770a81e4c2095 /coffee | |
| parent | aaba249304b184e12e2445ab22d66df1f39a51a5 (diff) | |
| download | mal-b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c.tar.gz mal-b8ee29b22fbaa7a01f2754b4d6dd9af52e02017c.zip | |
All: add keywords.
Also, fix nth and count to match cloure.
Diffstat (limited to 'coffee')
| -rw-r--r-- | coffee/core.coffee | 7 | ||||
| -rw-r--r-- | coffee/env.coffee | 15 | ||||
| -rw-r--r-- | coffee/printer.coffee | 1 | ||||
| -rw-r--r-- | coffee/reader.coffee | 9 | ||||
| -rw-r--r-- | coffee/step3_env.coffee | 14 | ||||
| -rw-r--r-- | coffee/step4_if_fn_do.coffee | 8 | ||||
| -rw-r--r-- | coffee/step5_tco.coffee | 8 | ||||
| -rw-r--r-- | coffee/step6_file.coffee | 14 | ||||
| -rw-r--r-- | coffee/step7_quote.coffee | 14 | ||||
| -rw-r--r-- | coffee/step8_macros.coffee | 20 | ||||
| -rw-r--r-- | coffee/step9_try.coffee | 22 | ||||
| -rw-r--r-- | coffee/stepA_interop.coffee | 20 | ||||
| -rw-r--r-- | coffee/types.coffee | 9 |
13 files changed, 88 insertions, 73 deletions
diff --git a/coffee/core.coffee b/coffee/core.coffee index d01e76f..8bb6958 100644 --- a/coffee/core.coffee +++ b/coffee/core.coffee @@ -32,6 +32,8 @@ exports.ns = { 'false?': types._false_Q, 'symbol': types._symbol, 'symbol?': types._symbol_Q, + 'keyword': types._keyword, + 'keyword?': types._keyword_Q, 'pr-str': (a...) -> a.map((exp) -> _pr_str(exp,true)).join(" "), 'str': (a...) -> a.map((exp) -> _pr_str(exp,false)).join(""), @@ -66,11 +68,12 @@ exports.ns = { 'sequential?': types._sequential_Q, 'cons': (a,b) -> [a].concat(b), 'concat': (a=[],b...) -> a.concat(b...), - 'nth': (a,b) -> if a.length > b then a[b] else null, + 'nth': (a,b) -> if a.length > b then a[b] else + throw new Error "nth: index out of bounds", 'first': (a) -> if a.length > 0 then a[0] else null, 'rest': (a) -> a[1..], 'empty?': (a) -> a.length == 0, - 'count': (a) -> a.length, + 'count': (a) -> if a == null then 0 else a.length, 'apply': (a,b...) -> a(b[0..-2].concat(b[b.length-1])...), 'map': (a,b) -> b.map((x) -> a(x)), 'conj': conj, diff --git a/coffee/env.coffee b/coffee/env.coffee index 667e467..80fbf12 100644 --- a/coffee/env.coffee +++ b/coffee/env.coffee @@ -12,13 +12,20 @@ exports.Env = class Env else @data[b.name] = exprs[i] find: (key) -> - if key of @data then @ + if not types._symbol_Q(key) + throw new Error("env.find key must be symbol") + if key.name of @data then @ else if @outer then @outer.find(key) else null - set: (key, value) -> @data[key] = value + set: (key, value) -> + if not types._symbol_Q(key) + throw new Error("env.set key must be symbol") + @data[key.name] = value get: (key) -> + if not types._symbol_Q(key) + throw new Error("env.get key must be symbol") env = @find(key) - throw new Error("'" + key + "' not found") if !env - env.data[key] + throw new Error("'" + key.name + "' not found") if !env + env.data[key.name] # vim: ts=2:sw=2 diff --git a/coffee/printer.coffee b/coffee/printer.coffee index 7844416..9f56e2e 100644 --- a/coffee/printer.coffee +++ b/coffee/printer.coffee @@ -16,6 +16,7 @@ exports._pr_str = _pr_str = (obj, print_readably=true) -> .replace(/"/g, '\\"') .replace(/\n/g, '\\n')) + '"' else obj + when 'keyword' then ":" + obj.slice(1) when 'symbol' then obj.name when 'nil' then 'nil' when 'atom' then "(atom " + _pr_str(obj.val,_r) + ")" diff --git a/coffee/reader.coffee b/coffee/reader.coffee index 5882b43..83d24d2 100644 --- a/coffee/reader.coffee +++ b/coffee/reader.coffee @@ -1,7 +1,5 @@ types = require "./types.coffee" -[_symbol, _vector, _hash_map] = [types._symbol, - types._vector, - types._hash_map] +_symbol = types._symbol class Reader @@ -28,6 +26,7 @@ read_atom = (rdr) -> token.slice(1, token.length-1) .replace(/\\"/g, '"') .replace(/\\n/g, "\n") + else if token[0] == ':' then types._keyword(token[1..]) else if token == "nil" then null else if token == "true" then true else if token == "false" then false @@ -44,10 +43,10 @@ read_list = (rdr, start='(', end=')') -> ast read_vector = (rdr) -> - _vector(read_list(rdr, '[', ']')...) + types._vector(read_list(rdr, '[', ']')...) read_hash_map = (rdr) -> - _hash_map(read_list(rdr, '{', '}')...) + types._hash_map(read_list(rdr, '{', '}')...) read_form = (rdr) -> token = rdr.peek() diff --git a/coffee/step3_env.coffee b/coffee/step3_env.coffee index a5398e7..1446197 100644 --- a/coffee/step3_env.coffee +++ b/coffee/step3_env.coffee @@ -9,7 +9,7 @@ READ = (str) -> reader.read_str str # eval eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -27,11 +27,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - env.set(a1.name, EVAL(a2, env)) + env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) EVAL(a2, let_env) else [f, args...] = eval_ast ast, env @@ -45,10 +45,10 @@ PRINT = (exp) -> printer._pr_str exp, true repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) -repl_env.set "+", (a,b) -> a+b -repl_env.set "-", (a,b) -> a-b -repl_env.set "*", (a,b) -> a*b -repl_env.set "/", (a,b) -> a/b +repl_env.set types._symbol("+"), (a,b) -> a+b +repl_env.set types._symbol("-"), (a,b) -> a-b +repl_env.set types._symbol("*"), (a,b) -> a*b +repl_env.set types._symbol("/"), (a,b) -> a/b # repl loop while (line = readline.readline("user> ")) != null diff --git a/coffee/step4_if_fn_do.coffee b/coffee/step4_if_fn_do.coffee index 037b58a..ef33478 100644 --- a/coffee/step4_if_fn_do.coffee +++ b/coffee/step4_if_fn_do.coffee @@ -10,7 +10,7 @@ READ = (str) -> reader.read_str str # eval eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -28,11 +28,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - env.set(a1.name, EVAL(a2, env)) + env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) EVAL(a2, let_env) when "do" el = eval_ast(ast[1..], env) @@ -58,7 +58,7 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns +repl_env.set types._symbol(k), v for k,v of core.ns # core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); diff --git a/coffee/step5_tco.coffee b/coffee/step5_tco.coffee index 4003e79..fa5aced 100644 --- a/coffee/step5_tco.coffee +++ b/coffee/step5_tco.coffee @@ -10,7 +10,7 @@ READ = (str) -> reader.read_str str # eval eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -29,11 +29,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - return env.set(a1.name, EVAL(a2, env)) + return env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) ast = a2 env = let_env when "do" @@ -64,7 +64,7 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns +repl_env.set types._symbol(k), v for k,v of core.ns # core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); diff --git a/coffee/step6_file.coffee b/coffee/step6_file.coffee index 449b03e..feafc63 100644 --- a/coffee/step6_file.coffee +++ b/coffee/step6_file.coffee @@ -10,7 +10,7 @@ READ = (str) -> reader.read_str str # eval eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -29,11 +29,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - return env.set(a1.name, EVAL(a2, env)) + return env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) ast = a2 env = let_env when "do" @@ -64,16 +64,16 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns -repl_env.set 'eval', (ast) -> EVAL(ast, repl_env) -repl_env.set '*ARGV*', [] +repl_env.set types._symbol(k), v for k,v of core.ns +repl_env.set types._symbol('eval'), (ast) -> EVAL(ast, repl_env) +repl_env.set types._symbol('*ARGV*'), [] # core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); if process? && process.argv.length > 2 - repl_env.set '*ARGV*', process.argv[3..] + repl_env.set types._symbol('*ARGV*'), process.argv[3..] rep('(load-file "' + process.argv[2] + '")') process.exit 0 diff --git a/coffee/step7_quote.coffee b/coffee/step7_quote.coffee index 404e684..7652a79 100644 --- a/coffee/step7_quote.coffee +++ b/coffee/step7_quote.coffee @@ -22,7 +22,7 @@ quasiquote = (ast) -> eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -41,11 +41,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - return env.set(a1.name, EVAL(a2, env)) + return env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) ast = a2 env = let_env when "quote" @@ -80,16 +80,16 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns -repl_env.set 'eval', (ast) -> EVAL(ast, repl_env) -repl_env.set '*ARGV*', [] +repl_env.set types._symbol(k), v for k,v of core.ns +repl_env.set types._symbol('eval'), (ast) -> EVAL(ast, repl_env) +repl_env.set types._symbol('*ARGV*'), [] # core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"); if process? && process.argv.length > 2 - repl_env.set '*ARGV*', process.argv[3..] + repl_env.set types._symbol('*ARGV*'), process.argv[3..] rep('(load-file "' + process.argv[2] + '")') process.exit 0 diff --git a/coffee/step8_macros.coffee b/coffee/step8_macros.coffee index 39404e7..6150d2e 100644 --- a/coffee/step8_macros.coffee +++ b/coffee/step8_macros.coffee @@ -21,17 +21,17 @@ quasiquote = (ast) -> is_macro_call = (ast, env) -> return types._list_Q(ast) && types._symbol_Q(ast[0]) && - env.find(ast[0].name) && env.get(ast[0].name).__ismacro__ + env.find(ast[0]) && env.get(ast[0]).__ismacro__ macroexpand = (ast, env) -> while is_macro_call(ast, env) - ast = env.get(ast[0].name)(ast[1..]...) + ast = env.get(ast[0])(ast[1..]...) ast eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -53,11 +53,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - return env.set(a1.name, EVAL(a2, env)) + return env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) ast = a2 env = let_env when "quote" @@ -67,7 +67,7 @@ EVAL = (ast, env) -> when "defmacro!" f = EVAL(a2, env) f.__ismacro__ = true - return env.set(a1.name, f) + return env.set(a1, f) when "macroexpand" return macroexpand(a1, env) when "do" @@ -98,9 +98,9 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns -repl_env.set 'eval', (ast) -> EVAL(ast, repl_env) -repl_env.set '*ARGV*', [] +repl_env.set types._symbol(k), v for k,v of core.ns +repl_env.set types._symbol('eval'), (ast) -> EVAL(ast, repl_env) +repl_env.set types._symbol('*ARGV*'), [] # core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))"); @@ -109,7 +109,7 @@ rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if ( rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") if process? && process.argv.length > 2 - repl_env.set '*ARGV*', process.argv[3..] + repl_env.set types._symbol('*ARGV*'), process.argv[3..] rep('(load-file "' + process.argv[2] + '")') process.exit 0 diff --git a/coffee/step9_try.coffee b/coffee/step9_try.coffee index d7919e7..d8f6f43 100644 --- a/coffee/step9_try.coffee +++ b/coffee/step9_try.coffee @@ -21,17 +21,17 @@ quasiquote = (ast) -> is_macro_call = (ast, env) -> return types._list_Q(ast) && types._symbol_Q(ast[0]) && - env.find(ast[0].name) && env.get(ast[0].name).__ismacro__ + env.find(ast[0]) && env.get(ast[0]).__ismacro__ macroexpand = (ast, env) -> while is_macro_call(ast, env) - ast = env.get(ast[0].name)(ast[1..]...) + ast = env.get(ast[0])(ast[1..]...) ast eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -53,11 +53,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - return env.set(a1.name, EVAL(a2, env)) + return env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) ast = a2 env = let_env when "quote" @@ -67,7 +67,7 @@ EVAL = (ast, env) -> when "defmacro!" f = EVAL(a2, env) f.__ismacro__ = true - return env.set(a1.name, f) + return env.set(a1, f) when "macroexpand" return macroexpand(a1, env) when "try*" @@ -106,24 +106,22 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns -repl_env.set 'eval', (ast) -> EVAL(ast, repl_env) -repl_env.set '*ARGV*', [] +repl_env.set types._symbol(k), v for k,v of core.ns +repl_env.set types._symbol('eval'), (ast) -> EVAL(ast, repl_env) +repl_env.set types._symbol('*ARGV*'), [] # core.mal: defined using the language itself -rep("(def! *host-language* \"CoffeeScript\")") 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)))))))") rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") if process? && process.argv.length > 2 - repl_env.set '*ARGV*', process.argv[3..] + repl_env.set types._symbol('*ARGV*'), process.argv[3..] rep('(load-file "' + process.argv[2] + '")') process.exit 0 # repl loop -rep("(println (str \"Mal [\" *host-language* \"]\"))") while (line = readline.readline("user> ")) != null continue if line == "" try diff --git a/coffee/stepA_interop.coffee b/coffee/stepA_interop.coffee index aa9c5cc..751f9ad 100644 --- a/coffee/stepA_interop.coffee +++ b/coffee/stepA_interop.coffee @@ -21,17 +21,17 @@ quasiquote = (ast) -> is_macro_call = (ast, env) -> return types._list_Q(ast) && types._symbol_Q(ast[0]) && - env.find(ast[0].name) && env.get(ast[0].name).__ismacro__ + env.find(ast[0]) && env.get(ast[0]).__ismacro__ macroexpand = (ast, env) -> while is_macro_call(ast, env) - ast = env.get(ast[0].name)(ast[1..]...) + ast = env.get(ast[0])(ast[1..]...) ast eval_ast = (ast, env) -> - if types._symbol_Q(ast) then env.get ast.name + if types._symbol_Q(ast) then env.get ast else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) else if types._vector_Q(ast) types._vector(ast.map((a) -> EVAL(a, env))...) @@ -53,11 +53,11 @@ EVAL = (ast, env) -> [a0, a1, a2, a3] = ast switch a0.name when "def!" - return env.set(a1.name, EVAL(a2, env)) + return env.set(a1, EVAL(a2, env)) when "let*" let_env = new Env(env) for k,i in a1 when i %% 2 == 0 - let_env.set(a1[i].name, EVAL(a1[i+1], let_env)) + let_env.set(a1[i], EVAL(a1[i+1], let_env)) ast = a2 env = let_env when "quote" @@ -67,7 +67,7 @@ EVAL = (ast, env) -> when "defmacro!" f = EVAL(a2, env) f.__ismacro__ = true - return env.set(a1.name, f) + return env.set(a1, f) when "macroexpand" return macroexpand(a1, env) when "try*" @@ -112,9 +112,9 @@ repl_env = new Env() rep = (str) -> PRINT(EVAL(READ(str), repl_env)) # core.coffee: defined using CoffeeScript -repl_env.set k, v for k,v of core.ns -repl_env.set 'eval', (ast) -> EVAL(ast, repl_env) -repl_env.set '*ARGV*', [] +repl_env.set types._symbol(k), v for k,v of core.ns +repl_env.set types._symbol('eval'), (ast) -> EVAL(ast, repl_env) +repl_env.set types._symbol('*ARGV*'), [] # core.mal: defined using the language itself rep("(def! *host-language* \"CoffeeScript\")") @@ -124,7 +124,7 @@ rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if ( rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") if process? && process.argv.length > 2 - repl_env.set '*ARGV*', process.argv[3..] + repl_env.set types._symbol('*ARGV*'), process.argv[3..] rep('(load-file "' + process.argv[2] + '")') process.exit 0 diff --git a/coffee/types.coffee b/coffee/types.coffee index 8982120..d732064 100644 --- a/coffee/types.coffee +++ b/coffee/types.coffee @@ -16,7 +16,8 @@ E._obj_type = _obj_type = (obj) -> switch typeof obj when 'number' then 'number' when 'function' then 'function' - when 'string' then 'string' + when 'string' + if obj[0] == '\u029e' then 'keyword' else 'string' else throw new Error "Unknown type '" + typeof(obj) + "'" E._sequential_Q = _sequential_Q = (o) -> _list_Q(o) or _vector_Q(o) @@ -69,6 +70,11 @@ class Symbol E._symbol = (str) -> new Symbol str E._symbol_Q = _symbol_Q = (o) -> o instanceof Symbol +# Keywords +E._keyword = _keyword = (str) -> "\u029e" + str +E._keyword_Q = _keyword_Q = (o) -> + typeof o == 'string' && o[0] == "\u029e" + # Functions E._function = (evalfn, ast, env, params) -> fn = (args...) -> evalfn(ast, new Env(env, params, args)) @@ -103,6 +109,7 @@ E._dissoc_BANG = (hm, args...) -> E._hash_map_Q = _hash_map_Q = (o) -> typeof o == "object" && !Array.isArray(o) && !(o == null) && + !(o instanceof Symbol) && !(o instanceof Atom) |
