Julia: update to verion 0.4. Add time-ms.
authorJoel Martin <github@martintribe.org>
Sat, 24 Oct 2015 20:39:13 +0000 (15:39 -0500)
committerJoel Martin <github@martintribe.org>
Sat, 24 Oct 2015 20:41:22 +0000 (15:41 -0500)
19 files changed:
Makefile
README.md
julia/Dockerfile
julia/core.jl
julia/env.jl
julia/printer.jl
julia/reader.jl
julia/step0_repl.jl
julia/step1_read_print.jl
julia/step2_eval.jl
julia/step3_env.jl
julia/step4_if_fn_do.jl
julia/step5_tco.jl
julia/step6_file.jl
julia/step7_quote.jl
julia/step8_macros.jl
julia/step9_try.jl
julia/stepA_mal.jl
julia/types.jl

index 5bf1544..d734b09 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,6 @@ EXCLUDE_TESTS += test^erlang^step5 # erlang is TCO, test passes
 EXCLUDE_TESTS += test^elixir^step5 # elixir is TCO, test passes
 EXCLUDE_TESTS += test^fsharp^step5 # completes at 10,000, fatal stack overflow at 100,000
 EXCLUDE_TESTS += test^haskell^step5 # test completes
-EXCLUDE_TESTS += test^julia^step5 # hangs test
 EXCLUDE_TESTS += test^make^step5 # no TCO capability/step
 EXCLUDE_TESTS += test^mal^step5  # no TCO capability/step
 EXCLUDE_TESTS += test^miniMAL^step5 # strange error with runtest.py
