My agentic slop goes here. Not intended for anyone else!

more

Changed files
+94 -23
yaml
ocaml-yamle
+19 -18
yaml/ocaml-yamle/lib/parser.ml
···
let tok = current_token t in
match tok.token with
| Token.Flow_mapping_end ->
-
t.state <- Flow_mapping_key;
-
empty_scalar_event ~anchor:None ~tag:None tok.span
+
(* Trailing comma case - don't emit empty scalar, just return to key state *)
+
skip_token t;
+
t.state <- pop_state t;
+
Event.Mapping_end, tok.span
| Token.Key ->
skip_token t;
if check t (function
···
parse_stream_start t
| Implicit_document_start ->
-
if check t (function
-
| Token.Version_directive _ | Token.Tag_directive _
-
| Token.Document_start | Token.Stream_end -> true
-
| _ -> false)
-
then begin
-
if check t (function Token.Stream_end -> true | _ -> false) then begin
-
let tok = current_token t in
-
skip_token t;
-
t.state <- End;
-
t.finished <- true;
-
Event.Stream_end, tok.span
-
end else begin
-
parse_document_start t ~implicit:false
-
end
-
end else
-
parse_document_start t ~implicit:true
+
let tok = current_token t in
+
(match tok.token with
+
| Token.Stream_end ->
+
skip_token t;
+
t.state <- End;
+
t.finished <- true;
+
Event.Stream_end, tok.span
+
| Token.Version_directive _ | Token.Tag_directive _ | Token.Document_start ->
+
parse_document_start t ~implicit:false
+
(* These tokens are invalid at document start - they indicate leftover junk *)
+
| Token.Flow_sequence_end | Token.Flow_mapping_end | Token.Flow_entry
+
| Token.Block_end | Token.Value ->
+
Error.raise_span tok.span (Unexpected_token "unexpected token at document start")
+
| _ ->
+
parse_document_start t ~implicit:true)
| Document_start ->
parse_document_start t ~implicit:false
+44 -5
yaml/ocaml-yamle/lib/scanner.ml
···
(Invalid_escape_sequence (Printf.sprintf "\\%c" c)));
loop ()
| Some '\n' | Some '\r' ->
+
(* Per YAML spec: discard trailing whitespace before line break *)
+
let len = Buffer.length buf in
+
let rec trim_end i =
+
if i < 0 then 0
+
else match Buffer.nth buf i with
+
| ' ' | '\t' -> trim_end (i - 1)
+
| _ -> i + 1
+
in
+
Buffer.truncate buf (trim_end (len - 1));
Input.consume_break t.input;
-
(* Fold to space *)
-
Buffer.add_char buf ' ';
-
(* Skip leading whitespace *)
-
while Input.next_is_blank t.input do
-
ignore (Input.next t.input)
+
(* Count consecutive line breaks (empty lines) *)
+
let empty_lines = ref 0 in
+
let continue = ref true in
+
while !continue do
+
(* Skip blanks (spaces/tabs) on the line *)
+
while Input.next_is_blank t.input do
+
ignore (Input.next t.input)
+
done;
+
(* Check if we hit another line break (empty line) *)
+
if Input.next_is_break t.input then begin
+
Input.consume_break t.input;
+
incr empty_lines
+
end else
+
continue := false
done;
+
(* Per YAML spec: single break = space, break + empty lines = newlines *)
+
if !empty_lines > 0 then begin
+
(* Empty lines: output N newlines where N = number of empty lines *)
+
for _ = 1 to !empty_lines do
+
Buffer.add_char buf '\n'
+
done
+
end else
+
(* Single break folds to space *)
+
Buffer.add_char buf ' ';
loop ()
| Some c ->
Buffer.add_char buf c;
···
scan_lines ();
let value = Buffer.contents buf in
+
(* Trim trailing whitespace (spaces and tabs) *)
+
let value =
+
let len = String.length value in
+
let rec find_end i =
+
if i < 0 then 0
+
else match value.[i] with
+
| ' ' | '\t' -> find_end (i - 1)
+
| _ -> i + 1
+
in
+
let end_pos = find_end (len - 1) in
+
String.sub value 0 end_pos
+
in
let span = Span.make ~start ~stop:(Input.mark t.input) in
(value, span)
+21
yaml/ocaml-yamle/tests/dune
···
(test
(name test_yamle)
+
(modules test_yamle)
(libraries yamle alcotest))
+
+
; Shared library for test suite support modules
+
(library
+
(name test_suite_lib)
+
(modules tree_format test_suite_loader)
+
(libraries yamle))
+
+
; yaml-test-suite compliance tests
+
; Run with: dune exec tests/test_suite.exe
+
; Or: YAML_TEST_SUITE=/path/to/yaml-test-suite dune exec tests/test_suite.exe
+
(executable
+
(name test_suite)
+
(modules test_suite)
+
(libraries yamle alcotest test_suite_lib))
+
+
(executable
+
(name test_analyze)
+
(modules test_analyze)
+
(libraries yamle test_suite_lib))
+
+10
yaml/ocaml-yamle/tests/test_yamle.ml
···
| `O [("a", `Float 1.0); ("b", `Float 2.0)] -> ()
| _ -> Alcotest.fail "expected flow mapping {a: 1, b: 2}"
+
let test_parse_flow_mapping_trailing_comma () =
+
let result = of_string "{ a: 1, }" in
+
match result with
+
| `O [("a", `Float 1.0)] -> ()
+
| `O pairs ->
+
Alcotest.failf "expected 1 pair but got %d pairs (trailing comma should not create empty entry)"
+
(List.length pairs)
+
| _ -> Alcotest.fail "expected flow mapping with 1 pair"
+
let value_tests = [
"parse null", `Quick, test_parse_null;
"parse bool", `Quick, test_parse_bool;
···
"parse nested", `Quick, test_parse_nested;
"parse flow sequence", `Quick, test_parse_flow_sequence;
"parse flow mapping", `Quick, test_parse_flow_mapping;
+
"flow mapping trailing comma", `Quick, test_parse_flow_mapping_trailing_comma;
]
(** Emitter tests *)