-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from invenia/ox/method
Add code to generate signature from Method
- Loading branch information
Showing
11 changed files
with
442 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
name = "ExprTools" | ||
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" | ||
authors = ["Curtis Vogt <[email protected]>"] | ||
version = "0.1.0" | ||
authors = ["Invenia Technical Computing"] | ||
version = "0.1.1" | ||
|
||
[compat] | ||
julia = "1" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,4 +10,5 @@ CurrentModule = ExprTools | |
```@docs | ||
splitdef | ||
combinedef | ||
signature | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
module ExprTools | ||
|
||
export splitdef, combinedef | ||
export signature, splitdef, combinedef | ||
|
||
include("function.jl") | ||
|
||
include("method.jl") | ||
include("type_utils.jl") | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
""" | ||
signature(m::Method) -> Dict{Symbol,Any} | ||
Finds the expression for a method's signature as broken up into its various components | ||
including: | ||
- `:name`: Name of the function | ||
- `:params`: Parametric types defined on constructors | ||
- `:args`: Positional arguments of the function | ||
- `:whereparams`: Where parameters | ||
All components listed above may not be present in the returned dictionary if they are | ||
not in the function definition. | ||
Limited support for: | ||
- `:kwargs`: Keyword arguments of the function. | ||
Only the names will be included, not the default values or type constraints. | ||
Unsupported: | ||
- `:rtype`: Return type of the function | ||
- `:body`: Function body0 | ||
- `:head`: Expression head of the function definition (`:function`, `:(=)`, `:(->)`) | ||
For more complete coverage, consider using [`splitdef`](@ref) | ||
with [`CodeTracking.definition`](https://github.com/timholy/CodeTracking.jl). | ||
The dictionary of components returned by `signature` match those returned by | ||
[`splitdef`](@ref) and include all that are required by [`combinedef`](@ref), except for | ||
the `:body` component. | ||
""" | ||
function signature(m::Method) | ||
def = Dict{Symbol, Any}() | ||
def[:name] = m.name | ||
|
||
def[:args] = arguments(m) | ||
def[:whereparams] = where_parameters(m) | ||
def[:params] = parameters(m) | ||
def[:kwargs] = kwargs(m) | ||
|
||
return Dict(k => v for (k, v) in def if v !== nothing) # filter out nonfields. | ||
end | ||
|
||
function slot_names(m::Method) | ||
ci = Base.uncompressed_ast(m) | ||
return ci.slotnames | ||
end | ||
|
||
function argument_names(m::Method) | ||
slot_syms = slot_names(m) | ||
@assert slot_syms[1] === Symbol("#self#") | ||
arg_names = slot_syms[2:m.nargs] # nargs includes 1 for `#self#` | ||
return arg_names | ||
end | ||
|
||
|
||
function argument_types(m::Method) | ||
# First parameter of `sig` is the type of the function itself | ||
return parameters(m.sig)[2:end] | ||
end | ||
|
||
name_of_type(x) = x | ||
name_of_type(tv::TypeVar) = tv.name | ||
function name_of_type(x::DataType) | ||
name_sym = Symbol(x.name) | ||
if isempty(x.parameters) | ||
return name_sym | ||
else | ||
parameter_names = name_of_type.(x.parameters) | ||
return :($(name_sym){$(parameter_names...)}) | ||
end | ||
end | ||
function name_of_type(x::UnionAll) | ||
name = name_of_type(x.body) | ||
whereparam = where_parameters(x.var) | ||
return :($name where $whereparam) | ||
end | ||
|
||
|
||
function arguments(m::Method) | ||
arg_names = argument_names(m) | ||
arg_types = argument_types(m) | ||
map(arg_names, arg_types) do name, type | ||
has_name = name !== Symbol("#unused#") | ||
type_name = name_of_type(type) | ||
if type === Any && has_name | ||
name | ||
elseif has_name | ||
:($name::$type_name) | ||
else | ||
:(::$type_name) | ||
end | ||
end | ||
end | ||
|
||
function where_parameters(x::TypeVar) | ||
if x.lb === Union{} && x.ub === Any | ||
return x.name | ||
elseif x.lb === Union{} | ||
return :($(x.name) <: $(Symbol(x.ub))) | ||
elseif x.ub === Any | ||
return :($(x.name) >: $(Symbol(x.lb))) | ||
else | ||
return :($(Symbol(x.lb)) <: $(x.name) <: $(Symbol(x.ub))) | ||
end | ||
end | ||
|
||
function where_parameters(m::Method) | ||
m.sig isa UnionAll || return nothing | ||
|
||
whereparams = [] | ||
sig = m.sig | ||
while sig isa UnionAll | ||
push!(whereparams, where_parameters(sig.var)) | ||
sig = sig.body | ||
end | ||
return whereparams | ||
end | ||
|
||
function parameters(m::Method) | ||
typeof_type = first(parameters(m.sig)) # will be e.g Type{Foo{P}} if it has any parameters | ||
typeof_type <: Type{<:Any} || return nothing | ||
|
||
function_type = first(parameters(typeof_type)) # will be e.g. Foo{P} | ||
parameter_types = parameters(function_type) | ||
return [name_of_type(type) for type in parameter_types] | ||
end | ||
|
||
function kwargs(m::Method) | ||
names = kwarg_names(m) | ||
isempty(names) && return nothing # we know it has no keywords. | ||
# TODO: Enhance this to support more than just their names | ||
# see https://github.com/invenia/ExprTools.jl/issues/6 | ||
return names | ||
end | ||
|
||
function kwarg_names(m::Method) | ||
mt = Base.get_methodtable(m) | ||
!isdefined(mt, :kwsorter) && return [] # no kwsorter means no keywords for sure. | ||
return Base.kwarg_decl(m, typeof(mt.kwsorter)) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
""" | ||
parameters(type) | ||
Extracts the type-parameters of the `type`. | ||
e.g. `parameters(Foo{A, B, C}) == [A, B, C]` | ||
""" | ||
parameters(sig::UnionAll) = parameters(sig.body) | ||
parameters(sig::DataType) = sig.parameters |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
5b643de
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register
5b643de
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/12951
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via: