this repo has no description
1open Odoc_parser
2
3type sexp = Sexplib0.Sexp.t = Atom of string | List of sexp list
4
5module Location_to_sexp = struct
6 let point : Loc.point -> sexp =
7 fun { line; column } ->
8 List [ Atom (string_of_int line); Atom (string_of_int column) ]
9
10 let span : Loc.span -> sexp =
11 fun { file; start; end_ } -> List [ Atom file; point start; point end_ ]
12
13 let at : ('a Loc.with_location -> sexp) -> 'a Loc.with_location -> sexp =
14 fun f ({ location; _ } as v) -> List [ span location; f v ]
15end
16
17let error err = Atom (Odoc_parser.Warning.to_string err)
18
19module Ast_to_sexp = struct
20 (* let at = Location_to_sexp.at *)
21 type at = {
22 at : 'a. ('a Loc.with_location -> sexp) -> 'a Loc.with_location -> sexp;
23 }
24
25 let loc_at = { at = Location_to_sexp.at }
26 let str s = Atom s
27 let str_at s = Atom s.Loc.value
28 let opt f s = match s with Some s -> List [ f s ] | None -> List []
29
30 let style : Ast.style -> sexp = function
31 | `Bold -> Atom "bold"
32 | `Italic -> Atom "italic"
33 | `Emphasis -> Atom "emphasis"
34 | `Superscript -> Atom "superscript"
35 | `Subscript -> Atom "subscript"
36
37 let alignment : Ast.alignment option -> sexp = function
38 | Some `Left -> Atom "left"
39 | Some `Center -> Atom "center"
40 | Some `Right -> Atom "right"
41 | None -> Atom "default"
42
43 let reference_kind : Ast.reference_kind -> sexp = function
44 | `Simple -> Atom "simple"
45 | `With_text -> Atom "with_text"
46
47 let media : Ast.media -> sexp = function
48 | `Image -> Atom "image"
49 | `Video -> Atom "video"
50 | `Audio -> Atom "audio"
51
52 let rec inline_element at : Ast.inline_element Loc.with_location -> sexp =
53 fun v ->
54 match v.value with
55 | `Space _ -> Atom "space"
56 | `Word w -> List [ Atom "word"; Atom w ]
57 | `Code_span c -> List [ Atom "code_span"; Atom c ]
58 | `Raw_markup (target, s) ->
59 List [ Atom "raw_markup"; opt str target; Atom s ]
60 | `Math_span s -> List [ Atom "math_span"; Atom s ]
61 | `Styled (s, es) ->
62 List [ style s; List (List.map (at.at (inline_element at)) es) ]
63 | `Reference (kind, r, es) ->
64 List
65 [
66 reference_kind kind;
67 at.at str_at r;
68 List (List.map (at.at (inline_element at)) es);
69 ]
70 | `Link (u, es) ->
71 List [ str u; List (List.map (at.at (inline_element at)) es) ]
72
73 let code_block_tags at tags =
74 let code_block_tag t =
75 match t with
76 | `Tag s -> List [ Atom "tag"; at.at str_at s ]
77 | `Binding (key, value) ->
78 List [ Atom "binding"; at.at str_at key; at.at str_at value ]
79 in
80 List (List.map code_block_tag tags)
81
82 let code_block_lang at { Ast.language; tags } =
83 List [ at.at str_at language; code_block_tags at tags ]
84
85 let media_href =
86 fun v ->
87 match v.Loc.value with
88 | `Reference href -> List [ Atom "Reference"; Atom href ]
89 | `Link href -> List [ Atom "Link"; Atom href ]
90
91 let rec nestable_block_element at :
92 Ast.nestable_block_element Loc.with_location -> sexp =
93 fun v ->
94 match v.value with
95 | `Paragraph es ->
96 List
97 [ Atom "paragraph"; List (List.map (at.at (inline_element at)) es) ]
98 | `Math_block s -> List [ Atom "math_block"; Atom s ]
99 | `Code_block { Ast.meta = None; content; output = None; _ } ->
100 let trimmed_content, warnings =
101 Odoc_parser.codeblock_content v.location content.value
102 in
103 let warnings =
104 if warnings = [] then []
105 else [ List (Atom "Warnings" :: List.map error warnings) ]
106 in
107 let content = Loc.at content.location trimmed_content in
108 List ([ Atom "code_block"; at.at str_at content ] @ warnings)
109 | `Code_block { meta = Some meta; content; output = None; _ } ->
110 let trimmed_content, warnings =
111 Odoc_parser.codeblock_content v.location content.value
112 in
113 let warnings =
114 if warnings = [] then []
115 else [ List (Atom "Warnings" :: List.map error warnings) ]
116 in
117 let content = Loc.at content.location trimmed_content in
118 List
119 ([ Atom "code_block"; code_block_lang at meta; at.at str_at content ]
120 @ warnings)
121 | `Code_block
122 {
123 meta = Some meta;
124 content;
125 output = Some output (* ; outer_location *);
126 _;
127 } ->
128 let trimmed_content, warnings =
129 Odoc_parser.codeblock_content v.location content.value
130 in
131 let warnings =
132 if warnings = [] then []
133 else [ List (Atom "Warnings" :: List.map error warnings) ]
134 in
135 let content = Loc.at content.location trimmed_content in
136 List
137 ([
138 Atom "code_block";
139 code_block_lang at meta;
140 at.at str_at content;
141 List (List.map (nestable_block_element at) output);
142 ]
143 @ warnings)
144 | `Code_block { meta = None; content = _; output = Some _output; _ } ->
145 List [ Atom "code_block_err" ]
146 | `Verbatim t ->
147 let trimmed_content, warnings =
148 Odoc_parser.verbatim_content v.location t
149 in
150 let warnings =
151 if warnings = [] then []
152 else [ List (Atom "Warnings" :: List.map error warnings) ]
153 in
154 List ([ Atom "verbatim"; Atom trimmed_content ] @ warnings)
155 | `Modules ps -> List [ Atom "modules"; List (List.map (at.at str_at) ps) ]
156 | `List (kind, weight, items) ->
157 let kind =
158 match kind with `Unordered -> "unordered" | `Ordered -> "ordered"
159 in
160 let weight =
161 match weight with `Light -> "light" | `Heavy -> "heavy"
162 in
163 let items =
164 items
165 |> List.map (fun item ->
166 List (List.map (at.at (nestable_block_element at)) item))
167 |> fun items -> List items
168 in
169 List [ Atom kind; Atom weight; items ]
170 | `Table ((grid, align), s) ->
171 let syntax = function `Light -> "light" | `Heavy -> "heavy" in
172 let kind = function `Header -> "header" | `Data -> "data" in
173 let map name x f = List [ Atom name; List (List.map f x) ] in
174 let alignment =
175 match align with
176 | None -> List [ Atom "align"; Atom "no alignment" ]
177 | Some align -> map "align" align @@ alignment
178 in
179 List
180 [
181 Atom "table";
182 List [ Atom "syntax"; Atom (syntax s) ];
183 ( map "grid" grid @@ fun row ->
184 map "row" row @@ fun (cell, k) ->
185 map (kind k) cell @@ at.at (nestable_block_element at) );
186 alignment;
187 ]
188 | `Media (kind, href, c, m) ->
189 List [ reference_kind kind; at.at media_href href; Atom c; media m ]
190
191 let tag at : Ast.tag -> sexp = function
192 | `Author s -> List [ Atom "@author"; Atom s ]
193 | `Deprecated es ->
194 List
195 (Atom "@deprecated" :: List.map (at.at (nestable_block_element at)) es)
196 | `Param (s, es) ->
197 List
198 ([ Atom "@param"; Atom s ]
199 @ List.map (at.at (nestable_block_element at)) es)
200 | `Raise (s, es) ->
201 List
202 ([ Atom "@raise"; Atom s ]
203 @ List.map (at.at (nestable_block_element at)) es)
204 | `Return es ->
205 List (Atom "@return" :: List.map (at.at (nestable_block_element at)) es)
206 | `Children_order es ->
207 List
208 (Atom "@children_order"
209 :: List.map (at.at (nestable_block_element at)) es)
210 | `Toc_status es ->
211 List
212 (Atom "@toc_status" :: List.map (at.at (nestable_block_element at)) es)
213 | `Order_category es ->
214 List
215 (Atom "@order_category"
216 :: List.map (at.at (nestable_block_element at)) es)
217 | `Short_title es ->
218 List
219 (Atom "@short_title"
220 :: List.map (at.at (nestable_block_element at)) es)
221 | `See (kind, s, es) ->
222 let kind =
223 match kind with
224 | `Url -> "url"
225 | `File -> "file"
226 | `Document -> "document"
227 in
228 List
229 ([ Atom "@see"; Atom kind; Atom s ]
230 @ List.map (at.at (nestable_block_element at)) es)
231 | `Since s -> List [ Atom "@since"; Atom s ]
232 | `Before (s, es) ->
233 List
234 ([ Atom "@before"; Atom s ]
235 @ List.map (at.at (nestable_block_element at)) es)
236 | `Version s -> List [ Atom "@version"; Atom s ]
237 | `Canonical p -> List [ Atom "@canonical"; at.at str_at p ]
238 | `Inline -> Atom "@inline"
239 | `Open -> Atom "@open"
240 | `Closed -> Atom "@closed"
241 | `Hidden -> Atom "@hidden"
242 | `Custom (s, es) ->
243 List
244 ([ Atom "@custom"; Atom s ]
245 @ List.map (at.at (nestable_block_element at)) es)
246
247 let block_element at : Ast.block_element Loc.with_location -> sexp = function
248 | { value = #Ast.nestable_block_element; _ } as e ->
249 nestable_block_element at e
250 | { value = `Heading (level, label, es); _ } ->
251 let label = List [ Atom "label"; opt str label ] in
252 let level = string_of_int level in
253 List
254 [ Atom level; label; List (List.map (at.at (inline_element at)) es) ]
255 | { value = `Tag t; _ } -> tag at t
256
257 let docs at : Ast.t -> sexp =
258 fun f -> List (List.map (at.at (block_element at)) f)
259end
260
261let parser_output formatter v =
262 let ast, warnings = Odoc_parser.(ast v, warnings v) in
263 let value = Ast_to_sexp.(docs loc_at ast) in
264 let warnings = List (List.map error warnings) in
265 let output =
266 List [ List [ Atom "output"; value ]; List [ Atom "warnings"; warnings ] ]
267 in
268 Sexplib0.Sexp.pp_hum formatter output;
269 Format.pp_print_flush formatter ()
270
271let test ?(location = { Loc.line = 1; column = 0 }) str =
272 let dummy_filename = "f.ml" in
273 let location =
274 {
275 Lexing.pos_fname = dummy_filename;
276 pos_lnum = location.line;
277 pos_bol = 0;
278 pos_cnum = location.column;
279 }
280 in
281 let ast = Odoc_parser.parse_comment ~location ~text:str in
282 Format.printf "%a" parser_output ast
283
284[@@@ocaml.warning "-32"]
285
286let%expect_test _ =
287 let module Trivial = struct
288 let empty =
289 test "";
290 [%expect "((output ()) (warnings ()))"]
291
292 let space =
293 test " ";
294 [%expect "((output ()) (warnings ()))"]
295
296 let two_spaces =
297 test " ";
298 [%expect "((output ()) (warnings ()))"]
299
300 let tab =
301 test "\t";
302 [%expect "((output ()) (warnings ()))"]
303
304 let mixed_space =
305 test " \t \t";
306 [%expect "((output ()) (warnings ()))"]
307
308 let newline =
309 test "\n";
310 [%expect "((output ()) (warnings ()))"]
311
312 let blank_line =
313 test "\n\n";
314 [%expect "((output ()) (warnings ()))"]
315
316 let cf_lf =
317 test "\r\n";
318 [%expect "((output ()) (warnings ()))"]
319 end in
320 ()
321
322let%expect_test _ =
323 let module One_paragraph = struct
324 let word =
325 test "foo";
326 [%expect
327 {|
328 ((output
329 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))))
330 (warnings ())) |}]
331
332 let two_words =
333 test "foo bar";
334 [%expect
335 {|
336 ((output
337 (((f.ml (1 0) (1 7))
338 (paragraph
339 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space)
340 ((f.ml (1 4) (1 7)) (word bar)))))))
341 (warnings ())) |}]
342
343 let two_words =
344 test "foo bar";
345 [%expect
346 {|
347 ((output
348 (((f.ml (1 0) (1 7))
349 (paragraph
350 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space)
351 ((f.ml (1 4) (1 7)) (word bar)))))))
352 (warnings ())) |}]
353
354 let two_spaces =
355 test "foo bar";
356 [%expect
357 {|
358 ((output
359 (((f.ml (1 0) (1 8))
360 (paragraph
361 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 5)) space)
362 ((f.ml (1 5) (1 8)) (word bar)))))))
363 (warnings ())) |}]
364
365 let mixed_space =
366 test "foo \t \t bar";
367 [%expect
368 {|
369 ((output
370 (((f.ml (1 0) (1 11))
371 (paragraph
372 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 8)) space)
373 ((f.ml (1 8) (1 11)) (word bar)))))))
374 (warnings ())) |}]
375
376 let two_lines =
377 test "foo\n";
378 [%expect
379 {|
380 ((output
381 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))))
382 (warnings ())) |}]
383
384 let two_lines_cr_lf =
385 test "foo\r\nbar";
386 [%expect
387 {|
388 ((output
389 (((f.ml (1 0) (2 3))
390 (paragraph
391 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (2 0)) space)
392 ((f.ml (2 0) (2 3)) (word bar)))))))
393 (warnings ())) |}]
394
395 let leading_space =
396 test " foo";
397 [%expect
398 {|
399 ((output
400 (((f.ml (1 1) (1 4)) (paragraph (((f.ml (1 1) (1 4)) (word foo)))))))
401 (warnings ())) |}]
402
403 let trailing_space =
404 test "foo ";
405 [%expect
406 {|
407 ((output
408 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))))
409 (warnings ())) |}]
410
411 let leading_space_on_line =
412 test "foo\n bar";
413 [%expect
414 {|
415 ((output
416 (((f.ml (1 0) (2 4))
417 (paragraph
418 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (2 1)) space)
419 ((f.ml (2 1) (2 4)) (word bar)))))))
420 (warnings ())) |}]
421
422 let trailing_space_on_line =
423 test "foo \nbar";
424 [%expect
425 {|
426 ((output
427 (((f.ml (1 0) (2 3))
428 (paragraph
429 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (2 0)) space)
430 ((f.ml (2 0) (2 3)) (word bar)))))))
431 (warnings ())) |}]
432
433 let leading_tab_on_line =
434 test "foo\n\tbar";
435 [%expect
436 {|
437 ((output
438 (((f.ml (1 0) (2 4))
439 (paragraph
440 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (2 1)) space)
441 ((f.ml (2 1) (2 4)) (word bar)))))))
442 (warnings ())) |}]
443
444 let trailing_tab_on_line =
445 test "foo\t\nbar";
446 [%expect
447 {|
448 ((output
449 (((f.ml (1 0) (2 3))
450 (paragraph
451 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (2 0)) space)
452 ((f.ml (2 0) (2 3)) (word bar)))))))
453 (warnings ())) |}]
454
455 let email =
456 test "foo@bar.com";
457 [%expect
458 {|
459 ((output
460 (((f.ml (1 0) (1 11))
461 (paragraph (((f.ml (1 0) (1 11)) (word foo@bar.com)))))))
462 (warnings ())) |}]
463 end in
464 ()
465
466let%expect_test _ =
467 let module Two_paragraphs = struct
468 let basic =
469 test "foo\n\nbar";
470 [%expect
471 {|
472 ((output
473 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
474 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))
475 (warnings ())) |}]
476
477 let leading_space =
478 test "foo \n\nbar";
479 [%expect
480 {|
481 ((output
482 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
483 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))
484 (warnings ())) |}]
485
486 let trailing_space =
487 test "foo\n\n bar";
488 [%expect
489 {|
490 ((output
491 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
492 ((f.ml (3 1) (3 4)) (paragraph (((f.ml (3 1) (3 4)) (word bar)))))))
493 (warnings ())) |}]
494
495 let cr_lf =
496 test "foo\r\n\r\nbar";
497 [%expect
498 {|
499 ((output
500 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
501 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))
502 (warnings ())) |}]
503
504 let mixed_cr_lf =
505 test "foo\n\r\nbar";
506 [%expect
507 {|
508 ((output
509 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
510 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))
511 (warnings ())) |}]
512 end in
513 ()
514
515let%expect_test _ =
516 let module Plus_minus_bar_words = struct
517 let minus_in_word =
518 test "foo-bar";
519 [%expect
520 {|
521 ((output
522 (((f.ml (1 0) (1 7)) (paragraph (((f.ml (1 0) (1 7)) (word foo-bar)))))))
523 (warnings ())) |}]
524
525 let minus_as_word =
526 test "foo -";
527 [%expect
528 {|
529 ((output
530 (((f.ml (1 0) (1 5))
531 (paragraph
532 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space)
533 ((f.ml (1 4) (1 5)) (word -)))))))
534 (warnings ())) |}]
535
536 let plus_in_word =
537 test "foo+bar";
538 [%expect
539 {|
540 ((output
541 (((f.ml (1 0) (1 7)) (paragraph (((f.ml (1 0) (1 7)) (word foo+bar)))))))
542 (warnings ())) |}]
543
544 let plus_as_word =
545 test "foo +";
546 [%expect
547 {|
548 ((output
549 (((f.ml (1 0) (1 5))
550 (paragraph
551 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space)
552 ((f.ml (1 4) (1 5)) (word +)))))))
553 (warnings ())) |}]
554
555 let bar_in_word =
556 test "foo|bar";
557 [%expect
558 {|
559 ((output
560 (((f.ml (1 0) (1 7))
561 (paragraph
562 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) (word |))
563 ((f.ml (1 4) (1 7)) (word bar)))))))
564 (warnings ())) |}]
565
566 let escaped_bar_in_word =
567 test "foo\\|bar";
568 [%expect
569 {|
570 ((output
571 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word "foo\\|bar")))))))
572 (warnings ())) |}]
573
574 let bar_as_word =
575 test "foo |";
576 [%expect
577 {|
578 ((output
579 (((f.ml (1 0) (1 5))
580 (paragraph
581 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space)
582 ((f.ml (1 4) (1 5)) (word |)))))))
583 (warnings ())) |}]
584
585 let negative_number =
586 test "-3.14 -1337";
587 [%expect
588 {|
589 ((output
590 (((f.ml (1 0) (1 11))
591 (paragraph
592 (((f.ml (1 0) (1 5)) (word -3.14)) ((f.ml (1 5) (1 6)) space)
593 ((f.ml (1 6) (1 11)) (word -1337)))))))
594 (warnings ())) |}]
595
596 let n_em_dash =
597 test "-- ---";
598 [%expect
599 {|
600 ((output
601 (((f.ml (1 0) (1 6))
602 (paragraph
603 (((f.ml (1 0) (1 2)) (word --)) ((f.ml (1 2) (1 3)) space)
604 ((f.ml (1 3) (1 6)) (word ---)))))))
605 (warnings ())) |}]
606
607 let minus_at =
608 test "-@";
609 [%expect
610 {|
611 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word -@)))))))
612 (warnings ())) |}]
613
614 let at_minus =
615 test "-@-";
616 [%expect
617 {|
618 ((output
619 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word -@-)))))))
620 (warnings ())) |}]
621
622 let option =
623 test "--option";
624 [%expect
625 {|
626 ((output
627 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word --option)))))))
628 (warnings ())) |}]
629 end in
630 ()
631
632let%expect_test _ =
633 let module Escape_sequence = struct
634 let left_brace =
635 test "\\{";
636 [%expect
637 {|
638 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word {)))))))
639 (warnings ())) |}]
640
641 let left_brace_in_word =
642 test "foo\\{bar";
643 [%expect
644 {|
645 ((output
646 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word foo{bar)))))))
647 (warnings ())) |}]
648
649 let right_brace =
650 test "\\}";
651 [%expect
652 {|
653 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word })))))))
654 (warnings ())) |}]
655
656 let right_brace_in_word =
657 test "foo\\{bar";
658 [%expect
659 {|
660 ((output
661 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word foo{bar)))))))
662 (warnings ())) |}]
663
664 let left_bracket =
665 test "\\[";
666 [%expect
667 {|
668 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word [)))))))
669 (warnings ())) |}]
670
671 let left_bracket_in_word =
672 test "foo\\[bar";
673 [%expect
674 {|
675 ((output
676 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word foo[bar)))))))
677 (warnings ())) |}]
678
679 let right_bracket =
680 test "\\]";
681 [%expect
682 {|
683 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word ])))))))
684 (warnings ())) |}]
685
686 let right_bracket_in_word =
687 test "foo\\]bar";
688 [%expect
689 {|
690 ((output
691 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word foo]bar)))))))
692 (warnings ())) |}]
693
694 let at =
695 test "@";
696 [%expect
697 {|
698 ((output (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word @)))))))
699 (warnings ( "File \"f.ml\", line 1, characters 0-1:\
700 \nStray '@'."))) |}]
701
702 let not_a_tag =
703 test "\\@author";
704 [%expect
705 {|
706 ((output
707 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word @author)))))))
708 (warnings ())) |}]
709
710 let at_in_word =
711 test "foo\\@bar";
712 [%expect
713 {|
714 ((output
715 (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (word foo@bar)))))))
716 (warnings ())) |}]
717
718 let trailing_backslash =
719 test "foo\\";
720 [%expect
721 {|
722 ((output
723 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (word "foo\\")))))))
724 (warnings ())) |}]
725
726 let none_escape =
727 test "foo\\bar";
728 [%expect
729 {|
730 ((output
731 (((f.ml (1 0) (1 7)) (paragraph (((f.ml (1 0) (1 7)) (word "foo\\bar")))))))
732 (warnings ())) |}]
733
734 let backslash_not_escaped =
735 test "foo\\\\{bar";
736 [%expect
737 {|
738 ((output
739 (((f.ml (1 0) (1 9)) (paragraph (((f.ml (1 0) (1 9)) (word "foo\\{bar")))))))
740 (warnings ())) |}]
741
742 let single_backslash =
743 test "\\";
744 [%expect
745 {|
746 ((output
747 (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word "\\")))))))
748 (warnings ())) |}]
749
750 let escape_minus =
751 test "\\{- foo";
752 [%expect
753 {|
754 ((output
755 (((f.ml (1 0) (1 7))
756 (paragraph
757 (((f.ml (1 0) (1 3)) (word {-)) ((f.ml (1 3) (1 4)) space)
758 ((f.ml (1 4) (1 7)) (word foo)))))))
759 (warnings ())) |}]
760
761 let escape_plus =
762 test "\\{+ foo";
763 [%expect
764 {|
765 ((output
766 (((f.ml (1 0) (1 7))
767 (paragraph
768 (((f.ml (1 0) (1 3)) (word {+)) ((f.ml (1 3) (1 4)) space)
769 ((f.ml (1 4) (1 7)) (word foo)))))))
770 (warnings ())) |}]
771
772 let minus_escape =
773 test "-\\{";
774 [%expect
775 {|
776 ((output (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word -{)))))))
777 (warnings ())) |}]
778
779 let plus_escape =
780 test "+\\{";
781 [%expect
782 {|
783 ((output (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word +{)))))))
784 (warnings ())) |}]
785
786 let escape_at =
787 test "\\{@author";
788 [%expect
789 {|
790 ((output
791 (((f.ml (1 0) (1 9)) (paragraph (((f.ml (1 0) (1 9)) (word {@author)))))))
792 (warnings ())) |}]
793
794 let two =
795 test "\\{\\}";
796 [%expect
797 {|
798 ((output (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (word {})))))))
799 (warnings ())) |}]
800 end in
801 ()
802
803let%expect_test _ =
804 let module Code_span = struct
805 let basic =
806 test "[foo]";
807 [%expect
808 {|
809 ((output
810 (((f.ml (1 0) (1 5)) (paragraph (((f.ml (1 0) (1 5)) (code_span foo)))))))
811 (warnings ())) |}]
812
813 let empty =
814 test "[]";
815 [%expect
816 {|
817 ((output
818 (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (code_span "")))))))
819 (warnings ())) |}]
820
821 let list =
822 test "[[]]";
823 [%expect
824 {|
825 ((output
826 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (code_span [])))))))
827 (warnings ())) |}]
828 (* TODO The next two error messages are particularly unintuitive. *)
829
830 let unbalanced_list =
831 test "[[]";
832 [%expect
833 {|
834 ((output
835 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (code_span [])))))))
836 (warnings
837 ( "File \"f.ml\", line 1, characters 3-3:\
838 \nEnd of text is not allowed in '[...]' (code)."))) |}]
839
840 let no_markup =
841 test "[{b";
842 [%expect
843 {|
844 ((output
845 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (code_span {b)))))))
846 (warnings
847 ( "File \"f.ml\", line 1, characters 3-3:\
848 \nEnd of text is not allowed in '[...]' (code)."))) |}]
849
850 let few_escapes =
851 test "[\\{]";
852 [%expect
853 {|
854 ((output
855 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (code_span "\\{")))))))
856 (warnings ())) |}]
857
858 let escaped_right_bracket =
859 test "[\\]]";
860 [%expect
861 {|
862 ((output
863 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (code_span ])))))))
864 (warnings ())) |}]
865
866 let escaped_left_bracket =
867 test "[\\[]";
868 [%expect
869 {|
870 ((output
871 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (code_span [)))))))
872 (warnings ())) |}]
873
874 let whitespace_preserved =
875 test "[ foo bar ]";
876 [%expect
877 {|
878 ((output
879 (((f.ml (1 0) (1 11))
880 (paragraph (((f.ml (1 0) (1 11)) (code_span " foo bar ")))))))
881 (warnings ())) |}]
882
883 let no_new_lines =
884 test "[foo\nbar]";
885 [%expect
886 {|
887 ((output
888 (((f.ml (1 0) (2 4))
889 (paragraph (((f.ml (1 0) (2 4)) (code_span "foo bar")))))))
890 (warnings ())) |}]
891
892 let cr_lf_preserved =
893 test "[foo\r\nbar]";
894 [%expect
895 {|
896 ((output
897 (((f.ml (1 0) (2 4))
898 (paragraph (((f.ml (1 0) (2 4)) (code_span "foo bar")))))))
899 (warnings ())) |}]
900
901 let no_double_new_line =
902 test "[foo\r\n\r\nbar]";
903 [%expect
904 {|
905 ((output
906 (((f.ml (1 0) (3 4))
907 (paragraph (((f.ml (1 0) (3 4)) (code_span "foo bar")))))))
908 (warnings
909 ( "File \"f.ml\", line 1, character 4 to line 3, character 0:\
910 \nBlank line is not allowed in '[...]' (code)."))) |}]
911
912 let no_double_crlf =
913 test "[foo\r\n\r\nbar]";
914 [%expect
915 {|
916 ((output
917 (((f.ml (1 0) (3 4))
918 (paragraph (((f.ml (1 0) (3 4)) (code_span "foo bar")))))))
919 (warnings
920 ( "File \"f.ml\", line 1, character 4 to line 3, character 0:\
921 \nBlank line is not allowed in '[...]' (code)."))) |}]
922
923 let not_merged =
924 test "[foo][bar]";
925 [%expect
926 {|
927 ((output
928 (((f.ml (1 0) (1 10))
929 (paragraph
930 (((f.ml (1 0) (1 5)) (code_span foo))
931 ((f.ml (1 5) (1 10)) (code_span bar)))))))
932 (warnings ())) |}]
933
934 let explicit_space =
935 test "[foo] [bar]";
936 [%expect
937 {|
938 ((output
939 (((f.ml (1 0) (1 11))
940 (paragraph
941 (((f.ml (1 0) (1 5)) (code_span foo)) ((f.ml (1 5) (1 6)) space)
942 ((f.ml (1 6) (1 11)) (code_span bar)))))))
943 (warnings ())) |}]
944
945 let untermindated =
946 test "[foo";
947 [%expect
948 {|
949 ((output
950 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (code_span foo)))))))
951 (warnings
952 ( "File \"f.ml\", line 1, characters 4-4:\
953 \nEnd of text is not allowed in '[...]' (code)."))) |}]
954 end in
955 ()
956
957let%expect_test _ =
958 let module Bold = struct
959 let basic =
960 test "{b foo}";
961 [%expect
962 {|
963 ((output
964 (((f.ml (1 0) (1 7))
965 (paragraph
966 (((f.ml (1 0) (1 7)) (bold (((f.ml (1 3) (1 6)) (word foo))))))))))
967 (warnings ())) |}]
968
969 let extra_leading_whitespace =
970 test "{b \t foo}";
971 [%expect
972 {|
973 ((output
974 (((f.ml (1 0) (1 10))
975 (paragraph
976 (((f.ml (1 0) (1 10)) (bold (((f.ml (1 6) (1 9)) (word foo))))))))))
977 (warnings ())) |}]
978
979 let leading_newline =
980 test "{b\nfoo}";
981 [%expect
982 {|
983 ((output
984 (((f.ml (1 0) (2 4))
985 (paragraph
986 (((f.ml (1 0) (2 4)) (bold (((f.ml (2 0) (2 3)) (word foo))))))))))
987 (warnings ())) |}]
988
989 let leading_cr_lf =
990 test "{b\r\nfoo}";
991 [%expect
992 {|
993 ((output
994 (((f.ml (1 0) (2 4))
995 (paragraph
996 (((f.ml (1 0) (2 4)) (bold (((f.ml (2 0) (2 3)) (word foo))))))))))
997 (warnings ())) |}]
998
999 let leading_newline_and_whitespace =
1000 test "{b\n foo}";
1001 [%expect
1002 {|
1003 ((output
1004 (((f.ml (1 0) (2 5))
1005 (paragraph
1006 (((f.ml (1 0) (2 5)) (bold (((f.ml (2 1) (2 4)) (word foo))))))))))
1007 (warnings ())) |}]
1008
1009 let no_leading_whitespace =
1010 test "{bfoo}";
1011 [%expect
1012 {|
1013 ((output
1014 (((f.ml (1 0) (1 6))
1015 (paragraph
1016 (((f.ml (1 0) (1 6)) (bold (((f.ml (1 2) (1 5)) (word foo))))))))))
1017 (warnings
1018 ( "File \"f.ml\", line 1, characters 0-2:\
1019 \n'{b' should be followed by space, a tab, or a new line."))) |}]
1020
1021 let trailing_whitespace =
1022 test "{b foo }";
1023 [%expect
1024 {|
1025 ((output
1026 (((f.ml (1 0) (1 8))
1027 (paragraph
1028 (((f.ml (1 0) (1 8)) (bold (((f.ml (1 3) (1 6)) (word foo))))))))))
1029 (warnings ())) |}]
1030
1031 let trailing_newline =
1032 test "{b foo\n}";
1033 [%expect
1034 {|
1035 ((output
1036 (((f.ml (1 0) (2 1))
1037 (paragraph
1038 (((f.ml (1 0) (2 1)) (bold (((f.ml (1 3) (1 6)) (word foo))))))))))
1039 (warnings ())) |}]
1040
1041 let trailing_cr_lf =
1042 test "{b foo\r\n}";
1043 [%expect
1044 {|
1045 ((output
1046 (((f.ml (1 0) (2 1))
1047 (paragraph
1048 (((f.ml (1 0) (2 1)) (bold (((f.ml (1 3) (1 6)) (word foo))))))))))
1049 (warnings ())) |}]
1050
1051 let two_words =
1052 test "{b foo bar}";
1053 [%expect
1054 {|
1055 ((output
1056 (((f.ml (1 0) (1 11))
1057 (paragraph
1058 (((f.ml (1 0) (1 11))
1059 (bold
1060 (((f.ml (1 3) (1 6)) (word foo)) ((f.ml (1 6) (1 7)) space)
1061 ((f.ml (1 7) (1 10)) (word bar))))))))))
1062 (warnings ())) |}]
1063
1064 let not_merged =
1065 test "{b foo}{b bar}";
1066 [%expect
1067 {|
1068 ((output
1069 (((f.ml (1 0) (1 14))
1070 (paragraph
1071 (((f.ml (1 0) (1 7)) (bold (((f.ml (1 3) (1 6)) (word foo)))))
1072 ((f.ml (1 7) (1 14)) (bold (((f.ml (1 10) (1 13)) (word bar))))))))))
1073 (warnings ())) |}]
1074
1075 let nested =
1076 test "{b foo{b bar}}";
1077 [%expect
1078 {|
1079 ((output
1080 (((f.ml (1 0) (1 14))
1081 (paragraph
1082 (((f.ml (1 0) (1 14))
1083 (bold
1084 (((f.ml (1 3) (1 6)) (word foo))
1085 ((f.ml (1 6) (1 13)) (bold (((f.ml (1 9) (1 12)) (word bar)))))))))))))
1086 (warnings ())) |}]
1087
1088 let newline =
1089 test "{b foo\nbar}";
1090 [%expect
1091 {|
1092 ((output
1093 (((f.ml (1 0) (2 4))
1094 (paragraph
1095 (((f.ml (1 0) (2 4))
1096 (bold
1097 (((f.ml (1 3) (1 6)) (word foo)) ((f.ml (1 6) (2 0)) space)
1098 ((f.ml (2 0) (2 3)) (word bar))))))))))
1099 (warnings ())) |}]
1100
1101 let cr_lf =
1102 test "{b foo\r\nbar}";
1103 [%expect
1104 {|
1105 ((output
1106 (((f.ml (1 0) (2 4))
1107 (paragraph
1108 (((f.ml (1 0) (2 4))
1109 (bold
1110 (((f.ml (1 3) (1 6)) (word foo)) ((f.ml (1 6) (2 0)) space)
1111 ((f.ml (2 0) (2 3)) (word bar))))))))))
1112 (warnings ())) |}]
1113
1114 let minus =
1115 test "{b -}";
1116 [%expect
1117 {|
1118 ((output
1119 (((f.ml (1 0) (1 5))
1120 (paragraph (((f.ml (1 0) (1 5)) (bold (((f.ml (1 3) (1 4)) (word -))))))))))
1121 (warnings ())) |}]
1122
1123 let minus_list_item =
1124 test "{b foo\n - bar}";
1125 [%expect
1126 {|
1127 ((output
1128 (((f.ml (1 0) (2 7))
1129 (paragraph
1130 (((f.ml (1 0) (2 7))
1131 (bold
1132 (((f.ml (1 3) (1 6)) (word foo)) ((f.ml (1 6) (2 1)) space)
1133 ((f.ml (2 1) (2 2)) (word -)) ((f.ml (2 2) (2 3)) space)
1134 ((f.ml (2 3) (2 6)) (word bar))))))))))
1135 (warnings
1136 ( "File \"f.ml\", line 2, characters 1-2:\
1137 \n'-' (bulleted list item) is not allowed in '{b ...}' (boldface text).\
1138 \nSuggestion: move '-' so it isn't the first thing on the line."))) |}]
1139
1140 let plus_list_item =
1141 test "{b foo\n + bar}";
1142 [%expect
1143 {|
1144 ((output
1145 (((f.ml (1 0) (2 7))
1146 (paragraph
1147 (((f.ml (1 0) (2 7))
1148 (bold
1149 (((f.ml (1 3) (1 6)) (word foo)) ((f.ml (1 6) (2 1)) space)
1150 ((f.ml (2 1) (2 2)) (word +)) ((f.ml (2 2) (2 3)) space)
1151 ((f.ml (2 3) (2 6)) (word bar))))))))))
1152 (warnings
1153 ( "File \"f.ml\", line 2, characters 1-2:\
1154 \n'+' (numbered list item) is not allowed in '{b ...}' (boldface text).\
1155 \nSuggestion: move '+' so it isn't the first thing on the line."))) |}]
1156
1157 let immediate_minus_list_item =
1158 test "{b\n- foo}";
1159 [%expect
1160 {|
1161 ((output
1162 (((f.ml (1 0) (2 6))
1163 (paragraph
1164 (((f.ml (1 0) (2 6))
1165 (bold
1166 (((f.ml (2 0) (2 1)) (word -)) ((f.ml (2 1) (2 2)) space)
1167 ((f.ml (2 2) (2 5)) (word foo))))))))))
1168 (warnings
1169 ( "File \"f.ml\", line 2, characters 0-1:\
1170 \n'-' (bulleted list item) is not allowed in '{b ...}' (boldface text).\
1171 \nSuggestion: move '-' so it isn't the first thing on the line."))) |}]
1172
1173 let immediate_plus_list_item =
1174 test "{b\n+ foo}";
1175 [%expect
1176 {|
1177 ((output
1178 (((f.ml (1 0) (2 6))
1179 (paragraph
1180 (((f.ml (1 0) (2 6))
1181 (bold
1182 (((f.ml (2 0) (2 1)) (word +)) ((f.ml (2 1) (2 2)) space)
1183 ((f.ml (2 2) (2 5)) (word foo))))))))))
1184 (warnings
1185 ( "File \"f.ml\", line 2, characters 0-1:\
1186 \n'+' (numbered list item) is not allowed in '{b ...}' (boldface text).\
1187 \nSuggestion: move '+' so it isn't the first thing on the line."))) |}]
1188
1189 let blank_line =
1190 test "{b foo\n\nbar}";
1191 [%expect
1192 {|
1193 ((output
1194 (((f.ml (1 0) (3 4))
1195 (paragraph
1196 (((f.ml (1 0) (3 4))
1197 (bold
1198 (((f.ml (1 3) (1 6)) (word foo)) ((f.ml (2 0) (2 0)) space)
1199 ((f.ml (3 0) (3 3)) (word bar))))))))))
1200 (warnings
1201 ( "File \"f.ml\", line 2, characters 0-0:\
1202 \nBlank line is not allowed in '{b ...}' (boldface text)."))) |}]
1203
1204 let immediate_blank_line =
1205 test "{b";
1206 [%expect
1207 {|
1208 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (bold ())))))))
1209 (warnings
1210 ( "File \"f.ml\", line 1, characters 0-2:\
1211 \n'{b' should be followed by space, a tab, or a new line."
1212 "File \"f.ml\", line 1, characters 2-2:\
1213 \nEnd of text is not allowed in '{b ...}' (boldface text)."
1214 "File \"f.ml\", line 1, characters 0-2:\
1215 \n'{b ...}' (boldface text) should not be empty."))) |}]
1216
1217 let end_of_comment =
1218 test "{b foo";
1219 [%expect
1220 {|
1221 ((output
1222 (((f.ml (1 0) (1 6))
1223 (paragraph
1224 (((f.ml (1 0) (1 6)) (bold (((f.ml (1 3) (1 6)) (word foo))))))))))
1225 (warnings
1226 ( "File \"f.ml\", line 1, characters 6-6:\
1227 \nEnd of text is not allowed in '{b ...}' (boldface text)."))) |}]
1228
1229 let nested_code_block =
1230 test "{b {[foo]}";
1231 [%expect
1232 {|
1233 ((output
1234 (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (bold ())))))
1235 ((f.ml (1 3) (1 10)) (code_block ((f.ml (1 5) (1 8)) foo)))))
1236 (warnings
1237 ( "File \"f.ml\", line 1, characters 3-10:\
1238 \n'{[...]}' (code block) is not allowed in '{b ...}' (boldface text)."
1239 "File \"f.ml\", line 1, characters 0-2:\
1240 \n'{b ...}' (boldface text) should not be empty."
1241 "File \"f.ml\", line 1, characters 3-10:\
1242 \n'{[...]}' (code block) should begin on its own line."))) |}]
1243
1244 let degenerate =
1245 test "{b}";
1246 [%expect
1247 {|
1248 ((output (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (bold ())))))))
1249 (warnings
1250 ( "File \"f.ml\", line 1, characters 0-3:\
1251 \n'{b ...}' (boldface text) should not be empty."))) |}]
1252
1253 let empty =
1254 test "{b }";
1255 [%expect
1256 {|
1257 ((output (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (bold ())))))))
1258 (warnings
1259 ( "File \"f.ml\", line 1, characters 0-4:\
1260 \n'{b ...}' (boldface text) should not be empty."))) |}]
1261 end in
1262 ()
1263
1264let%expect_test _ =
1265 let module Italic = struct
1266 let basic =
1267 test "{i foo}";
1268 [%expect
1269 {|
1270 ((output
1271 (((f.ml (1 0) (1 7))
1272 (paragraph
1273 (((f.ml (1 0) (1 7)) (italic (((f.ml (1 3) (1 6)) (word foo))))))))))
1274 (warnings ())) |}]
1275
1276 let extra_leading_whitespace =
1277 test "{i \t foo}";
1278 [%expect
1279 {|
1280 ((output
1281 (((f.ml (1 0) (1 10))
1282 (paragraph
1283 (((f.ml (1 0) (1 10)) (italic (((f.ml (1 6) (1 9)) (word foo))))))))))
1284 (warnings ())) |}]
1285
1286 let leading_newline =
1287 test "{i\nfoo}";
1288 [%expect
1289 {|
1290 ((output
1291 (((f.ml (1 0) (2 4))
1292 (paragraph
1293 (((f.ml (1 0) (2 4)) (italic (((f.ml (2 0) (2 3)) (word foo))))))))))
1294 (warnings ())) |}]
1295
1296 let leading_newline_and_whitespace =
1297 test "{i\n foo}";
1298 [%expect
1299 {|
1300 ((output
1301 (((f.ml (1 0) (2 5))
1302 (paragraph
1303 (((f.ml (1 0) (2 5)) (italic (((f.ml (2 1) (2 4)) (word foo))))))))))
1304 (warnings ())) |}]
1305 end in
1306 ()
1307
1308let%expect_test _ =
1309 let module Emphasis = struct
1310 let basic =
1311 test "{e foo}";
1312 [%expect
1313 {|
1314 ((output
1315 (((f.ml (1 0) (1 7))
1316 (paragraph
1317 (((f.ml (1 0) (1 7)) (emphasis (((f.ml (1 3) (1 6)) (word foo))))))))))
1318 (warnings ())) |}]
1319
1320 let extra_leading_whitespace =
1321 test "{e \t foo}";
1322 [%expect
1323 {|
1324 ((output
1325 (((f.ml (1 0) (1 10))
1326 (paragraph
1327 (((f.ml (1 0) (1 10)) (emphasis (((f.ml (1 6) (1 9)) (word foo))))))))))
1328 (warnings ())) |}]
1329
1330 let leading_newline =
1331 test "{e\nfoo}";
1332 [%expect
1333 {|
1334 ((output
1335 (((f.ml (1 0) (2 4))
1336 (paragraph
1337 (((f.ml (1 0) (2 4)) (emphasis (((f.ml (2 0) (2 3)) (word foo))))))))))
1338 (warnings ())) |}]
1339
1340 let leading_newline_and_whitespace =
1341 test "{e\n foo}";
1342 [%expect
1343 {|
1344 ((output
1345 (((f.ml (1 0) (2 5))
1346 (paragraph
1347 (((f.ml (1 0) (2 5)) (emphasis (((f.ml (2 1) (2 4)) (word foo))))))))))
1348 (warnings ())) |}]
1349 end in
1350 ()
1351
1352let%expect_test _ =
1353 let module Superscript = struct
1354 let basic =
1355 test "{^ foo}";
1356 [%expect
1357 {|
1358 ((output
1359 (((f.ml (1 0) (1 7))
1360 (paragraph
1361 (((f.ml (1 0) (1 7)) (superscript (((f.ml (1 3) (1 6)) (word foo))))))))))
1362 (warnings ())) |}]
1363
1364 let extra_leading_whitespace =
1365 test "{^ \t foo}";
1366 [%expect
1367 {|
1368 ((output
1369 (((f.ml (1 0) (1 10))
1370 (paragraph
1371 (((f.ml (1 0) (1 10)) (superscript (((f.ml (1 6) (1 9)) (word foo))))))))))
1372 (warnings ())) |}]
1373
1374 let leading_newline =
1375 test "{^\nfoo}";
1376 [%expect
1377 {|
1378 ((output
1379 (((f.ml (1 0) (2 4))
1380 (paragraph
1381 (((f.ml (1 0) (2 4)) (superscript (((f.ml (2 0) (2 3)) (word foo))))))))))
1382 (warnings ())) |}]
1383
1384 let leading_cr_lf =
1385 test "{^\r\nfoo}";
1386 [%expect
1387 {|
1388 ((output
1389 (((f.ml (1 0) (2 4))
1390 (paragraph
1391 (((f.ml (1 0) (2 4)) (superscript (((f.ml (2 0) (2 3)) (word foo))))))))))
1392 (warnings ())) |}]
1393
1394 let leading_newline_and_whitespace =
1395 test "{^\n foo}";
1396 [%expect
1397 {|
1398 ((output
1399 (((f.ml (1 0) (2 5))
1400 (paragraph
1401 (((f.ml (1 0) (2 5)) (superscript (((f.ml (2 1) (2 4)) (word foo))))))))))
1402 (warnings ())) |}]
1403
1404 let no_whitespace =
1405 test "{^foo}";
1406 [%expect
1407 {|
1408 ((output
1409 (((f.ml (1 0) (1 6))
1410 (paragraph
1411 (((f.ml (1 0) (1 6)) (superscript (((f.ml (1 2) (1 5)) (word foo))))))))))
1412 (warnings ())) |}]
1413
1414 let degenerate =
1415 test "{^}";
1416 [%expect
1417 {|
1418 ((output
1419 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (superscript ())))))))
1420 (warnings
1421 ( "File \"f.ml\", line 1, characters 0-3:\
1422 \n'{^...}' (superscript) should not be empty."))) |}]
1423
1424 let empty =
1425 test "{^ }";
1426 [%expect
1427 {|
1428 ((output
1429 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (superscript ())))))))
1430 (warnings
1431 ( "File \"f.ml\", line 1, characters 0-4:\
1432 \n'{^...}' (superscript) should not be empty."))) |}]
1433 end in
1434 ()
1435
1436let%expect_test _ =
1437 let module Subscript = struct
1438 let basic =
1439 test "{_ foo}";
1440 [%expect
1441 {|
1442 ((output
1443 (((f.ml (1 0) (1 7))
1444 (paragraph
1445 (((f.ml (1 0) (1 7)) (subscript (((f.ml (1 3) (1 6)) (word foo))))))))))
1446 (warnings ())) |}]
1447
1448 let extra_leading_whitespace =
1449 test "{_ \t foo}";
1450 [%expect
1451 {|
1452 ((output
1453 (((f.ml (1 0) (1 10))
1454 (paragraph
1455 (((f.ml (1 0) (1 10)) (subscript (((f.ml (1 6) (1 9)) (word foo))))))))))
1456 (warnings ())) |}]
1457
1458 let leading_newline =
1459 test "{_\nfoo}";
1460 [%expect
1461 {|
1462 ((output
1463 (((f.ml (1 0) (2 4))
1464 (paragraph
1465 (((f.ml (1 0) (2 4)) (subscript (((f.ml (2 0) (2 3)) (word foo))))))))))
1466 (warnings ())) |}]
1467
1468 let leading_newline_and_whitespace =
1469 test "{_\n foo}";
1470 [%expect
1471 {|
1472 ((output
1473 (((f.ml (1 0) (2 5))
1474 (paragraph
1475 (((f.ml (1 0) (2 5)) (subscript (((f.ml (2 1) (2 4)) (word foo))))))))))
1476 (warnings ())) |}]
1477
1478 let no_whitespace =
1479 test "{_foo}";
1480 [%expect
1481 {|
1482 ((output
1483 (((f.ml (1 0) (1 6))
1484 (paragraph
1485 (((f.ml (1 0) (1 6)) (subscript (((f.ml (1 2) (1 5)) (word foo))))))))))
1486 (warnings ())) |}]
1487
1488 let v_verbose =
1489 test "{_uv}";
1490 [%expect
1491 {|
1492 ((output
1493 (((f.ml (1 0) (1 5))
1494 (paragraph
1495 (((f.ml (1 0) (1 5)) (subscript (((f.ml (1 2) (1 4)) (word uv))))))))))
1496 (warnings ())) |}]
1497 end in
1498 ()
1499
1500let%expect_test _ =
1501 let module Simple_reference = struct
1502 let basic =
1503 test "{!foo}";
1504 [%expect
1505 {|
1506 ((output
1507 (((f.ml (1 0) (1 6))
1508 (paragraph (((f.ml (1 0) (1 6)) (simple ((f.ml (1 2) (1 6)) foo) ())))))))
1509 (warnings ())) |}]
1510
1511 let leading_whitespace =
1512 test "{! foo}";
1513 [%expect
1514 {|
1515 ((output
1516 (((f.ml (1 0) (1 7))
1517 (paragraph
1518 (((f.ml (1 0) (1 7)) (simple ((f.ml (1 2) (1 7)) " foo") ())))))))
1519 (warnings ())) |}]
1520
1521 let trailing_whitespace =
1522 test "{!foo }";
1523 [%expect
1524 {|
1525 ((output
1526 (((f.ml (1 0) (1 7))
1527 (paragraph
1528 (((f.ml (1 0) (1 7)) (simple ((f.ml (1 2) (1 7)) "foo ") ())))))))
1529 (warnings ())) |}]
1530
1531 let adjacent_word_leading =
1532 test "bar{!foo}";
1533 [%expect
1534 {|
1535 ((output
1536 (((f.ml (1 0) (1 9))
1537 (paragraph
1538 (((f.ml (1 0) (1 3)) (word bar))
1539 ((f.ml (1 3) (1 9)) (simple ((f.ml (1 5) (1 9)) foo) ())))))))
1540 (warnings ())) |}]
1541
1542 let explicit_leading_space =
1543 test "bar {!foo}";
1544 [%expect
1545 {|
1546 ((output
1547 (((f.ml (1 0) (1 10))
1548 (paragraph
1549 (((f.ml (1 0) (1 3)) (word bar)) ((f.ml (1 3) (1 4)) space)
1550 ((f.ml (1 4) (1 10)) (simple ((f.ml (1 6) (1 10)) foo) ())))))))
1551 (warnings ())) |}]
1552
1553 let adjacent_word_trailing =
1554 test "{!foo}bar";
1555 [%expect
1556 {|
1557 ((output
1558 (((f.ml (1 0) (1 9))
1559 (paragraph
1560 (((f.ml (1 0) (1 6)) (simple ((f.ml (1 2) (1 6)) foo) ()))
1561 ((f.ml (1 6) (1 9)) (word bar)))))))
1562 (warnings ())) |}]
1563
1564 let explicit_trailing_space =
1565 test "{!foo} bar";
1566 [%expect
1567 {|
1568 ((output
1569 (((f.ml (1 0) (1 10))
1570 (paragraph
1571 (((f.ml (1 0) (1 6)) (simple ((f.ml (1 2) (1 6)) foo) ()))
1572 ((f.ml (1 6) (1 7)) space) ((f.ml (1 7) (1 10)) (word bar)))))))
1573 (warnings ())) |}]
1574
1575 let kind =
1576 test "{!val:foo}";
1577 [%expect
1578 {|
1579 ((output
1580 (((f.ml (1 0) (1 10))
1581 (paragraph
1582 (((f.ml (1 0) (1 10)) (simple ((f.ml (1 2) (1 10)) val:foo) ())))))))
1583 (warnings ())) |}]
1584
1585 let empty =
1586 test "{!}";
1587 [%expect
1588 {|
1589 ((output
1590 (((f.ml (1 0) (1 3))
1591 (paragraph (((f.ml (1 0) (1 3)) (simple ((f.ml (1 2) (1 3)) "") ())))))))
1592 (warnings ())) |}]
1593
1594 let whitespace_only =
1595 test "{! }";
1596 [%expect
1597 {|
1598 ((output
1599 (((f.ml (1 0) (1 4))
1600 (paragraph (((f.ml (1 0) (1 4)) (simple ((f.ml (1 2) (1 4)) " ") ())))))))
1601 (warnings ())) |}]
1602
1603 let internal_whitespace =
1604 test "{!( * )}";
1605 [%expect
1606 {|
1607 ((output
1608 (((f.ml (1 0) (1 8))
1609 (paragraph
1610 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "( * )") ())))))))
1611 (warnings ())) |}]
1612
1613 (* TODO Limiting the character combinations allowed will make it easier to
1614 catch expressions accidentally written inside references. This can also
1615 be caught by a good resolver and resolver error messages. *)
1616 (* t "expression" *)
1617 let unterminated =
1618 test "{!foo";
1619 [%expect
1620 {|
1621 ((output
1622 (((f.ml (1 0) (1 5))
1623 (paragraph (((f.ml (1 0) (1 5)) (simple ((f.ml (1 2) (1 5)) foo) ())))))))
1624 (warnings
1625 ( "File \"f.ml\", line 1, characters 0-5:\
1626 \nOpen bracket '{!' is never closed."))) |}]
1627
1628 let empty_kind =
1629 test "{!:foo}";
1630 [%expect
1631 {|
1632 ((output
1633 (((f.ml (1 0) (1 7))
1634 (paragraph (((f.ml (1 0) (1 7)) (simple ((f.ml (1 2) (1 7)) :foo) ())))))))
1635 (warnings ())) |}]
1636
1637 let whitespace_kind =
1638 test "{! :foo}";
1639 [%expect
1640 {|
1641 ((output
1642 (((f.ml (1 0) (1 8))
1643 (paragraph
1644 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) " :foo") ())))))))
1645 (warnings ())) |}]
1646
1647 let with_kind_but_empty =
1648 test "{!val:}";
1649 [%expect
1650 {|
1651 ((output
1652 (((f.ml (1 0) (1 7))
1653 (paragraph (((f.ml (1 0) (1 7)) (simple ((f.ml (1 2) (1 7)) val:) ())))))))
1654 (warnings ())) |}]
1655
1656 let with_kind_but_whitespace =
1657 test "{!val: }";
1658 [%expect
1659 {|
1660 ((output
1661 (((f.ml (1 0) (1 8))
1662 (paragraph
1663 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "val: ") ())))))))
1664 (warnings ())) |}]
1665
1666 let leading_whitespace_in_kind =
1667 test "{! val:foo}";
1668 [%expect
1669 {|
1670 ((output
1671 (((f.ml (1 0) (1 11))
1672 (paragraph
1673 (((f.ml (1 0) (1 11)) (simple ((f.ml (1 2) (1 11)) " val:foo") ())))))))
1674 (warnings ())) |}]
1675
1676 let internal_whitespace_in_kind =
1677 test "{!va l:foo}";
1678 [%expect
1679 {|
1680 ((output
1681 (((f.ml (1 0) (1 11))
1682 (paragraph
1683 (((f.ml (1 0) (1 11)) (simple ((f.ml (1 2) (1 11)) "va l:foo") ())))))))
1684 (warnings ())) |}]
1685
1686 let internal_whitespace_in_referent =
1687 test "{!val:( * )}";
1688 [%expect
1689 {|
1690 ((output
1691 (((f.ml (1 0) (1 12))
1692 (paragraph
1693 (((f.ml (1 0) (1 12)) (simple ((f.ml (1 2) (1 12)) "val:( * )") ())))))))
1694 (warnings ())) |}]
1695
1696 let two_colons =
1697 test "{!val:foo:bar}";
1698 [%expect
1699 {|
1700 ((output
1701 (((f.ml (1 0) (1 14))
1702 (paragraph
1703 (((f.ml (1 0) (1 14)) (simple ((f.ml (1 2) (1 14)) val:foo:bar) ())))))))
1704 (warnings ())) |}]
1705
1706 let space_before_colon =
1707 test "{!val :foo}";
1708 [%expect
1709 {|
1710 ((output
1711 (((f.ml (1 0) (1 11))
1712 (paragraph
1713 (((f.ml (1 0) (1 11)) (simple ((f.ml (1 2) (1 11)) "val :foo") ())))))))
1714 (warnings ())) |}]
1715
1716 let space_after_colon =
1717 test "{!val: foo}";
1718 [%expect
1719 {|
1720 ((output
1721 (((f.ml (1 0) (1 11))
1722 (paragraph
1723 (((f.ml (1 0) (1 11)) (simple ((f.ml (1 2) (1 11)) "val: foo") ())))))))
1724 (warnings ())) |}]
1725
1726 let unterminated_after_kind =
1727 test "{!val:foo";
1728 [%expect
1729 {|
1730 ((output
1731 (((f.ml (1 0) (1 9))
1732 (paragraph
1733 (((f.ml (1 0) (1 9)) (simple ((f.ml (1 2) (1 9)) val:foo) ())))))))
1734 (warnings
1735 ( "File \"f.ml\", line 1, characters 0-9:\
1736 \nOpen bracket '{!' is never closed."))) |}]
1737
1738 let operator =
1739 test "{!(>>=)}";
1740 [%expect
1741 {|
1742 ((output
1743 (((f.ml (1 0) (1 8))
1744 (paragraph
1745 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "(>>=)") ())))))))
1746 (warnings ())) |}]
1747
1748 let operator_with_dash =
1749 test "{!(@->)}";
1750 [%expect
1751 {|
1752 ((output
1753 (((f.ml (1 0) (1 8))
1754 (paragraph
1755 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "(@->)") ())))))))
1756 (warnings ())) |}]
1757
1758 let operator_with_dot =
1759 test "{!(*.)}";
1760 [%expect
1761 {|
1762 ((output
1763 (((f.ml (1 0) (1 7))
1764 (paragraph
1765 (((f.ml (1 0) (1 7)) (simple ((f.ml (1 2) (1 7)) "(*.)") ())))))))
1766 (warnings ())) |}]
1767
1768 let operator_with_colon =
1769 test "{!(>::)}";
1770 [%expect
1771 {|
1772 ((output
1773 (((f.ml (1 0) (1 8))
1774 (paragraph
1775 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "(>::)") ())))))))
1776 (warnings ())) |}]
1777
1778 let operator_with_curly_braces =
1779 test "{!(.*{})}";
1780 [%expect
1781 {|
1782 ((output
1783 (((f.ml (1 0) (1 9))
1784 (paragraph
1785 (((f.ml (1 0) (1 9)) (simple ((f.ml (1 2) (1 9)) "(.*{})") ())))))))
1786 (warnings ())) |}]
1787
1788 let quotes_with_dash =
1789 test "{!\"my-name\"}";
1790 [%expect
1791 {|
1792 ((output
1793 (((f.ml (1 0) (1 12))
1794 (paragraph
1795 (((f.ml (1 0) (1 12)) (simple ((f.ml (1 2) (1 12)) "\"my-name\"") ())))))))
1796 (warnings ())) |}]
1797
1798 let quotes_with_curly_braces =
1799 test "{!\"}\"}";
1800 [%expect
1801 {|
1802 ((output
1803 (((f.ml (1 0) (1 6))
1804 (paragraph
1805 (((f.ml (1 0) (1 6)) (simple ((f.ml (1 2) (1 6)) "\"}\"") ())))))))
1806 (warnings ())) |}]
1807
1808 let operator_with_curly_braces =
1809 test "{!( } )}";
1810 [%expect
1811 {|
1812 ((output
1813 (((f.ml (1 0) (1 8))
1814 (paragraph
1815 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "( } )") ())))))))
1816 (warnings ())) |}]
1817
1818 let operator_unbalanced =
1819 test "{!(.*()}";
1820 [%expect
1821 {|
1822 ((output
1823 (((f.ml (1 0) (1 8))
1824 (paragraph
1825 (((f.ml (1 0) (1 8)) (simple ((f.ml (1 2) (1 8)) "(.*()}") ())))))))
1826 (warnings
1827 ( "File \"f.ml\", line 1, characters 2-8:\
1828 \nOpen bracket '(' is never closed."))) |}]
1829
1830 let operator_eof =
1831 test "{!(.*()";
1832 [%expect
1833 {|
1834 ((output
1835 (((f.ml (1 0) (1 7))
1836 (paragraph
1837 (((f.ml (1 0) (1 7)) (simple ((f.ml (1 2) (1 7)) "(.*()") ())))))))
1838 (warnings
1839 ( "File \"f.ml\", line 1, characters 2-7:\
1840 \nOpen bracket '(' is never closed."))) |}]
1841 end in
1842 ()
1843
1844let%expect_test _ =
1845 let module Reference_with_text = struct
1846 let basic =
1847 test "{{!foo} bar}";
1848 [%expect
1849 {|
1850 ((output
1851 (((f.ml (1 0) (1 12))
1852 (paragraph
1853 (((f.ml (1 0) (1 12))
1854 (with_text ((f.ml (1 3) (1 7)) foo)
1855 (((f.ml (1 8) (1 11)) (word bar))))))))))
1856 (warnings ())) |}]
1857
1858 let degenerate =
1859 test "{{!foo}}";
1860 [%expect
1861 {|
1862 ((output
1863 (((f.ml (1 0) (1 8))
1864 (paragraph
1865 (((f.ml (1 0) (1 8)) (with_text ((f.ml (1 3) (1 7)) foo) ())))))))
1866 (warnings
1867 ( "File \"f.ml\", line 1, characters 0-8:\
1868 \n'{{!...} ...}' (cross-reference) should not be empty."))) |}]
1869
1870 let empty =
1871 test "{{!foo} }";
1872 [%expect
1873 {|
1874 ((output
1875 (((f.ml (1 0) (1 9))
1876 (paragraph
1877 (((f.ml (1 0) (1 9)) (with_text ((f.ml (1 3) (1 7)) foo) ())))))))
1878 (warnings
1879 ( "File \"f.ml\", line 1, characters 0-9:\
1880 \n'{{!...} ...}' (cross-reference) should not be empty."))) |}]
1881
1882 let nested_markup =
1883 test "{{!foo} {b bar}}";
1884 [%expect
1885 {|
1886 ((output
1887 (((f.ml (1 0) (1 16))
1888 (paragraph
1889 (((f.ml (1 0) (1 16))
1890 (with_text ((f.ml (1 3) (1 7)) foo)
1891 (((f.ml (1 8) (1 15)) (bold (((f.ml (1 11) (1 14)) (word bar)))))))))))))
1892 (warnings ())) |}]
1893
1894 let in_markup =
1895 test "{e {{!foo} bar}}";
1896 [%expect
1897 {|
1898 ((output
1899 (((f.ml (1 0) (1 16))
1900 (paragraph
1901 (((f.ml (1 0) (1 16))
1902 (emphasis
1903 (((f.ml (1 3) (1 15))
1904 (with_text ((f.ml (1 6) (1 10)) foo)
1905 (((f.ml (1 11) (1 14)) (word bar)))))))))))))
1906 (warnings ())) |}]
1907
1908 let no_separating_space =
1909 test "{{!foo}bar}";
1910 [%expect
1911 {|
1912 ((output
1913 (((f.ml (1 0) (1 11))
1914 (paragraph
1915 (((f.ml (1 0) (1 11))
1916 (with_text ((f.ml (1 3) (1 7)) foo)
1917 (((f.ml (1 7) (1 10)) (word bar))))))))))
1918 (warnings ())) |}]
1919
1920 let kind =
1921 test "{{!val:foo} bar}";
1922 [%expect
1923 {|
1924 ((output
1925 (((f.ml (1 0) (1 16))
1926 (paragraph
1927 (((f.ml (1 0) (1 16))
1928 (with_text ((f.ml (1 3) (1 11)) val:foo)
1929 (((f.ml (1 12) (1 15)) (word bar))))))))))
1930 (warnings ())) |}]
1931
1932 let nested_reference =
1933 test "{{!foo} {!bar}}";
1934 [%expect
1935 {|
1936 ((output
1937 (((f.ml (1 0) (1 15))
1938 (paragraph
1939 (((f.ml (1 0) (1 15))
1940 (with_text ((f.ml (1 3) (1 7)) foo)
1941 (((f.ml (1 8) (1 14)) (simple ((f.ml (1 10) (1 14)) bar) ()))))))))))
1942 (warnings ())) |}]
1943
1944 let nested_empty =
1945 test "{{!foo} {{!bar}}}";
1946 [%expect
1947 {|
1948 ((output
1949 (((f.ml (1 0) (1 17))
1950 (paragraph
1951 (((f.ml (1 0) (1 17))
1952 (with_text ((f.ml (1 3) (1 7)) foo)
1953 (((f.ml (1 8) (1 16)) (with_text ((f.ml (1 11) (1 15)) bar) ()))))))))))
1954 (warnings
1955 ( "File \"f.ml\", line 1, characters 8-16:\
1956 \n'{{!...} ...}' (cross-reference) should not be empty."))) |}]
1957
1958 let nested_through_emphasis =
1959 test "{{!foo} {e {{!bar} baz}}}";
1960 [%expect
1961 {|
1962 ((output
1963 (((f.ml (1 0) (1 25))
1964 (paragraph
1965 (((f.ml (1 0) (1 25))
1966 (with_text ((f.ml (1 3) (1 7)) foo)
1967 (((f.ml (1 8) (1 24))
1968 (emphasis
1969 (((f.ml (1 11) (1 23))
1970 (with_text ((f.ml (1 14) (1 18)) bar)
1971 (((f.ml (1 19) (1 22)) (word baz))))))))))))))))
1972 (warnings ())) |}]
1973
1974 let simple_through_emphasis =
1975 test "{{!foo} {e {!bar}}}";
1976 [%expect
1977 {|
1978 ((output
1979 (((f.ml (1 0) (1 19))
1980 (paragraph
1981 (((f.ml (1 0) (1 19))
1982 (with_text ((f.ml (1 3) (1 7)) foo)
1983 (((f.ml (1 8) (1 18))
1984 (emphasis
1985 (((f.ml (1 11) (1 17)) (simple ((f.ml (1 13) (1 17)) bar) ())))))))))))))
1986 (warnings ())) |}]
1987
1988 let empty_target =
1989 test "{{!} foo}";
1990 [%expect
1991 {|
1992 ((output
1993 (((f.ml (1 0) (1 9))
1994 (paragraph
1995 (((f.ml (1 0) (1 9))
1996 (with_text ((f.ml (1 3) (1 4)) "") (((f.ml (1 5) (1 8)) (word foo))))))))))
1997 (warnings ())) |}]
1998
1999 let whitespace_only_in_target =
2000 test "{{! } foo}";
2001 [%expect
2002 {|
2003 ((output
2004 (((f.ml (1 0) (1 10))
2005 (paragraph
2006 (((f.ml (1 0) (1 10))
2007 (with_text ((f.ml (1 3) (1 5)) " ") (((f.ml (1 6) (1 9)) (word foo))))))))))
2008 (warnings ())) |}]
2009
2010 let internal_whitespace =
2011 test "{{!( * )} baz}";
2012 [%expect
2013 {|
2014 ((output
2015 (((f.ml (1 0) (1 14))
2016 (paragraph
2017 (((f.ml (1 0) (1 14))
2018 (with_text ((f.ml (1 3) (1 9)) "( * )")
2019 (((f.ml (1 10) (1 13)) (word baz))))))))))
2020 (warnings ())) |}]
2021
2022 let unterminated =
2023 test "{{!foo";
2024 [%expect
2025 {|
2026 ((output
2027 (((f.ml (1 0) (1 6))
2028 (paragraph
2029 (((f.ml (1 0) (1 6)) (with_text ((f.ml (1 3) (1 6)) foo) ())))))))
2030 (warnings
2031 ( "File \"f.ml\", line 1, characters 0-6:\
2032 \nOpen bracket '{{!' is never closed."
2033 "File \"f.ml\", line 1, characters 6-6:\
2034 \nEnd of text is not allowed in '{{!...} ...}' (cross-reference)."
2035 "File \"f.ml\", line 1, characters 0-6:\
2036 \n'{{!...} ...}' (cross-reference) should not be empty."))) |}]
2037
2038 let unterminated_content =
2039 test "{{!foo} bar";
2040 [%expect
2041 {|
2042 ((output
2043 (((f.ml (1 0) (1 11))
2044 (paragraph
2045 (((f.ml (1 0) (1 11))
2046 (with_text ((f.ml (1 3) (1 7)) foo)
2047 (((f.ml (1 8) (1 11)) (word bar))))))))))
2048 (warnings
2049 ( "File \"f.ml\", line 1, characters 11-11:\
2050 \nEnd of text is not allowed in '{{!...} ...}' (cross-reference)."))) |}]
2051 end in
2052 ()
2053
2054let%expect_test _ =
2055 let module Medias = struct
2056 let basic_simple =
2057 test
2058 "{image!foo}\n\n\
2059 {audio!foo}\n\n\
2060 {video!foo}\n\n\
2061 {image:foo}\n\n\
2062 {audio:foo}\n\n\
2063 {video:foo}";
2064 [%expect
2065 {|
2066 ((output
2067 (((f.ml (1 0) (1 11))
2068 (simple ((f.ml (1 7) (1 10)) (Reference foo)) "" image))
2069 ((f.ml (3 0) (3 11))
2070 (simple ((f.ml (3 7) (3 10)) (Reference foo)) "" audio))
2071 ((f.ml (5 0) (5 11))
2072 (simple ((f.ml (5 7) (5 10)) (Reference foo)) "" video))
2073 ((f.ml (7 0) (7 11)) (simple ((f.ml (7 7) (7 10)) (Link foo)) "" image))
2074 ((f.ml (9 0) (9 11)) (simple ((f.ml (9 7) (9 10)) (Link foo)) "" audio))
2075 ((f.ml (11 0) (11 11))
2076 (simple ((f.ml (11 7) (11 10)) (Link foo)) "" video))))
2077 (warnings ())) |}]
2078
2079 let basic =
2080 test
2081 "{{image!foo}bar}\n\n\
2082 {{audio!foo}bar}\n\n\
2083 {{video!foo}bar}\n\n\
2084 {{image:foo}bar}\n\n\
2085 {{audio:foo}bar}\n\n\
2086 {{video:foo}bar}";
2087 [%expect
2088 {|
2089 ((output
2090 (((f.ml (1 0) (1 16))
2091 (simple ((f.ml (1 8) (1 12)) (Reference foo)) bar image))
2092 ((f.ml (3 0) (3 16))
2093 (simple ((f.ml (3 8) (3 12)) (Reference foo)) bar audio))
2094 ((f.ml (5 0) (5 16))
2095 (simple ((f.ml (5 8) (5 12)) (Reference foo)) bar video))
2096 ((f.ml (7 0) (7 16)) (simple ((f.ml (7 8) (7 12)) (Link foo)) bar image))
2097 ((f.ml (9 0) (9 16)) (simple ((f.ml (9 8) (9 12)) (Link foo)) bar audio))
2098 ((f.ml (11 0) (11 16))
2099 (simple ((f.ml (11 8) (11 12)) (Link foo)) bar video))))
2100 (warnings ())) |}]
2101
2102 let empty =
2103 test "{{image!foo}}";
2104 [%expect
2105 {|
2106 ((output
2107 (((f.ml (1 0) (1 13))
2108 (simple ((f.ml (1 8) (1 12)) (Reference foo)) "" image))))
2109 (warnings
2110 ( "File \"f.ml\", line 1, characters 11-12:\
2111 \n'{{image!...} ...}' (image-reference) should not be empty."))) |}]
2112
2113 let whitespace =
2114 test "{{image!foo} }";
2115 [%expect
2116 {|
2117 ((output
2118 (((f.ml (1 0) (1 16))
2119 (simple ((f.ml (1 8) (1 12)) (Reference foo)) "" image))))
2120 (warnings
2121 ( "File \"f.ml\", line 1, characters 11-15:\
2122 \n'{{image!...} ...}' (image-reference) should not be empty."))) |}]
2123
2124 let trimming =
2125 test "{{image!foo} hello }";
2126 [%expect
2127 {|
2128 ((output
2129 (((f.ml (1 0) (1 27))
2130 (simple ((f.ml (1 8) (1 12)) (Reference foo)) hello image))))
2131 (warnings ())) |}]
2132
2133 let nested_markup_is_uninterpreted =
2134 test "{{image!foo}{b bar}}";
2135 [%expect
2136 {|
2137 ((output
2138 (((f.ml (1 0) (1 20))
2139 (simple ((f.ml (1 8) (1 12)) (Reference foo)) "{b bar}" image))))
2140 (warnings ())) |}]
2141
2142 let in_markup =
2143 test "{ul {li {{image!foo}bar}}}";
2144 [%expect
2145 {|
2146 ((output
2147 (((f.ml (1 0) (1 26))
2148 (unordered heavy
2149 ((((f.ml (1 8) (1 24))
2150 (simple ((f.ml (1 16) (1 20)) (Reference foo)) bar image))))))))
2151 (warnings ())) |}]
2152
2153 let unterminated_image =
2154 test "{{image!foo";
2155 [%expect
2156 {|
2157 ((output
2158 (((f.ml (1 0) (1 11))
2159 (simple ((f.ml (1 8) (1 10)) (Reference foo)) "" image))))
2160 (warnings
2161 ( "File \"f.ml\", line 1, characters 0-11:\
2162 \nOpen bracket '{{image!' is never closed."
2163 "File \"f.ml\", line 1, characters 11-11:\
2164 \nEnd of text is not allowed in '{{image!...} ...}' (image-reference)."
2165 "File \"f.ml\", line 1, characters 11-10:\
2166 \n'{{image!...} ...}' (image-reference) should not be empty."))) |}]
2167
2168 let unterminated_image_simple =
2169 test "{image!foo";
2170 [%expect
2171 {|
2172 ((output
2173 (((f.ml (1 0) (1 10))
2174 (simple ((f.ml (1 7) (1 9)) (Reference foo)) "" image))))
2175 (warnings
2176 ( "File \"f.ml\", line 1, characters 0-10:\
2177 \nOpen bracket '{image!' is never closed."))) |}]
2178
2179 let unterminated_video =
2180 test "{{video!foo";
2181 [%expect
2182 {|
2183 ((output
2184 (((f.ml (1 0) (1 11))
2185 (simple ((f.ml (1 8) (1 10)) (Reference foo)) "" video))))
2186 (warnings
2187 ( "File \"f.ml\", line 1, characters 0-11:\
2188 \nOpen bracket '{{video!' is never closed."
2189 "File \"f.ml\", line 1, characters 11-11:\
2190 \nEnd of text is not allowed in '{{video!...} ...}' (video-reference)."
2191 "File \"f.ml\", line 1, characters 11-10:\
2192 \n'{{video!...} ...}' (video-reference) should not be empty."))) |}]
2193
2194 let unterminated_video_simple =
2195 test "{video!foo";
2196 [%expect
2197 {|
2198 ((output
2199 (((f.ml (1 0) (1 10))
2200 (simple ((f.ml (1 7) (1 9)) (Reference foo)) "" video))))
2201 (warnings
2202 ( "File \"f.ml\", line 1, characters 0-10:\
2203 \nOpen bracket '{video!' is never closed."))) |}]
2204
2205 let unterminated_audio =
2206 test "{{audio!foo";
2207 [%expect
2208 {|
2209 ((output
2210 (((f.ml (1 0) (1 11))
2211 (simple ((f.ml (1 8) (1 10)) (Reference foo)) "" audio))))
2212 (warnings
2213 ( "File \"f.ml\", line 1, characters 0-11:\
2214 \nOpen bracket '{{audio!' is never closed."
2215 "File \"f.ml\", line 1, characters 11-11:\
2216 \nEnd of text is not allowed in '{{audio!...} ...}' (audio-reference)."
2217 "File \"f.ml\", line 1, characters 11-10:\
2218 \n'{{audio!...} ...}' (audio-reference) should not be empty."))) |}]
2219
2220 let unterminated_audio_simple =
2221 test "{audio!foo";
2222 [%expect
2223 {|
2224 ((output
2225 (((f.ml (1 0) (1 10))
2226 (simple ((f.ml (1 7) (1 9)) (Reference foo)) "" audio))))
2227 (warnings
2228 ( "File \"f.ml\", line 1, characters 0-10:\
2229 \nOpen bracket '{audio!' is never closed."))) |}]
2230
2231 let unterminated_content =
2232 test "{{image!foo} bar";
2233 [%expect
2234 {|
2235 ((output
2236 (((f.ml (1 0) (1 16))
2237 (simple ((f.ml (1 8) (1 11)) (Reference foo)) bar image))))
2238 (warnings
2239 ( "File \"f.ml\", line 1, characters 16-16:\
2240 \nEnd of text is not allowed in '{{image!...} ...}' (image-reference)."))) |}]
2241
2242 let newline_in_content =
2243 test "{{image!foo} bar \n baz}";
2244 [%expect
2245 {|
2246 ((output
2247 (((f.ml (1 0) (2 5))
2248 (simple ((f.ml (1 8) (2 -6)) (Reference foo)) "bar baz" image))))
2249 (warnings ())) |}]
2250 end in
2251 ()
2252
2253let%expect_test _ =
2254 let module Link = struct
2255 let basic =
2256 test "{{:foo} bar}";
2257 [%expect
2258 {|
2259 ((output
2260 (((f.ml (1 0) (1 12))
2261 (paragraph
2262 (((f.ml (1 0) (1 12)) (foo (((f.ml (1 8) (1 11)) (word bar))))))))))
2263 (warnings ())) |}]
2264
2265 let nested_markup =
2266 test "{{:foo} {b bar}}";
2267 [%expect
2268 {|
2269 ((output
2270 (((f.ml (1 0) (1 16))
2271 (paragraph
2272 (((f.ml (1 0) (1 16))
2273 (foo
2274 (((f.ml (1 8) (1 15)) (bold (((f.ml (1 11) (1 14)) (word bar)))))))))))))
2275 (warnings ())) |}]
2276
2277 let in_markup =
2278 test "{e {{:foo} bar}}";
2279 [%expect
2280 {|
2281 ((output
2282 (((f.ml (1 0) (1 16))
2283 (paragraph
2284 (((f.ml (1 0) (1 16))
2285 (emphasis
2286 (((f.ml (1 3) (1 15)) (foo (((f.ml (1 11) (1 14)) (word bar)))))))))))))
2287 (warnings ())) |}]
2288
2289 let no_separating_space =
2290 test "{{:foo}bar}";
2291 [%expect
2292 {|
2293 ((output
2294 (((f.ml (1 0) (1 11))
2295 (paragraph
2296 (((f.ml (1 0) (1 11)) (foo (((f.ml (1 7) (1 10)) (word bar))))))))))
2297 (warnings ())) |}]
2298
2299 let nested_link =
2300 test "{{:foo} {{:bar} baz}}";
2301 [%expect
2302 {|
2303 ((output
2304 (((f.ml (1 0) (1 21))
2305 (paragraph
2306 (((f.ml (1 0) (1 21))
2307 (foo
2308 (((f.ml (1 8) (1 20)) (bar (((f.ml (1 16) (1 19)) (word baz)))))))))))))
2309 (warnings ())) |}]
2310
2311 let nested_through_emphasis =
2312 test "{{:foo} {e {{:bar} baz}}}";
2313 [%expect
2314 {|
2315 ((output
2316 (((f.ml (1 0) (1 25))
2317 (paragraph
2318 (((f.ml (1 0) (1 25))
2319 (foo
2320 (((f.ml (1 8) (1 24))
2321 (emphasis
2322 (((f.ml (1 11) (1 23)) (bar (((f.ml (1 19) (1 22)) (word baz))))))))))))))))
2323 (warnings ())) |}]
2324
2325 let reference_through_emphasis =
2326 test "{{:foo} {e {!bar}}}";
2327 [%expect
2328 {|
2329 ((output
2330 (((f.ml (1 0) (1 19))
2331 (paragraph
2332 (((f.ml (1 0) (1 19))
2333 (foo
2334 (((f.ml (1 8) (1 18))
2335 (emphasis
2336 (((f.ml (1 11) (1 17)) (simple ((f.ml (1 13) (1 17)) bar) ())))))))))))))
2337 (warnings ())) |}]
2338
2339 let nested_in_reference =
2340 test "{{!foo} {e {{:bar} baz}}}";
2341 [%expect
2342 {|
2343 ((output
2344 (((f.ml (1 0) (1 25))
2345 (paragraph
2346 (((f.ml (1 0) (1 25))
2347 (with_text ((f.ml (1 3) (1 7)) foo)
2348 (((f.ml (1 8) (1 24))
2349 (emphasis
2350 (((f.ml (1 11) (1 23)) (bar (((f.ml (1 19) (1 22)) (word baz))))))))))))))))
2351 (warnings ())) |}]
2352
2353 let empty_target =
2354 test "{{:} foo}";
2355 [%expect
2356 {|
2357 ((output
2358 (((f.ml (1 0) (1 9))
2359 (paragraph (((f.ml (1 0) (1 9)) ("" (((f.ml (1 5) (1 8)) (word foo))))))))))
2360 (warnings
2361 ( "File \"f.ml\", line 1, characters 0-4:\
2362 \n'{{:...} ...}' (external link) should not be empty."))) |}]
2363
2364 let whitespace_only_in_target =
2365 test "{{: } foo}";
2366 [%expect
2367 {|
2368 ((output
2369 (((f.ml (1 0) (1 10))
2370 (paragraph
2371 (((f.ml (1 0) (1 10)) ("" (((f.ml (1 6) (1 9)) (word foo))))))))))
2372 (warnings
2373 ( "File \"f.ml\", line 1, characters 0-5:\
2374 \n'{{:...} ...}' (external link) should not be empty."))) |}]
2375
2376 let empty =
2377 test "{{:foo}}";
2378 [%expect
2379 {|
2380 ((output (((f.ml (1 0) (1 8)) (paragraph (((f.ml (1 0) (1 8)) (foo ())))))))
2381 (warnings ())) |}]
2382
2383 let internal_whitespace =
2384 test "{{:foo bar} baz}";
2385 [%expect
2386 {|
2387 ((output
2388 (((f.ml (1 0) (1 16))
2389 (paragraph
2390 (((f.ml (1 0) (1 16)) ("foo bar" (((f.ml (1 12) (1 15)) (word baz))))))))))
2391 (warnings ())) |}]
2392
2393 let unterminated =
2394 test "{{:foo";
2395 [%expect
2396 {|
2397 ((output (((f.ml (1 0) (1 6)) (paragraph (((f.ml (1 0) (1 6)) (foo ())))))))
2398 (warnings
2399 ( "File \"f.ml\", line 1, characters 0-6:\
2400 \nOpen bracket '{{:' is never closed."
2401 "File \"f.ml\", line 1, characters 6-6:\
2402 \nEnd of text is not allowed in '{{:...} ...}' (external link)."))) |}]
2403
2404 let single_braces =
2405 test "{:foo}";
2406 [%expect
2407 {|
2408 ((output (((f.ml (1 0) (1 6)) (paragraph (((f.ml (1 0) (1 6)) (foo ())))))))
2409 (warnings ())) |}]
2410
2411 let unterminated_single_braces =
2412 test "{:foo";
2413 [%expect
2414 {|
2415 ((output (((f.ml (1 0) (1 5)) (paragraph (((f.ml (1 0) (1 5)) (foo ())))))))
2416 (warnings
2417 ( "File \"f.ml\", line 1, characters 0-5:\
2418 \nOpen bracket '{:' is never closed."))) |}]
2419
2420 let empty_single_braces =
2421 test "{:}";
2422 [%expect
2423 {|
2424 ((output (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) ("" ())))))))
2425 (warnings
2426 ( "File \"f.ml\", line 1, characters 0-3:\
2427 \n'{:...} (external link)' should not be empty."))) |}]
2428
2429 let single_braces_whitespace_only =
2430 test "{: }";
2431 [%expect
2432 {|
2433 ((output (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) ("" ())))))))
2434 (warnings
2435 ( "File \"f.ml\", line 1, characters 0-4:\
2436 \n'{:...} (external link)' should not be empty."))) |}]
2437 end in
2438 ()
2439
2440let%expect_test _ =
2441 let module Module_list = struct
2442 let basic =
2443 test "{!modules:Foo}";
2444 [%expect
2445 {|
2446 ((output (((f.ml (1 0) (1 14)) (modules (((f.ml (1 0) (1 14)) Foo))))))
2447 (warnings ())) |}]
2448
2449 let two =
2450 test "{!modules:Foo Bar}";
2451 [%expect
2452 {|
2453 ((output
2454 (((f.ml (1 0) (1 18))
2455 (modules (((f.ml (1 0) (1 18)) Foo) ((f.ml (1 0) (1 18)) Bar))))))
2456 (warnings ())) |}]
2457
2458 let extra_whitespace =
2459 test "{!modules: Foo Bar }";
2460 [%expect
2461 {|
2462 ((output
2463 (((f.ml (1 0) (1 21))
2464 (modules (((f.ml (1 0) (1 21)) Foo) ((f.ml (1 0) (1 21)) Bar))))))
2465 (warnings ())) |}]
2466
2467 let newline =
2468 test "{!modules:Foo\nBar}";
2469 [%expect
2470 {|
2471 ((output
2472 (((f.ml (1 0) (2 4))
2473 (modules (((f.ml (1 0) (2 4)) Foo) ((f.ml (1 0) (2 4)) Bar))))))
2474 (warnings ())) |}]
2475
2476 let cr_lf =
2477 test "{!modules:Foo\r\nBar}";
2478 [%expect
2479 {|
2480 ((output
2481 (((f.ml (1 0) (2 4))
2482 (modules (((f.ml (1 0) (2 4)) Foo) ((f.ml (1 0) (2 4)) Bar))))))
2483 (warnings ())) |}]
2484
2485 let empty =
2486 test "{!modules:}";
2487 [%expect
2488 {|
2489 ((output (((f.ml (1 0) (1 11)) (modules ()))))
2490 (warnings
2491 ( "File \"f.ml\", line 1, characters 0-11:\
2492 \n'{!modules ...}' should not be empty."))) |}]
2493
2494 let whitespace_only =
2495 test "{!modules: }";
2496 [%expect
2497 {|
2498 ((output (((f.ml (1 0) (1 12)) (modules ()))))
2499 (warnings
2500 ( "File \"f.ml\", line 1, characters 0-12:\
2501 \n'{!modules ...}' should not be empty."))) |}]
2502
2503 let unterminated =
2504 test "{!modules:";
2505 [%expect
2506 {|
2507 ((output (((f.ml (1 0) (1 10)) (modules ()))))
2508 (warnings
2509 ( "File \"f.ml\", line 1, characters 10-10:\
2510 \nEnd of text is not allowed in '{!modules ...}'."
2511 "File \"f.ml\", line 1, characters 0-10:\
2512 \n'{!modules ...}' should not be empty."))) |}]
2513
2514 let in_paragraph =
2515 test "foo {!modules:Foo}";
2516 [%expect
2517 {|
2518 ((output
2519 (((f.ml (1 0) (1 4))
2520 (paragraph (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space))))
2521 ((f.ml (1 4) (1 18)) (modules (((f.ml (1 4) (1 18)) Foo))))))
2522 (warnings
2523 ( "File \"f.ml\", line 1, characters 4-18:\
2524 \n'{!modules ...}' should begin on its own line."))) |}]
2525
2526 let followed_by_word =
2527 test "{!modules:Foo} foo";
2528 [%expect
2529 {|
2530 ((output
2531 (((f.ml (1 0) (1 14)) (modules (((f.ml (1 0) (1 14)) Foo))))
2532 ((f.ml (1 15) (1 18)) (paragraph (((f.ml (1 15) (1 18)) (word foo)))))))
2533 (warnings
2534 ( "File \"f.ml\", line 1, characters 15-18:\
2535 \nParagraph should begin on its own line."))) |}]
2536
2537 let in_list =
2538 test "- {!modules:Foo}";
2539 [%expect
2540 {|
2541 ((output
2542 (((f.ml (1 0) (1 16))
2543 (unordered light
2544 ((((f.ml (1 2) (1 16)) (modules (((f.ml (1 2) (1 16)) Foo))))))))))
2545 (warnings ())) |}]
2546 end in
2547 ()
2548
2549let%expect_test _ =
2550 let module Code_block = struct
2551 let basic =
2552 test "{[foo]}";
2553 [%expect
2554 {|
2555 ((output (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))))
2556 (warnings ())) |}]
2557
2558 let empty =
2559 test "{[]}";
2560 [%expect
2561 {|
2562 ((output (((f.ml (1 0) (1 4)) (code_block ((f.ml (1 2) (1 2)) "")))))
2563 (warnings
2564 ( "File \"f.ml\", line 1, characters 0-4:\
2565 \n'{[...]}' (code block) should not be empty."))) |}]
2566
2567 let whitespace_only =
2568 test "{[ ]}";
2569 [%expect
2570 {|
2571 ((output (((f.ml (1 0) (1 5)) (code_block ((f.ml (1 2) (1 3)) " ")))))
2572 (warnings ()))
2573 |}]
2574
2575 let blank_line_only =
2576 test "{[\n \n]}";
2577 [%expect
2578 {|
2579 ((output (((f.ml (1 0) (3 2)) (code_block ((f.ml (1 2) (3 0)) " ")))))
2580 (warnings ()))
2581 |}]
2582
2583 let whitespace =
2584 test "{[foo bar]}";
2585 [%expect
2586 {|
2587 ((output (((f.ml (1 0) (1 11)) (code_block ((f.ml (1 2) (1 9)) "foo bar")))))
2588 (warnings ())) |}]
2589
2590 let newline =
2591 test "{[foo\nbar]}";
2592 [%expect
2593 {|
2594 ((output
2595 (((f.ml (1 0) (2 5)) (code_block ((f.ml (1 2) (2 3)) "foo\
2596 \nbar")))))
2597 (warnings ()))
2598 |}]
2599
2600 let cr_lf =
2601 test "{[foo\r\nbar]}";
2602 [%expect
2603 {|
2604 ((output
2605 (((f.ml (1 0) (2 5)) (code_block ((f.ml (1 2) (2 3)) "foo\r\
2606 \nbar")))))
2607 (warnings ()))
2608 |}]
2609
2610 let blank_line =
2611 test "{[foo\n\nbar]}";
2612 [%expect
2613 {|
2614 ((output
2615 (((f.ml (1 0) (3 5)) (code_block ((f.ml (1 2) (3 3)) "foo\
2616 \n\
2617 \nbar")))))
2618 (warnings ()))
2619 |}]
2620
2621 let leading_whitespace =
2622 test "{[ foo]}";
2623 [%expect
2624 {|
2625 ((output (((f.ml (1 0) (1 8)) (code_block ((f.ml (1 2) (1 6)) " foo")))))
2626 (warnings ()))
2627 |}]
2628
2629 let leading_whitespace_two =
2630 test "{[ foo\n bar]}";
2631 [%expect
2632 {|
2633 ((output
2634 (((f.ml (1 0) (2 6)) (code_block ((f.ml (1 2) (2 4)) " foo\
2635 \n bar")))))
2636 (warnings ()))
2637 |}]
2638
2639 let leading_whitespace_two_cr_lf =
2640 test "{[ foo\r\n bar]}";
2641 [%expect
2642 {|
2643 ((output
2644 (((f.ml (1 0) (2 6)) (code_block ((f.ml (1 2) (2 4)) " foo\r\
2645 \n bar")))))
2646 (warnings ()))
2647 |}]
2648
2649 let leading_whitespace_two_different_indent =
2650 test "{[ foo\n bar]}";
2651 [%expect
2652 {|
2653 ((output
2654 (((f.ml (1 0) (2 8)) (code_block ((f.ml (1 2) (2 6)) " foo\
2655 \n bar")))))
2656 (warnings ()))
2657 |}]
2658
2659 let leading_whitespace_two_different_indent_rev =
2660 test "{[ foo\n bar]}";
2661 [%expect
2662 {|
2663 ((output
2664 (((f.ml (1 0) (2 6)) (code_block ((f.ml (1 2) (2 4)) " foo\
2665 \n bar")))))
2666 (warnings ()))
2667 |}]
2668
2669 let leading_whitespace_two_different_indent_reloc =
2670 test "{[ foo\n bar]}";
2671 [%expect
2672 {|
2673 ((output
2674 (((f.ml (1 0) (2 11))
2675 (code_block ((f.ml (1 2) (2 9)) " foo\
2676 \n bar")))))
2677 (warnings ()))
2678 |}]
2679
2680 let leading_whitespace_with_empty_line =
2681 test "{[ foo\n\n bar]}";
2682 [%expect
2683 {|
2684 ((output
2685 (((f.ml (1 0) (3 6)) (code_block ((f.ml (1 2) (3 4)) " foo\
2686 \n\
2687 \n bar")))))
2688 (warnings ()))
2689 |}]
2690
2691 let leading_whitespace_with_whitespace_line_short =
2692 test "{[ foo\n \n bar]}";
2693 [%expect
2694 {|
2695 ((output
2696 (((f.ml (1 0) (3 7))
2697 (code_block ((f.ml (1 2) (3 5)) " foo\
2698 \n \
2699 \n bar")))))
2700 (warnings ()))
2701 |}]
2702
2703 let leading_whitespace_with_whitespace_line_long =
2704 test "{[ foo\n \n bar]}";
2705 [%expect
2706 {|
2707 ((output
2708 (((f.ml (1 0) (3 6))
2709 (code_block ((f.ml (1 2) (3 4)) " foo\
2710 \n \
2711 \n bar")))))
2712 (warnings ()))
2713 |}]
2714
2715 let leading_whitespace_leading_newline =
2716 test "{[\n foo\n bar\n]}";
2717 [%expect
2718 {|
2719 ((output
2720 (((f.ml (1 0) (4 2)) (code_block ((f.ml (1 2) (4 0)) " foo\
2721 \n bar")))))
2722 (warnings ()))
2723 |}]
2724
2725 let leading_tab =
2726 test "{[\tfoo]}";
2727 [%expect
2728 {|
2729 ((output (((f.ml (1 0) (1 8)) (code_block ((f.ml (1 2) (1 6)) "\tfoo")))))
2730 (warnings ()))
2731 |}]
2732
2733 let leading_tab_two =
2734 test "{[\tfoo\n\tbar]}";
2735 [%expect
2736 {|
2737 ((output
2738 (((f.ml (1 0) (2 6)) (code_block ((f.ml (1 2) (2 4)) "\tfoo\
2739 \n\tbar")))))
2740 (warnings ()))
2741 |}]
2742
2743 let leading_tab_two_different_indent =
2744 test "{[\tfoo\n\t\tbar]}";
2745 [%expect
2746 {|
2747 ((output
2748 (((f.ml (1 0) (2 7)) (code_block ((f.ml (1 2) (2 5)) "\tfoo\
2749 \n\t\tbar")))))
2750 (warnings ()))
2751 |}]
2752
2753 let leading_newline =
2754 test "{[\nfoo]}";
2755 [%expect
2756 {|
2757 ((output (((f.ml (1 0) (2 5)) (code_block ((f.ml (1 2) (2 3)) foo)))))
2758 (warnings ()))
2759 |}]
2760
2761 let leading_cr_lf =
2762 test "{[\r\nfoo]}";
2763 [%expect
2764 {|
2765 ((output (((f.ml (1 0) (2 5)) (code_block ((f.ml (1 2) (2 3)) foo)))))
2766 (warnings ()))
2767 |}]
2768
2769 let leading_newlines =
2770 test "{[\n\nfoo]}";
2771 [%expect
2772 {|
2773 ((output (((f.ml (1 0) (3 5)) (code_block ((f.ml (1 2) (3 3)) "\
2774 \nfoo")))))
2775 (warnings ()))
2776 |}]
2777
2778 let leading_newline_with_space =
2779 test "{[\n foo]}";
2780 [%expect
2781 {|
2782 ((output (((f.ml (1 0) (2 6)) (code_block ((f.ml (1 2) (2 4)) " foo")))))
2783 (warnings ()))
2784 |}]
2785
2786 let leading_newline_with_trash =
2787 test "{[ \nfoo]}";
2788 [%expect
2789 {|
2790 ((output (((f.ml (1 0) (2 5)) (code_block ((f.ml (1 2) (2 3)) foo)))))
2791 (warnings ()))
2792 |}]
2793
2794 let nested_opener =
2795 test "{[{[]}";
2796 [%expect
2797 {|
2798 ((output (((f.ml (1 0) (1 6)) (code_block ((f.ml (1 2) (1 4)) {[)))))
2799 (warnings ())) |}]
2800
2801 let nested_closer =
2802 test "{[foo]}]}";
2803 [%expect
2804 {|
2805 ((output (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))))
2806 (warnings ())) |}]
2807
2808 let nested_bracket =
2809 test "{[]]}";
2810 [%expect
2811 {|
2812 ((output (((f.ml (1 0) (1 5)) (code_block ((f.ml (1 2) (1 3)) ])))))
2813 (warnings ()))
2814 |}]
2815
2816 let two_nested_brackets =
2817 test "{[]]]}";
2818 [%expect
2819 {|
2820 ((output (((f.ml (1 0) (1 6)) (code_block ((f.ml (1 2) (1 4)) ]])))))
2821 (warnings ())) |}]
2822
2823 let nested_brackets_in_text =
2824 test "{[foo]]bar]}";
2825 [%expect
2826 {|
2827 ((output (((f.ml (1 0) (1 12)) (code_block ((f.ml (1 2) (1 10)) foo]]bar)))))
2828 (warnings ())) |}]
2829
2830 let trailing_whitespace =
2831 test "{[foo ]}";
2832 [%expect
2833 {|
2834 ((output (((f.ml (1 0) (1 8)) (code_block ((f.ml (1 2) (1 6)) "foo ")))))
2835 (warnings ()))
2836 |}]
2837
2838 let trailing_tab =
2839 test "{[foo\t]}";
2840 [%expect
2841 {|
2842 ((output (((f.ml (1 0) (1 8)) (code_block ((f.ml (1 2) (1 6)) "foo\t")))))
2843 (warnings ()))
2844 |}]
2845
2846 let trailing_newline =
2847 test "{[foo\n]}";
2848 [%expect
2849 {|
2850 ((output (((f.ml (1 0) (2 2)) (code_block ((f.ml (1 2) (2 0)) foo)))))
2851 (warnings ()))
2852 |}]
2853
2854 let trailing_cr_lf =
2855 test "{[foo\r\n]}";
2856 [%expect
2857 {|
2858 ((output (((f.ml (1 0) (2 2)) (code_block ((f.ml (1 2) (2 0)) "foo\r")))))
2859 (warnings ()))
2860 |}]
2861
2862 let trailing_newlines =
2863 test "{[foo\n\n]}";
2864 [%expect
2865 {|
2866 ((output (((f.ml (1 0) (3 2)) (code_block ((f.ml (1 2) (3 0)) "foo\n")))))
2867 (warnings ()))
2868 |}]
2869
2870 let preceded_by_whitespace =
2871 test "{[foo]}";
2872 [%expect
2873 {|
2874 ((output (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))))
2875 (warnings ())) |}]
2876
2877 let followed_by_whitespace =
2878 test "{[foo]}";
2879 [%expect
2880 {|
2881 ((output (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))))
2882 (warnings ())) |}]
2883
2884 let two_on_one_line =
2885 test "{[foo]} {[bar]}";
2886 [%expect
2887 {|
2888 ((output
2889 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
2890 ((f.ml (1 8) (1 15)) (code_block ((f.ml (1 10) (1 13)) bar)))))
2891 (warnings
2892 ( "File \"f.ml\", line 1, characters 8-15:\
2893 \n'{[...]}' (code block) should begin on its own line."))) |}]
2894
2895 let two =
2896 test "{[foo]}\n{[bar]}";
2897 [%expect
2898 {|
2899 ((output
2900 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
2901 ((f.ml (2 0) (2 7)) (code_block ((f.ml (2 2) (2 5)) bar)))))
2902 (warnings ())) |}]
2903
2904 let two_with_blank_line =
2905 test "{[foo]}\n\n{[bar]}";
2906 [%expect
2907 {|
2908 ((output
2909 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
2910 ((f.ml (3 0) (3 7)) (code_block ((f.ml (3 2) (3 5)) bar)))))
2911 (warnings ())) |}]
2912
2913 let followed_by_words =
2914 test "{[foo]} bar";
2915 [%expect
2916 {|
2917 ((output
2918 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
2919 ((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word bar)))))))
2920 (warnings
2921 ( "File \"f.ml\", line 1, characters 8-11:\
2922 \nParagraph should begin on its own line."))) |}]
2923
2924 let preceded_by_words =
2925 test "foo {[bar]}";
2926 [%expect
2927 {|
2928 ((output
2929 (((f.ml (1 0) (1 4))
2930 (paragraph (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space))))
2931 ((f.ml (1 4) (1 11)) (code_block ((f.ml (1 6) (1 9)) bar)))))
2932 (warnings
2933 ( "File \"f.ml\", line 1, characters 4-11:\
2934 \n'{[...]}' (code block) should begin on its own line."))) |}]
2935
2936 let preceded_by_paragraph =
2937 test "foo\n{[bar]}";
2938 [%expect
2939 {|
2940 ((output
2941 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
2942 ((f.ml (2 0) (2 7)) (code_block ((f.ml (2 2) (2 5)) bar)))))
2943 (warnings ())) |}]
2944
2945 let followed_by_paragraph =
2946 test "{[foo]}\nbar";
2947 [%expect
2948 {|
2949 ((output
2950 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
2951 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word bar)))))))
2952 (warnings ())) |}]
2953
2954 let unterminated =
2955 test "{[foo";
2956 [%expect
2957 {|
2958 ((output (((f.ml (1 0) (1 5)) (code_block ((f.ml (1 2) (1 5)) foo)))))
2959 (warnings
2960 ( "File \"f.ml\", line 1, characters 0-5:\
2961 \nMissing end of code block.\
2962 \nSuggestion: add ']}'."))) |}]
2963
2964 let unterminated_bracket =
2965 test "{[foo]";
2966 [%expect
2967 {|
2968 ((output (((f.ml (1 0) (1 6)) (code_block ((f.ml (1 2) (1 6)) foo])))))
2969 (warnings
2970 ( "File \"f.ml\", line 1, characters 0-6:\
2971 \nMissing end of code block.\
2972 \nSuggestion: add ']}'."))) |}]
2973
2974 let trailing_cr =
2975 test "{[foo\r]}";
2976 [%expect
2977 {|
2978 ((output (((f.ml (1 0) (1 8)) (code_block ((f.ml (1 2) (1 6)) "foo\r")))))
2979 (warnings ()))
2980 |}]
2981
2982 let comment =
2983 test "{[(* foo *)\nlet bar = ()]}";
2984 [%expect
2985 {|
2986 ((output
2987 (((f.ml (1 0) (2 14))
2988 (code_block ((f.ml (1 2) (2 12)) "(* foo *)\
2989 \nlet bar = ()")))))
2990 (warnings ()))
2991 |}]
2992
2993 let docstring =
2994 test "{[(** foo *)\nlet bar = ()]}";
2995 [%expect
2996 {|
2997 ((output
2998 (((f.ml (1 0) (2 14))
2999 (code_block ((f.ml (1 2) (2 12)) "(** foo *)\
3000 \nlet bar = ()")))))
3001 (warnings ()))
3002 |}]
3003
3004 let docstring_with_code_block =
3005 test "{[(** {[foo]} *)\nlet bar = ()]}";
3006 [%expect
3007 {|
3008 ((output
3009 (((f.ml (1 0) (1 13)) (code_block ((f.ml (1 2) (1 11)) "(** {[foo")))
3010 ((f.ml (1 14) (2 12))
3011 (paragraph
3012 (((f.ml (1 14) (1 16)) (word "*)")) ((f.ml (1 16) (2 0)) space)
3013 ((f.ml (2 0) (2 3)) (word let)) ((f.ml (2 3) (2 4)) space)
3014 ((f.ml (2 4) (2 7)) (word bar)) ((f.ml (2 7) (2 8)) space)
3015 ((f.ml (2 8) (2 9)) (word =)) ((f.ml (2 9) (2 10)) space)
3016 ((f.ml (2 10) (2 12)) (word "()")))))))
3017 (warnings
3018 ( "File \"f.ml\", line 1, characters 14-16:\
3019 \nParagraph should begin on its own line."))) |}]
3020
3021 let code_block_with_meta =
3022 test "{@ocaml env=f1 version>=4.06 [code goes here]}";
3023 [%expect
3024 {|
3025 ((output
3026 (((f.ml (1 0) (1 46))
3027 (code_block
3028 (((f.ml (1 2) (1 7)) ocaml)
3029 ((binding ((f.ml (1 8) (1 11)) env) ((f.ml (1 12) (1 14)) f1))
3030 (binding ((f.ml (1 15) (1 23)) version>) ((f.ml (1 24) (1 28)) 4.06))))
3031 ((f.ml (1 30) (1 44)) "code goes here")))))
3032 (warnings ()))
3033 |}]
3034
3035 let code_block_with_output =
3036 test "{delim@ocaml[foo]delim[output {b foo}]}";
3037 [%expect
3038 {|
3039 ((output
3040 (((f.ml (1 0) (1 39))
3041 (code_block (((f.ml (1 7) (1 12)) ocaml) ()) ((f.ml (1 13) (1 16)) foo)
3042 ((paragraph
3043 (((f.ml (1 23) (1 29)) (word output)) ((f.ml (1 29) (1 30)) space)
3044 ((f.ml (1 30) (1 37)) (bold (((f.ml (1 33) (1 36)) (word foo))))))))))))
3045 (warnings ()))
3046 |}]
3047
3048 let delimited_code_block_with_meta_and_output =
3049 test "{delim@ocaml env=f1 version>=4.06 [foo]delim[output {b foo}]}";
3050 [%expect
3051 {|
3052 ((output
3053 (((f.ml (1 0) (1 61))
3054 (code_block
3055 (((f.ml (1 7) (1 12)) ocaml)
3056 ((binding ((f.ml (1 13) (1 16)) env) ((f.ml (1 17) (1 19)) f1))
3057 (binding ((f.ml (1 20) (1 28)) version>) ((f.ml (1 29) (1 33)) 4.06))))
3058 ((f.ml (1 35) (1 38)) foo)
3059 ((paragraph
3060 (((f.ml (1 45) (1 51)) (word output)) ((f.ml (1 51) (1 52)) space)
3061 ((f.ml (1 52) (1 59)) (bold (((f.ml (1 55) (1 58)) (word foo))))))))))))
3062 (warnings ()))
3063 |}]
3064
3065 (* Code block contains ']['. *)
3066 let code_block_with_output_without_delim =
3067 test "{[foo][output {b foo}]}";
3068 [%expect
3069 {|
3070 ((output
3071 (((f.ml (1 0) (1 23))
3072 (code_block ((f.ml (1 2) (1 21)) "foo][output {b foo}")))))
3073 (warnings ()))
3074 |}]
3075
3076 (* Code block contains ']['. *)
3077 let code_block_with_output_and_lang_without_delim =
3078 test "{@ocaml[foo][output {b foo}]}";
3079 [%expect
3080 {|
3081 ((output
3082 (((f.ml (1 0) (1 29))
3083 (code_block (((f.ml (1 2) (1 7)) ocaml) ())
3084 ((f.ml (1 8) (1 27)) "foo][output {b foo}")))))
3085 (warnings ()))
3086 |}]
3087
3088 let code_block_with_output_unexpected_delim =
3089 test "{[foo]unexpected[output {b foo}]}";
3090 [%expect
3091 {|
3092 ((output
3093 (((f.ml (1 0) (1 33))
3094 (code_block ((f.ml (1 2) (1 31)) "foo]unexpected[output {b foo}")))))
3095 (warnings ()))
3096 |}]
3097
3098 let code_block_with_output_lang_unexpected_delim =
3099 test "{@ocaml[foo]unexpected[output {b foo}]}";
3100 [%expect
3101 {|
3102 ((output
3103 (((f.ml (1 0) (1 39))
3104 (code_block (((f.ml (1 2) (1 7)) ocaml) ())
3105 ((f.ml (1 8) (1 37)) "foo]unexpected[output {b foo}")))))
3106 (warnings ()))
3107 |}]
3108
3109 let code_block_with_output_wrong_delim =
3110 test "{delim@ocaml[foo]wrong[output {b foo}]delim}";
3111 [%expect
3112 {|
3113 ((output
3114 (((f.ml (1 0) (1 44))
3115 (code_block (((f.ml (1 7) (1 12)) ocaml) ())
3116 ((f.ml (1 13) (1 37)) "foo]wrong[output {b foo}")))))
3117 (warnings ()))
3118 |}]
3119
3120 let code_block_empty_meta =
3121 test "{@[code goes here]}";
3122 [%expect
3123 {|
3124 ((output
3125 (((f.ml (1 0) (1 19)) (code_block ((f.ml (1 3) (1 17)) "code goes here")))))
3126 (warnings
3127 ( "File \"f.ml\", line 1, characters 0-3:\
3128 \n'{@' should be followed by a language tag.\
3129 \nSuggestion: try '{[ ... ]}' or '{@ocaml[ ... ]}'.")))
3130 |}]
3131
3132 let unterminated_code_block_with_meta =
3133 test "{@meta[foo";
3134 [%expect
3135 {|
3136 ((output
3137 (((f.ml (1 0) (1 10))
3138 (code_block (((f.ml (1 2) (1 6)) meta) ()) ((f.ml (1 7) (1 10)) foo)))))
3139 (warnings
3140 ( "File \"f.ml\", line 1, characters 0-10:\
3141 \nMissing end of code block.\
3142 \nSuggestion: add ']}'.")))
3143 |}]
3144
3145 let unterminated_code_block_with_meta =
3146 test "{@met";
3147 [%expect
3148 {|
3149 ((output
3150 (((f.ml (1 0) (1 5))
3151 (code_block (((f.ml (1 2) (1 5)) met) ()) ((f.ml (1 5) (1 5)) "")))))
3152 (warnings
3153 ( "File \"f.ml\", line 1, characters 0-5:\
3154 \nMissing end of code block.\
3155 \nSuggestion: try '{@ocaml[ ... ]}'."
3156 "File \"f.ml\", line 1, characters 0-5:\
3157 \n'{[...]}' (code block) should not be empty.")))
3158 |}]
3159
3160 let newlines_after_langtag =
3161 test "{@ocaml\n[ code ]}";
3162 [%expect
3163 {|
3164 ((output
3165 (((f.ml (1 0) (2 9))
3166 (code_block (((f.ml (1 2) (1 7)) ocaml) ())
3167 ((f.ml (2 1) (2 7)) " code ")))))
3168 (warnings ()))
3169 |}]
3170
3171 let newlines_after_meta =
3172 test "{@ocaml kind=toplevel\n[ code ]}";
3173 [%expect
3174 {|
3175 ((output
3176 (((f.ml (1 0) (2 9))
3177 (code_block
3178 (((f.ml (1 2) (1 7)) ocaml)
3179 ((binding ((f.ml (1 8) (1 12)) kind) ((f.ml (1 13) (1 21)) toplevel))))
3180 ((f.ml (2 1) (2 7)) " code ")))))
3181 (warnings ()))
3182 |}]
3183
3184 let spaces_after_meta =
3185 test "{@ocaml kind=toplevel [ code ]}";
3186 [%expect
3187 {|
3188 ((output
3189 (((f.ml (1 0) (1 31))
3190 (code_block
3191 (((f.ml (1 2) (1 7)) ocaml)
3192 ((binding ((f.ml (1 8) (1 12)) kind) ((f.ml (1 13) (1 21)) toplevel))))
3193 ((f.ml (1 23) (1 29)) " code ")))))
3194 (warnings ()))
3195 |}]
3196
3197 let spaces_and_newline_after_meta =
3198 test "{@ocaml kind=toplevel \n [ code ]}";
3199 [%expect
3200 {|
3201 ((output
3202 (((f.ml (1 0) (2 11))
3203 (code_block
3204 (((f.ml (1 2) (1 7)) ocaml)
3205 ((binding ((f.ml (1 8) (1 12)) kind) ((f.ml (1 13) (1 21)) toplevel))))
3206 ((f.ml (2 3) (2 9)) " code ")))))
3207 (warnings ()))
3208 |}]
3209
3210 let newlines_inside_meta =
3211 test "{@ocaml kind=toplevel\nenv=e1[ code ]}";
3212 [%expect
3213 {|
3214 ((output
3215 (((f.ml (1 0) (2 15))
3216 (code_block
3217 (((f.ml (1 2) (1 7)) ocaml)
3218 ((binding ((f.ml (1 8) (1 12)) kind) ((f.ml (1 13) (1 21)) toplevel))
3219 (binding ((f.ml (2 0) (2 3)) env) ((f.ml (2 4) (2 6)) e1))))
3220 ((f.ml (2 7) (2 13)) " code ")))))
3221 (warnings ()))
3222 |}]
3223
3224 let newlines_between_meta =
3225 test "{@ocaml\nkind=toplevel[ code ]}";
3226 [%expect
3227 {|
3228 ((output
3229 (((f.ml (1 0) (2 22))
3230 (code_block
3231 (((f.ml (1 2) (1 7)) ocaml)
3232 ((binding ((f.ml (2 0) (2 4)) kind) ((f.ml (2 5) (2 13)) toplevel))))
3233 ((f.ml (2 14) (2 20)) " code ")))))
3234 (warnings ()))
3235 |}]
3236
3237 let empty_key =
3238 test "{@ocaml =foo [ code ]}";
3239 [%expect
3240 {|
3241 ((output
3242 (((f.ml (1 0) (1 22))
3243 (code_block (((f.ml (1 2) (1 7)) ocaml) ())
3244 ((f.ml (1 14) (1 20)) " code ")))))
3245 (warnings
3246 ( "File \"f.ml\", line 1, characters 8-9:\
3247 \nInvalid character in code block metadata tag '='."
3248 "File \"f.ml\", line 1, characters 9-10:\
3249 \nInvalid character in code block metadata tag 'f'.")))
3250 |}]
3251
3252 let no_escape_without_quotes =
3253 test {|{@ocaml \n\t\b=hello [ code ]}|};
3254 [%expect
3255 {|
3256 ((output
3257 (((f.ml (1 0) (1 30))
3258 (code_block
3259 (((f.ml (1 2) (1 7)) ocaml)
3260 ((binding ((f.ml (1 8) (1 14)) "\\n\\t\\b")
3261 ((f.ml (1 15) (1 20)) hello))))
3262 ((f.ml (1 22) (1 28)) " code ")))))
3263 (warnings ()))
3264 |}]
3265
3266 let escape_within_quotes =
3267 test {|{@ocaml "\065"=hello [ code ]}|};
3268 [%expect
3269 {|
3270 ((output
3271 (((f.ml (1 0) (1 30))
3272 (code_block
3273 (((f.ml (1 2) (1 7)) ocaml)
3274 ((binding ((f.ml (1 8) (1 14)) A) ((f.ml (1 15) (1 20)) hello))))
3275 ((f.ml (1 22) (1 28)) " code ")))))
3276 (warnings ()))
3277 |}]
3278
3279 let langtag_non_word =
3280 test "{@ocaml,top[ code ]}";
3281 [%expect
3282 {|
3283 ((output
3284 (((f.ml (1 0) (1 20))
3285 (code_block (((f.ml (1 2) (1 7)) ocaml) ())
3286 ((f.ml (1 12) (1 18)) " code ")))))
3287 (warnings
3288 ( "File \"f.ml\", line 1, characters 7-8:\
3289 \nInvalid character in code block metadata tag ','.")))
3290 |}]
3291
3292 let delimited_code_block =
3293 test "{delim@ocaml[ all{}[2[{{]doo}}]]'''(* ]} ]delim}";
3294 [%expect
3295 {|
3296 ((output
3297 (((f.ml (1 0) (1 48))
3298 (code_block (((f.ml (1 7) (1 12)) ocaml) ())
3299 ((f.ml (1 13) (1 41)) " all{}[2[{{]doo}}]]'''(* ]} ")))))
3300 (warnings ()))
3301 |}]
3302
3303 let code_block_with_output =
3304 test
3305 {|{delim@ocaml[ let x = ]delim[ {err@mdx-error[ here's the error ]} ]err}
3306 ]delim}|};
3307 [%expect
3308 {|
3309 ((output
3310 (((f.ml (1 0) (2 15))
3311 (code_block (((f.ml (1 7) (1 12)) ocaml) ())
3312 ((f.ml (1 13) (1 22)) " let x = ")
3313 ((code_block (((f.ml (1 35) (1 44)) mdx-error) ())
3314 ((f.ml (1 45) (1 66)) " here's the error ]} "))
3315 (paragraph
3316 (((f.ml (2 8) (2 9)) (word ])) ((f.ml (2 9) (2 14)) (word delim)))))))))
3317 (warnings
3318 ( "File \"f.ml\", line 2, characters 8-9:\
3319 \nUnpaired ']' (end of code).\
3320 \nSuggestion: try '\\]'.")))
3321 |}]
3322
3323 let delimited_code_block_with_output =
3324 test "{delim@ocaml[ foo ]delim[ ]}";
3325 [%expect
3326 {|
3327 ((output
3328 (((f.ml (1 0) (1 28))
3329 (code_block (((f.ml (1 7) (1 12)) ocaml) ())
3330 ((f.ml (1 13) (1 18)) " foo ") ()))))
3331 (warnings ()))
3332 |}]
3333
3334 (** {3 Code block indentation}
3335
3336 Code blocks strip some whitespace from the content of a multiline code
3337 block. We test that here, as well as warnings related to that.
3338
3339 Let's test warnings first. When the indentation is less than the
3340 identation of the opening bracket, we warn. *)
3341
3342 let too_few_indentation =
3343 test {|
3344 {[
3345 foo
3346 ]}|};
3347 [%expect
3348 {|
3349 ((output
3350 (((f.ml (2 3) (4 3))
3351 (code_block ((f.ml (2 5) (4 1)) foo)
3352 (Warnings
3353 "File \"f.ml\", line 2, character 3 to line 4, character 3:\
3354 \nCode blocks should be indented at the opening `{`.")))))
3355 (warnings ()))
3356 |}]
3357
3358 let multiline_without_newline =
3359 test {|
3360 {[ foo
3361 ]}|};
3362 [%expect
3363 {|
3364 ((output (((f.ml (2 3) (3 3)) (code_block ((f.ml (2 5) (3 1)) " foo")))))
3365 (warnings ()))
3366 |}]
3367
3368 let everything_is_wrong =
3369 test {|
3370 {[ foo
3371 bar ]}|};
3372 [%expect
3373 {|
3374 ((output
3375 (((f.ml (2 3) (3 8))
3376 (code_block ((f.ml (2 5) (3 6)) " foo\
3377 \nbar ")
3378 (Warnings
3379 "File \"f.ml\", line 2, character 3 to line 3, character 8:\
3380 \nCode blocks should be indented at the opening `{`.")))))
3381 (warnings ()))
3382 |}]
3383
3384 let all_good_multiline =
3385 test {|
3386 {[
3387 foo
3388 ]}|};
3389 [%expect
3390 {|
3391 ((output (((f.ml (2 3) (4 3)) (code_block ((f.ml (2 5) (4 1)) foo)))))
3392 (warnings ()))
3393 |}]
3394
3395 let all_good_single_line =
3396 test {| {[ foo ]} |};
3397 [%expect
3398 {|
3399 ((output (((f.ml (1 1) (1 10)) (code_block ((f.ml (1 3) (1 8)) " foo ")))))
3400 (warnings ()))
3401 |}]
3402
3403 (** Let's now test that the correct amount of whitespace is removed. *)
3404
3405 let descending_stair =
3406 test {|
3407 {[
3408 foo
3409 bar
3410 baz
3411 ]}|};
3412 [%expect
3413 {|
3414 ((output
3415 (((f.ml (2 3) (6 3))
3416 (code_block ((f.ml (2 5) (6 1)) "foo\
3417 \n bar\
3418 \n baz")))))
3419 (warnings ()))
3420 |}]
3421
3422 let ascending_stair =
3423 test {|
3424 {[
3425 baz
3426 bar
3427 foo
3428 ]}|};
3429 [%expect
3430 {|
3431 ((output
3432 (((f.ml (2 3) (6 3))
3433 (code_block ((f.ml (2 5) (6 1)) " baz\
3434 \n bar\
3435 \nfoo")))))
3436 (warnings ()))
3437 |}]
3438
3439 let indented_after_opening_fence =
3440 test {|
3441 {[
3442 baz
3443 bar
3444 foo
3445 ]}|};
3446 [%expect
3447 {|
3448 ((output
3449 (((f.ml (2 3) (6 3))
3450 (code_block ((f.ml (2 5) (6 1)) " baz\
3451 \n bar\
3452 \n foo")))))
3453 (warnings ()))
3454 |}]
3455
3456 let indentation_warning_case =
3457 test {|
3458 {[
3459 baz
3460 bar
3461 foo
3462 ]}|};
3463 [%expect
3464 {|
3465 ((output
3466 (((f.ml (2 3) (6 3))
3467 (code_block ((f.ml (2 5) (6 1)) " baz\
3468 \nbar\
3469 \n foo")
3470 (Warnings
3471 "File \"f.ml\", line 2, character 3 to line 6, character 3:\
3472 \nCode blocks should be indented at the opening `{`.")))))
3473 (warnings ()))
3474 |}]
3475
3476 (** {3 Metadata tags}
3477
3478 Code blocks have a metadata field, with bindings and simple tags. *)
3479
3480 let lots_of_tags =
3481 test
3482 {|{@ocaml env=f1 version=4.06 "tag with several words" "binding with"=singleword also="other case" "everything has"="multiple words" [foo]}|};
3483 [%expect
3484 {|
3485 ((output
3486 (((f.ml (1 0) (1 137))
3487 (code_block
3488 (((f.ml (1 2) (1 7)) ocaml)
3489 ((binding ((f.ml (1 8) (1 11)) env) ((f.ml (1 12) (1 14)) f1))
3490 (binding ((f.ml (1 15) (1 22)) version) ((f.ml (1 23) (1 27)) 4.06))
3491 (tag ((f.ml (1 28) (1 52)) "tag with several words"))
3492 (binding ((f.ml (1 53) (1 67)) "binding with")
3493 ((f.ml (1 68) (1 78)) singleword))
3494 (binding ((f.ml (1 79) (1 83)) also)
3495 ((f.ml (1 84) (1 96)) "other case"))
3496 (binding ((f.ml (1 97) (1 113)) "everything has")
3497 ((f.ml (1 114) (1 130)) "multiple words"))))
3498 ((f.ml (1 132) (1 135)) foo)))))
3499 (warnings ()))
3500 |}]
3501
3502 let lots_of_tags_with_newlines =
3503 test
3504 {|{@ocaml
3505 env=f1
3506 version=4.06
3507 single_tag
3508 "tag with several words"
3509 "binding with"=singleword
3510 also="other case"
3511 "everything has"="multiple words"
3512 [foo]}|};
3513 [%expect
3514 {|
3515 ((output
3516 (((f.ml (1 0) (9 15))
3517 (code_block
3518 (((f.ml (1 2) (1 7)) ocaml)
3519 ((binding ((f.ml (2 9) (2 12)) env) ((f.ml (2 13) (2 15)) f1))
3520 (binding ((f.ml (3 9) (3 16)) version) ((f.ml (3 17) (3 21)) 4.06))
3521 (tag ((f.ml (4 9) (4 19)) single_tag))
3522 (tag ((f.ml (5 9) (5 33)) "tag with several words"))
3523 (binding ((f.ml (6 9) (6 23)) "binding with")
3524 ((f.ml (6 24) (6 34)) singleword))
3525 (binding ((f.ml (7 9) (7 13)) also)
3526 ((f.ml (7 14) (7 26)) "other case"))
3527 (binding ((f.ml (8 9) (8 25)) "everything has")
3528 ((f.ml (8 26) (8 42)) "multiple words"))))
3529 ((f.ml (9 10) (9 13)) foo)))))
3530 (warnings ()))
3531 |}]
3532
3533 let escaping1 =
3534 test {|{@ocaml "\""="\"" [foo]}|};
3535 [%expect
3536 {|
3537 ((output
3538 (((f.ml (1 0) (1 24))
3539 (code_block
3540 (((f.ml (1 2) (1 7)) ocaml)
3541 ((binding ((f.ml (1 8) (1 12)) "\"") ((f.ml (1 13) (1 17)) "\""))))
3542 ((f.ml (1 19) (1 22)) foo)))))
3543 (warnings ()))
3544 |}]
3545
3546 let escaping2 =
3547 test {|{@ocaml \"=\" [foo]}|};
3548 [%expect
3549 {|
3550 ((output
3551 (((f.ml (1 0) (1 20))
3552 (code_block (((f.ml (1 2) (1 7)) ocaml) ()) ((f.ml (1 15) (1 18)) foo)))))
3553 (warnings
3554 ( "File \"f.ml\", line 1, characters 9-10:\
3555 \nInvalid character in code block metadata tag '\"'.")))
3556 |}]
3557
3558 let two_slashes_are_required =
3559 test {|{@ocaml "\\" [foo]}|};
3560 [%expect
3561 {|
3562 ((output
3563 (((f.ml (1 0) (1 19))
3564 (code_block
3565 (((f.ml (1 2) (1 7)) ocaml) ((tag ((f.ml (1 8) (1 12)) "\\"))))
3566 ((f.ml (1 14) (1 17)) foo)))))
3567 (warnings ()))
3568 |}]
3569
3570 let escaped_char_are_allowed_but_warn =
3571 test {|
3572 {@ocaml "\a\b\c" [foo]}|};
3573 [%expect
3574 {|
3575 ((output
3576 (((f.ml (2 5) (2 28))
3577 (code_block
3578 (((f.ml (2 7) (2 12)) ocaml) ((tag ((f.ml (2 13) (2 21)) "a\bc"))))
3579 ((f.ml (2 23) (2 26)) foo)))))
3580 (warnings
3581 ( "File \"f.ml\", line 2, characters 14-16:\
3582 \nThe 'a' character should not be escaped.\
3583 \nSuggestion: Remove \\."
3584 "File \"f.ml\", line 2, characters 18-20:\
3585 \nThe 'c' character should not be escaped.\
3586 \nSuggestion: Remove \\.")))
3587 |}]
3588
3589 let escaped_char_are_allowed_but_warn2 =
3590 test {|
3591 {@ocaml "\a\b\c"="\x\y\z" [foo]}|};
3592 [%expect
3593 {|
3594 ((output
3595 (((f.ml (2 5) (2 37))
3596 (code_block
3597 (((f.ml (2 7) (2 12)) ocaml)
3598 ((binding ((f.ml (2 13) (2 21)) "a\bc") ((f.ml (2 22) (2 30)) xyz))))
3599 ((f.ml (2 32) (2 35)) foo)))))
3600 (warnings
3601 ( "File \"f.ml\", line 2, characters 14-16:\
3602 \nThe 'a' character should not be escaped.\
3603 \nSuggestion: Remove \\."
3604 "File \"f.ml\", line 2, characters 18-20:\
3605 \nThe 'c' character should not be escaped.\
3606 \nSuggestion: Remove \\."
3607 "File \"f.ml\", line 2, characters 23-25:\
3608 \nThe 'x' character should not be escaped.\
3609 \nSuggestion: Remove \\."
3610 "File \"f.ml\", line 2, characters 25-27:\
3611 \nThe 'y' character should not be escaped.\
3612 \nSuggestion: Remove \\."
3613 "File \"f.ml\", line 2, characters 27-29:\
3614 \nThe 'z' character should not be escaped.\
3615 \nSuggestion: Remove \\.")))
3616 |}]
3617 end in
3618 ()
3619
3620let%expect_test _ =
3621 let module Verbatim = struct
3622 let basic =
3623 test "{v foo v}";
3624 [%expect
3625 {| ((output (((f.ml (1 0) (1 9)) (verbatim foo)))) (warnings ())) |}]
3626
3627 let empty =
3628 test "{v v}";
3629 [%expect
3630 {|
3631 ((output (((f.ml (1 0) (1 5)) (verbatim ""))))
3632 (warnings
3633 ( "File \"f.ml\", line 1, characters 0-5:\
3634 \n'{v ... v}' (verbatim text) should not be empty."))) |}]
3635
3636 let degenerate =
3637 test "{vv}";
3638 [%expect
3639 {|
3640 ((output (((f.ml (1 0) (1 4)) (verbatim v}))))
3641 (warnings
3642 ( "File \"f.ml\", line 1, characters 2-4:\
3643 \n'v}' should be preceded by whitespace."
3644 "File \"f.ml\", line 1, characters 0-2:\
3645 \n'{v' should be followed by whitespace."))) |}]
3646
3647 let whitespace_only =
3648 test "{v v}";
3649 [%expect
3650 {|
3651 ((output (((f.ml (1 0) (1 6)) (verbatim ""))))
3652 (warnings
3653 ( "File \"f.ml\", line 1, characters 0-6:\
3654 \n'{v ... v}' (verbatim text) should not be empty."))) |}]
3655
3656 let blank_line_only =
3657 test "{v\n \nv}";
3658 [%expect
3659 {| ((output (((f.ml (1 0) (3 2)) (verbatim " ")))) (warnings ())) |}]
3660
3661 let no_leading_whitespace =
3662 test "{vfoo v}";
3663 [%expect
3664 {|
3665 ((output (((f.ml (1 0) (1 8)) (verbatim foo))))
3666 (warnings
3667 ( "File \"f.ml\", line 1, characters 0-2:\
3668 \n'{v' should be followed by whitespace."))) |}]
3669
3670 let no_trailing_whitespace =
3671 test "{v foov}";
3672 [%expect
3673 {|
3674 ((output (((f.ml (1 0) (1 8)) (verbatim foov}))))
3675 (warnings
3676 ( "File \"f.ml\", line 1, characters 6-8:\
3677 \n'v}' should be preceded by whitespace."))) |}]
3678
3679 let multiple_leading_whitespace =
3680 test "{v foo v}";
3681 [%expect
3682 {| ((output (((f.ml (1 0) (1 10)) (verbatim " foo")))) (warnings ())) |}]
3683
3684 let multiple_trailing_whitespace =
3685 test "{v foo v}";
3686 [%expect
3687 {| ((output (((f.ml (1 0) (1 10)) (verbatim "foo ")))) (warnings ())) |}]
3688
3689 let leading_tab =
3690 test "{v\tfoo v}";
3691 [%expect
3692 {| ((output (((f.ml (1 0) (1 9)) (verbatim "\tfoo")))) (warnings ())) |}]
3693
3694 let leading_newline =
3695 test "{v\nfoo v}";
3696 [%expect
3697 {| ((output (((f.ml (1 0) (2 6)) (verbatim foo)))) (warnings ())) |}]
3698
3699 let leading_cr_lf =
3700 test "{v\r\nfoo v}";
3701 [%expect
3702 {| ((output (((f.ml (1 0) (2 6)) (verbatim foo)))) (warnings ())) |}]
3703
3704 let trailing_tab =
3705 test "{v foo\tv}";
3706 [%expect
3707 {| ((output (((f.ml (1 0) (1 9)) (verbatim "foo\t")))) (warnings ())) |}]
3708
3709 let trailing_newline =
3710 test "{v foo\nv}";
3711 [%expect
3712 {| ((output (((f.ml (1 0) (2 2)) (verbatim foo)))) (warnings ())) |}]
3713
3714 let trailing_cr_lf =
3715 test "{v foo\r\nv}";
3716 [%expect
3717 {| ((output (((f.ml (1 0) (2 2)) (verbatim "foo\r")))) (warnings ())) |}]
3718
3719 let internal_whitespace =
3720 test "{v foo bar v}";
3721 [%expect
3722 {| ((output (((f.ml (1 0) (1 13)) (verbatim "foo bar")))) (warnings ())) |}]
3723
3724 let newline =
3725 test "{v foo\nbar v}";
3726 [%expect
3727 {|
3728 ((output (((f.ml (1 0) (2 6)) (verbatim "foo\
3729 \nbar")))) (warnings ()))
3730 |}]
3731
3732 let cr_lf =
3733 test "{v foo\r\nbar v}";
3734 [%expect
3735 {|
3736 ((output (((f.ml (1 0) (2 6)) (verbatim "foo\r\
3737 \nbar")))) (warnings ()))
3738 |}]
3739
3740 let blank_line =
3741 test "{v foo\n\nbar v}";
3742 [%expect
3743 {|
3744 ((output (((f.ml (1 0) (3 6)) (verbatim "foo\
3745 \n\
3746 \nbar")))) (warnings ()))
3747 |}]
3748
3749 let leading_newlines =
3750 test "{v\n\nfoo v}";
3751 [%expect
3752 {|
3753 ((output (((f.ml (1 0) (3 6)) (verbatim "\
3754 \nfoo")))) (warnings ()))
3755 |}]
3756
3757 let leading_newline_with_space =
3758 test "{v\n foo v}";
3759 [%expect
3760 {| ((output (((f.ml (1 0) (2 7)) (verbatim " foo")))) (warnings ())) |}]
3761
3762 let leading_newline_with_trash =
3763 test "{v \nfoo v}";
3764 [%expect
3765 {| ((output (((f.ml (1 0) (2 6)) (verbatim foo)))) (warnings ())) |}]
3766
3767 let nested_opener =
3768 test "{v {v v}";
3769 [%expect
3770 {| ((output (((f.ml (1 0) (1 8)) (verbatim {v)))) (warnings ())) |}]
3771
3772 let nested_closer =
3773 test "{v foo v} v}";
3774 [%expect
3775 {|
3776 ((output
3777 (((f.ml (1 0) (1 9)) (verbatim foo))
3778 ((f.ml (1 10) (1 11)) (paragraph (((f.ml (1 10) (1 11)) (word v)))))
3779 ((f.ml (1 11) (1 12)) (paragraph (((f.ml (1 11) (1 12)) (word })))))))
3780 (warnings
3781 ( "File \"f.ml\", line 1, characters 10-11:\
3782 \nParagraph should begin on its own line."
3783 "File \"f.ml\", line 1, characters 11-12:\
3784 \nUnpaired '}' (end of markup).\
3785 \nSuggestion: try '\\}'."))) |}]
3786
3787 let nested_closer_with_word =
3788 test "{v {dev} v}";
3789 [%expect
3790 {| ((output (((f.ml (1 0) (1 11)) (verbatim {dev})))) (warnings ())) |}]
3791
3792 let nested_v =
3793 test "{v v v}";
3794 [%expect
3795 {| ((output (((f.ml (1 0) (1 7)) (verbatim v)))) (warnings ())) |}]
3796
3797 let two_nested_vs =
3798 test "{v vv v}";
3799 [%expect
3800 {| ((output (((f.ml (1 0) (1 8)) (verbatim vv)))) (warnings ())) |}]
3801
3802 let nested_v_at_end =
3803 test "{v vv}";
3804 [%expect
3805 {|
3806 ((output (((f.ml (1 0) (1 6)) (verbatim vv}))))
3807 (warnings
3808 ( "File \"f.ml\", line 1, characters 4-6:\
3809 \n'v}' should be preceded by whitespace."))) |}]
3810
3811 let two_nested_vs_at_end =
3812 test "{v vvv}";
3813 [%expect
3814 {|
3815 ((output (((f.ml (1 0) (1 7)) (verbatim vvv}))))
3816 (warnings
3817 ( "File \"f.ml\", line 1, characters 5-7:\
3818 \n'v}' should be preceded by whitespace."))) |}]
3819
3820 let nested_vs_in_text =
3821 test "{v foovvbar v}";
3822 [%expect
3823 {| ((output (((f.ml (1 0) (1 14)) (verbatim foovvbar)))) (warnings ())) |}]
3824
3825 let trailing_newlines =
3826 test "{v foo\n\nv}";
3827 [%expect
3828 {| ((output (((f.ml (1 0) (3 2)) (verbatim "foo\n")))) (warnings ())) |}]
3829
3830 let preceded_by_whitespace =
3831 test "{v foo v}";
3832 [%expect
3833 {| ((output (((f.ml (1 0) (1 9)) (verbatim foo)))) (warnings ())) |}]
3834
3835 let followed_by_whitespace =
3836 test "{v foo v}";
3837 [%expect
3838 {| ((output (((f.ml (1 0) (1 9)) (verbatim foo)))) (warnings ())) |}]
3839
3840 let two_on_one_line =
3841 test "{v foo v} {v bar v}";
3842 [%expect
3843 {|
3844 ((output
3845 (((f.ml (1 0) (1 9)) (verbatim foo)) ((f.ml (1 10) (1 19)) (verbatim bar))))
3846 (warnings
3847 ( "File \"f.ml\", line 1, characters 10-19:\
3848 \n'{v ... v}' (verbatim text) should begin on its own line."))) |}]
3849
3850 let two =
3851 test "{v foo v}\n{v bar v}";
3852 [%expect
3853 {|
3854 ((output
3855 (((f.ml (1 0) (1 9)) (verbatim foo)) ((f.ml (2 0) (2 9)) (verbatim bar))))
3856 (warnings ())) |}]
3857
3858 let two_with_blank_line =
3859 test "{v foo v}\n\n{v bar v}";
3860 [%expect
3861 {|
3862 ((output
3863 (((f.ml (1 0) (1 9)) (verbatim foo)) ((f.ml (3 0) (3 9)) (verbatim bar))))
3864 (warnings ())) |}]
3865
3866 let followed_by_words =
3867 test "{v foo v} bar";
3868 [%expect
3869 {|
3870 ((output
3871 (((f.ml (1 0) (1 9)) (verbatim foo))
3872 ((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word bar)))))))
3873 (warnings
3874 ( "File \"f.ml\", line 1, characters 10-13:\
3875 \nParagraph should begin on its own line."))) |}]
3876
3877 let preceded_by_words =
3878 test "foo {v bar v}";
3879 [%expect
3880 {|
3881 ((output
3882 (((f.ml (1 0) (1 4))
3883 (paragraph (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) space))))
3884 ((f.ml (1 4) (1 13)) (verbatim bar))))
3885 (warnings
3886 ( "File \"f.ml\", line 1, characters 4-13:\
3887 \n'{v ... v}' (verbatim text) should begin on its own line."))) |}]
3888
3889 let preceded_by_paragraph =
3890 test "foo\n{v bar v}";
3891 [%expect
3892 {|
3893 ((output
3894 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
3895 ((f.ml (2 0) (2 9)) (verbatim bar))))
3896 (warnings ())) |}]
3897
3898 let followed_by_paragraph =
3899 test "{v foo v}\nbar";
3900 [%expect
3901 {|
3902 ((output
3903 (((f.ml (1 0) (1 9)) (verbatim foo))
3904 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word bar)))))))
3905 (warnings ())) |}]
3906
3907 let unterminated =
3908 test "{v foo";
3909 [%expect
3910 {|
3911 ((output (((f.ml (1 0) (1 6)) (verbatim foo))))
3912 (warnings
3913 ( "File \"f.ml\", line 1, characters 6-6:\
3914 \nEnd of text is not allowed in '{v ... v}' (verbatim text)."))) |}]
3915
3916 let unterminated_v =
3917 test "{v foo v";
3918 [%expect
3919 {|
3920 ((output (((f.ml (1 0) (1 8)) (verbatim "foo v"))))
3921 (warnings
3922 ( "File \"f.ml\", line 1, characters 8-8:\
3923 \nEnd of text is not allowed in '{v ... v}' (verbatim text)."))) |}]
3924
3925 let unterminated_empty =
3926 test "{v";
3927 [%expect
3928 {|
3929 ((output (((f.ml (1 0) (1 2)) (verbatim ""))))
3930 (warnings
3931 ( "File \"f.ml\", line 1, characters 2-2:\
3932 \nEnd of text is not allowed in '{v ... v}' (verbatim text)."
3933 "File \"f.ml\", line 1, characters 0-2:\
3934 \n'{v ... v}' (verbatim text) should not be empty."))) |}]
3935
3936 let unterminated_whitespace =
3937 test "{v";
3938 [%expect
3939 {|
3940 ((output (((f.ml (1 0) (1 2)) (verbatim ""))))
3941 (warnings
3942 ( "File \"f.ml\", line 1, characters 2-2:\
3943 \nEnd of text is not allowed in '{v ... v}' (verbatim text)."
3944 "File \"f.ml\", line 1, characters 0-2:\
3945 \n'{v ... v}' (verbatim text) should not be empty."))) |}]
3946
3947 let unterminated_whitespace_2 =
3948 test "{v";
3949 [%expect
3950 {|
3951 ((output (((f.ml (1 0) (1 2)) (verbatim ""))))
3952 (warnings
3953 ( "File \"f.ml\", line 1, characters 2-2:\
3954 \nEnd of text is not allowed in '{v ... v}' (verbatim text)."
3955 "File \"f.ml\", line 1, characters 0-2:\
3956 \n'{v ... v}' (verbatim text) should not be empty."))) |}]
3957
3958 let trailing_cr =
3959 test "{v foo\rv}";
3960 [%expect
3961 {| ((output (((f.ml (1 0) (1 9)) (verbatim "foo\r")))) (warnings ())) |}]
3962
3963 (** {3 Verbatim indentation}
3964
3965 Verbatims work as code blocks. We test that here. *)
3966
3967 let too_few_indentation =
3968 test {|
3969 {v
3970 foo
3971 v}|};
3972 [%expect
3973 {|
3974 ((output
3975 (((f.ml (2 3) (4 3))
3976 (verbatim foo
3977 (Warnings
3978 "File \"f.ml\", line 2, character 3 to line 4, character 3:\
3979 \nVerbatims should be indented at the opening `{`.")))))
3980 (warnings ()))
3981 |}]
3982
3983 let multiline_without_newline =
3984 test {|
3985 {v foo
3986 v}|};
3987 [%expect
3988 {| ((output (((f.ml (2 3) (3 3)) (verbatim foo)))) (warnings ())) |}]
3989
3990 let everything_is_wrong =
3991 test {|
3992 {[ foo
3993 bar ]}|};
3994 [%expect
3995 {|
3996 ((output
3997 (((f.ml (2 3) (3 8))
3998 (code_block ((f.ml (2 5) (3 6)) " foo\
3999 \nbar ")
4000 (Warnings
4001 "File \"f.ml\", line 2, character 3 to line 3, character 8:\
4002 \nCode blocks should be indented at the opening `{`.")))))
4003 (warnings ()))
4004 |}]
4005
4006 let all_good_multiline =
4007 test {|
4008 {v
4009 foo
4010 v}|};
4011 [%expect
4012 {| ((output (((f.ml (2 3) (4 3)) (verbatim foo)))) (warnings ())) |}]
4013
4014 let all_good_single_line =
4015 test {| {v foo v} |};
4016 [%expect
4017 {| ((output (((f.ml (1 1) (1 10)) (verbatim foo)))) (warnings ())) |}]
4018
4019 (** Let's now test that the correct amount of whitespace is removed. *)
4020
4021 let descending_stair =
4022 test {|
4023 {v
4024 foo
4025 bar
4026 baz
4027 v}|};
4028 [%expect
4029 {|
4030 ((output (((f.ml (2 3) (6 3)) (verbatim "foo\
4031 \n bar\
4032 \n baz"))))
4033 (warnings ()))
4034 |}]
4035
4036 let ascending_stair =
4037 test {|
4038 {v
4039 baz
4040 bar
4041 foo
4042 v}|};
4043 [%expect
4044 {|
4045 ((output (((f.ml (2 3) (6 3)) (verbatim " baz\
4046 \n bar\
4047 \nfoo"))))
4048 (warnings ()))
4049 |}]
4050
4051 let indented_after_opening_fence =
4052 test {|
4053 {v
4054 baz
4055 bar
4056 foo
4057 v}|};
4058 [%expect
4059 {|
4060 ((output (((f.ml (2 3) (6 3)) (verbatim " baz\
4061 \n bar\
4062 \n foo"))))
4063 (warnings ()))
4064 |}]
4065
4066 let indentation_warning_case =
4067 test {|
4068 {v
4069 baz
4070 bar
4071 foo
4072 v}|};
4073 [%expect
4074 {|
4075 ((output
4076 (((f.ml (2 3) (6 3))
4077 (verbatim " baz\
4078 \nbar\
4079 \n foo"
4080 (Warnings
4081 "File \"f.ml\", line 2, character 3 to line 6, character 3:\
4082 \nVerbatims should be indented at the opening `{`.")))))
4083 (warnings ()))
4084 |}]
4085 end in
4086 ()
4087
4088let%expect_test _ =
4089 let module Shorthand_list = struct
4090 let basic =
4091 test "- foo";
4092 [%expect
4093 {|
4094 ((output
4095 (((f.ml (1 0) (1 5))
4096 (unordered light
4097 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))))
4098 (warnings ())) |}]
4099
4100 let multiple_items =
4101 test "- foo\n- bar";
4102 [%expect
4103 {|
4104 ((output
4105 (((f.ml (1 0) (2 5))
4106 (unordered light
4107 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo))))))
4108 (((f.ml (2 2) (2 5)) (paragraph (((f.ml (2 2) (2 5)) (word bar)))))))))))
4109 (warnings ())) |}]
4110
4111 let two_lists =
4112 test "- foo\n\n- bar";
4113 [%expect
4114 {|
4115 ((output
4116 (((f.ml (1 0) (1 5))
4117 (unordered light
4118 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))
4119 ((f.ml (3 0) (3 5))
4120 (unordered light
4121 ((((f.ml (3 2) (3 5)) (paragraph (((f.ml (3 2) (3 5)) (word bar)))))))))))
4122 (warnings ())) |}]
4123
4124 let ordered =
4125 test "+ foo";
4126 [%expect
4127 {|
4128 ((output
4129 (((f.ml (1 0) (1 5))
4130 (ordered light
4131 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))))
4132 (warnings ())) |}]
4133
4134 let leading_whitespace =
4135 test "- foo";
4136 [%expect
4137 {|
4138 ((output
4139 (((f.ml (1 0) (1 5))
4140 (unordered light
4141 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))))
4142 (warnings ())) |}]
4143
4144 let trailing_whitespace =
4145 test "- foo";
4146 [%expect
4147 {|
4148 ((output
4149 (((f.ml (1 0) (1 5))
4150 (unordered light
4151 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))))
4152 (warnings ())) |}]
4153
4154 let bullet_in_line =
4155 test "- foo - bar";
4156 [%expect
4157 {|
4158 ((output
4159 (((f.ml (1 0) (1 11))
4160 (unordered light
4161 ((((f.ml (1 2) (1 11))
4162 (paragraph
4163 (((f.ml (1 2) (1 5)) (word foo)) ((f.ml (1 5) (1 6)) space)
4164 ((f.ml (1 6) (1 7)) (word -)) ((f.ml (1 7) (1 8)) space)
4165 ((f.ml (1 8) (1 11)) (word bar)))))))))))
4166 (warnings ())) |}]
4167
4168 let bullet_in_line_immediately =
4169 test "- - foo";
4170 [%expect
4171 {|
4172 ((output
4173 (((f.ml (1 0) (1 7))
4174 (unordered light
4175 (()
4176 (((f.ml (1 4) (1 7)) (paragraph (((f.ml (1 4) (1 7)) (word foo)))))))))))
4177 (warnings
4178 ( "File \"f.ml\", line 1, characters 2-3:\
4179 \n'-' (bulleted list item) should begin on its own line."
4180 "File \"f.ml\", line 1, characters 0-1:\
4181 \n'-' (bulleted list item) should not be empty."))) |}]
4182
4183 let code_block =
4184 test "- {[foo]}";
4185 [%expect
4186 {|
4187 ((output
4188 (((f.ml (1 0) (1 9))
4189 (unordered light
4190 ((((f.ml (1 2) (1 9)) (code_block ((f.ml (1 4) (1 7)) foo)))))))))
4191 (warnings ())) |}]
4192
4193 let verbatim =
4194 test "- {v foo v}";
4195 [%expect
4196 {|
4197 ((output
4198 (((f.ml (1 0) (1 11))
4199 (unordered light ((((f.ml (1 2) (1 11)) (verbatim foo))))))))
4200 (warnings ())) |}]
4201
4202 let multiple_blocks =
4203 test "- foo\n{[bar]}";
4204 [%expect
4205 {|
4206 ((output
4207 (((f.ml (1 0) (2 7))
4208 (unordered light
4209 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))
4210 ((f.ml (2 0) (2 7)) (code_block ((f.ml (2 2) (2 5)) bar)))))))))
4211 (warnings ())) |}]
4212
4213 let followed_by_code_block =
4214 test "- foo\n\n{[bar]}";
4215 [%expect
4216 {|
4217 ((output
4218 (((f.ml (1 0) (1 5))
4219 (unordered light
4220 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))
4221 ((f.ml (3 0) (3 7)) (code_block ((f.ml (3 2) (3 5)) bar)))))
4222 (warnings ())) |}]
4223
4224 let different_kinds =
4225 test "- foo\n+ bar";
4226 [%expect
4227 {|
4228 ((output
4229 (((f.ml (1 0) (1 5))
4230 (unordered light
4231 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))
4232 ((f.ml (2 0) (2 5))
4233 (ordered light
4234 ((((f.ml (2 2) (2 5)) (paragraph (((f.ml (2 2) (2 5)) (word bar)))))))))))
4235 (warnings ())) |}]
4236
4237 let no_content =
4238 test "-";
4239 [%expect
4240 {|
4241 ((output (((f.ml (1 0) (1 1)) (unordered light (())))))
4242 (warnings
4243 ( "File \"f.ml\", line 1, characters 0-1:\
4244 \n'-' (bulleted list item) should not be empty."))) |}]
4245
4246 let immediate_newline =
4247 test "-\nfoo";
4248 [%expect
4249 {|
4250 ((output
4251 (((f.ml (1 0) (2 3))
4252 (unordered light
4253 ((((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))))))
4254 (warnings ())) |}]
4255
4256 let immediate_blank_line =
4257 test "-\n\nfoo";
4258 [%expect
4259 {|
4260 ((output
4261 (((f.ml (1 0) (1 1)) (unordered light (())))
4262 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word foo)))))))
4263 (warnings
4264 ( "File \"f.ml\", line 1, characters 0-1:\
4265 \n'-' (bulleted list item) should not be empty."))) |}]
4266
4267 let immediate_markup =
4268 test "-{b foo}";
4269 [%expect
4270 {|
4271 ((output
4272 (((f.ml (1 0) (1 8))
4273 (unordered light
4274 ((((f.ml (1 1) (1 8))
4275 (paragraph
4276 (((f.ml (1 1) (1 8)) (bold (((f.ml (1 4) (1 7)) (word foo))))))))))))))
4277 (warnings ())) |}]
4278
4279 let after_code_block =
4280 test "{[foo]} - bar";
4281 [%expect
4282 {|
4283 ((output
4284 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
4285 ((f.ml (1 8) (1 13))
4286 (unordered light
4287 ((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word bar)))))))))))
4288 (warnings
4289 ( "File \"f.ml\", line 1, characters 8-9:\
4290 \n'-' (bulleted list item) should begin on its own line."))) |}]
4291 end in
4292 ()
4293
4294let%expect_test _ =
4295 let module Explicit_list = struct
4296 let basic =
4297 test "{ul {li foo}}";
4298 [%expect
4299 {|
4300 ((output
4301 (((f.ml (1 0) (1 13))
4302 (unordered heavy
4303 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))))))
4304 (warnings ())) |}]
4305
4306 let ordered =
4307 test "{ol {li foo}}";
4308 [%expect
4309 {|
4310 ((output
4311 (((f.ml (1 0) (1 13))
4312 (ordered heavy
4313 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))))))
4314 (warnings ())) |}]
4315
4316 let two_items =
4317 test "{ul {li foo} {li bar}}";
4318 [%expect
4319 {|
4320 ((output
4321 (((f.ml (1 0) (1 22))
4322 (unordered heavy
4323 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo))))))
4324 (((f.ml (1 17) (1 20)) (paragraph (((f.ml (1 17) (1 20)) (word bar)))))))))))
4325 (warnings ())) |}]
4326
4327 let items_on_separate_lines =
4328 test "{ul {li foo}\n{li bar}}";
4329 [%expect
4330 {|
4331 ((output
4332 (((f.ml (1 0) (2 9))
4333 (unordered heavy
4334 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo))))))
4335 (((f.ml (2 4) (2 7)) (paragraph (((f.ml (2 4) (2 7)) (word bar)))))))))))
4336 (warnings ())) |}]
4337
4338 let blank_line =
4339 test "{ul {li foo}\n\n{li bar}}";
4340 [%expect
4341 {|
4342 ((output
4343 (((f.ml (1 0) (3 9))
4344 (unordered heavy
4345 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo))))))
4346 (((f.ml (3 4) (3 7)) (paragraph (((f.ml (3 4) (3 7)) (word bar)))))))))))
4347 (warnings ())) |}]
4348
4349 let blank_line_in_item =
4350 test "{ul {li foo\n\nbar}}";
4351 [%expect
4352 {|
4353 ((output
4354 (((f.ml (1 0) (3 5))
4355 (unordered heavy
4356 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))
4357 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))))))
4358 (warnings ())) |}]
4359
4360 let junk =
4361 test "{ul foo}";
4362 [%expect
4363 {|
4364 ((output (((f.ml (1 0) (1 8)) (unordered heavy ()))))
4365 (warnings
4366 ( "File \"f.ml\", line 1, characters 4-7:\
4367 \n'foo' is not allowed in '{ul ...}' (bulleted list).\
4368 \nSuggestion: move 'foo' into a list item, '{li ...}' or '{- ...}'."
4369 "File \"f.ml\", line 1, characters 0-3:\
4370 \n'{ul ...}' (bulleted list) should not be empty."))) |}]
4371
4372 let junk_with_no_whitespace =
4373 test "{ulfoo}";
4374 [%expect
4375 {|
4376 ((output (((f.ml (1 0) (1 7)) (unordered heavy ()))))
4377 (warnings
4378 ( "File \"f.ml\", line 1, characters 3-6:\
4379 \n'foo' is not allowed in '{ul ...}' (bulleted list).\
4380 \nSuggestion: move 'foo' into a list item, '{li ...}' or '{- ...}'."
4381 "File \"f.ml\", line 1, characters 0-3:\
4382 \n'{ul ...}' (bulleted list) should not be empty."))) |}]
4383
4384 let empty =
4385 test "{ul}";
4386 [%expect
4387 {|
4388 ((output (((f.ml (1 0) (1 4)) (unordered heavy ()))))
4389 (warnings
4390 ( "File \"f.ml\", line 1, characters 0-3:\
4391 \n'{ul ...}' (bulleted list) should not be empty."))) |}]
4392
4393 let unterminated_list =
4394 test "{ul";
4395 [%expect
4396 {|
4397 ((output (((f.ml (1 0) (1 3)) (unordered heavy ()))))
4398 (warnings
4399 ( "File \"f.ml\", line 1, characters 3-3:\
4400 \nEnd of text is not allowed in '{ul ...}' (bulleted list).\
4401 \nSuggestion: add '}'."
4402 "File \"f.ml\", line 1, characters 0-3:\
4403 \n'{ul ...}' (bulleted list) should not be empty."))) |}]
4404
4405 let no_whitespace =
4406 test "{ul{li foo}}";
4407 [%expect
4408 {|
4409 ((output
4410 (((f.ml (1 0) (1 12))
4411 (unordered heavy
4412 ((((f.ml (1 7) (1 10)) (paragraph (((f.ml (1 7) (1 10)) (word foo)))))))))))
4413 (warnings ())) |}]
4414
4415 let whitespace_at_end_of_item =
4416 test "{ul {li foo\n\n\n}}";
4417 [%expect
4418 {|
4419 ((output
4420 (((f.ml (1 0) (4 2))
4421 (unordered heavy
4422 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))))))
4423 (warnings ())) |}]
4424
4425 let unterminated_li_syntax =
4426 test "{ul {li foo";
4427 [%expect
4428 {|
4429 ((output
4430 (((f.ml (1 0) (1 11))
4431 (unordered heavy
4432 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))))))
4433 (warnings
4434 ( "File \"f.ml\", line 1, characters 11-11:\
4435 \nEnd of text is not allowed in '{li ...}' (list item).\
4436 \nSuggestion: add '}'."
4437 "File \"f.ml\", line 1, characters 11-11:\
4438 \nEnd of text is not allowed in '{ul ...}' (bulleted list).\
4439 \nSuggestion: add '}'."))) |}]
4440
4441 let unterminated_left_curly_brace =
4442 test "{ul {- foo";
4443 [%expect
4444 {|
4445 ((output
4446 (((f.ml (1 0) (1 10))
4447 (unordered heavy
4448 ((((f.ml (1 7) (1 10)) (paragraph (((f.ml (1 7) (1 10)) (word foo)))))))))))
4449 (warnings
4450 ( "File \"f.ml\", line 1, characters 10-10:\
4451 \nEnd of text is not allowed in '{- ...}' (list item).\
4452 \nSuggestion: add '}'."
4453 "File \"f.ml\", line 1, characters 10-10:\
4454 \nEnd of text is not allowed in '{ul ...}' (bulleted list).\
4455 \nSuggestion: add '}'."))) |}]
4456
4457 let empty_li_styntax =
4458 test "{ul {li }}";
4459 [%expect
4460 {|
4461 ((output (((f.ml (1 0) (1 10)) (unordered heavy (())))))
4462 (warnings
4463 ( "File \"f.ml\", line 1, characters 4-7:\
4464 \n'{li ...}' (list item) should not be empty."))) |}]
4465
4466 let empty_left_curly_brace =
4467 test "{ul {- }}";
4468 [%expect
4469 {|
4470 ((output (((f.ml (1 0) (1 9)) (unordered heavy (())))))
4471 (warnings
4472 ( "File \"f.ml\", line 1, characters 4-6:\
4473 \n'{- ...}' (list item) should not be empty."))) |}]
4474
4475 let li_syntax_without_whitespace =
4476 test "{ul {lifoo}}";
4477 [%expect
4478 {|
4479 ((output
4480 (((f.ml (1 0) (1 12))
4481 (unordered heavy
4482 ((((f.ml (1 7) (1 10)) (paragraph (((f.ml (1 7) (1 10)) (word foo)))))))))))
4483 (warnings
4484 ( "File \"f.ml\", line 1, characters 4-7:\
4485 \n'{li ...}' should be followed by space, a tab, or a new line."))) |}]
4486
4487 let li_syntax_followed_by_newline =
4488 test "{ul {li\nfoo}}";
4489 [%expect
4490 {|
4491 ((output
4492 (((f.ml (1 0) (2 5))
4493 (unordered heavy
4494 ((((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))))))
4495 (warnings ())) |}]
4496
4497 let li_syntax_followed_by_cr_lf =
4498 test "{ul {li\r\nfoo}}";
4499 [%expect
4500 {|
4501 ((output
4502 (((f.ml (1 0) (2 5))
4503 (unordered heavy
4504 ((((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))))))
4505 (warnings ())) |}]
4506
4507 let li_syntax_followed_by_blank_line =
4508 test "{ul {li\n\nfoo}}";
4509 [%expect
4510 {|
4511 ((output
4512 (((f.ml (1 0) (3 5))
4513 (unordered heavy
4514 ((((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word foo)))))))))))
4515 (warnings ())) |}]
4516
4517 let left_curly_brace_without_whitespace =
4518 test "{ul {-foo}}";
4519 [%expect
4520 {|
4521 ((output
4522 (((f.ml (1 0) (1 11))
4523 (unordered heavy
4524 ((((f.ml (1 6) (1 9)) (paragraph (((f.ml (1 6) (1 9)) (word foo)))))))))))
4525 (warnings ())) |}]
4526
4527 let mixed_list_items =
4528 test "{ul {li foo} {- bar}}";
4529 [%expect
4530 {|
4531 ((output
4532 (((f.ml (1 0) (1 21))
4533 (unordered heavy
4534 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo))))))
4535 (((f.ml (1 16) (1 19)) (paragraph (((f.ml (1 16) (1 19)) (word bar)))))))))))
4536 (warnings ())) |}]
4537
4538 let nested =
4539 test "{ul {li {ul {li foo}}}}";
4540 [%expect
4541 {|
4542 ((output
4543 (((f.ml (1 0) (1 23))
4544 (unordered heavy
4545 ((((f.ml (1 8) (1 21))
4546 (unordered heavy
4547 ((((f.ml (1 16) (1 19))
4548 (paragraph (((f.ml (1 16) (1 19)) (word foo)))))))))))))))
4549 (warnings ())) |}]
4550
4551 let shorthand_in_explicit =
4552 test "{ul {li - foo\n- bar}}";
4553 [%expect
4554 {|
4555 ((output
4556 (((f.ml (1 0) (2 7))
4557 (unordered heavy
4558 ((((f.ml (1 8) (2 5))
4559 (unordered light
4560 ((((f.ml (1 10) (1 13))
4561 (paragraph (((f.ml (1 10) (1 13)) (word foo))))))
4562 (((f.ml (2 2) (2 5)) (paragraph (((f.ml (2 2) (2 5)) (word bar)))))))))))))))
4563 (warnings ())) |}]
4564
4565 let explicit_in_shorthand =
4566 test "- {ul {li foo}}";
4567 [%expect
4568 {|
4569 ((output
4570 (((f.ml (1 0) (1 15))
4571 (unordered light
4572 ((((f.ml (1 2) (1 15))
4573 (unordered heavy
4574 ((((f.ml (1 10) (1 13))
4575 (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))))))
4576 (warnings ())) |}]
4577
4578 let bare_li_syntax =
4579 test "{li foo}";
4580 [%expect
4581 {|
4582 ((output
4583 (((f.ml (1 4) (1 7)) (paragraph (((f.ml (1 4) (1 7)) (word foo)))))
4584 ((f.ml (1 7) (1 8)) (paragraph (((f.ml (1 7) (1 8)) (word })))))))
4585 (warnings
4586 ( "File \"f.ml\", line 1, characters 0-3:\
4587 \n'{li ...}' (list item) is not allowed in top-level text.\
4588 \nSuggestion: move '{li ...}' into '{ul ...}' (bulleted list), or use '-' (bulleted list item)."
4589 "File \"f.ml\", line 1, characters 7-8:\
4590 \nUnpaired '}' (end of markup).\
4591 \nSuggestion: try '\\}'."))) |}]
4592
4593 let bare_left_curly_brace =
4594 test "{- foo";
4595 [%expect
4596 {|
4597 ((output
4598 (((f.ml (1 3) (1 6)) (paragraph (((f.ml (1 3) (1 6)) (word foo)))))))
4599 (warnings
4600 ( "File \"f.ml\", line 1, characters 0-2:\
4601 \n'{- ...}' (list item) is not allowed in top-level text.\
4602 \nSuggestion: move '{- ...}' into '{ul ...}' (bulleted list), or use '-' (bulleted list item)."))) |}]
4603
4604 let after_code_block =
4605 test "{[foo]} {ul {li bar}}";
4606 [%expect
4607 {|
4608 ((output
4609 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
4610 ((f.ml (1 8) (1 21))
4611 (unordered heavy
4612 ((((f.ml (1 16) (1 19)) (paragraph (((f.ml (1 16) (1 19)) (word bar)))))))))))
4613 (warnings
4614 ( "File \"f.ml\", line 1, characters 8-11:\
4615 \n'{ul ...}' (bulleted list) should begin on its own line."))) |}]
4616 end in
4617 ()
4618
4619let%expect_test _ =
4620 let module Deprecated = struct
4621 let basic =
4622 test "@deprecated";
4623 [%expect
4624 {| ((output (((f.ml (1 0) (1 11)) (@deprecated)))) (warnings ())) |}]
4625
4626 let words =
4627 test "@deprecated foo bar";
4628 [%expect
4629 {|
4630 ((output
4631 (((f.ml (1 0) (1 19))
4632 (@deprecated
4633 ((f.ml (1 12) (1 19))
4634 (paragraph
4635 (((f.ml (1 12) (1 15)) (word foo)) ((f.ml (1 15) (1 16)) space)
4636 ((f.ml (1 16) (1 19)) (word bar)))))))))
4637 (warnings ())) |}]
4638
4639 let multiline =
4640 test "@deprecated foo\nbar";
4641 [%expect
4642 {|
4643 ((output
4644 (((f.ml (1 0) (2 3))
4645 (@deprecated
4646 ((f.ml (1 12) (2 3))
4647 (paragraph
4648 (((f.ml (1 12) (1 15)) (word foo)) ((f.ml (1 15) (2 0)) space)
4649 ((f.ml (2 0) (2 3)) (word bar)))))))))
4650 (warnings ())) |}]
4651
4652 let paragraphs =
4653 test "@deprecated foo\n\nbar";
4654 [%expect
4655 {|
4656 ((output
4657 (((f.ml (1 0) (1 15))
4658 (@deprecated
4659 ((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))))
4660 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word bar)))))))
4661 (warnings ())) |}]
4662
4663 let whitespace_only =
4664 test "@deprecated";
4665 [%expect
4666 {| ((output (((f.ml (1 0) (1 11)) (@deprecated)))) (warnings ())) |}]
4667
4668 let immediate_newline =
4669 test "@deprecated\nfoo";
4670 [%expect
4671 {|
4672 ((output
4673 (((f.ml (1 0) (2 3))
4674 (@deprecated
4675 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))))
4676 (warnings ())) |}]
4677
4678 let immediate_cr_lf =
4679 test "@deprecated\r\nfoo";
4680 [%expect
4681 {|
4682 ((output
4683 (((f.ml (1 0) (2 3))
4684 (@deprecated
4685 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))))
4686 (warnings ())) |}]
4687
4688 let immediate_blank_line =
4689 test "@deprecated\n\nfoo";
4690 [%expect
4691 {|
4692 ((output
4693 (((f.ml (1 0) (1 11)) (@deprecated))
4694 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word foo)))))))
4695 (warnings ())) |}]
4696
4697 let extra_whitespace =
4698 test "@deprecated foo";
4699 [%expect
4700 {|
4701 ((output
4702 (((f.ml (1 0) (1 16))
4703 (@deprecated
4704 ((f.ml (1 13) (1 16)) (paragraph (((f.ml (1 13) (1 16)) (word foo)))))))))
4705 (warnings ())) |}]
4706
4707 let followed_by_deprecated =
4708 test "@deprecated foo\n@deprecated bar";
4709 [%expect
4710 {|
4711 ((output
4712 (((f.ml (1 0) (1 15))
4713 (@deprecated
4714 ((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))))
4715 ((f.ml (2 0) (2 15))
4716 (@deprecated
4717 ((f.ml (2 12) (2 15)) (paragraph (((f.ml (2 12) (2 15)) (word bar)))))))))
4718 (warnings ())) |}]
4719
4720 let followed_by_deprecated_cr_lf =
4721 test "@deprecated foo\r\n@deprecated bar";
4722 [%expect
4723 {|
4724 ((output
4725 (((f.ml (1 0) (1 15))
4726 (@deprecated
4727 ((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))))
4728 ((f.ml (2 0) (2 15))
4729 (@deprecated
4730 ((f.ml (2 12) (2 15)) (paragraph (((f.ml (2 12) (2 15)) (word bar)))))))))
4731 (warnings ())) |}]
4732
4733 let nested_in_self =
4734 test "@deprecated foo @deprecated bar";
4735 [%expect
4736 {|
4737 ((output
4738 (((f.ml (1 0) (1 31))
4739 (@deprecated
4740 ((f.ml (1 12) (1 16))
4741 (paragraph
4742 (((f.ml (1 12) (1 15)) (word foo)) ((f.ml (1 15) (1 16)) space))))
4743 ((f.ml (1 16) (1 27))
4744 (paragraph (((f.ml (1 16) (1 27)) (word @deprecated)))))
4745 ((f.ml (1 28) (1 31)) (paragraph (((f.ml (1 28) (1 31)) (word bar)))))))))
4746 (warnings
4747 ( "File \"f.ml\", line 1, characters 16-27:\
4748 \n'@deprecated' is not allowed in '@deprecated'.\
4749 \nSuggestion: move '@deprecated' outside of any other markup."))) |}]
4750
4751 let nested_in_self_at_start =
4752 test "@deprecated @deprecated foo";
4753 [%expect
4754 {|
4755 ((output
4756 (((f.ml (1 0) (1 27))
4757 (@deprecated
4758 ((f.ml (1 12) (1 23))
4759 (paragraph (((f.ml (1 12) (1 23)) (word @deprecated)))))
4760 ((f.ml (1 24) (1 27)) (paragraph (((f.ml (1 24) (1 27)) (word foo)))))))))
4761 (warnings
4762 ( "File \"f.ml\", line 1, characters 12-23:\
4763 \n'@deprecated' is not allowed in '@deprecated'.\
4764 \nSuggestion: move '@deprecated' outside of any other markup."))) |}]
4765
4766 let preceded_by_paragraph =
4767 test "foo\n@deprecated";
4768 [%expect
4769 {|
4770 ((output
4771 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
4772 ((f.ml (2 0) (2 11)) (@deprecated))))
4773 (warnings ())) |}]
4774
4775 let preceded_by_shorthand_list =
4776 test "- foo\n@deprecated";
4777 [%expect
4778 {|
4779 ((output
4780 (((f.ml (1 0) (1 5))
4781 (unordered light
4782 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))
4783 ((f.ml (2 0) (2 11)) (@deprecated))))
4784 (warnings ())) |}]
4785
4786 let with_shorthand_list =
4787 test "@deprecated - foo";
4788 [%expect
4789 {|
4790 ((output
4791 (((f.ml (1 0) (1 17))
4792 (@deprecated
4793 ((f.ml (1 12) (1 17))
4794 (unordered light
4795 ((((f.ml (1 14) (1 17))
4796 (paragraph (((f.ml (1 14) (1 17)) (word foo)))))))))))))
4797 (warnings ())) |}]
4798
4799 let with_shorthand_list_double_item =
4800 test "@deprecated - foo\n- bar";
4801 [%expect
4802 {|
4803 ((output
4804 (((f.ml (1 0) (2 5))
4805 (@deprecated
4806 ((f.ml (1 12) (2 5))
4807 (unordered light
4808 ((((f.ml (1 14) (1 17))
4809 (paragraph (((f.ml (1 14) (1 17)) (word foo))))))
4810 (((f.ml (2 2) (2 5)) (paragraph (((f.ml (2 2) (2 5)) (word bar)))))))))))))
4811 (warnings ())) |}]
4812
4813 let double_implicitly_ended =
4814 test "@deprecated - foo\n- bar\n\nNew paragraph";
4815 [%expect
4816 {|
4817 ((output
4818 (((f.ml (1 0) (2 5))
4819 (@deprecated
4820 ((f.ml (1 12) (2 5))
4821 (unordered light
4822 ((((f.ml (1 14) (1 17))
4823 (paragraph (((f.ml (1 14) (1 17)) (word foo))))))
4824 (((f.ml (2 2) (2 5)) (paragraph (((f.ml (2 2) (2 5)) (word bar)))))))))))
4825 ((f.ml (4 0) (4 13))
4826 (paragraph
4827 (((f.ml (4 0) (4 3)) (word New)) ((f.ml (4 3) (4 4)) space)
4828 ((f.ml (4 4) (4 13)) (word paragraph)))))))
4829 (warnings ())) |}]
4830
4831 let with_shorthand_list_after_newline =
4832 test "@deprecated\n- foo";
4833 [%expect
4834 {|
4835 ((output
4836 (((f.ml (1 0) (2 5))
4837 (@deprecated
4838 ((f.ml (2 0) (2 5))
4839 (unordered light
4840 ((((f.ml (2 2) (2 5)) (paragraph (((f.ml (2 2) (2 5)) (word foo)))))))))))))
4841 (warnings ())) |}]
4842
4843 let prefix =
4844 test "@deprecatedfoo";
4845 [%expect
4846 {| ((output (((f.ml (1 0) (1 14)) (@custom deprecatedfoo)))) (warnings ())) |}]
4847
4848 let after_code_block =
4849 test "{[foo]} @deprecated";
4850 [%expect
4851 {|
4852 ((output
4853 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
4854 ((f.ml (1 8) (1 19)) (@deprecated))))
4855 (warnings
4856 ( "File \"f.ml\", line 1, characters 8-19:\
4857 \n'@deprecated' should begin on its own line."))) |}]
4858
4859 let followed_by_section =
4860 test "@deprecated foo\n{2 Bar}";
4861 [%expect
4862 {|
4863 ((output
4864 (((f.ml (1 0) (1 15))
4865 (@deprecated
4866 ((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word foo)))))))
4867 ((f.ml (2 0) (2 7)) (2 (label ()) (((f.ml (2 3) (2 6)) (word Bar)))))))
4868 (warnings ())) |}]
4869 end in
4870 ()
4871
4872let%expect_test _ =
4873 let module Param = struct
4874 let basic =
4875 test "@param foo";
4876 [%expect
4877 {| ((output (((f.ml (1 0) (1 10)) (@param foo)))) (warnings ())) |}]
4878
4879 let bare =
4880 test "@param";
4881 [%expect
4882 {|
4883 ((output (((f.ml (1 0) (1 6)) (@param ""))))
4884 (warnings
4885 ( "File \"f.ml\", line 1, characters 0-6:\
4886 \n'@param' expects parameter name on the same line."))) |}]
4887
4888 let bare_with_whitespace =
4889 test "@param";
4890 [%expect
4891 {|
4892 ((output (((f.ml (1 0) (1 6)) (@param ""))))
4893 (warnings
4894 ( "File \"f.ml\", line 1, characters 0-6:\
4895 \n'@param' expects parameter name on the same line."))) |}]
4896
4897 let immediate_newline =
4898 test "@param\nfoo";
4899 [%expect
4900 {|
4901 ((output
4902 (((f.ml (1 0) (2 3))
4903 (@param ""
4904 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))))
4905 (warnings
4906 ( "File \"f.ml\", line 1, characters 0-6:\
4907 \n'@param' expects parameter name on the same line."))) |}]
4908
4909 let followed_by_whitespace =
4910 test "@param foo";
4911 [%expect
4912 {| ((output (((f.ml (1 0) (1 10)) (@param foo)))) (warnings ())) |}]
4913
4914 let extra_whitespace =
4915 test "@param foo";
4916 [%expect
4917 {| ((output (((f.ml (1 0) (1 11)) (@param foo)))) (warnings ())) |}]
4918
4919 let words =
4920 test "@param foo bar baz";
4921 [%expect
4922 {|
4923 ((output
4924 (((f.ml (1 0) (1 18))
4925 (@param foo
4926 ((f.ml (1 11) (1 18))
4927 (paragraph
4928 (((f.ml (1 11) (1 14)) (word bar)) ((f.ml (1 14) (1 15)) space)
4929 ((f.ml (1 15) (1 18)) (word baz)))))))))
4930 (warnings ())) |}]
4931
4932 let multiline =
4933 test "@param foo\nbar\nbaz";
4934 [%expect
4935 {|
4936 ((output
4937 (((f.ml (1 0) (3 3))
4938 (@param foo
4939 ((f.ml (2 0) (3 3))
4940 (paragraph
4941 (((f.ml (2 0) (2 3)) (word bar)) ((f.ml (2 3) (3 0)) space)
4942 ((f.ml (3 0) (3 3)) (word baz)))))))))
4943 (warnings ())) |}]
4944
4945 let paragraphs =
4946 test "@param foo bar\n\nbaz";
4947 [%expect
4948 {|
4949 ((output
4950 (((f.ml (1 0) (1 14))
4951 (@param foo
4952 ((f.ml (1 11) (1 14)) (paragraph (((f.ml (1 11) (1 14)) (word bar)))))))
4953 ((f.ml (3 0) (3 3)) (paragraph (((f.ml (3 0) (3 3)) (word baz)))))))
4954 (warnings ())) |}]
4955
4956 let two =
4957 test "@param foo\n@param bar";
4958 [%expect
4959 {|
4960 ((output
4961 (((f.ml (1 0) (1 10)) (@param foo)) ((f.ml (2 0) (2 10)) (@param bar))))
4962 (warnings ())) |}]
4963
4964 let nested =
4965 test "@param foo @param bar";
4966 [%expect
4967 {|
4968 ((output
4969 (((f.ml (1 0) (1 21))
4970 (@param foo
4971 ((f.ml (1 11) (1 21))
4972 (paragraph
4973 (((f.ml (1 11) (1 21)) (word @param)) ((f.ml (1 11) (1 21)) space)
4974 ((f.ml (1 11) (1 21)) (word bar)))))))))
4975 (warnings
4976 ( "File \"f.ml\", line 1, characters 11-21:\
4977 \n'@param' is not allowed in '@param'.\
4978 \nSuggestion: move '@param' outside of any other markup."))) |}]
4979
4980 let preceded_by_paragraph =
4981 test "foo\n@param bar";
4982 [%expect
4983 {|
4984 ((output
4985 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
4986 ((f.ml (2 0) (2 10)) (@param bar))))
4987 (warnings ())) |}]
4988
4989 let prefix =
4990 test "@paramfoo";
4991 [%expect
4992 {| ((output (((f.ml (1 0) (1 9)) (@custom paramfoo)))) (warnings ())) |}]
4993
4994 let after_code_block =
4995 test "{[foo]} @param foo";
4996 [%expect
4997 {|
4998 ((output
4999 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
5000 ((f.ml (1 8) (1 18)) (@param foo))))
5001 (warnings
5002 ( "File \"f.ml\", line 1, characters 8-18:\
5003 \n'@param' should begin on its own line."))) |}]
5004 end in
5005 ()
5006
5007let%expect_test _ =
5008 let module Raise = struct
5009 let basic =
5010 test "@raise Foo";
5011 [%expect
5012 {| ((output (((f.ml (1 0) (1 10)) (@raise Foo)))) (warnings ())) |}]
5013
5014 let bare =
5015 test "@raise";
5016 [%expect
5017 {|
5018 ((output (((f.ml (1 0) (1 6)) (@raise ""))))
5019 (warnings
5020 ( "File \"f.ml\", line 1, characters 0-6:\
5021 \n'@raise' expects exception constructor on the same line."))) |}]
5022
5023 let words =
5024 test "@raise foo bar baz";
5025 [%expect
5026 {|
5027 ((output
5028 (((f.ml (1 0) (1 18))
5029 (@raise foo
5030 ((f.ml (1 11) (1 18))
5031 (paragraph
5032 (((f.ml (1 11) (1 14)) (word bar)) ((f.ml (1 14) (1 15)) space)
5033 ((f.ml (1 15) (1 18)) (word baz)))))))))
5034 (warnings ())) |}]
5035
5036 let prefix =
5037 test "@raisefoo";
5038 [%expect
5039 {| ((output (((f.ml (1 0) (1 9)) (@custom raisefoo)))) (warnings ())) |}]
5040 end in
5041 ()
5042
5043let%expect_test _ =
5044 let module Return = struct
5045 let basic =
5046 test "@return";
5047 [%expect {| ((output (((f.ml (1 0) (1 7)) (@return)))) (warnings ())) |}]
5048
5049 let words =
5050 test "@return foo bar";
5051 [%expect
5052 {|
5053 ((output
5054 (((f.ml (1 0) (1 15))
5055 (@return
5056 ((f.ml (1 8) (1 15))
5057 (paragraph
5058 (((f.ml (1 8) (1 11)) (word foo)) ((f.ml (1 11) (1 12)) space)
5059 ((f.ml (1 12) (1 15)) (word bar)))))))))
5060 (warnings ())) |}]
5061
5062 let prefix =
5063 test "@returnfoo";
5064 [%expect
5065 {| ((output (((f.ml (1 0) (1 10)) (@custom returnfoo)))) (warnings ())) |}]
5066 end in
5067 ()
5068
5069let%expect_test _ =
5070 let module See = struct
5071 let url =
5072 test "@see <foo>";
5073 [%expect
5074 {| ((output (((f.ml (1 0) (1 10)) (@see url foo)))) (warnings ())) |}]
5075
5076 let file =
5077 test "@see 'foo'";
5078 [%expect
5079 {| ((output (((f.ml (1 0) (1 10)) (@see file foo)))) (warnings ())) |}]
5080
5081 let document =
5082 test "@see \"foo\"";
5083 [%expect
5084 {| ((output (((f.ml (1 0) (1 10)) (@see document foo)))) (warnings ())) |}]
5085
5086 let bare =
5087 test "@see";
5088 [%expect
5089 {|
5090 ((output
5091 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (word @see)))))))
5092 (warnings
5093 ( "File \"f.ml\", line 1, characters 0-4:\
5094 \n'@see' should be followed by <url>, 'file', or \"document title\"."))) |}]
5095
5096 let unterminated_url =
5097 test "@see <foo";
5098 [%expect
5099 {|
5100 ((output
5101 (((f.ml (1 0) (1 9))
5102 (paragraph
5103 (((f.ml (1 0) (1 4)) (word @see)) ((f.ml (1 4) (1 5)) space)
5104 ((f.ml (1 5) (1 9)) (word <foo)))))))
5105 (warnings
5106 ( "File \"f.ml\", line 1, characters 0-4:\
5107 \n'@see' should be followed by <url>, 'file', or \"document title\"."))) |}]
5108
5109 let unterminated_file =
5110 test "@see 'foo";
5111 [%expect
5112 {|
5113 ((output
5114 (((f.ml (1 0) (1 9))
5115 (paragraph
5116 (((f.ml (1 0) (1 4)) (word @see)) ((f.ml (1 4) (1 5)) space)
5117 ((f.ml (1 5) (1 9)) (word 'foo)))))))
5118 (warnings
5119 ( "File \"f.ml\", line 1, characters 0-4:\
5120 \n'@see' should be followed by <url>, 'file', or \"document title\"."))) |}]
5121
5122 let unterminated_document =
5123 test "@see foo";
5124 [%expect
5125 {|
5126 ((output
5127 (((f.ml (1 0) (1 8))
5128 (paragraph
5129 (((f.ml (1 0) (1 4)) (word @see)) ((f.ml (1 4) (1 5)) space)
5130 ((f.ml (1 5) (1 8)) (word foo)))))))
5131 (warnings
5132 ( "File \"f.ml\", line 1, characters 0-4:\
5133 \n'@see' should be followed by <url>, 'file', or \"document title\"."))) |}]
5134
5135 let no_space =
5136 test "@see<foo>";
5137 [%expect
5138 {| ((output (((f.ml (1 0) (1 9)) (@see url foo)))) (warnings ())) |}]
5139
5140 let words =
5141 test "@see <foo> bar";
5142 [%expect
5143 {|
5144 ((output
5145 (((f.ml (1 0) (1 14))
5146 (@see url foo
5147 ((f.ml (1 11) (1 14)) (paragraph (((f.ml (1 11) (1 14)) (word bar)))))))))
5148 (warnings ())) |}]
5149
5150 let prefix =
5151 test "@seefoo";
5152 [%expect
5153 {| ((output (((f.ml (1 0) (1 7)) (@custom seefoo)))) (warnings ())) |}]
5154
5155 let after_code_block =
5156 test "{[foo]} @see <foo>";
5157 [%expect
5158 {|
5159 ((output
5160 (((f.ml (1 0) (1 7)) (code_block ((f.ml (1 2) (1 5)) foo)))
5161 ((f.ml (1 8) (1 18)) (@see url foo))))
5162 (warnings
5163 ( "File \"f.ml\", line 1, characters 8-18:\
5164 \n'@see' should begin on its own line."))) |}]
5165
5166 let url_attempted_nested_closer =
5167 test "@see <foo>bar>";
5168 [%expect
5169 {|
5170 ((output
5171 (((f.ml (1 0) (1 14))
5172 (@see url foo
5173 ((f.ml (1 10) (1 14)) (paragraph (((f.ml (1 10) (1 14)) (word bar>)))))))))
5174 (warnings ())) |}]
5175
5176 let file_attempted_nested_closer =
5177 test "@see 'foo'bar'";
5178 [%expect
5179 {|
5180 ((output
5181 (((f.ml (1 0) (1 14))
5182 (@see file foo
5183 ((f.ml (1 10) (1 14)) (paragraph (((f.ml (1 10) (1 14)) (word bar')))))))))
5184 (warnings ())) |}]
5185
5186 let document_attempted_nested_closer =
5187 test "@see \"foo\"bar\"";
5188 [%expect
5189 {|
5190 ((output
5191 (((f.ml (1 0) (1 14))
5192 (@see document foo
5193 ((f.ml (1 10) (1 14))
5194 (paragraph (((f.ml (1 10) (1 14)) (word "bar\"")))))))))
5195 (warnings ())) |}]
5196 end in
5197 ()
5198
5199let%expect_test _ =
5200 let module Since = struct
5201 let basic =
5202 test "@since foo";
5203 [%expect
5204 {| ((output (((f.ml (1 0) (1 10)) (@since foo)))) (warnings ())) |}]
5205
5206 let bare =
5207 test "@since";
5208 [%expect
5209 {|
5210 ((output (((f.ml (1 0) (1 6)) (@since ""))))
5211 (warnings
5212 ( "File \"f.ml\", line 1, characters 0-6:\
5213 \n'@since' should not be empty."))) |}]
5214
5215 let prefix =
5216 test "@sincefoo";
5217 [%expect
5218 {| ((output (((f.ml (1 0) (1 9)) (@custom sincefoo)))) (warnings ())) |}]
5219
5220 let with_whitespace =
5221 test "@since foo bar";
5222 [%expect
5223 {| ((output (((f.ml (1 0) (1 14)) (@since "foo bar")))) (warnings ())) |}]
5224
5225 let leading_whitespace =
5226 test "@since foo";
5227 [%expect
5228 {| ((output (((f.ml (1 0) (1 11)) (@since foo)))) (warnings ())) |}]
5229
5230 let trailing_whitespace =
5231 test "@since foo";
5232 [%expect
5233 {| ((output (((f.ml (1 0) (1 10)) (@since foo)))) (warnings ())) |}]
5234
5235 let whitespace_only =
5236 test "@since";
5237 [%expect
5238 {|
5239 ((output (((f.ml (1 0) (1 6)) (@since ""))))
5240 (warnings
5241 ( "File \"f.ml\", line 1, characters 0-6:\
5242 \n'@since' should not be empty."))) |}]
5243 end in
5244 ()
5245
5246let%expect_test _ =
5247 let module Before = struct
5248 let basic =
5249 test "@before Foo";
5250 [%expect
5251 {| ((output (((f.ml (1 0) (1 11)) (@before Foo)))) (warnings ())) |}]
5252
5253 let bare =
5254 test "@before";
5255 [%expect
5256 {|
5257 ((output (((f.ml (1 0) (1 7)) (@before ""))))
5258 (warnings
5259 ( "File \"f.ml\", line 1, characters 0-7:\
5260 \n'@before' expects version number on the same line."))) |}]
5261
5262 let words =
5263 test "@before foo bar baz";
5264 [%expect
5265 {|
5266 ((output
5267 (((f.ml (1 0) (1 19))
5268 (@before foo
5269 ((f.ml (1 12) (1 19))
5270 (paragraph
5271 (((f.ml (1 12) (1 15)) (word bar)) ((f.ml (1 15) (1 16)) space)
5272 ((f.ml (1 16) (1 19)) (word baz)))))))))
5273 (warnings ())) |}]
5274
5275 let prefix =
5276 test "@beforefoo";
5277 [%expect
5278 {| ((output (((f.ml (1 0) (1 10)) (@custom beforefoo)))) (warnings ())) |}]
5279 end in
5280 ()
5281
5282let%expect_test _ =
5283 let module Version = struct
5284 let basic =
5285 test "@version foo";
5286 [%expect
5287 {| ((output (((f.ml (1 0) (1 12)) (@version foo)))) (warnings ())) |}]
5288
5289 let bare =
5290 test "@version";
5291 [%expect
5292 {|
5293 ((output (((f.ml (1 0) (1 8)) (@version ""))))
5294 (warnings
5295 ( "File \"f.ml\", line 1, characters 0-8:\
5296 \n'@version' should not be empty."))) |}]
5297
5298 let prefix =
5299 test "@versionfoo";
5300 [%expect
5301 {| ((output (((f.ml (1 0) (1 11)) (@custom versionfoo)))) (warnings ())) |}]
5302
5303 let with_whitespace =
5304 test "@version foo bar";
5305 [%expect
5306 {| ((output (((f.ml (1 0) (1 16)) (@version "foo bar")))) (warnings ())) |}]
5307
5308 let leading_whitespace =
5309 test "@version foo";
5310 [%expect
5311 {| ((output (((f.ml (1 0) (1 13)) (@version foo)))) (warnings ())) |}]
5312
5313 let trailing_whitespace =
5314 test "@version foo";
5315 [%expect
5316 {| ((output (((f.ml (1 0) (1 12)) (@version foo)))) (warnings ())) |}]
5317
5318 let whitespace_only =
5319 test "@version";
5320 [%expect
5321 {|
5322 ((output (((f.ml (1 0) (1 8)) (@version ""))))
5323 (warnings
5324 ( "File \"f.ml\", line 1, characters 0-8:\
5325 \n'@version' should not be empty."))) |}]
5326 end in
5327 ()
5328
5329let%expect_test _ =
5330 let module Canonical = struct
5331 let basic =
5332 test "@canonical Foo";
5333 [%expect
5334 {|
5335 ((output (((f.ml (1 0) (1 14)) (@canonical ((f.ml (1 11) (1 14)) Foo)))))
5336 (warnings ())) |}]
5337
5338 let empty =
5339 test "@canonical";
5340 [%expect
5341 {|
5342 ((output (((f.ml (1 0) (1 10)) (@canonical ((f.ml (1 11) (1 10)) "")))))
5343 (warnings
5344 ( "File \"f.ml\", line 1, characters 0-10:\
5345 \n'@canonical' should not be empty."))) |}]
5346
5347 let whitespace_only =
5348 test "@canonical";
5349 [%expect
5350 {|
5351 ((output (((f.ml (1 0) (1 10)) (@canonical ((f.ml (1 11) (1 10)) "")))))
5352 (warnings
5353 ( "File \"f.ml\", line 1, characters 0-10:\
5354 \n'@canonical' should not be empty."))) |}]
5355
5356 let extra_whitespace =
5357 test "@canonical Foo";
5358 [%expect
5359 {|
5360 ((output (((f.ml (1 0) (1 15)) (@canonical ((f.ml (1 11) (1 15)) Foo)))))
5361 (warnings ())) |}]
5362
5363 let prefix =
5364 test "@canonicalfoo";
5365 [%expect
5366 {| ((output (((f.ml (1 0) (1 13)) (@custom canonicalfoo)))) (warnings ())) |}]
5367
5368 (* TODO This should probably be an error of some kind, as Foo Bar is not a
5369 valid module path. *)
5370 let with_whitespace =
5371 test "@canonical Foo Bar";
5372 [%expect
5373 {|
5374 ((output
5375 (((f.ml (1 0) (1 18)) (@canonical ((f.ml (1 11) (1 18)) "Foo Bar")))))
5376 (warnings ())) |}]
5377 end in
5378 ()
5379
5380let%expect_test _ =
5381 let module Inline = struct
5382 let basic =
5383 test "@inline";
5384 [%expect {| ((output (((f.ml (1 0) (1 7)) @inline))) (warnings ())) |}]
5385
5386 let prefix =
5387 test "@inlinefoo";
5388 [%expect
5389 {| ((output (((f.ml (1 0) (1 10)) (@custom inlinefoo)))) (warnings ())) |}]
5390
5391 let extra_whitespace =
5392 test "@inline";
5393 [%expect {| ((output (((f.ml (1 0) (1 7)) @inline))) (warnings ())) |}]
5394
5395 let followed_by_junk =
5396 test "@inline foo";
5397 [%expect
5398 {|
5399 ((output
5400 (((f.ml (1 0) (1 7)) @inline)
5401 ((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))
5402 (warnings
5403 ( "File \"f.ml\", line 1, characters 8-11:\
5404 \nParagraph should begin on its own line."))) |}]
5405
5406 let followed_by_paragraph =
5407 test "@inline\nfoo";
5408 [%expect
5409 {|
5410 ((output
5411 (((f.ml (1 0) (1 7)) @inline)
5412 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
5413 (warnings ())) |}]
5414
5415 let followed_by_tag =
5416 test "@inline\n@deprecated";
5417 [%expect
5418 {|
5419 ((output (((f.ml (1 0) (1 7)) @inline) ((f.ml (2 0) (2 11)) (@deprecated))))
5420 (warnings ())) |}]
5421
5422 let with_list =
5423 test "@inline - foo";
5424 [%expect
5425 {|
5426 ((output
5427 (((f.ml (1 0) (1 7)) @inline)
5428 ((f.ml (1 8) (1 13))
5429 (unordered light
5430 ((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))
5431 (warnings
5432 ( "File \"f.ml\", line 1, characters 8-9:\
5433 \n'-' (bulleted list item) should begin on its own line."))) |}]
5434 end in
5435 ()
5436
5437let%expect_test _ =
5438 let module Open = struct
5439 let basic =
5440 test "@open";
5441 [%expect {| ((output (((f.ml (1 0) (1 5)) @open))) (warnings ())) |}]
5442
5443 let prefix =
5444 test "@openfoo";
5445 [%expect
5446 {| ((output (((f.ml (1 0) (1 8)) (@custom openfoo)))) (warnings ())) |}]
5447
5448 let extra_whitespace =
5449 test "@open";
5450 [%expect {| ((output (((f.ml (1 0) (1 5)) @open))) (warnings ())) |}]
5451
5452 let followed_by_junk =
5453 test "@open foo";
5454 [%expect
5455 {|
5456 ((output
5457 (((f.ml (1 0) (1 5)) @open)
5458 ((f.ml (1 6) (1 9)) (paragraph (((f.ml (1 6) (1 9)) (word foo)))))))
5459 (warnings
5460 ( "File \"f.ml\", line 1, characters 6-9:\
5461 \nParagraph should begin on its own line."))) |}]
5462
5463 let followed_by_paragraph =
5464 test "@open\nfoo";
5465 [%expect
5466 {|
5467 ((output
5468 (((f.ml (1 0) (1 5)) @open)
5469 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
5470 (warnings ())) |}]
5471
5472 let followed_by_tag =
5473 test "@open\n@deprecated";
5474 [%expect
5475 {|
5476 ((output (((f.ml (1 0) (1 5)) @open) ((f.ml (2 0) (2 11)) (@deprecated))))
5477 (warnings ())) |}]
5478
5479 let with_list =
5480 test "@open - foo";
5481 [%expect
5482 {|
5483 ((output
5484 (((f.ml (1 0) (1 5)) @open)
5485 ((f.ml (1 6) (1 11))
5486 (unordered light
5487 ((((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))))))
5488 (warnings
5489 ( "File \"f.ml\", line 1, characters 6-7:\
5490 \n'-' (bulleted list item) should begin on its own line."))) |}]
5491 end in
5492 ()
5493
5494let%expect_test _ =
5495 let module Closed = struct
5496 let basic =
5497 test "@closed";
5498 [%expect {| ((output (((f.ml (1 0) (1 7)) @closed))) (warnings ())) |}]
5499
5500 let prefix =
5501 test "@closedfoo";
5502 [%expect
5503 {| ((output (((f.ml (1 0) (1 10)) (@custom closedfoo)))) (warnings ())) |}]
5504
5505 let extra_whitespace =
5506 test "@closed";
5507 [%expect {| ((output (((f.ml (1 0) (1 7)) @closed))) (warnings ())) |}]
5508
5509 let followed_by_junk =
5510 test "@closed foo";
5511 [%expect
5512 {|
5513 ((output
5514 (((f.ml (1 0) (1 7)) @closed)
5515 ((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))
5516 (warnings
5517 ( "File \"f.ml\", line 1, characters 8-11:\
5518 \nParagraph should begin on its own line."))) |}]
5519
5520 let followed_by_paragraph =
5521 test "@closed\nfoo";
5522 [%expect
5523 {|
5524 ((output
5525 (((f.ml (1 0) (1 7)) @closed)
5526 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
5527 (warnings ())) |}]
5528
5529 let followed_by_tag =
5530 test "@closed\n@deprecated";
5531 [%expect
5532 {|
5533 ((output (((f.ml (1 0) (1 7)) @closed) ((f.ml (2 0) (2 11)) (@deprecated))))
5534 (warnings ())) |}]
5535
5536 let with_list =
5537 test "@closed - foo";
5538 [%expect
5539 {|
5540 ((output
5541 (((f.ml (1 0) (1 7)) @closed)
5542 ((f.ml (1 8) (1 13))
5543 (unordered light
5544 ((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))
5545 (warnings
5546 ( "File \"f.ml\", line 1, characters 8-9:\
5547 \n'-' (bulleted list item) should begin on its own line."))) |}]
5548 end in
5549 ()
5550
5551let%expect_test _ =
5552 let module Hidden = struct
5553 let basic =
5554 test "@hidden";
5555 [%expect {| ((output (((f.ml (1 0) (1 7)) @hidden))) (warnings ())) |}]
5556
5557 let prefix =
5558 test "@hiddenfoo";
5559 [%expect
5560 {| ((output (((f.ml (1 0) (1 10)) (@custom hiddenfoo)))) (warnings ())) |}]
5561
5562 let extra_whitespace =
5563 test "@hidden";
5564 [%expect {| ((output (((f.ml (1 0) (1 7)) @hidden))) (warnings ())) |}]
5565
5566 let followed_by_junk =
5567 test "@hidden foo";
5568 [%expect
5569 {|
5570 ((output
5571 (((f.ml (1 0) (1 7)) @hidden)
5572 ((f.ml (1 8) (1 11)) (paragraph (((f.ml (1 8) (1 11)) (word foo)))))))
5573 (warnings
5574 ( "File \"f.ml\", line 1, characters 8-11:\
5575 \nParagraph should begin on its own line."))) |}]
5576
5577 let followed_by_paragraph =
5578 test "@hidden\nfoo";
5579 [%expect
5580 {|
5581 ((output
5582 (((f.ml (1 0) (1 7)) @hidden)
5583 ((f.ml (2 0) (2 3)) (paragraph (((f.ml (2 0) (2 3)) (word foo)))))))
5584 (warnings ())) |}]
5585
5586 let followed_by_tag =
5587 test "@hidden\n@deprecated";
5588 [%expect
5589 {|
5590 ((output (((f.ml (1 0) (1 7)) @hidden) ((f.ml (2 0) (2 11)) (@deprecated))))
5591 (warnings ())) |}]
5592
5593 let with_list =
5594 test "@hidden - foo";
5595 [%expect
5596 {|
5597 ((output
5598 (((f.ml (1 0) (1 7)) @hidden)
5599 ((f.ml (1 8) (1 13))
5600 (unordered light
5601 ((((f.ml (1 10) (1 13)) (paragraph (((f.ml (1 10) (1 13)) (word foo)))))))))))
5602 (warnings
5603 ( "File \"f.ml\", line 1, characters 8-9:\
5604 \n'-' (bulleted list item) should begin on its own line."))) |}]
5605 end in
5606 ()
5607
5608let%expect_test _ =
5609 let module Bad_markup = struct
5610 let left_brace =
5611 test "{";
5612 [%expect
5613 {|
5614 ((output (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word {)))))))
5615 (warnings
5616 ( "File \"f.ml\", line 1, characters 0-1:\
5617 \n'{': bad markup.\
5618 \nSuggestion: escape the brace with '\\{'."))) |}]
5619
5620 let left_brace_with_letter =
5621 test "{g";
5622 [%expect
5623 {|
5624 ((output
5625 (((f.ml (1 0) (1 2))
5626 (paragraph (((f.ml (1 0) (1 1)) (word {)) ((f.ml (1 1) (1 2)) (word g)))))))
5627 (warnings
5628 ( "File \"f.ml\", line 1, characters 0-1:\
5629 \n'{': bad markup.\
5630 \nSuggestion: escape the brace with '\\{'."))) |}]
5631
5632 let left_brace_with_letters =
5633 test "{gg";
5634 [%expect
5635 {|
5636 ((output
5637 (((f.ml (1 0) (1 3))
5638 (paragraph
5639 (((f.ml (1 0) (1 1)) (word {)) ((f.ml (1 1) (1 3)) (word gg)))))))
5640 (warnings
5641 ( "File \"f.ml\", line 1, characters 0-1:\
5642 \n'{': bad markup.\
5643 \nSuggestion: escape the brace with '\\{'."))) |}]
5644
5645 let empty_braces =
5646 test "{}";
5647 [%expect
5648 {|
5649 ((output
5650 (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word {)))))
5651 ((f.ml (1 1) (1 2)) (paragraph (((f.ml (1 1) (1 2)) (word })))))))
5652 (warnings
5653 ( "File \"f.ml\", line 1, characters 0-1:\
5654 \n'{': bad markup.\
5655 \nSuggestion: escape the brace with '\\{'."
5656 "File \"f.ml\", line 1, characters 1-2:\
5657 \nUnpaired '}' (end of markup).\
5658 \nSuggestion: try '\\}'."))) |}]
5659
5660 let left_space =
5661 test "{ foo}";
5662 [%expect
5663 {|
5664 ((output
5665 (((f.ml (1 0) (1 6)) (paragraph (((f.ml (1 0) (1 6)) (code_span " foo")))))))
5666 (warnings
5667 ( "File \"f.ml\", line 1, characters 0-6:\
5668 \n'{ foo}': bad markup.\
5669 \nSuggestion: did you mean '{! foo}' or '[ foo]'?"))) |}]
5670
5671 let left_spaces =
5672 test "{ foo}";
5673 [%expect
5674 {|
5675 ((output
5676 (((f.ml (1 0) (1 7))
5677 (paragraph (((f.ml (1 0) (1 7)) (code_span " foo")))))))
5678 (warnings
5679 ( "File \"f.ml\", line 1, characters 0-7:\
5680 \n'{ foo}': bad markup.\
5681 \nSuggestion: did you mean '{! foo}' or '[ foo]'?"))) |}]
5682
5683 let left_space_eof =
5684 test "{";
5685 [%expect
5686 {|
5687 ((output (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word {)))))))
5688 (warnings
5689 ( "File \"f.ml\", line 1, characters 0-1:\
5690 \n'{': bad markup.\
5691 \nSuggestion: escape the brace with '\\{'."))) |}]
5692
5693 let braces_instead_of_brackets =
5694 test "{foo}";
5695 [%expect
5696 {|
5697 ((output
5698 (((f.ml (1 0) (1 5)) (paragraph (((f.ml (1 0) (1 5)) (code_span foo)))))))
5699 (warnings
5700 ( "File \"f.ml\", line 1, characters 0-5:\
5701 \n'{foo}': bad markup.\
5702 \nSuggestion: did you mean '{!foo}' or '[foo]'?"))) |}]
5703
5704 let right_brace =
5705 test "}";
5706 [%expect
5707 {|
5708 ((output (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word })))))))
5709 (warnings
5710 ( "File \"f.ml\", line 1, characters 0-1:\
5711 \nUnpaired '}' (end of markup).\
5712 \nSuggestion: try '\\}'."))) |}]
5713
5714 let right_brace_in_paragraph =
5715 test "foo}";
5716 [%expect
5717 {|
5718 ((output
5719 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
5720 ((f.ml (1 3) (1 4)) (paragraph (((f.ml (1 3) (1 4)) (word })))))))
5721 (warnings
5722 ( "File \"f.ml\", line 1, characters 3-4:\
5723 \nUnpaired '}' (end of markup).\
5724 \nSuggestion: try '\\}'."))) |}]
5725
5726 let multiple_right_brace =
5727 test "foo } bar } baz";
5728 [%expect
5729 {|
5730 ((output
5731 (((f.ml (1 0) (1 3)) (paragraph (((f.ml (1 0) (1 3)) (word foo)))))
5732 ((f.ml (1 4) (1 5)) (paragraph (((f.ml (1 4) (1 5)) (word })))))
5733 ((f.ml (1 6) (1 9)) (paragraph (((f.ml (1 6) (1 9)) (word bar)))))
5734 ((f.ml (1 10) (1 11)) (paragraph (((f.ml (1 10) (1 11)) (word })))))
5735 ((f.ml (1 12) (1 15)) (paragraph (((f.ml (1 12) (1 15)) (word baz)))))))
5736 (warnings
5737 ( "File \"f.ml\", line 1, characters 4-5:\
5738 \nUnpaired '}' (end of markup).\
5739 \nSuggestion: try '\\}'."
5740 "File \"f.ml\", line 1, characters 10-11:\
5741 \nUnpaired '}' (end of markup).\
5742 \nSuggestion: try '\\}'."))) |}]
5743
5744 let right_brace_in_list_item =
5745 test "- foo}";
5746 [%expect
5747 {|
5748 ((output
5749 (((f.ml (1 0) (1 5))
5750 (unordered light
5751 ((((f.ml (1 2) (1 5)) (paragraph (((f.ml (1 2) (1 5)) (word foo)))))))))
5752 ((f.ml (1 5) (1 6)) (paragraph (((f.ml (1 5) (1 6)) (word })))))))
5753 (warnings
5754 ( "File \"f.ml\", line 1, characters 5-6:\
5755 \nUnpaired '}' (end of markup).\
5756 \nSuggestion: try '\\}'."))) |}]
5757
5758 let right_brace_in_code_span =
5759 test "[foo}]";
5760 [%expect
5761 {|
5762 ((output
5763 (((f.ml (1 0) (1 6)) (paragraph (((f.ml (1 0) (1 6)) (code_span foo})))))))
5764 (warnings ())) |}]
5765
5766 let right_brace_in_code_block =
5767 test "{[foo}]}";
5768 [%expect
5769 {|
5770 ((output (((f.ml (1 0) (1 8)) (code_block ((f.ml (1 2) (1 6)) foo})))))
5771 (warnings ())) |}]
5772
5773 let right_brace_in_verbatim_text =
5774 test "{v foo} v}";
5775 [%expect
5776 {| ((output (((f.ml (1 0) (1 10)) (verbatim foo})))) (warnings ())) |}]
5777
5778 let right_brace_in_author =
5779 test "@author Foo}";
5780 [%expect
5781 {| ((output (((f.ml (1 0) (1 12)) (@author Foo})))) (warnings ())) |}]
5782
5783 let right_brace_in_deprecated =
5784 test "@deprecated }";
5785 [%expect
5786 {|
5787 ((output
5788 (((f.ml (1 0) (1 11)) (@deprecated))
5789 ((f.ml (1 12) (1 13)) (paragraph (((f.ml (1 12) (1 13)) (word })))))))
5790 (warnings
5791 ( "File \"f.ml\", line 1, characters 12-13:\
5792 \nUnpaired '}' (end of markup).\
5793 \nSuggestion: try '\\}'."))) |}]
5794
5795 let right_bracket =
5796 test "]";
5797 [%expect
5798 {|
5799 ((output (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word ])))))))
5800 (warnings
5801 ( "File \"f.ml\", line 1, characters 0-1:\
5802 \nUnpaired ']' (end of code).\
5803 \nSuggestion: try '\\]'."))) |}]
5804
5805 let right_bracket_in_paragraph =
5806 test "foo]";
5807 [%expect
5808 {|
5809 ((output
5810 (((f.ml (1 0) (1 4))
5811 (paragraph
5812 (((f.ml (1 0) (1 3)) (word foo)) ((f.ml (1 3) (1 4)) (word ])))))))
5813 (warnings
5814 ( "File \"f.ml\", line 1, characters 3-4:\
5815 \nUnpaired ']' (end of code).\
5816 \nSuggestion: try '\\]'."))) |}]
5817
5818 let right_bracket_in_shorthand_list =
5819 test "- foo]";
5820 [%expect
5821 {|
5822 ((output
5823 (((f.ml (1 0) (1 6))
5824 (unordered light
5825 ((((f.ml (1 2) (1 6))
5826 (paragraph
5827 (((f.ml (1 2) (1 5)) (word foo)) ((f.ml (1 5) (1 6)) (word ])))))))))))
5828 (warnings
5829 ( "File \"f.ml\", line 1, characters 5-6:\
5830 \nUnpaired ']' (end of code).\
5831 \nSuggestion: try '\\]'."))) |}]
5832
5833 let right_bracket_in_code_span =
5834 test "[]]";
5835 [%expect
5836 {|
5837 ((output
5838 (((f.ml (1 0) (1 3))
5839 (paragraph
5840 (((f.ml (1 0) (1 2)) (code_span "")) ((f.ml (1 2) (1 3)) (word ])))))))
5841 (warnings
5842 ( "File \"f.ml\", line 1, characters 2-3:\
5843 \nUnpaired ']' (end of code).\
5844 \nSuggestion: try '\\]'."))) |}]
5845
5846 let right_bracket_in_style =
5847 test "{b]}";
5848 [%expect
5849 {|
5850 ((output (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (bold ())))))))
5851 (warnings
5852 ( "File \"f.ml\", line 1, characters 0-2:\
5853 \n'{b' should be followed by space, a tab, or a new line."
5854 "File \"f.ml\", line 1, characters 2-4:\
5855 \n']}' is not allowed in '{b ...}' (boldface text)."
5856 "File \"f.ml\", line 1, characters 0-2:\
5857 \n'{b ...}' (boldface text) should not be empty."))) |}]
5858
5859 let right_bracket_in_verbatim =
5860 test "{v ] v}";
5861 [%expect
5862 {| ((output (((f.ml (1 0) (1 7)) (verbatim ])))) (warnings ())) |}]
5863
5864 let right_bracket_in_list =
5865 test "{ul ]}";
5866 [%expect
5867 {|
5868 ((output (((f.ml (1 0) (1 6)) (unordered heavy ()))))
5869 (warnings
5870 ( "File \"f.ml\", line 1, characters 4-6:\
5871 \n']}' is not allowed in '{ul ...}' (bulleted list).\
5872 \nSuggestion: move ']}' into a list item, '{li ...}' or '{- ...}'."
5873 "File \"f.ml\", line 1, characters 6-6:\
5874 \nEnd of text is not allowed in '{ul ...}' (bulleted list).\
5875 \nSuggestion: add '}'."
5876 "File \"f.ml\", line 1, characters 0-3:\
5877 \n'{ul ...}' (bulleted list) should not be empty."))) |}]
5878
5879 let right_bracket_in_list_item =
5880 test "{ul {li ]}}";
5881 [%expect
5882 {|
5883 ((output (((f.ml (1 0) (1 11)) (unordered heavy (())))))
5884 (warnings
5885 ( "File \"f.ml\", line 1, characters 4-7:\
5886 \n'{li ...}' (list item) should not be empty."
5887 "File \"f.ml\", line 1, characters 11-11:\
5888 \nEnd of text is not allowed in '{ul ...}' (bulleted list).\
5889 \nSuggestion: add '}'."))) |}]
5890
5891 let right_bracket_in_heading =
5892 test "{2 ]}";
5893 [%expect
5894 {|
5895 ((output (((f.ml (1 0) (1 2)) (2 (label ()) ()))))
5896 (warnings
5897 ( "File \"f.ml\", line 1, characters 3-5:\
5898 \n']}' is not allowed in '{2 ...}' (section heading)."
5899 "File \"f.ml\", line 1, characters 0-2:\
5900 \n'{2 ...}' (section heading) should not be empty."))) |}]
5901
5902 let right_bracket_in_author =
5903 test "@author Foo]";
5904 [%expect
5905 {| ((output (((f.ml (1 0) (1 12)) (@author Foo])))) (warnings ())) |}]
5906
5907 let at =
5908 test "@";
5909 [%expect
5910 {|
5911 ((output (((f.ml (1 0) (1 1)) (paragraph (((f.ml (1 0) (1 1)) (word @)))))))
5912 (warnings ( "File \"f.ml\", line 1, characters 0-1:\
5913 \nStray '@'."))) |}]
5914
5915 let cr =
5916 test "";
5917 [%expect {| ((output ()) (warnings ())) |}]
5918 end in
5919 ()
5920
5921let%expect_test _ =
5922 let module Utf_8 = struct
5923 let lambda =
5924 test "\xce\xbb";
5925 [%expect
5926 {|
5927 ((output
5928 (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word "\206\187")))))))
5929 (warnings ())) |}]
5930
5931 let words =
5932 test "\xce\xbb \xce\xbb";
5933 [%expect
5934 {|
5935 ((output
5936 (((f.ml (1 0) (1 5))
5937 (paragraph
5938 (((f.ml (1 0) (1 2)) (word "\206\187")) ((f.ml (1 2) (1 3)) space)
5939 ((f.ml (1 3) (1 5)) (word "\206\187")))))))
5940 (warnings ())) |}]
5941
5942 let no_validation =
5943 test "Î";
5944 [%expect
5945 {|
5946 ((output
5947 (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word "\195\142")))))))
5948 (warnings ())) |}]
5949
5950 let escapes =
5951 test "\xce\xbb\\}";
5952 [%expect
5953 {|
5954 ((output
5955 (((f.ml (1 0) (1 4)) (paragraph (((f.ml (1 0) (1 4)) (word "\206\187}")))))))
5956 (warnings ())) |}]
5957
5958 let newline =
5959 test "\xce\xbb \n \xce\xbb";
5960 [%expect
5961 {|
5962 ((output
5963 (((f.ml (1 0) (2 3))
5964 (paragraph
5965 (((f.ml (1 0) (1 2)) (word "\206\187")) ((f.ml (1 2) (2 1)) space)
5966 ((f.ml (2 1) (2 3)) (word "\206\187")))))))
5967 (warnings ())) |}]
5968
5969 let paragraphs =
5970 test "\xce\xbb \n\n \xce\xbb";
5971 [%expect
5972 {|
5973 ((output
5974 (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word "\206\187")))))
5975 ((f.ml (3 1) (3 3)) (paragraph (((f.ml (3 1) (3 3)) (word "\206\187")))))))
5976 (warnings ())) |}]
5977
5978 let code_span =
5979 test "[\xce\xbb]";
5980 [%expect
5981 {|
5982 ((output
5983 (((f.ml (1 0) (1 4))
5984 (paragraph (((f.ml (1 0) (1 4)) (code_span "\206\187")))))))
5985 (warnings ())) |}]
5986
5987 let minus =
5988 test "\xce\xbb-\xce\xbb";
5989 [%expect
5990 {|
5991 ((output
5992 (((f.ml (1 0) (1 5))
5993 (paragraph (((f.ml (1 0) (1 5)) (word "\206\187-\206\187")))))))
5994 (warnings ())) |}]
5995
5996 let shorthand_list =
5997 test "- \xce\xbb";
5998 [%expect
5999 {|
6000 ((output
6001 (((f.ml (1 0) (1 4))
6002 (unordered light
6003 ((((f.ml (1 2) (1 4))
6004 (paragraph (((f.ml (1 2) (1 4)) (word "\206\187")))))))))))
6005 (warnings ())) |}]
6006
6007 let styled =
6008 test "{b \xce\xbb}";
6009 [%expect
6010 {|
6011 ((output
6012 (((f.ml (1 0) (1 6))
6013 (paragraph
6014 (((f.ml (1 0) (1 6)) (bold (((f.ml (1 3) (1 5)) (word "\206\187"))))))))))
6015 (warnings ())) |}]
6016
6017 let reference_target =
6018 test "{!\xce\xbb}";
6019 [%expect
6020 {|
6021 ((output
6022 (((f.ml (1 0) (1 5))
6023 (paragraph
6024 (((f.ml (1 0) (1 5)) (simple ((f.ml (1 2) (1 5)) "\206\187") ())))))))
6025 (warnings ())) |}]
6026
6027 let code_block =
6028 test "{[\xce\xbb]}";
6029 [%expect
6030 {|
6031 ((output (((f.ml (1 0) (1 6)) (code_block ((f.ml (1 2) (1 4)) "\206\187")))))
6032 (warnings ())) |}]
6033
6034 let verbatim =
6035 test "{v \xce\xbb v}";
6036 [%expect
6037 {| ((output (((f.ml (1 0) (1 8)) (verbatim "\206\187")))) (warnings ())) |}]
6038
6039 let label =
6040 test "{2:\xce\xbb Bar}";
6041 [%expect
6042 {|
6043 ((output
6044 (((f.ml (1 0) (1 10))
6045 (2 (label ("\206\187")) (((f.ml (1 6) (1 9)) (word Bar)))))))
6046 (warnings ())) |}]
6047
6048 let author =
6049 test "@author \xce\xbb";
6050 [%expect
6051 {| ((output (((f.ml (1 0) (1 10)) (@author "\206\187")))) (warnings ())) |}]
6052
6053 let param =
6054 test "@param \xce\xbb";
6055 [%expect
6056 {| ((output (((f.ml (1 0) (1 9)) (@param "\206\187")))) (warnings ())) |}]
6057
6058 let raise =
6059 test "@raise \xce\xbb";
6060 [%expect
6061 {| ((output (((f.ml (1 0) (1 9)) (@raise "\206\187")))) (warnings ())) |}]
6062
6063 let see =
6064 test "@see <\xce\xbb>";
6065 [%expect
6066 {| ((output (((f.ml (1 0) (1 9)) (@see url "\206\187")))) (warnings ())) |}]
6067
6068 let since =
6069 test "@since \xce\xbb";
6070 [%expect
6071 {| ((output (((f.ml (1 0) (1 9)) (@since "\206\187")))) (warnings ())) |}]
6072
6073 let before =
6074 test "@before \xce\xbb";
6075 [%expect
6076 {| ((output (((f.ml (1 0) (1 10)) (@before "\206\187")))) (warnings ())) |}]
6077
6078 let version =
6079 test "@version \xce\xbb";
6080 [%expect
6081 {| ((output (((f.ml (1 0) (1 11)) (@version "\206\187")))) (warnings ())) |}]
6082
6083 let right_brace =
6084 test "\xce\xbb}";
6085 [%expect
6086 {|
6087 ((output
6088 (((f.ml (1 0) (1 2)) (paragraph (((f.ml (1 0) (1 2)) (word "\206\187")))))
6089 ((f.ml (1 2) (1 3)) (paragraph (((f.ml (1 2) (1 3)) (word })))))))
6090 (warnings
6091 ( "File \"f.ml\", line 1, characters 2-3:\
6092 \nUnpaired '}' (end of markup).\
6093 \nSuggestion: try '\\}'."))) |}]
6094 end in
6095 ()
6096
6097let%expect_test _ =
6098 let module Comment_location = struct
6099 let error_on_first_line =
6100 test "@foo";
6101 [%expect
6102 {| ((output (((f.ml (1 0) (1 4)) (@custom foo)))) (warnings ())) |}]
6103
6104 let error_on_second_line =
6105 test " \n @foo";
6106 [%expect
6107 {| ((output (((f.ml (2 2) (2 6)) (@custom foo)))) (warnings ())) |}]
6108 end in
6109 ()
6110
6111let%expect_test _ =
6112 let module Unsupported = struct
6113 (* test "index list"
6114 "{!indexlist}"
6115 (Ok []); *)
6116
6117 let left_alignment =
6118 test "{L foo}";
6119 [%expect
6120 {|
6121 ((output
6122 (((f.ml (1 0) (1 7)) (paragraph (((f.ml (1 3) (1 6)) (word foo)))))))
6123 (warnings
6124 ( "File \"f.ml\", line 1, characters 0-7:\
6125 \n'{L ...}' (left alignment) should not be used because it has no effect."))) |}]
6126
6127 let center_alignment =
6128 test "{C foo}";
6129 [%expect
6130 {|
6131 ((output
6132 (((f.ml (1 0) (1 7)) (paragraph (((f.ml (1 3) (1 6)) (word foo)))))))
6133 (warnings
6134 ( "File \"f.ml\", line 1, characters 0-7:\
6135 \n'{C ...}' (center alignment) should not be used because it has no effect."))) |}]
6136
6137 let right_alignment =
6138 test "{R foo}";
6139 [%expect
6140 {|
6141 ((output
6142 (((f.ml (1 0) (1 7)) (paragraph (((f.ml (1 3) (1 6)) (word foo)))))))
6143 (warnings
6144 ( "File \"f.ml\", line 1, characters 0-7:\
6145 \n'{R ...}' (right alignment) should not be used because it has no effect."))) |}]
6146
6147 let custom_style =
6148 test "{c foo}";
6149 [%expect
6150 {|
6151 ((output
6152 (((f.ml (1 0) (1 7))
6153 (paragraph (((f.ml (1 0) (1 7)) (code_span "c foo")))))))
6154 (warnings
6155 ( "File \"f.ml\", line 1, characters 0-7:\
6156 \n'{c foo}': bad markup.\
6157 \nSuggestion: did you mean '{!c foo}' or '[c foo]'?"))) |}]
6158
6159 let custom_tag =
6160 test "@custom";
6161 [%expect
6162 {| ((output (((f.ml (1 0) (1 7)) (@custom custom)))) (warnings ())) |}]
6163
6164 let custom_tag_with_dot =
6165 test "@foo.bar";
6166 [%expect
6167 {| ((output (((f.ml (1 0) (1 8)) (@custom foo.bar)))) (warnings ())) |}]
6168
6169 let custom_tag_with_multiple_dots =
6170 test "@callout.box.large";
6171 [%expect
6172 {| ((output (((f.ml (1 0) (1 18)) (@custom callout.box.large)))) (warnings ())) |}]
6173
6174 let custom_tag_with_underscore =
6175 test "@foo_bar";
6176 [%expect
6177 {| ((output (((f.ml (1 0) (1 8)) (@custom foo_bar)))) (warnings ())) |}]
6178
6179 let custom_tag_with_number =
6180 test "@rfc2616";
6181 [%expect
6182 {| ((output (((f.ml (1 0) (1 8)) (@custom rfc2616)))) (warnings ())) |}]
6183
6184 let custom_tag_with_content =
6185 test "@foo.bar This is the content";
6186 [%expect
6187 {|
6188 ((output
6189 (((f.ml (1 0) (1 28))
6190 (@custom foo.bar
6191 ((f.ml (1 9) (1 28))
6192 (paragraph
6193 (((f.ml (1 9) (1 13)) (word This)) ((f.ml (1 13) (1 14)) space)
6194 ((f.ml (1 14) (1 16)) (word is)) ((f.ml (1 16) (1 17)) space)
6195 ((f.ml (1 17) (1 20)) (word the)) ((f.ml (1 20) (1 21)) space)
6196 ((f.ml (1 21) (1 28)) (word content)))))))))
6197 (warnings ()))
6198 |}]
6199
6200 let custom_tag_trailing_dot =
6201 test "@foo. bar";
6202 [%expect
6203 {|
6204 ((output
6205 (((f.ml (1 0) (1 9))
6206 (@custom foo.
6207 ((f.ml (1 6) (1 9)) (paragraph (((f.ml (1 6) (1 9)) (word bar)))))))))
6208 (warnings ())) |}]
6209
6210 let custom_reference_kind =
6211 test "{!custom:foo}";
6212 [%expect
6213 {|
6214 ((output
6215 (((f.ml (1 0) (1 13))
6216 (paragraph
6217 (((f.ml (1 0) (1 13)) (simple ((f.ml (1 2) (1 13)) custom:foo) ())))))))
6218 (warnings ())) |}]
6219
6220 let html_tag =
6221 test "<b>foo</b>";
6222 [%expect
6223 {|
6224 ((output
6225 (((f.ml (1 0) (1 10))
6226 (paragraph (((f.ml (1 0) (1 10)) (word <b>foo</b>)))))))
6227 (warnings ())) |}]
6228 end in
6229 ()
6230
6231let%expect_test _ =
6232 let module Locations = struct
6233 (* test "index list"
6234 "{!indexlist}"
6235 (Ok []); *)
6236
6237 let lexing_pos_to_sexp : Lexing.position -> sexp =
6238 fun v ->
6239 List
6240 [
6241 List [ Atom "pos_fname"; Atom v.pos_fname ];
6242 List [ Atom "pos_bol"; Atom (string_of_int v.pos_bol) ];
6243 List [ Atom "pos_lnum"; Atom (string_of_int v.pos_lnum) ];
6244 List [ Atom "pos_cnum"; Atom (string_of_int v.pos_cnum) ];
6245 ]
6246
6247 let parser_output formatter pv =
6248 let ast, warnings = Odoc_parser.(ast pv, warnings pv) in
6249 let at conv v =
6250 let { Loc.start; end_; _ } = Loc.location v in
6251 let v' = v |> conv in
6252 let start' =
6253 Odoc_parser.position_of_point pv start |> lexing_pos_to_sexp
6254 in
6255 let start'' = Location_to_sexp.point start in
6256 let end' =
6257 Odoc_parser.position_of_point pv end_ |> lexing_pos_to_sexp
6258 in
6259 let end'' = Location_to_sexp.point end_ in
6260 List
6261 [
6262 List [ Atom "start"; start' ];
6263 List [ Atom "start_loc"; start'' ];
6264 List [ Atom "end"; end' ];
6265 List [ Atom "end_loc"; end'' ];
6266 List [ Atom "value"; v' ];
6267 ]
6268 in
6269 let sexp = Ast_to_sexp.(docs { at } ast) in
6270 let warnings = List (List.map error warnings) in
6271 let output =
6272 List
6273 [ List [ Atom "output"; sexp ]; List [ Atom "warnings"; warnings ] ]
6274 in
6275 Sexplib0.Sexp.pp_hum formatter output;
6276 Format.pp_print_flush formatter ()
6277
6278 let test
6279 ?(location =
6280 Lexing.{ pos_bol = 0; pos_cnum = 0; pos_lnum = 1; pos_fname = "none" })
6281 text =
6282 let ast = Odoc_parser.parse_comment ~location ~text in
6283 Format.printf "%a" parser_output ast
6284
6285 let non_offset_location =
6286 test "one\n two\n three";
6287 [%expect
6288 {|
6289 ((output
6290 (((start ((pos_fname none) (pos_bol 0) (pos_lnum 1) (pos_cnum 0)))
6291 (start_loc (1 0))
6292 (end ((pos_fname none) (pos_bol 9) (pos_lnum 3) (pos_cnum 16)))
6293 (end_loc (3 7))
6294 (value
6295 (paragraph
6296 (((start ((pos_fname none) (pos_bol 0) (pos_lnum 1) (pos_cnum 0)))
6297 (start_loc (1 0))
6298 (end ((pos_fname none) (pos_bol 0) (pos_lnum 1) (pos_cnum 3)))
6299 (end_loc (1 3)) (value (word one)))
6300 ((start ((pos_fname none) (pos_bol 0) (pos_lnum 1) (pos_cnum 3)))
6301 (start_loc (1 3))
6302 (end ((pos_fname none) (pos_bol 4) (pos_lnum 2) (pos_cnum 5)))
6303 (end_loc (2 1)) (value space))
6304 ((start ((pos_fname none) (pos_bol 4) (pos_lnum 2) (pos_cnum 5)))
6305 (start_loc (2 1))
6306 (end ((pos_fname none) (pos_bol 4) (pos_lnum 2) (pos_cnum 8)))
6307 (end_loc (2 4)) (value (word two)))
6308 ((start ((pos_fname none) (pos_bol 4) (pos_lnum 2) (pos_cnum 8)))
6309 (start_loc (2 4))
6310 (end ((pos_fname none) (pos_bol 9) (pos_lnum 3) (pos_cnum 11)))
6311 (end_loc (3 2)) (value space))
6312 ((start ((pos_fname none) (pos_bol 9) (pos_lnum 3) (pos_cnum 11)))
6313 (start_loc (3 2))
6314 (end ((pos_fname none) (pos_bol 9) (pos_lnum 3) (pos_cnum 16)))
6315 (end_loc (3 7)) (value (word three)))))))))
6316 (warnings ())) |}]
6317
6318 let offset_location =
6319 test
6320 ~location:
6321 Lexing.
6322 { pos_bol = 10; pos_cnum = 20; pos_lnum = 2; pos_fname = "none" }
6323 "one\n two\n three";
6324 [%expect
6325 {|
6326 ((output
6327 (((start ((pos_fname none) (pos_bol 10) (pos_lnum 2) (pos_cnum 20)))
6328 (start_loc (2 10))
6329 (end ((pos_fname none) (pos_bol 29) (pos_lnum 4) (pos_cnum 36)))
6330 (end_loc (4 7))
6331 (value
6332 (paragraph
6333 (((start ((pos_fname none) (pos_bol 10) (pos_lnum 2) (pos_cnum 20)))
6334 (start_loc (2 10))
6335 (end ((pos_fname none) (pos_bol 10) (pos_lnum 2) (pos_cnum 23)))
6336 (end_loc (2 13)) (value (word one)))
6337 ((start ((pos_fname none) (pos_bol 10) (pos_lnum 2) (pos_cnum 23)))
6338 (start_loc (2 13))
6339 (end ((pos_fname none) (pos_bol 24) (pos_lnum 3) (pos_cnum 25)))
6340 (end_loc (3 1)) (value space))
6341 ((start ((pos_fname none) (pos_bol 24) (pos_lnum 3) (pos_cnum 25)))
6342 (start_loc (3 1))
6343 (end ((pos_fname none) (pos_bol 24) (pos_lnum 3) (pos_cnum 28)))
6344 (end_loc (3 4)) (value (word two)))
6345 ((start ((pos_fname none) (pos_bol 24) (pos_lnum 3) (pos_cnum 28)))
6346 (start_loc (3 4))
6347 (end ((pos_fname none) (pos_bol 29) (pos_lnum 4) (pos_cnum 31)))
6348 (end_loc (4 2)) (value space))
6349 ((start ((pos_fname none) (pos_bol 29) (pos_lnum 4) (pos_cnum 31)))
6350 (start_loc (4 2))
6351 (end ((pos_fname none) (pos_bol 29) (pos_lnum 4) (pos_cnum 36)))
6352 (end_loc (4 7)) (value (word three)))))))))
6353 (warnings ())) |}]
6354 end in
6355 ()
6356
6357let%expect_test _ =
6358 let module Math = struct
6359 let block =
6360 test "{math \\sum_{i=0}^n x^i%}";
6361 [%expect
6362 {|
6363 ((output (((f.ml (1 0) (1 24)) (math_block "\\sum_{i=0}^n x^i%"))))
6364 (warnings ())) |}]
6365
6366 let complex_block =
6367 test
6368 {|{math
6369 \alpha(x)=\left\{
6370 \begin{array}{ll} % beginning of the array
6371 x \% 4\\ % some variable modulo 4
6372 \frac{1}{1+e^{-kx}}\\ % something else
6373 \frac{e^x-e^{-x}}{e^x+e^{-x}} % another action
6374 \end{array} % end of the array
6375 \right.
6376 }|};
6377 [%expect
6378 {|
6379 ((output
6380 (((f.ml (1 0) (9 7))
6381 (math_block
6382 " \\alpha(x)=\\left\\{\
6383 \n \\begin{array}{ll} % beginning of the array\
6384 \n x \\% 4\\\\ % some variable modulo 4\
6385 \n \\frac{1}{1+e^{-kx}}\\\\ % something else\
6386 \n \\frac{e^x-e^{-x}}{e^x+e^{-x}} % another action\
6387 \n \\end{array} % end of the array\
6388 \n \\right.\
6389 \n "))))
6390 (warnings ())) |}]
6391
6392 let inline =
6393 test "{m x + 4}";
6394 [%expect
6395 {|
6396 ((output
6397 (((f.ml (1 0) (1 9))
6398 (paragraph (((f.ml (1 0) (1 9)) (math_span "x + 4")))))))
6399 (warnings ())) |}]
6400
6401 let inline_nested =
6402 test "{m \\sub_{i=0}^n x^i}";
6403 [%expect
6404 {|
6405 ((output
6406 (((f.ml (1 0) (1 20))
6407 (paragraph (((f.ml (1 0) (1 20)) (math_span "\\sub_{i=0}^n x^i")))))))
6408 (warnings ())) |}]
6409
6410 let inline_false_nesting =
6411 test "{m \\{ \\mathbb{only_left}}";
6412 [%expect
6413 {|
6414 ((output
6415 (((f.ml (1 0) (1 25))
6416 (paragraph (((f.ml (1 0) (1 25)) (math_span "\\{ \\mathbb{only_left}")))))))
6417 (warnings ())) |}]
6418
6419 let inline_false_terminator =
6420 test "{m \\mathbb{only_left}\\}}";
6421 [%expect
6422 {|
6423 ((output
6424 (((f.ml (1 0) (1 24))
6425 (paragraph (((f.ml (1 0) (1 24)) (math_span "\\mathbb{only_left}\\}")))))))
6426 (warnings ())) |}]
6427 end in
6428 ()