<file_sep>#ifndef INCLUDE_TOML_PARSER_HPP
#define INCLUDE_TOML_PARSER_HPP

#include <exception>
#include <functional>
#include <string_view>
#include "parser.h"
#include "constant.h"

extern "C" {

int toml__internal_on_section(
    toml__internal_t* s, const unsigned char* p,
    const unsigned char* endp);

int toml__internal_on_field(
    toml__internal_t* s, const unsigned char* p,
    const unsigned char* endp);

int toml__internal_on_value(
    toml__internal_t* s, const unsigned char* p,
    const unsigned char* endp);

int toml__internal_on_after_value(
    toml__internal_t* s, const unsigned char* p,
    const unsigned char* endp);

int toml__internal_on_entry_push(
    toml__internal_t* s, const unsigned char* p,
    const unsigned char* endp);

int toml__internal_on_entry_pop(
    toml__internal_t* s, const unsigned char* p,
    const unsigned char* endp);

}

namespace llparse::toml {
    class parser;
    struct parser_setting_s {
        std::function<void (const parser& p, std::string_view chunk)> on_value;
        std::function<void (const parser& p)> on_after_value; // 数据完结
    };
    typedef struct parser_setting_s parser_setting_t;
    
    class parser {
    public:
        parser(const parser_setting_t& setting) noexcept;
        void parse(std::string_view str);
        void reset();
        std::string     field() const noexcept;
        std::uint8_t    value_type() const noexcept;
        std::uint32_t   value_array_index() const noexcept;
    private:
        toml__internal_t parser_;
        parser_setting_t setting_;
        
        std::vector<std::string>     prefix_;
        std::string field_;
        std::vector<std::uint8_t> container_;
        std::vector<std::uint32_t>    index_;
        // 前缀
        friend int ::toml__internal_on_section(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        // 字段
        friend int ::toml__internal_on_field(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        // friend int ::toml__internal_on_after_field(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        // 数据
        friend int ::toml__internal_on_value(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        friend int ::toml__internal_on_after_value(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        // 层级
        friend int ::toml__internal_on_entry_push(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        friend int ::toml__internal_on_entry_pop(toml__internal_t* s, const unsigned char* p, const unsigned char* endp);
        
    };

    class unknown_error: public std::exception {
    public:
        unknown_error(const char* where)
        : where_(where) {
        }
        const char* what() const noexcept;
    private:
        std::string where_;
    };

    class unexpected_token: public std::exception {
    public:
        unexpected_token(char token, const char* where)
        : token_(token)
        , where_(where) {

        }
        const char* what() const noexcept;
    private:
        std::string where_;
        char token_;
    };
}

#endif  /* INCLUDE_TOML_PARSER_HPP */
<file_sep>.PHONY: all var clean install

ENVIRON?=stage
VERSION=1.0.2

CXX?=g++
AR?=ar
NODE?=/data/server/node/bin/node
CFLAGS?= -g -O0
CFLAGS+= -fPIC -std=c11
CXXFLAGS?= -g -O0
CXXFLAGS+= -fPIC -std=c++17

TESTORS_SOURCES := $(wildcard ./test/*.cpp)
TARGETS := $(patsubst ./test/%.cpp,%,${TESTORS_SOURCES})
TESTORS := $(patsubst ./test/%.cpp,./${ENVIRON}/%.test,${TESTORS_SOURCES})

all: ${TESTORS} ./${ENVIRON}/liblltoml.a | ${ENVIRON}

${ENVIRON}:
	mkdir -p ./${ENVIRON}
	for name in ${TARGETS} ; \
	do \
		mkdir -p "./${ENVIRON}/$$name"; \
	done

SOURCES := $(wildcard $(foreach target,${TARGETS},./src/${target}/*.cpp))
DEFINES := $(foreach target,${TARGETS},./src/${target}/parser.mjs)
PARSERS := $(foreach target,${TARGETS},./src/${target}/parser.c)
OBJECTS := $(patsubst ./src/%.c,./${ENVIRON}/%.c.o, ${PARSERS}) $(patsubst ./src/%.cpp,./${ENVIRON}/%.cpp.o, ${SOURCES}) 
.PHONY: ${ENVIRON} var clean install 

var:
	@echo TESTORS = [${TESTORS}]
	@echo SOURCES = [${SOURCES}]
	@echo DEFINES = [${DEFINES}]
	@echo PARSERS = [${PARSERS}]
	@echo OBJECTS = [${OBJECTS}]

clean:
	rm -rf ./${ENVIRON}

install:
	mkdir -p /data/vendor/lltoml-${VERSION}/include/toml
	mkdir -p /data/vendor/lltoml-${VERSION}/lib
	cp ./src/toml/*.hpp /data/vendor/lltoml-${VERSION}/include/toml
	cp ./src/toml/*.h /data/vendor/lltoml-${VERSION}/include/toml
	cp ./${ENVIRON}/liblltoml.a /data/vendor/lltoml-${VERSION}/lib

./${ENVIRON}/%.c.o: ./src/%.c | ${ENVIRON}
	${CXX} -x c ${CFLAGS} -c $^ -o $@
./${ENVIRON}/%.cpp.o: ./src/%.cpp | ${ENVIRON}
	${CXX} ${CXXFLAGS} -c $^ -o $@
./src/%.c: ./src/%.mjs
	${NODE} --experimental-modules $^

./${ENVIRON}/%.test: ./test/%.cpp ${OBJECTS} | ${ENVIRON}
	${CXX} ${CXXFLAGS} -o $@ $^

./${ENVIRON}/liblltoml.a: ${OBJECTS} | ${ENVIRON}
	${AR} rcs $@ $^
<file_sep>"use strict";

import llparse from 'llparse';

import { promises as fs } from 'fs';
import { dirname } from "path";
import { fileURLToPath } from "url";

const ERRORS = Object.fromEntries([
    "ERROR_SUCCESS",
    "ERROR_UNEXPECTED_TOKEN",
    "ERROR_UNKNOWN_ERROR",
].map((v, i) => [v, i]));

const VALUE_TYPES = Object.fromEntries([
    "VALUE_TYPE_UNKNOWN",
    "VALUE_TYPE_BOOLEAN",
    "VALUE_TYPE_INTEGER",
    "VALUE_TYPE_HEX_INTEGER",
    "VALUE_TYPE_OCT_INTEGER",
    "VALUE_TYPE_BIN_INTEGER",
    "VALUE_TYPE_FLOAT",
    "VALUE_TYPE_INFINITY",
    "VALUE_TYPE_NAN",
    "VALUE_TYPE_DATE",
    "VALUE_TYPE_BASIC_STRING",
    "VALUE_TYPE_RAW_STRING",
].map((v, i) => [v, i]));

const CONTAINER_TYPES = Object.fromEntries([
    "CONTAINER_TYPE_TABLE",
    "CONTAINER_TYPE_ARRAY",
    "CONTAINER_TYPE_ARRAY_TABLE",
].map((v, i) => [v, i]));

const parser = new llparse.LLParse("toml__internal");

function E(name, where) {
    if(ERRORS[name]) return parser.error(ERRORS[name], where);
    else throw new Error("undefined error '" + name + "'");
}

// 属性
parser.property("i8", "value_type");
parser.property("i8", "container_type");
parser.property("i32", "array_index");
// 初始
// 前缀
const   type_prefix = parser.node("before_prefix_table");
const before_prefix = parser.node("before_prefix");
const     on_prefix_start = parser.invoke(parser.code.match("toml__internal_on_section"), before_prefix);
const     on_prefix = parser.span(parser.code.span("toml__internal_on_field"));
const        prefix_basic = parser.node("prefix_basic");
const        prefix_quote = parser.node("prefix_quote");
const  after_prefix = parser.node("after_prefix");
const  after_prefix_next = parser.node("after_prefix_next");
const  after_prefix_which = parser.node("after_prefix_which");
// 字段
const    before_field = parser.node("before_field");
const on_before_field = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_UNKNOWN"]), before_field);
// const        on_field = parser.span(parser.code.span("toml__internal_on_field"));
const        on_field = on_prefix;
const           field_quote = parser.node("field_quote");
const           field_basic = parser.node("field_basic");
const     after_field = parser.node("after_field");
// const  on_after_field = parser.invoke(parser.code.match("toml__internal_on_after_field"), after_field);
const  on_after_field = after_field;
const     after_field_next = parser.node("after_field_next");
const     after_field_expect_equal = parser.node("after_field_expect_equal");
const     after_field_expect_field = parser.node("after_field_expect_equal");
// 符号
const    before_equal = parser.node("before_equal");
const           equal = parser.node("equal");
const     after_equal = parser.node("after_equal");
// 值
const    before_value = parser.node("before_value");
const on_before_value = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_UNKNOWN"]), before_value);
const        on_value = parser.span(parser.code.span("toml__internal_on_value"));
// 值 - 无分隔符
const           value_unknown = parser.node("value_unknown");
const           value_boolean = parser.node("value_boolean");
const        on_value_boolean = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_BOOLEAN"]), value_boolean);
const           value_integer = parser.node("value_integer");
const        on_value_integer = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_INTEGER"]), value_integer);
const           value_hex_integer = parser.node("value_hex_integer");
const        on_value_hex_integer = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_HEX_INTEGER"]), value_hex_integer);
const           value_oct_integer = parser.node("value_oct_integer");
const        on_value_oct_integer = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_OCT_INTEGER"]), value_oct_integer);
const           value_bin_integer = parser.node("value_bin_integer");
const        on_value_bin_integer = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_BIN_INTEGER"]), value_bin_integer);
const           value_float = parser.node("value_float")
const        on_value_float = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_FLOAT"]), value_float);
const           value_infinite = parser.node("value_infinite");
const        on_value_infinite = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_INFINITY"]), value_infinite);
const           value_date = parser.node("value_date");
const    before_value_date = parser.node("before_value_date");
const        on_value_date = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_DATE"]), value_date);
const     after_value_date = parser.node("after_value_date");
// 值 - 有分隔符
const    before_value_basic_string = parser.node("before_value_basic_string");
const on_before_value_basic_string = parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_BASIC_STRING"]), before_value_basic_string);
const           value_basic_string = parser.node("value_basic_string");
const     after_value_basic_string = parser.node("after_value_basic_string");
const           value_multi_basic_string = parser.node("value_multi_basic_string");
const           value_multi_basic_string_concat = parser.node("value_multi_basic_string");
const     after_value_multi_basic_string = parser.node("after_value_multi_basic_string");
const    before_value_raw_string = parser.node("before_value_raw_string");
const on_before_value_raw_string =  parser.invoke(parser.code.update("value_type", VALUE_TYPES["VALUE_TYPE_RAW_STRING"]), before_value_raw_string);
const           value_raw_string = parser.node("value_raw_string");
const     after_value_raw_string = parser.node("after_value_raw_string");
const           value_multi_raw_string = parser.node("value_multi_raw_string");
const     after_value_multi_raw_string = parser.node("after_value_multi_raw_string");
// 结束
const     after_value_expect_field = parser.node("after_value_expect_field");
const     after_value_expect_value = parser.node("after_value_expect_value");
const  on_after_value_which = parser.invoke(parser.code.load("container_type"), {2: after_value_expect_field, 1: after_value_expect_value, 0: after_value_expect_field}, E("ERROR_UNKNOWN_ERROR", "after_value"));
const  on_after_value = parser.invoke(parser.code.match("toml__internal_on_after_value"), on_after_value_which);

// 容器 数组、表格 层级关系处理
const     on_cstart_array = parser.invoke(parser.code.update("container_type", CONTAINER_TYPES["CONTAINER_TYPE_ARRAY"]),
    parser.invoke(parser.code.match("toml__internal_on_entry_push"), on_before_value));
const     on_cstart_table = parser.invoke(parser.code.update("container_type", CONTAINER_TYPES["CONTAINER_TYPE_TABLE"]),
    parser.invoke(parser.code.match("toml__internal_on_entry_push"), on_before_field));
const     on_cstart_array_table = parser.invoke(parser.code.update("container_type", CONTAINER_TYPES["CONTAINER_TYPE_ARRAY_TABLE"]),
    parser.invoke(parser.code.match("toml__internal_on_entry_push"), on_before_field));
// const before_cfinish = parser.node("before_cfinish");
const     on_cfinish = parser.invoke(parser.code.match("toml__internal_on_entry_pop"), on_after_value_which); // on_entry_pop 需要维护, 不再调用 on_after_value
const     on_cfinish_before_field = parser.invoke(parser.code.match("toml__internal_on_entry_pop"), on_before_field); // on_entry_pop 需要维护，下一个节马上开始
// 注释
const comment_expect_field = parser.node("begin_comment_expect_field");
const comment_expect_equal = parser.node("begin_comment_expect_equal");
const comment_expect_value = parser.node("begin_comment_expect_value");
// 前缀
// --------------------------------------------------------------------------------
type_prefix
    .match("[[", on_prefix_start)
    .otherwise(on_prefix_start);

before_prefix
    // .skipTo(comment_expect_field)
    .peek(["#", "]"], E("ERROR_UNEXPECTED_TOKEN", "before_prefix"))
    .match([" ", "\t"], before_prefix)
    .match('"', on_prefix.start(prefix_quote)) // on_prefix 实际上与 on_field 是同一个 SPAN , 区别在 cstart 后的转换过程
    .otherwise(on_prefix.start(prefix_basic));

prefix_basic
    .peek(["#", "\r", "\n"], E("ERROR_UNEXPECTED_TOKEN", "prefix_basic"))
    .peek([".", " ", "\t", "]"], on_prefix.end(after_prefix))
    .skipTo(prefix_basic);

prefix_quote
    .peek("\"", on_prefix.end(after_prefix))
    .skipTo(prefix_quote);

after_prefix
    .match([" ", "\t", "\r", "\n"], after_prefix)
    .peek("]", after_prefix_which)
    .peek('.', on_prefix.start(after_prefix_next))
    .otherwise(E("ERROR_UNEXPECTED_TOKEN", "after_prefix"));

after_prefix_which
    .match("]]", on_cstart_array_table)
    .skipTo(on_cstart_table)

after_prefix_next
    .skipTo(on_prefix.end(before_prefix));

// 字段
// --------------------------------------------------------------------------------
before_field // <-- after_field / after_value
    .match([" ", "\t", "\r", "\n"], before_field)
    .peek("#", comment_expect_field)
    .match("[", type_prefix)
    .match("\"", on_field.start(field_quote))
    .otherwise(on_field.start(field_basic));

field_basic
    .peek([".", " ", "\t", "]", "=", "#", "\r", "\n"], on_field.end(on_after_field))
    .skipTo(field_basic);

field_quote
    .peek("\"", on_field.end(on_after_field))
    .skipTo(field_quote);

after_field
    .match(["\"", " ", "\t"], after_field_expect_equal)
    .peek(".", on_field.start(after_field_next)) // 子级 key 不改变数据类型
    .match("]", after_field_expect_field)
    // .peek("#", comment_expect_equal) // 不允许出现此种情况 AAAA #CCCCC \n = BBBBB
    .otherwise( before_equal );

after_field_next
    .skipTo(on_field.end(before_field))

after_field_expect_equal
    .match([" ", "\t"], after_field_expect_equal)
    .otherwise(before_equal);

after_field_expect_field
    .match([" ", "\t"], after_field_expect_field)
    .otherwise(on_before_field); // 注意重置数据类型

// 符号
// --------------------------------------------------------------------------------
before_equal
    .peek(["\r", "\n"], E("ERROR_UNEXPECTED_TOKEN", "before_equal")) // 不允许出现此种情况 AAAA \n = BBBBB
    .match([" ", "\t"], before_equal)
    .peek("#", comment_expect_equal)
    .otherwise(equal);

equal
    .match("=", after_equal)
    .otherwise(E("ERROR_UNEXPECTED_TOKEN", "equal"));

after_equal
    .match([" ", "\t"], after_equal)
    .peek("#", comment_expect_value)
    .peek(["\r", "\n"], E("ERROR_UNEXPECTED_TOKEN", "after_equal"))
    .otherwise(before_value);

// 值
// --------------------------------------------------------------------------------

before_value
    .match([" ", "\t"], before_value)
    .peek(["\r", "\n"], E("ERROR_UNEXPECTED_TOKEN", "before_value"))
    // 0 比较特别（0x/0o/0b)
    .match("+", on_value.start(on_value_integer))
    .peek(["-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], on_value.start(on_value_integer))
    .peek("t", on_value.start(on_value_boolean)) // true
    .peek("f", on_value.start(on_value_boolean)) // false
    .match("[", on_cstart_array)
    .match("{", on_cstart_table)
    // 待确认是否未多行文本
    .peek('"', on_before_value_basic_string)
    .peek("'", on_before_value_raw_string)
    .peek("#", comment_expect_value)
    .otherwise(on_value.start(value_unknown))

value_unknown
    .match(["-", ":"], on_value_date)
    .peek([",", "]", "}", " ", "\t", "#", "\r", "\n"], on_value.end(on_after_value))
    .skipTo(value_unknown);

value_boolean
    .match(["true", "false"], on_value.end(on_after_value))
    .otherwise(E("ERROR_UNEXPECTED_TOKEN", "value_boolean"));

value_integer
    .peek([",", "]", "}", " ", "\t", "#", "\r", "\n"], on_value.end(on_after_value))
    .match("x", on_value_hex_integer)
    .match("o", on_value_oct_integer)
    .match("b", on_value_bin_integer)
    .match("+inf", on_value_infinite)
    .peek("-", before_value_date)
    .match("inf", on_value_infinite)
    .match("e-", on_value_float)
    .match("e+", on_value_float)
    .match("E-", on_value_float)
    .match("E+", on_value_float)
    .match(":", on_value_date)
    .match(".", on_value_float)
    .skipTo(value_integer);

value_hex_integer
    .match(["_", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "A", "B", "C", "D", "E", "F"], value_hex_integer)
    .otherwise(on_value.end(on_after_value));

value_oct_integer
    .match(["_", "0", "1", "2", "3", "4", "5", "6", "7"], value_hex_integer)
    .otherwise(on_value.end(on_after_value));

value_bin_integer
    .match(["_", "0", "1"], value_hex_integer)
    .otherwise(on_value.end(on_after_value));

value_infinite
    .otherwise(on_value.end(on_after_value));

value_float
    .peek([",", "]", "}", " ", "t", "#", "\r", "\n"], on_value.end(on_after_value))
    .skipTo(value_float);

before_value_date
    .match("-inf", on_value_infinite)
    .otherwise(value_date)

value_date
    .peek(" ", after_value_date) // 可能是结束符号
    .peek([",", "]", "}", "\t", "#", "\r", "\n"], on_value.end(on_after_value))
    .skipTo(value_date);

after_value_date
    .match([" 0", " 1", " 2"], value_date) // 合理的三种形式
    .otherwise(on_value.end(on_after_value)); // 其他形式结束匹配

// 值 - 分隔符
// ----------------------------------------------------------------------------------------------------
before_value_basic_string
    .match('"""', on_value.start(value_multi_basic_string)) // match at least 
    .otherwise(on_value.start(value_basic_string)); // '"'

value_basic_string
    .peek('"', on_value.end(after_value_basic_string))
    .peek(["\r", "\n"], E("ERROR_UNEXPECTED_TOKEN", "value_basic_string"))
    .skipTo(value_basic_string);

after_value_basic_string
    .match('"', on_after_value)
    .otherwise(E("ERROR_UNEXPECTED_TOKEN", "after_value_basic_string"));

value_multi_basic_string
    .peek('"', on_value.end(after_value_multi_basic_string)) // 暂停解析，但有可能恢复
    .peek("\\", on_value.end(value_multi_basic_string_concat)) // 分行书写长文本
    .skipTo(value_multi_basic_string);

value_multi_basic_string_concat // 用于单行长文本
    .match("\\\r\n", on_value.start(value_multi_basic_string))
    .match("\\\n", on_value.start(value_multi_basic_string))
    .otherwise(on_value.start(value_multi_basic_string))

after_value_multi_basic_string
    .match('"""', on_after_value)
    .otherwise(on_value.start(value_multi_basic_string)); // 未匹配结束符，恢复

before_value_raw_string
    .match("'''", on_value.start(value_multi_raw_string))
    .otherwise(on_value.start(value_raw_string));

value_raw_string
    .peek("'", on_value.end(after_value_raw_string))
    .skipTo(value_raw_string);

after_value_raw_string
    .match("'", on_after_value)
    .otherwise(E("ERROR_UNEXPECTED_TOKEN", "after_value_raw_string"));

value_multi_raw_string
    .peek("'", on_value.end(after_value_multi_raw_string)) // 暂停解析，但有可能恢复
    .skipTo(value_multi_raw_string);

after_value_multi_raw_string
    .match("'''", on_after_value)
    .otherwise(on_value.start(value_multi_raw_string)); // 未匹配结束符，恢复

after_value_expect_field
    .match([",", " ", "\t", "\r", "\n"], after_value_expect_field) // 不允许在 value 后继续定义 field 必须换行
    .match(["}"/*, "]"*/], on_cfinish) // 容器结束，需要回到上一层
    .peek("]", E("ERROR_UNEXPECTED_TOKEN", "after_value"))
    .peek("#", comment_expect_field)
    .peek("[", on_cfinish_before_field)
    .otherwise(on_before_field);

after_value_expect_value
    .match([",", " ", "\t", "\r", "\n"], after_value_expect_value)
    .match([/*"}",*/ "]"], on_cfinish) // 容器结束，需要回到上一层
    .peek("}", E("ERROR_UNEXPECTED_TOKEN", "after_value"))
    .peek("#", comment_expect_value)
    // .peek("[", on_cfinish_before_field)
    .otherwise(on_before_value);

// 注释
// ----------------------------------------------------------------------------------------------
comment_expect_field
    .match(["\r", "\n"], on_before_field)
    // .match("#", comment_expect_field)
    .skipTo(comment_expect_field);

comment_expect_equal
    .match(["\r", "\n"], before_equal)
    // .match("#", comment_expect_equal)
    .skipTo(comment_expect_equal);

comment_expect_value
    .match(["\r", "\n"], before_value)
    // .match("#", comment_expect_value)
    .skipTo(comment_expect_value);

const __dirname  = dirname(fileURLToPath(import.meta.url));

async function constant_header() {
    let header = "#ifndef TOML__INTERNAL_CONSTANT_H\n#define TOML__INTERNAL_CONSTANT_H\n\n#include <cstdint>\n\n";
    header += "namespace llparse::toml {\n";
        
    header += "\n\tenum error_t: std::uint8_t {\n";
    for(let key in ERRORS) {
        header += "\t\t" + key.padEnd(16) + " = " + ERRORS[key] + ",\n";
    }
    header += "\t};\n"

    header += "\n\tenum container_type_t: std::uint8_t {\n";
    for(let key in CONTAINER_TYPES) {
        header += "\t\t" + key.padEnd(16) + " = " + CONTAINER_TYPES[key] + ",\n";
    }
    header += "\t};\n";

    header += "\n\tenum value_type_t: std::uint8_t {\n";
    for(let key in VALUE_TYPES) {
        header += "\t\t" + key.padEnd(16) + " = " + VALUE_TYPES[key] + ",\n";
    }
    header += "\t};\n";
    
    header += "}\n#endif // TOML__INTERNAL_CONSTANT_H\n";
    await fs.writeFile(__dirname + "/constant.h", header);
}

async function build() {
    const art = parser.build(before_field, {"c": {
        "header": "parser",
    }});
    await fs.writeFile(__dirname + "/parser.h", art.header);
    await fs.writeFile(__dirname + "/parser.c", art.c);
    await constant_header();
    console.log("parser source and constant header generated.");
}

build().catch((error) => {
    console.log(error);
    process.exit(-1);
});
<file_sep>#include "toml.hpp"
#include <cstdio>
#include <string_view>
#include "error.h"

extern "C" {
    // 前缀
    // ---------------------------------------------------------------------------------------------------------------------

    int toml__internal_on_section(toml__internal_t* s, const unsigned char* p, const unsigned char* endp) {
        auto * self = static_cast<llparse::toml::parser*>(s->data);
        self->prefix_.resize(1);
        self->index_.resize(1);
        s->array_index = self->index_.back();
        return 0;
    }
    // 字段
    // ---------------------------------------------------------------------------------------------------------------------
    int toml__internal_on_field(toml__internal_t* s, const unsigned char* p, const unsigned char* endp) {
        auto * self = static_cast<llparse::toml::parser*>(s->data);
        if(endp > p) {
            self->field_.append((const char*)p, static_cast<std::size_t>(endp - p));
        }
        return 0;
    }
    // 数据
    // ---------------------------------------------------------------------------------------------------------------------

    int toml__internal_on_value(toml__internal_t* s, const unsigned char* p, const unsigned char* endp) {
        const auto * self = static_cast<llparse::toml::parser*>(s->data);
        if(endp > p) {
            if(self->setting_.on_value) self->setting_.on_value(*self, {(const char*) p, static_cast<std::size_t>(endp - p)});
        }
        
        return 0;
    }
    int toml__internal_on_after_value(toml__internal_t* s, const unsigned char* p, const unsigned char* endp) {
        auto * self = static_cast<llparse::toml::parser*>(s->data);
        if(self->setting_.on_after_value) self->setting_.on_after_value(*self);
        self->field_.clear();
        if(s->container_type == llparse::toml::CONTAINER_TYPE_ARRAY) s->array_index = ++self->index_.back();
        return 0;
    }
    // 层级关系
    // ---------------------------------------------------------------------------------------------------------------------
    int toml__internal_on_entry_push(toml__internal_t* s, const unsigned char* p, const unsigned char* endp) {
        auto * self = static_cast<llparse::toml::parser*>(s->data);
        // std::cout << "> on_entry1: << " << self->prefix_ << "\n";
        if(self->field_.empty()) self->field_.assign("#");
        else if(s->container_type == (std::uint8_t) llparse::toml::CONTAINER_TYPE_ARRAY_TABLE) self->field_.append(".#");
        self->prefix_.push_back(self->field_);
        
        self->field_.clear();
        if(self->container_.back() == (std::uint8_t) llparse::toml::CONTAINER_TYPE_ARRAY) {
            if(s->container_type == (std::uint8_t) llparse::toml::CONTAINER_TYPE_TABLE) {
                s->container_type = (std::uint8_t) llparse::toml::CONTAINER_TYPE_ARRAY_TABLE;
            }
        }
        // 开始一个 ARRAY 节
        if(s->container_type == (std::uint8_t) llparse::toml::CONTAINER_TYPE_ARRAY) {
            self->index_.back() = s->array_index;
            s->array_index = 0;
            self->index_.push_back(s->array_index);
        }
        self->container_.push_back(s->container_type);
        return 0;
    }

    int toml__internal_on_entry_pop(toml__internal_t* s, const unsigned char* p, const unsigned char* endp) {
        auto * self = static_cast<llparse::toml::parser*>(s->data);
        self->prefix_.pop_back();
        std::uint8_t ct = self->container_.back();
        self->container_.pop_back();
        
        s->container_type = self->container_.back();
        // 结束的了一个 array 节
        if(ct == llparse::toml::CONTAINER_TYPE_ARRAY) {
            self->index_.pop_back();
            s->array_index = self->index_.back();
        }
        if(s->container_type == llparse::toml::CONTAINER_TYPE_ARRAY || // 本节结束后上层是一个 array 节
            ct == llparse::toml::CONTAINER_TYPE_ARRAY_TABLE) { // 本节 array_table 结束
            s->array_index = ++self->index_.back();
        }
        return 0;
    }

} // extern "C"

namespace llparse::toml {

    parser::parser(const parser_setting_t& setting) noexcept
    : setting_(setting) {
        toml__internal_init(&parser_);
        parser_.data = this;
        parser_.container_type = llparse::toml::CONTAINER_TYPE_TABLE;
        parser_.array_index = 0;
        prefix_.push_back("$");
        container_.push_back((std::uint8_t) parser_.container_type);
        index_.push_back((std::uint32_t) parser_.array_index);
    }

    void parser::parse(std::string_view str) {
        switch(toml__internal_execute(&parser_, str.data(), str.data() + str.size())) {
        case ERROR_SUCCESS:
            break;
        case ERROR_UNEXPECTED_TOKEN:
            throw unexpected_token(parser_.error_pos[0], parser_.reason);
        default:
            throw unknown_error(parser_.reason);
        }
    }

    void parser::reset() {
        toml__internal_init(&parser_);
        container_.resize(1);
    }

    std::string parser::field() const noexcept  {
        std::string pre = prefix_[0];
        for(int i=1;i<prefix_.size();++i) {
            pre.push_back('.');
            pre.append(prefix_[i]);
        }
        if(field_.empty()) {
            if(parser_.container_type == CONTAINER_TYPE_ARRAY) {
                pre.push_back('.');
                pre.push_back('#');
            }
        }else{
            pre.push_back('.');
            pre.append(field_);
        }
        return pre;
    }

    std::uint8_t parser::value_type() const noexcept  {
        return parser_.value_type;
    }

    std::uint32_t parser::value_array_index() const noexcept  {
        return parser_.array_index;
    }

    const char* unknown_error::what() const noexcept {
        static char buffer[64];
        std::sprintf(buffer, "TOML parse failed: unknown error @%s", where_.c_str());
        return buffer;
    }

    const char* unexpected_token::what() const noexcept {
        static char buffer[96]; 
        std::sprintf(buffer, "TOML parse failed: unexpected token (0x%02x => '%c') @%s", token_, token_, where_.c_str());
        return buffer;
    }
}<file_sep>#include "../src/toml/toml.hpp"
#include <cstring>
#include <iostream>
#include <fstream>
#include <memory>

template <class T>
void null_deleter(T* t) {}

int main(int argc, char* argv[]) {
    std::string value;
    llparse::toml::parser p({
        /*.on_value = */[&value] (const llparse::toml::parser& p, std::string_view chunk) {
            value.append(chunk);
            std::cout << "= on_value: " << p.field() << " #" << p.value_array_index() << " => (" << value << ")\n";
        },
        /* .on_after_value = */[&value] (const llparse::toml::parser& p) {
            // if(p.prefix() == ".a.b.e") exit(0);
            std::cout << "= on_after_value: " << p.field() << " #" << p.value_array_index() << " => [" << value << "]@" << (int)p.value_type() << "\n";
            value.clear();
        },
    });
    std::string flr;
    std::shared_ptr<std::istream> is;
    if(argc > 1) is.reset(new std::ifstream(argv[1]));
    else is.reset(&std::cin, null_deleter<std::istream>);
    while(!is->eof()) {
        std::getline(*is, flr);
        flr.append("\n");
        p.parse(flr);
    };
    return 0;
}
<file_sep>### 介绍
学习和测试 [llparse](https://github.com/nodejs/llparse) / [llhttp](https://github.com/nodejs/llhttp) 编写的 [toml](https://github.com/toml-lang/toml) 解析器;

* `llparse` - 可方便的用于文本类协议的增量解析器生成(目前支持的转换等功能是配合 HTTP 协议设计的, 可能有所不足), 可生成对应头文件、源文件或字节码;
* `llhttp` - 使用上述 `llparse` 开发生成的 HTTP 解析器, 据官方介绍效率较 [http_parser](https://github.com/nodejs/http-parser) 提升一倍有余;

### 协议
本项目使用 MIT 协议
