Skip to content

Commit a2d0624

Browse files
gilthojonludlam
authored andcommitted
try at math syntax
1 parent d573aad commit a2d0624

File tree

5 files changed

+126
-5
lines changed

5 files changed

+126
-5
lines changed

src/ast.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ type inline_element =
2222
| `Styled of style * inline_element with_location list
2323
| `Reference of
2424
reference_kind * string with_location * inline_element with_location list
25-
| `Link of string * inline_element with_location list ]
25+
| `Link of string * inline_element with_location list
26+
| `Math of bool * string ]
2627
(** Inline elements are equivalent to what would be found in a [span] in HTML.
2728
Mostly these are straightforward. The [`Reference] constructor takes a triple
2829
whose second element is the reference itself, and the third the replacement

src/lexer.mll

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ let raw_markup =
262262
let raw_markup_target =
263263
([^ ':' '%'] | '%'+ [^ ':' '%' '}'])* '%'*
264264

265+
let math_block = raw_markup
266+
265267
let language_tag_char =
266268
['a'-'z' 'A'-'Z' '0'-'9' '_' '-' ]
267269

@@ -320,6 +322,9 @@ rule token input = parse
320322

321323
| "{_"
322324
{ emit input (`Begin_style `Subscript) }
325+
326+
| "{m" horizontal_space
327+
{ inline_math (Buffer.create 1024) 0 (Lexing.lexeme_start lexbuf) input lexbuf }
323328

324329
| "{!modules:" ([^ '}']* as modules) '}'
325330
{ emit input (`Modules modules) }
@@ -361,6 +366,16 @@ rule token input = parse
361366
{ verbatim
362367
(Buffer.create 1024) None (Lexing.lexeme_start lexbuf) input lexbuf }
363368

369+
| "{%math" horizontal_space (raw_markup as s) ("%}" | eof as e)
370+
{ let token = `Math (true, s) in
371+
if e <> "%}" then
372+
warning
373+
input
374+
~start_offset:(Lexing.lexeme_end lexbuf)
375+
(Parse_error.not_allowed
376+
~what:(Token.describe `End)
377+
~in_what:(Token.describe token));
378+
emit input token }
364379
| "{%" ((raw_markup_target as target) ':')? (raw_markup as s)
365380
("%}" | eof as e)
366381
{ let token = `Raw_markup (target, s) in
@@ -372,7 +387,7 @@ rule token input = parse
372387
~what:(Token.describe `End)
373388
~in_what:(Token.describe token));
374389
emit input token }
375-
390+
376391
| "{ul"
377392
{ emit input (`Begin_list `Unordered) }
378393

@@ -538,7 +553,40 @@ and code_span buffer nesting_level start_offset input = parse
538553
{ Buffer.add_char buffer c;
539554
code_span buffer nesting_level start_offset input lexbuf }
540555

556+
and inline_math buffer nesting_level start_offset input = parse
557+
| '}'
558+
{ if nesting_level == 0 then
559+
emit input (`Math (false, Buffer.contents buffer)) ~start_offset
560+
else begin
561+
Buffer.add_char buffer '}';
562+
inline_math buffer (nesting_level - 1) start_offset input lexbuf
563+
end
564+
}
565+
| '{'
566+
{ Buffer.add_char buffer '{';
567+
inline_math buffer (nesting_level + 1) start_offset input lexbuf }
568+
| ("\\{" | "\\}") as s
569+
{ Buffer.add_string buffer s;
570+
inline_math buffer nesting_level start_offset input lexbuf }
571+
| newline newline
572+
{ warning
573+
input
574+
(Parse_error.not_allowed
575+
~what:(Token.describe (`Blank_line "\n\n"))
576+
~in_what:(Token.describe (`Math (false, ""))));
577+
Buffer.add_char buffer '\n';
578+
inline_math buffer nesting_level start_offset input lexbuf }
541579

580+
| eof
581+
{ warning
582+
input
583+
(Parse_error.not_allowed
584+
~what:(Token.describe `End)
585+
~in_what:(Token.describe (`Math (false, ""))));
586+
emit input (`Math (false, Buffer.contents buffer)) ~start_offset }
587+
| _ as c
588+
{ Buffer.add_char buffer c;
589+
inline_math buffer nesting_level start_offset input lexbuf }
542590

543591
and verbatim buffer last_false_terminator start_offset input = parse
544592
| (space_char as c) "v}"

src/syntax.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ type token_that_always_begins_an_inline_element =
5454
| `Simple_reference of string
5555
| `Begin_reference_with_replacement_text of string
5656
| `Simple_link of string
57-
| `Begin_link_with_replacement_text of string ]
57+
| `Begin_link_with_replacement_text of string
58+
| `Math of bool * string ]
5859

5960
(* Check that the token constructors above actually are all in [Token.t]. *)
6061
let _check_subset : token_that_always_begins_an_inline_element -> Token.t =
@@ -105,6 +106,9 @@ let rec inline_element :
105106
| `Raw_markup (raw_markup_target, s) ->
106107
junk input;
107108
Loc.at location (`Raw_markup (raw_markup_target, s))
109+
| `Math s ->
110+
junk input;
111+
Loc.at location (`Math s)
108112
| `Begin_style s as parent_markup ->
109113
junk input;
110114

src/token.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ type t =
5353
string
5454
| `Code_span of string
5555
| `Raw_markup of string option * string
56+
| `Math of bool * string
57+
(* The boolean is true iff the math is a block *)
5658
| `Begin_style of style
5759
| `Begin_paragraph_style of paragraph_style
5860
| (* Other inline element markup. *)
@@ -123,6 +125,7 @@ let describe : [< t | `Comment ] -> string = function
123125
| `Begin_style `Emphasis -> "'{e ...}' (emphasized text)"
124126
| `Begin_style `Superscript -> "'{^...}' (superscript)"
125127
| `Begin_style `Subscript -> "'{_...}' (subscript)"
128+
| `Math (b, _) -> if b then "'{%math ...%}' (math block)" else "'{m ...}' (inline math)"
126129
| `Simple_reference _ -> "'{!...}' (cross-reference)"
127130
| `Begin_reference_with_replacement_text _ ->
128131
"'{{!...} ...}' (cross-reference)"

test/test.ml

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ module Ast_to_sexp = struct
4141
| `Code_span c -> List [ Atom "code_span"; Atom c ]
4242
| `Raw_markup (target, s) ->
4343
List [ Atom "raw_markup"; opt str target; Atom s ]
44+
| `Math (b, s) ->
45+
let b_descr = if b then Atom "block" else Atom "inline" in
46+
List [Atom "math"; b_descr; Atom s]
4447
| `Styled (s, es) ->
4548
List [ style s; List (List.map (at.at (inline_element at)) es) ]
4649
| `Reference (kind, r, es) ->
@@ -1279,8 +1282,8 @@ let%expect_test _ =
12791282
( "File \"f.ml\", line 1, characters 0-4:\
12801283
\n'{^...}' (superscript) should not be empty."))) |}]
12811284
end in
1282-
()
1283-
1285+
()
1286+
12841287
let%expect_test _ =
12851288
let module Subscript = struct
12861289
let basic =
@@ -5303,3 +5306,65 @@ let%expect_test _ =
53035306
(warnings ())) |}]
53045307
end in
53055308
()
5309+
5310+
let%expect_test _ =
5311+
let module Math = struct
5312+
let block =
5313+
test "{%math \\sum_{i=0}^n x^i%}";
5314+
[%expect {|
5315+
((output
5316+
(((f.ml (1 0) (1 25))
5317+
(paragraph (((f.ml (1 0) (1 25)) (math block "\\sum_{i=0}^n x^i")))))))
5318+
(warnings ())) |}]
5319+
5320+
let complex_block =
5321+
test {|{%math
5322+
\alpha(x)=\left\{
5323+
\begin{array}{ll} % beginning of the array
5324+
x \% 4\\ % some variable modulo 4
5325+
\frac{1}{1+e^{-kx}}\\ % something else
5326+
\frac{e^x-e^{-x}}{e^x+e^{-x}} % another action
5327+
\end{array} % end of the array
5328+
\right.
5329+
%}|}
5330+
5331+
let inline =
5332+
test "{m x + 4}";
5333+
[%expect {|
5334+
((output
5335+
(((f.ml (1 0) (9 8))
5336+
(paragraph
5337+
(((f.ml (1 0) (9 8))
5338+
(raw_markup ()
5339+
"math\
5340+
\n \\alpha(x)=\\left\\{\
5341+
\n \\begin{array}{ll} % beginning of the array\
5342+
\n x \\% 4\\\\ % some variable modulo 4\
5343+
\n \\frac{1}{1+e^{-kx}}\\\\ % something else\
5344+
\n \\frac{e^x-e^{-x}}{e^x+e^{-x}} % another action\
5345+
\n \\end{array} % end of the array\
5346+
\n \\right.\
5347+
\n ")))))))
5348+
(warnings ()))((output
5349+
(((f.ml (1 0) (1 9))
5350+
(paragraph (((f.ml (1 0) (1 9)) (math inline "x + 4")))))))
5351+
(warnings ())) |}]
5352+
5353+
let inline_nested =
5354+
test "{m \\sub_{i=0}^n x^i}";
5355+
[%expect {|
5356+
((output
5357+
(((f.ml (1 0) (1 20))
5358+
(paragraph (((f.ml (1 0) (1 20)) (math inline "\\sub_{i=0}^n x^i")))))))
5359+
(warnings ())) |}]
5360+
5361+
let inline_false_terminator =
5362+
test "{m \\{ \\mathbb{only_left}}";
5363+
[%expect {|
5364+
((output
5365+
(((f.ml (1 0) (1 25))
5366+
(paragraph
5367+
(((f.ml (1 0) (1 25)) (math inline "\\{ \\mathbb{only_left}")))))))
5368+
(warnings ())) |}]
5369+
end in
5370+
()

0 commit comments

Comments
 (0)