refactor replace parse_bridge with Parse module

Rename parse_bridge to parse and give it clearer entry points: - Parse.document: structural lexer → Menhir → Raw_ast.document - Parse.inline: inline lexer → Menhir → Ast.inline list The Menhir lexbuf wiring boilerplate lives here (shared dummy_pos, position threading). Lexers remain focused on tokenization only.

Commit
42f14dbcfd777bbe2a10a5a383d636e58dd72d46
Author
Kiro (high) <noreply@kiro.dev>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/normalize.ml
index 96b976fb..21e0e823 100644..100644
@@ -102,7 +102,7 @@
102 102 in
103 103 (* Parse remaining text as inline content *)
104 104 let title_inline =
105 Removed: if trim rest3 = "" then [] else Parse_bridge.parse_inline (trim rest3)
105 Added: if trim rest3 = "" then [] else Parse.inline (trim rest3)
106 106 in
107 107 (todo, priority, commented, title_inline, tags)
108 108
@@ -237,12 +237,12 @@
237 237 | Some t -> (Some t, body_text)
238 238 | None -> extract_list_tag body_text
239 239 in
240 Removed: let tag_inline = Option.map (fun t -> Parse_bridge.parse_inline t) tag_opt in
240 Added: let tag_inline = Option.map (fun t -> Parse.inline t) tag_opt in
241 241 (* Build contents: paragraph from text + sub-list if any *)
242 242 let contents =
243 243 let text_elements =
244 244 if trim content_text = "" then []
245 Removed: else [ Ast.Paragraph (Parse_bridge.parse_inline content_text, []) ]
245 Added: else [ Ast.Paragraph (Parse.inline content_text, []) ]
246 246 in
247 247 let sub_list_elements =
248 248 if sub_items = [] then []
@@ -280,7 +280,7 @@
280 280 else s
281 281 in
282 282 let parts = String.split_on_char '|' s in
283 Removed: List.map (fun cell -> Parse_bridge.parse_inline (trim cell)) parts
283 Added: List.map (fun cell -> Parse.inline (trim cell)) parts
284 284
285 285 let normalize_table_row (row : Raw_ast.raw_table_row) : Ast.table_row =
286 286 match row with
@@ -375,8 +375,7 @@
375 375 match raw.rb_body with
376 376 | Raw_ast.Recursive_body elems -> normalize_recursive_body elems config
377 377 | Raw_ast.Opaque_body s ->
378 Removed: if trim s = "" then []
379 Removed: else [ Ast.Paragraph (Parse_bridge.parse_inline s, []) ]
378 Added: if trim s = "" then [] else [ Ast.Paragraph (Parse.inline s, []) ]
380 379 in
381 380 Ast.Quote_block { qt_contents = contents; qt_affiliated = affiliated }
382 381 | "center" ->
@@ -384,14 +383,13 @@
384 383 match raw.rb_body with
385 384 | Raw_ast.Recursive_body elems -> normalize_recursive_body elems config
386 385 | Raw_ast.Opaque_body s ->
387 Removed: if trim s = "" then []
388 Removed: else [ Ast.Paragraph (Parse_bridge.parse_inline s, []) ]
386 Added: if trim s = "" then [] else [ Ast.Paragraph (Parse.inline s, []) ]
389 387 in
390 388 Ast.Center_block { cn_contents = contents; cn_affiliated = affiliated }
391 389 | "verse" ->
392 390 let inline =
393 391 match raw.rb_body with
394 Removed: | Raw_ast.Opaque_body s -> Parse_bridge.parse_inline s
392 Added: | Raw_ast.Opaque_body s -> Parse.inline s
395 393 | Raw_ast.Recursive_body _ -> []
396 394 in
397 395 Ast.Verse_block { vs_contents = inline; vs_affiliated = affiliated }
@@ -400,8 +398,7 @@
400 398 match raw.rb_body with
401 399 | Raw_ast.Recursive_body elems -> normalize_recursive_body elems config
402 400 | Raw_ast.Opaque_body s ->
403 Removed: if trim s = "" then []
404 Removed: else [ Ast.Paragraph (Parse_bridge.parse_inline s, []) ]
401 Added: if trim s = "" then [] else [ Ast.Paragraph (Parse.inline s, []) ]
405 402 in
406 403 Ast.Custom_block
407 404 {
@@ -463,7 +460,7 @@
463 460 | Raw_ast.Raw_paragraph [] -> None
464 461 | Raw_ast.Raw_paragraph lines ->
465 462 let text = String.concat " " lines in
466 Removed: let inline = Parse_bridge.parse_inline text in
463 Added: let inline = Parse.inline text in
467 464 Some (Ast.Paragraph (inline, affiliated))
468 465 | Raw_ast.Raw_list_items items ->
469 466 let kind = determine_list_kind_with_tags items in
@@ -500,7 +497,7 @@
500 497 (** Extract a timestamp from a raw planning entry. Uses the inline parser which
501 498 handles timestamps. *)
502 499 let extract_timestamp ts_str =
503 Removed: let inlines = Parse_bridge.parse_inline ts_str in
500 Added: let inlines = Parse.inline ts_str in
504 501 let rec find_ts = function
505 502 | [] -> None
506 503 | Ast.Timestamp ts :: _ -> Some ts
lib/org.ml
index 03f6344b..724fa62d 100644..100644
@@ -22,9 +22,10 @@
22 22
23 23 module Private = struct
24 24 module Lexer = Lexer
25 Added: module Inline_lexer = Inline_lexer
26 Added: module Parse = Parse
25 27 module Parser = Parser
26 28 module Token = Token
27 Removed: module Parse_bridge = Parse_bridge
28 29 module Raw_ast = Raw_ast
29 30 module Prescan = Prescan
30 31 end
@@ -50,5 +51,5 @@
50 51 for #+TODO declarations automatically. *)
51 52 let parse ?config input =
52 53 let config = match config with Some c -> c | None -> Prescan.scan input in
53 Removed: let raw = Parse_bridge.parse ~config input in
54 Added: let raw = Parse.document ~config input in
54 55 Normalize.normalize config raw
lib/parse.ml
index 00000000..4f167bb7 000000..100644
@@ -0,0 +1,31 @@
1 Added: (** Parser orchestration.
2 Added:
3 Added: Wires the handwritten lexers into the Menhir-generated parsers. *)
4 Added:
5 Added: let dummy_pos =
6 Added: { Lexing.pos_fname = ""; pos_lnum = 0; pos_bol = 0; pos_cnum = 0 }
7 Added:
8 Added: (** Parse input text into a [Raw_ast.document]. *)
9 Added: let document ~config input =
10 Added: let st = Lexer.create ~config input in
11 Added: let dummy_lexbuf = Lexing.from_string "" in
12 Added: dummy_lexbuf.Lexing.lex_start_p <- dummy_pos;
13 Added: dummy_lexbuf.Lexing.lex_curr_p <- dummy_pos;
14 Added: let token_fun _lexbuf =
15 Added: let tok = Lexer.next_token st in
16 Added: let ln = Lexer.line_number st in
17 Added: dummy_lexbuf.Lexing.lex_start_p <- { dummy_pos with Lexing.pos_lnum = ln };
18 Added: dummy_lexbuf.Lexing.lex_curr_p <- { dummy_pos with Lexing.pos_lnum = ln };
19 Added: tok
20 Added: in
21 Added: Parser.document token_fun dummy_lexbuf
22 Added:
23 Added: (** Parse inline text into a list of [Ast.inline] objects. *)
24 Added: let inline input =
25 Added: let st = Inline_lexer.create input in
26 Added: let dummy_lexbuf = Lexing.from_string "" in
27 Added: dummy_lexbuf.Lexing.lex_start_p <- dummy_pos;
28 Added: dummy_lexbuf.Lexing.lex_curr_p <- dummy_pos;
29 Added: let token_fun _lexbuf = Inline_lexer.next_token st in
30 Added: try Inline_parser.inline_content token_fun dummy_lexbuf
31 Added: with Inline_parser.Error -> [ Ast.Plain input ]
lib/parse_bridge.ml
index 20bd3351..00000000 100644..000000
@@ -1,37 +0,0 @@
1 Removed: (** Bridge between the handwritten lexers and the Menhir parsers.
2 Removed:
3 Removed: Provides entry points that wire lexer state into the Menhir-generated parser
4 Removed: functions. No token conversion is needed since the lexers produce parser
5 Removed: tokens directly. *)
6 Removed:
7 Removed: (** A dummy lexbuf position for Menhir (we track positions ourselves). *)
8 Removed: let dummy_pos =
9 Removed: { Lexing.pos_fname = ""; pos_lnum = 0; pos_bol = 0; pos_cnum = 0 }
10 Removed:
11 Removed: (** Parse input text into a Raw_ast.document using the structural lexer and
12 Removed: Menhir parser. *)
13 Removed: let parse ~config input =
14 Removed: let lexer_state = Lexer.create ~config input in
15 Removed: let dummy_lexbuf = Lexing.from_string "" in
16 Removed: dummy_lexbuf.Lexing.lex_start_p <- dummy_pos;
17 Removed: dummy_lexbuf.Lexing.lex_curr_p <- dummy_pos;
18 Removed: let token_fun _lexbuf =
19 Removed: let tok = Lexer.next_token lexer_state in
20 Removed: let ln = Lexer.line_number lexer_state in
21 Removed: dummy_lexbuf.Lexing.lex_start_p <- { dummy_pos with Lexing.pos_lnum = ln };
22 Removed: dummy_lexbuf.Lexing.lex_curr_p <- { dummy_pos with Lexing.pos_lnum = ln };
23 Removed: tok
24 Removed: in
25 Removed: Parser.document token_fun dummy_lexbuf
26 Removed:
27 Removed: (** Parse inline text into a list of Ast.inline objects. *)
28 Removed: let parse_inline input =
29 Removed: let st = Inline_lexer.create input in
30 Removed: let dummy_lexbuf = Lexing.from_string "" in
31 Removed: dummy_lexbuf.Lexing.lex_start_p <- dummy_pos;
32 Removed: dummy_lexbuf.Lexing.lex_curr_p <- dummy_pos;
33 Removed: let token_fun _lexbuf = Inline_lexer.next_token st in
34 Removed: try Inline_parser.inline_content token_fun dummy_lexbuf
35 Removed: with Inline_parser.Error ->
36 Removed: (* Fallback: if inline parsing fails, return plain text *)
37 Removed: [ Ast.Plain input ]
test/test_main.ml
index c90ef4ed..56ee4043 100644..100644
@@ -173,12 +173,11 @@
173 173 check_tok "property" "Property(\"CUSTOM_ID\", \"my-id\")" (List.nth toks 0)
174 174
175 175 (* Parser tests *)
176 Removed: module P = Org.Private.Parse_bridge
177 176 module R = Org.Private.Raw_ast
178 177 module A = Org.Ast
179 178
180 Removed: let parse input = P.parse ~config input
181 Removed: let parse_inline input = P.parse_inline input
179 Added: let parse input = Org.Private.Parse.document ~config input
180 Added: let parse_inline input = Org.Private.Parse.inline input
182 181
183 182 let test_parse_empty () =
184 183 let doc = parse "" in