From f7220efd9acd096040f78b52756e717b8612a2a7 Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Wed, 12 Apr 2017 16:59:47 -0400 Subject: [PATCH 1/2] Copy JSON.jl to Writer.jl (for review) --- src/Writer.jl | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 src/Writer.jl diff --git a/src/Writer.jl b/src/Writer.jl new file mode 100644 index 0000000..296c756 --- /dev/null +++ b/src/Writer.jl @@ -0,0 +1,327 @@ +isdefined(Base, :__precompile__) && __precompile__() + +module JSON + +using Compat + +export json # returns a compact (or indented) JSON representation as a string + +include("Common.jl") + +# Parser modules +include("Parser.jl") + +# Writer modules +include("Serializations.jl") + +using .Common +import .Parser.parse +import .Serializations.StandardSerialization + +""" +Internal JSON.jl implementation detail; do not depend on this type. + +A JSON primitive that wraps around any composite type to enable `Dict`-like +serialization. +""" +immutable CompositeTypeWrapper{T} + wrapped::T + fns::Vector{Symbol} +end +CompositeTypeWrapper(x) = CompositeTypeWrapper(x, fieldnames(x)) + +const JSONPrimitive = Union{ + Associative, Tuple, AbstractArray, AbstractString, Integer, + AbstractFloat, Void, CompositeTypeWrapper} + +""" +Return a value of a JSON-encodable primitive type that `x` should be lowered +into before encoding as JSON. Supported types are: `Associative` to JSON +objects, `Tuple` and `AbstractVector` to JSON arrays, `AbstractArray` to nested +JSON arrays, `AbstractString` to JSON string, `Integer` and `AbstractFloat` to +JSON number, `Bool` to JSON boolean, and `Void` to JSON null. + +Extensions of this method should preserve the property that the return value is +one of the aforementioned types. If first lowering to some intermediate type is +required, then extensions should call `lower` before returning a value. + +Note that the return value need not be *recursively* lowered—this function may +for instance return an `AbstractArray{Any, 1}` whose elements are not JSON +primitives. +""" +function lower(a) + if nfields(typeof(a)) > 0 + CompositeTypeWrapper(a) + else + error("Cannot serialize type $(typeof(a))") + end +end + +if isdefined(Base, :Dates) + lower(s::Base.Dates.TimeType) = string(s) +end + +if VERSION < v"0.5.0-dev+2396" + lower(f::Function) = "function at $(f.fptr)" +end + +lower(c::Char) = string(c) +lower(d::Type) = string(d) +lower(m::Module) = throw(ArgumentError("cannot serialize Module $m as JSON")) +lower(x::Real) = Float64(x) + +""" +Abstract supertype of all JSON and JSON-like structural writer contexts. +""" +@compat abstract type StructuralContext <: IO end + +""" +Internal implementation detail. + +A JSON structural context around an `IO` object. Structural writer contexts +define the behaviour of serializing JSON structural objects, such as objects, +arrays, and strings to JSON. The translation of Julia types to JSON structural +objects is not handled by a `JSONContext`, but by a `Serialization` wrapper +around it. Abstract supertype of `PrettyContext` and `CompactContext`. Data can +be written to a JSON context in the usual way, but often higher-level operations +such as `begin_array` or `begin_object` are preferred to directly writing bytes +to the stream. +""" +@compat abstract type JSONContext <: StructuralContext end + +""" +Internal implementation detail. + +Keeps track of the current location in the array or object, which winds and +unwinds during serialization. +""" +type PrettyContext{T<:IO} <: JSONContext + io::T + step::Int # number of spaces to step + state::Int # number of steps at present + first::Bool # whether an object/array was just started +end +PrettyContext(io::IO, step) = PrettyContext(io, step, 0, false) + +""" +Internal implementation detail. + +For compact printing, which in JSON is fully recursive. +""" +type CompactContext{T<:IO} <: JSONContext + io::T + first::Bool +end +CompactContext(io::IO) = CompactContext(io, false) + +""" +Internal implementation detail. + +Implements an IO context safe for printing into JSON strings. +""" +immutable StringContext{T<:IO} <: IO + io::T +end + +# These make defining additional methods on `show_json` easier. +const CS = Serializations.CommonSerialization +const SC = StructuralContext + +# Low-level direct access +Base.write(io::JSONContext, byte::UInt8) = write(io.io, byte) +Base.write(io::StringContext, byte::UInt8) = + write(io.io, ESCAPED_ARRAY[byte + 0x01]) +#= turn on if there's a performance benefit +write(io::StringContext, char::Char) = + char <= '\x7f' ? write(io, ESCAPED_ARRAY[@compat UInt8(c) + 0x01]) : + Base.print(io, c) +=# + +""" +Internal implementation detail. + +If appropriate, write a newline, then indent the IO by the appropriate number of +spaces. Otherwise, do nothing. +""" +@inline function indent(io::PrettyContext) + write(io, NEWLINE) + for _ in 1:io.state + write(io, SPACE) + end +end +@inline indent(io::CompactContext) = nothing + +""" +Internal implementation detail. + +Write a colon, followed by a space if appropriate. +""" +@inline separate(io::PrettyContext) = write(io, SEPARATOR, SPACE) +@inline separate(io::CompactContext) = write(io, SEPARATOR) + +""" +Internal implementation detail. + +If this is not the first item written in a collection, write a comma in the IO. +Otherwise, do not write a comma, but set a flag that the first element has been +written already. +""" +@inline function delimit(io::JSONContext) + if !io.first + write(io, DELIMITER) + end + io.first = false +end + +for kind in ("object", "array") + beginfn = Symbol("begin_", kind) + beginsym = Symbol(uppercase(kind), "_BEGIN") + endfn = Symbol("end_", kind) + endsym = Symbol(uppercase(kind), "_END") + # Begin and end objects + @eval function $beginfn(io::PrettyContext) + write(io, $beginsym) + io.state += io.step + io.first = true + end + @eval $beginfn(io::CompactContext) = (write(io, $beginsym); io.first = true) + @eval function $endfn(io::PrettyContext) + io.state -= io.step + if !io.first + indent(io) + end + write(io, $endsym) + io.first = false + end + @eval $endfn(io::CompactContext) = (write(io, $endsym); io.first = false) +end + +function show_string(io::IO, x) + write(io, STRING_DELIM) + Base.print(StringContext(io), x) + write(io, STRING_DELIM) +end + +show_null(io::IO) = Base.print(io, "null") + +function show_element(io::JSONContext, s, x) + delimit(io) + indent(io) + show_json(io, s, x) +end + +function show_key(io::JSONContext, k) + delimit(io) + indent(io) + show_string(io, k) + separate(io) +end + +function show_pair(io::JSONContext, s, k, v) + show_key(io, k) + show_json(io, s, v) +end +show_pair(io::JSONContext, s, kv) = show_pair(io, s, first(kv), last(kv)) + +# Default serialization rules for CommonSerialization (CS) +show_json(io::SC, ::CS, x::Union{AbstractString, Symbol}) = show_string(io, x) + +function show_json(io::SC, s::CS, x::Union{Integer, AbstractFloat}) + # workaround for issue in Julia 0.5.x where Float32 values are printed as + # 3.4f-5 instead of 3.4e-5 + @static if v"0.5-" <= VERSION < v"0.6.0-dev.788" + if isa(x, Float32) + return show_json(io, s, Float64(x)) + end + end + if isfinite(x) + Base.print(io, x) + else + show_null(io) + end +end + +show_json(io::SC, ::CS, ::Void) = show_null(io) + +function show_json(io::SC, s::CS, a::Nullable) + if isnull(a) + Base.print(io, "null") + else + show_json(io, s, get(a)) + end +end + +function show_json(io::SC, s::CS, a::Associative) + begin_object(io) + for kv in a + show_pair(io, s, kv) + end + end_object(io) +end + +function show_json(io::SC, s::CS, x::CompositeTypeWrapper) + begin_object(io) + fns = x.fns + for k in 1:length(fns) + show_pair(io, s, fns[k], getfield(x.wrapped, k)) + end + end_object(io) +end + +function show_json(io::SC, s::CS, x::Union{AbstractVector, Tuple}) + begin_array(io) + for elt in x + show_element(io, s, elt) + end + end_array(io) +end + +""" +Serialize a multidimensional array to JSON in column-major format. That is, +`json([1 2 3; 4 5 6]) == "[[1,4],[2,5],[3,6]]"`. +""" +function show_json{T,n}(io::SC, s::CS, A::AbstractArray{T,n}) + begin_array(io) + newdims = ntuple(_ -> :, Val{n - 1}) + for j in 1:size(A, n) + show_element(io, s, Compat.view(A, newdims..., j)) + end + end_array(io) +end + +show_json(io::SC, s::CS, a) = show_json(io, s, lower(a)) + +# Fallback show_json for non-SC types +""" +Serialize Julia object `obj` to IO `io` using the behaviour described by `s`. If +`indent` is provided, then the JSON will be pretty-printed; otherwise it will be +printed on one line. If pretty-printing is enabled, then a trailing newline will +be printed; otherwise there will be no trailing newline. +""" +function show_json(io::IO, s::Serializations.Serialization, obj; indent=nothing) + ctx = indent === nothing ? CompactContext(io) : PrettyContext(io, indent) + show_json(ctx, s, obj) + if indent !== nothing + println(io) + end +end + +print(io::IO, obj, indent) = + show_json(io, StandardSerialization(), obj; indent=indent) +print(io::IO, obj) = show_json(io, StandardSerialization(), obj) + +print(a, indent) = print(STDOUT, a, indent) +print(a) = print(STDOUT, a) + +json(a) = sprint(JSON.print, a) +json(a, indent) = sprint(JSON.print, a, indent) + +function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict{Compat.UTF8String, Any}, use_mmap=true) + sz = filesize(filename) + open(filename) do io + s = use_mmap ? Compat.UTF8String(Mmap.mmap(io, Vector{UInt8}, sz)) : readstring(io) + JSON.parse(s; dicttype=dicttype) + end +end + +end # module From fc4959b36da7008a1968789fa58d4e6373729216 Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Wed, 12 Apr 2017 16:54:38 -0400 Subject: [PATCH 2/2] Reorganize some code --- src/JSON.jl | 323 +--------------------- src/Parser.jl | 13 +- src/Writer.jl | 85 +++--- test/json-checker.jl | 2 +- test/{json_samples.jl => json-samples.jl} | 0 test/runtests.jl | 2 +- 6 files changed, 70 insertions(+), 355 deletions(-) rename test/{json_samples.jl => json-samples.jl} (100%) diff --git a/src/JSON.jl b/src/JSON.jl index 296c756..4939032 100644 --- a/src/JSON.jl +++ b/src/JSON.jl @@ -1,4 +1,4 @@ -isdefined(Base, :__precompile__) && __precompile__() +__precompile__() module JSON @@ -13,315 +13,16 @@ include("Parser.jl") # Writer modules include("Serializations.jl") - -using .Common -import .Parser.parse -import .Serializations.StandardSerialization - -""" -Internal JSON.jl implementation detail; do not depend on this type. - -A JSON primitive that wraps around any composite type to enable `Dict`-like -serialization. -""" -immutable CompositeTypeWrapper{T} - wrapped::T - fns::Vector{Symbol} -end -CompositeTypeWrapper(x) = CompositeTypeWrapper(x, fieldnames(x)) - -const JSONPrimitive = Union{ - Associative, Tuple, AbstractArray, AbstractString, Integer, - AbstractFloat, Void, CompositeTypeWrapper} - -""" -Return a value of a JSON-encodable primitive type that `x` should be lowered -into before encoding as JSON. Supported types are: `Associative` to JSON -objects, `Tuple` and `AbstractVector` to JSON arrays, `AbstractArray` to nested -JSON arrays, `AbstractString` to JSON string, `Integer` and `AbstractFloat` to -JSON number, `Bool` to JSON boolean, and `Void` to JSON null. - -Extensions of this method should preserve the property that the return value is -one of the aforementioned types. If first lowering to some intermediate type is -required, then extensions should call `lower` before returning a value. - -Note that the return value need not be *recursively* lowered—this function may -for instance return an `AbstractArray{Any, 1}` whose elements are not JSON -primitives. -""" -function lower(a) - if nfields(typeof(a)) > 0 - CompositeTypeWrapper(a) - else - error("Cannot serialize type $(typeof(a))") - end -end - -if isdefined(Base, :Dates) - lower(s::Base.Dates.TimeType) = string(s) -end - -if VERSION < v"0.5.0-dev+2396" - lower(f::Function) = "function at $(f.fptr)" -end - -lower(c::Char) = string(c) -lower(d::Type) = string(d) -lower(m::Module) = throw(ArgumentError("cannot serialize Module $m as JSON")) -lower(x::Real) = Float64(x) - -""" -Abstract supertype of all JSON and JSON-like structural writer contexts. -""" -@compat abstract type StructuralContext <: IO end - -""" -Internal implementation detail. - -A JSON structural context around an `IO` object. Structural writer contexts -define the behaviour of serializing JSON structural objects, such as objects, -arrays, and strings to JSON. The translation of Julia types to JSON structural -objects is not handled by a `JSONContext`, but by a `Serialization` wrapper -around it. Abstract supertype of `PrettyContext` and `CompactContext`. Data can -be written to a JSON context in the usual way, but often higher-level operations -such as `begin_array` or `begin_object` are preferred to directly writing bytes -to the stream. -""" -@compat abstract type JSONContext <: StructuralContext end - -""" -Internal implementation detail. - -Keeps track of the current location in the array or object, which winds and -unwinds during serialization. -""" -type PrettyContext{T<:IO} <: JSONContext - io::T - step::Int # number of spaces to step - state::Int # number of steps at present - first::Bool # whether an object/array was just started -end -PrettyContext(io::IO, step) = PrettyContext(io, step, 0, false) - -""" -Internal implementation detail. - -For compact printing, which in JSON is fully recursive. -""" -type CompactContext{T<:IO} <: JSONContext - io::T - first::Bool -end -CompactContext(io::IO) = CompactContext(io, false) - -""" -Internal implementation detail. - -Implements an IO context safe for printing into JSON strings. -""" -immutable StringContext{T<:IO} <: IO - io::T -end - -# These make defining additional methods on `show_json` easier. -const CS = Serializations.CommonSerialization -const SC = StructuralContext - -# Low-level direct access -Base.write(io::JSONContext, byte::UInt8) = write(io.io, byte) -Base.write(io::StringContext, byte::UInt8) = - write(io.io, ESCAPED_ARRAY[byte + 0x01]) -#= turn on if there's a performance benefit -write(io::StringContext, char::Char) = - char <= '\x7f' ? write(io, ESCAPED_ARRAY[@compat UInt8(c) + 0x01]) : - Base.print(io, c) -=# - -""" -Internal implementation detail. - -If appropriate, write a newline, then indent the IO by the appropriate number of -spaces. Otherwise, do nothing. -""" -@inline function indent(io::PrettyContext) - write(io, NEWLINE) - for _ in 1:io.state - write(io, SPACE) - end -end -@inline indent(io::CompactContext) = nothing - -""" -Internal implementation detail. - -Write a colon, followed by a space if appropriate. -""" -@inline separate(io::PrettyContext) = write(io, SEPARATOR, SPACE) -@inline separate(io::CompactContext) = write(io, SEPARATOR) - -""" -Internal implementation detail. - -If this is not the first item written in a collection, write a comma in the IO. -Otherwise, do not write a comma, but set a flag that the first element has been -written already. -""" -@inline function delimit(io::JSONContext) - if !io.first - write(io, DELIMITER) - end - io.first = false -end - -for kind in ("object", "array") - beginfn = Symbol("begin_", kind) - beginsym = Symbol(uppercase(kind), "_BEGIN") - endfn = Symbol("end_", kind) - endsym = Symbol(uppercase(kind), "_END") - # Begin and end objects - @eval function $beginfn(io::PrettyContext) - write(io, $beginsym) - io.state += io.step - io.first = true - end - @eval $beginfn(io::CompactContext) = (write(io, $beginsym); io.first = true) - @eval function $endfn(io::PrettyContext) - io.state -= io.step - if !io.first - indent(io) - end - write(io, $endsym) - io.first = false - end - @eval $endfn(io::CompactContext) = (write(io, $endsym); io.first = false) -end - -function show_string(io::IO, x) - write(io, STRING_DELIM) - Base.print(StringContext(io), x) - write(io, STRING_DELIM) -end - -show_null(io::IO) = Base.print(io, "null") - -function show_element(io::JSONContext, s, x) - delimit(io) - indent(io) - show_json(io, s, x) -end - -function show_key(io::JSONContext, k) - delimit(io) - indent(io) - show_string(io, k) - separate(io) -end - -function show_pair(io::JSONContext, s, k, v) - show_key(io, k) - show_json(io, s, v) -end -show_pair(io::JSONContext, s, kv) = show_pair(io, s, first(kv), last(kv)) - -# Default serialization rules for CommonSerialization (CS) -show_json(io::SC, ::CS, x::Union{AbstractString, Symbol}) = show_string(io, x) - -function show_json(io::SC, s::CS, x::Union{Integer, AbstractFloat}) - # workaround for issue in Julia 0.5.x where Float32 values are printed as - # 3.4f-5 instead of 3.4e-5 - @static if v"0.5-" <= VERSION < v"0.6.0-dev.788" - if isa(x, Float32) - return show_json(io, s, Float64(x)) - end - end - if isfinite(x) - Base.print(io, x) - else - show_null(io) - end -end - -show_json(io::SC, ::CS, ::Void) = show_null(io) - -function show_json(io::SC, s::CS, a::Nullable) - if isnull(a) - Base.print(io, "null") - else - show_json(io, s, get(a)) - end -end - -function show_json(io::SC, s::CS, a::Associative) - begin_object(io) - for kv in a - show_pair(io, s, kv) - end - end_object(io) -end - -function show_json(io::SC, s::CS, x::CompositeTypeWrapper) - begin_object(io) - fns = x.fns - for k in 1:length(fns) - show_pair(io, s, fns[k], getfield(x.wrapped, k)) - end - end_object(io) -end - -function show_json(io::SC, s::CS, x::Union{AbstractVector, Tuple}) - begin_array(io) - for elt in x - show_element(io, s, elt) - end - end_array(io) -end - -""" -Serialize a multidimensional array to JSON in column-major format. That is, -`json([1 2 3; 4 5 6]) == "[[1,4],[2,5],[3,6]]"`. -""" -function show_json{T,n}(io::SC, s::CS, A::AbstractArray{T,n}) - begin_array(io) - newdims = ntuple(_ -> :, Val{n - 1}) - for j in 1:size(A, n) - show_element(io, s, Compat.view(A, newdims..., j)) - end - end_array(io) -end - -show_json(io::SC, s::CS, a) = show_json(io, s, lower(a)) - -# Fallback show_json for non-SC types -""" -Serialize Julia object `obj` to IO `io` using the behaviour described by `s`. If -`indent` is provided, then the JSON will be pretty-printed; otherwise it will be -printed on one line. If pretty-printing is enabled, then a trailing newline will -be printed; otherwise there will be no trailing newline. -""" -function show_json(io::IO, s::Serializations.Serialization, obj; indent=nothing) - ctx = indent === nothing ? CompactContext(io) : PrettyContext(io, indent) - show_json(ctx, s, obj) - if indent !== nothing - println(io) - end -end - -print(io::IO, obj, indent) = - show_json(io, StandardSerialization(), obj; indent=indent) -print(io::IO, obj) = show_json(io, StandardSerialization(), obj) - -print(a, indent) = print(STDOUT, a, indent) -print(a) = print(STDOUT, a) - -json(a) = sprint(JSON.print, a) -json(a, indent) = sprint(JSON.print, a, indent) - -function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict{Compat.UTF8String, Any}, use_mmap=true) - sz = filesize(filename) - open(filename) do io - s = use_mmap ? Compat.UTF8String(Mmap.mmap(io, Vector{UInt8}, sz)) : readstring(io) - JSON.parse(s; dicttype=dicttype) - end -end +include("Writer.jl") + +# stuff to re-"export" +# note that this package does not actually export anything except `json` but +# all of the following are part of the public interface in one way or another +using .Parser: parse, parsefile +using .Writer: show_json, json, lower, print, StructuralContext, show_element, + show_string, show_key, show_pair, show_null, begin_array, + end_array, begin_object, end_object, indent, delimit, separate +using .Serializations: Serialization, CommonSerialization, + StandardSerialization end # module diff --git a/src/Parser.jl b/src/Parser.jl index 52611c6..d6938e6 100644 --- a/src/Parser.jl +++ b/src/Parser.jl @@ -3,9 +3,6 @@ module Parser # JSON using ..Common using Compat -import Compat: String - -export parse """ Like `isspace`, but work on bytes and includes only the four whitespace @@ -388,7 +385,15 @@ function parse{T<:Associative}(io::IO; dicttype::Type{T}=Dict{Compat.UTF8String, parse_value(ps, unparameterize_type(T)) end +function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict{Compat.UTF8String, Any}, use_mmap=true) + sz = filesize(filename) + open(filename) do io + s = use_mmap ? Compat.UTF8String(Mmap.mmap(io, Vector{UInt8}, sz)) : readstring(io) + parse(s; dicttype=dicttype) + end +end + # Efficient implementations of some of the above for in-memory parsing include("specialized.jl") -end #module Parser +end # module Parser diff --git a/src/Writer.jl b/src/Writer.jl index 296c756..63f7333 100644 --- a/src/Writer.jl +++ b/src/Writer.jl @@ -1,22 +1,9 @@ -isdefined(Base, :__precompile__) && __precompile__() - -module JSON +module Writer using Compat - -export json # returns a compact (or indented) JSON representation as a string - -include("Common.jl") - -# Parser modules -include("Parser.jl") - -# Writer modules -include("Serializations.jl") - -using .Common -import .Parser.parse -import .Serializations.StandardSerialization +using ..Common +using ..Serializations: Serialization, StandardSerialization, + CommonSerialization """ Internal JSON.jl implementation detail; do not depend on this type. @@ -35,6 +22,8 @@ const JSONPrimitive = Union{ AbstractFloat, Void, CompositeTypeWrapper} """ + lower(x) + Return a value of a JSON-encodable primitive type that `x` should be lowered into before encoding as JSON. Supported types are: `Associative` to JSON objects, `Tuple` and `AbstractVector` to JSON arrays, `AbstractArray` to nested @@ -124,7 +113,7 @@ immutable StringContext{T<:IO} <: IO end # These make defining additional methods on `show_json` easier. -const CS = Serializations.CommonSerialization +const CS = CommonSerialization const SC = StructuralContext # Low-level direct access @@ -138,10 +127,10 @@ write(io::StringContext, char::Char) = =# """ -Internal implementation detail. + indent(io::StructuralContext) -If appropriate, write a newline, then indent the IO by the appropriate number of -spaces. Otherwise, do nothing. +If appropriate, write a newline to the given context, then indent it by the +appropriate number of spaces. Otherwise, do nothing. """ @inline function indent(io::PrettyContext) write(io, NEWLINE) @@ -152,19 +141,19 @@ end @inline indent(io::CompactContext) = nothing """ -Internal implementation detail. + separate(io::StructuralContext) -Write a colon, followed by a space if appropriate. +Write a colon, followed by a space if appropriate, to the given context. """ @inline separate(io::PrettyContext) = write(io, SEPARATOR, SPACE) @inline separate(io::CompactContext) = write(io, SEPARATOR) """ -Internal implementation detail. + delimit(io::StructuralContext) -If this is not the first item written in a collection, write a comma in the IO. -Otherwise, do not write a comma, but set a flag that the first element has been -written already. +If this is not the first item written in a collection, write a comma in the +structural context. Otherwise, do not write a comma, but set a flag that the +first element has been written already. """ @inline function delimit(io::JSONContext) if !io.first @@ -196,20 +185,42 @@ for kind in ("object", "array") @eval $endfn(io::CompactContext) = (write(io, $endsym); io.first = false) end +""" + show_string(io::IO, str) + +Print `str` as a JSON string (that is, properly escaped and wrapped by double +quotes) to the given IO object `io`. +""" function show_string(io::IO, x) write(io, STRING_DELIM) Base.print(StringContext(io), x) write(io, STRING_DELIM) end +""" + show_null(io::IO) + +Print the string `null` to the given IO object `io`. +""" show_null(io::IO) = Base.print(io, "null") +""" + show_element(io::StructuralContext, s, x) + +Print object `x` as an element of a JSON array to context `io` using rules +defined by serialization `s`. +""" function show_element(io::JSONContext, s, x) delimit(io) indent(io) show_json(io, s, x) end +""" + show_key(io::StructuralContext, k) + +Print string `k` as the key of a JSON key-value pair to context `io`. +""" function show_key(io::JSONContext, k) delimit(io) indent(io) @@ -217,6 +228,12 @@ function show_key(io::JSONContext, k) separate(io) end +""" + show_pair(io::StructuralContext, s, k, v) + +Print the key-value pair defined by `k => v` as JSON to context `io`, using +rules defined by serialization `s`. +""" function show_pair(io::JSONContext, s, k, v) show_key(io, k) show_json(io, s, v) @@ -298,7 +315,7 @@ Serialize Julia object `obj` to IO `io` using the behaviour described by `s`. If printed on one line. If pretty-printing is enabled, then a trailing newline will be printed; otherwise there will be no trailing newline. """ -function show_json(io::IO, s::Serializations.Serialization, obj; indent=nothing) +function show_json(io::IO, s::Serialization, obj; indent=nothing) ctx = indent === nothing ? CompactContext(io) : PrettyContext(io, indent) show_json(ctx, s, obj) if indent !== nothing @@ -313,15 +330,7 @@ print(io::IO, obj) = show_json(io, StandardSerialization(), obj) print(a, indent) = print(STDOUT, a, indent) print(a) = print(STDOUT, a) -json(a) = sprint(JSON.print, a) -json(a, indent) = sprint(JSON.print, a, indent) +json(a) = sprint(print, a) +json(a, indent) = sprint(print, a, indent) -function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict{Compat.UTF8String, Any}, use_mmap=true) - sz = filesize(filename) - open(filename) do io - s = use_mmap ? Compat.UTF8String(Mmap.mmap(io, Vector{UInt8}, sz)) : readstring(io) - JSON.parse(s; dicttype=dicttype) - end end - -end # module diff --git a/test/json-checker.jl b/test/json-checker.jl index 7ec16d4..48acc44 100644 --- a/test/json-checker.jl +++ b/test/json-checker.jl @@ -1,6 +1,6 @@ # Run modified JSON checker tests -const JSON_DATA_DIR = joinpath(dirname(dirname(@__FILE__)), "data") +const JSON_DATA_DIR = joinpath(dirname(@__DIR__), "data") for i in 1:38 file = "fail$(lpad(i, 2, 0)).json" diff --git a/test/json_samples.jl b/test/json-samples.jl similarity index 100% rename from test/json_samples.jl rename to test/json-samples.jl diff --git a/test/runtests.jl b/test/runtests.jl index f44ec45..7bba04b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,7 +6,7 @@ import Compat: String import DataStructures include("json-checker.jl") -include(joinpath(dirname(@__FILE__),"json_samples.jl")) +include("json-samples.jl") @test JSON.parse("{\"x\": 3}", dicttype=DataStructures.OrderedDict) == DataStructures.OrderedDict{AbstractString,Any}([("x",3)]) @test JSON.parse("{\"x\": 3}", dicttype=Dict{Symbol,Int32}) == Dict{Symbol,Int32}([(:x,3)])