Skip to content

Commit 98c202a

Browse files
authored
Parse docstrings within structs as K"doc" (#511)
Julia's ecosystem (including Base.Docs and flisp lowering) assumes that strings within `struct` definitions are per-field docstrings, but the flisp parser doesn't handle these - they are only recognized when the struct itself has a docstring and are processed by the `@doc` macro recursing into the struct's internals. For example, the following doesn't result in any docs attached to `A`. ```julia struct A "x_docs" x "y_docs" y end ``` This change adds `K"doc"` node parsing to the insides of a struct, making the semantics clearer in the parser tree and making it possible to address this problems in the future within JuliaLowering. Also ensure that the `Expr` form is unaffected by this change.
1 parent 32b80e3 commit 98c202a

File tree

4 files changed

+21
-4
lines changed

4 files changed

+21
-4
lines changed

src/expr.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,19 @@ function _internal_node_to_Expr(source, srcrange, head, childranges, childheads,
466466
headsym = :call
467467
pushfirst!(args, :*)
468468
elseif k == K"struct"
469+
@assert args[2].head == :block
470+
orig_fields = args[2].args
471+
fields = Expr(:block)
472+
for field in orig_fields
473+
if @isexpr(field, :macrocall) && field.args[1] == GlobalRef(Core, Symbol("@doc"))
474+
# @doc macro calls don't occur within structs, in Expr form.
475+
push!(fields.args, field.args[3])
476+
push!(fields.args, field.args[4])
477+
else
478+
push!(fields.args, field)
479+
end
480+
end
481+
args[2] = fields
469482
pushfirst!(args, has_flags(head, MUTABLE_FLAG))
470483
elseif k == K"importpath"
471484
headsym = :.

src/parser.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,9 @@ end
536536
# Parse docstrings attached by a space or single newline
537537
#
538538
# flisp: parse-docstring
539-
function parse_docstring(ps::ParseState)
539+
function parse_docstring(ps::ParseState, down=parse_eq)
540540
mark = position(ps)
541-
parse_eq(ps)
541+
down(ps)
542542
if peek_behind(ps).kind == K"string"
543543
is_doc = true
544544
k = peek(ps)
@@ -563,7 +563,7 @@ function parse_docstring(ps::ParseState)
563563
# """\n doc\n """ foo ==> (doc (string-s "doc\n") foo)
564564
end
565565
if is_doc
566-
parse_eq(ps)
566+
down(ps)
567567
emit(ps, mark, K"doc")
568568
end
569569
end
@@ -1947,7 +1947,7 @@ function parse_resword(ps::ParseState)
19471947
@check peek(ps) == K"struct"
19481948
bump(ps, TRIVIA_FLAG)
19491949
parse_subtype_spec(ps)
1950-
parse_block(ps, parse_struct_field)
1950+
parse_block(ps, ps1->parse_docstring(ps1, parse_struct_field))
19511951
bump_closing_token(ps, K"end")
19521952
emit(ps, mark, K"struct", is_mut ? MUTABLE_FLAG : EMPTY_FLAGS)
19531953
elseif word == K"primitive"

test/expr.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,9 @@
727727
Expr(:block, LineNumberNode(2), :a, LineNumberNode(3), :b))
728728
@test parsestmt("struct A const a end", version=v"1.8") ==
729729
Expr(:struct, false, :A, Expr(:block, LineNumberNode(1), Expr(:const, :a)))
730+
731+
@test parsestmt("struct A \n \"doc\" \n a end") ==
732+
Expr(:struct, false, :A, Expr(:block, LineNumberNode(2), "doc", :a))
730733
end
731734

732735
@testset "export" begin

test/parser.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ tests = [
502502
# struct
503503
"struct A <: B \n a::X \n end" => "(struct (<: A B) (block (::-i a X)))"
504504
"struct A \n a \n b \n end" => "(struct A (block a b))"
505+
"struct A \n \"doca\" \n a \n \"docb\" \n b \n end" => "(struct A (block (doc (string \"doca\") a) (doc (string \"docb\") b)))"
505506
"mutable struct A end" => "(struct-mut A (block))"
506507
((v=v"1.8",), "struct A const a end") => "(struct A (block (const a)))"
507508
((v=v"1.7",), "struct A const a end") => "(struct A (block (error (const a))))"

0 commit comments

Comments
 (0)