Macros can only operate on syntactically valid Julia code, since they always operate on expression objects. Single quotes ('
) in Julia always denote single-character literals, so something like 'abc'
is not valid syntax, so this will error during parsing. Disallowing multi-character strings enclosed with single quotes was a conscious decision, because otherwise you would get parsing ambiguities, since '
is also a postfix operator for adjoint
. For this specific case, a non-standard string literal would probably make more sense.
5 Likes
Thanks for the explanation. Did I understood you correctly that:
@js { d: 'thirty', 123 }
is not possible, but
js"{ d: 'thirty', 123 }"
could be?
4 Likes
Yes! It should be as simple as:
using JSON3
macro js_str(s)
return :(JSON3.read($s))
end
4 Likes
Thanks. Pretty cool! However, the same problem persists:
julia> using JSON3
julia> macro js_str(s)
return :(JSON3.read($s))
end
@js_str (macro with 1 method)
julia> js"{\"a_number\" : 5.0, \"an_array\" : [\"string\", 9]}"
Dict{String,Any} with 2 entries:
"an_array" => Any["string", 9]
"a_number" => 5.0
julia> js"{'a_number' : 5.0, 'an_array' : ['string', 9]}"
ERROR: Invalid object key
Line: 0
Around: ...{'a_number' : 5.0, 'an...
^
Stacktrace:
[1] error(::String) at .\error.jl:33
[2] _error(::String, ::JSON.Parser.MemoryParserState) at C:\Users\tfr004\.julia\packages\JSON\d89fA\src\Parser.jl:142
[3] parse_object(::JSON.Parser.ParserContext{Dict{String,Any},Int64,true,nothing}, ::JSON.Parser.MemoryParserState) at C:\Users\tfr004\.julia\packages\JSON\d89fA\src\Parser.jl:227
[4] parse_value(::JSON.Parser.ParserContext{Dict{String,Any},Int64,true,nothing}, ::JSON.Parser.MemoryParserState) at C:\Users\tfr004\.julia\packages\JSON\d89fA\src\Parser.jl:168
[5] #parse#1(::Type, ::Type{Int64}, ::Bool, ::Nothing, ::typeof(JSON.Parser.parse), ::String) at C:\Users\tfr004\.julia\packages\JSON\d89fA\src\Parser.jl:463
[6] parse(::String) at C:\Users\tfr004\.julia\packages\JSON\d89fA\src\Parser.jl:461
[7] top-level scope at REPL[16]:1
julia>
Possibly because 'key'
is not valid JSON syntax. You need "key"
. And then probably you want """
to make your life easier, eg
julia> js"""{"a_number" : 5.0, "an_array" : ["string", 9]}"""
JSON3.Object{Base.CodeUnits{UInt8,String},Array{UInt64,1}} with 2 entries:
:a_number => 5
:an_array => Any["string", 9]
2 Likes
Have a look at Simon’s JSServe.jl
https://github.com/SimonDanisch/JSServe.jl
It might be of some interest
Try this
julia> js"""
{
"a_number" : 5.0,
"an_array" : ["string", 9]
}
"""
JSON3.Object{Base.CodeUnits{UInt8,String},Array{UInt64,1}} with 2 entries:
:a_number => 5
:an_array => Any["string", 9]
Edit: If you really wanted a Dict
, just do this
julia> macro js_str(s)
return :(Dict(JSON3.read($s)))
end
@js_str (macro with 1 method)
julia> js"""
{
"a_number" : 5.0,
"an_array" : ["string", 9]
}
"""
Dict{Symbol,Any} with 2 entries:
:a_number => 5
:an_array => Any["string", 9]
2 Likes
Joining late…
I’ve asked about this separately.
This is the code I can up with. Maybe it’s of use to someone…
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 : { # recursive...
b : i, # accessing local variable
e : nothing,
}, "c": [1, 2.0, "mixed types"], # array
"d": i + j # expression
})
end
aa()
#Dict{String, Any} with 3 entries:
# "c" => Any[1, 2.0, "mixed types"]
# "a" => Dict{String, Any}("e"=>nothing, "b"=>2)
# "d" => 5
Thanks,
DD
2 Likes