Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Parser: Use implicit ending for tags
Browse files Browse the repository at this point in the history
They are not necessarily at the end anymore, and the end similarly as light
syntax list: on new lines or heading.

This is a breaking change, which according to ocaml#1138 is fixing more things than
breaking them.
It will allow using custom tags and tags in mld files.
panglesd committed Nov 8, 2024
1 parent 3addbf9 commit 6ded9da
Showing 3 changed files with 71 additions and 140 deletions.
115 changes: 43 additions & 72 deletions src/parser/syntax.ml
Original file line number Diff line number Diff line change
@@ -580,7 +580,7 @@ type ('block, 'stops_at_which_tokens) context =
| In_explicit_list : (Ast.nestable_block_element, stops_at_delimiters) context
| In_table_cell : (Ast.nestable_block_element, stops_at_delimiters) context
| In_code_results : (Ast.nestable_block_element, code_stop) context
| In_tag : (Ast.nestable_block_element, Token.t) context
| In_tag : (Ast.nestable_block_element, stopped_implicitly) context

(* This is a no-op. It is needed to prove to the type system that nestable block
elements are acceptable block elements in all contexts. *)
@@ -638,13 +638,12 @@ let rec block_element_list :
* where_in_line =
fun context ~parent_markup input ->
let rec consume_block_elements :
parsed_a_tag:bool ->
where_in_line ->
block with_location list ->
block with_location list
* stops_at_which_tokens with_location
* where_in_line =
fun ~parsed_a_tag where_in_line acc ->
fun where_in_line acc ->
let describe token =
match token with
| #token_that_always_begins_an_inline_element -> "paragraph"
@@ -657,16 +656,6 @@ let rec block_element_list :
|> add_warning input
in

let warn_if_after_tags { Loc.location; value = token } =
if parsed_a_tag then
let suggestion =
Printf.sprintf "move %s before any tags." (Token.describe token)
in
Parse_error.not_allowed ~what:(describe token)
~in_what:"the tags section" ~suggestion location
|> add_warning input
in

let warn_because_not_at_top_level { Loc.location; value = token } =
let suggestion =
Printf.sprintf "move %s outside of any other markup."
@@ -700,31 +689,33 @@ let rec block_element_list :
| In_tag -> (List.rev acc, next_token, where_in_line)
| In_code_results ->
junk input;
consume_block_elements ~parsed_a_tag where_in_line acc)
consume_block_elements where_in_line acc)
| { value = `Right_code_delimiter; _ } as next_token -> (
match context with
| In_code_results -> (List.rev acc, next_token, where_in_line)
| _ ->
junk input;
consume_block_elements ~parsed_a_tag where_in_line acc)
consume_block_elements where_in_line acc)
(* Whitespace. This can terminate some kinds of block elements. It is also
necessary to track it to interpret [`Minus] and [`Plus] correctly, as
well as to ensure that all block elements begin on their own line. *)
| { value = `Space _; _ } ->
junk input;
consume_block_elements ~parsed_a_tag where_in_line acc
consume_block_elements where_in_line acc
| { value = `Single_newline _; _ } ->
junk input;
consume_block_elements ~parsed_a_tag `At_start_of_line acc
consume_block_elements `At_start_of_line acc
| { value = `Blank_line _; _ } as next_token -> (
match context with
(* Blank lines terminate shorthand lists ([- foo]). They also terminate
paragraphs, but the paragraph parser is aware of that internally. *)
(* Blank lines terminate shorthand lists ([- foo]) and tags. They also
terminate paragraphs, but the paragraph parser is aware of that
internally. *)
| In_shorthand_list -> (List.rev acc, next_token, where_in_line)
| In_tag -> (List.rev acc, next_token, where_in_line)
(* Otherwise, blank lines are pretty much like single newlines. *)
| _ ->
junk input;
consume_block_elements ~parsed_a_tag `At_start_of_line acc)
consume_block_elements `At_start_of_line acc)
(* Explicit list items ([{li ...}] and [{- ...}]) can never appear directly
in block content. They can only appear inside [{ul ...}] and [{ol ...}].
So, catch those. *)
@@ -740,7 +731,7 @@ let rec block_element_list :
|> add_warning input;

