From d2e7264326761a55a4eab04175fe9eb87f359900 Mon Sep 17 00:00:00 2001 From: Krasimir Angelov Date: Wed, 19 Aug 2026 16:22:22 +0200 Subject: [PATCH] a first draft of an API for collaborative editing --- src/runtime/c/pgf/parser.cxx | 32 ++++++++++++++++++++++++++++++++ src/runtime/c/pgf/parser.h | 7 +++++-- src/runtime/c/pgf/pgf.cxx | 32 ++++++++++++++++++++++++++++++++ src/runtime/c/pgf/pgf.h | 27 +++++++++++++++++++++++++++ src/runtime/haskell/PGF2.hsc | 31 +++++++++++++++++++++++++++++++ src/runtime/haskell/PGF2/FFI.hsc | 11 ++++++++++- 6 files changed, 137 insertions(+), 3 deletions(-) diff --git a/src/runtime/c/pgf/parser.cxx b/src/runtime/c/pgf/parser.cxx index f367f7b09..776906d23 100644 --- a/src/runtime/c/pgf/parser.cxx +++ b/src/runtime/c/pgf/parser.cxx @@ -1605,6 +1605,38 @@ void PgfParser::print_expr_state(PgfMarshaller *m, ExprState *estate) } #endif +PgfText *PgfParser::get_text() { + return sentence; +} + +bool PgfParser::change(size_t start, size_t end, PgfText *change) +{ + if (start > sentence->size || end > sentence->size || start > end) + 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; + } + + memcpy(&sentence->text[start+change->size], &sentence->text[end], sentence->size-end); + memcpy(&sentence->text[start], change->text, change->size); + + 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; + } + + sentence->size = new_size; + return true; +} + PgfParseTableMaker::PgfParseTableMaker(ref concr) : PgfAbstractParser(concr) { diff --git a/src/runtime/c/pgf/parser.h b/src/runtime/c/pgf/parser.h index 14f8b8e8b..7176e2fb5 100644 --- a/src/runtime/c/pgf/parser.h +++ b/src/runtime/c/pgf/parser.h @@ -270,7 +270,7 @@ public: virtual ~PgfAbstractParser(); }; -class PGF_INTERNAL_DECL PgfParser : private PgfAbstractParser, public PgfExprEnum +class PGF_INTERNAL_DECL PgfParser : private PgfAbstractParser, public PgfExprEnum, public PgfParseChart { PgfMarshaller *m; PgfUnmarshaller *u; @@ -314,7 +314,10 @@ public: void prepare(ref start); - PgfExpr fetch(PgfDB *db, prob_t *prob); + virtual PgfExpr fetch(PgfDB *db, prob_t *prob); + + virtual PgfText *get_text(); + virtual bool change(size_t start, size_t end, PgfText *change); }; class PGF_INTERNAL_DECL PgfParseTableMaker : private PgfAbstractParser diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index 2db16e1ef..0cf830cb9 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -2757,6 +2757,38 @@ void pgf_free_expr_enum(PgfExprEnum *en) delete en; } +PGF_API +PgfParseChart *pgf_parse_chart(PgfDB *db, PgfConcrRevision revision, + PgfType ty, PgfMarshaller *m, PgfUnmarshaller *u, + PgfText *sentence, + PgfExn * err) +{ + PGF_API_BEGIN { + DB_scope scope(db, READER_SCOPE); + + ref concr = db->revision2concr(revision); + + bool case_sensitive = pgf_is_case_sensitive(concr); + + PgfLincatUnmarshaller lincat_u(concr); + m->match_type(&lincat_u, ty); + if (lincat_u.lincat == 0) + return 0; + + PgfParser *parser = new PgfParser(concr, sentence, case_sensitive, m, u); + parser->prepare(lincat_u.lincat); + return parser; + } PGF_API_END + + return NULL; +} + +PGF_API +void pgf_free_parse_chart(PgfParseChart *chart) +{ + delete chart; +} + PGF_API PgfText *pgf_get_printname(PgfDB *db, PgfConcrRevision revision, PgfText *fun, PgfExn* err) diff --git a/src/runtime/c/pgf/pgf.h b/src/runtime/c/pgf/pgf.h index 8a590591c..68b4889b0 100644 --- a/src/runtime/c/pgf/pgf.h +++ b/src/runtime/c/pgf/pgf.h @@ -830,6 +830,33 @@ PgfExprEnum *pgf_parse(PgfDB *db, PgfConcrRevision revision, PGF_API_DECL 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 ~PgfParseChart() {}; +}; +#else +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); +}; +struct PgfParseChart { + PgfParseChartVtbl *vtbl; +}; +#endif + +PGF_API_DECL +PgfParseChart *pgf_parse_chart(PgfDB *db, PgfConcrRevision revision, + PgfType ty, PgfMarshaller *m, PgfUnmarshaller *u, + PgfText *sentence, + PgfExn * err); + +PGF_API_DECL +void pgf_free_parse_chart(PgfParseChart *chart); + PGF_API_DECL PgfText *pgf_get_printname(PgfDB *db, PgfConcrRevision revision, PgfText *fun, PgfExn* err); diff --git a/src/runtime/haskell/PGF2.hsc b/src/runtime/haskell/PGF2.hsc index a1a0c6e5d..d3d7c546f 100644 --- a/src/runtime/haskell/PGF2.hsc +++ b/src/runtime/haskell/PGF2.hsc @@ -87,6 +87,7 @@ module PGF2 (-- * PGF -- ** Parsing ParseOutput(..), parse, parseWithHeuristics, complete, + parseChart, getParseChartText, changeParseChartText, -- * Exceptions PGFError(..), @@ -872,6 +873,36 @@ 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/FFI.hsc b/src/runtime/haskell/PGF2/FFI.hsc index 6b3e90447..dd2519519 100644 --- a/src/runtime/haskell/PGF2/FFI.hsc +++ b/src/runtime/haskell/PGF2/FFI.hsc @@ -49,6 +49,7 @@ data PgfProbsCallback data PgfMorphoCallback data PgfCohortsCallback data PgfExprEnum +data PgfParseChart data PgfAlignmentPhrase data PgfParseTableMaker @@ -284,9 +285,17 @@ foreign import ccall pgf_align_words :: Ptr PgfDB -> Ptr Concr -> StablePtr Expr foreign import ccall pgf_parse :: Ptr PgfDB -> Ptr Concr -> StablePtr Type -> Ptr PgfMarshaller -> Ptr PgfUnmarshaller -> Ptr PgfText -> Ptr PgfExn -> IO (Ptr PgfExprEnum) +foreign import ccall "&pgf_free_expr_enum" pgf_free_expr_enum :: FunPtr (Ptr PgfExprEnum -> IO ()) + foreign import ccall "dynamic" callFetch :: Dynamic (Ptr PgfExprEnum -> Ptr PgfDB -> Ptr (#type prob_t) -> IO (StablePtr Expr)) -foreign import ccall "&pgf_free_expr_enum" pgf_free_expr_enum :: FunPtr (Ptr PgfExprEnum -> IO ()) +foreign import ccall pgf_parse_chart :: Ptr PgfDB -> Ptr Concr -> StablePtr Type -> Ptr PgfMarshaller -> Ptr PgfUnmarshaller -> Ptr PgfText -> Ptr PgfExn -> IO (Ptr PgfParseChart) + +foreign import ccall "&pgf_free_parse_chart" pgf_free_parse_chart :: FunPtr (Ptr PgfParseChart -> IO ()) + +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 "wrapper" wrapSymbol0 :: Wrapper (Ptr PgfLinearizationOutputIface -> IO ())