1
0
forked from GitHub/gf-core

API for adding concrete syntaxes. Garbage collection to be fixed!

This commit is contained in:
krangelov
2021-10-21 19:18:14 +02:00
parent 259ed52a77
commit 1413c273cc
15 changed files with 529 additions and 197 deletions

View File

@@ -36,4 +36,10 @@ void PgfPGF::release(ref<PgfPGF> pgf)
namespace_release(pgf->abstract.aflags);
namespace_release(pgf->abstract.funs);
namespace_release(pgf->abstract.cats);
namespace_release(pgf->concretes);
}
void PgfConcr::release(ref<PgfConcr> concr)
{
namespace_release(concr->cflags);
}

View File

@@ -54,6 +54,7 @@ private:
};
class PgfPGF;
class PgfConcr;
#include "db.h"
#include "text.h"
@@ -103,6 +104,14 @@ typedef struct {
Namespace<PgfAbsCat> cats;
} PgfAbstr;
struct PGF_INTERNAL_DECL PgfConcr {
size_t ref_count;
Namespace<PgfFlag> cflags;
PgfText name;
static void release(ref<PgfConcr> pgf);
};
struct PGF_INTERNAL_DECL PgfPGF {
size_t ref_count;
@@ -110,7 +119,7 @@ struct PGF_INTERNAL_DECL PgfPGF {
uint16_t minor_version;
Namespace<PgfFlag> gflags;
PgfAbstr abstract;
//PgfConcrs* concretes;
Namespace<PgfConcr> concretes;
// If the revision is transient, then it is in a double-linked list
// with all other transient revisions.

View File

@@ -1043,6 +1043,23 @@ ref<PgfPGF> PgfDB::revision2pgf(PgfRevision revision)
return pgf;
}
PGF_INTERNAL
ref<PgfConcr> PgfDB::revision2concr(PgfConcrRevision revision)
{
if (revision <= sizeof(*current_db->ms) || revision >= current_db->ms->top)
throw pgf_error("Invalid revision");
mchunk *chunk = mem2chunk(ptr(current_db->ms,revision));
if (chunksize(chunk) < sizeof(PgfConcr))
throw pgf_error("Invalid revision");
ref<PgfConcr> concr = revision;
if (chunksize(chunk) != request2size(sizeof(PgfConcr)+concr->name.size+1))
throw pgf_error("Invalid revision");
return concr;
}
PGF_INTERNAL
bool PgfDB::is_persistant_revision(ref<PgfPGF> pgf)
{

View File

@@ -85,6 +85,7 @@ public:
static PGF_INTERNAL_DECL ref<PgfPGF> get_revision(PgfText *name);
static PGF_INTERNAL_DECL void set_revision(ref<PgfPGF> pgf);
static PGF_INTERNAL_DECL ref<PgfPGF> revision2pgf(PgfRevision revision);
static PGF_INTERNAL_DECL ref<PgfConcr> revision2concr(PgfConcrRevision revision);
static PGF_INTERNAL_DECL bool is_persistant_revision(ref<PgfPGF> pgf);
static PGF_INTERNAL_DECL void link_transient_revision(ref<PgfPGF> pgf);
static PGF_INTERNAL_DECL void unlink_transient_revision(ref<PgfPGF> pgf);

View File

@@ -480,7 +480,7 @@ void namespace_iter(Namespace<V> map, PgfItor* itor, PgfExn *err)
if (err->type != PGF_EXN_NONE)
return;
itor->fn(itor, &map->value->name, &(*map->value), err);
itor->fn(itor, &map->value->name, map->value.as_object(), err);
if (err->type != PGF_EXN_NONE)
return;

View File

@@ -175,6 +175,7 @@ PgfDB *pgf_new_ngf(PgfText *abstract_name,
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;
@@ -255,6 +256,36 @@ void pgf_free_revision(PgfDB *db, PgfRevision revision)
delete db;
}
PGF_API_DECL
void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision 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. Mostly 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
PgfText *pgf_abstract_name(PgfDB *db, PgfRevision revision,
PgfExn *err)
@@ -281,6 +312,18 @@ void pgf_iter_categories(PgfDB *db, PgfRevision revision,
} PGF_API_END
}
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);
namespace_iter(pgf->concretes, itor, err);
} PGF_API_END
}
PGF_API
PgfType pgf_start_cat(PgfDB *db, PgfRevision revision,
PgfUnmarshaller *u,
@@ -397,11 +440,11 @@ struct PgfItorHelper : PgfItor
};
static
void iter_by_cat_helper(PgfItor *itor, PgfText *key, void *value,
void iter_by_cat_helper(PgfItor *itor, PgfText *key, object value,
PgfExn *err)
{
PgfItorHelper* helper = (PgfItorHelper*) itor;
PgfAbsFun* absfun = (PgfAbsFun*) value;
ref<PgfAbsFun> absfun = value;
if (textcmp(helper->cat, &absfun->type->name) == 0)
helper->itor->fn(helper->itor, key, value, err);
}
@@ -483,6 +526,46 @@ prob_t pgf_function_prob(PgfDB *db, PgfRevision revision,
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,
@@ -604,6 +687,10 @@ PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision,
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);
@@ -752,6 +839,81 @@ void pgf_drop_category(PgfDB *db, PgfRevision revision,
} 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 = 1;
concr->cflags = 0;
memcpy(&concr->name, name, sizeof(PgfText)+name->size+1);
Namespace<PgfConcr> concrs =
namespace_insert(pgf->concretes, concr);
namespace_release(pgf->concretes);
pgf->concretes = concrs;
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 = 1;
clone->cflags = concr->cflags;
memcpy(&clone->name, name, sizeof(PgfText)+name->size+1);
Namespace<PgfConcr> concrs =
namespace_insert(pgf->concretes, clone);
namespace_release(pgf->concretes);
pgf->concretes = concrs;
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
}
PGF_API
PgfLiteral pgf_get_global_flag(PgfDB *db, PgfRevision revision,
PgfText *name,
@@ -843,3 +1005,49 @@ void pgf_set_abstract_flag(PgfDB *db, PgfRevision revision,
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);
flag->value = m->match_lit(&u, value);
Namespace<PgfFlag> cflags =
namespace_insert(concr->cflags, flag);
namespace_release(concr->cflags);
concr->cflags = cflags;
} PGF_API_END
}

