From a36ec39a21dd5198f788fe8b1fbcb7ed058769b0 Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Sun, 24 Sep 2017 22:11:58 -0400 Subject: [PATCH] Drop v0.5 support, Compat dependency (#217) * Drop v0.5 support, Compat dependency * Stop testing on 0.5 in CI --- .travis.yml | 1 - REQUIRE | 3 +- appveyor.yml | 2 -- src/Common.jl | 6 ---- src/JSON.jl | 2 -- src/Parser.jl | 28 +++++++-------- src/Serializations.jl | 16 ++++----- src/Writer.jl | 68 +++++++++++++++++-------------------- src/bytes.jl | 2 +- src/specialized.jl | 4 +-- test/REQUIRE | 1 + test/lowering.jl | 7 ++-- test/regression/issue109.jl | 5 ++- test/serializer.jl | 15 ++++---- 14 files changed, 66 insertions(+), 94 deletions(-) diff --git a/.travis.yml b/.travis.yml index b805f4d..868e9a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ os: - osx - linux julia: - - 0.5 - 0.6 - nightly notifications: diff --git a/REQUIRE b/REQUIRE index 1992b52..137767a 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1 @@ -julia 0.5 -Compat 0.31.0 +julia 0.6 diff --git a/appveyor.yml b/appveyor.yml index 738db1a..fde4cb5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,5 @@ environment: matrix: - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe" - - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe" - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe" - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" diff --git a/src/Common.jl b/src/Common.jl index 282b78b..65fd062 100644 --- a/src/Common.jl +++ b/src/Common.jl @@ -3,12 +3,6 @@ Internal implementation detail. """ module Common -using Compat - -# The expression head to use for constructing types. -# TODO: Remove this hack when 0.5 support is dropped. -const STRUCTHEAD = VERSION < v"0.7.0-DEV.1263" ? :type : :struct - include("bytes.jl") include("errors.jl") diff --git a/src/JSON.jl b/src/JSON.jl index 4939032..e95ab16 100644 --- a/src/JSON.jl +++ b/src/JSON.jl @@ -2,8 +2,6 @@ __precompile__() module JSON -using Compat - export json # returns a compact (or indented) JSON representation as a string include("Common.jl") diff --git a/src/Parser.jl b/src/Parser.jl index d6a289b..943e2e8 100644 --- a/src/Parser.jl +++ b/src/Parser.jl @@ -2,8 +2,6 @@ module Parser # JSON using ..Common -using Compat - """ Like `isspace`, but work on bytes and includes only the four whitespace characters defined by the JSON standard: space, tab, line feed, and carriage @@ -16,21 +14,19 @@ Like `isdigit`, but for bytes. """ isjsondigit(b::UInt8) = DIGIT_ZERO ≤ b ≤ DIGIT_NINE -@compat abstract type ParserState end +abstract type ParserState end -eval(Expr(Common.STRUCTHEAD, true, :(MemoryParserState <: ParserState), -quote +mutable struct MemoryParserState <: ParserState utf8data::Vector{UInt8} s::Int -end)) +end -eval(Expr(Common.STRUCTHEAD, true, :(StreamingParserState{T <: IO} <: ParserState), -quote +mutable struct StreamingParserState{T <: IO} <: ParserState io::T cur::UInt8 used::Bool -end)) -StreamingParserState{T <: IO}(io::T) = StreamingParserState{T}(io, 0x00, true) +end +StreamingParserState(io::IO) = StreamingParserState(io, 0x00, true) """ Return the byte at the current position of the `ParserState`. If there is no @@ -367,14 +363,14 @@ function parse_number(ps::ParserState) end -function unparameterize_type{T}(::Type{T}) +function unparameterize_type(T::Type) candidate = typeintersect(T, Associative{String, Any}) candidate <: Union{} ? T : candidate end -function parse{T<:Associative}(str::AbstractString; dicttype::Type{T}=Dict{String,Any}) +function parse(str::AbstractString; dicttype::Type{<:Associative}=Dict{String,Any}) ps = MemoryParserState(Vector{UInt8}(String(str)), 1) - v = parse_value(ps, unparameterize_type(T)) + v = parse_value(ps, unparameterize_type(dicttype)) chomp_space!(ps) if hasmore(ps) _error(E_EXPECTED_EOF, ps) @@ -382,12 +378,12 @@ function parse{T<:Associative}(str::AbstractString; dicttype::Type{T}=Dict{Strin v end -function parse{T<:Associative}(io::IO; dicttype::Type{T}=Dict{String,Any}) +function parse(io::IO; dicttype::Type{<:Associative}=Dict{String,Any}) ps = StreamingParserState(io) - parse_value(ps, unparameterize_type(T)) + parse_value(ps, unparameterize_type(dicttype)) end -function parsefile{T<:Associative}(filename::AbstractString; dicttype::Type{T}=Dict{String, Any}, use_mmap=true) +function parsefile(filename::AbstractString; dicttype::Type{<:Associative}=Dict{String, Any}, use_mmap=true) sz = filesize(filename) open(filename) do io s = use_mmap ? String(Mmap.mmap(io, Vector{UInt8}, sz)) : read(io, String) diff --git a/src/Serializations.jl b/src/Serializations.jl index 0d88c58..6601879 100644 --- a/src/Serializations.jl +++ b/src/Serializations.jl @@ -7,27 +7,24 @@ implementations, as they relate to JSON. module Serializations -using Compat using ..Common """ A `Serialization` defines how objects are lowered to JSON format. """ -@compat abstract type Serialization end +abstract type Serialization end -@compat abstract type CommonSerialization <: Serialization end -@doc """ +""" The `CommonSerialization` comes with a default set of rules for serializing Julia types to their JSON equivalents. Additional rules are provided either by packages explicitly defining `JSON.show_json` for this serialization, or by the `JSON.lower` method. Most concrete implementations of serializers should subtype `CommonSerialization`, unless it is desirable to bypass the `lower` system, in which case `Serialization` should be subtyped. -""" CommonSerialization +""" +abstract type CommonSerialization <: Serialization end -eval(Expr(Common.STRUCTHEAD, false, :(StandardSerialization <: CommonSerialization), - quote end)) -@doc """ +""" The `StandardSerialization` defines a common, standard JSON serialization format that is optimized to: @@ -37,6 +34,7 @@ that is optimized to: All serializations defined for `CommonSerialization` are inherited by `StandardSerialization`. It is therefore generally advised to add new serialization behaviour to `CommonSerialization`. -""" StandardSerialization +""" +struct StandardSerialization <: CommonSerialization end end diff --git a/src/Writer.jl b/src/Writer.jl index 1b3601f..6fc45bc 100644 --- a/src/Writer.jl +++ b/src/Writer.jl @@ -1,21 +1,20 @@ module Writer -using Compat using ..Common using ..Serializations: Serialization, StandardSerialization, CommonSerialization -eval(Expr(Common.STRUCTHEAD, false, :(CompositeTypeWrapper{T}), -quote - wrapped::T - fns::Vector{Symbol} -end)) -@doc """ +""" 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. -""" CompositeTypeWrapper +""" +struct CompositeTypeWrapper{T} + wrapped::T + fns::Vector{Symbol} +end + CompositeTypeWrapper(x) = CompositeTypeWrapper(x, fieldnames(typeof(x))) """ @@ -60,7 +59,7 @@ lower(x::Base.AbstractSet) = collect(x) """ Abstract supertype of all JSON and JSON-like structural writer contexts. """ -@compat abstract type StructuralContext <: IO end +abstract type StructuralContext <: IO end """ Internal implementation detail. @@ -74,46 +73,43 @@ 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 +abstract type JSONContext <: StructuralContext end -eval(Expr(Common.STRUCTHEAD, true, :(PrettyContext{T<:IO} <: JSONContext), -quote - 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)) -@doc """ +""" Internal implementation detail. Keeps track of the current location in the array or object, which winds and unwinds during serialization. -""" PrettyContext +""" +mutable struct 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) -eval(Expr(Common.STRUCTHEAD, true, :(CompactContext{T<:IO} <: JSONContext), -quote - io::T - first::Bool -end)) -@doc """ +""" Internal implementation detail. For compact printing, which in JSON is fully recursive. -""" CompactContext +""" +mutable struct CompactContext{T<:IO} <: JSONContext + io::T + first::Bool +end CompactContext(io::IO) = CompactContext(io, false) -eval(Expr(Common.STRUCTHEAD, false, :(StringContext{T<:IO} <: IO), -quote - io::T -end)) -@doc """ +""" Internal implementation detail. Implements an IO context safe for printing into JSON strings. -""" StringContext +""" +struct StringContext{T<:IO} <: IO + io::T +end -# These make defining additional methods on `show_json` easier. +# These aliases make defining additional methods on `show_json` easier. const CS = CommonSerialization const SC = StructuralContext @@ -123,7 +119,7 @@ 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]) : + char <= '\x7f' ? write(io, ESCAPED_ARRAY[UInt8(c) + 0x01]) : Base.print(io, c) =# @@ -312,7 +308,7 @@ 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}) +function show_json(io::SC, s::CS, A::AbstractArray{<:Any,n}) where n begin_array(io) newdims = ntuple(_ -> :, n - 1) for j in indices(A, n) @@ -322,7 +318,7 @@ function show_json{T,n}(io::SC, s::CS, A::AbstractArray{T,n}) end # special case for 0-dimensional arrays -show_json{T}(io::SC, s::CS, A::AbstractArray{T,0}) = show_json(io, s, A[]) +show_json(io::SC, s::CS, A::AbstractArray{<:Any,0}) = show_json(io, s, A[]) show_json(io::SC, s::CS, a) = show_json(io, s, lower(a)) diff --git a/src/bytes.jl b/src/bytes.jl index 373b482..0a41eed 100644 --- a/src/bytes.jl +++ b/src/bytes.jl @@ -52,7 +52,7 @@ for c in 0x00:0xFF [c] # UTF-8 character copied verbatim elseif haskey(REVERSE_ESCAPES, c) [BACKSLASH, REVERSE_ESCAPES[c]] - elseif iscntrl(@compat Char(c)) || !isprint(@compat Char(c)) + elseif iscntrl(Char(c)) || !isprint(Char(c)) UInt8[BACKSLASH, LATIN_U, hex(c, 4)...] else [c] diff --git a/src/specialized.jl b/src/specialized.jl index 6ea57a2..e139c80 100644 --- a/src/specialized.jl +++ b/src/specialized.jl @@ -1,13 +1,11 @@ # Specialized functions for increased performance when JSON is in-memory -using Compat: StringVector - function parse_string(ps::MemoryParserState) # "Dry Run": find length of string so we can allocate the right amount of # memory from the start. Does not do full error checking. fastpath, len = predict_string(ps) # Now read the string itself - b = StringVector(len) + b = Base.StringVector(len) # Fast path occurs when the string has no escaped characters. This is quite # often the case in real-world data, especially when keys are short strings. diff --git a/test/REQUIRE b/test/REQUIRE index d0dacdd..e191e81 100644 --- a/test/REQUIRE +++ b/test/REQUIRE @@ -1,3 +1,4 @@ DataStructures FixedPointNumbers OffsetArrays +Compat 0.31.0 diff --git a/test/lowering.jl b/test/lowering.jl index 9eb3f29..96d2ce6 100644 --- a/test/lowering.jl +++ b/test/lowering.jl @@ -2,7 +2,6 @@ module TestLowering using JSON using Base.Test -using Compat using FixedPointNumbers: Fixed if isdefined(Base, :Dates) @@ -12,13 +11,13 @@ end @test JSON.json(:x) == "\"x\"" @test_throws ArgumentError JSON.json(Base) -eval(Expr(JSON.Common.STRUCTHEAD, false, :(Type151{T}), quote +struct Type151{T} x::T -end)) +end @test JSON.parse(JSON.json(Type151)) == string(Type151) -JSON.lower{T}(v::Type151{T}) = Dict(:type => T, :value => v.x) +JSON.lower(v::Type151{T}) where {T} = Dict(:type => T, :value => v.x) @test JSON.parse(JSON.json(Type151(1.0))) == Dict( "type" => "Float64", "value" => 1.0) diff --git a/test/regression/issue109.jl b/test/regression/issue109.jl index 0cf5b6d..6dc2d9d 100644 --- a/test/regression/issue109.jl +++ b/test/regression/issue109.jl @@ -1,7 +1,6 @@ -eval(Expr(JSON.Common.STRUCTHEAD, true, :t109, -quote +mutable struct t109 i::Int -end)) +end let iob = IOBuffer() JSON.print(iob, t109(1)) diff --git a/test/serializer.jl b/test/serializer.jl index 6584388..9c05fb0 100644 --- a/test/serializer.jl +++ b/test/serializer.jl @@ -2,7 +2,6 @@ module TestSerializer using JSON using Base.Test -using Compat # to define a new serialization behaviour, import these first import JSON.Serializations: CommonSerialization, StandardSerialization @@ -20,9 +19,8 @@ function sprint_kwarg(f, args...; kwargs...) end # issue #168: Print NaN and Inf as Julia would -eval(Expr(JSON.Common.STRUCTHEAD, false, :(NaNSerialization <: CS), quote end)) -JSON.show_json(io::SC, ::NaNSerialization, f::AbstractFloat) = - Base.print(io, f) +struct NaNSerialization <: CS end +JSON.show_json(io::SC, ::NaNSerialization, f::AbstractFloat) = Base.print(io, f) @test sprint(JSON.show_json, NaNSerialization(), [NaN, Inf, -Inf, 0.0]) == "[NaN,Inf,-Inf,0.0]" @@ -42,11 +40,10 @@ JSON.show_json(io::SC, ::NaNSerialization, f::AbstractFloat) = """ # issue #170: Print JavaScript functions directly -eval(Expr(JSON.Common.STRUCTHEAD, false, :(JSSerialization <: CS), quote end)) -eval(Expr(JSON.Common.STRUCTHEAD, false, :JSFunction, -quote +struct JSSerialization <: CS end +struct JSFunction data::String -end)) +end function JSON.show_json(io::SC, ::JSSerialization, f::JSFunction) first = true @@ -74,7 +71,7 @@ end """ # test serializing a type without any fields -eval(Expr(JSON.Common.STRUCTHEAD, false, :SingletonType, quote end)) +struct SingletonType end @test_throws ErrorException json(SingletonType()) # test printing to STDOUT