# Json/bson dsl

**URL:** <https://discourse.julialang.org/t/json-bson-dsl/79940>\
**Category:** General Usage\
**Tags:** json\
**Created:** [April 24, 2022, 12:42pm UTC](https://discourse.julialang.org/t/json-bson-dsl/79940 "2022-04-24T12:42:57Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [April 24, 2022, 12:42pm UTC](https://discourse.julialang.org/t/json-bson-dsl/79940/1 "2022-04-24T12:42:57Z")

</div>

Hi,

I’ve been playing a bit with `Mongoc` which is a thin layer on top of the MongoDB C library. MongoDB is leaning _heavily_ into JSON, which makes for non-intuitive code (from the [Mongoc docs](https://felipenoris.github.io/Mongoc.jl/stable/tutorial/#Create-Index)):

```julia
create_indexes_cmd = Mongoc.BSON(
        "createIndexes" => collection_name,
        "indexes" => [Mongoc.BSON("key" => Mongoc.BSON("group" => 1), "name" => "group_index")]
    )

```

Julia is an amazing language for making your own DSL. I’m wondering why no one implemented a JSON DSL? This seems quite easy.

It took me ~ 30 minutes to hack the following (I’ve never written a Julia macro before):

```julia
parse_expr(e) = e

function parse_expr(e::Expr)
    if e.head == :braces
        d = Dict()
        for f in e.args
            f isa Expr || error("not a valid JSON")
            if f.head == :call
                f.args[1] == :(:) || error("not a valid JSON")
                f2 = f.args[2]
                typeof(f2) ∈ (Symbol, String) || error("not a valid JSON")
                v = parse_expr(f.args[3])
                d[f2] = v
            end
        end
        return d
    elseif e.head == :vect
        v = similar(e.args)
        for i in eachindex(e.args)
            a = 
            v[i] = parse_expr(e.args[i])
        end
        return v
    end
end

macro json(e)
    return parse_expr(e)
end

@json { a: [{"b": "c"}, 5, 2.0] }

# returns:
# Dict{Any, Any} with 1 entry:
# :a => Any[Dict{Any, Any}("b"=>"c"), 5, 2.0]

```

The Mongoc example from above then becomes:

```julia
j = @json {"createIndexes": "collname",
        "indexes" : [{ "key": {"group": 1}, "name" : "group_index" }] }

@show j
#j = Dict{Any, Any}("createIndexes" => "collname", "indexes" => Any[Dict{Any, Any}("key" => Dict{Any, Any}("group" => 1), "name" => "group_index")]) 

```

---

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [April 25, 2022, 3:16pm UTC](https://discourse.julialang.org/t/json-bson-dsl/79940/2 "2022-04-25T15:16:44Z")

</div>

A better version, now supporting local variables:

```julia
json(n) = n
json(n::Symbol) = esc(n)

function json(n::Expr)
    if n.head == :vect
        return Expr(:vect, map(json, n.args)...)
    elseif n.head == :braces
        kv = []
        for f in n.args
            f isa Expr || error("not a valid JSON")
            f.args[1] == :(:) || error("not a valid JSON")
            k = f.args[2]

            typeof(k) ∈ (Symbol, String) || error("not a valid JSON")
            k = string(k)
            v = json(f.args[3])
            push!(kv, :($k=>$v))
        end
        return :(Dict{String, Any}($(kv...)))
    else
        return esc(n)
    end
end

macro json(n)
    return json(n)
end

function aa()
    i = 2
    j = 3
    return @json({a : {b:i}, "c": [1,2,3.0], "d": i+j})
end

aa()
# Dict{String, Any} with 3 entries:
# "c" => [1.0, 2.0, 3.0]
# "a" => Dict{String, Any}("b"=>2)
# "d" => 5

```
