Skip to content

Commit

Permalink
change ordered keyword to dicttype keyword; this provides more flexib…
Browse files Browse the repository at this point in the history
…ility, and avoids the pseudo-dependency on DataStructures that was causing precompile problems
  • Loading branch information
stevengj committed Oct 5, 2015
1 parent fe9de2d commit 15f10f6
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 39 deletions.
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,18 @@ json(a::Any)
Returns a compact JSON representation as an `AbstractString`.

```julia
JSON.parse(s::AbstractString; ordered=false)
JSON.parse(io::IO; ordered=false)
JSON.parsefile(filename::AbstractString; ordered=false, use_mmap=true)
JSON.parse(s::AbstractString; dicttype=Dict)
JSON.parse(io::IO, dicttype=Dict)
JSON.parsefile(filename::AbstractString; dicttype=Dict, use_mmap=true)
```

Parses a JSON `AbstractString` or IO stream into a nested Array or Dict.

If `ordered=true` is specified, JSON objects are parsed into
`OrderedDicts`, which maintains the insertion order of the items in
the object. (*)

(*) Requires the `DataStructures.jl` package to be installed.
The `dicttype` indicates the dictionary type (`<: Associative`) that
JSON objects are parsed to. It defaults to `Dict` (the built-in Julia
dictionary), but a different type can be passed to, for example,
provide a desired ordering. For example, if you `import DataStructures`
(assuming the [DataStructures
package](https://github.com/JuliaLang/DataStructures.jl) is
installed), you can pass `dicttype=DataStructures.OrderedDict` to
maintain the insertion order of the items in the object.
8 changes: 4 additions & 4 deletions src/JSON.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ function consumeString(io::IO, obj::IOBuffer)
throw(EOFError())
end

function parse(io::IO; ordered::Bool=false)
function parse{T<:Associative}(io::IO; dicttype::Type{T}=Dict)
open_bracket = close_bracket = nothing
try
open_bracket, close_bracket = determine_bracket_type(io)
Expand All @@ -278,14 +278,14 @@ function parse(io::IO; ordered::Bool=false)
consumeString(io, obj)
end
end
JSON.parse(takebuf_string(obj), ordered=ordered)
JSON.parse(takebuf_string(obj); dicttype=dicttype)
end

function parsefile(filename::AbstractString; ordered::Bool=false, use_mmap=true)
function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict, use_mmap=true)
sz = filesize(filename)
open(filename) do io
s = use_mmap ? UTF8String(Mmap.mmap(io, Vector{UInt8}, sz)) : readall(io)
JSON.parse(s, ordered=ordered)
JSON.parse(s; dicttype=dicttype)
end
end

Expand Down
37 changes: 11 additions & 26 deletions src/Parser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@ module Parser #JSON

using Compat

#Define ordered dictionary from DataStructures if present
function __init__()
global _HAVE_DATASTRUCTURES = try
@eval import DataStructures.OrderedDict
true
catch
false
end
end

const TYPES = Any # Union{Dict, Array, AbstractString, Number, Bool, Void} # Types it may encounter
const KEY_TYPES = AbstractString # Union{AbstractString} # Types it may encounter as object keys

Expand Down Expand Up @@ -77,13 +67,13 @@ end

# PARSING

function parse_array{T<:AbstractString}(ps::ParserState{T}, ordered::Bool)
function parse_array{T<:AbstractString}(ps::ParserState{T}, dictT::Type)
incr(ps) # Skip over the '['
_array = TYPES[]
chomp_space(ps)
charat(ps)==']' && (incr(ps); return _array) # Check for empty array
while true # Extract values from array
v = parse_value(ps, ordered) # Extract value
v = parse_value(ps, dictT) # Extract value
push!(_array, v)
# Eat up trailing whitespace
chomp_space(ps)
Expand All @@ -101,23 +91,19 @@ function parse_array{T<:AbstractString}(ps::ParserState{T}, ordered::Bool)
return _array
end

function parse_object{T<:AbstractString}(ps::ParserState{T}, ordered::Bool)
if ordered
parse_object(ps, ordered, OrderedDict{KEY_TYPES,TYPES}())
else
parse_object(ps, ordered, Dict{KEY_TYPES,TYPES}())
end
function parse_object{T<:AbstractString}(ps::ParserState{T}, dictT::Type)
parse_object(ps, dictT, dictT{KEY_TYPES,TYPES}())
end

function parse_object{T<:AbstractString}(ps::ParserState{T}, ordered::Bool, obj)
function parse_object{T<:AbstractString}(ps::ParserState{T}, dictT::Type, obj)
incr(ps) # Skip over opening '{'
chomp_space(ps)
charat(ps)=='}' && (incr(ps); return obj) # Check for empty object
while true
chomp_space(ps)
_key = parse_string(ps) # Key
skip_separator(ps)
_value = parse_value(ps, ordered) # Value
_value = parse_value(ps, dictT) # Value
obj[_key] = _value # Building object
chomp_space(ps)
c = charat(ps) # Find the next pair or end of object
Expand Down Expand Up @@ -213,19 +199,19 @@ function parse_simple{T<:AbstractString}(ps::ParserState{T})
ret
end

function parse_value{T<:AbstractString}(ps::ParserState{T}, ordered::Bool)
function parse_value{T<:AbstractString}(ps::ParserState{T}, dictT::Type)
chomp_space(ps)
(ps.s > ps.e) && return nothing # Nothing left

ch = charat(ps)
if ch == '"'
ret = parse_string(ps)
elseif ch == '{'
ret = parse_object(ps, ordered)
ret = parse_object(ps, dictT)
elseif (ch >= '0' && ch <= '9') || ch=='-' || ch=='+'
ret = parse_number(ps)
elseif ch == '['
ret = parse_array(ps, ordered)
ret = parse_array(ps, dictT)
elseif ch == 'f' || ch == 't' || ch == 'n'
ret = parse_simple(ps)
else
Expand Down Expand Up @@ -315,12 +301,11 @@ function parse_number{T<:AbstractString}(ps::ParserState{T})
end
end

function parse(str::AbstractString; ordered::Bool=false)
function parse{T<:Associative}(str::AbstractString; dicttype::Type{T}=Dict)
pos::Int = 1
len::Int = endof(str)
len < 1 && return
ordered && !_HAVE_DATASTRUCTURES && error("DataStructures package required for ordered parsing: try `Pkg.add(\"DataStructures\")`")
parse_value(ParserState(str, pos, len), ordered)
parse_value(ParserState(str, pos, len), dicttype)
end

end #module Parser
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import DataStructures

include(joinpath(dirname(@__FILE__),"json_samples.jl"))

@test JSON.parse("{\"x\": 3}"; ordered = true) == DataStructures.OrderedDict{AbstractString,Any}([("x",3)])
@test JSON.parse("{\"x\": 3}", dicttype=DataStructures.OrderedDict) == DataStructures.OrderedDict{AbstractString,Any}([("x",3)])

# Test definitions -------
validate_c(c) = begin
Expand Down

0 comments on commit 15f10f6

Please sign in to comment.