Mercurial > lbo > hg > juliaplay
view julia/parallel/ParallelProcessing/src/jsonparser.jl @ 32:3d916aa02d00
Implement basic JSON parser
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 19 Mar 2023 20:04:34 +0100 |
parents | |
children | 2d033830c26e |
line wrap: on
line source
mutable struct JP s::String pos::Int end function JP(s::AbstractString)::JP JP(string(s), 1) end function current(jp::JP)::Char jp.s[jp.pos] end function next!(jp::JP) jp.pos += 1 end function isend(jp::JP) jp.pos > length(jp.s) end function take_num!(jp::JP)::Union{Nothing,Float64} pred(c) = isdigit(c) || (c == '.') # todo: exponential numbers span = takewhile!(jp, pred) if isnothing(span) nothing else a, b = span parse(Float64, (@view jp.s[a:b])) end end function take_bool!(jp::JP)::Union{Nothing,Bool} if expect_prefix!(jp, "true") true elseif expect_prefix!(jp, "false") false else nothing end end function take_dict!(jp::JP)::Union{Nothing,Dict{String,Any}} expect!(jp, '{') || return nothing d = Dict{String,Any}() while true key = take_str!(jp) if isnothing(key) # Empty dict break end expect!(jp, ':') || error("malformatted dict - expecting ':'") val = take_obj!(jp) d[key] = val if expect!(jp, ',') continue else # End of dict break end end expect!(jp, '}') || error("Unclosed dict - '}' missing") d end function take_str!(jp::JP)::Union{Nothing,String} expect!(jp, '"') || return nothing span = takewhile!(jp, (!=)('"')) if isnothing(span) error("unclosed string at $(jp.pos)") end expect!(jp, '"') || error("unclosed string at $(jp.pos)") a, b = span jp.s[a:b] end function take_list!(jp::JP)::Union{Nothing,Vector{Any}} expect!(jp, '[') || return nothing l = Any[] while true o = take_obj!(jp) if isnothing(o) break else push!(l, o) end if expect!(jp, ',') continue else break end end expect!(jp, ']') || error("Missing closing ']' at $(jp.pos)") l end function take_obj!(jp::JP)::Union{Nothing,Any} d = take_dict!(jp) if !isnothing(d) return d end n = take_num!(jp) if !isnothing(n) return n end s = take_str!(jp) if !isnothing(s) return s end b = take_bool!(jp) if !isnothing(b) return b end l = take_list!(jp) if !isnothing(l) return l end nothing end function parse_object(s::AbstractString) jp = JP(s) take_obj!(jp) end function takewhile!(jp::JP, pred::Function, stripws=true)::Union{Nothing,Tuple{Int,Int}} if stripws strip_ws!(jp) end if !isend(jp) && pred(current(jp)) a = jp.pos b = a while !isend(jp) && pred(current(jp)) next!(jp) b += 1 end (a, b-1) else nothing end end function strip_ws!(jp::JP) while !isend(jp) && isspace(jp.s[jp.pos]) jp.pos += 1 end end function expect!(jp::JP, c::Char)::Bool strip_ws!(jp) if current(jp) == c next!(jp) true else false end end function expect_prefix!(jp::JP, pref::AbstractString)::Bool strip_ws!(jp) if (@view jp.s[jp.pos:min(length(jp.s), jp.pos+length(pref)-1)]) == pref jp.pos += length(pref) true else false end end