Skip to content

Commit 481a05c

Browse files
Merge pull request #15738 from MichaelHatherly/mh/coredocs
Docsystem Improvements
2 parents f656caf + 3dc91cf commit 481a05c

File tree

12 files changed

+744
-785
lines changed

12 files changed

+744
-785
lines changed

base/boot.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,19 @@ Array{T}(::Type{T}, m::Int) = Array{T,1}(m)
323323
Array{T}(::Type{T}, m::Int,n::Int) = Array{T,2}(m,n)
324324
Array{T}(::Type{T}, m::Int,n::Int,o::Int) = Array{T,3}(m,n,o)
325325

326+
# docsystem basics
327+
macro doc(x...)
328+
atdoc(x...)
329+
end
330+
macro __doc__(x)
331+
Expr(:escape, Expr(:block, Expr(:meta, :doc), x))
332+
end
333+
macro doc_str(s)
334+
Expr(:escape, s)
335+
end
336+
atdoc = (str, expr) -> Expr(:escape, expr)
337+
atdoc!(λ) = global atdoc = λ
338+
326339
module TopModule
327340
# this defines the types that lowering expects to be defined in a (top) module
328341
# that are usually inherited from Core, but could be defined custom for a module

base/coreimg.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ print(x::ANY) = show(x)
1616
println(x::ANY) = ccall(:jl_, Void, (Any,), x) # includes a newline
1717
print(a::ANY...) = for x=a; print(x); end
1818

19-
# Doc macro shim.
20-
macro doc(str, def) Expr(:escape, def) end
21-
2219
## Load essential files and libraries
2320
include("essentials.jl")
2421
include("generator.jl")
@@ -67,6 +64,9 @@ include("intset.jl")
6764
include("dict.jl")
6865
include("iterator.jl")
6966

67+
# core docsystem
68+
include("docs/core.jl")
69+
7070
# compiler
7171
include("inference.jl")
7272

base/docs/Docs.jl

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ will cause that specific method to be documented, as opposed to the whole functi
5252
docs are concatenated together in the order they were defined to provide docs for the
5353
function.
5454
"""
55-
:(Base.DocBootstrap.@doc)
55+
:(Core.@doc)
5656

5757
include("bindings.jl")
5858

5959
import Base.Markdown: @doc_str, MD
6060
import Base.Meta: quot, isexpr
6161
import Base: Callable
62+
import Core.Inference.CoreDocs: lazy_iterpolate
6263

6364
export doc
6465

@@ -99,7 +100,7 @@ function argtype(expr::Expr)
99100
isexpr(expr, :(...)) && return :(Vararg{$(argtype(expr.args[1]))})
100101
argtype(expr.args[1])
101102
end
102-
argtype(::Symbol) = :Any
103+
argtype(other) = :Any
103104

104105
function typevars(expr::Expr)
105106
isexpr(expr, :curly) && return [tvar(x) for x in expr.args[2:end]]
@@ -126,13 +127,9 @@ The `.data` fields stores several values related to the docstring, such as: path
126127
linenumber, source code, and fielddocs.
127128
"""
128129
type DocStr
129-
text :: UTF8String
130+
text :: Core.SimpleVector
130131
object :: Nullable
131132
data :: Dict{Symbol, Any}
132-
133-
DocStr(text::AbstractString, data) = new(text, Nullable(), data)
134-
DocStr(object, data) = new("", Nullable(object), data)
135-
DocStr(docstr::DocStr, data) = docstr
136133
end
137134

138135
function docstr(binding::Binding, typesig::ANY = Union{})
@@ -147,7 +144,13 @@ function docstr(binding::Binding, typesig::ANY = Union{})
147144
end
148145
error("could not find matching docstring for '$binding :: $typesig'.")
149146
end
150-
docstr(object, data = Dict()) = DocStr(object, data)
147+
docstr(object, data = Dict()) = _docstr(object, data)
148+
149+
_docstr(vec::Core.SimpleVector, data) = DocStr(vec, Nullable(), data)
150+
_docstr(str::AbstractString, data) = DocStr(Core.svec(str), Nullable(), data)
151+
_docstr(object, data) = DocStr(Core.svec(), Nullable(object), data)
152+
153+
_docstr(doc::DocStr, data) = (doc.data = merge(data, doc.data); doc)
151154

152155
macro ref(x)
153156
binding = bindingexpr(namify(x))
@@ -157,9 +160,18 @@ end
157160

158161
docexpr(args...) = Expr(:call, docstr, args...)
159162

163+
function formatdoc(d::DocStr)
164+
buffer = IOBuffer()
165+
for part in d.text
166+
formatdoc(buffer, d, part)
167+
end
168+
Markdown.parse(seekstart(buffer))
169+
end
170+
@noinline formatdoc(buffer, d, part) = print(buffer, part)
171+
160172
function parsedoc(d::DocStr)
161173
if isnull(d.object)
162-
md = Markdown.parse(d.text)
174+
md = formatdoc(d)
163175
md.meta[:module] = d.data[:module]
164176
md.meta[:path] = d.data[:path]
165177
d.object = Nullable(md)
@@ -282,7 +294,10 @@ function fielddoc(binding::Binding, field::Symbol)
282294
multidoc = dict[binding]
283295
if haskey(multidoc.docs, Union{})
284296
fields = multidoc.docs[Union{}].data[:fields]
285-
haskey(fields, field) && return Markdown.parse(fields[field])
297+
if haskey(fields, field)
298+
doc = fields[field]
299+
return isa(doc, Markdown.MD) ? doc : Markdown.parse(doc)
300+
end
286301
end
287302
end
288303
end
@@ -377,7 +392,7 @@ isdoc(s::AbstractString) = true
377392

