Files
gf-core/src/runtime/c/pgf/reader.c
2012-02-29 14:43:08 +00:00

885 lines
22 KiB
C

/*
* Copyright 2010 University of Helsinki.
*
* This file is part of libpgf.
*
* Libpgf is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Libpgf is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libpgf. If not, see <http://www.gnu.org/licenses/>.
*/
#include "data.h"
#include "expr.h"
#include <gu/defs.h>
#include <gu/map.h>
#include <gu/seq.h>
#include <gu/assert.h>
#include <gu/intern.h>
#include <gu/in.h>
#include <gu/bits.h>
#include <gu/exn.h>
#include <gu/utf8.h>
#define GU_LOG_ENABLE
#include <gu/log.h>
typedef struct PgfIdContext PgfIdContext;
typedef GuMap PgfContsMap;
//
// PgfReader
//
typedef struct PgfReader PgfReader;
struct PgfReader {
GuIn* in;
GuExn* err;
GuPool* opool;
GuPool* tmp_pool;
GuSymTable* symtab;
PgfConcr* curr_concr;
GuMap* curr_lindefs;
PgfContsMap* curr_conts_map; // used temporary for building the bu index for the parser
GuTypeMap* read_to_map;
GuTypeMap* read_new_map;
void* curr_key;
};
typedef struct PgfReadTagExn PgfReadTagExn;
struct PgfReadTagExn {
GuType* type;
int tag;
};
static GU_DEFINE_TYPE(PgfReadTagExn, abstract, _);
static GU_DEFINE_TYPE(PgfReadExn, abstract, _);
static uint8_t
pgf_read_u8(PgfReader* rdr)
{
uint8_t u = gu_in_u8(rdr->in, rdr->err);
gu_debug("u8: %u", u);
return u;
}
static uint32_t
pgf_read_uint(PgfReader* rdr)
{
uint32_t u = 0;
int shift = 0;
uint8_t b = 0;
do {
b = pgf_read_u8(rdr);
gu_return_on_exn(rdr->err, 0);
u |= (b & ~0x80) << shift;
shift += 7;
} while (b & 0x80);
gu_debug("uint: %u", u);
return u;
}
static int32_t
pgf_read_int(PgfReader* rdr)
{
uint32_t u = pgf_read_uint(rdr);
return gu_decode_2c32(u, rdr->err);
}
static GuLength
pgf_read_len(PgfReader* rdr)
{
int32_t len = pgf_read_int(rdr);
// It's crucial that we return 0 on failure, so the
// caller can proceed without checking for error
// immediately.
gu_return_on_exn(rdr->err, 0);
if (len < 0) {
gu_raise_i(rdr->err, PgfReadTagExn,
.type = gu_type(GuLength), .tag = len);
return 0;
}
return (GuLength) len;
}
typedef const struct PgfReadToFn PgfReadToFn;
struct PgfReadToFn {
void (*fn)(GuType* type, PgfReader* rdr, void* to);
};
static void
pgf_read_to(PgfReader* rdr, GuType* type, void* to) {
PgfReadToFn* fn = gu_type_map_get(rdr->read_to_map, type);
fn->fn(type, rdr, to);
}
typedef const struct PgfReadNewFn PgfReadNewFn;
struct PgfReadNewFn {
void* (*fn)(GuType* type, PgfReader* rdr, GuPool* pool,
size_t* size_out);
};
static void*
pgf_read_new(PgfReader* rdr, GuType* type, GuPool* pool, size_t* size_out)
{
size_t size = 0;
PgfReadNewFn* fn = gu_type_map_get(rdr->read_new_map, type);
return fn->fn(type, rdr, pool, size_out ? size_out : &size);
}
static void*
pgf_read_new_type(GuType* type, PgfReader* rdr, GuPool* pool,
size_t* size_out)
{
GuTypeRepr* repr = gu_type_repr(type);
void* to = gu_malloc_aligned(pool, repr->size, repr->align);
pgf_read_to(rdr, type, to);
*size_out = repr->size;
return to;
}
static void*
pgf_read_struct(GuStructRepr* stype, PgfReader* rdr, void* to,
GuPool* pool, size_t* size_out)
{
GuTypeRepr* repr = gu_type_cast((GuType*)stype, repr);
size_t size = repr->size;
GuLength length = 0;
bool have_length = false;
uint8_t* p = NULL;
uint8_t* bto = to;
gu_enter("-> struct %s", stype->name);
for (int i = 0; i < stype->members.len; i++) {
const GuMember* m = &stype->members.elems[i];
gu_enter("-> %s.%s", stype->name, m->name);
if (m->is_flex) {
gu_assert(have_length && p == NULL && pool != NULL);
size_t m_size = gu_type_size(m->type);
size = gu_flex_size(size, m->offset,
length, m_size);
p = gu_malloc_aligned(pool, size, repr->align);
for (size_t j = 0; j < length; j++) {
pgf_read_to(rdr, m->type,
&p[m->offset + j * m_size]);
gu_return_on_exn(rdr->err, NULL);
}
} else {
pgf_read_to(rdr, m->type, &bto[m->offset]);
gu_return_on_exn(rdr->err, NULL);
}
if (m->type == gu_type(GuLength)) {
gu_assert(!have_length);
have_length = true;
length = gu_member(GuLength, to, m->offset);
}
gu_exit("<- %s.%s", stype->name, m->name);
}
if (p) {
memcpy(p, to, repr->size);
}
if (size_out) {
*size_out = size;
}
gu_exit("<- struct %s", stype->name);
return p;
}
static void
pgf_read_to_struct(GuType* type, PgfReader* rdr, void* to)
{
GuStructRepr* stype = gu_type_cast(type, struct);
pgf_read_struct(stype, rdr, to, NULL, NULL);
}
static void*
pgf_read_new_struct(GuType* type, PgfReader* rdr,
GuPool* pool, size_t* size_out)
{
GuStructRepr* stype = gu_type_cast(type, struct);
if (gu_struct_has_flex(stype)) {
GuPool* tmp_pool = gu_new_pool();
void* to = gu_type_malloc(type, tmp_pool);
void* p = pgf_read_struct(stype, rdr, to, pool, size_out);
gu_pool_free(tmp_pool);
gu_assert(p);
return p;
} else {
void* to = gu_type_malloc(type, pool);
pgf_read_struct(stype, rdr, to, NULL, NULL);
return to;
}
}
static void
pgf_read_to_pointer(GuType* type, PgfReader* rdr, void* to)
{
GuPointerType* ptype = (GuPointerType*) type;
GuType* pointed = ptype->pointed_type;
gu_require(gu_type_has_kind(pointed, gu_kind(struct)) ||
gu_type_has_kind(pointed, gu_kind(abstract)));
GuStruct** sto = to;
*sto = pgf_read_new(rdr, pointed, rdr->opool, NULL);
}
static void
pgf_read_to_GuVariant(GuType* type, PgfReader* rdr, void* to)
{
GuVariantType* vtype = (GuVariantType*) type;
GuVariant* vto = to;
uint8_t btag = pgf_read_u8(rdr);
gu_return_on_exn(rdr->err,);
if (btag >= vtype->ctors.len) {
gu_raise_i(rdr->err, PgfReadTagExn,
.type = type, .tag = btag);
return;
}
GuConstructor* ctor = &vtype->ctors.elems[btag];
gu_enter("-> variant %s", ctor->c_name);
GuPool* tmp_pool = gu_new_pool();
GuTypeRepr* repr = gu_type_repr(ctor->type);
size_t size = repr->size;
void* init = pgf_read_new(rdr, ctor->type, tmp_pool, &size);
*vto = gu_make_variant(btag, size, repr->align, init, rdr->opool);
gu_pool_free(tmp_pool);
gu_exit("<- variant %s", ctor->c_name);
}
static void
pgf_read_to_enum(GuType* type, PgfReader* rdr, void* to)
{
// For now, assume that enum values are encoded in a single octet
GuEnumType* etype = (GuEnumType*) type;
uint8_t tag = pgf_read_u8(rdr);
gu_return_on_exn(rdr->err,);
if (tag >= etype->constants.len) {
gu_raise_i(rdr->err, PgfReadTagExn,
.type = type, .tag = tag);
return;
}
GuEnumConstant* econ = &etype->constants.elems[tag];
size_t size = gu_type_size(type);
if (size == sizeof(int8_t)) {
*((int8_t*) to) = econ->value;
} else if (size == sizeof(int16_t)) {
*((int16_t*) to) = econ->value;
} else if (size == sizeof(int32_t)) {
*((int32_t*) to) = econ->value;
} else if (size == sizeof(int64_t)) {
*((int64_t*) to) = econ->value;
} else {
gu_impossible();
}
}
static void
pgf_read_to_void(GuType* info, PgfReader* rdr, void* to)
{
(void) (info && rdr && to);
}
static void
pgf_read_to_int(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
*(int*) to = pgf_read_int(rdr);
}
static void
pgf_read_to_uint16_t(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
*(uint16_t*) to = gu_in_u16be(rdr->in, rdr->err);
}
static void
pgf_read_to_GuLength(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
*(GuLength*) to = pgf_read_len(rdr);
}
static void
pgf_read_to_double(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
*(double*) to = gu_in_f64be(rdr->in, rdr->err);
}
static void
pgf_read_to_alias(GuType* type, PgfReader* rdr, void* to)
{
GuTypeAlias* atype = gu_type_cast(type, alias);
pgf_read_to(rdr, atype->type, to);
}
static void
pgf_read_into_map(GuMapType* mtype, PgfReader* rdr, GuMap* map)
{
GuPool* tmp_pool = gu_new_pool();
void* key = NULL;
GuLength len = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, );
if (mtype->hasher) {
key = gu_type_malloc(mtype->key_type, tmp_pool);
}
for (size_t i = 0; i < len; i++) {
if (mtype->hasher) {
pgf_read_to(rdr, mtype->key_type, key);
} else {
key = pgf_read_new(rdr, mtype->key_type,
rdr->opool, NULL);
}
gu_return_on_exn(rdr->err, );
rdr->curr_key = key;
/* If an old value already exists, read into
it. This allows us to create the value
object and point into it before we read the
content. */
void* val0p = gu_map_insert(map, key);
void* valp = pgf_read_new(rdr, mtype->value_type, tmp_pool, NULL);
// if the map has been updated,
// then the old val0p may not be valid.
val0p = gu_map_find(map, key);
memcpy(val0p, valp, gu_type_size(mtype->value_type));
gu_return_on_exn(rdr->err, );
}
gu_pool_free(tmp_pool);
}
static void*
pgf_read_new_GuMap(GuType* type, PgfReader* rdr, GuPool* pool, size_t* size_out)
{
(void) size_out;
GuMapType* mtype = (GuMapType*) type;
GuMap* map = gu_map_type_make(mtype, pool);
pgf_read_into_map(mtype, rdr, map);
gu_return_on_exn(rdr->err, NULL);
return map;
}
static void
pgf_read_to_GuString(GuType* type, PgfReader* rdr, void* to)
{
(void) (type);
gu_enter("-> GuString");
GuString* sp = to;
GuPool* tmp_pool = gu_new_pool();
GuStringBuf* sbuf = gu_string_buf(tmp_pool);
GuWriter* wtr = gu_string_buf_writer(sbuf);
GuLength len = pgf_read_len(rdr);
for (size_t i = 0; i < len; i++) {
GuUCS ucs = gu_in_utf8(rdr->in, rdr->err);
gu_ucs_write(ucs, wtr, rdr->err);
}
GuString str = gu_string_buf_freeze(sbuf, tmp_pool);
GuSymbol sym = gu_symtable_intern(rdr->symtab, str);
gu_pool_free(tmp_pool);
gu_exit("<- GuString");
*sp = sym;
}
static void
pgf_read_to_PgfCId(GuType* type, PgfReader* rdr, void* to)
{
(void) (type);
gu_enter("-> PgfCId");
PgfCId* sp = to;
GuPool* tmp_pool = gu_new_pool();
GuStringBuf* sbuf = gu_string_buf(tmp_pool);
GuWriter* wtr = gu_string_buf_writer(sbuf);
GuLength len = pgf_read_len(rdr);
for (size_t i = 0; i < len; i++) {
// CIds are in latin-1
GuUCS ucs = gu_in_u8(rdr->in, rdr->err);
gu_ucs_write(ucs, wtr, rdr->err);
}
GuString str = gu_string_buf_freeze(sbuf, tmp_pool);
GuSymbol sym = gu_symtable_intern(rdr->symtab, str);
gu_pool_free(tmp_pool);
gu_exit("<- PgfCId");
*sp = sym;
}
static void
pgf_read_to_PgfCCatId(GuType* type, PgfReader* rdr, void* to)
{
(void) (type);
PgfCCat** pto = to;
int fid = pgf_read_int(rdr);
gu_return_on_exn(rdr->err,);
PgfCCat* ccat = gu_map_get(rdr->curr_concr->ccats, &fid, PgfCCat*);
if (!ccat) {
ccat = gu_new(PgfCCat, rdr->opool);
ccat->cnccat = NULL;
ccat->lindefs = gu_map_get(rdr->curr_lindefs, &fid, PgfFunIds*);
ccat->n_synprods = 0;
ccat->prods = gu_null_seq;
ccat->fid = fid;
gu_map_put(rdr->curr_concr->ccats, &fid, PgfCCat*, ccat);
}
*pto = ccat;
}
static void
pgf_read_to_PgfCCat(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
gu_enter("->");
int* fidp = rdr->curr_key;
GuLength n_prods = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, );
PgfCCat* ccat = to;
ccat->cnccat = NULL;
ccat->lindefs = gu_map_get(rdr->curr_lindefs, fidp, PgfFunIds*);
ccat->prods = gu_new_seq(PgfProduction, n_prods, rdr->opool);
ccat->fid = *fidp;
size_t top = 0;
size_t bot = n_prods-1;
for (size_t i = 0; i < n_prods; i++) {
PgfProduction prod;
pgf_read_to(rdr, gu_type(PgfProduction), &prod);
gu_return_on_exn(rdr->err, );
GuVariantInfo i = gu_variant_open(prod);
switch (i.tag) {
case PGF_PRODUCTION_APPLY: {
PgfProductionApply* papp = i.data;
if (gu_seq_length(papp->args) > 0)
gu_seq_set(ccat->prods, PgfProduction, top++, prod);
else
gu_seq_set(ccat->prods, PgfProduction, bot--, prod);
break;
}
case PGF_PRODUCTION_COERCE: {
gu_seq_set(ccat->prods, PgfProduction, top++, prod);
break;
}
default:
gu_impossible();
}
}
ccat->n_synprods = top;
gu_exit("<-");
}
// This is only needed because new_struct would otherwise override.
// TODO: get rid of new_struct and all the FAM mess
static void*
pgf_read_new_PgfCCat(GuType* type, PgfReader* rdr, GuPool* pool,
size_t* size_out)
{
PgfCCat* ccat = gu_map_get(rdr->curr_concr->ccats, rdr->curr_key, PgfCCat*);
if (!ccat) {
ccat = gu_new(PgfCCat, pool);
gu_map_put(rdr->curr_concr->ccats, rdr->curr_key, PgfCCat*, ccat);
}
pgf_read_to_PgfCCat(type, rdr, ccat);
*size_out = sizeof(PgfCCat);
return ccat;
}
static void*
pgf_read_new_GuList(GuType* type, PgfReader* rdr, GuPool* pool, size_t* size_out)
{
GuListType* ltype = gu_type_cast(type, GuList);
GuLength length = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, NULL);
void* list = gu_list_type_alloc(ltype, length, pool);
for (size_t i = 0; i < length; i++) {
void* elem = gu_list_type_index(ltype, list, i);
pgf_read_to(rdr, ltype->elem_type, elem);
gu_return_on_exn(rdr->err, NULL);
}
*size_out = gu_flex_size(ltype->size, ltype->elems_offset,
length,
gu_type_size(ltype->elem_type));
return list;
}
static void
pgf_read_to_GuSeq(GuType* type, PgfReader* rdr, void* to)
{
gu_enter("->");
GuSeqType* stype = gu_type_cast(type, GuSeq);
GuLength length = pgf_read_len(rdr);
GuTypeRepr* repr = gu_type_repr(stype->elem_type);
gu_return_on_exn(rdr->err, );
GuSeq seq = gu_make_seq(repr->size, length, rdr->opool);
uint8_t* data = gu_seq_data(seq);
for (size_t i = 0; i < length; i++) {
void* elem = &data[i * repr->size];
pgf_read_to(rdr, stype->elem_type, elem);
gu_return_on_exn(rdr->err, );
}
GuSeq* sto = to;
*sto = seq;
gu_exit("<-");
}
static void
pgf_read_to_PgfEquationsM(GuType* type, PgfReader* rdr, void* to)
{
GuSeq* sto = to;
uint8_t tag = pgf_read_u8(rdr);
gu_return_on_exn(rdr->err,);
switch (tag) {
case 0:
*sto = gu_null_seq;
break;
case 1: {
GuLength length = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, );
GuSeq seq = gu_new_seq(PgfEquation*, length, rdr->opool);
PgfEquation** data = gu_seq_data(seq);
for (size_t i = 0; i < length; i++) {
GuLength n_patts = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, );
PgfEquation *equ =
gu_malloc(rdr->opool,
sizeof(PgfEquation)+sizeof(PgfPatt)*n_patts);
equ->n_patts = n_patts;
for (GuLength j = 0; j < n_patts; j++) {
pgf_read_to(rdr, gu_type(PgfPatt), &equ->patts[j]);
gu_return_on_exn(rdr->err, );
}
pgf_read_to(rdr, gu_type(PgfExpr), &equ->body);
gu_return_on_exn(rdr->err, );
data[i] = equ;
}
*sto = seq;
break;
}
default:
gu_raise_i(rdr->err, PgfReadTagExn,
.type = type, .tag = tag);
break;
}
}
static void
pgf_read_to_PgfSeqId(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
int32_t id = pgf_read_int(rdr);
gu_return_on_exn(rdr->err,);
if (id < 0 || id >= gu_list_length(rdr->curr_concr->sequences)) {
gu_raise(rdr->err, PgfReadExn);
return;
}
*(PgfSeqId*) to = gu_list_elems(rdr->curr_concr->sequences)[id];
}
static void
pgf_read_to_PgfFunId(GuType* type, PgfReader* rdr, void* to)
{
(void) type;
int32_t id = pgf_read_int(rdr);
gu_return_on_exn(rdr->err,);
if (id < 0 || id >= gu_list_length(rdr->curr_concr->cncfuns)) {
gu_raise(rdr->err, PgfReadExn);
return;
}
*(PgfFunId*) to = gu_list_elems(rdr->curr_concr->cncfuns)[id];
}
static GU_DEFINE_TYPE(PgfLinDefs, GuIntMap, gu_ptr_type(PgfFunIds),
&gu_null_struct);
typedef PgfCCat PgfCCatData;
static GU_DEFINE_TYPE(PgfCCatData, typedef, gu_type(PgfCCat));
static GU_DEFINE_TYPE(PgfCCatMap, GuIntMap, gu_ptr_type(PgfCCat),
&gu_null_struct);
static GU_DEFINE_TYPE(PgfCncCatMap, GuStringMap, gu_ptr_type(PgfCncCat),
&gu_null_struct);
static PgfCncCat*
pgf_ccat_set_cnccat(PgfCCat* ccat)
{
if (!ccat->cnccat) {
size_t n_prods = gu_seq_length(ccat->prods);
for (size_t i = 0; i < n_prods; i++) {
PgfProduction prod =
gu_seq_get(ccat->prods, PgfProduction, i);
GuVariantInfo i = gu_variant_open(prod);
switch (i.tag) {
case PGF_PRODUCTION_COERCE: {
PgfProductionCoerce* pcoerce = i.data;
PgfCncCat* cnccat =
pgf_ccat_set_cnccat(pcoerce->coerce);
if (!ccat->cnccat) {
ccat->cnccat = cnccat;
} else if (ccat->cnccat != cnccat) {
// XXX: real error
gu_impossible();
}
break;
}
case PGF_PRODUCTION_APPLY:
// Shouldn't happen with current PGF.
// XXX: real error
gu_impossible();
break;
default:
gu_impossible();
}
}
}
return ccat->cnccat;
}
typedef struct {
GuMapItor fn;
PgfReader* rdr;
} PgfIndexFn;
static void
pgf_read_ccat_cb(GuMapItor* fn, const void* key, void* value, GuExn* err)
{
(void) (key && err);
PgfCCat* ccat = *((PgfCCat**) value);
pgf_ccat_set_cnccat(ccat);
}
extern GU_DECLARE_TYPE(PgfContsMap, GuMap);
void
pgf_parser_bu_index(PgfConcr* concr, PgfCCat* cat, PgfProduction prod,
PgfContsMap* conts_map,
GuPool *pool, GuPool *tmp_pool);
void
pgf_lzr_index(PgfConcr* concr, PgfCCat* cat, PgfProduction prod,
GuPool *pool);
static void
pgf_index_prods(GuMapItor* fn, const void* key, void* value, GuExn* err)
{
(void) (key && err);
PgfIndexFn* clo = (PgfIndexFn*) fn;
PgfCCat* ccat = *((PgfCCat**) value);
PgfReader *rdr = clo->rdr;
if (gu_seq_is_null(ccat->prods))
return;
size_t n_prods = gu_seq_length(ccat->prods);
for (size_t i = 0; i < n_prods; i++) {
PgfProduction prod = gu_seq_get(ccat->prods, PgfProduction, i);
pgf_parser_bu_index(rdr->curr_concr, ccat, prod,
rdr->curr_conts_map,
rdr->opool, rdr->tmp_pool);
pgf_lzr_index(rdr->curr_concr, ccat, prod, rdr->opool);
}
}
static void*
pgf_read_new_PgfConcr(GuType* type, PgfReader* rdr, GuPool* pool,
size_t* size_out)
{
(void) (type && size_out);
PgfConcr* concr = gu_new(PgfConcr, pool);
rdr->curr_concr = concr;
concr->cflags =
pgf_read_new(rdr, gu_type(PgfFlags), pool, NULL);
concr->printnames =
pgf_read_new(rdr, gu_type(PgfPrintNames), pool, NULL);
concr->sequences =
pgf_read_new(rdr, gu_type(PgfSequences), pool, NULL);
concr->cncfuns =
pgf_read_new(rdr, gu_type(PgfCncFuns), pool, NULL);
GuMapType* lindefs_t = gu_type_cast(gu_type(PgfLinDefs), GuMap);
rdr->curr_lindefs = gu_map_type_make(lindefs_t, rdr->tmp_pool);
pgf_read_into_map(lindefs_t, rdr, rdr->curr_lindefs);
rdr->curr_conts_map = gu_map_type_new(PgfContsMap, rdr->tmp_pool);
GuMapType* ccats_t = gu_type_cast(gu_type(PgfCCatMap), GuMap);
concr->ccats =
gu_new_int_map(PgfCCat*, &gu_null_struct, pool);
concr->fun_indices = gu_map_type_new(PgfFunIndices, pool);
concr->coerce_idx = gu_map_type_new(PgfCoerceIdx, pool);
concr->lexicon_idx = gu_map_type_new(PgfTransitions,pool);
concr->epsilon_idx = gu_map_type_new(PgfEpsilonIdx, pool);
pgf_read_into_map(ccats_t, rdr, concr->ccats);
concr->cnccats = pgf_read_new(rdr, gu_type(PgfCncCatMap), pool, NULL);
concr->total_cats = pgf_read_int(rdr);
concr->max_fid = concr->total_cats;
PgfIndexFn clo1 = { { pgf_read_ccat_cb }, rdr };
gu_map_iter(concr->ccats, &clo1.fn, NULL);
PgfIndexFn clo2 = { { pgf_index_prods }, rdr };
gu_map_iter(concr->ccats, &clo2.fn, NULL);
// set the function ids
int n_funs = gu_list_length(concr->cncfuns);
for (int funid = 0; funid < n_funs; funid++) {
PgfCncFun* cncfun = gu_list_index(concr->cncfuns, funid);
cncfun->funid = funid;
}
return concr;
}
static void*
pgf_read_new_PgfCncCat(GuType* type, PgfReader* rdr, GuPool* pool,
size_t* size_out)
{
PgfCId cid = *(PgfCId*) rdr->curr_key;
gu_enter("-> cid");
(void) (type && size_out);
int first = pgf_read_int(rdr);
int last = pgf_read_int(rdr);
int n_lins = pgf_read_len(rdr);
PgfCncCat* cnccat =
gu_malloc(pool, sizeof(PgfCncCat)+n_lins*sizeof(GuString));
cnccat->cid = cid;
int len = last + 1 - first;
cnccat->cats = gu_new_list(PgfCCatIds, pool, len);
for (int i = 0; i < len; i++) {
int fid = first + i;
PgfCCat* ccat = gu_map_get(rdr->curr_concr->ccats, &fid, PgfCCat*);
if (!ccat) {
ccat = gu_new(PgfCCat, rdr->opool);
ccat->cnccat = NULL;
ccat->lindefs = gu_map_get(rdr->curr_lindefs, &fid, PgfFunIds*);
ccat->n_synprods = 0;
ccat->prods = gu_null_seq;
ccat->fid = fid;
gu_map_put(rdr->curr_concr->ccats, &fid, PgfCCat*, ccat);
}
gu_list_index(cnccat->cats, i) = ccat;
ccat->cnccat = cnccat;
gu_debug("range[%d] = %d", i, ccat ? ccat->fid : -1);
}
cnccat->n_lins = n_lins;
for (size_t i = 0; i < cnccat->n_lins; i++) {
pgf_read_to(rdr, gu_type(GuString), &cnccat->labels[i]);
}
gu_exit("<-");
return cnccat;
}
#define PGF_READ_TO_FN(k_, fn_) \
{ gu_kind(k_), (void*) &(PgfReadToFn){ fn_ } }
#define PGF_READ_TO(k_) \
PGF_READ_TO_FN(k_, pgf_read_to_##k_)
static GuTypeTable
pgf_read_to_table = GU_TYPETABLE(
GU_SLIST_0,
PGF_READ_TO(struct),
PGF_READ_TO(GuVariant),
PGF_READ_TO(enum),
PGF_READ_TO(void),
PGF_READ_TO(int),
PGF_READ_TO(uint16_t),
PGF_READ_TO(GuLength),
PGF_READ_TO(PgfCId),
PGF_READ_TO(GuString),
PGF_READ_TO(double),
PGF_READ_TO(pointer),
PGF_READ_TO(PgfEquationsM),
PGF_READ_TO(GuSeq),
PGF_READ_TO(PgfCCatId),
PGF_READ_TO(PgfCCat),
PGF_READ_TO(PgfSeqId),
PGF_READ_TO(PgfFunId),
PGF_READ_TO(alias));
#define PGF_READ_NEW_FN(k_, fn_) \
{ gu_kind(k_), (void*) &(PgfReadNewFn){ fn_ } }
#define PGF_READ_NEW(k_) \
PGF_READ_NEW_FN(k_, pgf_read_new_##k_)
static GuTypeTable
pgf_read_new_table = GU_TYPETABLE(
GU_SLIST_0,
PGF_READ_NEW(type),
PGF_READ_NEW(struct),
PGF_READ_NEW(GuMap),
PGF_READ_NEW(GuList),
PGF_READ_NEW(PgfCCat),
PGF_READ_NEW(PgfCncCat),
PGF_READ_NEW(PgfConcr)
);
static PgfReader*
pgf_new_reader(GuIn* in, GuPool* opool, GuPool* tmp_pool, GuExn* err)
{
PgfReader* rdr = gu_new(PgfReader, tmp_pool);
rdr->opool = opool;
rdr->tmp_pool = tmp_pool;
rdr->symtab = gu_new_symtable(opool, tmp_pool);
rdr->err = err;
rdr->in = in;
rdr->curr_concr = NULL;
rdr->curr_lindefs = NULL;
rdr->curr_conts_map = NULL;
rdr->read_to_map = gu_new_type_map(&pgf_read_to_table, tmp_pool);
rdr->read_new_map = gu_new_type_map(&pgf_read_new_table, tmp_pool);
return rdr;
}
PgfPGF*
pgf_read(GuIn* in, GuPool* pool, GuExn* err)
{
GuPool* tmp_pool = gu_new_pool();
PgfReader* rdr = pgf_new_reader(in, pool, tmp_pool, err);
PgfPGF* pgf = pgf_read_new(rdr, gu_type(PgfPGF), pool, NULL);
gu_pool_free(tmp_pool);
gu_return_on_exn(err, NULL);
return pgf;
}