Mercurial > lbo > hg > juliaplay
view julia/parallel/ParallelProcessing/src/metaparser.jl @ 36:03d20a4dd8f2
json: metaparser
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 24 Mar 2023 21:30:03 +0100 |
parents | |
children | 37a528750178 |
line wrap: on
line source
function parse_struct(s::Expr) s.head == :struct || error("Expr must be struct but is $s") args = s.args[2:end] typedef = args[1] fields = args[2] fields.head == :block || error("Expr must contain a block but has $fields") fields_exprs = Pair[] for f in fields.args if typeof(f) == LineNumberNode continue end typeof(f) == Expr || error("Field $f in $typedef must have type!") f.head == :(::) || error( "Field $f in $typedef must be type! (we don't support constructors etc. - struct must be plain)", ) name, typ = f.args typeof(typ) == Symbol || error("Type of $f should be symbol (simple type) but is $(typeof(typ)): $typ") typ = eval(typ) isconcretetype(typ) || error("Type of field $name must be concrete, but is not (is $typ)!") push!(fields_exprs, name => eval(typ)) end fields_exprs end function get_type_of_struct(s::Expr) s.head == :struct || error("Expr must be struct, is $s") typedef = s.args[2] if typeof(typedef) == Symbol typedef elseif typeof(typedef) == Expr error("We don't support generic structs yet :(") end end function json_parseable(strct) typs::Vector{Pair{Symbol,Type}} = parse_struct(strct) typ = get_type_of_struct(strct) fieldvars = [:($(name)::Union{$typ,Nothing} = nothing) for (name, typ) in typs] method_map = Dict( Int64 => :take_num!, Float64 => :take_num!, String => :take_str!, Dict => :take_object!, Bool => :take_bool!, ) methods = [(name, method_map[typ]) for (name, typ) in typs] field_dispatch = [ quote if !matched && key == $(string(name)) $name = $(method)(jp) matched = true end end for (name, method) in methods ] quote $strct function ParallelProcessing.take_struct!( ::Type{$(esc(typ))}, jp::JP, )::Union{Nothing,$typ} expect!(jp, '{') || return nothing $(fieldvars...) while true key = take_str!(jp) if isnothing(key) break end matched = false $(field_dispatch...) if !matched take_val!(jp) end if expect!(jp, ',') continue else break end end if isnothing(level) || isnothing(kind) error("Elements missing from object: $level, $kind") end expect!(jp, '}') || error("unclosed Details object") Details(level, kind) end end end macro json_parseable(strct) json_parseable(strct) end function take_struct_!(::Type{Details}, jp::JP)::Union{Nothing,Details} expect!(jp, '{') || return nothing level::Union{Nothing,String} = nothing kind::Union{Nothing,Int} = nothing while true key = take_str!(jp) if isnothing(key) break end expect!(jp, ':') || error("malformed object - expected ':'") # Custom code! if key == "level" level = take_str!(jp) elseif key == "kind" kind = take_num!(jp) else # Ignore unknown keys take_val!(jp) end if expect!(jp, ',') continue else break end end if isnothing(level) || isnothing(kind) error("Elements missing from object: $level, $kind") end expect!(jp, '}') || error("unclosed Details object") Details(level, kind) end