packages feed

YamlReference-0.4: Text/Yaml/Reference.bnf

-- ** 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:

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

-- Separation:

s_separate n c = case c of
                      BlockIn  -> s_separate_in_line
                      BlockOut -> s_separate_in_line
                      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

-- 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 n c = nest BeginProperties
                    & ( ( c_ns_anchor_property & ( s_separate n c & c_ns_tag_property ?) )
                      / ( c_ns_tag_property & ( s_separate n c & c_ns_anchor_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 *)

-- 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 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 n c ?)
                          & ( c_collect_entry
                            & ( s_separate 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 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 n c ?)
                          & ( c_collect_entry
                            & ( s_separate 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 n c
                                 & ( "node" ^ c_flow_json_node n c ) ! "entry"
                                 & ( ( s_separate n c ?) & c_ns_flow_map_adjacent_value n c
                                   / e_node )
s_ns_flow_map_explicit_yaml  n c = s_separate n c
                                 & ( "node" ^ ns_flow_yaml_node n c ) ! "entry"
                                 & ( ( s_separate n c ?) & c_ns_flow_map_separate_value n c
                                   / e_node )
s_ns_flow_map_explicit_empty n c = s_separate 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 n c & ns_flow_node n c
                                   / e_node )
c_ns_flow_map_adjacent_value n c = c_mapping_value ! "pair"
                                 & ( ( s_separate 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 n c & s_separate n c ?)
                       & c_flow_json_content n c
                       & nest EndNode
ns_flow_yaml_node  n c = nest BeginNode
                       & ( c_ns_alias
                         / ( c_ns_properties n c
                           & ( s_separate n c & 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 n c
                           & ( s_separate n c & 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
                         & ( 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
                         & ( 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 n FlowOut & ns_flow_node (n .+ 1) FlowOut & s_l_comments
s_l__block_in_block n c = nest BeginNode
                        & ( s_separate n c & c_ns_properties n c ?)
                        & s_l__block_content n c
                        & nest EndNode
s_l__block_content  n c = s_separate n c & c_l__literal n
                        / s_separate n c & 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 )