index 1ce783f..c944d75 100644 (file)
--- a/README.md
+++ b/README.md
@@ -190,7 +190,8 @@ iex -S mix stepX_YYY
 
 *The Erlang implementation was created by [Nathan Fiedler (nlfiedler)](https://github.com/nlfiedler)*
 
-The Erlang implementation of mal requires [Erlang/OTP R17](http://www.erlang.org/download.html) and [rebar](https://github.com/rebar/rebar) to build.
+The Erlang implementation of mal requires [Erlang/OTP R17](http://www.erlang.org/download.html)
+and [rebar](https://github.com/rebar/rebar) to build.
 
 ```
 cd erlang
@@ -317,7 +318,7 @@ node stepX_YYY.js
 
 ### Julia
 
-The Julia implementation of mal has been tested with Julia 0.3.7.
+The Julia implementation of mal requires Julia 0.4.
 
 ```
 cd julia
index fdc643d..90a9410 100644 (file)
@@ -24,6 +24,6 @@ WORKDIR /mal
 # Julia
 RUN apt-get -y install software-properties-common
 RUN apt-add-repository -y ppa:staticfloat/juliareleases
-RUN apt-get -y update
+RUN apt-get update -y
 RUN apt-get -y install julia
 
index 58da730..ddfdd2a 100644 (file)
@@ -8,9 +8,9 @@ import readline_mod
 export ns
 
 function concat(args...)
-    res = {}
+    res = []
     for a=args
-        res = [res, Any[a...]]
+        res = [res; Any[a...]]
     end
     res
 end
@@ -27,7 +27,7 @@ function with_meta(obj, meta)
     new_obj
 end
 
-ns = {
+ns = Dict{Any,Any}(
     symbol("=") => (a,b) -> types.equal_Q(a, b),
     :throw => (a) -> throw(types.MalException(a)),
 
@@ -37,7 +37,7 @@ ns = {
     symbol("symbol") => (a) -> symbol(a),
     symbol("symbol?") => (a) -> typeof(a) === Symbol,
     symbol("keyword") => (a) -> a[1] == '\u029e' ? a : "\u029e$(a)",
-    symbol("keyword?") => (a) -> isa(a,String) && a[1] == '\u029e',
+    symbol("keyword?") => (a) -> isa(a,AbstractString) && a[1] == '\u029e',
 
     symbol("pr-str") => (a...) -> join(map((e)->pr_str(e, true),a)," "),
     :str => (a...) -> join(map((e)->pr_str(e, false),a),""),
@@ -55,6 +55,7 @@ ns = {
     :- => -,
     symbol("*") => *,
     :/ => div,
+    symbol("time-ms") => () -> round(Int, time()*1000),
 
     :list => (a...) -> Any[a...],
     symbol("list?") => (a) -> isa(a, Array),
@@ -66,11 +67,11 @@ ns = {
     :dissoc => (a, b...) -> foldl((x,y) -> delete!(x,y),copy(a), b),
     :get => (a,b) -> a === nothing ? nothing : get(a,b,nothing),
     symbol("contains?") => haskey,
-    :keys => (a) -> {keys(a)...},
-    :vals => (a) -> {values(a)...},
+    :keys => (a) -> [keys(a)...],
+    :vals => (a) -> [values(a)...],
 
     symbol("sequential?") => types.sequential_Q,
-    :cons => (a,b) -> [Any[a], Any[b...]],
+    :cons => (a,b) -> [Any[a]; Any[b...]],
     :concat => concat,
     :nth => (a,b) -> b+1 > length(a) ? error("nth: index out of range") : a[b+1],
     :first => (a) -> isempty(a) ? nothing : first(a),
@@ -78,7 +79,7 @@ ns = {
     symbol("empty?") => isempty,
     :count => (a) -> a == nothing ? 0 : length(a),
     :apply => do_apply,
-    :map => (a,b) -> isa(a,types.MalFunc) ? {map(a.fn,b)...} : {map(a,b)...},
+    :map => (a,b) -> isa(a,types.MalFunc) ? [map(a.fn,b)...] : [map(a,b)...],
 
     :conj => nothing,
 
@@ -89,6 +90,6 @@ ns = {
     :deref => (a) -> a.val,
     :reset! => (a,b) -> a.val = b,
     :swap! => (a,b,c...) -> a.val = do_apply(b, a.val, c),
-    }
+    )
 
 end
index 8223282..2451b51 100644 (file)
@@ -1,6 +1,6 @@
 module env
 
-export Env, set, find, get
+export Env, env_set, env_find, env_get
 
 type Env
     outer::Any
@@ -29,22 +29,22 @@ function Env(outer, binds, exprs)
 end
 
 
-function set(env::Env, k::Symbol, v)
+function env_set(env::Env, k::Symbol, v)
     env.data[k] = v
 end
 
-function find(env::Env, k::Symbol)
+function env_find(env::Env, k::Symbol)
     if haskey(env.data, k)
         env
     elseif env.outer != nothing
-        find(env.outer, k)
+        env_find(env.outer, k)
     else
         nothing
     end
 end
 
-function get(env::Env, k::Symbol)
-    e = find(env, k)
+function env_get(env::Env, k::Symbol)
+    e = env_find(env, k)
     if e != nothing
         e.data[k]
     else
index d61db72..44e0b1e 100644 (file)
@@ -12,9 +12,9 @@ function pr_str(obj, print_readably=true)
         "[$(join([pr_str(o, _r) for o=obj], " "))]"
     elseif isa(obj, Dict)
         "{$(join(["$(pr_str(o[1],_r)) $(pr_str(o[2],_r))" for o=obj], " "))}"
-    elseif isa(obj, String)
+    elseif isa(obj, AbstractString)
         if length(obj) > 0 && obj[1] == '\u029e'
-            ":$(obj[2:end])"
+            ":$(obj[3:end])"
         elseif _r
             str = replace(replace(replace(obj,
                                           "\\", "\\\\"),
index f7e5692..caabb94 100644 (file)
@@ -34,7 +34,7 @@ end
 function read_atom(rdr)
     token = next(rdr)
     if ismatch(r"^-?[0-9]+$", token)
-        int(token)
+        parse(Int,token)
     elseif ismatch(r"^-?[0-9][0-9.]*$", token)
         float(token)
     elseif ismatch(r"^\".*\"$", token)
@@ -85,23 +85,23 @@ function read_form(rdr)
     token = peek(rdr)
     if token == "'"
         next(rdr)
-        [[:quote], Any[read_form(rdr)]]
+        [[:quote]; Any[read_form(rdr)]]
     elseif token == "`"
         next(rdr)
-        [[:quasiquote], Any[read_form(rdr)]]
+        [[:quasiquote]; Any[read_form(rdr)]]
     elseif token == "~"
         next(rdr)
-        [[:unquote], Any[read_form(rdr)]]
+        [[:unquote]; Any[read_form(rdr)]]
     elseif token == "~@"
         next(rdr)
-        [[symbol("splice-unquote")], Any[read_form(rdr)]]
+        [[symbol("splice-unquote")]; Any[read_form(rdr)]]
     elseif token == "^"
         next(rdr)
         meta = read_form(rdr)
-        [[symbol("with-meta")], Any[read_form(rdr)], Any[meta]]
+        [[symbol("with-meta")]; Any[read_form(rdr)]; Any[meta]]
     elseif token == "@"
         next(rdr)
-        [[symbol("deref")], Any[read_form(rdr)]]
+        [[symbol("deref")]; Any[read_form(rdr)]]
 
     elseif token == ")"
         error("unexpected ')'")
index 326dea3..049cde1 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 
 # READ
@@ -19,7 +20,7 @@ end
 
 # REPL
 function REP(str)
-    return PRINT(EVAL(READ(str), {}))
+    return PRINT(EVAL(READ(str), []))
 end
 
 while true
index 84245f7..604b1f9 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -21,7 +22,7 @@ end
 
 # REPL
 function REP(str)
-    return PRINT(EVAL(READ(str), {}))
+    return PRINT(EVAL(READ(str), []))
 end
 
 while true
index 4cbc196..0089fe6 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -37,10 +38,10 @@ function PRINT(exp)
 end
 
 # REPL
-repl_env = {:+ => +,
-            :- => -,
-            :* => *,
-            :/ => div}
+repl_env = Dict{Any,Any}(:+ => +,
+                         :- => -,
+                         :* => *,
+                         :/ => div)
 function REP(str)
     return PRINT(EVAL(READ(str), repl_env))
 end
index a243d2b..c0bcde1 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -13,7 +14,7 @@ end
 # EVAL
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -28,11 +29,11 @@ function EVAL(ast, env)
 
     # apply
     if     :def! == ast[1]
-        set(env, ast[2], EVAL(ast[3], env))
+        env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         EVAL(ast[3], let_env)
     else
@@ -49,10 +50,10 @@ end
 
 # REPL
 repl_env = Env(nothing,
-               {:+ => +,
-                :- => -,
-                :* => *,
-                :/ => div})
+               Dict{Any,Any}(:+ => +,
+                             :- => -,
+                             :* => *,
+                             :/ => div))
 function REP(str)
     return PRINT(EVAL(READ(str), repl_env))
 end
index 3bcc6eb..6af7d06 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -14,7 +15,7 @@ end
 # EVAL
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -29,11 +30,11 @@ function EVAL(ast, env)
 
     # apply
     if     :def! == ast[1]
-        set(env, ast[2], EVAL(ast[3], env))
+        env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         EVAL(ast[3], let_env)
     elseif :do == ast[1]
@@ -86,8 +87,10 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index 39860fe..37f3209 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -15,7 +16,7 @@ end
 # EVAL
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -27,15 +28,16 @@ end
 
 function EVAL(ast, env)
   while true
+    #println("EVAL: $(printer.pr_str(ast,true))")
     if !isa(ast, Array) return eval_ast(ast, env) end
 
     # apply
     if     :def! == ast[1]
-        return set(env, ast[2], EVAL(ast[3], env))
+        return env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         env = let_env
         ast = ast[3]
@@ -103,8 +105,11 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        # TODO: show at least part of stack
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index 5ee35fb..9851348 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -15,7 +16,7 @@ end
 # EVAL
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -27,15 +28,16 @@ end
 
 function EVAL(ast, env)
   while true
+    #println("EVAL: $(printer.pr_str(ast,true))")
     if !isa(ast, Array) return eval_ast(ast, env) end
 
     # apply
     if     :def! == ast[1]
-        return set(env, ast[2], EVAL(ast[3], env))
+        return env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         env = let_env
         ast = ast[3]
@@ -88,8 +90,8 @@ end
 
 # core.jl: defined using Julia
 repl_env = Env(nothing, core.ns)
-set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
-set(repl_env, symbol("*ARGV*"), ARGS[2:end])
+env_set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
+env_set(repl_env, symbol("*ARGV*"), ARGS[2:end])
 
 # core.mal: defined using the language itself
 REP("(def! not (fn* (a) (if a false true)))")
@@ -111,8 +113,11 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        # TODO: show at least part of stack
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index 5cf10e5..8206da4 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -19,19 +20,19 @@ end
 
 function quasiquote(ast)
     if !ispair(ast)
-        [[:quote], Any[ast]]
+        [[:quote]; Any[ast]]
     elseif ast[1] == :unquote
         ast[2]
     elseif ispair(ast[1]) && ast[1][1] == symbol("splice-unquote")
-        [[:concat], Any[ast[1][2]], Any[quasiquote(ast[2:end])]]
+        [[:concat]; Any[ast[1][2]]; Any[quasiquote(ast[2:end])]]
     else
-        [[:cons], Any[quasiquote(ast[1])], Any[quasiquote(ast[2:end])]]
+        [[:cons]; Any[quasiquote(ast[1])]; Any[quasiquote(ast[2:end])]]
     end
 end
 
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -43,15 +44,16 @@ end
 
 function EVAL(ast, env)
   while true
+    #println("EVAL: $(printer.pr_str(ast,true))")
     if !isa(ast, Array) return eval_ast(ast, env) end
 
     # apply
     if     :def! == ast[1]
-        return set(env, ast[2], EVAL(ast[3], env))
+        return env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         env = let_env
         ast = ast[3]
@@ -109,8 +111,8 @@ end
 
 # core.jl: defined using Julia
 repl_env = Env(nothing, core.ns)
-set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
-set(repl_env, symbol("*ARGV*"), ARGS[2:end])
+env_set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
+env_set(repl_env, symbol("*ARGV*"), ARGS[2:end])
 
 # core.mal: defined using the language itself
 REP("(def! not (fn* (a) (if a false true)))")
@@ -132,8 +134,11 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        # TODO: show at least part of stack
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index 19cf2ee..52c373e 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -19,27 +20,27 @@ end
 
 function quasiquote(ast)
     if !ispair(ast)
-        [[:quote], Any[ast]]
+        [[:quote]; Any[ast]]
     elseif ast[1] == :unquote
         ast[2]
     elseif ispair(ast[1]) && ast[1][1] == symbol("splice-unquote")
-        [[:concat], Any[ast[1][2]], Any[quasiquote(ast[2:end])]]
+        [[:concat]; Any[ast[1][2]]; Any[quasiquote(ast[2:end])]]
     else
-        [[:cons], Any[quasiquote(ast[1])], Any[quasiquote(ast[2:end])]]
+        [[:cons]; Any[quasiquote(ast[1])]; Any[quasiquote(ast[2:end])]]
     end
 end
 
 function ismacroCall(ast, env)
     return isa(ast, Array) &&
            isa(ast[1], Symbol) &&
-           find(env, ast[1]) != nothing &&
-           isa(get(env, ast[1]), MalFunc) &&
-           get(env, ast[1]).ismacro
+           env_find(env, ast[1]) != nothing &&
+           isa(env_get(env, ast[1]), MalFunc) &&
+           env_get(env, ast[1]).ismacro
 end
 
 function macroexpand(ast, env)
     while ismacroCall(ast, env)
-        mac = get(env, ast[1])
+        mac = env_get(env, ast[1])
         ast = mac.fn(ast[2:end]...)
     end
     ast
@@ -47,7 +48,7 @@ end
 
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -67,11 +68,11 @@ function EVAL(ast, env)
     if !isa(ast, Array) return ast end
 
     if     :def! == ast[1]
-        return set(env, ast[2], EVAL(ast[3], env))
+        return env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         env = let_env
         ast = ast[3]
@@ -84,7 +85,7 @@ function EVAL(ast, env)
     elseif :defmacro! == ast[1]
         func = EVAL(ast[3], env)
         func.ismacro = true
-        return set(env, ast[2], func)
+        return env_set(env, ast[2], func)
     elseif :macroexpand == ast[1]
         return macroexpand(ast[2], env)
     elseif :do == ast[1]
@@ -135,8 +136,8 @@ end
 
 # core.jl: defined using Julia
 repl_env = Env(nothing, core.ns)
-set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
-set(repl_env, symbol("*ARGV*"), ARGS[2:end])
+env_set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
+env_set(repl_env, symbol("*ARGV*"), ARGS[2:end])
 
 # core.mal: defined using the language itself
 REP("(def! not (fn* (a) (if a false true)))")
@@ -161,8 +162,11 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        # TODO: show at least part of stack
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index 327c2de..f2bc385 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -19,27 +20,27 @@ end
 
 function quasiquote(ast)
     if !ispair(ast)
-        [[:quote], Any[ast]]
+        [[:quote]; Any[ast]]
     elseif ast[1] == :unquote
         ast[2]
     elseif ispair(ast[1]) && ast[1][1] == symbol("splice-unquote")
-        [[:concat], Any[ast[1][2]], Any[quasiquote(ast[2:end])]]
+        [[:concat]; Any[ast[1][2]]; Any[quasiquote(ast[2:end])]]
     else
-        [[:cons], Any[quasiquote(ast[1])], Any[quasiquote(ast[2:end])]]
+        [[:cons]; Any[quasiquote(ast[1])]; Any[quasiquote(ast[2:end])]]
     end
 end
 
 function ismacroCall(ast, env)
     return isa(ast, Array) &&
            isa(ast[1], Symbol) &&
-           find(env, ast[1]) != nothing &&
-           isa(get(env, ast[1]), MalFunc) &&
-           get(env, ast[1]).ismacro
+           env_find(env, ast[1]) != nothing &&
+           isa(env_get(env, ast[1]), MalFunc) &&
+           env_get(env, ast[1]).ismacro
 end
 
 function macroexpand(ast, env)
     while ismacroCall(ast, env)
-        mac = get(env, ast[1])
+        mac = env_get(env, ast[1])
         ast = mac.fn(ast[2:end]...)
     end
     ast
@@ -47,7 +48,7 @@ end
 
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -67,11 +68,11 @@ function EVAL(ast, env)
     if !isa(ast, Array) return ast end
 
     if     :def! == ast[1]
-        return set(env, ast[2], EVAL(ast[3], env))
+        return env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         env = let_env
         ast = ast[3]
@@ -84,7 +85,7 @@ function EVAL(ast, env)
     elseif :defmacro! == ast[1]
         func = EVAL(ast[3], env)
         func.ismacro = true
-        return set(env, ast[2], func)
+        return env_set(env, ast[2], func)
     elseif :macroexpand == ast[1]
         return macroexpand(ast[2], env)
     elseif symbol("try*") == ast[1]
@@ -100,7 +101,7 @@ function EVAL(ast, env)
                 e = string(e)
             end
             if length(ast) > 2 && ast[3][1] == symbol("catch*")
-                return EVAL(ast[3][3], Env(env, {ast[3][2]}, {e}))
+                return EVAL(ast[3][3], Env(env, Any[ast[3][2]], Any[e]))
             else
                 rethrow(exc)
             end
@@ -153,8 +154,8 @@ end
 
 # core.jl: defined using Julia
 repl_env = Env(nothing, core.ns)
-set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
-set(repl_env, symbol("*ARGV*"), ARGS[2:end])
+env_set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
+env_set(repl_env, symbol("*ARGV*"), ARGS[2:end])
 
 # core.mal: defined using the language itself
 REP("(def! not (fn* (a) (if a false true)))")
@@ -179,8 +180,11 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        # TODO: show at least part of stack
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index 05a554a..5782b28 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env julia
 
+push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
 import readline_mod
 import reader
 import printer
@@ -19,27 +20,27 @@ end
 
 function quasiquote(ast)
     if !ispair(ast)
-        [[:quote], Any[ast]]
+        [[:quote]; Any[ast]]
     elseif ast[1] == :unquote
         ast[2]
     elseif ispair(ast[1]) && ast[1][1] == symbol("splice-unquote")
-        [[:concat], Any[ast[1][2]], Any[quasiquote(ast[2:end])]]
+        [[:concat]; Any[ast[1][2]]; Any[quasiquote(ast[2:end])]]
     else
-        [[:cons], Any[quasiquote(ast[1])], Any[quasiquote(ast[2:end])]]
+        [[:cons]; Any[quasiquote(ast[1])]; Any[quasiquote(ast[2:end])]]
     end
 end
 
 function ismacroCall(ast, env)
     return isa(ast, Array) &&
            isa(ast[1], Symbol) &&
-           find(env, ast[1]) != nothing &&
-           isa(get(env, ast[1]), MalFunc) &&
-           get(env, ast[1]).ismacro
+           env_find(env, ast[1]) != nothing &&
+           isa(env_get(env, ast[1]), MalFunc) &&
+           env_get(env, ast[1]).ismacro
 end
 
 function macroexpand(ast, env)
     while ismacroCall(ast, env)
-        mac = get(env, ast[1])
+        mac = env_get(env, ast[1])
         ast = mac.fn(ast[2:end]...)
     end
     ast
@@ -47,7 +48,7 @@ end
 
 function eval_ast(ast, env)
     if typeof(ast) == Symbol
-        get(env,ast)
+        env_get(env,ast)
     elseif isa(ast, Array) || isa(ast, Tuple)
         map((x) -> EVAL(x,env), ast)
     elseif isa(ast, Dict)
@@ -67,11 +68,11 @@ function EVAL(ast, env)
     if !isa(ast, Array) return ast end
 
     if     :def! == ast[1]
-        return set(env, ast[2], EVAL(ast[3], env))
+        return env_set(env, ast[2], EVAL(ast[3], env))
     elseif symbol("let*") == ast[1]
         let_env = Env(env)
         for i = 1:2:length(ast[2])
-            set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
+            env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
         end
         env = let_env
         ast = ast[3]
@@ -84,7 +85,7 @@ function EVAL(ast, env)
     elseif :defmacro! == ast[1]
         func = EVAL(ast[3], env)
         func.ismacro = true
-        return set(env, ast[2], func)
+        return env_set(env, ast[2], func)
     elseif :macroexpand == ast[1]
         return macroexpand(ast[2], env)
     elseif symbol("try*") == ast[1]
@@ -100,7 +101,7 @@ function EVAL(ast, env)
                 e = string(e)
             end
             if length(ast) > 2 && ast[3][1] == symbol("catch*")
-                return EVAL(ast[3][3], Env(env, {ast[3][2]}, {e}))
+                return EVAL(ast[3][3], Env(env, Any[ast[3][2]], Any[e]))
             else
                 rethrow(exc)
             end
@@ -153,8 +154,8 @@ end
 
 # core.jl: defined using Julia
 repl_env = Env(nothing, core.ns)
-set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
-set(repl_env, symbol("*ARGV*"), ARGS[2:end])
+env_set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
+env_set(repl_env, symbol("*ARGV*"), ARGS[2:end])
 
 # core.mal: defined using the language itself
 REP("(def! *host-language* \"julia\")")
@@ -181,8 +182,11 @@ while true
         else
             println("Error: $(string(e))")
         end
-        bt = catch_backtrace()
-        Base.show_backtrace(STDERR, bt)
+        # TODO: show at least part of stack
+        if !isa(e, StackOverflowError)
+            bt = catch_backtrace()
+            Base.show_backtrace(STDERR, bt)
+        end
         println()
     end
 end
index ccbb038..fb809a6 100644 (file)
@@ -39,7 +39,7 @@ function equal_Q(a, b)
 
     if sequential_Q(a)
         tuple(a...) == tuple(b...)
-    elseif isa(a,String)
+    elseif isa(a,AbstractString)
         a == b
     else
         a === b