View File

@@ -85,16 +85,16 @@ typedef struct {
const char *msg;
} PgfExn;
typedef uintptr_t object;
/* A generic structure to pass a callback for iteration over a collection */
typedef struct PgfItor PgfItor;
struct PgfItor {
void (*fn)(PgfItor* self, PgfText* key, void *value,
void (*fn)(PgfItor* self, PgfText* key, object value,
PgfExn *err);
};
typedef uintptr_t object;
/// An abstract syntax tree
typedef object PgfExpr;
@@ -219,6 +219,7 @@ typedef float prob_t;
typedef struct PgfDB PgfDB;
typedef object PgfRevision;
typedef object PgfConcrRevision;
/* Reads a PGF file and builds the database in memory.
* If successful, *revision will contain the initial revision of
@@ -264,6 +265,9 @@ void pgf_write_pgf(const char* fpath,
PGF_API_DECL
void pgf_free_revision(PgfDB *pgf, PgfRevision revision);
PGF_API_DECL
void pgf_free_concr_revision(PgfDB *db, PgfConcrRevision revision);
/* Returns a newly allocated text which contains the abstract name of
* the grammar. The text must be released with a call to free.
*/
@@ -275,6 +279,10 @@ PGF_API_DECL
void pgf_iter_categories(PgfDB *db, PgfRevision revision,
PgfItor *itor, PgfExn *err);
PGF_API
void pgf_iter_concretes(PgfDB *db, PgfRevision revision,
PgfItor *itor, PgfExn *err);
PGF_API_DECL
PgfType pgf_start_cat(PgfDB *db, PgfRevision revision,
PgfUnmarshaller *u,
@@ -313,6 +321,14 @@ prob_t pgf_function_prob(PgfDB *db, PgfRevision revision,
PgfText *funname,
PgfExn* err);
PGF_API_DECL
PgfText *pgf_concrete_name(PgfDB *db, PgfConcrRevision revision,
PgfExn* err);
PGF_API_DECL
PgfText *pgf_concrete_language_code(PgfDB *db, PgfConcrRevision revision,
PgfExn* err);
typedef struct PgfPrintContext PgfPrintContext;
struct PgfPrintContext {
@@ -387,6 +403,21 @@ void pgf_drop_category(PgfDB *db, PgfRevision revision,
PgfText *name,
PgfExn *err);
PGF_API_DECL
PgfConcrRevision pgf_create_concrete(PgfDB *db, PgfRevision revision,
PgfText *name,
PgfExn *err);
PGF_API_DECL
PgfConcrRevision pgf_clone_concrete(PgfDB *db, PgfRevision revision,
PgfText *name,
PgfExn *err);
PGF_API_DECL
void pgf_drop_concrete(PgfDB *db, PgfRevision revision,
PgfText *name,
PgfExn *err);
PGF_API_DECL
PgfLiteral pgf_get_global_flag(PgfDB *db, PgfRevision revision,
PgfText *name,
@@ -409,5 +440,16 @@ void pgf_set_abstract_flag(PgfDB *db, PgfRevision revision,
PgfLiteral value,
PgfMarshaller *m,
PgfExn *err);
PGF_API_DECL
PgfLiteral pgf_get_concrete_flag(PgfDB *db, PgfConcrRevision revision,
PgfText *name,
PgfUnmarshaller *u,
PgfExn *err);
PGF_API_DECL
void pgf_set_concrete_flag(PgfDB *db, PgfConcrRevision revision,
PgfText *name,
PgfLiteral value,
PgfMarshaller *m,
PgfExn *err);
#endif // PGF_H_

View File

@@ -203,10 +203,13 @@ PgfLiteral PgfReader::read_literal()
break;
}
case PgfLiteralInt::tag: {
size_t size = read_len();
ref<PgfLiteralInt> lit_int =
PgfDB::malloc<PgfLiteralInt>(sizeof(uintmax_t));
lit_int->size = 1;
lit_int->val[0] = read_int();
PgfDB::malloc<PgfLiteralInt>(sizeof(uintmax_t)*size);
lit_int->size = size;
for (size_t i = 0; i < size; i++) {
lit_int->val[i] = (uintmax_t) read_uint();
}
lit = ref<PgfLiteralInt>::tagged(lit_int);
break;
}
@@ -428,6 +431,14 @@ void PgfReader::read_abstract(ref<PgfAbstr> abstract)
abstract->cats = read_namespace<PgfAbsCat>(&PgfReader::read_abscat);
}
ref<PgfConcr> PgfReader::read_concrete()
{
ref<PgfConcr> concr = read_name(&PgfConcr::name);
concr->ref_count = 1;
concr->cflags = read_namespace<PgfFlag>(&PgfReader::read_flag);
return concr;
}
ref<PgfPGF> PgfReader::read_pgf()
{
ref<PgfPGF> pgf = PgfDB::malloc<PgfPGF>(master_size+1);
@@ -445,6 +456,8 @@ ref<PgfPGF> PgfReader::read_pgf()
read_abstract(ref<PgfAbstr>::from_ptr(&pgf->abstract));
pgf->concretes = read_namespace<PgfConcr>(&PgfReader::read_concrete);
pgf->prev = 0;
pgf->next = 0;

View File

@@ -68,6 +68,8 @@ public:
ref<PgfAbsCat> read_abscat();
void read_abstract(ref<PgfAbstr> abstract);
ref<PgfConcr> read_concrete();
ref<PgfPGF> read_pgf();
private:

View File

@@ -385,6 +385,12 @@ void PgfWriter::write_abstract(ref<PgfAbstr> abstract)
this->abstract = 0;
}
void PgfWriter::write_concrete(ref<PgfConcr> concr)
{
write_name(&concr->name);
write_namespace<PgfFlag>(concr->cflags, &PgfWriter::write_flag);
}
void PgfWriter::write_pgf(ref<PgfPGF> pgf)
{
write_u16be(pgf->major_version);
@@ -393,4 +399,5 @@ void PgfWriter::write_pgf(ref<PgfPGF> pgf)
write_namespace<PgfFlag>(pgf->gflags, &PgfWriter::write_flag);
write_abstract(ref<PgfAbstr>::from_ptr(&pgf->abstract));
write_namespace<PgfConcr>(pgf->concretes, &PgfWriter::write_concrete);
}

View File

@@ -42,6 +42,8 @@ public:
void write_abscat(ref<PgfAbsCat> abscat);
void write_abstract(ref<PgfAbstr> abstract);
void write_concrete(ref<PgfConcr> concr);
void write_pgf(ref<PgfPGF> pgf);
private: