Mercurial > lbo > hg > juliaplay
changeset 32:3d916aa02d00
Implement basic JSON parser
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 19 Mar 2023 20:04:34 +0100 |
parents | e3af2d3890ce |
children | 2d033830c26e |
files | julia/parallel/ParallelProcessing/src/ParallelProcessing.jl julia/parallel/ParallelProcessing/src/jsonparser.jl |
diffstat | 2 files changed, 180 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/julia/parallel/ParallelProcessing/src/ParallelProcessing.jl Sun Mar 19 13:09:54 2023 +0100 +++ b/julia/parallel/ParallelProcessing/src/ParallelProcessing.jl Sun Mar 19 20:04:34 2023 +0100 @@ -1,5 +1,5 @@ module ParallelProcessing include("json.jl") - +include("jsonparser.jl") end # module ParallelProcessing
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/julia/parallel/ParallelProcessing/src/jsonparser.jl Sun Mar 19 20:04:34 2023 +0100 @@ -0,0 +1,179 @@ + +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