-- ** Spec productions -- -- These are copied directly from the spec, with the addition of the occasional -- decision point and commitment. c_printable = '\x9' / '\xA' / '\xD' / ('\x20', '\x7E') / '\x85' / ('\xA0', '\xD7FF') / ('\xE000', '\xFFFD') / ('\x10000', '\x10FFFF') c_byte_order_mark = '\xFEFF' & detect_utf_encoding -- Indicators: c_sequence_entry = indicator '-' c_mapping_key = indicator '?' c_mapping_value = indicator ':' c_collect_entry = indicator ',' c_sequence_start = indicator '[' c_sequence_end = indicator ']' c_mapping_start = indicator '{' c_mapping_end = indicator '}' c_comment = indicator '#' c_anchor = indicator '&' c_alias = indicator '*' c_tag = indicator '!' c_literal = indicator '|' c_folded = indicator '>' c_single_quote = indicator '\'' c_double_quote = indicator '"' c_directive = indicator '%' c_reserved = indicator ( '@' / '`' ) c_indicator = c_sequence_entry / c_mapping_key / c_mapping_value / c_collect_entry / c_sequence_start / c_sequence_end / c_mapping_start / c_mapping_end / c_comment / c_anchor / c_alias / c_tag / c_literal / c_folded / c_single_quote / c_double_quote / c_directive / c_reserved c_flow_indicator = c_collect_entry / c_sequence_start / c_sequence_end / c_mapping_start / c_mapping_end -- Line breaks: b_line_feed = '\xA' b_carriage_return = '\xD' b_next_line = '\x85' b_line_separator = '\x2028' b_paragraph_separator = '\x2029' b_char = b_line_feed / b_carriage_return / b_next_line / b_line_separator / b_paragraph_separator b_specific = ( b_line_separator / b_paragraph_separator ) & nextLine b_generic = ( b_carriage_return & b_line_feed / b_carriage_return / b_line_feed / b_next_line ) & nextLine b_as_line_feed = token LineFeed b_generic b_normalized = b_as_line_feed / token Break b_specific b_ignored_generic = token Continue b_generic b_ignored_any = b_ignored_generic / token Continue b_specific -- Chars: nb_char = c_printable - b_char s_space = '\x20' s_tab = '\x9' s_white = s_space / s_tab ns_char = nb_char - s_white ns_dec_digit = ('\x30', '\x39') ns_hex_digit = ns_dec_digit / ('\x41', '\x46') / ('\x61', '\x66') ns_ascii_letter = ('\x41', '\x5A') / ('\x61', '\x7A') ns_word_char = ns_dec_digit / ns_ascii_letter / '-' ns_uri_char = "escape" ^ ( ns_word_char / '%' ! "escape" & ns_hex_digit & ns_hex_digit / ';' / '/' / '?' / ':' / '@' / '&' / '=' / '+' / '$' / ',' / '_' / '.' / '!' / '~' / '*' / '\'' / '(' / ')' / '[' / ']' ) ns_tag_char = ns_uri_char - c_tag -- Escape: c_escape = indicator '\\' ns_esc_null = meta '0' ns_esc_bell = meta 'a' ns_esc_backspace = meta 'b' ns_esc_horizontal_tab = meta ( 't' / '\x9' ) ns_esc_line_feed = meta 'n' ns_esc_vertical_tab = meta 'v' ns_esc_form_feed = meta 'f' ns_esc_carriage_return = meta 'r' ns_esc_escape = meta 'e' ns_esc_space = meta '\x20' ns_esc_double_quote = meta '"' ns_esc_backslash = meta '\\' ns_esc_next_line = meta 'N' ns_esc_non_breaking_space = meta '_' ns_esc_line_separator = meta 'L' ns_esc_paragraph_separator = meta 'P' ns_esc_8_bit = indicator 'x' ! "escaped" & meta ( ns_hex_digit % 2 ) ns_esc_16_bit = indicator 'u' ! "escaped" & meta ( ns_hex_digit % 4 ) ns_esc_32_bit = indicator 'U' ! "escaped" & meta ( ns_hex_digit % 8 ) ns_esc_char = nest BeginEscape & c_escape ! "escape" & "escaped" ^ ( ns_esc_null / ns_esc_bell / ns_esc_backspace / ns_esc_horizontal_tab / ns_esc_line_feed / ns_esc_vertical_tab / ns_esc_form_feed / ns_esc_carriage_return / ns_esc_escape / ns_esc_space / ns_esc_double_quote / ns_esc_backslash / ns_esc_next_line / ns_esc_non_breaking_space / ns_esc_line_separator / ns_esc_paragraph_separator / ns_esc_8_bit / ns_esc_16_bit / ns_esc_32_bit ) & nest EndEscape -- Spaces: s_indent n = token Indent ( s_space % n ) s_indent_lt n = token Indent ( s_space <% n ) s_indent_le n = token Indent ( s_space <% (n .+ 1) ) s_separate_in_line = token White ( s_white +) / sol -- Empty lines s_ignored_prefix n s = case s of Plain -> s_ignored_prefix_flow n Double -> s_ignored_prefix_flow n Single -> s_ignored_prefix_flow n Literal -> s_ignored_prefix_block n Folded -> s_ignored_prefix_block n s_ignored_prefix_flow n = s_indent n & ( s_separate_in_line ?) s_ignored_prefix_block n = s_indent n l_empty n s = ( s_ignored_prefix n s / s_indent_lt n ) & b_normalized -- Comments: TODO c_nb_comment_text = nest BeginComment & c_comment & meta ( nb_char *) & nest EndComment s_b_comment = ( s_separate_in_line & ( c_nb_comment_text ?) ?) & b_ignored_any s_l_comments = ( s_b_comment / sol ) & ( l_comment *) l_comment = s_separate_in_line & ( c_nb_comment_text ?) & b_ignored_any -- Folding: b_l_folded_specific n s = token Break b_specific & ( l_empty n s *) b_l_folded_as_space = token LineFold b_generic b_l_folded_trimmed n s = b_ignored_generic & ( l_empty n s +) b_l_folded_any n s = b_l_folded_specific n s / b_l_folded_trimmed n s / b_l_folded_as_space s_l_flow_folded n = ( s_separate_in_line ?) & b_l_folded_any n Plain -- Directives: l_directive = nest BeginDirective & c_directive & "directive" ^ ( ns_yaml_directive / ns_tag_directive / ns_reserved_directive ) & nest EndDirective & s_l_comments ns_reserved_directive = ns_directive_name & ( s_separate_in_line & ns_directive_parameter *) ns_directive_name = meta ( ns_char +) ns_directive_parameter = meta ( ns_char +) -- Yaml directive: ns_yaml_directive = meta [ 'Y', 'A', 'M', 'L' ] ! "directive" & s_separate_in_line & ns_yaml_version ns_yaml_version = meta ( ( ns_dec_digit +) & '.' & ( ns_dec_digit +) ) -- Tag directive: ns_tag_directive = meta [ 'T', 'A', 'G' ] ! "directive" & s_separate_in_line & c_tag_handle & s_separate_in_line & ns_tag_prefix c_tag_handle = c_named_tag_handle / c_secondary_tag_handle / c_primary_tag_handle c_primary_tag_handle = nest BeginHandle & c_tag & nest EndHandle c_secondary_tag_handle = nest BeginHandle & c_tag & c_tag & nest EndHandle c_named_tag_handle = nest BeginHandle & c_tag & meta ( ns_word_char +) & c_tag & nest EndHandle ns_tag_prefix = nest BeginTag & ( c_ns_local_tag_prefix / ns_global_tag_prefix ) & nest EndTag c_ns_local_tag_prefix = c_tag & meta ( ns_uri_char *) ns_global_tag_prefix = meta ( ns_tag_char & ( ns_uri_char *) ) -- Properties: c_ns_properties = nest BeginProperties & c_ns_property & ( s_separate_in_line & c_ns_property *) & nest EndProperties c_ns_property = c_ns_anchor_property / c_ns_tag_property -- Tag: c_ns_tag_property = nest BeginTag & ( c_verbatim_tag / c_ns_shorthand_tag / c_non_specific_tag ) & nest EndTag c_verbatim_tag = c_tag & indicator '<' & meta ( ns_uri_char +) & indicator '>' c_ns_shorthand_tag = c_named_tag_handle & meta ( ns_uri_char +) / c_secondary_tag_handle & meta ( ns_uri_char +) / c_primary_tag_handle & meta ( ns_tag_char +) c_non_specific_tag = c_tag -- Anchor: c_ns_anchor_property = nest BeginAnchor & c_anchor & ns_anchor_name & nest EndAnchor ns_anchor_char = ns_char - c_flow_indicator ns_anchor_name = meta ( ns_anchor_char +) -- Double: nb_double_char = "escape" ^ ( ns_esc_char / nb_char - c_escape - c_double_quote ) ns_double_char = nb_double_char - s_white c_double_quoted n c = nest BeginScalar & c_double_quote ! "node" & text ( nb_double_text n c ) & c_double_quote & nest EndScalar nb_double_text n c = case c of FlowOut -> s_double_multi n FlowIn -> s_double_multi n FlowKey -> ( nb_double_char *) s_double_multi n = ( s_ns_double_chars *) & ( s_ns_double_next n *) & ( s_white *) s_ns_double_chars = ( s_white *) & ns_double_char s_ns_double_next n = s_l_double_any n & s_ignored_prefix n Double & ( ns_double_char & ( s_ns_double_chars *) ?) s_l_double_any n = "escape" ^ ( s_b_double_escaped / s_l_flow_folded n ) s_b_double_escaped = ( s_white *) & nest BeginEscape & c_escape ! "escape" & b_ignored_any & nest EndEscape -- Single: c_quoted_quote = nest BeginEscape & c_single_quote ! "escape" & meta '\'' & nest EndEscape nb_single_char = "escape" ^ ( c_quoted_quote / nb_char - c_single_quote ) ns_single_char = nb_single_char - s_white c_single_quoted n c = nest BeginScalar & c_single_quote & text ( nb_single_text n c ) & c_single_quote & nest EndScalar nb_single_text n c = case c of FlowOut -> s_single_multi n FlowIn -> s_single_multi n FlowKey -> ( nb_single_char *) s_ns_single_chars = ( s_white *) & ns_single_char s_single_multi n = ( s_ns_single_chars *) & ( s_ns_single_next n *) & ( s_white *) s_ns_single_next n = s_l_flow_folded n & s_ignored_prefix n Double & ( ns_single_char & ( s_ns_single_chars *) ?) -- Plain: ns_plain_safe c = case c of FlowOut -> ns_plain_safe_out FlowIn -> ns_plain_safe_in FlowKey -> ns_plain_safe_in ns_plain_safe_out = ns_char - c_mapping_value - c_comment ns_plain_safe_in = ns_plain_safe_out - c_flow_indicator ns_plain_char c = ( ':' +) & ( '#' / ns_plain_safe c ) & ( '#' *) / ns_plain_safe c & ( '#' *) nb_plain_char c = s_white / ns_plain_char c ns_plain_first c = ( '-' / '?' / ':' ) & ( ( '#' +) / ns_plain_char c ) / ns_plain_char c - c_indicator ns_plain n c = nest BeginScalar & text (case c of FlowOut -> ns_plain_multi n c FlowIn -> ns_plain_multi n c FlowKey -> ns_plain_single c) & nest EndScalar ns_plain_single c = ns_plain_first c ! "node" & ( s_ns_plain_chars c *) s_ns_plain_chars c = ( s_white *) & ns_plain_char c ns_plain_multi n c = ns_plain_single c & ( s_ns_plain_next n c *) s_ns_plain_next n c = s_l_flow_folded n & s_ignored_prefix n Plain & ns_plain_char c & ( s_ns_plain_chars c *) -- Separation: TODO s_separate_in_flow n c = case c of FlowOut -> s_separate_lines n FlowIn -> s_separate_lines n FlowKey -> s_separate_in_line s_separate_lines n = s_l_comments & s_ignored_prefix_flow n / s_separate_in_line -- Flow collection: in_flow c = case c of FlowOut -> FlowIn FlowIn -> FlowIn FlowKey -> FlowKey -- Flow sequence: c_flow_sequence n c = nest BeginSequence & c_sequence_start ! "node" & ( s_separate_in_flow n c ?) & ( ns_s_flow_seq_entries n (in_flow c) ?) & c_sequence_end & nest EndSequence ns_s_flow_seq_entries n c = ns_flow_seq_entry n c & ( s_separate_in_flow n c ?) & ( c_collect_entry & ( s_separate_in_flow n c ?) & ( ns_s_flow_seq_entries n c ?) ?) ns_flow_seq_entry n c = "pair" ^ ( ns_flow_map_single_pair n c / "node" ^ ns_flow_node n c ) -- Flow mapping: c_flow_mapping n c = nest BeginMapping & c_mapping_start ! "node" & ( s_separate_in_flow n c ?) & ( ns_s_flow_map_entries n (in_flow c) ?) & c_mapping_end & nest EndMapping ns_s_flow_map_entries n c = ns_flow_map_entry n c & ( s_separate_in_flow n c ?) & ( c_collect_entry & ( s_separate_in_flow n c ?) & ( ns_s_flow_map_entries n c ?) ?) ns_flow_map_entry n c = nest BeginPair & "pair" ^ ( c_mapping_key ! "pair" & s_ns_flow_map_explicit_entry n c / ns_flow_map_implicit_entry n c ) & nest EndPair s_ns_flow_map_explicit_entry n c = "entry" ^ ( s_ns_flow_map_explicit_json n c / s_ns_flow_map_explicit_yaml n c / s_ns_flow_map_explicit_empty n c / e_node & e_node ) s_ns_flow_map_explicit_json n c = s_separate_in_flow n c & ( "node" ^ c_flow_json_node n c ) ! "entry" & ( ( s_separate_in_flow n c ?) & c_ns_flow_map_adjacent_value n c / e_node ) s_ns_flow_map_explicit_yaml n c = s_separate_in_flow n c & ( "node" ^ ns_flow_yaml_node n c ) ! "entry" & ( ( s_separate_in_flow n c ?) & c_ns_flow_map_separate_value n c / e_node ) s_ns_flow_map_explicit_empty n c = s_separate_in_flow n c & e_node & c_ns_flow_map_separate_value n c c_ns_flow_map_separate_value n c = c_mapping_value ! "pair" & ( s_separate_in_flow n c & ns_flow_node n c / e_node ) c_ns_flow_map_adjacent_value n c = c_mapping_value ! "pair" & ( ( s_separate_in_flow n c ?) & ns_flow_node n c / e_node ) ns_flow_map_implicit_entry n c = c_ns_flow_map_implicit_json n c / ns_flow_map_implicit_yaml n c / ns_flow_map_implicit_empty n c c_ns_flow_map_implicit_json n c = c_s_simple_json_key & ( c_ns_flow_map_adjacent_value n c / e_node ) ns_flow_map_implicit_yaml n c = ns_s_simple_yaml_key & ( c_ns_flow_map_separate_value n c / e_node ) ns_flow_map_implicit_empty n c = e_node & c_ns_flow_map_separate_value n c c_s_simple_json_key = ( "node" ^ ( c_flow_json_node na FlowKey ) & ( s_separate_in_line ?) ) `limitedTo` 1024 ns_s_simple_yaml_key = ( "node" ^ ( ns_flow_yaml_node na FlowKey ) & ( s_separate_in_line ?) ) `limitedTo` 1024 ns_flow_map_single_pair n c = nest BeginMapping & nest BeginPair & ( c_mapping_key ! "pair" & s_ns_flow_map_explicit_entry n c / ns_flow_map_single_entry n c ) & nest EndPair & nest EndMapping ns_flow_map_single_entry n c = "entry" ^ ( c_ns_flow_map_single_json n c / ns_flow_map_single_yaml n c / ns_flow_map_implicit_empty n c ) c_ns_flow_map_single_json n c = c_s_simple_json_key & c_ns_flow_map_adjacent_value n c ns_flow_map_single_yaml n c = ns_s_simple_yaml_key & c_ns_flow_map_separate_value n c -- Alias: c_ns_alias = nest BeginAlias & c_alias ! "node" & ns_anchor_name & nest EndAlias -- Empty: e_scalar = nest BeginScalar & nest EndScalar e_node = nest BeginNode & e_scalar & nest EndNode -- Flow node: ns_flow_content n c = c_flow_json_content n c / ns_flow_yaml_content n c c_flow_json_content n c = c_flow_sequence n c / c_flow_mapping n c / c_single_quoted n c / c_double_quoted n c ns_flow_yaml_content n c = ns_plain n c c_flow_json_node n c = nest BeginNode & ( c_ns_properties & s_separate_in_line ?) & c_flow_json_content n c & nest EndNode ns_flow_yaml_node n c = nest BeginNode & ( c_ns_alias / ( c_ns_properties & ( s_separate_in_line & ns_flow_yaml_content n c / e_scalar ) ) / ns_flow_yaml_content n c ) & nest EndNode ns_flow_node n c = nest BeginNode & ( c_ns_alias / ( c_ns_properties & ( s_separate_in_line & ns_flow_content n c / e_scalar ) ) / ns_flow_content n c ) & nest EndNode -- Block scalar: c_indentation_indicator n = indicator ( ns_dec_digit - '0' ) & asInteger / detect_scalar_indentation n detect_scalar_indentation n = peek $ ( nb_char *) & ( b_ignored_any & ( l_empty n Literal *) ?) & count_spaces (-n) count_spaces n = (s_space & count_spaces (n .+ 1)) / result (max 1 n) c_style_indicator s = case s of Literal -> indicator '|' Folded -> indicator '>' c_chomping_indicator = indicator '-' & result Strip / indicator '+' ! "header" & result Keep / result Clip c_b__block_header n s = c_style_indicator s ! "node" & "header" ^ ( do t <- c_chomping_indicator m <- c_indentation_indicator n ( s_white / b_char ) ?! "header" s_b_comment result (m, t) / do m <- c_indentation_indicator n t <- c_chomping_indicator s_b_comment result (m, t) ) -- Chomping: b_chomped_last t = case t of Strip -> nest EndScalar & b_ignored_any Clip -> b_normalized & nest EndScalar Keep -> b_normalized l_chomped_empty n t = case t of Strip -> l_strip_empty n Clip -> l_strip_empty n Keep -> l_keep_empty n l_strip_empty n = ( s_indent_le n & b_ignored_any *) & ( l_trail_comments n ?) l_keep_empty n = ( s_indent_le n & b_normalized *) & nest EndScalar & ( l_trail_comments n ?) l_trail_comments n = s_indent_lt n & c_nb_comment_text & b_ignored_any & ( l_comment *) -- Literal: c_l__literal n = do nest BeginScalar (m, t) <- c_b__block_header n Literal text ( l_literal_content (n .+ m) t ) l_nb_literal_chars n = ( l_empty n Literal *) & s_indent n & ( nb_char +) b_l_literal_next n = b_normalized & l_nb_literal_chars n l_literal_content n t = ( l_nb_literal_chars n & ( b_l_literal_next n *) & b_chomped_last t ?) & l_chomped_empty n t -- Folded: c_l__folded n = do nest BeginScalar (m, t) <- c_b__block_header n Folded text ( l_folded_content (n .+ m) t ) s_nb_folded_text n = s_indent n & ns_char ! "fold" & ( nb_char *) l_nb_folded_lines n = s_nb_folded_text n & ( b_l_folded_any n Folded & s_nb_folded_text n *) l_nb_start_with_folded n = ( l_empty n Folded *) & l_nb_folded_lines n & "fold" ^ ( b_normalized & l_nb_start_with_spaced n ?) s_nb_spaced_text n = s_indent n & s_white ! "fold" & ( nb_char *) b_l_spaced n = b_normalized & ( l_empty n Folded *) l_nb_spaced_lines n = s_nb_spaced_text n & ( b_l_spaced n & s_nb_spaced_text n *) l_nb_start_with_spaced n = ( l_empty n Folded *) & l_nb_spaced_lines n & "fold" ^ ( b_normalized & l_nb_start_with_folded n ?) l_nb_start_with_any n = "fold" ^ ( l_nb_start_with_folded n / l_nb_start_with_spaced n ) l_folded_content n t = ( l_nb_start_with_any n & b_chomped_last t ?) & l_chomped_empty n t -- Block sequence: seq_spaces n c = case c of BlockOut -> n BlockIn -> n .- 1 l__block_sequence n = do m <- detect_collection_indentation n ( nest BeginSequence & ( s_indent (n .+ m) & c_l_block_seq_entry (n .+ m) +) & nest EndSequence ) detect_collection_indentation n = peek $ ( l_comment* ) & count_spaces (-n) c_l_block_seq_entry n = c_sequence_entry ! "node" & s_l__block_indented n BlockOut s_l__block_indented n c = do m <- detect_inline_indentation ( s_indent m & "node" ^ ( ns_l_in_line_sequence (n .+ 1 .+ m) / ns_l_in_line_mapping (n .+ 1 .+ m) ) ) / s_l__block_node n c / e_node & s_l_comments detect_inline_indentation = peek $ count_spaces 0 ns_l_in_line_sequence n = nest BeginNode & nest BeginSequence & c_l_block_seq_entry n & ( s_indent n & c_l_block_seq_entry n *) & nest EndSequence & nest EndNode -- Block mapping: l__block_mapping n = do m <- detect_collection_indentation n ( nest BeginMapping & ( s_indent (n .+ m) & ns_l_block_map_entry (n .+ m) +) & nest EndMapping ) ns_l_block_map_entry n = nest BeginPair & ( c_l_block_map_explicit_entry n / ns_l_block_map_implicit_entry n ) & nest EndPair c_l_block_map_explicit_entry n = c_l_block_map_explicit_key n & ( l_block_map_explicit_value n / e_node ) c_l_block_map_explicit_key n = c_mapping_key ! "node" & s_l__block_indented n BlockIn l_block_map_explicit_value n = s_indent n & c_mapping_value & s_l__block_indented n BlockIn ns_l_block_map_implicit_entry n = ns_s_block_map_implicit_key & c_l_block_map_implicit_value n / e_node & c_l_block_map_implicit_value n ns_s_block_map_implicit_key = c_s_simple_json_key / ns_s_simple_yaml_key c_l_block_map_implicit_value n = c_mapping_value ! "node" & ( s_l__block_node n BlockIn / e_node & s_l_comments ) ns_l_in_line_mapping n = nest BeginNode & nest BeginMapping & ns_l_block_map_entry n & ( s_indent n & ns_l_block_map_entry n *) & nest EndMapping & nest EndNode -- Block node: s_l__block_node n c = s_l__block_in_block n c / s_l__flow_in_block n s_l__flow_in_block n = s_separate_in_line & ns_flow_node (n .+ 1) FlowOut & s_l_comments s_l__block_in_block n c = nest BeginNode & ( s_separate_in_line & c_ns_properties ?) & s_l__block_content n c & nest EndNode s_l__block_content n c = s_separate_in_line & c_l__literal n / s_separate_in_line & c_l__folded n / s_l_comments & l__block_sequence (seq_spaces n c) / s_l_comments & l__block_mapping n -- Document: c_document_start = token DocumentStart [ '-', '-', '-' ] c_document_end = token DocumentEnd [ '.', '.', '.' ] l_document_prefix = ( c_byte_order_mark ?) & ( l_comment *) l_document_suffix = c_document_end & s_l_comments l_forbidden = sol & ( c_document_start / c_document_end ) & ( b_char / s_white / eof ) l_implicit_document = nest BeginDocument & s_l__block_node (-1) BlockOut `forbidding` l_forbidden & nest EndDocument l_explicit_document = nest BeginDocument & ( l_directive ! "doc" *) & c_document_start ! "doc" & "node" ^ ( l_implicit_document / e_node & s_l_comments ) & nest EndDocument e_no_document = empty -- Stream: l_yaml_stream = nest BeginStream & l_documents & ( l_document_suffix & l_documents *) & nest EndStream l_documents = l_leading_document & ( l_following_document *) l_leading_document = l_document_prefix & "doc" ^ ( l_explicit_document / "node" ^ ( l_implicit_document / e_no_document ) ) l_following_document = l_document_prefix & "doc" ^ ( l_explicit_document / e_no_document )