mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-09-17 07:46:00 -06:00
a higher-level API allows for a more efficient implementation
This commit is contained in:
+122
-32
@@ -114,7 +114,7 @@ void PgfAbstractParser::process(Item *item, State *state)
|
||||
}
|
||||
|
||||
PGF_INTERNAL_DECL
|
||||
int text_symbol_cmp(PgfTextSpot *spot, const uint8_t *end,
|
||||
int text_symbol_cmp(PgfText *sentence, PgfTextSpot *spot,
|
||||
ref<PgfSymbolKS> sym, bool case_sensitive);
|
||||
|
||||
void PgfAbstractParser::symbol(Item *item, State *state, PgfSymbol sym)
|
||||
@@ -857,8 +857,12 @@ PgfParser::PgfParser(ref<PgfConcr> concr, PgfText *sentence, bool case_sensitive
|
||||
this->m = m;
|
||||
this->u = u;
|
||||
this->sentence = textdup(sentence);
|
||||
this->end = (uint8_t *) (this->sentence->text+this->sentence->size);
|
||||
this->case_sensitive = case_sensitive;
|
||||
this->prev_state = NULL;
|
||||
this->update_old_pos = 0;
|
||||
this->update_new_pos = 0;
|
||||
this->delta_byte_pos = 0;
|
||||
this->allocated_size = sizeof(PgfText)+sentence->size+1;
|
||||
}
|
||||
|
||||
PgfParser::~PgfParser()
|
||||
@@ -906,11 +910,11 @@ void PgfParser::bu_predict(PgfPhrasetable<PgfSymbolKS> phrasetable,
|
||||
return;
|
||||
|
||||
PgfTextSpot current = state->end;
|
||||
int cmp = text_symbol_cmp(¤t,end,phrasetable->value.key,case_sensitive);
|
||||
int cmp = text_symbol_cmp(sentence,¤t,phrasetable->value.key,case_sensitive);
|
||||
if (cmp < 0) {
|
||||
bu_predict(phrasetable->left,state,outside_prob,min,max);
|
||||
} else if (cmp > 0) {
|
||||
ptrdiff_t len = current.ptr - state->end.ptr;
|
||||
ptrdiff_t len = current.byte_pos - state->end.byte_pos;
|
||||
|
||||
if (min <= len-1)
|
||||
bu_predict(phrasetable->left,state,outside_prob,min,len-1);
|
||||
@@ -918,7 +922,7 @@ void PgfParser::bu_predict(PgfPhrasetable<PgfSymbolKS> phrasetable,
|
||||
if (len <= max)
|
||||
bu_predict(phrasetable->right,state,outside_prob,len,max);
|
||||
} else {
|
||||
ptrdiff_t len = current.ptr - state->end.ptr;
|
||||
ptrdiff_t len = current.byte_pos - state->end.byte_pos;
|
||||
|
||||
if (min <= len)
|
||||
bu_predict(phrasetable->left,state,outside_prob,min,len);
|
||||
@@ -1150,7 +1154,7 @@ void PgfParser::prepare(ref<PgfConcrLincat> start)
|
||||
fprintf(stderr, "------------------------------------------\n");
|
||||
#endif
|
||||
|
||||
PgfTextSpot start_spot = {0, (uint8_t *) sentence->text};
|
||||
PgfTextSpot start_spot = {0, 0};
|
||||
State *state = new_state(start_spot, 0);
|
||||
|
||||
for (size_t i = start->n_lindefs; i < start->rules.size(); i++) {
|
||||
@@ -1168,12 +1172,8 @@ void PgfParser::prepare(ref<PgfConcrLincat> start)
|
||||
}
|
||||
}
|
||||
|
||||
PgfExpr PgfParser::fetch(PgfDB *db, prob_t *prob)
|
||||
void PgfParser::perform_search()
|
||||
{
|
||||
DB_scope scope(db, READER_SCOPE);
|
||||
|
||||
bool first_fetch = (concr->last_fid == last_fid);
|
||||
|
||||
for (;;) {
|
||||
State *state = current_state;
|
||||
prob_t min_prob = INFINITY;
|
||||
@@ -1218,6 +1218,15 @@ PgfExpr PgfParser::fetch(PgfDB *db, prob_t *prob)
|
||||
}
|
||||
current_state = prev;
|
||||
}
|
||||
}
|
||||
|
||||
PgfExpr PgfParser::fetch(PgfDB *db, prob_t *prob)
|
||||
{
|
||||
DB_scope scope(db, READER_SCOPE);
|
||||
|
||||
bool first_fetch = (concr->last_fid == last_fid);
|
||||
|
||||
perform_search();
|
||||
|
||||
if (first_fetch && queue.size() == 0) {
|
||||
std::vector<CCat*> chunks;
|
||||
@@ -1367,8 +1376,8 @@ PgfAbstractParser::State *PgfParser::new_state(const PgfTextSpot &start, prob_t
|
||||
{
|
||||
State **prev = ¤t_state;
|
||||
State *state = current_state;
|
||||
while (state != NULL && state->start.ptr <= start.ptr) {
|
||||
if (state->start.ptr == start.ptr)
|
||||
while (state != NULL && state->start.byte_pos <= start.byte_pos) {
|
||||
if (state->start.byte_pos == start.byte_pos)
|
||||
return state;
|
||||
prev = &state->next;
|
||||
state = state->next;
|
||||
@@ -1381,13 +1390,13 @@ PgfAbstractParser::State *PgfParser::new_state(const PgfTextSpot &start, prob_t
|
||||
state->next = *prev;
|
||||
*prev = state;
|
||||
|
||||
while (state->end.ptr < end) {
|
||||
const uint8_t *ptr = state->end.ptr;
|
||||
while (state->end.byte_pos < sentence->size) {
|
||||
const uint8_t *ptr = (uint8_t *) &sentence->text[state->end.byte_pos];
|
||||
uint32_t ucs = pgf_utf8_decode(&ptr);
|
||||
if (!pgf_utf8_is_space(ucs))
|
||||
break;
|
||||
state->end.pos++;
|
||||
state->end.ptr = ptr;
|
||||
state->end.byte_pos = ptr-(uint8_t *) sentence->text;
|
||||
}
|
||||
|
||||
state->needs_bind = (state->start.pos > 0 && state->start.pos == state->end.pos);
|
||||
@@ -1398,7 +1407,7 @@ PgfAbstractParser::State *PgfParser::new_state(const PgfTextSpot &start, prob_t
|
||||
void PgfParser::symbol_token(Item *item, State *state, ref<PgfSymbolKS> symks)
|
||||
{
|
||||
PgfTextSpot next = state->end;
|
||||
if (text_symbol_cmp(&next,end,symks,case_sensitive) != 0)
|
||||
if (text_symbol_cmp(sentence,&next,symks,case_sensitive) != 0)
|
||||
return;
|
||||
|
||||
State *next_state = new_state(next, item->inside_prob+item->outside_prob);
|
||||
@@ -1516,7 +1525,7 @@ void PgfParser::suspend(Cont *cont,Item *item,bool do_predict,ref<PgfSymbolCat>
|
||||
|
||||
void PgfParser::final_item(State *state, CCat *ccat, Item *item, interval_t value, interval_t lin_idx)
|
||||
{
|
||||
if (item->cont == NULL && state->end.ptr == end) {
|
||||
if (item->cont == NULL && state->end.byte_pos == sentence->size) {
|
||||
ExprState *estate = new(item->args.size()) ExprState;
|
||||
estate->expr = 0;
|
||||
estate->prob = 0;
|
||||
@@ -1609,40 +1618,121 @@ PgfText *PgfParser::get_text() {
|
||||
return sentence;
|
||||
}
|
||||
|
||||
bool PgfParser::change(size_t start, size_t end, PgfText *change)
|
||||
void PgfParser::start()
|
||||
{
|
||||
if (start > sentence->size || end > sentence->size || start > end)
|
||||
prev_state = current_state;
|
||||
current_state = NULL;
|
||||
while (prev_state != NULL) {
|
||||
State *next = prev_state->next;
|
||||
prev_state->next = current_state;
|
||||
current_state = prev_state;
|
||||
prev_state = next;
|
||||
}
|
||||
update_old_pos = 0;
|
||||
update_new_pos = 0;
|
||||
delta_byte_pos = 0;
|
||||
}
|
||||
|
||||
bool PgfParser::skip(size_t i)
|
||||
{
|
||||
update_old_pos += i;
|
||||
update_new_pos += i;
|
||||
if (update_new_pos > sentence->size)
|
||||
return false;
|
||||
|
||||
size_t new_size = sentence->size + change->size - (end-start);
|
||||
|
||||
if (sentence->size < new_size) {
|
||||
PgfText *new_sentence = (PgfText *) realloc(sentence, sizeof(PgfText)+new_size+1);
|
||||
if (new_sentence == NULL)
|
||||
return false;
|
||||
sentence = new_sentence;
|
||||
while (current_state != NULL && current_state->start.pos < update_old_pos) {
|
||||
State *next = current_state->next;
|
||||
current_state->next = prev_state;
|
||||
current_state->start.pos += update_new_pos-update_old_pos;
|
||||
current_state->start.byte_pos += delta_byte_pos;
|
||||
current_state->end.pos += update_new_pos-update_old_pos;
|
||||
current_state->end.byte_pos += delta_byte_pos;
|
||||
prev_state = current_state;
|
||||
current_state = next;
|
||||
}
|
||||
|
||||
memcpy(&sentence->text[start+change->size], &sentence->text[end], sentence->size-end);
|
||||
memcpy(&sentence->text[start], change->text, change->size);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sentence->size > new_size) {
|
||||
PgfText *new_sentence = (PgfText *) realloc(sentence, sizeof(PgfText)+new_size+1);
|
||||
bool PgfParser::change(size_t i, PgfText *change)
|
||||
{
|
||||
update_old_pos += i;
|
||||
if (update_new_pos+i > sentence->size)
|
||||
return false;
|
||||
|
||||
while (current_state != NULL && current_state->end.pos <= update_old_pos) {
|
||||
State *next = current_state->next;
|
||||
delete current_state;
|
||||
current_state = next;
|
||||
}
|
||||
|
||||
size_t new_size = sentence->size + change->size - i;
|
||||
size_t new_allocated_size = sizeof(PgfText)+new_size+1;
|
||||
if (allocated_size < new_allocated_size) {
|
||||
PgfText *new_sentence = (PgfText *) realloc(sentence, new_allocated_size);
|
||||
if (new_sentence == NULL)
|
||||
return false;
|
||||
sentence = new_sentence;
|
||||
allocated_size = new_allocated_size;
|
||||
}
|
||||
|
||||
const uint8_t *ptr1 = (uint8_t *)
|
||||
&sentence->text[prev_state->start.byte_pos];
|
||||
size_t pos = prev_state->start.pos;
|
||||
while (pos < update_new_pos) {
|
||||
pgf_utf8_decode(&ptr1); pos++;
|
||||
}
|
||||
|
||||
const uint8_t *ptr2 = ptr1;
|
||||
while (pos < update_new_pos+i) {
|
||||
pgf_utf8_decode(&ptr2); pos++;
|
||||
}
|
||||
|
||||
memcpy((void*) (ptr1+change->size), ptr2, (uint8_t*)sentence->text+sentence->size-ptr2+1);
|
||||
memcpy((void*) ptr1, change->text, change->size);
|
||||
|
||||
delta_byte_pos += (ptr1+change->size)-ptr2;
|
||||
ptr2 = ptr1+change->size;
|
||||
while (ptr1 < ptr2) {
|
||||
pgf_utf8_decode(&ptr1);
|
||||
update_new_pos++;
|
||||
}
|
||||
|
||||
sentence->size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PgfParser::done()
|
||||
{
|
||||
while (current_state != NULL) {
|
||||
State *next = current_state->next;
|
||||
current_state->next = prev_state;
|
||||
current_state->start.pos += update_new_pos-update_old_pos;
|
||||
current_state->start.byte_pos += delta_byte_pos;
|
||||
current_state->end.pos += update_new_pos-update_old_pos;
|
||||
current_state->end.byte_pos += delta_byte_pos;
|
||||
prev_state = current_state;
|
||||
current_state = next;
|
||||
}
|
||||
current_state = prev_state;
|
||||
prev_state = NULL;
|
||||
update_old_pos = 0;
|
||||
update_new_pos = 0;
|
||||
delta_byte_pos = 0;
|
||||
|
||||
for (State *state = current_state; state != NULL; state=state->next) {
|
||||
fprintf(stderr, "(%zd:%zd-%zd:%zd) ", state->start.pos, state->start.byte_pos
|
||||
, state->end.pos, state->end.byte_pos);
|
||||
}
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
PgfParseTableMaker::PgfParseTableMaker(ref<PgfConcr> concr)
|
||||
: PgfAbstractParser(concr)
|
||||
{
|
||||
current_state = new State;
|
||||
current_state->start.pos = 0;
|
||||
current_state->start.ptr = NULL;
|
||||
current_state->start.byte_pos = 0;
|
||||
current_state->end = current_state->start;
|
||||
current_state->viterbi_prob = 0;
|
||||
current_state->next = NULL;
|
||||
|
||||
@@ -275,9 +275,14 @@ class PGF_INTERNAL_DECL PgfParser : private PgfAbstractParser, public PgfExprEnu
|
||||
PgfMarshaller *m;
|
||||
PgfUnmarshaller *u;
|
||||
PgfText *sentence;
|
||||
uint8_t *end;
|
||||
bool case_sensitive;
|
||||
|
||||
// The following are used only during chart updates.
|
||||
State *prev_state;
|
||||
size_t update_old_pos, update_new_pos;
|
||||
ssize_t delta_byte_pos;
|
||||
ssize_t allocated_size;
|
||||
|
||||
virtual State *new_state(const PgfTextSpot &start, prob_t viterbi_prob);
|
||||
virtual void symbol_token(Item *item, State *state, ref<PgfSymbolKS> symks);
|
||||
virtual void symbol_bind(Item *item, State *state, PgfSymbol sym);
|
||||
@@ -313,11 +318,15 @@ public:
|
||||
virtual ~PgfParser();
|
||||
|
||||
void prepare(ref<PgfConcrLincat> start);
|
||||
void perform_search();
|
||||
|
||||
virtual PgfExpr fetch(PgfDB *db, prob_t *prob);
|
||||
|
||||
virtual PgfText *get_text();
|
||||
virtual bool change(size_t start, size_t end, PgfText *change);
|
||||
virtual void start();
|
||||
virtual bool skip(size_t i);
|
||||
virtual bool change(size_t i, PgfText *change);
|
||||
virtual void done();
|
||||
};
|
||||
|
||||
class PGF_INTERNAL_DECL PgfParseTableMaker : private PgfAbstractParser
|
||||
|
||||
@@ -2777,6 +2777,7 @@ PgfParseChart *pgf_parse_chart(PgfDB *db, PgfConcrRevision revision,
|
||||
|
||||
PgfParser *parser = new PgfParser(concr, sentence, case_sensitive, m, u);
|
||||
parser->prepare(lincat_u.lincat);
|
||||
parser->perform_search();
|
||||
return parser;
|
||||
} PGF_API_END
|
||||
|
||||
|
||||
@@ -833,7 +833,10 @@ void pgf_free_expr_enum(PgfExprEnum *en);
|
||||
#ifdef __cplusplus
|
||||
struct PgfParseChart {
|
||||
virtual PgfText *get_text()=0;
|
||||
virtual bool change(size_t start, size_t end, PgfText *change)=0;
|
||||
virtual void start()=0;
|
||||
virtual bool skip(size_t i)=0;
|
||||
virtual bool change(size_t i, PgfText *change)=0;
|
||||
virtual void done()=0;
|
||||
virtual ~PgfParseChart() {};
|
||||
};
|
||||
#else
|
||||
@@ -841,7 +844,10 @@ typedef struct PgfParseChart PgfParseChart;
|
||||
typedef struct PgfParseChartVtbl PgfParseChartVtbl;
|
||||
struct PgfParseChartVtbl {
|
||||
PgfText *(*get_text)(PgfParseChart *this);
|
||||
int (*change)(PgfParseChart *this, size_t start, size_t end, PgfText *change);
|
||||
void (*start)(PgfParseChart *this);
|
||||
int (*skip)(PgfParseChart *this, size_t i);
|
||||
int (*change)(PgfParseChart *this, size_t i, PgfText *change);
|
||||
void (*done)(PgfParseChart *this);
|
||||
};
|
||||
struct PgfParseChart {
|
||||
PgfParseChartVtbl *vtbl;
|
||||
|
||||
@@ -32,16 +32,19 @@ int lparam_cmp(PgfLParam *p1, PgfLParam *p2)
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
int text_symbol_cmp(PgfTextSpot *spot, const uint8_t *end,
|
||||
int text_symbol_cmp(PgfText *sentence, PgfTextSpot *spot,
|
||||
ref<PgfSymbolKS> sym_ks, bool case_sensitive)
|
||||
{
|
||||
int res1 = 0;
|
||||
|
||||
const uint8_t *s1 = (uint8_t *) &sentence->text[spot->byte_pos];
|
||||
const uint8_t *e1 = (uint8_t *) &sentence->text[sentence->size];
|
||||
|
||||
const uint8_t *s2 = (uint8_t *) &sym_ks->token.text;
|
||||
const uint8_t *e2 = s2+sym_ks->token.size;
|
||||
|
||||
for (;;) {
|
||||
if (spot->ptr >= end) {
|
||||
if (s1 >= e1) {
|
||||
if (s2 < e2)
|
||||
return -1;
|
||||
return case_sensitive ? res1 : 0;
|
||||
@@ -51,8 +54,10 @@ int text_symbol_cmp(PgfTextSpot *spot, const uint8_t *end,
|
||||
return case_sensitive ? res1 : 0;
|
||||
}
|
||||
|
||||
uint32_t ucs1 = pgf_utf8_decode(&spot->ptr); spot->pos++;
|
||||
uint32_t ucs1 = pgf_utf8_decode(&s1);
|
||||
uint32_t ucs1i = pgf_utf8_to_upper(ucs1);
|
||||
spot->pos++;
|
||||
spot->byte_pos = s1-(uint8_t*) sentence->text;
|
||||
|
||||
uint32_t ucs2 = pgf_utf8_decode(&s2);
|
||||
uint32_t ucs2i = pgf_utf8_to_upper(ucs2);
|
||||
@@ -74,7 +79,7 @@ int text_symbol_cmp(PgfTextSpot *spot, const uint8_t *end,
|
||||
}
|
||||
|
||||
static
|
||||
bool text_symbols_match(PgfTextSpot *spot, const uint8_t *end,
|
||||
bool text_symbols_match(PgfText *sentence, PgfTextSpot *spot,
|
||||
vector<PgfSymbol> syms, size_t dot, bool *bind,
|
||||
bool case_sensitive)
|
||||
{
|
||||
@@ -82,20 +87,20 @@ bool text_symbols_match(PgfTextSpot *spot, const uint8_t *end,
|
||||
PgfSymbol sym = syms[dot];
|
||||
switch (ref<PgfSymbol>::get_tag(sym)) {
|
||||
case PgfSymbolKS::tag: {
|
||||
const uint8_t *start = spot->ptr;
|
||||
size_t start = spot->byte_pos;
|
||||
for (;;) {
|
||||
const uint8_t *ptr = spot->ptr;
|
||||
const uint8_t *ptr = (uint8_t *) sentence->text+spot->byte_pos;
|
||||
uint32_t ucs = pgf_utf8_decode(&ptr);
|
||||
if (!pgf_utf8_is_space(ucs))
|
||||
break;
|
||||
spot->ptr = ptr;
|
||||
spot->byte_pos = ptr-(uint8_t *)sentence->text;
|
||||
spot->pos++;
|
||||
}
|
||||
|
||||
if (*bind != (start == spot->ptr))
|
||||
if (*bind != (start == spot->byte_pos))
|
||||
return false;
|
||||
|
||||
if (text_symbol_cmp(spot,end,sym,case_sensitive) != 0)
|
||||
if (text_symbol_cmp(sentence,spot,sym,case_sensitive) != 0)
|
||||
return false;
|
||||
|
||||
break;
|
||||
@@ -104,13 +109,13 @@ bool text_symbols_match(PgfTextSpot *spot, const uint8_t *end,
|
||||
auto symkp = ref<PgfSymbolKP>::untagged(syms[dot]);
|
||||
|
||||
PgfTextSpot current = *spot;
|
||||
if (text_symbols_match(¤t, end, symkp->default_form, 0, bind, case_sensitive)) {
|
||||
if (text_symbols_match(sentence, ¤t, symkp->default_form, 0, bind, case_sensitive)) {
|
||||
goto matched;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < symkp->alts.size(); i++) {
|
||||
current = *spot;
|
||||
if (text_symbols_match(¤t, end, symkp->alts[i].form, 0, bind, case_sensitive)) {
|
||||
if (text_symbols_match(sentence, ¤t, symkp->alts[i].form, 0, bind, case_sensitive)) {
|
||||
goto matched;
|
||||
}
|
||||
}
|
||||
@@ -145,7 +150,7 @@ bool text_symbols_match(PgfTextSpot *spot, const uint8_t *end,
|
||||
}
|
||||
|
||||
static
|
||||
bool text_item_match(PgfTextSpot *spot, const uint8_t *end,
|
||||
bool text_item_match(PgfText *sentence, PgfTextSpot *spot,
|
||||
ref<PgfItem> item,
|
||||
bool case_sensitive)
|
||||
{
|
||||
@@ -155,15 +160,15 @@ bool text_item_match(PgfTextSpot *spot, const uint8_t *end,
|
||||
if (item->pre_alt > 0) {
|
||||
auto symkp = ref<PgfSymbolKP>::untagged(syms[item->pre_dot]);
|
||||
if (item->pre_alt == 1) {
|
||||
if (!text_symbols_match(spot, end, symkp->default_form, item->dot, &bind, case_sensitive))
|
||||
if (!text_symbols_match(sentence, spot, symkp->default_form, item->dot, &bind, case_sensitive))
|
||||
return false;
|
||||
} else {
|
||||
if (!text_symbols_match(spot, end, symkp->alts[item->pre_alt-2].form, item->dot, &bind, case_sensitive))
|
||||
if (!text_symbols_match(sentence, spot, symkp->alts[item->pre_alt-2].form, item->dot, &bind, case_sensitive))
|
||||
return false;
|
||||
}
|
||||
dot = item->pre_dot+1;
|
||||
}
|
||||
return text_symbols_match(spot, end, syms, dot, &bind, case_sensitive);
|
||||
return text_symbols_match(sentence, spot, syms, dot, &bind, case_sensitive);
|
||||
}
|
||||
|
||||
PGF_INTERNAL_DECL
|
||||
@@ -202,9 +207,8 @@ void phrasetable_lookup(PgfPhrasetable<PgfSymbolKS> table,
|
||||
|
||||
PgfTextSpot spot;
|
||||
spot.pos = 0;
|
||||
spot.ptr = (uint8_t *) sentence->text;
|
||||
const uint8_t *end = spot.ptr+sentence->size;
|
||||
int cmp = text_symbol_cmp(&spot,end,table->value.key,case_sensitive);
|
||||
spot.byte_pos = 0;
|
||||
int cmp = text_symbol_cmp(sentence,&spot,table->value.key,case_sensitive);
|
||||
if (cmp < 0) {
|
||||
phrasetable_lookup(table->left,sentence,case_sensitive,scanner,err);
|
||||
} else if (cmp > 0) {
|
||||
@@ -223,7 +227,7 @@ void phrasetable_lookup(PgfPhrasetable<PgfSymbolKS> table,
|
||||
ref<PgfConcrLin> lin = ref<PgfConcrLin>::untagged(item->rule->container);
|
||||
if (lin->absfun->type->hypos.size() == 0) {
|
||||
PgfTextSpot current = spot;
|
||||
if (text_item_match(¤t, end, item, case_sensitive) && current.ptr == end) {
|
||||
if (text_item_match(sentence, ¤t, item, case_sensitive) && current.byte_pos == sentence->size) {
|
||||
scanner->match(lin, item->rule->lin_idx->i0, err);
|
||||
if (err->type != PGF_EXN_NONE)
|
||||
return;
|
||||
@@ -255,12 +259,12 @@ struct PGF_INTERNAL_DECL PgfCohortsState {
|
||||
}
|
||||
};
|
||||
|
||||
PgfText *sentence;
|
||||
PgfTextSpot spot;
|
||||
std::priority_queue<PgfTextSpot, std::vector<PgfTextSpot>, PgfTextSpotComparator> queue;
|
||||
|
||||
PgfTextSpot last;
|
||||
bool skipping;
|
||||
const uint8_t *end; // pointer into the end of the sentence
|
||||
|
||||
bool case_sensitive;
|
||||
PgfPhraseScanner *scanner;
|
||||
@@ -303,7 +307,7 @@ void finish_skipping(PgfCohortsState *state) {
|
||||
state->err);
|
||||
*/
|
||||
state->last.pos = 0;
|
||||
state->last.ptr = NULL;
|
||||
state->last.byte_pos = 0;
|
||||
state->skipping = false;
|
||||
}
|
||||
}
|
||||
@@ -311,17 +315,17 @@ void finish_skipping(PgfCohortsState *state) {
|
||||
static
|
||||
void phrasetable_lookup_prefixes(PgfCohortsState *state,
|
||||
PgfPhrasetable<PgfSymbolKS> table,
|
||||
ptrdiff_t min, ptrdiff_t max)
|
||||
size_t min, size_t max)
|
||||
{
|
||||
if (table == 0)
|
||||
return;
|
||||
|
||||
PgfTextSpot current = state->spot;
|
||||
int cmp = text_symbol_cmp(¤t,state->end,table->value.key,state->case_sensitive);
|
||||
int cmp = text_symbol_cmp(state->sentence,¤t,table->value.key,state->case_sensitive);
|
||||
if (cmp < 0) {
|
||||
phrasetable_lookup_prefixes(state,table->left,min,max);
|
||||
} else if (cmp > 0) {
|
||||
ptrdiff_t len = current.ptr - state->spot.ptr;
|
||||
size_t len = current.byte_pos - state->spot.byte_pos;
|
||||
|
||||
if (min <= len-1)
|
||||
phrasetable_lookup_prefixes(state,table->left,min,len-1);
|
||||
@@ -329,7 +333,7 @@ void phrasetable_lookup_prefixes(PgfCohortsState *state,
|
||||
if (len <= max)
|
||||
phrasetable_lookup_prefixes(state,table->right,len,max);
|
||||
} else {
|
||||
ptrdiff_t len = current.ptr - state->spot.ptr;
|
||||
size_t len = current.byte_pos - state->spot.byte_pos;
|
||||
|
||||
finish_skipping(state);
|
||||
if (state->err->type != PGF_EXN_NONE)
|
||||
@@ -391,15 +395,15 @@ void phrasetable_lookup_cohorts(PgfPhrasetable<PgfSymbolKS> table,
|
||||
{
|
||||
PgfTextSpot spot;
|
||||
spot.pos = 0;
|
||||
spot.ptr = (uint8_t *) sentence->text;
|
||||
spot.byte_pos = 0;
|
||||
|
||||
PgfCohortsState state;
|
||||
state.spot.pos = -1;
|
||||
state.spot.ptr = NULL;
|
||||
state.spot.byte_pos = -1;
|
||||
state.sentence = sentence;
|
||||
state.queue.push(spot);
|
||||
state.last = spot;
|
||||
state.skipping = false;
|
||||
state.end = (uint8_t *) &sentence->text[sentence->size];
|
||||
state.case_sensitive = case_sensitive;
|
||||
state.scanner = scanner;
|
||||
state.err = err;
|
||||
@@ -412,20 +416,20 @@ void phrasetable_lookup_cohorts(PgfPhrasetable<PgfSymbolKS> table,
|
||||
state.spot = spot;
|
||||
|
||||
// skip leading spaces
|
||||
while (state.spot.ptr < state.end) {
|
||||
const uint8_t *ptr = state.spot.ptr;
|
||||
while (state.spot.byte_pos < state.sentence->size) {
|
||||
const uint8_t *ptr = (uint8_t *) &sentence->text[state.spot.byte_pos];
|
||||
uint32_t ucs = pgf_utf8_decode(&ptr);
|
||||
if (!pgf_utf8_is_space(ucs))
|
||||
break;
|
||||
state.spot.pos++;
|
||||
state.spot.ptr = ptr;
|
||||
state.spot.byte_pos = ptr-(uint8_t *) sentence->text;
|
||||
}
|
||||
|
||||
state.scanner->space(&spot,&state.spot,state.err);
|
||||
if (state.err->type != PGF_EXN_NONE)
|
||||
return;
|
||||
|
||||
while (state.spot.ptr < state.end) {
|
||||
while (state.spot.byte_pos < state.sentence->size) {
|
||||
phrasetable_lookup_prefixes(&state, table, 1, sentence->size);
|
||||
if (state.err->type != PGF_EXN_NONE)
|
||||
return;
|
||||
@@ -438,7 +442,7 @@ void phrasetable_lookup_cohorts(PgfPhrasetable<PgfSymbolKS> table,
|
||||
if (state.err->type != PGF_EXN_NONE)
|
||||
return;
|
||||
state.last.pos = 0;
|
||||
state.last.ptr = (uint8_t*) sentence->text;
|
||||
state.last.byte_pos = 0;
|
||||
break;
|
||||
} else {
|
||||
// No matches were found, try the next position
|
||||
@@ -451,14 +455,14 @@ void phrasetable_lookup_cohorts(PgfPhrasetable<PgfSymbolKS> table,
|
||||
state.skipping = true;
|
||||
}
|
||||
|
||||
const uint8_t *ptr = state.spot.ptr;
|
||||
const uint8_t *ptr = (uint8_t *) &state.sentence->text[state.spot.byte_pos];
|
||||
uint32_t ucs = pgf_utf8_decode(&ptr);
|
||||
if (pgf_utf8_is_space(ucs)) {
|
||||
state.queue.push(state.spot);
|
||||
break;
|
||||
}
|
||||
state.spot.pos++;
|
||||
state.spot.ptr = ptr;
|
||||
state.spot.byte_pos = ptr-(uint8_t *) state.sentence->text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ struct PgfConcrLincat;
|
||||
|
||||
struct PGF_INTERNAL_DECL PgfTextSpot {
|
||||
size_t pos; // position in Unicode characters
|
||||
const uint8_t *ptr; // pointer into the spot location
|
||||
size_t byte_pos; // position in number of bytes
|
||||
};
|
||||
|
||||
struct PGF_INTERNAL_DECL PgfItem {
|
||||
|
||||
@@ -87,7 +87,6 @@ module PGF2 (-- * PGF
|
||||
|
||||
-- ** Parsing
|
||||
ParseOutput(..), parse, parseWithHeuristics, complete,
|
||||
ParseChart, parseChart, getParseChartText, changeParseChartText,
|
||||
|
||||
-- * Exceptions
|
||||
PGFError(..),
|
||||
@@ -873,36 +872,6 @@ enumerateExprs c_db c_revision c_enum_ptr = do
|
||||
rest <- unsafeInterleaveIO (fetchLazy c_fetch c_enum)
|
||||
return ((expr,prob) : rest)
|
||||
|
||||
data ParseChart = ParseChart {ch_db :: Ptr PgfDB,
|
||||
ch_revision :: ForeignPtr Concr,
|
||||
ch_chart :: ForeignPtr PgfParseChart
|
||||
}
|
||||
|
||||
parseChart :: Concr -> Type -> String -> IO ParseChart
|
||||
parseChart c ty sent =
|
||||
withForeignPtr (c_revision c) $ \c_revision_ptr ->
|
||||
bracket (newStablePtr ty) freeStablePtr $ \c_ty ->
|
||||
withText sent $ \c_sent -> do
|
||||
c_chart <- withPgfExn "parseChart" (pgf_parse_chart (c_db c) c_revision_ptr c_ty marshaller unmarshaller c_sent)
|
||||
fptr <- newForeignPtr pgf_free_parse_chart c_chart
|
||||
return (ParseChart (c_db c) (c_revision c) fptr)
|
||||
|
||||
getParseChartText :: ParseChart -> IO String
|
||||
getParseChartText (ParseChart c_db c_revision c_chart) =
|
||||
withForeignPtr c_chart $ \c_chart_ptr -> do
|
||||
c_get_text <- (#peek PgfParseChartVtbl, get_text) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
c_text <- callGetText c_get_text c_chart_ptr
|
||||
peekText c_text
|
||||
|
||||
changeParseChartText :: ParseChart -> CSize -> CSize -> String -> IO Bool
|
||||
changeParseChartText (ParseChart c_db c_revision c_chart) start end text =
|
||||
withForeignPtr c_revision $ \_ ->
|
||||
withForeignPtr c_chart $ \c_chart_ptr ->
|
||||
withText text $ \c_text -> do
|
||||
c_change <- (#peek PgfParseChartVtbl, change) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
c_res <- callChange c_change c_chart_ptr start end c_text
|
||||
return (c_res /= 0)
|
||||
|
||||
parseWithHeuristics :: Concr -- ^ the language with which we parse
|
||||
-> Type -- ^ the start category
|
||||
-> String -- ^ the input sentence
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
-------------------------------------------------
|
||||
-- |
|
||||
-- Module : PGF2.Colab
|
||||
-- Maintainer : Krasimir Angelov
|
||||
-- Stability : stable
|
||||
-- Portability : portable
|
||||
--
|
||||
-- This module is a server API for implementing
|
||||
-- collaborative editing, where the edited document
|
||||
-- is continuously parsed.
|
||||
-------------------------------------------------
|
||||
|
||||
module PGF2.Collab
|
||||
( ParseChart, parseChart
|
||||
, getParseChartText
|
||||
, Change(..), changeParseChartText
|
||||
) where
|
||||
|
||||
import PGF2.Expr
|
||||
import PGF2.FFI
|
||||
|
||||
import Foreign
|
||||
import Foreign.C
|
||||
import Control.Exception(bracket)
|
||||
|
||||
#include <pgf/pgf.h>
|
||||
|
||||
data ParseChart = ParseChart {ch_db :: Ptr PgfDB,
|
||||
ch_revision :: ForeignPtr Concr,
|
||||
ch_chart :: ForeignPtr PgfParseChart
|
||||
}
|
||||
|
||||
parseChart :: Concr -> Type -> String -> IO ParseChart
|
||||
parseChart c ty sent =
|
||||
withForeignPtr (c_revision c) $ \c_revision_ptr ->
|
||||
bracket (newStablePtr ty) freeStablePtr $ \c_ty ->
|
||||
withText sent $ \c_sent -> do
|
||||
c_chart <- withPgfExn "parseChart" (pgf_parse_chart (c_db c) c_revision_ptr c_ty marshaller unmarshaller c_sent)
|
||||
fptr <- newForeignPtr pgf_free_parse_chart c_chart
|
||||
return (ParseChart (c_db c) (c_revision c) fptr)
|
||||
|
||||
getParseChartText :: ParseChart -> IO String
|
||||
getParseChartText (ParseChart c_db c_revision c_chart) =
|
||||
withForeignPtr c_chart $ \c_chart_ptr -> do
|
||||
c_get_text <- (#peek PgfParseChartVtbl, get_text) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
c_text <- callGetText c_get_text c_chart_ptr
|
||||
peekText c_text
|
||||
|
||||
data Change = Skip {-# UNPACK #-} !CSize | Change {-# UNPACK #-} !CSize String deriving Show
|
||||
|
||||
changeParseChartText :: ParseChart -> [Change] -> IO Bool
|
||||
changeParseChartText (ParseChart c_db c_revision c_chart) changes =
|
||||
withForeignPtr c_revision $ \_ ->
|
||||
withForeignPtr c_chart $ \c_chart_ptr -> do
|
||||
c_start <- (#peek PgfParseChartVtbl, start) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
callStart c_start c_chart_ptr
|
||||
res <- apply c_chart_ptr changes
|
||||
c_done <- (#peek PgfParseChartVtbl, done) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
callDone c_done c_chart_ptr
|
||||
return res
|
||||
where
|
||||
apply c_chart_ptr [] = return True
|
||||
apply c_chart_ptr (Skip i :changes) = do
|
||||
c_skip <- (#peek PgfParseChartVtbl, skip) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
c_res <- callSkip c_skip c_chart_ptr i
|
||||
if c_res == 0
|
||||
then return False
|
||||
else apply c_chart_ptr changes
|
||||
apply c_chart_ptr (Change i text:changes) = do
|
||||
c_change <- (#peek PgfParseChartVtbl, change) =<< (#peek PgfParseChart, vtbl) c_chart_ptr
|
||||
c_res <- withText text (callChange c_change c_chart_ptr i)
|
||||
if c_res == 0
|
||||
then return False
|
||||
else apply c_chart_ptr changes
|
||||
@@ -295,7 +295,13 @@ foreign import ccall "&pgf_free_parse_chart" pgf_free_parse_chart :: FunPtr (Ptr
|
||||
|
||||
foreign import ccall "dynamic" callGetText :: Dynamic (Ptr PgfParseChart -> IO (Ptr PgfText))
|
||||
|
||||
foreign import ccall "dynamic" callChange :: Dynamic (Ptr PgfParseChart -> CSize -> CSize -> Ptr PgfText -> IO CInt)
|
||||
foreign import ccall "dynamic" callStart :: Dynamic (Ptr PgfParseChart -> IO CInt)
|
||||
|
||||
foreign import ccall "dynamic" callSkip :: Dynamic (Ptr PgfParseChart -> CSize -> IO CInt)
|
||||
|
||||
foreign import ccall "dynamic" callChange :: Dynamic (Ptr PgfParseChart -> CSize -> Ptr PgfText -> IO CInt)
|
||||
|
||||
foreign import ccall "dynamic" callDone :: Dynamic (Ptr PgfParseChart -> IO CInt)
|
||||
|
||||
foreign import ccall "wrapper" wrapSymbol0 :: Wrapper (Ptr PgfLinearizationOutputIface -> IO ())
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ library
|
||||
exposed-modules:
|
||||
PGF2,
|
||||
PGF2.Transactions,
|
||||
PGF2.Collab,
|
||||
PGF2.ByteCode,
|
||||
-- backwards compatibility API:
|
||||
PGF
|
||||
|
||||
Reference in New Issue
Block a user