junk input;
consume_block_elements ~parsed_a_tag where_in_line acc
consume_block_elements where_in_line acc
(* Table rows ([{tr ...}]) can never appear directly
in block content. They can only appear inside [{table ...}]. *)
| { value = `Begin_table_row as token; location } ->
@@ -753,7 +744,7 @@ let rec block_element_list :
~suggestion location
|> add_warning input;
junk input;
consume_block_elements ~parsed_a_tag where_in_line acc
consume_block_elements where_in_line acc
(* Table cells ([{th ...}] and [{td ...}]) can never appear directly
in block content. They can only appear inside [{tr ...}]. *)
| { value = `Begin_table_cell _ as token; location } ->
@@ -766,9 +757,8 @@ let rec block_element_list :
~suggestion location
|> add_warning input;
junk input;
consume_block_elements ~parsed_a_tag where_in_line acc
(* Tags. These can appear at the top level only. Also, once one tag is seen,
the only top-level elements allowed are more tags. *)
consume_block_elements where_in_line acc
(* Tags. These can appear at the top level only. *)
| { value = `Tag tag as token; location } as next_token -> (
let recover_when_not_at_top_level context =
warn_because_not_at_top_level next_token;
@@ -779,8 +769,7 @@ let rec block_element_list :
|> accepted_in_all_contexts context
|> Loc.at location
in
consume_block_elements ~parsed_a_tag `At_start_of_line
(paragraph :: acc)
consume_block_elements `At_start_of_line (paragraph :: acc)
in

match context with
@@ -831,8 +820,7 @@ let rec block_element_list :
in

let tag = Loc.at location (`Tag tag) in
consume_block_elements ~parsed_a_tag:true `After_text
(tag :: acc)
consume_block_elements `After_text (tag :: acc)
| (`Deprecated | `Return) as tag ->
let content, _stream_head, where_in_line =
block_element_list In_tag ~parent_markup:token input
@@ -846,8 +834,7 @@ let rec block_element_list :
location :: List.map Loc.location content |> Loc.span
in
let tag = Loc.at location (`Tag tag) in
consume_block_elements ~parsed_a_tag:true where_in_line
(tag :: acc)
consume_block_elements where_in_line (tag :: acc)
| (`Param _ | `Raise _ | `Before _) as tag ->
let content, _stream_head, where_in_line =
block_element_list In_tag ~parent_markup:token input
@@ -862,8 +849,7 @@ let rec block_element_list :
location :: List.map Loc.location content |> Loc.span
in
let tag = Loc.at location (`Tag tag) in
consume_block_elements ~parsed_a_tag:true where_in_line
(tag :: acc)
consume_block_elements where_in_line (tag :: acc)
| `See (kind, target) ->
let content, _next_token, where_in_line =
block_element_list In_tag ~parent_markup:token input
@@ -873,23 +859,19 @@ let rec block_element_list :
in
let tag = `Tag (`See (kind, target, content)) in
let tag = Loc.at location tag in
consume_block_elements ~parsed_a_tag:true where_in_line
(tag :: acc)
consume_block_elements where_in_line (tag :: acc)
| (`Inline | `Open | `Closed | `Hidden) as tag ->
let tag = Loc.at location (`Tag tag) in
consume_block_elements ~parsed_a_tag:true `After_text
(tag :: acc)))
consume_block_elements `After_text (tag :: acc)))
| ( { value = #token_that_always_begins_an_inline_element; _ }
| { value = `Bar; _ } ) as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;

