DMS-XS-Parser

 view release on metacpan or  search on metacpan

vendor/dms-c/dms.c  view on Meta::CPAN

            snprintf(tmp, sizeof tmp, "\\u%04X", c);
            emit_push(e, tmp);
        } else {
            emit_push_ch(e, (char)c);
        }
    }
}

static void emit_format_key(emitter *e, const char *k) {
    if (key_is_bare(k)) {
        emit_push(e, k);
        return;
    }
    bool has_sq = strchr(k, '\'') != NULL;
    bool has_nl = strchr(k, '\n') != NULL || strchr(k, '\r') != NULL;
    if (!has_sq && !has_nl) {
        emit_push_ch(e, '\'');
        emit_push(e, k);
        emit_push_ch(e, '\'');
    } else {
        emit_push_ch(e, '"');
        emit_escape_basic(e, k);
        emit_push_ch(e, '"');
    }
}

/* ---- forward decls ---- */

static void emit_document_body(emitter *e);
static void emit_table_block(emitter *e, const dms_table *t,
                             const dms_breadcrumb_seg *path, size_t path_len,
                             size_t indent);
static void emit_list_block(emitter *e, const dms_list *l,
                            const dms_breadcrumb_seg *path, size_t path_len,
                            size_t indent);
static void emit_value_inline(emitter *e, const dms_value *v,
                              const dms_breadcrumb_seg *path, size_t path_len);
static void emit_integer(emitter *e, int64_t n,
                         const dms_breadcrumb_seg *path, size_t path_len);
static void emit_string(emitter *e, const char *s,
                        const dms_breadcrumb_seg *path, size_t path_len);
static void emit_heredoc(emitter *e, const char *body,
                         dms_heredoc_flavor flavor, const char *label,
                         const dms_heredoc_modifier_call *mods, size_t nmods);
static void emit_modifier_arg(emitter *e, const dms_value *v);
static void emit_comment_line(emitter *e, const dms_attached_comment *ac, size_t indent);
static void emit_trailing_for(emitter *e, const dms_breadcrumb_seg *path, size_t path_len);
static void emit_floating_for(emitter *e, const dms_breadcrumb_seg *path, size_t path_len, size_t indent);
static void emit_leading_for(emitter *e, const dms_breadcrumb_seg *path, size_t path_len, size_t indent);
static bool has_trailing_for(const emitter *e, const dms_breadcrumb_seg *path, size_t path_len);
static bool is_flow_safe(const emitter *e, const dms_value *v,
                         const dms_breadcrumb_seg *path, size_t path_len);
static const dms_original_literal *find_form(const emitter *e,
                                             const dms_breadcrumb_seg *path, size_t path_len);

/* Build + sort index arrays. In lite mode, both lookup arrays are
   left NULL so every `find_first_match` short-circuits — comments are
   dropped, integer base / string flavor fall back to canonical form. */
static void emitter_init(emitter *e, const dms_document *doc, bool lite) {
    buf_init(&e->out);
    buf_ensure(&e->out, 64 * 1024);  /* pre-size: skip realloc cascade on typical-sized configs */
    e->doc = doc;
    e->comments_sorted = NULL;
    e->forms_sorted = NULL;
    e->path_buf = NULL;
    e->path_buf_cap = 0;
    e->lite = lite;
    if (lite) return;
    if (doc->num_comments > 0) {
        e->comments_sorted = (size_t *)malloc(doc->num_comments * sizeof(size_t));
        for (size_t i = 0; i < doc->num_comments; i++) e->comments_sorted[i] = i;
        sort_ctx ctx; ctx.doc = doc; ctx.is_form = 0;
        sort_indices(e->comments_sorted, doc->num_comments, ctx);
    }
    if (doc->num_original_forms > 0) {
        e->forms_sorted = (size_t *)malloc(doc->num_original_forms * sizeof(size_t));
        for (size_t i = 0; i < doc->num_original_forms; i++) e->forms_sorted[i] = i;
        sort_ctx ctx; ctx.doc = doc; ctx.is_form = 1;
        sort_indices(e->forms_sorted, doc->num_original_forms, ctx);
    }
}

static void emitter_free(emitter *e) {
    free(e->comments_sorted);
    free(e->forms_sorted);
    free(e->path_buf);
}

/* Grow the shared breadcrumb buffer to fit at least `need` segments.
   Used by emit_table_block / emit_list_block / emit_value_inline so they
   no longer malloc/free a fresh path per kvpair. */
static void path_ensure(emitter *e, size_t need) {
    if (need <= e->path_buf_cap) return;
    size_t newcap = e->path_buf_cap ? e->path_buf_cap * 2 : 16;
    while (newcap < need) newcap *= 2;
    e->path_buf = (dms_breadcrumb_seg *)xrealloc(e->path_buf, newcap * sizeof(dms_breadcrumb_seg));
    e->path_buf_cap = newcap;
}

/* Look up the first OriginalLiteral whose path equals (path, path_len). */
static const dms_original_literal *find_form(const emitter *e,
                                             const dms_breadcrumb_seg *path, size_t path_len) {
    size_t idx = find_first_match(e, 1, path, path_len);
    if (idx == (size_t)-1) return NULL;
    size_t src_idx = e->forms_sorted[idx];
    return &e->doc->original_forms[src_idx].lit;
}

/* ---- comment helpers ---- */

static bool has_trailing_for(const emitter *e, const dms_breadcrumb_seg *path, size_t path_len) {
    size_t first = find_first_match(e, 0, path, path_len);
    if (first == (size_t)-1) return false;
    for (size_t i = first; i < e->doc->num_comments; i++) {
        const dms_attached_comment *ac = &e->doc->comments[e->comments_sorted[i]];
        if (cmp_path(ac->path, ac->path_len, path, path_len) != 0) break;
        if (ac->position == DMS_COMMENT_TRAILING) return true;
    }
    return false;
}



( run in 1.614 second using v1.01-cache-2.11-cpan-40ba7b3775d )