Interior comments, fragment comments, get_siblings + doc_gen comment support
Parser: read_value/read_list now capture Comment nodes inside lists when ~comments:true. Module-level _preserve_comments ref threads the flag through the recursive descent without changing signatures. Pretty printer: has_interior_comments (recursive) forces multi-line when any nested list contains comments. Comment nodes inside lists emit as indented comment lines. Edit tools: separate_comments strips interior comments recursively via strip_interior_comments before passing to tree-tools (paths stay correct). extract_fragment_comments parses new source with comments, attaches leading comments to the target position in the comment map. sx_get_siblings: injects comments for top-level siblings. sx_doc_gen: parses with comments, tracks preceding Comment node, includes cleaned comment text in generated component documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -110,7 +110,35 @@ let try_number str =
|
||||
| Some n -> Some (Number n)
|
||||
| None -> None
|
||||
|
||||
(* Module-level flag — when true, comments are captured as Comment nodes.
|
||||
Set by parse_all ~comments:true, reset after. *)
|
||||
let _preserve_comments = ref false
|
||||
|
||||
(* Collect consecutive comment lines into a Comment node *)
|
||||
let collect_comment_node s =
|
||||
let lines = ref [] in
|
||||
let rec go () =
|
||||
skip_whitespace s;
|
||||
if not (at_end s) && s.src.[s.pos] = ';' then begin
|
||||
lines := read_comment s :: !lines;
|
||||
go ()
|
||||
end
|
||||
in
|
||||
go ();
|
||||
Comment (String.concat "\n" (List.rev !lines))
|
||||
|
||||
let rec read_value s : value =
|
||||
(* In comment-preserving mode, check for comments first *)
|
||||
if !_preserve_comments then begin
|
||||
skip_whitespace s;
|
||||
if not (at_end s) && s.src.[s.pos] = ';' then
|
||||
collect_comment_node s
|
||||
else
|
||||
read_value_core s
|
||||
end else
|
||||
read_value_core s
|
||||
|
||||
and read_value_core s : value =
|
||||
skip_whitespace_and_comments s;
|
||||
if at_end s then begin
|
||||
let line = ref 1 in
|
||||
@@ -184,14 +212,29 @@ and read_list s close_char =
|
||||
advance s; (* skip opening paren/bracket *)
|
||||
let items = ref [] in
|
||||
let rec go () =
|
||||
skip_whitespace_and_comments s;
|
||||
if at_end s then raise (Parse_error "Unterminated list");
|
||||
if s.src.[s.pos] = close_char then begin
|
||||
advance s;
|
||||
List (List.rev !items)
|
||||
if !_preserve_comments then begin
|
||||
skip_whitespace s;
|
||||
if at_end s then raise (Parse_error "Unterminated list");
|
||||
if s.src.[s.pos] = close_char then begin
|
||||
advance s;
|
||||
List (List.rev !items)
|
||||
end else if s.src.[s.pos] = ';' then begin
|
||||
items := collect_comment_node s :: !items;
|
||||
go ()
|
||||
end else begin
|
||||
items := read_value_core s :: !items;
|
||||
go ()
|
||||
end
|
||||
end else begin
|
||||
items := read_value s :: !items;
|
||||
go ()
|
||||
skip_whitespace_and_comments s;
|
||||
if at_end s then raise (Parse_error "Unterminated list");
|
||||
if s.src.[s.pos] = close_char then begin
|
||||
advance s;
|
||||
List (List.rev !items)
|
||||
end else begin
|
||||
items := read_value s :: !items;
|
||||
go ()
|
||||
end
|
||||
end
|
||||
in go ()
|
||||
|
||||
@@ -220,42 +263,25 @@ and read_dict s =
|
||||
|
||||
|
||||
(** Parse a string into a list of SX values.
|
||||
When [~comments:true], top-level ;; comments are preserved as [Comment]
|
||||
nodes in the result list. Default is [false] (strip comments). *)
|
||||
When [~comments:true], comments are preserved as [Comment] nodes —
|
||||
both at top level and inside lists. Default is [false] (strip). *)
|
||||
let parse_all ?(comments=false) src =
|
||||
_preserve_comments := comments;
|
||||
let s = make_state src in
|
||||
let results = ref [] in
|
||||
let rec go () =
|
||||
if comments then begin
|
||||
skip_whitespace s;
|
||||
if at_end s then List.rev !results
|
||||
else if s.src.[s.pos] = ';' then begin
|
||||
(* Collect consecutive comment lines into one Comment node *)
|
||||
let lines = ref [] in
|
||||
let rec collect () =
|
||||
skip_whitespace s;
|
||||
if not (at_end s) && s.src.[s.pos] = ';' then begin
|
||||
lines := read_comment s :: !lines;
|
||||
collect ()
|
||||
end
|
||||
in
|
||||
collect ();
|
||||
let text = String.concat "\n" (List.rev !lines) in
|
||||
results := Comment text :: !results;
|
||||
go ()
|
||||
end else begin
|
||||
results := read_value s :: !results;
|
||||
go ()
|
||||
end
|
||||
end else begin
|
||||
skip_whitespace_and_comments s;
|
||||
if at_end s then List.rev !results
|
||||
else begin
|
||||
results := read_value s :: !results;
|
||||
go ()
|
||||
end
|
||||
if !_preserve_comments then skip_whitespace s
|
||||
else skip_whitespace_and_comments s;
|
||||
if at_end s then (
|
||||
_preserve_comments := false;
|
||||
List.rev !results
|
||||
) else begin
|
||||
results := read_value s :: !results;
|
||||
go ()
|
||||
end
|
||||
in go ()
|
||||
in
|
||||
try go ()
|
||||
with e -> _preserve_comments := false; raise e
|
||||
|
||||
(** Parse a file into a list of SX values. *)
|
||||
let parse_file ?(comments=false) path =
|
||||
|
||||
Reference in New Issue
Block a user