let block = paragraph input in
let block = Loc.map (accepted_in_all_contexts context) block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| { value = `Verbatim s as token; location } as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;
if s = "" then
Parse_error.should_not_be_empty ~what:(Token.describe token) location
@@ -899,9 +881,8 @@ let rec block_element_list :
let block = accepted_in_all_contexts context token in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| { value = `Math_block s as token; location } as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;
if s = "" then
Parse_error.should_not_be_empty ~what:(Token.describe token) location
@@ -911,14 +892,13 @@ let rec block_element_list :
let block = accepted_in_all_contexts context token in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| {
value =
`Code_block (meta, delim, { value = s; location = v_loc }, has_outputs)
as token;
location;
} as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;
junk input;
let delimiter = if delim = "" then None else Some delim in
@@ -958,9 +938,8 @@ let rec block_element_list :
in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| { value = `Modules s as token; location } as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;

junk input;
@@ -999,9 +978,8 @@ let rec block_element_list :
let block = accepted_in_all_contexts context (`Modules modules) in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| { value = `Begin_list kind as token; location } as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;

junk input;
@@ -1018,10 +996,9 @@ let rec block_element_list :
let block = accepted_in_all_contexts context block in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| { value = (`Begin_table_light | `Begin_table_heavy) as token; location }
as next_token ->
warn_if_after_tags next_token;
warn_if_after_text next_token;
junk input;
let block, brace_location =
@@ -1037,7 +1014,7 @@ let rec block_element_list :
let block = accepted_in_all_contexts context (`Table block) in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
| { value = (`Minus | `Plus) as token; location } as next_token -> (
(match where_in_line with
| `After_text | `After_shorthand_bullet ->
@@ -1046,8 +1023,6 @@ let rec block_element_list :
|> add_warning input
| _ -> ());

warn_if_after_tags next_token;

match context with
| In_shorthand_list -> (List.rev acc, next_token, where_in_line)
| _ ->
@@ -1064,11 +1039,9 @@ let rec block_element_list :
let block = accepted_in_all_contexts context block in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag where_in_line acc)
consume_block_elements where_in_line acc)
| { value = `Begin_section_heading (level, label) as token; location } as
next_token -> (
warn_if_after_tags next_token;

let recover_when_not_at_top_level context =
warn_because_not_at_top_level next_token;
junk input;
@@ -1083,8 +1056,7 @@ let rec block_element_list :
|> accepted_in_all_contexts context
|> Loc.at location
in
consume_block_elements ~parsed_a_tag `At_start_of_line
(paragraph :: acc)
consume_block_elements `At_start_of_line (paragraph :: acc)
in

match context with
@@ -1094,7 +1066,10 @@ let rec block_element_list :
else recover_when_not_at_top_level context
| In_explicit_list -> recover_when_not_at_top_level context
| In_table_cell -> recover_when_not_at_top_level context
| In_tag -> recover_when_not_at_top_level context
| In_tag ->
if where_in_line = `At_start_of_line then
(List.rev acc, next_token, where_in_line)
else recover_when_not_at_top_level context
| In_code_results -> recover_when_not_at_top_level context
| Top_level ->
if where_in_line <> `At_start_of_line then
@@ -1127,7 +1102,7 @@ let rec block_element_list :
let heading = `Heading (level, label, content) in
let heading = Loc.at location heading in
let acc = heading :: acc in
consume_block_elements ~parsed_a_tag `After_text acc)
consume_block_elements `After_text acc)
| { value = `Begin_paragraph_style _ as token; location } ->
junk input;
let content, brace_location =
@@ -1146,13 +1121,11 @@ let rec block_element_list :
|> accepted_in_all_contexts context
|> Loc.at location
in
consume_block_elements ~parsed_a_tag `At_start_of_line (paragraph :: acc)
consume_block_elements `At_start_of_line (paragraph :: acc)
| {
location;
value = `Media_with_replacement_text (href, media, content) as token;
} as next_token ->
warn_if_after_tags next_token;

location;
value = `Media_with_replacement_text (href, media, content) as token;
} ->
junk input;

