Mercurial > lbo > hg > juliaplay
view julia/parallel/ParallelProcessing/src/metaparser.jl @ 37:37a528750178
Make JSON struct parser generator work
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 24 Mar 2023 22:07:52 +0100 |
parents | 03d20a4dd8f2 |
children | bae384998d85 |
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] fieldnames = [name for (name, _) in typs] Mod = :ParallelProcessing 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 = $Mod.$(method)(jp) matched = true end end for (name, method) in methods ] quote $strct function ParallelProcessing.take_struct!( ::Type{$typ}, jp::$(Mod).JP, )::Union{Nothing,$typ} $Mod.expect!(jp, '{') || return nothing $(fieldvars...) while true key = $Mod.take_str!(jp) if isnothing(key) break end $Mod.expect!(jp, ':') || error("malformed object - expected ':'") matched = false $(field_dispatch...) if !matched $Mod.take_val!(jp) end if $Mod.expect!(jp, ',') continue else break end end #if $(fields_filled_cond...) # error("Elements missing from object") #end $Mod.expect!(jp, '}') || error("unclosed object") $(typ)($(fieldnames...)) end end |> esc end macro json_parseable(strct) json_parseable(strct) end