378393
isdoc(x) = isexpr(x, :string) ||
379394
(isexpr(x, :macrocall) && x.args[1] == symbol("@doc_str")) ||
380-
(isexpr(x, :call) && x.args[1] == Expr(:., Base.Markdown, QuoteNode(:doc_str)))
395+
(isexpr(x, :call) && x.args[1] == Base.Markdown.doc_str)
381396

382397
function unblock(ex)
383398
isexpr(ex, :block) || return ex
@@ -430,7 +445,8 @@ function metadata(expr)
430445
# Source code for the object being documented.
431446
push!(args, :($(Pair)(:source, $(quot(expr)))))
432447
# Filename and linenumber of the docstring.
433-
push!(args, :($(Pair)(:path, $(Base).@__FILE__)), :($(Pair)(:linenumber, @__LINE__)))
448+
push!(args, :($(Pair)(:path, $(Base).@__FILE__)))
449+
push!(args, :($(Pair)(:linenumber, $(unsafe_load(cglobal(:jl_lineno, Int))))))
434450
# Module in which the docstring is defined.
435451
push!(args, :($(Pair)(:module, $(current_module)())))
436452
# Field docs for concrete types.
@@ -451,9 +467,14 @@ function metadata(expr)
451467
:($(Dict)($(args...)))
452468
end
453469

470+
function keyworddoc(str, def)
471+
docstr = esc(docexpr(lazy_iterpolate(str), metadata(def)))
472+
:($(keywords)[$(esc(quot(def.name)))] = $docstr)
473+
end
474+
454475
function objectdoc(str, def, expr, sig = :(Union{}))
455476
binding = esc(bindingexpr(namify(expr)))
456-
docstr = esc(docexpr(str, metadata(expr)))
477+
docstr = esc(docexpr(lazy_iterpolate(str), metadata(expr)))
457478
quote
458479
$(esc(def))
459480
$(doc!)($binding, $docstr, $(esc(sig)))
@@ -480,7 +501,7 @@ end
480501
# Shares a single doc, `meta`, between several expressions from the tuple expression `ex`.
481502
function multidoc(meta, ex, define)
482503
out = Expr(:toplevel)
483-
str = docexpr(meta, metadata(ex))
504+
str = docexpr(lazy_iterpolate(meta), metadata(ex))
484505
ref = Ref{DocStr}()
485506
for (n, arg) in enumerate(ex.args)
486507
# The first `arg` to be documented needs to also create the docstring for the group.
@@ -508,7 +529,7 @@ more than one expression is marked then the same docstring is applied to each ex
508529
509530
`@__doc__` has no effect when a macro that uses it is not documented.
510531
"""
511-
:(Base.@__doc__)
532+
:(Core.@__doc__)
512533

513534
function __doc__!(meta, def, define)
514535
# Two cases must be handled here to avoid redefining all definitions contained in `def`:
@@ -575,6 +596,13 @@ function docm(meta, ex, define = true)
575596
# Initalise the module's docstring storage.
576597
initmeta()
577598

599+
# Keywords using the `@kw_str` macro in `base/docs/basedocs.jl`.
600+
#
601+
# "..."
602+
# kw"if", kw"else"
603+
#
604+
isa(x, Base.BaseDocs.Keyword) ? keyworddoc(meta, x) :
605+
578606
# Method / macro definitions and "call" syntax.
579607
#
580608
# function f(...) ... end
@@ -631,7 +659,7 @@ function docerror(ex)
631659
if isexpr(ex, :macrocall)
632660
txt *= "\n\n'$(ex.args[1])' not documentable. See 'Base.@__doc__' docs for details."
633661
end
634-
:(error($txt, "\n"))
662+
:($(error)($txt, "\n"))
635663
end
636664

637665
function docm(ex)
@@ -652,20 +680,21 @@ function docm(ex)
652680
end
653681
end
654682

655-
# Swap out the bootstrap macro with the real one
656-
657-
Base.DocBootstrap.setexpand!(docm)
658-
659-
# Names are resolved relative to the Base module, so inject the ones we need there.
660-
661-
eval(Base, :(import .Docs: @doc_str))
662-
663-
Base.DocBootstrap.loaddocs()
664-
665683
# MD support
666-
667684
catdoc(md::MD...) = MD(md...)
668685

669686
include("utils.jl")
670687

688+
# Swap out the bootstrap macro with the real one.
689+
Core.atdoc!(docm)
690+
691+
function loaddocs(docs)
692+
for (mod, ex, str, file, line) in docs
693+
data = Dict(:path => string(file), :linenumber => line)
694+
doc = docstr(str, data)
695+
eval(mod, :(@doc($doc, $ex, false)))
696+
end
697+
empty!(docs)
698+
end
699+
671700
end

0 commit comments

Comments
 (0)