Skip to content

Instantly share code, notes, and snippets.

@darwindarak
Last active August 29, 2015 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darwindarak/0eb5e53c21c896392938 to your computer and use it in GitHub Desktop.
Save darwindarak/0eb5e53c21c896392938 to your computer and use it in GitHub Desktop.
Macro to modify `Nullable{NonLeafType}` annotations
# @nullable_nodes function MyFunc(a::Nullable{NonLeafType}) ... end
#
# gives
#
# function{T <: NonLeafType}(a::Nullable{T}) ... end
#
# and
#
# @nullable_nodes type MyType
# a::Nullable{NonLeafType}
# end
#
# should give
#
# type MyType{T <: NonLeafType}
# a::Nullable{T}
# end
macro nullable_nodes(expr)
if expr.head == :function
typedefs = expr.args[1].args[2:end]
elseif expr.head == :type
typedefs = expr.args[3].args
end
# Find all the Nullable{T} annotations where T is not a leaftype
P = 'A'
nodetypes = []
for annotation in typedefs
nulldef = (isa(annotation, Expr) &&
annotation.head == :(::) &&
isa(annotation.args[2], Expr) &&
annotation.args[2].args[1] == :Nullable)
if !nulldef
continue
end
T = annotation.args[2].args[2]
if !isleaftype(eval(T))
name = symbol("$(P)_null")
push!(nodetypes, (name, T))
annotation.args[2].args[2] = name
P += 1
end
end
if expr.head == :function
header = expr.args[1].args[1]
expr.args[1].args[1] = add_type_parameters(header, nodetypes)
elseif expr.head == :type
header = expr.args[2]
expr.args[2] = add_type_parameters(header, nodetypes)
end
esc(expr)
end
function add_type_parameters(header::Symbol, params)
return add_type_parameters(:($(header){}), params)
end
function add_type_parameters(header::Expr, params)
if header.head == :(<:)
for (i,arg) in enumerate(header.args)
if isa(arg, Expr) && arg.head == :curly
header.args[i] = add_type_parameters(arg, params)
return header
end
end
curly = :($(header.args[1]){})
for (P, T) in params
push!(curly.args, Expr(:(<:), P, T))
end
header.args[1] = curly
return header
elseif header.head == :curly
for (P, T) in params
push!(header.args, Expr(:(<:), P, T))
end
return header
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment