/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef PPM_UTIL_TOML_H
#define PPM_UTIL_TOML_H

#include <stddef.h>
#include <stdint.h>

#include <ppm/error.h>

/*
 * Minimal TOML parser.
 *
 * Scope is deliberately narrow: just enough to parse ppm.toml and ppm.lock.
 * Supported:
 *   - tables       [section] and [section.subsection]
 *   - keys         bare and quoted ("key" = ...)
 *   - strings      basic ("foo") and literal ('foo'); no multi-line strings
 *   - arrays       arrays of strings (only); homogeneous
 *   - comments     # to end of line
 *
 * Out of scope (we will reject and report):
 *   - inline tables, dotted keys, arrays of tables, integers, floats,
 *     datetimes, booleans, multi-line strings, escape sequences other than
 *     \\, \", \n, \t, \r.
 *
 * Allocation: every owned string is heap-allocated. Free the document with
 * ppm_toml_free; that recursively releases everything beneath it.
 */

typedef enum {
    PPM_TOML_STRING,
    PPM_TOML_ARRAY,
    PPM_TOML_TABLE,
} ppm_toml_kind_t;

typedef struct ppm_toml_node ppm_toml_node_t;

typedef struct ppm_toml_pair {
    char            *key;   /* owned */
    ppm_toml_node_t *value; /* owned */
} ppm_toml_pair_t;

struct ppm_toml_node {
    ppm_toml_kind_t kind;
    /* Source position for error reporting. */
    int line;
    int col;
    union {
        char *str;                    /* PPM_TOML_STRING */
        struct {                      /* PPM_TOML_ARRAY  */
            ppm_toml_node_t **items;
            size_t            len;
            size_t            cap;
        } arr;
        struct {                      /* PPM_TOML_TABLE  */
            ppm_toml_pair_t *pairs;
            size_t           len;
            size_t           cap;
        } tbl;
    } u;
};

/*
 * Parse a NUL-terminated buffer into a top-level table node. On parse
 * failure, *out_err is set to a heap-allocated, single-line message that
 * the caller must free; *out_node is left untouched.
 */
ppm_error_t ppm_toml_parse(const char *src, ppm_toml_node_t **out_node,
                           char **out_err);

void ppm_toml_free(ppm_toml_node_t *node);

/*
 * Convenience lookups. Returns NULL when the key is missing or has the
 * wrong kind. The returned pointers are borrowed from the document and
 * remain valid until the document is freed.
 */
const ppm_toml_node_t *ppm_toml_get      (const ppm_toml_node_t *tbl, const char *key);
const char            *ppm_toml_get_str  (const ppm_toml_node_t *tbl, const char *key);
const ppm_toml_node_t *ppm_toml_get_table(const ppm_toml_node_t *tbl, const char *key);
const ppm_toml_node_t *ppm_toml_get_array(const ppm_toml_node_t *tbl, const char *key);

#endif /* PPM_UTIL_TOML_H */
