mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-09 04:59:31 -06:00
remove dump and yaml from libgu
This commit is contained in:
@@ -4,8 +4,8 @@ include $(CLEAR_VARS)
|
||||
|
||||
jni_c_files := ../java/jpgf.c
|
||||
pgf_c_files := data.c expr.c graphviz.c lexer.c linearizer.c literals.c parser.c parseval.c pgf.c printer.c reader.c reasoner.c
|
||||
gu_c_files := assert.c choice.c dump.c exn.c fun.c in.c list.c map.c out.c read.c str.c type.c utf8.c write.c \
|
||||
bits.c defs.c enum.c file.c hash.c intern.c log.c mem.c prime.c seq.c string.c ucs.c variant.c yaml.c
|
||||
gu_c_files := assert.c choice.c exn.c fun.c in.c list.c map.c out.c read.c str.c type.c utf8.c write.c \
|
||||
bits.c defs.c enum.c file.c hash.c intern.c log.c mem.c prime.c seq.c string.c ucs.c variant.c
|
||||
|
||||
LOCAL_MODULE := jpgf
|
||||
LOCAL_SRC_FILES := $(addprefix ../c/pgf/, $(pgf_c_files)) $(addprefix ../c/gu/, $(gu_c_files))
|
||||
|
||||
@@ -14,7 +14,6 @@ guinclude_HEADERS = \
|
||||
gu/bits.h \
|
||||
gu/choice.h \
|
||||
gu/defs.h \
|
||||
gu/dump.h \
|
||||
gu/enum.h \
|
||||
gu/exn.h \
|
||||
gu/file.h \
|
||||
@@ -37,8 +36,7 @@ guinclude_HEADERS = \
|
||||
gu/ucs.h \
|
||||
gu/utf8.h \
|
||||
gu/variant.h \
|
||||
gu/write.h \
|
||||
gu/yaml.h
|
||||
gu/write.h
|
||||
|
||||
pgfincludedir=$(includedir)/pgf
|
||||
pgfinclude_HEADERS = \
|
||||
@@ -56,7 +54,6 @@ libgu_la_SOURCES = \
|
||||
gu/choice.c \
|
||||
gu/defs.c \
|
||||
gu/seq.c \
|
||||
gu/dump.c \
|
||||
gu/enum.c \
|
||||
gu/exn.c \
|
||||
gu/file.c \
|
||||
@@ -77,8 +74,7 @@ libgu_la_SOURCES = \
|
||||
gu/utf8.c \
|
||||
gu/write.c \
|
||||
gu/ucs.c \
|
||||
gu/variant.c \
|
||||
gu/yaml.c
|
||||
gu/variant.c
|
||||
|
||||
libteyjus_la_SOURCES = \
|
||||
teyjus/simulator/abstmachine.c \
|
||||
|
||||
@@ -1,411 +0,0 @@
|
||||
#include <gu/dump.h>
|
||||
#include <gu/list.h>
|
||||
#include <gu/variant.h>
|
||||
#include <gu/seq.h>
|
||||
#include <gu/assert.h>
|
||||
#include <gu/str.h>
|
||||
#include <gu/file.h>
|
||||
|
||||
GuDump*
|
||||
gu_new_dump(GuWriter* wtr, GuTypeTable* dumpers, GuExn* err, GuPool* pool)
|
||||
{
|
||||
GuDump* ctx = gu_new(GuDump, pool);
|
||||
ctx->pool = pool;
|
||||
if (dumpers == NULL) {
|
||||
dumpers = &gu_dump_table;
|
||||
}
|
||||
ctx->dumpers = gu_new_type_map(dumpers, pool);
|
||||
ctx->yaml = gu_new_yaml(wtr, err, pool);
|
||||
ctx->data = gu_new_addr_map(void, void*, &gu_null, pool);
|
||||
ctx->print_address = false;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void
|
||||
gu_dump(GuType* type, const void* value, GuDump* ctx)
|
||||
{
|
||||
GuDumpFn* dumper = gu_type_map_get(ctx->dumpers, type);
|
||||
if (ctx->print_address) {
|
||||
GuPool* pool = gu_new_pool();
|
||||
GuString s = gu_format_string(pool, "%p", value);
|
||||
gu_yaml_comment(ctx->yaml, s);
|
||||
gu_pool_free(pool);
|
||||
}
|
||||
(*dumper)(dumper, type, value, ctx);
|
||||
}
|
||||
|
||||
void
|
||||
gu_dump_stderr(GuType* type, const void* value, GuExn* err)
|
||||
{
|
||||
GuPool* pool = gu_new_pool();
|
||||
GuOut* out = gu_file_out(stderr, pool);
|
||||
#if 0
|
||||
GuWriter* wtr = gu_locale_writer(out, pool);
|
||||
#else
|
||||
GuWriter* wtr = gu_new_utf8_writer(out, pool);
|
||||
#endif
|
||||
GuDump* ctx = gu_new_dump(wtr, NULL, err, pool);
|
||||
gu_dump(type, value, ctx);
|
||||
gu_pool_free(pool);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_scalar(GuDump* ctx, const char* fmt, ...)
|
||||
{
|
||||
GuPool* tmp_pool = gu_local_pool();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
GuString s = gu_format_string_v(fmt, args, tmp_pool);
|
||||
va_end(args);
|
||||
gu_yaml_scalar(ctx->yaml, s);
|
||||
gu_pool_free(tmp_pool);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_str_scalar(GuDump* ctx, const char* str)
|
||||
{
|
||||
GuPool* tmp_pool = gu_local_pool();
|
||||
GuString s = gu_str_string(str, tmp_pool);
|
||||
gu_yaml_scalar(ctx->yaml, s);
|
||||
gu_pool_free(tmp_pool);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_null(GuDump* ctx)
|
||||
{
|
||||
gu_yaml_tag_secondary(ctx->yaml, "null");
|
||||
gu_yaml_scalar(ctx->yaml, gu_empty_string);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_int(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
const int* ip = p;
|
||||
gu_dump_scalar(ctx, "%d", *ip);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_uint16(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
const uint16_t* ip = p;
|
||||
gu_dump_scalar(ctx, "%" PRIu16, *ip);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_size(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) (dumper && type);
|
||||
const size_t* zp = p;
|
||||
gu_dump_scalar(ctx, "%zu", *zp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
gu_dump_double(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
const double* dp = p;
|
||||
gu_dump_scalar(ctx, "%lf", *dp);
|
||||
}
|
||||
|
||||
static const char gu_dump_length_key[] = "gu_dump_length_key";
|
||||
|
||||
static void
|
||||
gu_dump_length(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
const GuLength* ip = p;
|
||||
gu_dump_scalar(ctx, "%d", *ip);
|
||||
GuLength* lenp = gu_map_get(ctx->data, gu_dump_length_key, void*);
|
||||
if (lenp != NULL) {
|
||||
*lenp = *ip;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_str(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
const GuStr* sp = p;
|
||||
gu_dump_str_scalar(ctx, *sp);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_string(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
const GuString* sp = p;
|
||||
gu_yaml_scalar(ctx->yaml, *sp);
|
||||
}
|
||||
|
||||
|
||||
// For _non-shared_ pointers.
|
||||
static void
|
||||
gu_dump_pointer(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuPointerType* ptype = (GuPointerType*) type;
|
||||
void* const* pp = p;
|
||||
if (*pp == NULL) {
|
||||
gu_dump_null(ctx);
|
||||
} else {
|
||||
gu_dump(ptype->pointed_type, *pp, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GuMapItor itor;
|
||||
GuMapType* mtype;
|
||||
GuDump* ctx;
|
||||
} GuDumpMapFn;
|
||||
|
||||
static void
|
||||
gu_dump_map_itor(GuMapItor* self, const void* key, void* value, GuExn* err)
|
||||
{
|
||||
(void) err;
|
||||
GuDumpMapFn* clo = (GuDumpMapFn*) self;
|
||||
gu_dump(clo->mtype->key_type, key, clo->ctx);
|
||||
gu_dump(clo->mtype->value_type, value, clo->ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_map(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuMapType* mtype = (GuMapType*) type;
|
||||
GuMap* map = (GuMap*) p;
|
||||
gu_yaml_begin_mapping(ctx->yaml);
|
||||
GuDumpMapFn clo = { { gu_dump_map_itor }, mtype, ctx };
|
||||
gu_map_iter(map, &clo.itor, NULL);
|
||||
gu_yaml_end(ctx->yaml);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gu_dump_struct(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuStructRepr* srepr = (GuStructRepr*) type;
|
||||
gu_yaml_begin_mapping(ctx->yaml);
|
||||
const uint8_t* data = p;
|
||||
GuLength* old_lenp = gu_map_get(ctx->data, gu_dump_length_key, void*);
|
||||
GuLength len = (GuLength)-1;
|
||||
gu_map_put(ctx->data, gu_dump_length_key, void*, &len);
|
||||
|
||||
for (int i = 0; i < srepr->members.len; i++) {
|
||||
const GuMember* member = &srepr->members.elems[i];
|
||||
gu_dump_str_scalar(ctx, member->name);
|
||||
const uint8_t* memp = &data[member->offset];
|
||||
if (member->is_flex) {
|
||||
// Flexible array member
|
||||
gu_assert(len != (GuLength)-1);
|
||||
size_t mem_s = gu_type_size(member->type);
|
||||
gu_yaml_begin_sequence(ctx->yaml);
|
||||
for (GuLength i = 0; i < len; i++) {
|
||||
gu_dump(member->type, &memp[i * mem_s], ctx);
|
||||
}
|
||||
gu_yaml_end(ctx->yaml);
|
||||
} else {
|
||||
gu_dump(member->type, memp, ctx);
|
||||
}
|
||||
}
|
||||
gu_yaml_end(ctx->yaml);
|
||||
if (old_lenp) {
|
||||
gu_map_set(ctx->data, gu_dump_length_key, void*, old_lenp);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_alias(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuTypeAlias* alias = gu_type_cast(type, alias);
|
||||
|
||||
gu_dump(alias->type, p, ctx);
|
||||
}
|
||||
|
||||
static const char gu_dump_reference_key[] = "reference";
|
||||
|
||||
static bool
|
||||
gu_dump_anchor(GuDump* ctx, const void* p)
|
||||
{
|
||||
GuMap* map = gu_map_get(ctx->data, gu_dump_reference_key, void*);
|
||||
if (map == NULL) {
|
||||
map = gu_new_addr_map(void, GuYamlAnchor,
|
||||
&gu_yaml_null_anchor, ctx->pool);
|
||||
gu_map_put(ctx->data, gu_dump_reference_key, void*, map);
|
||||
}
|
||||
GuYamlAnchor a = gu_map_get(map, p, GuYamlAnchor);
|
||||
if (a == gu_yaml_null_anchor) {
|
||||
a = gu_yaml_anchor(ctx->yaml);
|
||||
gu_map_put(map, p, GuYamlAnchor, a);
|
||||
return true;
|
||||
} else {
|
||||
gu_yaml_alias(ctx->yaml, a);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_referenced(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuTypeAlias* alias = gu_type_cast(type, alias);
|
||||
bool created = gu_dump_anchor(ctx, p);
|
||||
if (created) {
|
||||
gu_dump(alias->type, p, ctx);
|
||||
} else {
|
||||
// gu_assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_reference(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
(void) type;
|
||||
void* const* pp = p;
|
||||
bool created = gu_dump_anchor(ctx, *pp);
|
||||
if (created) {
|
||||
// gu_assert(false);
|
||||
GuPointerType* ptype = (GuPointerType*) type;
|
||||
gu_dump(ptype->pointed_type, *pp, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_shared(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
void* const* pp = p;
|
||||
if (*pp == NULL) {
|
||||
gu_dump_null(ctx);
|
||||
} else {
|
||||
bool created = gu_dump_anchor(ctx, *pp);
|
||||
if (created) {
|
||||
GuPointerType* ptype = (GuPointerType*) type;
|
||||
gu_dump(ptype->pointed_type, *pp, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_list(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuListType* ltype = (GuListType*) type;
|
||||
const uint8_t* up = p;
|
||||
int len = * (const int*) p;
|
||||
size_t elem_size = gu_type_size(ltype->elem_type);
|
||||
gu_yaml_begin_sequence(ctx->yaml);
|
||||
for (int i = 0; i < len; i++) {
|
||||
ptrdiff_t offset = ltype->elems_offset + i * elem_size;
|
||||
gu_dump(ltype->elem_type, &up[offset], ctx);
|
||||
}
|
||||
gu_yaml_end(ctx->yaml);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_variant(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuVariantType* vtype = gu_type_cast(type, GuVariant);
|
||||
const GuVariant* vp = p;
|
||||
int tag = gu_variant_tag(*vp);
|
||||
for (int i = 0; i < vtype->ctors.len; i++) {
|
||||
GuConstructor* ctor = &vtype->ctors.elems[i];
|
||||
if (ctor->c_tag == tag) {
|
||||
gu_yaml_begin_mapping(ctx->yaml);
|
||||
gu_dump_str_scalar(ctx, ctor->c_name);
|
||||
void* data = gu_variant_data(*vp);
|
||||
gu_dump(ctor->type, data, ctx);
|
||||
gu_yaml_end(ctx->yaml);
|
||||
return;
|
||||
}
|
||||
}
|
||||
gu_assert(false);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gu_dump_enum(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuEnumType* etype = gu_type_cast(type, enum);
|
||||
GuEnumConstant* cp = gu_enum_value(etype, p);
|
||||
gu_assert(cp != NULL);
|
||||
gu_dump_str_scalar(ctx, cp->name);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_dump_seq(GuDumpFn* dumper, GuType* type, const void* p,
|
||||
GuDump* ctx)
|
||||
{
|
||||
(void) dumper;
|
||||
GuSeqType* dtype = gu_type_cast(type, GuSeq);
|
||||
size_t elem_size = gu_type_size(dtype->elem_type);
|
||||
const GuSeq* seqp = p;
|
||||
GuSeq seq = *seqp;
|
||||
if (gu_seq_is_null(seq)) {
|
||||
gu_dump_null(ctx);
|
||||
return;
|
||||
}
|
||||
size_t len = gu_seq_length(seq);
|
||||
const uint8_t* data = gu_seq_data(seq);
|
||||
gu_yaml_begin_sequence(ctx->yaml);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
const void* elemp = &data[i * elem_size];
|
||||
gu_dump(dtype->elem_type, elemp, ctx);
|
||||
}
|
||||
gu_yaml_end(ctx->yaml);
|
||||
}
|
||||
|
||||
|
||||
GuTypeTable
|
||||
gu_dump_table = GU_TYPETABLE(
|
||||
GU_SLIST_0,
|
||||
{ gu_kind(int), gu_fn(gu_dump_int) },
|
||||
{ gu_kind(uint16_t), gu_fn(gu_dump_uint16) },
|
||||
{ gu_kind(size_t), gu_fn(gu_dump_size) },
|
||||
{ gu_kind(GuStr), gu_fn(gu_dump_str) },
|
||||
{ gu_kind(GuString), gu_fn(gu_dump_string) },
|
||||
{ gu_kind(struct), gu_fn(gu_dump_struct) },
|
||||
{ gu_kind(pointer), gu_fn(gu_dump_pointer) },
|
||||
{ gu_kind(GuMap), gu_fn(gu_dump_map) },
|
||||
{ gu_kind(alias), gu_fn(gu_dump_alias) },
|
||||
{ gu_kind(reference), gu_fn(gu_dump_reference) },
|
||||
{ gu_kind(referenced), gu_fn(gu_dump_referenced) },
|
||||
{ gu_kind(shared), gu_fn(gu_dump_shared) },
|
||||
{ gu_kind(GuList), gu_fn(gu_dump_list) },
|
||||
{ gu_kind(GuSeq), gu_fn(gu_dump_seq) },
|
||||
{ gu_kind(GuLength), gu_fn(gu_dump_length) },
|
||||
{ gu_kind(GuVariant), gu_fn(gu_dump_variant) },
|
||||
{ gu_kind(double), gu_fn(gu_dump_double) },
|
||||
{ gu_kind(enum), gu_fn(gu_dump_enum) },
|
||||
);
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef GU_DUMP_H_
|
||||
#define GU_DUMP_H_
|
||||
|
||||
#include <gu/defs.h>
|
||||
#include <gu/yaml.h>
|
||||
#include <gu/type.h>
|
||||
#include <gu/map.h>
|
||||
|
||||
typedef struct GuDump GuDump;
|
||||
|
||||
struct GuDump {
|
||||
GuPool* pool;
|
||||
GuYaml* yaml;
|
||||
GuMap* data;
|
||||
GuTypeMap* dumpers;
|
||||
bool print_address;
|
||||
};
|
||||
|
||||
typedef void (*GuDumpFn)(GuFn* self, GuType* type, const void* value, GuDump* ctx);
|
||||
|
||||
GuDump*
|
||||
gu_new_dump(GuWriter* wtr, GuTypeTable* dumpers, GuExn* err, GuPool* pool);
|
||||
|
||||
void
|
||||
gu_dump(GuType* type, const void* value, GuDump* ctx);
|
||||
|
||||
void
|
||||
gu_dump_stderr(GuType* type, const void* value, GuExn* err);
|
||||
|
||||
extern GuTypeTable
|
||||
gu_dump_table;
|
||||
|
||||
|
||||
#endif // GU_DUMP_H_
|
||||
@@ -1,339 +0,0 @@
|
||||
#include <gu/yaml.h>
|
||||
#include <gu/seq.h>
|
||||
#include <gu/assert.h>
|
||||
#include <gu/read.h>
|
||||
#include <gu/ucs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
const GuYamlAnchor gu_yaml_null_anchor = 0;
|
||||
|
||||
typedef const struct GuYamlState GuYamlState;
|
||||
|
||||
struct GuYamlState {
|
||||
const char* prefix;
|
||||
const char* suffix;
|
||||
GuYamlState* next;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
GuYamlState document, first_key, key, value, first_elem, elem;
|
||||
} gu_yaml_states = {
|
||||
.document = {
|
||||
.prefix = "---\n",
|
||||
.suffix = "\n...\n",
|
||||
.next = &gu_yaml_states.document,
|
||||
},
|
||||
.key = {
|
||||
.prefix = "? ",
|
||||
.next = &gu_yaml_states.value,
|
||||
},
|
||||
.value = {
|
||||
.prefix = ": ",
|
||||
.suffix = ",",
|
||||
.next = &gu_yaml_states.key,
|
||||
},
|
||||
.elem = {
|
||||
.suffix = ",",
|
||||
.next = &gu_yaml_states.elem,
|
||||
},
|
||||
};
|
||||
|
||||
typedef const struct GuYamlFrameClass GuYamlFrameClass;
|
||||
|
||||
struct GuYamlFrameClass {
|
||||
const char* open;
|
||||
GuYamlState* first;
|
||||
const char* close;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
GuYamlFrameClass document, mapping, sequence;
|
||||
} gu_yaml_frame_classes = {
|
||||
.mapping = {
|
||||
.open = "{",
|
||||
.first = &gu_yaml_states.key,
|
||||
.close = "}",
|
||||
},
|
||||
.sequence = {
|
||||
.open = "[",
|
||||
.first = &gu_yaml_states.elem,
|
||||
.close = "]",
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct GuYamlFrame GuYamlFrame;
|
||||
|
||||
struct GuYamlFrame {
|
||||
GuYamlFrameClass* klass;
|
||||
GuYamlState* next;
|
||||
};
|
||||
|
||||
typedef GuBuf GuYamlStack;
|
||||
|
||||
struct GuYaml {
|
||||
GuWriter* wtr;
|
||||
GuExn* err;
|
||||
GuPool* pool;
|
||||
GuYamlState* state;
|
||||
bool in_node;
|
||||
bool have_anchor;
|
||||
bool have_tag;
|
||||
int next_anchor;
|
||||
bool indent;
|
||||
int indent_level;
|
||||
bool indented;
|
||||
GuYamlStack* stack;
|
||||
};
|
||||
|
||||
|
||||
GuYaml*
|
||||
gu_new_yaml(GuWriter* wtr, GuExn* err, GuPool* pool)
|
||||
{
|
||||
GuYaml* yaml = gu_new(GuYaml, pool);
|
||||
yaml->wtr = wtr;
|
||||
yaml->pool = pool;
|
||||
yaml->err = err;
|
||||
yaml->state = &gu_yaml_states.document;
|
||||
yaml->in_node = false;
|
||||
yaml->have_anchor = false;
|
||||
yaml->have_tag = false;
|
||||
yaml->next_anchor = 1;
|
||||
yaml->stack = gu_new_buf(GuYamlFrame, pool);
|
||||
yaml->indent = true;
|
||||
yaml->indent_level = 0;
|
||||
yaml->indented = false;
|
||||
return yaml;
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_printf(GuYaml* yaml, const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
gu_vprintf(fmt, args, yaml->wtr, yaml->err);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_putc(GuYaml* yaml, char c)
|
||||
{
|
||||
gu_putc(c, yaml->wtr, yaml->err);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_puts(GuYaml* yaml, const char* str)
|
||||
{
|
||||
gu_puts(str, yaml->wtr, yaml->err);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_begin_line(GuYaml* yaml)
|
||||
{
|
||||
if (yaml->indent && !yaml->indented) {
|
||||
for (int i = 0; i < yaml->indent_level; i++) {
|
||||
gu_yaml_putc(yaml, ' ');
|
||||
}
|
||||
yaml->indented = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_end_line(GuYaml* yaml)
|
||||
{
|
||||
if (yaml->indent) {
|
||||
gu_yaml_putc(yaml, '\n');
|
||||
}
|
||||
yaml->indented = false;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gu_yaml_begin_node(GuYaml* yaml)
|
||||
{
|
||||
gu_yaml_begin_line(yaml);
|
||||
if (!yaml->in_node) {
|
||||
if (yaml->state->prefix != NULL) {
|
||||
gu_yaml_puts(yaml, yaml->state->prefix);
|
||||
}
|
||||
yaml->in_node = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_end_node(GuYaml* yaml)
|
||||
{
|
||||
gu_assert(yaml->in_node);
|
||||
if (yaml->state->suffix != NULL) {
|
||||
gu_yaml_puts(yaml, yaml->state->suffix);
|
||||
}
|
||||
gu_yaml_end_line(yaml);
|
||||
yaml->in_node = false;
|
||||
yaml->have_anchor = false;
|
||||
yaml->have_tag = false;
|
||||
if (yaml->state != NULL) {
|
||||
yaml->state = yaml->state->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_begin(GuYaml* yaml, GuYamlFrameClass* klass)
|
||||
{
|
||||
gu_yaml_begin_node(yaml);
|
||||
gu_yaml_puts(yaml, klass->open);
|
||||
gu_buf_push(yaml->stack, GuYamlFrame,
|
||||
((GuYamlFrame) { .klass = klass, .next = yaml->state}));
|
||||
yaml->state = klass->first;
|
||||
yaml->in_node = yaml->have_anchor = yaml->have_tag = false;
|
||||
gu_yaml_end_line(yaml);
|
||||
yaml->indent_level++;
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_begin_mapping(GuYaml* yaml)
|
||||
{
|
||||
gu_yaml_begin(yaml, &gu_yaml_frame_classes.mapping);
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_begin_sequence(GuYaml* yaml)
|
||||
{
|
||||
gu_yaml_begin(yaml, &gu_yaml_frame_classes.sequence);
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_end(GuYaml* yaml)
|
||||
{
|
||||
gu_assert(!yaml->in_node);
|
||||
yaml->indent_level--;
|
||||
gu_yaml_begin_line(yaml);
|
||||
GuYamlFrame f = gu_buf_pop(yaml->stack, GuYamlFrame);
|
||||
gu_yaml_puts(yaml, f.klass->close);
|
||||
yaml->state = f.next;
|
||||
yaml->in_node = true;
|
||||
gu_yaml_end_node(yaml);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gu_yaml_scalar(GuYaml* yaml, GuString s)
|
||||
{
|
||||
gu_yaml_begin_node(yaml);
|
||||
gu_yaml_putc(yaml, '"');
|
||||
GuPool* tmp_pool = gu_local_pool();
|
||||
GuReader* rdr = gu_string_reader(s, tmp_pool);
|
||||
GuExn* err = gu_exn(yaml->err, GuEOF, NULL);
|
||||
|
||||
static const char esc[0x20] = {
|
||||
[0x00] = '0',
|
||||
[0x07] = 'a', 'b', 't', 'n', 'v', 'f', 'r',
|
||||
[0x1b] = 'e'
|
||||
};
|
||||
|
||||
while (true) {
|
||||
GuUCS u = gu_read_ucs(rdr, err);
|
||||
if (!gu_ok(err)) {
|
||||
break;
|
||||
}
|
||||
if (GU_LIKELY(u >= 0x20 && u < 0x7f)) {
|
||||
if (GU_UNLIKELY(u == 0x22 || u == 0x5c)) {
|
||||
gu_yaml_putc(yaml, '\\');
|
||||
}
|
||||
gu_ucs_write(u, yaml->wtr, yaml->err);
|
||||
} else if (GU_UNLIKELY(u < 0x20 && esc[u])) {
|
||||
gu_yaml_printf(yaml, "\\%c", esc[u]);
|
||||
} else if (GU_UNLIKELY(u <= 0x9f)) {
|
||||
gu_yaml_printf(yaml, "\\x%02x", (unsigned) u);
|
||||
} else if (GU_UNLIKELY((u >= 0xd800 && u <= 0xdfff) ||
|
||||
(u >= 0xfffe && u <= 0xffff))) {
|
||||
gu_yaml_printf(yaml, "\\u%04x", (unsigned) u);
|
||||
} else {
|
||||
gu_ucs_write(u, yaml->wtr, yaml->err);
|
||||
}
|
||||
}
|
||||
gu_pool_free(tmp_pool);
|
||||
gu_yaml_putc(yaml, '"');
|
||||
gu_yaml_end_node(yaml);
|
||||
}
|
||||
|
||||
static void
|
||||
gu_yaml_tag(GuYaml* yaml, const char* format, ...)
|
||||
{
|
||||
gu_yaml_begin_node(yaml);
|
||||
gu_assert(!yaml->have_tag);
|
||||
gu_yaml_putc(yaml, '!');
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
gu_vprintf(format, args, yaml->wtr, yaml->err);
|
||||
va_end(args);
|
||||
gu_yaml_putc(yaml, ' ');
|
||||
yaml->have_tag = true;
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_tag_primary(GuYaml* yaml, const char* tag)
|
||||
{
|
||||
// TODO: check tag validity
|
||||
gu_yaml_tag(yaml, "%s", tag);
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_tag_secondary(GuYaml* yaml, const char* tag)
|
||||
{
|
||||
// TODO: check tag validity
|
||||
gu_yaml_tag(yaml, "!%s", tag);
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_tag_named(GuYaml* yaml, const char* handle, const char* tag)
|
||||
{
|
||||
// TODO: check tag validity
|
||||
gu_yaml_tag(yaml, "%s!%s", handle, tag);
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_tag_verbatim(GuYaml* yaml, const char* uri)
|
||||
{
|
||||
// XXX: uri escaping?
|
||||
gu_yaml_tag(yaml, "<%s>", uri);
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_tag_non_specific(GuYaml* yaml)
|
||||
{
|
||||
gu_yaml_tag(yaml, "");
|
||||
}
|
||||
|
||||
GuYamlAnchor
|
||||
gu_yaml_anchor(GuYaml* yaml)
|
||||
{
|
||||
gu_yaml_begin_node(yaml);
|
||||
gu_assert(!yaml->have_anchor);
|
||||
yaml->have_anchor = true;
|
||||
int anchor = yaml->next_anchor++;
|
||||
gu_yaml_printf(yaml, "&%d ", anchor);
|
||||
return anchor;
|
||||
}
|
||||
|
||||
void
|
||||
gu_yaml_alias(GuYaml* yaml, GuYamlAnchor anchor)
|
||||
{
|
||||
gu_yaml_begin_node(yaml);
|
||||
gu_assert(!yaml->have_anchor && !yaml->have_tag);
|
||||
gu_yaml_printf(yaml, "*%d ", anchor);
|
||||
gu_yaml_end_node(yaml);
|
||||
return;
|
||||
}
|
||||
|
||||
void gu_yaml_comment(GuYaml* yaml, GuString s)
|
||||
{
|
||||
gu_yaml_begin_line(yaml);
|
||||
gu_yaml_puts(yaml, "# ");
|
||||
// TODO: verify no newlines in comment
|
||||
gu_string_write(s, yaml->wtr, yaml->err);
|
||||
gu_yaml_puts(yaml, "\n");
|
||||
yaml->indented = false;
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef GU_YAML_H_
|
||||
#define GU_YAML_H_
|
||||
|
||||
#include <gu/mem.h>
|
||||
#include <gu/write.h>
|
||||
#include <gu/string.h>
|
||||
|
||||
typedef struct GuYaml GuYaml;
|
||||
|
||||
typedef int GuYamlAnchor;
|
||||
|
||||
extern const GuYamlAnchor gu_yaml_null_anchor;
|
||||
|
||||
GuYaml* gu_new_yaml(GuWriter* wtr, GuExn* err, GuPool* pool);
|
||||
|
||||
GuYamlAnchor gu_yaml_anchor(GuYaml* yaml);
|
||||
|
||||
void gu_yaml_tag_primary(GuYaml* yaml, const char* tag);
|
||||
void gu_yaml_tag_secondary(GuYaml* yaml, const char* tag);
|
||||
void gu_yaml_tag_named(GuYaml* yaml, const char* handle, const char* tag);
|
||||
void gu_yaml_tag_verbatim(GuYaml* yaml, const char* uri);
|
||||
void gu_yaml_tag_non_specific(GuYaml* yaml);
|
||||
void gu_yaml_comment(GuYaml* yaml, GuString comment);
|
||||
|
||||
|
||||
void gu_yaml_scalar(GuYaml* yaml, GuString scalar);
|
||||
|
||||
void gu_yaml_alias(GuYaml* yaml, GuYamlAnchor anchor);
|
||||
|
||||
void gu_yaml_begin_document(GuYaml* yaml);
|
||||
|
||||
void gu_yaml_begin_sequence(GuYaml* yaml);
|
||||
|
||||
void gu_yaml_begin_mapping(GuYaml* yaml);
|
||||
|
||||
void gu_yaml_end(GuYaml* yaml);
|
||||
|
||||
#endif // GU_YAML_H_
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include <gu/type.h>
|
||||
#include <gu/dump.h>
|
||||
#include <gu/enum.h>
|
||||
|
||||
/// Linearization of abstract syntax trees.
|
||||
|
||||
Reference in New Issue
Block a user