DMS-XS-Parser

 view release on metacpan or  search on metacpan

Parser.xs  view on Meta::CPAN


    /* Post-process exponent. */
    char out[64];
    int oi = 0;
    int has_dot_or_e = 0;
    for (int i = 0; i < chosen_n; i++) {
        char c = buf[i];
        if (c == '.') has_dot_or_e = 1;
        if (c == 'e' || c == 'E') {
            has_dot_or_e = 1;
            out[oi++] = c;
            i++;
            int sign = 1;
            if (i < chosen_n && buf[i] == '+') { i++; }
            else if (i < chosen_n && buf[i] == '-') { sign = -1; i++; }
            /* skip leading zeros */
            while (i < chosen_n && buf[i] == '0') i++;
            if (i >= chosen_n || buf[i] < '0' || buf[i] > '9') {
                /* exponent collapsed to zero — drop it */
                /* Pop the 'e' we already wrote. */
                oi--;
                continue;
            }
            if (sign < 0) out[oi++] = '-';
            while (i < chosen_n) out[oi++] = buf[i++];
            break;
        }
        out[oi++] = c;
    }
    if (!has_dot_or_e) {
        out[oi++] = '.';
        out[oi++] = '0';
    }
    jbuf_puts(j, out, (size_t)oi);
}

static void emit_value(jbuf *j, const dms_value *v, int indent);

/* Emit a tagged scalar:
 *   {
 *     "type": "<t>",
 *     "value": "<v>"
 *   }
 * with the same indentation rules as encoder.pl. */
static void emit_tagged(jbuf *j, const char *type, int indent,
                        void (*write_value)(jbuf *, const dms_value *),
                        const dms_value *v) {
    jbuf_puts(j, "{\n", 2);
    jbuf_indent(j, indent + 1);
    jbuf_puts(j, "\"type\": \"", 9);
    jbuf_putcstr(j, type);
    jbuf_puts(j, "\",\n", 3);
    jbuf_indent(j, indent + 1);
    jbuf_puts(j, "\"value\": \"", 10);
    write_value(j, v);
    jbuf_puts(j, "\"\n", 2);
    jbuf_indent(j, indent);
    jbuf_putc(j, '}');
}

/* write_value callbacks — write the inner string of a tagged scalar
 * (no surrounding quotes; the caller already wrote them). */
static void wv_bool(jbuf *j, const dms_value *v) {
    jbuf_putcstr(j, v->u.b ? "true" : "false");
}

static void wv_int(jbuf *j, const dms_value *v) {
    jbuf_int64(j, v->u.i);
}

static void wv_float(jbuf *j, const dms_value *v) {
    jbuf_float(j, v->u.f);
}

/* Datetime values: stored as a UTF-8 NUL-terminated string in v->u.s.
 * No JSON escaping is needed (datetime/date/time strings are ASCII), but
 * for safety we run them through the same escape code as other strings. */
static void wv_str_escape(jbuf *j, const dms_value *v) {
    const char *s = v->u.s ? v->u.s : "";
    for (const char *p = s; *p; p++) {
        unsigned char c = (unsigned char)*p;
        switch (c) {
            case '"':  jbuf_puts(j, "\\\"", 2); break;
            case '\\': jbuf_puts(j, "\\\\", 2); break;
            case '\n': jbuf_puts(j, "\\n", 2); break;
            case '\r': jbuf_puts(j, "\\r", 2); break;
            case '\t': jbuf_puts(j, "\\t", 2); break;
            case '\b': jbuf_puts(j, "\\b", 2); break;
            case '\f': jbuf_puts(j, "\\f", 2); break;
            default:
                if (c < 0x20) {
                    char tmp[8];
                    int k = snprintf(tmp, sizeof(tmp), "\\u%04x", c);
                    jbuf_puts(j, tmp, (size_t)k);
                } else {
                    jbuf_putc(j, (char)c);
                }
        }
    }
}

static void emit_value(jbuf *j, const dms_value *v, int indent) {
    switch (v->type) {
        case DMS_BOOL:
            emit_tagged(j, "bool", indent, wv_bool, v); return;
        case DMS_INTEGER:
            emit_tagged(j, "integer", indent, wv_int, v); return;
        case DMS_FLOAT:
            emit_tagged(j, "float", indent, wv_float, v); return;
        case DMS_STRING:
            emit_tagged(j, "string", indent, wv_str_escape, v); return;
        case DMS_OFFSET_DT:
            emit_tagged(j, "offset-datetime", indent, wv_str_escape, v); return;
        case DMS_LOCAL_DT:
            emit_tagged(j, "local-datetime", indent, wv_str_escape, v); return;
        case DMS_LOCAL_DATE:
            emit_tagged(j, "local-date", indent, wv_str_escape, v); return;
        case DMS_LOCAL_TIME:
            emit_tagged(j, "local-time", indent, wv_str_escape, v); return;
        case DMS_TABLE: {
            if (v->u.t.len == 0) { jbuf_puts(j, "{}", 2); return; }



( run in 3.493 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )