Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Documenting macro-generated code #13006

Merged
merged 1 commit into from
Sep 29, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion base/Enums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ macro enum(T,syms...)
end
blk = quote
# enum definition
bitstype 32 $(esc(T)) <: Enum
Base.@__doc__(bitstype 32 $(esc(T)) <: Enum)
function Base.convert(::Type{$(esc(typename))}, x::Integer)
$(membershiptest(:x, values)) || enum_argument_error($(Expr(:quote, typename)), x)
Intrinsics.box($(esc(typename)), convert(Int32, x))
Expand Down
43 changes: 42 additions & 1 deletion base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -496,9 +496,49 @@ end

multidoc(meta, objs) = quote $([:(@doc $(esc(meta)) $(esc(obj))) for obj in objs]...) end

doc"""
@__doc__(ex)

Low-level macro used to mark expressions returned by a macro that should be documented. If
more than one expression is marked then the same docstring is applied to each expression.

macro example(f)
quote
$(f)() = 0
@__doc__ $(f)(x) = 1
$(f)(x, y) = 2
end |> esc
end

`@__doc__` has no effect when a macro that uses it is not documented.
"""
:(Base.@__doc__)

function __doc__!(meta, def::Expr)
if isexpr(def, :block) && length(def.args) == 2 && def.args[1] == symbol("#doc#")
# Convert `Expr(:block, :#doc#, ...)` created by `@__doc__` to an `@doc`.
def.head = :macrocall
def.args = [symbol("@doc"), meta, def.args[end]]
true
else
found = false
for each in def.args
found |= __doc__!(meta, each)
end
found
end
end
__doc__!(meta, def) = false

fexpr(ex) = isexpr(ex, :function, :stagedfunction, :(=)) && isexpr(ex.args[1], :call)

function docm(meta, def, define = true)

err = (
"invalid doc expression:", def, isexpr(def, :macrocall) ?
"'$(def.args[1])' is not documentable. See 'help?> Base.@__doc__' for details." : ""
)

def′ = unblock(def)

isexpr(def′, :quote) && isexpr(def′.args[1], :macrocall) &&
Expand All @@ -522,7 +562,8 @@ function docm(meta, def, define = true)
:global) ? vardoc(meta, def, namify(def′)) :
isvar(def′) ? objdoc(meta, def′) :
isexpr(def′, :tuple) ? multidoc(meta, def′.args) :
isa(def′, Expr) ? error("invalid doc expression $def′") :
__doc__!(meta, def′) ? esc(def′) :
isa(def′, Expr) ? error(strip(join(err, "\n\n"))) :
objdoc(meta, def′)
end

Expand Down
2 changes: 2 additions & 0 deletions base/docs/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ macro doc(args...)
DocBootstrap._expand_(args...)
end

macro __doc__(ex) esc(Expr(:block, symbol("#doc#"), ex)) end

module DocBootstrap

type List
Expand Down
48 changes: 48 additions & 0 deletions test/docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,54 @@ let d1 = @doc(DocsTest.val)
@test d1 !== nothing
end

# Document specific expressions generated by macro calls.
module MacroGenerated

import Base.@__doc__

macro example_1(f)
quote
$(f)() = 0
@__doc__ $(f)(x) = x
$(f)(x, y) = x + y
end |> esc
end

"f"
@example_1 f

@example_1 _f

macro example_2(f)
quote
$(f)() = 0
@__doc__ $(f)(x) = x
@__doc__ $(f)(x, y) = x + y
end |> esc
end

"g"
@example_2 g

@example_2 _g

end

let funcdoc = meta(MacroGenerated)[MacroGenerated.f]
@test funcdoc.order == [Tuple{Any}]
@test funcdoc.meta[Tuple{Any}] == doc"f"
end

@test isdefined(MacroGenerated, :_f)

let funcdoc = meta(MacroGenerated)[MacroGenerated.g]
@test funcdoc.order == [Tuple{Any}, Tuple{Any, Any}]
@test funcdoc.meta[Tuple{Any}] == doc"g"
@test funcdoc.meta[Tuple{Any, Any}] == doc"g"
end

@test isdefined(MacroGenerated, :_g)

# Issue #12700.
@test @doc(DocsTest.@m) == doc"Inner.@m"

Expand Down