let r_location =
@@ -1181,10 +1154,8 @@ let rec block_element_list :
let block = accepted_in_all_contexts context block in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
| { location; value = `Simple_media (href, media) } as next_token ->
warn_if_after_tags next_token;

consume_block_elements `After_text acc
| { location; value = `Simple_media (href, media) } ->
junk input;

let r_location =
@@ -1198,7 +1169,7 @@ let rec block_element_list :
let block = accepted_in_all_contexts context block in
let block = Loc.at location block in
let acc = block :: acc in
consume_block_elements ~parsed_a_tag `After_text acc
consume_block_elements `After_text acc
in

let where_in_line =
@@ -1211,7 +1182,7 @@ let rec block_element_list :
| In_tag -> `After_tag
in

consume_block_elements ~parsed_a_tag:false where_in_line []
consume_block_elements where_in_line []

(* {3 Lists} *)

80 changes: 20 additions & 60 deletions src/parser/test/test.ml
Original file line number Diff line number Diff line change
@@ -4051,10 +4051,10 @@ let%expect_test _ =
[%expect
{|
((output
(((f.ml (1 0) (3 3))
(((f.ml (1 0) (1 15))
(@deprecated
((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))
((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))))
((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))))
((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))
(warnings ())) |}]

let whitespace_only =
@@ -4087,9 +4087,8 @@ let%expect_test _ =
[%expect
{|
((output
(((f.ml (1 0) (3 3))
(@deprecated
((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word foo)))))))))
(((f.ml (1 0) (1 11)) (@deprecated))
((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word foo)))))))
(warnings ())) |}]

let extra_whitespace =
@@ -4233,14 +4232,11 @@ let%expect_test _ =
[%expect
{|
((output
(((f.ml (1 0) (2 7))
(((f.ml (1 0) (1 15))
(@deprecated
((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))
((f.ml (2 0) (2 7)) (paragraph (((f.ml (2 3) (2 6)) (word Bar)))))))))
(warnings
( "File \"f.ml\", line 2, characters 0-2:\
\n'{2 ...}' (section heading) is not allowed in '@deprecated'.\
\nSuggestion: move '{2' outside of any other markup."))) |}]
((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))))
((f.ml (2 0) (2 7)) (2 (label ()) (((f.ml (2 3) (2 6)) (word Bar)))))))
(warnings ())) |}]
end in
()

@@ -4322,10 +4318,10 @@ let%expect_test _ =
[%expect
{|
((output
(((f.ml (1 0) (3 3))
(((f.ml (1 0) (1 14))
(@param foo
((f.ml (1 11) (1 14)) (paragraph (((f.ml (1 11) (1 14)) (word bar)))))
((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word baz)))))))))
((f.ml (1 11) (1 14)) (paragraph (((f.ml (1 11) (1 14)) (word bar)))))))
((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word baz)))))))
(warnings ())) |}]

let two =
@@ -4826,9 +4822,6 @@ let%expect_test _ =
((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))
(warnings
( "File \"f.ml\", line 1, characters 8-11:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."
"File \"f.ml\", line 1, characters 8-11:\
\nParagraph should begin on its own line."))) |}]

let followed_by_paragraph =
@@ -4838,10 +4831,7 @@ let%expect_test _ =
((output
(((f.ml (1 0) (1 7)) @inline)
((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
(warnings
( "File \"f.ml\", line 2, characters 0-3:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."))) |}]
(warnings ())) |}]

let followed_by_tag =
test "@inline\n@deprecated";
@@ -4861,10 +4851,7 @@ let%expect_test _ =
((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))
(warnings
( "File \"f.ml\", line 1, characters 8-9:\
\n'-' (bulleted list item) should begin on its own line."
"File \"f.ml\", line 1, characters 8-9:\
\n'-' (bulleted list item) is not allowed in the tags section.\
\nSuggestion: move '-' (bulleted list item) before any tags."))) |}]
\n'-' (bulleted list item) should begin on its own line."))) |}]
end in
()

