duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

parse.hpp (33234B)


      1 #ifndef _C4_YML_PARSE_HPP_
      2 #define _C4_YML_PARSE_HPP_
      3 
      4 #ifndef _C4_YML_TREE_HPP_
      5 #include "c4/yml/tree.hpp"
      6 #endif
      7 
      8 #ifndef _C4_YML_NODE_HPP_
      9 #include "c4/yml/node.hpp"
     10 #endif
     11 
     12 #ifndef _C4_YML_DETAIL_STACK_HPP_
     13 #include "c4/yml/detail/stack.hpp"
     14 #endif
     15 
     16 #include <stdarg.h>
     17 
     18 #if defined(_MSC_VER)
     19 #   pragma warning(push)
     20 #   pragma warning(disable: 4251/*needs to have dll-interface to be used by clients of struct*/)
     21 #endif
     22 
     23 namespace c4 {
     24 namespace yml {
     25 
     26 struct RYML_EXPORT ParserOptions
     27 {
     28 private:
     29 
     30     typedef enum : uint32_t {
     31         LOCATIONS = (1 << 0),
     32         DEFAULTS = 0,
     33     } Flags_e;
     34 
     35     uint32_t flags = DEFAULTS;
     36 public:
     37     ParserOptions() = default;
     38 
     39     /** @name source location tracking */
     40     /** @{ */
     41 
     42     /** enable/disable source location tracking */
     43     ParserOptions& locations(bool enabled)
     44     {
     45         if(enabled)
     46             flags |= LOCATIONS;
     47         else
     48             flags &= ~LOCATIONS;
     49         return *this;
     50     }
     51     bool locations() const { return (flags & LOCATIONS) != 0u; }
     52 
     53     /** @} */
     54 };
     55 
     56 
     57 //-----------------------------------------------------------------------------
     58 //-----------------------------------------------------------------------------
     59 //-----------------------------------------------------------------------------
     60 class RYML_EXPORT Parser
     61 {
     62 public:
     63 
     64     /** @name construction and assignment */
     65     /** @{ */
     66 
     67     Parser(Callbacks const& cb, ParserOptions opts={});
     68     Parser(ParserOptions opts={}) : Parser(get_callbacks(), opts) {}
     69     ~Parser();
     70 
     71     Parser(Parser &&);
     72     Parser(Parser const&);
     73     Parser& operator=(Parser &&);
     74     Parser& operator=(Parser const&);
     75 
     76     /** @} */
     77 
     78 public:
     79 
     80     /** @name modifiers */
     81     /** @{ */
     82 
     83     /** Reserve a certain capacity for the parsing stack.
     84      * This should be larger than the expected depth of the parsed
     85      * YAML tree.
     86      *
     87      * The parsing stack is the only (potential) heap memory used by
     88      * the parser.
     89      *
     90      * If the requested capacity is below the default
     91      * stack size of 16, the memory is used directly in the parser
     92      * object; otherwise it will be allocated from the heap.
     93      *
     94      * @note this reserves memory only for the parser itself; all the
     95      * allocations for the parsed tree will go through the tree's
     96      * allocator.
     97      *
     98      * @note the tree and the arena can (and should) also be reserved. */
     99     void reserve_stack(size_t capacity)
    100     {
    101         m_stack.reserve(capacity);
    102     }
    103 
    104     /** Reserve a certain capacity for the array used to track node
    105      * locations in the source buffer. */
    106     void reserve_locations(size_t num_source_lines)
    107     {
    108         _resize_locations(num_source_lines);
    109     }
    110 
    111     /** Reserve a certain capacity for the character arena used to
    112      * filter scalars. */
    113     void reserve_filter_arena(size_t num_characters)
    114     {
    115         _resize_filter_arena(num_characters);
    116     }
    117 
    118     /** @} */
    119 
    120 public:
    121 
    122     /** @name getters and modifiers */
    123     /** @{ */
    124 
    125     /** Get the current callbacks in the parser. */
    126     Callbacks callbacks() const { return m_stack.m_callbacks; }
    127 
    128     /** Get the name of the latest file parsed by this object. */
    129     csubstr filename() const { return m_file; }
    130 
    131     /** Get the latest YAML buffer parsed by this object. */
    132     csubstr source() const { return m_buf; }
    133 
    134     size_t stack_capacity() const { return m_stack.capacity(); }
    135     size_t locations_capacity() const { return m_newline_offsets_capacity; }
    136     size_t filter_arena_capacity() const { return m_filter_arena.len; }
    137 
    138     ParserOptions const& options() const { return m_options; }
    139 
    140     /** @} */
    141 
    142 public:
    143 
    144     /** @name parse_in_place */
    145     /** @{ */
    146 
    147     /** Create a new tree and parse into its root.
    148      * The tree is created with the callbacks currently in the parser. */
    149     Tree parse_in_place(csubstr filename, substr src)
    150     {
    151         Tree t(callbacks());
    152         t.reserve(_estimate_capacity(src));
    153         this->parse_in_place(filename, src, &t, t.root_id());
    154         return t;
    155     }
    156 
    157     /** Parse into an existing tree, starting at its root node.
    158      * The callbacks in the tree are kept, and used to allocate
    159      * the tree members, if any allocation is required. */
    160     void parse_in_place(csubstr filename, substr src, Tree *t)
    161     {
    162         this->parse_in_place(filename, src, t, t->root_id());
    163     }
    164 
    165     /** Parse into an existing node.
    166      * The callbacks in the tree are kept, and used to allocate
    167      * the tree members, if any allocation is required. */
    168     void parse_in_place(csubstr filename, substr src, Tree *t, size_t node_id);
    169     //   ^^^^^^^^^^^^^ this is the workhorse overload; everything else is syntactic candy
    170 
    171     /** Parse into an existing node.
    172      * The callbacks in the tree are kept, and used to allocate
    173      * the tree members, if any allocation is required. */
    174     void parse_in_place(csubstr filename, substr src, NodeRef node)
    175     {
    176         this->parse_in_place(filename, src, node.tree(), node.id());
    177     }
    178 
    179     RYML_DEPRECATED("use parse_in_place() instead") Tree parse(csubstr filename, substr src) { return parse_in_place(filename, src); }
    180     RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, Tree *t) { parse_in_place(filename, src, t); }
    181     RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, Tree *t, size_t node_id) { parse_in_place(filename, src, t, node_id); }
    182     RYML_DEPRECATED("use parse_in_place() instead") void parse(csubstr filename, substr src, NodeRef node) { parse_in_place(filename, src, node); }
    183 
    184     /** @} */
    185 
    186 public:
    187 
    188     /** @name parse_in_arena: copy the YAML source buffer to the
    189      * tree's arena, then parse the copy in situ
    190      *
    191      * @note overloads receiving a substr YAML buffer are intentionally
    192      * left undefined, such that calling parse_in_arena() with a substr
    193      * will cause a linker error. This is to prevent an accidental
    194      * copy of the source buffer to the tree's arena, because substr
    195      * is implicitly convertible to csubstr. If you really intend to parse
    196      * a mutable buffer in the tree's arena, convert it first to immutable
    197      * by assigning the substr to a csubstr prior to calling parse_in_arena().
    198      * This is not needed for parse_in_place() because csubstr is not
    199      * implicitly convertible to substr. */
    200     /** @{ */
    201 
    202     // READ THE NOTE ABOVE!
    203     #define RYML_DONT_PARSE_SUBSTR_IN_ARENA "Do not pass a (mutable) substr to parse_in_arena(); if you have a substr, it should be parsed in place. Consider using parse_in_place() instead, or convert the buffer to csubstr prior to calling. This function is deliberately left undefined and will cause a linker error."
    204     RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr csrc);
    205     RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, Tree *t);
    206     RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, Tree *t, size_t node_id);
    207     RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr csrc, NodeRef node);
    208 
    209     /** Create a new tree and parse into its root.
    210      * The immutable YAML source is first copied to the tree's arena,
    211      * and parsed from there.
    212      * The callbacks in the tree are kept, and used to allocate
    213      * the tree members, if any allocation is required. */
    214     Tree parse_in_arena(csubstr filename, csubstr csrc)
    215     {
    216         Tree t(callbacks());
    217         substr src = t.copy_to_arena(csrc);
    218         t.reserve(_estimate_capacity(csrc));
    219         this->parse_in_place(filename, src, &t, t.root_id());
    220         return t;
    221     }
    222 
    223     /** Parse into an existing tree, starting at its root node.
    224      * The immutable YAML source is first copied to the tree's arena,
    225      * and parsed from there.
    226      * The callbacks in the tree are kept, and used to allocate
    227      * the tree members, if any allocation is required. */
    228     void parse_in_arena(csubstr filename, csubstr csrc, Tree *t)
    229     {
    230         substr src = t->copy_to_arena(csrc);
    231         this->parse_in_place(filename, src, t, t->root_id());
    232     }
    233 
    234     /** Parse into a specific node in an existing tree.
    235      * The immutable YAML source is first copied to the tree's arena,
    236      * and parsed from there.
    237      * The callbacks in the tree are kept, and used to allocate
    238      * the tree members, if any allocation is required. */
    239     void parse_in_arena(csubstr filename, csubstr csrc, Tree *t, size_t node_id)
    240     {
    241         substr src = t->copy_to_arena(csrc);
    242         this->parse_in_place(filename, src, t, node_id);
    243     }
    244 
    245     /** Parse into a specific node in an existing tree.
    246      * The immutable YAML source is first copied to the tree's arena,
    247      * and parsed from there.
    248      * The callbacks in the tree are kept, and used to allocate
    249      * the tree members, if any allocation is required. */
    250     void parse_in_arena(csubstr filename, csubstr csrc, NodeRef node)
    251     {
    252         substr src = node.tree()->copy_to_arena(csrc);
    253         this->parse_in_place(filename, src, node.tree(), node.id());
    254     }
    255 
    256     RYML_DEPRECATED("use parse_in_arena() instead") Tree parse(csubstr filename, csubstr csrc) { return parse_in_arena(filename, csrc); }
    257     RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, Tree *t) { parse_in_arena(filename, csrc, t); }
    258     RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, Tree *t, size_t node_id) { parse_in_arena(filename, csrc, t, node_id); }
    259     RYML_DEPRECATED("use parse_in_arena() instead") void parse(csubstr filename, csubstr csrc, NodeRef node) { parse_in_arena(filename, csrc, node); }
    260 
    261     /** @} */
    262 
    263 public:
    264 
    265     /** @name locations */
    266     /** @{ */
    267 
    268     /** Get the location of a node of the last tree to be parsed by this parser. */
    269     Location location(Tree const& tree, size_t node_id) const;
    270     /** Get the location of a node of the last tree to be parsed by this parser. */
    271     Location location(ConstNodeRef node) const;
    272     /** Get the string starting at a particular location, to the end
    273      * of the parsed source buffer. */
    274     csubstr location_contents(Location const& loc) const;
    275     /** Given a pointer to a buffer position, get the location. @p val
    276      * must be pointing to somewhere in the source buffer that was
    277      * last parsed by this object. */
    278     Location val_location(const char *val) const;
    279 
    280     /** @} */
    281 
    282 private:
    283 
    284     typedef enum {
    285         BLOCK_LITERAL, //!< keep newlines (|)
    286         BLOCK_FOLD     //!< replace newline with single space (>)
    287     } BlockStyle_e;
    288 
    289     typedef enum {
    290         CHOMP_CLIP,    //!< single newline at end (default)
    291         CHOMP_STRIP,   //!< no newline at end     (-)
    292         CHOMP_KEEP     //!< all newlines from end (+)
    293     } BlockChomp_e;
    294 
    295 private:
    296 
    297     using flag_t = int;
    298 
    299     static size_t _estimate_capacity(csubstr src) { size_t c = _count_nlines(src); c = c >= 16 ? c : 16; return c; }
    300 
    301     void  _reset();
    302 
    303     bool  _finished_file() const;
    304     bool  _finished_line() const;
    305 
    306     csubstr _peek_next_line(size_t pos=npos) const;
    307     bool    _advance_to_peeked();
    308     void    _scan_line();
    309 
    310     csubstr _slurp_doc_scalar();
    311 
    312     /**
    313      * @param [out] quoted
    314      * Will only be written to if this method returns true.
    315      * Will be set to true if the scanned scalar was quoted, by '', "", > or |.
    316      */
    317     bool    _scan_scalar_seq_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
    318     bool    _scan_scalar_map_blck(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
    319     bool    _scan_scalar_seq_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
    320     bool    _scan_scalar_map_flow(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
    321     bool    _scan_scalar_unk(csubstr *C4_RESTRICT scalar, bool *C4_RESTRICT quoted);
    322 
    323     csubstr _scan_comment();
    324     csubstr _scan_squot_scalar();
    325     csubstr _scan_dquot_scalar();
    326     csubstr _scan_block();
    327     substr  _scan_plain_scalar_blck(csubstr currscalar, csubstr peeked_line, size_t indentation);
    328     substr  _scan_plain_scalar_flow(csubstr currscalar, csubstr peeked_line);
    329     substr  _scan_complex_key(csubstr currscalar, csubstr peeked_line);
    330     csubstr _scan_to_next_nonempty_line(size_t indentation);
    331     csubstr _extend_scanned_scalar(csubstr currscalar);
    332 
    333     csubstr _filter_squot_scalar(const substr s);
    334     csubstr _filter_dquot_scalar(substr s);
    335     csubstr _filter_plain_scalar(substr s, size_t indentation);
    336     csubstr _filter_block_scalar(substr s, BlockStyle_e style, BlockChomp_e chomp, size_t indentation);
    337     template<bool backslash_is_escape, bool keep_trailing_whitespace>
    338     bool    _filter_nl(substr scalar, size_t *C4_RESTRICT pos, size_t *C4_RESTRICT filter_arena_pos, size_t indentation);
    339     template<bool keep_trailing_whitespace>
    340     void    _filter_ws(substr scalar, size_t *C4_RESTRICT pos, size_t *C4_RESTRICT filter_arena_pos);
    341     bool    _apply_chomp(substr buf, size_t *C4_RESTRICT pos, BlockChomp_e chomp);
    342 
    343     void  _handle_finished_file();
    344     void  _handle_line();
    345 
    346     bool  _handle_indentation();
    347 
    348     bool  _handle_unk();
    349     bool  _handle_map_flow();
    350     bool  _handle_map_blck();
    351     bool  _handle_seq_flow();
    352     bool  _handle_seq_blck();
    353     bool  _handle_top();
    354     bool  _handle_types();
    355     bool  _handle_key_anchors_and_refs();
    356     bool  _handle_val_anchors_and_refs();
    357     void  _move_val_tag_to_key_tag();
    358     void  _move_key_tag_to_val_tag();
    359     void  _move_key_tag2_to_key_tag();
    360     void  _move_val_anchor_to_key_anchor();
    361     void  _move_key_anchor_to_val_anchor();
    362 
    363     void  _push_level(bool explicit_flow_chars = false);
    364     void  _pop_level();
    365 
    366     void  _start_unk(bool as_child=true);
    367 
    368     void  _start_map(bool as_child=true);
    369     void  _start_map_unk(bool as_child);
    370     void  _stop_map();
    371 
    372     void  _start_seq(bool as_child=true);
    373     void  _stop_seq();
    374 
    375     void  _start_seqimap();
    376     void  _stop_seqimap();
    377 
    378     void  _start_doc(bool as_child=true);
    379     void  _stop_doc();
    380     void  _start_new_doc(csubstr rem);
    381     void  _end_stream();
    382 
    383     NodeData* _append_val(csubstr val, flag_t quoted=false);
    384     NodeData* _append_key_val(csubstr val, flag_t val_quoted=false);
    385     bool  _rval_dash_start_or_continue_seq();
    386 
    387     void  _store_scalar(csubstr s, flag_t is_quoted);
    388     csubstr _consume_scalar();
    389     void  _move_scalar_from_top();
    390 
    391     inline NodeData* _append_val_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); return _append_val({nullptr, size_t(0)}); }
    392     inline NodeData* _append_key_val_null(const char *str) { _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); return _append_key_val({nullptr, size_t(0)}); }
    393     inline void      _store_scalar_null(const char *str) {  _RYML_CB_ASSERT(m_stack.m_callbacks, str >= m_buf.begin() && str <= m_buf.end()); _store_scalar({nullptr, size_t(0)}, false); }
    394 
    395     void  _set_indentation(size_t behind);
    396     void  _save_indentation(size_t behind=0);
    397     bool  _maybe_set_indentation_from_anchor_or_tag();
    398 
    399     void  _write_key_anchor(size_t node_id);
    400     void  _write_val_anchor(size_t node_id);
    401 
    402     void _handle_directive(csubstr directive);
    403 
    404     void _skipchars(char c);
    405     template<size_t N>
    406     void _skipchars(const char (&chars)[N]);
    407 
    408 private:
    409 
    410     static size_t _count_nlines(csubstr src);
    411 
    412 private:
    413 
    414     typedef enum : flag_t {
    415         RTOP = 0x01 <<  0,   ///< reading at top level
    416         RUNK = 0x01 <<  1,   ///< reading an unknown: must determine whether scalar, map or seq
    417         RMAP = 0x01 <<  2,   ///< reading a map
    418         RSEQ = 0x01 <<  3,   ///< reading a seq
    419         FLOW = 0x01 <<  4,   ///< reading is inside explicit flow chars: [] or {}
    420         QMRK = 0x01 <<  5,   ///< reading an explicit key (`? key`)
    421         RKEY = 0x01 <<  6,   ///< reading a scalar as key
    422         RVAL = 0x01 <<  7,   ///< reading a scalar as val
    423         RNXT = 0x01 <<  8,   ///< read next val or keyval
    424         SSCL = 0x01 <<  9,   ///< there's a stored scalar
    425         QSCL = 0x01 << 10,   ///< stored scalar was quoted
    426         RSET = 0x01 << 11,   ///< the (implicit) map being read is a !!set. @see https://yaml.org/type/set.html
    427         NDOC = 0x01 << 12,   ///< no document mode. a document has ended and another has not started yet.
    428         //! reading an implicit map nested in an explicit seq.
    429         //! eg, {key: [key2: value2, key3: value3]}
    430         //! is parsed as {key: [{key2: value2}, {key3: value3}]}
    431         RSEQIMAP = 0x01 << 13,
    432     } State_e;
    433 
    434     struct LineContents
    435     {
    436         csubstr  full;        ///< the full line, including newlines on the right
    437         csubstr  stripped;    ///< the stripped line, excluding newlines on the right
    438         csubstr  rem;         ///< the stripped line remainder; initially starts at the first non-space character
    439         size_t   indentation; ///< the number of spaces on the beginning of the line
    440 
    441         LineContents() : full(), stripped(), rem(), indentation() {}
    442 
    443         void reset_with_next_line(csubstr buf, size_t pos);
    444 
    445         void reset(csubstr full_, csubstr stripped_)
    446         {
    447             full = full_;
    448             stripped = stripped_;
    449             rem = stripped_;
    450             // find the first column where the character is not a space
    451             indentation = full.first_not_of(' ');
    452         }
    453 
    454         size_t current_col() const
    455         {
    456             return current_col(rem);
    457         }
    458 
    459         size_t current_col(csubstr s) const
    460         {
    461             RYML_ASSERT(s.str >= full.str);
    462             RYML_ASSERT(full.is_super(s));
    463             size_t col = static_cast<size_t>(s.str - full.str);
    464             return col;
    465         }
    466     };
    467 
    468     struct State
    469     {
    470         flag_t       flags;
    471         size_t       level;
    472         size_t       node_id; // don't hold a pointer to the node as it will be relocated during tree resizes
    473         csubstr      scalar;
    474         size_t       scalar_col; // the column where the scalar (or its quotes) begin
    475 
    476         Location     pos;
    477         LineContents line_contents;
    478         size_t       indref;
    479 
    480         State() : flags(), level(), node_id(), scalar(), scalar_col(), pos(), line_contents(), indref() {}
    481 
    482         void reset(const char *file, size_t node_id_)
    483         {
    484             flags = RUNK|RTOP;
    485             level = 0;
    486             pos.name = to_csubstr(file);
    487             pos.offset = 0;
    488             pos.line = 1;
    489             pos.col = 1;
    490             node_id = node_id_;
    491             scalar_col = 0;
    492             scalar.clear();
    493             indref = 0;
    494         }
    495     };
    496 
    497     void _line_progressed(size_t ahead);
    498     void _line_ended();
    499     void _line_ended_undo();
    500 
    501     void _prepare_pop()
    502     {
    503         RYML_ASSERT(m_stack.size() > 1);
    504         State const& curr = m_stack.top();
    505         State      & next = m_stack.top(1);
    506         next.pos = curr.pos;
    507         next.line_contents = curr.line_contents;
    508         next.scalar = curr.scalar;
    509     }
    510 
    511     inline bool _at_line_begin() const
    512     {
    513         return m_state->line_contents.rem.begin() == m_state->line_contents.full.begin();
    514     }
    515     inline bool _at_line_end() const
    516     {
    517         csubstr r = m_state->line_contents.rem;
    518         return r.empty() || r.begins_with(' ', r.len);
    519     }
    520     inline bool _token_is_from_this_line(csubstr token) const
    521     {
    522         return token.is_sub(m_state->line_contents.full);
    523     }
    524 
    525     inline NodeData * node(State const* s) const { return m_tree->get(s->node_id); }
    526     inline NodeData * node(State const& s) const { return m_tree->get(s .node_id); }
    527     inline NodeData * node(size_t node_id) const { return m_tree->get(   node_id); }
    528 
    529     inline bool has_all(flag_t f) const { return (m_state->flags & f) == f; }
    530     inline bool has_any(flag_t f) const { return (m_state->flags & f) != 0; }
    531     inline bool has_none(flag_t f) const { return (m_state->flags & f) == 0; }
    532 
    533     static inline bool has_all(flag_t f, State const* s) { return (s->flags & f) == f; }
    534     static inline bool has_any(flag_t f, State const* s) { return (s->flags & f) != 0; }
    535     static inline bool has_none(flag_t f, State const* s) { return (s->flags & f) == 0; }
    536 
    537     inline void set_flags(flag_t f) { set_flags(f, m_state); }
    538     inline void add_flags(flag_t on) { add_flags(on, m_state); }
    539     inline void addrem_flags(flag_t on, flag_t off) { addrem_flags(on, off, m_state); }
    540     inline void rem_flags(flag_t off) { rem_flags(off, m_state); }
    541 
    542     void set_flags(flag_t f, State * s);
    543     void add_flags(flag_t on, State * s);
    544     void addrem_flags(flag_t on, flag_t off, State * s);
    545     void rem_flags(flag_t off, State * s);
    546 
    547     void _resize_filter_arena(size_t num_characters);
    548     void _grow_filter_arena(size_t num_characters);
    549     substr _finish_filter_arena(substr dst, size_t pos);
    550 
    551     void _prepare_locations();
    552     void _resize_locations(size_t sz);
    553     bool _locations_dirty() const;
    554 
    555     bool _location_from_cont(Tree const& tree, size_t node, Location *C4_RESTRICT loc) const;
    556     bool _location_from_node(Tree const& tree, size_t node, Location *C4_RESTRICT loc, size_t level) const;
    557 
    558 private:
    559 
    560     void _free();
    561     void _clr();
    562     void _cp(Parser const* that);
    563     void _mv(Parser *that);
    564 
    565 #ifdef RYML_DBG
    566     template<class ...Args> void _dbg(csubstr fmt, Args const& C4_RESTRICT ...args) const;
    567 #endif
    568     template<class ...Args> void _err(csubstr fmt, Args const& C4_RESTRICT ...args) const;
    569     template<class DumpFn>  void _fmt_msg(DumpFn &&dumpfn) const;
    570     static csubstr _prfl(substr buf, flag_t v);
    571 
    572 private:
    573 
    574     ParserOptions m_options;
    575 
    576     csubstr m_file;
    577      substr m_buf;
    578 
    579     size_t  m_root_id;
    580     Tree *  m_tree;
    581 
    582     detail::stack<State> m_stack;
    583     State * m_state;
    584 
    585     size_t  m_key_tag_indentation;
    586     size_t  m_key_tag2_indentation;
    587     csubstr m_key_tag;
    588     csubstr m_key_tag2;
    589     size_t  m_val_tag_indentation;
    590     csubstr m_val_tag;
    591 
    592     bool    m_key_anchor_was_before;
    593     size_t  m_key_anchor_indentation;
    594     csubstr m_key_anchor;
    595     size_t  m_val_anchor_indentation;
    596     csubstr m_val_anchor;
    597 
    598     substr m_filter_arena;
    599 
    600     size_t *m_newline_offsets;
    601     size_t  m_newline_offsets_size;
    602     size_t  m_newline_offsets_capacity;
    603     csubstr m_newline_offsets_buf;
    604 };
    605 
    606 
    607 //-----------------------------------------------------------------------------
    608 //-----------------------------------------------------------------------------
    609 //-----------------------------------------------------------------------------
    610 
    611 /** @name parse_in_place
    612  *
    613  * @desc parse a mutable YAML source buffer.
    614  *
    615  * @note These freestanding functions use a temporary parser object,
    616  * and are convenience functions to easily parse YAML without the need
    617  * to instantiate a separate parser. Note that some properties
    618  * (notably node locations in the original source code) are only
    619  * available through the parser object after it has parsed the
    620  * code. If you need access to any of these properties, use
    621  * Parser::parse_in_place() */
    622 /** @{ */
    623 
    624 inline Tree parse_in_place(                  substr yaml                         ) { Parser np; return np.parse_in_place({}      , yaml); } //!< parse in-situ a modifiable YAML source buffer.
    625 inline Tree parse_in_place(csubstr filename, substr yaml                         ) { Parser np; return np.parse_in_place(filename, yaml); } //!< parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
    626 inline void parse_in_place(                  substr yaml, Tree *t                ) { Parser np; np.parse_in_place({}      , yaml, t); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
    627 inline void parse_in_place(csubstr filename, substr yaml, Tree *t                ) { Parser np; np.parse_in_place(filename, yaml, t); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
    628 inline void parse_in_place(                  substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place({}      , yaml, t, node_id); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
    629 inline void parse_in_place(csubstr filename, substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
    630 inline void parse_in_place(                  substr yaml, NodeRef node           ) { Parser np; np.parse_in_place({}      , yaml, node); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer
    631 inline void parse_in_place(csubstr filename, substr yaml, NodeRef node           ) { Parser np; np.parse_in_place(filename, yaml, node); } //!< reusing the YAML tree, parse in-situ a modifiable YAML source buffer, providing a filename for error messages.
    632 
    633 RYML_DEPRECATED("use parse_in_place() instead") inline Tree parse(                  substr yaml                         ) { Parser np; return np.parse_in_place({}      , yaml); }
    634 RYML_DEPRECATED("use parse_in_place() instead") inline Tree parse(csubstr filename, substr yaml                         ) { Parser np; return np.parse_in_place(filename, yaml); }
    635 RYML_DEPRECATED("use parse_in_place() instead") inline void parse(                  substr yaml, Tree *t                ) { Parser np; np.parse_in_place({}      , yaml, t); }
    636 RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, Tree *t                ) { Parser np; np.parse_in_place(filename, yaml, t); }
    637 RYML_DEPRECATED("use parse_in_place() instead") inline void parse(                  substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place({}      , yaml, t, node_id); }
    638 RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_place(filename, yaml, t, node_id); }
    639 RYML_DEPRECATED("use parse_in_place() instead") inline void parse(                  substr yaml, NodeRef node           ) { Parser np; np.parse_in_place({}      , yaml, node); }
    640 RYML_DEPRECATED("use parse_in_place() instead") inline void parse(csubstr filename, substr yaml, NodeRef node           ) { Parser np; np.parse_in_place(filename, yaml, node); }
    641 
    642 /** @} */
    643 
    644 
    645 //-----------------------------------------------------------------------------
    646 
    647 /** @name parse_in_arena
    648  * @desc parse a read-only YAML source buffer, copying it first to the tree's arena.
    649  *
    650  * @note These freestanding functions use a temporary parser object,
    651  * and are convenience functions to easily parse YAML without the need
    652  * to instantiate a separate parser. Note that some properties
    653  * (notably node locations in the original source code) are only
    654  * available through the parser object after it has parsed the
    655  * code. If you need access to any of these properties, use
    656  * Parser::parse_in_arena().
    657  *
    658  * @note overloads receiving a substr YAML buffer are intentionally
    659  * left undefined, such that calling parse_in_arena() with a substr
    660  * will cause a linker error. This is to prevent an accidental
    661  * copy of the source buffer to the tree's arena, because substr
    662  * is implicitly convertible to csubstr. If you really intend to parse
    663  * a mutable buffer in the tree's arena, convert it first to immutable
    664  * by assigning the substr to a csubstr prior to calling parse_in_arena().
    665  * This is not needed for parse_in_place() because csubstr is not
    666  * implicitly convertible to substr. */
    667 /** @{ */
    668 
    669 /* READ THE NOTE ABOVE! */
    670 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(                  substr yaml                         );
    671 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) Tree parse_in_arena(csubstr filename, substr yaml                         );
    672 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(                  substr yaml, Tree *t                );
    673 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t                );
    674 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(                  substr yaml, Tree *t, size_t node_id);
    675 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, Tree *t, size_t node_id);
    676 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(                  substr yaml, NodeRef node           );
    677 RYML_DEPRECATED(RYML_DONT_PARSE_SUBSTR_IN_ARENA) void parse_in_arena(csubstr filename, substr yaml, NodeRef node           );
    678 
    679 inline Tree parse_in_arena(                  csubstr yaml                         ) { Parser np; return np.parse_in_arena({}      , yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena.
    680 inline Tree parse_in_arena(csubstr filename, csubstr yaml                         ) { Parser np; return np.parse_in_arena(filename, yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    681 inline void parse_in_arena(                  csubstr yaml, Tree *t                ) { Parser np; np.parse_in_arena({}      , yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
    682 inline void parse_in_arena(csubstr filename, csubstr yaml, Tree *t                ) { Parser np; np.parse_in_arena(filename, yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    683 inline void parse_in_arena(                  csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena({}      , yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
    684 inline void parse_in_arena(csubstr filename, csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    685 inline void parse_in_arena(                  csubstr yaml, NodeRef node           ) { Parser np; np.parse_in_arena({}      , yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
    686 inline void parse_in_arena(csubstr filename, csubstr yaml, NodeRef node           ) { Parser np; np.parse_in_arena(filename, yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    687 
    688 RYML_DEPRECATED("use parse_in_arena() instead") inline Tree parse(                  csubstr yaml                         ) { Parser np; return np.parse_in_arena({}      , yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena.
    689 RYML_DEPRECATED("use parse_in_arena() instead") inline Tree parse(csubstr filename, csubstr yaml                         ) { Parser np; return np.parse_in_arena(filename, yaml); } //!< parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    690 RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(                  csubstr yaml, Tree *t                ) { Parser np; np.parse_in_arena({}      , yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
    691 RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, Tree *t                ) { Parser np; np.parse_in_arena(filename, yaml, t); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    692 RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(                  csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena({}      , yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
    693 RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, Tree *t, size_t node_id) { Parser np; np.parse_in_arena(filename, yaml, t, node_id); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    694 RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(                  csubstr yaml, NodeRef node           ) { Parser np; np.parse_in_arena({}      , yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena.
    695 RYML_DEPRECATED("use parse_in_arena() instead") inline void parse(csubstr filename, csubstr yaml, NodeRef node           ) { Parser np; np.parse_in_arena(filename, yaml, node); } //!< reusing the YAML tree, parse a read-only YAML source buffer, copying it first to the tree's source arena, providing a filename for error messages.
    696 
    697 /** @} */
    698 
    699 } // namespace yml
    700 } // namespace c4
    701 
    702 #if defined(_MSC_VER)
    703 #   pragma warning(pop)
    704 #endif
    705 
    706 #endif /* _C4_YML_PARSE_HPP_ */