diff --git a/src/runtime/c/pgf/parser.cxx b/src/runtime/c/pgf/parser.cxx index 776906d23..ca6022dcb 100644 --- a/src/runtime/c/pgf/parser.cxx +++ b/src/runtime/c/pgf/parser.cxx @@ -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 sym, bool case_sensitive); void PgfAbstractParser::symbol(Item *item, State *state, PgfSymbol sym) @@ -857,8 +857,12 @@ PgfParser::PgfParser(ref 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 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 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 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 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 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 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 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 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; diff --git a/src/runtime/c/pgf/parser.h b/src/runtime/c/pgf/parser.h index 7176e2fb5..29ce2fc7c 100644 --- a/src/runtime/c/pgf/parser.h +++ b/src/runtime/c/pgf/parser.h @@ -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 symks); virtual void symbol_bind(Item *item, State *state, PgfSymbol sym); @@ -313,11 +318,15 @@ public: virtual ~PgfParser(); void prepare(ref 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 diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index 0cf830cb9..c013a2c4a 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -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 diff --git a/src/runtime/c/pgf/pgf.h b/src/runtime/c/pgf/pgf.h index 68b4889b0..6041cd8f6 100644 --- a/src/runtime/c/pgf/pgf.h +++ b/src/runtime/c/pgf/pgf.h @@ -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; diff --git a/src/runtime/c/pgf/phrasetable.cxx b/src/runtime/c/pgf/phrasetable.cxx index 76b583d3c..303f37fce 100644 --- a/src/runtime/c/pgf/phrasetable.cxx +++ b/src/runtime/c/pgf/phrasetable.cxx @@ -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 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 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::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::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 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::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 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 table, ref lin = ref::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, 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 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 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 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 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 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; } } diff --git a/src/runtime/c/pgf/phrasetable.h b/src/runtime/c/pgf/phrasetable.h index 3d8cb4c86..727f3668c 100644 --- a/src/runtime/c/pgf/phrasetable.h +++ b/src/runtime/c/pgf/phrasetable.h @@ -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 { diff --git a/src/runtime/haskell/PGF2.hsc b/src/runtime/haskell/PGF2.hsc index 23c557ef5..a1a0c6e5d 100644 --- a/src/runtime/haskell/PGF2.hsc +++ b/src/runtime/haskell/PGF2.hsc @@ -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 diff --git a/src/runtime/haskell/PGF2/Collab.hsc b/src/runtime/haskell/PGF2/Collab.hsc new file mode 100644 index 000000000..0f3387c49 --- /dev/null +++ b/src/runtime/haskell/PGF2/Collab.hsc @@ -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 + +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 diff --git a/src/runtime/haskell/PGF2/FFI.hsc b/src/runtime/haskell/PGF2/FFI.hsc index dd2519519..54b2d93b3 100644 --- a/src/runtime/haskell/PGF2/FFI.hsc +++ b/src/runtime/haskell/PGF2/FFI.hsc @@ -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 ()) diff --git a/src/runtime/haskell/pgf2.cabal b/src/runtime/haskell/pgf2.cabal index 147a306ae..6c3ba549f 100644 --- a/src/runtime/haskell/pgf2.cabal +++ b/src/runtime/haskell/pgf2.cabal @@ -23,6 +23,7 @@ library exposed-modules: PGF2, PGF2.Transactions, + PGF2.Collab, PGF2.ByteCode, -- backwards compatibility API: PGF