forked from GitHub/gf-core
1848 lines
49 KiB
C++
1848 lines
49 KiB
C++
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
#ifdef _WIN32
|
|
#include <sys\stat.h>
|
|
#endif
|
|
|
|
#include "data.h"
|
|
#include "reader.h"
|
|
#include "writer.h"
|
|
#include "printer.h"
|
|
|
|
static void
|
|
pgf_exn_clear(PgfExn* err)
|
|
{
|
|
err->type = PGF_EXN_NONE;
|
|
err->code = 0;
|
|
err->msg = NULL;
|
|
}
|
|
|
|
#define PGF_API_BEGIN \
|
|
pgf_exn_clear(err); \
|
|
\
|
|
try \
|
|
|
|
#define PGF_API_END \
|
|
catch (pgf_systemerror& e) { \
|
|
err->type = PGF_EXN_SYSTEM_ERROR; \
|
|
err->code = e.code(); \
|
|
err->msg = e.filepath(); \
|
|
} catch (pgf_error& e) { \
|
|
err->type = PGF_EXN_PGF_ERROR; \
|
|
err->msg = strdup(e.what()); \
|
|
}
|
|
|
|
PGF_INTERNAL size_t master_size = 6;
|
|
PGF_INTERNAL char master_text[] = {'m','a','s','t','e','r',0};
|
|
|
|
PGF_API
|
|
PgfDB *pgf_read_pgf(const char* fpath,
|
|
PgfRevision *revision,
|
|
PgfExn* err)
|
|
{
|
|
PgfDB *db = NULL;
|
|
FILE *in = NULL;
|
|
|
|
PGF_API_BEGIN {
|
|
db = new PgfDB(NULL, 0, 0);
|
|
in = fopen(fpath, "rb");
|
|
if (!in) {
|
|
throw pgf_systemerror(errno, fpath);
|
|
}
|
|
|
|
{
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfReader rdr(in);
|
|
ref<PgfPGF> pgf = rdr.read_pgf();
|
|
|
|
PgfDB::set_revision(pgf);
|
|
*revision = pgf.as_object();
|
|
}
|
|
|
|
db->ref_count++;
|
|
return db;
|
|
} PGF_API_END
|
|
|
|
end:
|
|
if (in != NULL)
|
|
fclose(in);
|
|
|
|
if (db != NULL)
|
|
delete db;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
PgfDB *pgf_boot_ngf(const char* pgf_path, const char* ngf_path,
|
|
PgfRevision *revision,
|
|
PgfExn* err)
|
|
{
|
|
PgfDB *db = NULL;
|
|
FILE *in = NULL;
|
|
|
|
PGF_API_BEGIN {
|
|
db = new PgfDB(ngf_path, O_CREAT | O_EXCL | O_RDWR,
|
|
#ifndef _WIN32
|
|
S_IRUSR | S_IWUSR
|
|
#else
|
|
_S_IREAD | _S_IWRITE
|
|
#endif
|
|
);
|
|
|
|
in = fopen(pgf_path, "rb");
|
|
if (!in) {
|
|
throw pgf_systemerror(errno, pgf_path);
|
|
}
|
|
|
|
{
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfReader rdr(in);
|
|
ref<PgfPGF> pgf = rdr.read_pgf();
|
|
|
|
PgfDB::set_revision(pgf);
|
|
*revision = pgf.as_object();
|
|
|
|
PgfDB::sync();
|
|
}
|
|
|
|
db->ref_count++;
|
|
return db;
|
|
} PGF_API_END
|
|
|
|
if (in != NULL)
|
|
fclose(in);
|
|
|
|
if (db != NULL) {
|
|
delete db;
|
|
remove(ngf_path);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
PgfDB *pgf_read_ngf(const char *fpath,
|
|
PgfRevision *revision,
|
|
PgfExn* err)
|
|
{
|
|
PgfDB *db = NULL;
|
|
|
|
bool is_new = false;
|
|
PGF_API_BEGIN {
|
|
db = new PgfDB(fpath, O_RDWR, 0);
|
|
|
|
PgfText *master = (PgfText *)alloca(sizeof(PgfText)+master_size+1);
|
|
master->size = master_size;
|
|
memcpy(&master->text, master_text, master_size+1);
|
|
|
|
{
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::get_revision(master);
|
|
Node<PgfPGF>::add_value_ref(pgf);
|
|
*revision = pgf.as_object();
|
|
}
|
|
|
|
db->ref_count++;
|
|
return db;
|
|
} PGF_API_END
|
|
|
|
if (db != NULL) {
|
|
delete db;
|
|
if (is_new)
|
|
remove(fpath);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
PgfDB *pgf_new_ngf(PgfText *abstract_name,
|
|
const char *fpath,
|
|
PgfRevision *revision,
|
|
PgfExn* err)
|
|
{
|
|
PgfDB *db = NULL;
|
|
|
|
PGF_API_BEGIN {
|
|
db = new PgfDB(fpath, O_CREAT | O_EXCL | O_RDWR,
|
|
#ifndef _WIN32
|
|
S_IRUSR | S_IWUSR
|
|
#else
|
|
0
|
|
#endif
|
|
);
|
|
|
|
{
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::malloc<PgfPGF>(master_size+1);
|
|
pgf->ref_count = 1;
|
|
pgf->major_version = PGF_MAJOR_VERSION;
|
|
pgf->minor_version = PGF_MINOR_VERSION;
|
|
pgf->gflags = 0;
|
|
pgf->abstract.name = PgfDB::malloc<PgfText>(abstract_name->size+1);
|
|
memcpy(&(*pgf->abstract.name), abstract_name, sizeof(PgfText)+abstract_name->size+1);
|
|
pgf->abstract.aflags = 0;
|
|
pgf->abstract.funs = 0;
|
|
pgf->abstract.cats = 0;
|
|
pgf->concretes = 0;
|
|
pgf->prev = 0;
|
|
pgf->next = 0;
|
|
pgf->name.size = master_size;
|
|
memcpy(&pgf->name.text, master_text, master_size+1);
|
|
PgfDB::set_revision(pgf);
|
|
*revision = pgf.as_object();
|
|
|
|
PgfDB::sync();
|
|
}
|
|
|
|
db->ref_count++;
|
|
return db;
|
|
} PGF_API_END
|
|
|
|
if (db != NULL) {
|
|
delete db;
|
|
if (fpath != NULL)
|
|
remove(fpath);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_write_pgf(const char* fpath,
|
|
PgfDB *db, PgfRevision revision,
|
|
PgfExn* err)
|
|
{
|
|
FILE *out = NULL;
|
|
|
|
PGF_API_BEGIN {
|
|
out = fopen(fpath, "wb");
|
|
if (!out) {
|
|
throw pgf_systemerror(errno, fpath);
|
|
}
|
|
|
|
{
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
PgfWriter wtr(out);
|
|
wtr.write_pgf(pgf);
|
|
}
|
|
} PGF_API_END
|
|
|
|
end:
|
|
if (out != NULL)
|
|
fclose(out);
|
|
}
|
|
|
|
PGF_API_DECL
|
|
void pgf_free_revision(PgfDB *db, PgfRevision revision)
|
|
{
|
|
try {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
if (pgf->ref_count == 1 && PgfDB::is_persistant_revision(pgf)) {
|
|
// Someone is trying to release the last reference count
|
|
// to a persistant revision. Most likely this is an
|
|
// error in the reference counting for one of the clients.
|
|
// The best that we can do is to ignore the request.
|
|
return;
|
|
}
|
|
|
|
if (!(--pgf->ref_count)) {
|
|
PgfDB::unlink_transient_revision(pgf);
|
|
PgfPGF::release(pgf);
|
|
PgfDB::free(pgf);
|
|
}
|
|
|
|
db->ref_count--;
|
|
} catch (std::runtime_error& e) {
|
|
// silently ignore and hope for the best
|
|
}
|
|
|
|
if (!db->ref_count)
|
|
delete db;
|
|
}
|
|
|
|
PGF_API_DECL
|
|
void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision)
|
|
{
|
|
try {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
if (!(--concr->ref_count_ex)) {
|
|
PgfDB::unlink_transient_revision(concr);
|
|
}
|
|
|
|
if (!(--concr->ref_count)) {
|
|
PgfConcr::release(concr);
|
|
PgfDB::free(concr);
|
|
}
|
|
|
|
db->ref_count--;
|
|
} catch (std::runtime_error& e) {
|
|
// silently ignore and hope for the best
|
|
}
|
|
|
|
if (!db->ref_count)
|
|
delete db;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_abstract_name(PgfDB *db, PgfRevision revision,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
return textdup(&(*pgf->abstract.name));
|
|
} PGF_API_END
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_iter_categories(PgfDB *db, PgfRevision revision,
|
|
PgfItor *itor, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
namespace_iter(pgf->abstract.cats, itor, err);
|
|
} PGF_API_END
|
|
}
|
|
|
|
struct PgfItorConcrHelper : PgfItor
|
|
{
|
|
PgfDB *db;
|
|
PgfItor *itor;
|
|
};
|
|
|
|
static
|
|
void iter_concretes_helper(PgfItor *itor, PgfText *key, object value,
|
|
PgfExn *err)
|
|
{
|
|
PgfItorConcrHelper* helper = (PgfItorConcrHelper*) itor;
|
|
ref<PgfConcr> concr = value;
|
|
concr->ref_count++;
|
|
concr->ref_count_ex++;
|
|
helper->db->ref_count++;
|
|
helper->itor->fn(helper->itor, key, value, err);
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_iter_concretes(PgfDB *db, PgfRevision revision,
|
|
PgfItor *itor, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
PgfItorConcrHelper helper;
|
|
helper.fn = iter_concretes_helper;
|
|
helper.db = db;
|
|
helper.itor = itor;
|
|
|
|
namespace_iter(pgf->concretes, &helper, err);
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
PgfType pgf_start_cat(PgfDB *db, PgfRevision revision,
|
|
PgfUnmarshaller *u,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
PgfText *startcat = (PgfText *)
|
|
alloca(sizeof(PgfText)+9);
|
|
startcat->size = 8;
|
|
strcpy(startcat->text, "startcat");
|
|
|
|
ref<PgfFlag> flag =
|
|
namespace_lookup(pgf->abstract.aflags, startcat);
|
|
|
|
if (flag != 0) {
|
|
switch (ref<PgfLiteral>::get_tag(flag->value)) {
|
|
case PgfLiteralStr::tag: {
|
|
auto lstr = ref<PgfLiteralStr>::untagged(flag->value);
|
|
|
|
PgfType type = pgf_read_type(&lstr->val, u);
|
|
if (type == 0)
|
|
break;
|
|
return type;
|
|
}
|
|
}
|
|
}
|
|
|
|
PgfText *s = (PgfText *)
|
|
alloca(sizeof(PgfText)+2);
|
|
s->size = 1;
|
|
s->text[0] = 'S';
|
|
s->text[1] = 0;
|
|
return u->dtyp(0,NULL,s,0,NULL);
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
PgfTypeHypo *pgf_category_context(PgfDB *db, PgfRevision revision,
|
|
PgfText *catname, size_t *n_hypos, PgfUnmarshaller *u,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfAbsCat> abscat =
|
|
namespace_lookup(pgf->abstract.cats, catname);
|
|
if (abscat == 0) {
|
|
*n_hypos = 0;
|
|
return NULL;
|
|
}
|
|
|
|
PgfDBMarshaller m;
|
|
|
|
PgfTypeHypo *hypos = (PgfTypeHypo *)
|
|
malloc(abscat->context->len * sizeof(PgfTypeHypo));
|
|
for (size_t i = 0; i < abscat->context->len; i++) {
|
|
hypos[i].bind_type = abscat->context->data[i].bind_type;
|
|
hypos[i].cid = textdup(abscat->context->data[i].cid);
|
|
hypos[i].type = m.match_type(u, abscat->context->data[i].type.as_object());
|
|
}
|
|
|
|
*n_hypos = abscat->context->len;
|
|
return hypos;
|
|
} PGF_API_END
|
|
|
|
*n_hypos = 0;
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
prob_t pgf_category_prob(PgfDB *db, PgfRevision revision,
|
|
PgfText *catname,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfAbsCat> abscat =
|
|
namespace_lookup(pgf->abstract.cats, catname);
|
|
if (abscat == 0) {
|
|
return INFINITY;
|
|
}
|
|
|
|
return abscat->prob;
|
|
} PGF_API_END
|
|
|
|
return INFINITY;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_iter_functions(PgfDB *db, PgfRevision revision,
|
|
PgfItor *itor, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
pgf_exn_clear(err);
|
|
namespace_iter(pgf->abstract.funs, itor, err);
|
|
} PGF_API_END
|
|
}
|
|
|
|
struct PgfItorCatHelper : PgfItor
|
|
{
|
|
PgfText *cat;
|
|
PgfItor *itor;
|
|
};
|
|
|
|
static
|
|
void iter_by_cat_helper(PgfItor *itor, PgfText *key, object value,
|
|
PgfExn *err)
|
|
{
|
|
PgfItorCatHelper* helper = (PgfItorCatHelper*) itor;
|
|
ref<PgfAbsFun> absfun = value;
|
|
if (textcmp(helper->cat, &absfun->type->name) == 0)
|
|
helper->itor->fn(helper->itor, key, value, err);
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_iter_functions_by_cat(PgfDB *db, PgfRevision revision,
|
|
PgfText *cat, PgfItor *itor, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
PgfItorCatHelper helper;
|
|
helper.fn = iter_by_cat_helper;
|
|
helper.cat = cat;
|
|
helper.itor = itor;
|
|
|
|
namespace_iter(pgf->abstract.funs, &helper, err);
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
PgfType pgf_function_type(PgfDB *db, PgfRevision revision,
|
|
PgfText *funname, PgfUnmarshaller *u,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfAbsFun> absfun =
|
|
namespace_lookup(pgf->abstract.funs, funname);
|
|
if (absfun == 0)
|
|
return 0;
|
|
|
|
return PgfDBMarshaller().match_type(u, absfun->type.as_object());
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
int pgf_function_is_constructor(PgfDB *db, PgfRevision revision,
|
|
PgfText *funname,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfAbsFun> absfun =
|
|
namespace_lookup(pgf->abstract.funs, funname);
|
|
if (absfun == 0)
|
|
return false;
|
|
|
|
return (absfun->bytecode == 0);
|
|
} PGF_API_END
|
|
|
|
return false;
|
|
}
|
|
|
|
PGF_API
|
|
prob_t pgf_function_prob(PgfDB *db, PgfRevision revision,
|
|
PgfText *funname,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfAbsFun> absfun =
|
|
namespace_lookup(pgf->abstract.funs, funname);
|
|
if (absfun == 0)
|
|
return INFINITY;
|
|
|
|
return absfun->prob;
|
|
} PGF_API_END
|
|
|
|
return INFINITY;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_concrete_name(PgfDB *db, PgfConcrRevision revision,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
return textdup(&concr->name);
|
|
} PGF_API_END
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_concrete_language_code(PgfDB *db, PgfConcrRevision revision,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
size_t size = strlen("language");
|
|
PgfText *language = (PgfText *) alloca(sizeof(PgfText)+size+1);
|
|
language->size = size;
|
|
strcpy((char*) &language->text, "language");
|
|
|
|
ref<PgfFlag> flag =
|
|
namespace_lookup(concr->cflags, language);
|
|
if (flag != 0 &&
|
|
ref<PgfLiteral>::get_tag(flag->value) == PgfLiteralStr::tag) {
|
|
ref<PgfLiteralStr> lstr = ref<PgfLiteralStr>::untagged(flag->value);
|
|
return textdup(&lstr->val);
|
|
}
|
|
} PGF_API_END
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_expr(PgfExpr e,
|
|
PgfPrintContext *ctxt, int prio,
|
|
PgfMarshaller *m)
|
|
{
|
|
PgfPrinter printer(ctxt,prio,m);
|
|
m->match_expr(&printer, e);
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_ident(PgfText *name)
|
|
{
|
|
PgfPrinter printer(NULL,0,NULL);
|
|
printer.efun(name);
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfExpr pgf_read_expr(PgfText *input, PgfUnmarshaller *u)
|
|
{
|
|
PgfExprParser parser(input, u);
|
|
PgfExpr res = parser.parse_expr();
|
|
if (!parser.eof()) {
|
|
u->free_ref(res);
|
|
return 0;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
PGF_API
|
|
PgfExpr pgf_read_expr_ex(PgfText *input, const char **end_pos, PgfUnmarshaller *u)
|
|
{
|
|
PgfExprParser parser(input, u);
|
|
PgfExpr expr = parser.parse_expr();
|
|
*end_pos = parser.get_token_pos();
|
|
return expr;
|
|
}
|
|
|
|
PGF_API
|
|
prob_t pgf_expr_prob(PgfDB *db, PgfRevision revision,
|
|
PgfExpr e,
|
|
PgfMarshaller *m,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
PgfExprProbEstimator estimator(pgf, m);
|
|
m->match_expr(&estimator, e);
|
|
return estimator.get_prob();
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_type(PgfType ty,
|
|
PgfPrintContext *ctxt, int prio,
|
|
PgfMarshaller *m)
|
|
{
|
|
PgfPrinter printer(ctxt,prio,m);
|
|
m->match_type(&printer, ty);
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_context(size_t n_hypos, PgfTypeHypo *hypos,
|
|
PgfPrintContext *ctxt, int prio,
|
|
PgfMarshaller *m)
|
|
{
|
|
PgfPrinter printer(ctxt,prio,m);
|
|
for (size_t i = 0; i < n_hypos; i++) {
|
|
if (i > 0)
|
|
printer.puts(" ");
|
|
printer.hypo(&hypos[i],4);
|
|
}
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfType pgf_read_type(PgfText *input, PgfUnmarshaller *u)
|
|
{
|
|
PgfExprParser parser(input, u);
|
|
PgfType res = parser.parse_type();
|
|
if (!parser.eof()) {
|
|
u->free_ref(res);
|
|
return 0;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_category_internal(object o)
|
|
{
|
|
ref<PgfAbsCat> abscat = o;
|
|
|
|
PgfInternalMarshaller m;
|
|
PgfPrinter printer(NULL,0,&m);
|
|
|
|
printer.puts("cat ");
|
|
printer.efun(&abscat->name);
|
|
|
|
for (size_t i = 0; i < abscat->context->len; i++) {
|
|
printer.puts(" ");
|
|
|
|
PgfTypeHypo hypo;
|
|
hypo.bind_type = abscat->context->data[i].bind_type;
|
|
hypo.cid = abscat->context->data[i].cid;
|
|
hypo.type = abscat->context->data[i].type.as_object();
|
|
printer.hypo(&hypo,4);
|
|
}
|
|
|
|
printer.nprintf(32, " ; -- %g", abscat->prob);
|
|
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_start_cat_internal(PgfDB *db, PgfRevision revision, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
PgfText *startcat = (PgfText *)
|
|
alloca(sizeof(PgfText)+9);
|
|
startcat->size = 8;
|
|
strcpy(startcat->text, "startcat");
|
|
|
|
ref<PgfFlag> flag =
|
|
namespace_lookup(pgf->abstract.aflags, startcat);
|
|
|
|
if (flag != 0) {
|
|
PgfInternalMarshaller m;
|
|
PgfPrinter printer(NULL,0,&m);
|
|
printer.puts("startcat = ");
|
|
m.match_lit(&printer, flag->value);
|
|
return printer.get_text();
|
|
}
|
|
} PGF_API_END
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_function_internal(object o)
|
|
{
|
|
ref<PgfAbsFun> absfun = o;
|
|
|
|
PgfInternalMarshaller m;
|
|
PgfPrinter printer(NULL,0,&m);
|
|
|
|
printer.puts(absfun->bytecode != 0 ? "fun " : "data ");
|
|
printer.efun(&absfun->name);
|
|
printer.puts(" : ");
|
|
m.match_type(&printer, absfun->type.as_object());
|
|
printer.nprintf(32, " ; -- %g", absfun->prob);
|
|
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_iter_lincats(PgfDB *db, PgfConcrRevision cnc_revision,
|
|
PgfItor *itor, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(cnc_revision);
|
|
|
|
namespace_iter(concr->lincats, itor, err);
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_iter_lins(PgfDB *db, PgfConcrRevision cnc_revision,
|
|
PgfItor *itor, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(cnc_revision);
|
|
|
|
namespace_iter(concr->lins, itor, err);
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_get_lincat_counts_internal(object o, size_t *counts)
|
|
{
|
|
ref<PgfConcrLincat> lincat = o;
|
|
counts[0] = lincat->fields->len;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_get_lincat_field_internal(object o, size_t i)
|
|
{
|
|
ref<PgfConcrLincat> lincat = o;
|
|
return &(**vector_elem(lincat->fields, i));
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_get_lin_counts_internal(object o, size_t *counts)
|
|
{
|
|
ref<PgfConcrLin> lin = o;
|
|
counts[0] = lin->res->len;
|
|
counts[1] = lin->seqs->len / lin->res->len;
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_lin_sig_internal(object o, size_t i)
|
|
{
|
|
ref<PgfConcrLin> lin = o;
|
|
ref<PgfDTyp> ty = lin->absfun->type;
|
|
|
|
PgfInternalMarshaller m;
|
|
PgfPrinter printer(NULL,0,&m);
|
|
|
|
printer.efun(&lin->name);
|
|
printer.puts(" : ");
|
|
|
|
size_t n_args = lin->args->len / lin->res->len;
|
|
for (size_t j = 0; j < n_args; j++) {
|
|
if (j > 0)
|
|
printer.puts(" * ");
|
|
|
|
printer.parg(vector_elem(ty->hypos, j)->type,
|
|
vector_elem(lin->args, i*n_args + j));
|
|
}
|
|
|
|
if (n_args > 0)
|
|
printer.puts(" -> ");
|
|
|
|
printer.efun(&ty->name);
|
|
printer.puts("(");
|
|
printer.lparam(*vector_elem(lin->res, i));
|
|
printer.puts(")");
|
|
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfText *pgf_print_lin_seq_internal(object o, size_t i, size_t j)
|
|
{
|
|
ref<PgfConcrLin> lin = o;
|
|
|
|
PgfInternalMarshaller m;
|
|
PgfPrinter printer(NULL,0,&m);
|
|
|
|
size_t n_seqs = lin->seqs->len / lin->res->len;
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, i*n_seqs + j);
|
|
|
|
for (size_t k = 0; k < syms->len; k++) {
|
|
if (k > 0)
|
|
printer.puts(" ");
|
|
|
|
printer.symbol(*vector_elem(syms, k));
|
|
}
|
|
|
|
return printer.get_text();
|
|
}
|
|
|
|
PGF_API
|
|
PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
size_t name_size =
|
|
(name == NULL) ? pgf->name.size : name->size;
|
|
|
|
ref<PgfPGF> new_pgf = PgfDB::malloc<PgfPGF>(name_size+1);
|
|
new_pgf->ref_count = 1;
|
|
new_pgf->major_version = pgf->major_version;
|
|
new_pgf->minor_version = pgf->minor_version;
|
|
|
|
new_pgf->gflags = pgf->gflags;
|
|
if (pgf->gflags != 0)
|
|
Node<PgfFlag>::add_node_ref(pgf->gflags);
|
|
|
|
new_pgf->abstract.name = textdup_db(&(*pgf->abstract.name));
|
|
|
|
new_pgf->abstract.aflags = pgf->abstract.aflags;
|
|
if (pgf->abstract.aflags != 0)
|
|
Node<PgfFlag>::add_node_ref(pgf->abstract.aflags);
|
|
|
|
new_pgf->abstract.funs = pgf->abstract.funs;
|
|
if (pgf->abstract.funs != 0)
|
|
Node<PgfAbsFun>::add_node_ref(pgf->abstract.funs);
|
|
|
|
new_pgf->abstract.cats = pgf->abstract.cats;
|
|
if (pgf->abstract.cats != 0)
|
|
Node<PgfAbsCat>::add_node_ref(pgf->abstract.cats);
|
|
|
|
new_pgf->concretes = pgf->concretes;
|
|
if (pgf->concretes != 0)
|
|
Node<PgfConcr>::add_node_ref(pgf->concretes);
|
|
|
|
new_pgf->prev = 0;
|
|
new_pgf->next = 0;
|
|
PgfDB::link_transient_revision(new_pgf);
|
|
|
|
memcpy(&new_pgf->name, ((name == NULL) ? &pgf->name : name),
|
|
sizeof(PgfText)+name_size+1);
|
|
|
|
db->ref_count++;
|
|
return new_pgf.as_object();
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_commit_revision(PgfDB *db, PgfRevision revision,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> new_pgf = PgfDB::revision2pgf(revision);
|
|
ref<PgfPGF> old_pgf = PgfDB::get_revision(&new_pgf->name);
|
|
|
|
PgfDB::unlink_transient_revision(new_pgf);
|
|
PgfDB::set_revision(new_pgf);
|
|
|
|
if (old_pgf != 0)
|
|
PgfDB::link_transient_revision(old_pgf);
|
|
|
|
PgfDB::sync();
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
ref<PgfPGF> pgf = PgfDB::get_revision(name);
|
|
if (pgf != 0) {
|
|
Node<PgfPGF>::add_value_ref(pgf);
|
|
db->ref_count++;
|
|
}
|
|
return pgf.as_object();
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_create_function(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfType ty, size_t arity, char *bytecode,
|
|
prob_t prob,
|
|
PgfMarshaller *m,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfDBUnmarshaller u(m);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
ref<PgfAbsFun> absfun = PgfDB::malloc<PgfAbsFun>(name->size+1);
|
|
absfun->ref_count = 1;
|
|
absfun->type = m->match_type(&u, ty);
|
|
absfun->arity = arity;
|
|
absfun->bytecode = bytecode ? PgfDB::malloc<char>(0) : 0;
|
|
absfun->prob = prob;
|
|
memcpy(&absfun->name, name, sizeof(PgfText)+name->size+1);
|
|
|
|
Namespace<PgfAbsFun> funs =
|
|
namespace_insert(pgf->abstract.funs, absfun);
|
|
namespace_release(pgf->abstract.funs);
|
|
pgf->abstract.funs = funs;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_drop_function(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
Namespace<PgfAbsFun> funs =
|
|
namespace_delete(pgf->abstract.funs, name);
|
|
namespace_release(pgf->abstract.funs);
|
|
pgf->abstract.funs = funs;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_create_category(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
size_t n_hypos, PgfTypeHypo *context, prob_t prob,
|
|
PgfMarshaller *m,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfDBUnmarshaller u(m);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
ref<PgfAbsCat> abscat = PgfDB::malloc<PgfAbsCat>(name->size+1);
|
|
abscat->ref_count = 1;
|
|
abscat->context = vector_new<PgfHypo>(n_hypos);
|
|
abscat->prob = prob;
|
|
memcpy(&abscat->name, name, sizeof(PgfText)+name->size+1);
|
|
|
|
for (size_t i = 0; i < n_hypos; i++) {
|
|
vector_elem(abscat->context, i)->bind_type = context[i].bind_type;
|
|
vector_elem(abscat->context, i)->cid = textdup_db(context[i].cid);
|
|
vector_elem(abscat->context, i)->type = m->match_type(&u, context[i].type);
|
|
}
|
|
|
|
Namespace<PgfAbsCat> cats =
|
|
namespace_insert(pgf->abstract.cats, abscat);
|
|
namespace_release(pgf->abstract.cats);
|
|
pgf->abstract.cats = cats;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_drop_category(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
Namespace<PgfAbsCat> cats =
|
|
namespace_delete(pgf->abstract.cats, name);
|
|
namespace_release(pgf->abstract.cats);
|
|
pgf->abstract.cats = cats;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
PgfConcrRevision pgf_create_concrete(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfConcr> concr =
|
|
namespace_lookup(pgf->concretes, name);
|
|
if (concr != 0)
|
|
throw pgf_error("The concrete syntax already exists");
|
|
|
|
concr = PgfDB::malloc<PgfConcr>(name->size+1);
|
|
concr->ref_count = 2;
|
|
concr->ref_count_ex = 1;
|
|
concr->cflags = 0;
|
|
concr->lins = 0;
|
|
concr->lincats = 0;
|
|
concr->printnames = 0;
|
|
concr->prev = 0;
|
|
concr->next = 0;
|
|
memcpy(&concr->name, name, sizeof(PgfText)+name->size+1);
|
|
|
|
PgfDB::link_transient_revision(concr);
|
|
|
|
Namespace<PgfConcr> concrs =
|
|
namespace_insert(pgf->concretes, concr);
|
|
namespace_release(pgf->concretes);
|
|
pgf->concretes = concrs;
|
|
|
|
db->ref_count++;
|
|
return concr.as_object();
|
|
} PGF_API_END
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
PgfConcrRevision pgf_clone_concrete(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfConcr> concr =
|
|
namespace_lookup(pgf->concretes, name);
|
|
if (concr == 0)
|
|
throw pgf_error("Unknown concrete syntax");
|
|
|
|
ref<PgfConcr> clone = PgfDB::malloc<PgfConcr>(name->size+1);
|
|
clone->ref_count = 2;
|
|
clone->ref_count_ex = 1;
|
|
clone->cflags = concr->cflags;
|
|
clone->lins = concr->lins;
|
|
clone->lincats = concr->lincats;
|
|
clone->printnames = concr->printnames;
|
|
clone->prev = 0;
|
|
clone->next = 0;
|
|
memcpy(&clone->name, name, sizeof(PgfText)+name->size+1);
|
|
|
|
if (clone->cflags != 0)
|
|
Node<PgfFlag>::add_node_ref(clone->cflags);
|
|
|
|
PgfDB::link_transient_revision(clone);
|
|
|
|
Namespace<PgfConcr> concrs =
|
|
namespace_insert(pgf->concretes, clone);
|
|
namespace_release(pgf->concretes);
|
|
pgf->concretes = concrs;
|
|
|
|
db->ref_count++;
|
|
return clone.as_object();
|
|
} PGF_API_END
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_drop_concrete(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
Namespace<PgfConcr> concrs =
|
|
namespace_delete(pgf->concretes, name);
|
|
namespace_release(pgf->concretes);
|
|
pgf->concretes = concrs;
|
|
} PGF_API_END
|
|
}
|
|
|
|
class PGF_INTERNAL PgfLinBuilder : public PgfLinBuilderIface
|
|
{
|
|
ref<PgfConcrLin> lin;
|
|
size_t arg_index;
|
|
size_t res_index;
|
|
size_t seq_index;
|
|
size_t sym_index;
|
|
|
|
const char *builder_error_msg =
|
|
"Detected incorrect use of the linearization builder";
|
|
|
|
public:
|
|
PgfLinBuilder(ref<PgfAbsFun> absfun, PgfConcr *concr, size_t n_prods)
|
|
{
|
|
ref<PgfConcrLincat> lincat =
|
|
namespace_lookup(concr->lincats, &absfun->type->name);
|
|
if (lincat == 0) {
|
|
throw pgf_error("Missing linearization category");
|
|
}
|
|
|
|
ref<Vector<PgfPArg>> args =
|
|
vector_new<PgfPArg>(n_prods*absfun->type->hypos->len);
|
|
ref<Vector<ref<PgfLParam>>> res =
|
|
vector_new<ref<PgfLParam>>(n_prods);
|
|
ref<Vector<ref<Vector<PgfSymbol>>>> seqs =
|
|
vector_new<ref<Vector<PgfSymbol>>>(n_prods*lincat->fields->len);
|
|
|
|
lin = PgfDB::malloc<PgfConcrLin>(absfun->name.size+1);
|
|
memcpy(&lin->name, &absfun->name, sizeof(PgfText)+absfun->name.size+1);
|
|
lin->ref_count = 1;
|
|
lin->absfun = absfun;
|
|
lin->args = args;
|
|
lin->res = res;
|
|
lin->seqs = seqs;
|
|
|
|
this->arg_index = 0;
|
|
this->res_index = 0;
|
|
this->seq_index = 0;
|
|
this->sym_index = (size_t) -1;
|
|
}
|
|
|
|
void start_production(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (res_index >= lin->res->len)
|
|
throw pgf_error(builder_error_msg);
|
|
*vector_elem(lin->res, res_index) = 0;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_argument(size_t i0, size_t n_terms, size_t *terms, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (arg_index >= lin->args->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<PgfLParam> param = PgfDB::malloc<PgfLParam>(n_terms*2*sizeof(size_t));
|
|
param->i0 = i0;
|
|
param->n_terms = n_terms;
|
|
|
|
for (size_t i = 0; i < n_terms; i++) {
|
|
param->terms[i].factor = terms[2*i];
|
|
param->terms[i].var = terms[2*i+1];
|
|
}
|
|
|
|
ref<PgfPArg> parg = vector_elem(lin->args, arg_index);
|
|
parg->param = param;
|
|
|
|
arg_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void set_result(size_t i0, size_t n_terms, size_t *terms, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (res_index >= lin->res->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<PgfLParam> param = PgfDB::malloc<PgfLParam>(n_terms*2*sizeof(size_t));
|
|
param->i0 = i0;
|
|
param->n_terms = n_terms;
|
|
|
|
for (size_t i = 0; i < n_terms; i++) {
|
|
param->terms[i].factor = terms[2*i];
|
|
param->terms[i].var = terms[2*i+1];
|
|
}
|
|
|
|
*vector_elem(lin->res, res_index) = param;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void start_sequence(size_t n_syms, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = vector_new<PgfSymbol>(n_syms);
|
|
*vector_elem(lin->seqs, seq_index) = syms;
|
|
sym_index = 0;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symcat(size_t d, size_t i0, size_t n_terms, size_t *terms, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<PgfSymbolCat> symcat = PgfDB::malloc<PgfSymbolCat>(n_terms*2*sizeof(size_t));
|
|
symcat->d = d;
|
|
symcat->r.i0 = i0;
|
|
symcat->r.n_terms = n_terms;
|
|
|
|
for (size_t i = 0; i < n_terms; i++) {
|
|
symcat->r.terms[i].factor = terms[2*i];
|
|
symcat->r.terms[i].var = terms[2*i+1];
|
|
}
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolCat>::tagged(symcat);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symlit(size_t d, size_t i0, size_t n_terms, size_t *terms, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<PgfSymbolLit> symlit = PgfDB::malloc<PgfSymbolLit>(n_terms*2*sizeof(size_t));
|
|
symlit->d = d;
|
|
symlit->r.i0 = i0;
|
|
symlit->r.n_terms = n_terms;
|
|
|
|
for (size_t i = 0; i < n_terms; i++) {
|
|
symlit->r.terms[i].factor = terms[2*i];
|
|
symlit->r.terms[i].var = terms[2*i+1];
|
|
}
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolLit>::tagged(symlit);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symvar(size_t d, size_t r, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<PgfSymbolVar> symvar = PgfDB::malloc<PgfSymbolVar>();
|
|
symvar->d = d;
|
|
symvar->r = r;
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolVar>::tagged(symvar);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symks(PgfText *token, PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<PgfSymbolKS> symtok = PgfDB::malloc<PgfSymbolKS>(token->size+1);
|
|
memcpy(&symtok->token, token, sizeof(PgfText)+token->size+1);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolKS>::tagged(symtok);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symbind(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolBIND>::tagged(0);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symsoftbind(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolSOFTBIND>::tagged(0);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symne(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolNE>::tagged(0);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symsoftspace(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolSOFTSPACE>::tagged(0);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symcapit(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolCAPIT>::tagged(0);
|
|
sym_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void add_symallcapit(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index == (size_t) -1)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (seq_index >= lin->seqs->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
|
|
if (sym_index >= syms->len)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
*vector_elem(syms, sym_index) = ref<PgfSymbolALLCAPIT>::tagged(0);
|
|
} PGF_API_END
|
|
}
|
|
|
|
void end_sequence(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
if (sym_index != (*vector_elem(lin->seqs, seq_index))->len)
|
|
throw pgf_error(builder_error_msg);
|
|
sym_index = (size_t) -1;
|
|
seq_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
void end_production(PgfExn *err)
|
|
{
|
|
if (err->type != PGF_EXN_NONE)
|
|
return;
|
|
|
|
PGF_API_BEGIN {
|
|
size_t n_args = (lin->args->len/lin->res->len);
|
|
if (arg_index != (res_index+1)*n_args)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
if (*vector_elem(lin->res, res_index) == 0)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
size_t n_seqs = (lin->seqs->len/lin->res->len);
|
|
if (seq_index != (res_index+1)*n_seqs)
|
|
throw pgf_error(builder_error_msg);
|
|
|
|
res_index++;
|
|
} PGF_API_END
|
|
}
|
|
|
|
ref<PgfConcrLin> done()
|
|
{
|
|
if (res_index != lin->res->len)
|
|
throw pgf_error(builder_error_msg);
|
|
return lin;
|
|
}
|
|
|
|
void failed()
|
|
{
|
|
for (size_t i = 0; i < arg_index; i++) {
|
|
PgfDB::free(vector_elem(lin->args, i)->param);
|
|
}
|
|
PgfDB::free(lin->args);
|
|
|
|
for (size_t i = 0; i < res_index; i++) {
|
|
PgfDB::free(*vector_elem(lin->res, i));
|
|
}
|
|
PgfDB::free(lin->res);
|
|
|
|
for (size_t i = 0; i < seq_index; i++) {
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, i);
|
|
for (size_t j = 0; j < syms->len; j++) {
|
|
PgfSymbol sym = *vector_elem(syms, j);
|
|
PgfDB::free(ref<void>::untagged(sym));
|
|
}
|
|
PgfDB::free(syms);
|
|
}
|
|
if (sym_index != (size_t) -1) {
|
|
ref<Vector<PgfSymbol>> syms = *vector_elem(lin->seqs, seq_index);
|
|
for (size_t j = 0; j < sym_index; j++) {
|
|
PgfSymbol sym = *vector_elem(syms, j);
|
|
PgfDB::free(ref<void>::untagged(sym));
|
|
}
|
|
PgfDB::free(syms);
|
|
}
|
|
PgfDB::free(lin->seqs);
|
|
|
|
PgfDB::free(lin);
|
|
lin = 0;
|
|
}
|
|
};
|
|
|
|
|
|
PGF_API
|
|
void pgf_create_lincat(PgfDB *db,
|
|
PgfRevision revision, PgfConcrRevision cnc_revision,
|
|
PgfText *name, size_t n_fields, PgfText **fields,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(cnc_revision);
|
|
|
|
ref<PgfAbsCat> abscat =
|
|
namespace_lookup(pgf->abstract.cats, name);
|
|
if (abscat == 0) {
|
|
throw pgf_error("There is no corresponding category in the abstract syntax");
|
|
}
|
|
|
|
ref<Vector<ref<PgfText>>> db_fields = vector_new<ref<PgfText>>(n_fields);
|
|
for (size_t i = 0; i < n_fields; i++) {
|
|
ref<PgfText> field = textdup_db(fields[i]);
|
|
*vector_elem(db_fields, i) = field;
|
|
}
|
|
|
|
ref<PgfConcrLincat> lincat = PgfDB::malloc<PgfConcrLincat>(name->size+1);
|
|
memcpy(&lincat->name, name, sizeof(PgfText)+name->size+1);
|
|
lincat->ref_count = 1;
|
|
lincat->abscat = abscat;
|
|
lincat->fields = db_fields;
|
|
|
|
Namespace<PgfConcrLincat> lincats =
|
|
namespace_insert(concr->lincats, lincat);
|
|
namespace_release(concr->lincats);
|
|
concr->lincats = lincats;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_drop_lincat(PgfDB *db,
|
|
PgfConcrRevision revision,
|
|
PgfText *name, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
Namespace<PgfConcrLincat> lincats =
|
|
namespace_delete(concr->lincats, name);
|
|
namespace_release(concr->lincats);
|
|
concr->lincats = lincats;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_create_lin(PgfDB *db,
|
|
PgfRevision revision, PgfConcrRevision cnc_revision,
|
|
PgfText *name, size_t n_prods,
|
|
PgfBuildLinIface *build,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(cnc_revision);
|
|
|
|
ref<PgfAbsFun> absfun =
|
|
namespace_lookup(pgf->abstract.funs, name);
|
|
if (absfun == 0) {
|
|
throw pgf_error("There is no corresponding function in the abstract syntax");
|
|
}
|
|
|
|
PgfLinBuilder builder(absfun, concr, n_prods);
|
|
build->build(&builder, err);
|
|
if (err->type == PGF_EXN_NONE) {
|
|
ref<PgfConcrLin> lin = builder.done();
|
|
Namespace<PgfConcrLin> lins =
|
|
namespace_insert(concr->lins, lin);
|
|
namespace_release(concr->lins);
|
|
concr->lins = lins;
|
|
} else {
|
|
builder.failed();
|
|
}
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_drop_lin(PgfDB *db,
|
|
PgfConcrRevision revision,
|
|
PgfText *name, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
Namespace<PgfConcrLin> lins =
|
|
namespace_delete(concr->lins, name);
|
|
namespace_release(concr->lins);
|
|
concr->lins = lins;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
int pgf_has_linearization(PgfDB *db, PgfConcrRevision revision,
|
|
PgfText *name, PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
ref<PgfConcrLin> lin =
|
|
namespace_lookup(concr->lins, name);
|
|
|
|
return (lin != 0);
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
PgfLiteral pgf_get_global_flag(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfUnmarshaller *u,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfFlag> flag =
|
|
namespace_lookup(pgf->gflags, name);
|
|
if (flag != 0) {
|
|
return PgfDBMarshaller().match_lit(u, flag->value);
|
|
}
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_set_global_flag(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfLiteral value,
|
|
PgfMarshaller *m,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfDBUnmarshaller u(m);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfFlag> flag = PgfDB::malloc<PgfFlag>(name->size+1);
|
|
flag->ref_count = 1;
|
|
memcpy(&flag->name, name, sizeof(PgfText)+name->size+1);
|
|
PgfLiteral lit = m->match_lit(&u, value);
|
|
flag->value = lit;
|
|
Namespace<PgfFlag> gflags =
|
|
namespace_insert(pgf->gflags, flag);
|
|
namespace_release(pgf->gflags);
|
|
pgf->gflags = gflags;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
PgfLiteral pgf_get_abstract_flag(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfUnmarshaller *u,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfFlag> flag =
|
|
namespace_lookup(pgf->abstract.aflags, name);
|
|
if (flag != 0) {
|
|
return PgfDBMarshaller().match_lit(u, flag->value);
|
|
}
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_set_abstract_flag(PgfDB *db, PgfRevision revision,
|
|
PgfText *name,
|
|
PgfLiteral value,
|
|
PgfMarshaller *m,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfDBUnmarshaller u(m);
|
|
|
|
ref<PgfPGF> pgf = PgfDB::revision2pgf(revision);
|
|
|
|
ref<PgfFlag> flag = PgfDB::malloc<PgfFlag>(name->size+1);
|
|
flag->ref_count = 1;
|
|
memcpy(&flag->name, name, sizeof(PgfText)+name->size+1);
|
|
PgfLiteral lit = m->match_lit(&u, value);
|
|
flag->value = lit;
|
|
Namespace<PgfFlag> aflags =
|
|
namespace_insert(pgf->abstract.aflags, flag);
|
|
namespace_release(pgf->abstract.aflags);
|
|
pgf->abstract.aflags = aflags;
|
|
} PGF_API_END
|
|
}
|
|
|
|
PGF_API
|
|
PgfLiteral pgf_get_concrete_flag(PgfDB *db, PgfConcrRevision revision,
|
|
PgfText *name,
|
|
PgfUnmarshaller *u,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, READER_SCOPE);
|
|
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
ref<PgfFlag> flag =
|
|
namespace_lookup(concr->cflags, name);
|
|
if (flag != 0) {
|
|
return PgfDBMarshaller().match_lit(u, flag->value);
|
|
}
|
|
} PGF_API_END
|
|
|
|
return 0;
|
|
}
|
|
|
|
PGF_API
|
|
void pgf_set_concrete_flag(PgfDB *db, PgfConcrRevision revision,
|
|
PgfText *name,
|
|
PgfLiteral value,
|
|
PgfMarshaller *m,
|
|
PgfExn *err)
|
|
{
|
|
PGF_API_BEGIN {
|
|
DB_scope scope(db, WRITER_SCOPE);
|
|
|
|
PgfDBUnmarshaller u(m);
|
|
|
|
ref<PgfConcr> concr = PgfDB::revision2concr(revision);
|
|
|
|
ref<PgfFlag> flag = PgfDB::malloc<PgfFlag>(name->size+1);
|
|
flag->ref_count = 1;
|
|
memcpy(&flag->name, name, sizeof(PgfText)+name->size+1);
|
|
PgfLiteral lit = m->match_lit(&u, value);
|
|
flag->value = lit;
|
|
Namespace<PgfFlag> cflags =
|
|
namespace_insert(concr->cflags, flag);
|
|
namespace_release(concr->cflags);
|
|
concr->cflags = cflags;
|
|
} PGF_API_END
|
|
}
|