mirror of
https://github.com/kanaka/mal.git
synced 2024-11-11 00:52:44 +03:00
141 lines
3.9 KiB
Julia
141 lines
3.9 KiB
Julia
module core
|
|
|
|
import types
|
|
import reader
|
|
using printer
|
|
import readline_mod
|
|
|
|
export ns
|
|
|
|
function string_Q(obj)
|
|
isa(obj,AbstractString) && (length(obj) == 0 || obj[1] != '\u029e')
|
|
end
|
|
|
|
function keyword_Q(obj)
|
|
isa(obj,AbstractString) && (length(obj) > 0 && obj[1] == '\u029e')
|
|
end
|
|
|
|
function concat(args...)
|
|
res = []
|
|
for a=args
|
|
res = [res; Any[a...]]
|
|
end
|
|
res
|
|
end
|
|
|
|
function do_apply(f, all_args...)
|
|
fn = isa(f,types.MalFunc) ? f.fn : f
|
|
args = concat(all_args[1:end-1], all_args[end])
|
|
fn(args...)
|
|
end
|
|
|
|
function do_map(a,b)
|
|
# map and convert to array/list
|
|
if isa(a,types.MalFunc)
|
|
collect(map(a.fn,b))
|
|
else
|
|
collect(map(a,b))
|
|
end
|
|
end
|
|
|
|
function conj(seq, args...)
|
|
if isa(seq,Array)
|
|
concat(reverse(args), seq)
|
|
else
|
|
tuple(concat(seq, args)...)
|
|
end
|
|
end
|
|
|
|
function do_seq(obj)
|
|
if isa(obj,Array)
|
|
length(obj) > 0 ? obj : nothing
|
|
elseif isa(obj,Tuple)
|
|
length(obj) > 0 ? Any[obj...] : nothing
|
|
elseif isa(obj,AbstractString)
|
|
length(obj) > 0 ? [string(c) for c=obj] : nothing
|
|
elseif obj == nothing
|
|
nothing
|
|
else
|
|
error("seq: called on non-sequence")
|
|
end
|
|
end
|
|
|
|
|
|
function with_meta(obj, meta)
|
|
new_obj = types.copy(obj)
|
|
new_obj.meta = meta
|
|
new_obj
|
|
end
|
|
|
|
ns = Dict{Any,Any}(
|
|
symbol("=") => (a,b) -> types.equal_Q(a, b),
|
|
:throw => (a) -> throw(types.MalException(a)),
|
|
|
|
symbol("nil?") => (a) -> a === nothing,
|
|
symbol("true?") => (a) -> a === true,
|
|
symbol("false?") => (a) -> a === false,
|
|
symbol("string?") => string_Q,
|
|
symbol("symbol") => (a) -> symbol(a),
|
|
symbol("symbol?") => (a) -> typeof(a) === Symbol,
|
|
symbol("keyword") => (a) -> a[1] == '\u029e' ? a : "\u029e$(a)",
|
|
symbol("keyword?") => keyword_Q,
|
|
symbol("number?") => (a) -> isa(a, AbstractFloat) || isa(a, Int64),
|
|
symbol("fn?") => (a) -> isa(a, Function) || (isa(a, types.MalFunc) && !a.ismacro),
|
|
symbol("macro?") => (a) -> isa(a, types.MalFunc) && a.ismacro,
|
|
|
|
symbol("pr-str") => (a...) -> join(map((e)->pr_str(e, true),a)," "),
|
|
:str => (a...) -> join(map((e)->pr_str(e, false),a),""),
|
|
:prn => (a...) -> println(join(map((e)->pr_str(e, true),a)," ")),
|
|
:println => (a...) -> println(join(map((e)->pr_str(e, false),a)," ")),
|
|
symbol("read-string") => (a) -> reader.read_str(a),
|
|
:readline => readline_mod.do_readline,
|
|
:slurp => (a) -> readall(open(a)),
|
|
|
|
:< => <,
|
|
:<= => <=,
|
|
:> => >,
|
|
:>= => >=,
|
|
:+ => +,
|
|
:- => -,
|
|
symbol("*") => *,
|
|
:/ => div,
|
|
symbol("time-ms") => () -> round(Int, time()*1000),
|
|
|
|
:list => (a...) -> Any[a...],
|
|
symbol("list?") => (a) -> isa(a, Array),
|
|
:vector => (a...) -> tuple(a...),
|
|
symbol("vector?") => (a) -> isa(a, Tuple),
|
|
symbol("hash-map") => types.hash_map,
|
|
symbol("map?") => (a) -> isa(a, Dict),
|
|
:assoc => (a, b...) -> merge(a, types.hash_map(b...)),
|
|
: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)...],
|
|
|
|
symbol("sequential?") => types.sequential_Q,
|
|
: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) -> a === nothing || isempty(a) ? nothing : first(a),
|
|
:rest => (a) -> a === nothing ? Any[] : Any[a[2:end]...],
|
|
symbol("empty?") => isempty,
|
|
:count => (a) -> a == nothing ? 0 : length(a),
|
|
:apply => do_apply,
|
|
:map => do_map,
|
|
|
|
:conj => conj,
|
|
:seq => do_seq,
|
|
|
|
:meta => (a) -> isa(a,types.MalFunc) ? a.meta : nothing,
|
|
symbol("with-meta") => with_meta,
|
|
:atom => (a) -> types.Atom(a),
|
|
symbol("atom?") => (a) -> isa(a,types.Atom),
|
|
:deref => (a) -> a.val,
|
|
:reset! => (a,b) -> a.val = b,
|
|
:swap! => (a,b,c...) -> a.val = do_apply(b, a.val, c),
|
|
)
|
|
|
|
end
|