@@ -4897,9 +4884,6 @@ let%expect_test _ =
((f.ml (1 6) (1 9)) (paragraph (((f.ml (1 6) (1 9)) (word foo)))))))
(warnings
( "File \"f.ml\", line 1, characters 6-9:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."
"File \"f.ml\", line 1, characters 6-9:\
\nParagraph should begin on its own line."))) |}]

let followed_by_paragraph =
@@ -4909,10 +4893,7 @@ let%expect_test _ =
((output
(((f.ml (1 0) (1 5)) @open)
((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
(warnings
( "File \"f.ml\", line 2, characters 0-3:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."))) |}]
(warnings ())) |}]

let followed_by_tag =
test "@open\n@deprecated";
@@ -4932,10 +4913,7 @@ let%expect_test _ =
((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))))))
(warnings
( "File \"f.ml\", line 1, characters 6-7:\
\n'-' (bulleted list item) should begin on its own line."
"File \"f.ml\", line 1, characters 6-7:\
\n'-' (bulleted list item) is not allowed in the tags section.\
\nSuggestion: move '-' (bulleted list item) before any tags."))) |}]
\n'-' (bulleted list item) should begin on its own line."))) |}]
end in
()

@@ -4969,9 +4947,6 @@ let%expect_test _ =
((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))
(warnings
( "File \"f.ml\", line 1, characters 8-11:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."
"File \"f.ml\", line 1, characters 8-11:\
\nParagraph should begin on its own line."))) |}]

let followed_by_paragraph =
@@ -4981,10 +4956,7 @@ let%expect_test _ =
((output
(((f.ml (1 0) (1 7)) @closed)
((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
(warnings
( "File \"f.ml\", line 2, characters 0-3:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."))) |}]
(warnings ())) |}]

let followed_by_tag =
test "@closed\n@deprecated";
@@ -5004,10 +4976,7 @@ let%expect_test _ =
((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))
(warnings
( "File \"f.ml\", line 1, characters 8-9:\
\n'-' (bulleted list item) should begin on its own line."
"File \"f.ml\", line 1, characters 8-9:\
\n'-' (bulleted list item) is not allowed in the tags section.\
\nSuggestion: move '-' (bulleted list item) before any tags."))) |}]
\n'-' (bulleted list item) should begin on its own line."))) |}]
end in
()

@@ -5041,9 +5010,6 @@ let%expect_test _ =
((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))
(warnings
( "File \"f.ml\", line 1, characters 8-11:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."
"File \"f.ml\", line 1, characters 8-11:\
\nParagraph should begin on its own line."))) |}]

let followed_by_paragraph =
@@ -5053,10 +5019,7 @@ let%expect_test _ =
((output
(((f.ml (1 0) (1 7)) @hidden)
((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
(warnings
( "File \"f.ml\", line 2, characters 0-3:\
\nParagraph is not allowed in the tags section.\
\nSuggestion: move 'foo' before any tags."))) |}]
(warnings ())) |}]

let followed_by_tag =
test "@hidden\n@deprecated";
@@ -5076,10 +5039,7 @@ let%expect_test _ =
((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))
(warnings
( "File \"f.ml\", line 1, characters 8-9:\
\n'-' (bulleted list item) should begin on its own line."
"File \"f.ml\", line 1, characters 8-9:\
\n'-' (bulleted list item) is not allowed in the tags section.\
\nSuggestion: move '-' (bulleted list item) before any tags."))) |}]
\n'-' (bulleted list item) should begin on its own line."))) |}]
end in
()

