this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more

+94 -23
+19 -18
yaml/ocaml-yamle/lib/parser.ml
··· 527 527 let tok = current_token t in 528 528 match tok.token with 529 529 | Token.Flow_mapping_end -> 530 - t.state <- Flow_mapping_key; 531 - empty_scalar_event ~anchor:None ~tag:None tok.span 530 + (* Trailing comma case - don't emit empty scalar, just return to key state *) 531 + skip_token t; 532 + t.state <- pop_state t; 533 + Event.Mapping_end, tok.span 532 534 | Token.Key -> 533 535 skip_token t; 534 536 if check t (function ··· 575 577 parse_stream_start t 576 578 577 579 | Implicit_document_start -> 578 - if check t (function 579 - | Token.Version_directive _ | Token.Tag_directive _ 580 - | Token.Document_start | Token.Stream_end -> true 581 - | _ -> false) 582 - then begin 583 - if check t (function Token.Stream_end -> true | _ -> false) then begin 584 - let tok = current_token t in 585 - skip_token t; 586 - t.state <- End; 587 - t.finished <- true; 588 - Event.Stream_end, tok.span 589 - end else begin 590 - parse_document_start t ~implicit:false 591 - end 592 - end else 593 - parse_document_start t ~implicit:true 580 + let tok = current_token t in 581 + (match tok.token with 582 + | Token.Stream_end -> 583 + skip_token t; 584 + t.state <- End; 585 + t.finished <- true; 586 + Event.Stream_end, tok.span 587 + | Token.Version_directive _ | Token.Tag_directive _ | Token.Document_start -> 588 + parse_document_start t ~implicit:false 589 + (* These tokens are invalid at document start - they indicate leftover junk *) 590 + | Token.Flow_sequence_end | Token.Flow_mapping_end | Token.Flow_entry 591 + | Token.Block_end | Token.Value -> 592 + Error.raise_span tok.span (Unexpected_token "unexpected token at document start") 593 + | _ -> 594 + parse_document_start t ~implicit:true) 594 595 595 596 | Document_start -> 596 597 parse_document_start t ~implicit:false
+44 -5
yaml/ocaml-yamle/lib/scanner.ml
··· 367 367 (Invalid_escape_sequence (Printf.sprintf "\\%c" c))); 368 368 loop () 369 369 | Some '\n' | Some '\r' -> 370 + (* Per YAML spec: discard trailing whitespace before line break *) 371 + let len = Buffer.length buf in 372 + let rec trim_end i = 373 + if i < 0 then 0 374 + else match Buffer.nth buf i with 375 + | ' ' | '\t' -> trim_end (i - 1) 376 + | _ -> i + 1 377 + in 378 + Buffer.truncate buf (trim_end (len - 1)); 370 379 Input.consume_break t.input; 371 - (* Fold to space *) 372 - Buffer.add_char buf ' '; 373 - (* Skip leading whitespace *) 374 - while Input.next_is_blank t.input do 375 - ignore (Input.next t.input) 380 + (* Count consecutive line breaks (empty lines) *) 381 + let empty_lines = ref 0 in 382 + let continue = ref true in 383 + while !continue do 384 + (* Skip blanks (spaces/tabs) on the line *) 385 + while Input.next_is_blank t.input do 386 + ignore (Input.next t.input) 387 + done; 388 + (* Check if we hit another line break (empty line) *) 389 + if Input.next_is_break t.input then begin 390 + Input.consume_break t.input; 391 + incr empty_lines 392 + end else 393 + continue := false 376 394 done; 395 + (* Per YAML spec: single break = space, break + empty lines = newlines *) 396 + if !empty_lines > 0 then begin 397 + (* Empty lines: output N newlines where N = number of empty lines *) 398 + for _ = 1 to !empty_lines do 399 + Buffer.add_char buf '\n' 400 + done 401 + end else 402 + (* Single break folds to space *) 403 + Buffer.add_char buf ' '; 377 404 loop () 378 405 | Some c -> 379 406 Buffer.add_char buf c; ··· 469 496 470 497 scan_lines (); 471 498 let value = Buffer.contents buf in 499 + (* Trim trailing whitespace (spaces and tabs) *) 500 + let value = 501 + let len = String.length value in 502 + let rec find_end i = 503 + if i < 0 then 0 504 + else match value.[i] with 505 + | ' ' | '\t' -> find_end (i - 1) 506 + | _ -> i + 1 507 + in 508 + let end_pos = find_end (len - 1) in 509 + String.sub value 0 end_pos 510 + in 472 511 let span = Span.make ~start ~stop:(Input.mark t.input) in 473 512 (value, span) 474 513
+21
yaml/ocaml-yamle/tests/dune
··· 1 1 (test 2 2 (name test_yamle) 3 + (modules test_yamle) 3 4 (libraries yamle alcotest)) 5 + 6 + ; Shared library for test suite support modules 7 + (library 8 + (name test_suite_lib) 9 + (modules tree_format test_suite_loader) 10 + (libraries yamle)) 11 + 12 + ; yaml-test-suite compliance tests 13 + ; Run with: dune exec tests/test_suite.exe 14 + ; Or: YAML_TEST_SUITE=/path/to/yaml-test-suite dune exec tests/test_suite.exe 15 + (executable 16 + (name test_suite) 17 + (modules test_suite) 18 + (libraries yamle alcotest test_suite_lib)) 19 + 20 + (executable 21 + (name test_analyze) 22 + (modules test_analyze) 23 + (libraries yamle test_suite_lib)) 24 +
+10
yaml/ocaml-yamle/tests/test_yamle.ml
··· 128 128 | `O [("a", `Float 1.0); ("b", `Float 2.0)] -> () 129 129 | _ -> Alcotest.fail "expected flow mapping {a: 1, b: 2}" 130 130 131 + let test_parse_flow_mapping_trailing_comma () = 132 + let result = of_string "{ a: 1, }" in 133 + match result with 134 + | `O [("a", `Float 1.0)] -> () 135 + | `O pairs -> 136 + Alcotest.failf "expected 1 pair but got %d pairs (trailing comma should not create empty entry)" 137 + (List.length pairs) 138 + | _ -> Alcotest.fail "expected flow mapping with 1 pair" 139 + 131 140 let value_tests = [ 132 141 "parse null", `Quick, test_parse_null; 133 142 "parse bool", `Quick, test_parse_bool; ··· 138 147 "parse nested", `Quick, test_parse_nested; 139 148 "parse flow sequence", `Quick, test_parse_flow_sequence; 140 149 "parse flow mapping", `Quick, test_parse_flow_mapping; 150 + "flow mapping trailing comma", `Quick, test_parse_flow_mapping_trailing_comma; 141 151 ] 142 152 143 153 (** Emitter tests *)