1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-27 06:40:14 +03:00
mal/impls/julia/reader.jl
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

133 lines
3.0 KiB
Julia

module reader
export read_str
import types
type Reader
tokens
position::Int64
end
function next(rdr::Reader)
if rdr.position > length(rdr.tokens)
return nothing
end
rdr.position += 1
rdr.tokens[rdr.position-1]
end
function peek(rdr::Reader)
if rdr.position > length(rdr.tokens)
return nothing
end
rdr.tokens[rdr.position]
end
function tokenize(str)
re = r"[\s,]*(~@|[\[\]{}()'`~^@]|\"(?:\\.|[^\\\"])*\"?|;.*|[^\s\[\]{}('\"`,;)]*)"
tokens = map((m) -> m.captures[1], eachmatch(re, str))
filter((t) -> t != "" && t[1] != ';', tokens)
end
function read_atom(rdr)
token = next(rdr)
if ismatch(r"^-?[0-9]+$", token)
parse(Int,token)
elseif ismatch(r"^-?[0-9][0-9.]*$", token)
float(token)
elseif ismatch(r"^\"(?:\\.|[^\\\"])*\"$", token)
replace(token[2:end-1], r"\\.", (r) -> get(Dict("\\n"=>"\n",
"\\\""=>"\"",
"\\\\"=>"\\"), r, r))
elseif ismatch(r"^\".*$", token)
error("expected '\"', got EOF")
elseif token[1] == ':'
"\u029e$(token[2:end])"
elseif token == "nil"
nothing
elseif token == "true"
true
elseif token == "false"
false
else
symbol(token)
end
end
function read_list(rdr, start="(", last=")")
ast = Any[]
token = next(rdr)
if (token != start)
error("expected '$(start)'")
end
while ((token = peek(rdr)) != last)
if token == nothing
error("expected '$(last)', got EOF")
end
push!(ast, read_form(rdr))
end
next(rdr)
ast
end
function read_vector(rdr)
lst = read_list(rdr, "[", "]")
tuple(lst...)
end
function read_hash_map(rdr)
lst = read_list(rdr, "{", "}")
types.hash_map(lst...)
end
function read_form(rdr)
token = peek(rdr)
if token == "'"
next(rdr)
[[:quote]; Any[read_form(rdr)]]
elseif token == "`"
next(rdr)
[[:quasiquote]; Any[read_form(rdr)]]
elseif token == "~"
next(rdr)
[[:unquote]; Any[read_form(rdr)]]
elseif token == "~@"
next(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]]
elseif token == "@"
next(rdr)
[[symbol("deref")]; Any[read_form(rdr)]]
elseif token == ")"
error("unexpected ')'")
elseif token == "("
read_list(rdr)
elseif token == "]"
error("unexpected ']'")
elseif token == "["
read_vector(rdr)
elseif token == "}"
error("unexpected '}'")
elseif token == "{"
read_hash_map(rdr)
else
read_atom(rdr)
end
end
function read_str(str)
tokens = tokenize(str)
if length(tokens) == 0
return nothing
end
read_form(Reader(tokens, 1))
end
end