16 changes: 8 additions & 8 deletions test/model/semantics/test.ml
Original file line number Diff line number Diff line change
@@ -759,49 +759,49 @@ let%expect_test _ =
test "@author Foo\nbar";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Paragraph":[{"`Word":"bar"}]}],"warnings":["File \"f.ml\", line 2, characters 0-3:\nParagraph is not allowed in the tags section.\nSuggestion: move 'bar' before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Paragraph":[{"`Word":"bar"}]}],"warnings":[]} |}]

let followed_by_code_span =
test "@author Foo\n[bar]";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Paragraph":[{"`Code_span":"bar"}]}],"warnings":["File \"f.ml\", line 2, characters 0-5:\nParagraph is not allowed in the tags section.\nSuggestion: move '[...]' (code) before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Paragraph":[{"`Code_span":"bar"}]}],"warnings":[]} |}]

let followed_by_code_block =
test "@author Foo\n{[bar]}";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Code_block":["None","bar"]}],"warnings":["File \"f.ml\", line 2, characters 0-7:\n'{[...]}' (code block) is not allowed in the tags section.\nSuggestion: move '{[...]}' (code block) before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Code_block":["None","bar"]}],"warnings":[]} |}]

let followed_by_verbatim =
test "@author Foo\n{v bar v}";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Verbatim":"bar"}],"warnings":["File \"f.ml\", line 2, characters 0-9:\n'{v ... v}' (verbatim text) is not allowed in the tags section.\nSuggestion: move '{v ... v}' (verbatim text) before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Verbatim":"bar"}],"warnings":[]} |}]

let followed_by_modules =
test "@author foo\n{!modules:Foo}";
[%expect
{|
{"value":[{"`Tag":{"`Author":"foo"}},{"`Modules":[[{"`Root":["Foo","`TUnknown"]},"None"]]}],"warnings":["File \"f.ml\", line 2, characters 0-14:\n'{!modules ...}' is not allowed in the tags section.\nSuggestion: move '{!modules ...}' before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"foo"}},{"`Modules":[[{"`Root":["Foo","`TUnknown"]},"None"]]}],"warnings":[]} |}]

let followed_by_list =
test "@author Foo\n{ul {li bar}}";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`List":["`Unordered",[[{"`Paragraph":[{"`Word":"bar"}]}]]]}],"warnings":["File \"f.ml\", line 2, characters 0-3:\n'{ul ...}' (bulleted list) is not allowed in the tags section.\nSuggestion: move '{ul ...}' (bulleted list) before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`List":["`Unordered",[[{"`Paragraph":[{"`Word":"bar"}]}]]]}],"warnings":[]} |}]

let followed_by_shorthand_list =
test "@author Foo\n- bar";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`List":["`Unordered",[[{"`Paragraph":[{"`Word":"bar"}]}]]]}],"warnings":["File \"f.ml\", line 2, characters 0-1:\n'-' (bulleted list item) is not allowed in the tags section.\nSuggestion: move '-' (bulleted list item) before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`List":["`Unordered",[[{"`Paragraph":[{"`Word":"bar"}]}]]]}],"warnings":[]} |}]

let followed_by_section_heading =
test "@author Foo\n{2 Bar}";
[%expect
{|
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Heading":[{"heading_level":"`Subsection","heading_label_explicit":"false"},{"`Label":[{"`Page":["None","f.ml"]},"bar"]},[{"`Word":"Bar"}]]}],"warnings":["File \"f.ml\", line 2, characters 0-2:\n'{2 ...}' (section heading) is not allowed in the tags section.\nSuggestion: move '{2 ...}' (section heading) before any tags."]} |}]
{"value":[{"`Tag":{"`Author":"Foo"}},{"`Heading":[{"heading_level":"`Subsection","heading_label_explicit":"false"},{"`Label":[{"`Page":["None","f.ml"]},"bar"]},[{"`Word":"Bar"}]]}],"warnings":[]} |}]

let followed_by_author =
test "@author Foo\n@author Bar";

0 comments on commit 6ded9da

Please sign in to comment.