diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0ca0794b0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -sudo: required - -language: c - -services: - - docker - -before_install: - - docker pull odanoburu/gf-src:3.9 - -script: - - | - docker run --mount src="$(pwd)",target=/home/gfer,type=bind odanoburu/gf-src:3.9 /bin/bash -c "cd /home/gfer/src/runtime/c && - autoreconf -i && ./configure && make && make install ; cd /home/gfer ; cabal install -fserver -fc-runtime --extra-lib-dirs='/usr/local/lib'" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..ac209f1af --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +### New since 3.11 (WIP) + +- Added a changelog! + +### 3.11 + +See + +### 3.10 + +See diff --git a/Makefile b/Makefile index cdb35e49a..fc2a38808 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,6 @@ bintar: # Make a source tar.gz distribution using git to make sure that everything is included. # We put the distribution in dist/ so it is removed on `make clean` -sdist: - test -d dist || mkdir dist - git archive --format=tar.gz --output=dist/gf-${VERSION}.tar.gz HEAD +# sdist: +# test -d dist || mkdir dist +# git archive --format=tar.gz --output=dist/gf-${VERSION}.tar.gz HEAD diff --git a/README.md b/README.md index e393be0e6..79e6ab68f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![GF Logo](doc/Logos/gf1.svg) +![GF Logo](https://www.grammaticalframework.org/doc/Logos/gf1.svg) # Grammatical Framework (GF) @@ -39,7 +39,7 @@ or: stack install ``` -For more information, including links to precompiled binaries, see the [download page](http://www.grammaticalframework.org/download/index.html). +For more information, including links to precompiled binaries, see the [download page](https://www.grammaticalframework.org/download/index.html). ## About this repository diff --git a/RELEASE.md b/RELEASE.md index 04bd4b933..1deaa3a90 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -47,11 +47,14 @@ but the generated _artifacts_ must be manually attached to the release as _asset In order to do this you will need to be added the [GF maintainers](https://hackage.haskell.org/package/gf/maintainers/) on Hackage. -1. Run `make sdist` +1. Run `stack sdist --test-tarball` and address any issues. 2. Upload the package, either: - 1. **Manually**: visit and upload the file `dist/gf-X.Y.tar.gz` - 2. **via Cabal (≥2.4)**: `cabal upload dist/gf-X.Y.tar.gz` -3. If the documentation-building fails on the Hackage server, do: + 1. **Manually**: visit and upload the file generated by the previous command. + 2. **via Stack**: `stack upload . --candidate` +3. After testing the candidate, publish it: + 1. **Manually**: visit + 1. **via Stack**: `stack upload .` +4. If the documentation-building fails on the Hackage server, do: ``` cabal v2-haddock --builddir=dist/docs --haddock-for-hackage --enable-doc cabal upload --documentation dist/docs/*-docs.tar.gz diff --git a/doc/gf-people.md b/doc/gf-people.md index 7d0ef90c2..d7b755b9d 100644 --- a/doc/gf-people.md +++ b/doc/gf-people.md @@ -7,7 +7,6 @@ title: "Grammatical Framework: Authors and Acknowledgements" The current maintainers of GF are [Krasimir Angelov](http://www.chalmers.se/cse/EN/organization/divisions/computing-science/people/angelov-krasimir), -[Thomas Hallgren](http://www.cse.chalmers.se/~hallgren/), [Aarne Ranta](http://www.cse.chalmers.se/~aarne/), [John J. Camilleri](http://johnjcamilleri.com), and [Inari Listenmaa](https://inariksit.github.io/). @@ -22,6 +21,7 @@ and The following people have contributed code to some of the versions: +- [Thomas Hallgren](http://www.cse.chalmers.se/~hallgren/) (University of Gothenburg) - Grégoire Détrez (University of Gothenburg) - Ramona Enache (University of Gothenburg) - [Björn Bringert](http://www.cse.chalmers.se/alumni/bringert) (University of Gothenburg) diff --git a/download/index-3.11.md b/download/index-3.11.md index 4f2798a0a..8fa1d5c02 100644 --- a/download/index-3.11.md +++ b/download/index-3.11.md @@ -53,26 +53,39 @@ You will probably need to update the `PATH` environment variable to include your For more information, see [Using GF on Windows](https://www.grammaticalframework.org/~inari/gf-windows.html) (latest updated for Windows 10). - -## Installing from the latest developer source code +**Obtaining** -If you haven't already, clone the repository with: +To obtain the source code for the **release**, +download it from [GitHub](https://github.com/GrammaticalFramework/gf-core/releases). +Alternatively, to obtain the **latest version** of the source code: + +1. If you haven't already, clone the repository with: ``` git clone https://github.com/GrammaticalFramework/gf-core.git ``` - -If you've already cloned the repository previously, update with: - +2. If you've already cloned the repository previously, update with: ``` git pull ``` -Then install with: +**Installing** + +You can then install with: ``` cabal install ``` diff --git a/index.html b/index.html index 8816cc265..f657cc5b5 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@ - + @@ -85,10 +85,27 @@

Contribute

@@ -154,7 +171,7 @@ least one, it may help you to get a first idea of what GF is.
-

Applications & Availability

+

Applications & availability

GF can be used for building translation systems, @@ -219,19 +236,28 @@ least one, it may help you to get a first idea of what GF is. or browse the channel logs.

- If you have a larger question which the community may benefit from, we recommend you ask it on the mailing list. + There is also a GF server on Discord. +

+ +

+ For bug reports and feature requests, please create an issue in the + GF Core or + RGL repository. + + For programming questions, consider asking them on Stack Overflow with the gf tag. + If you have a more general question to the community, we recommend you ask it on the mailing list.

News

-
2021-07-25
-
- GF 3.11 released. - Release notes -
+
2021-07-25
+
+ GF 3.11 released. + Release notes +
2021-05-05
GF WordNet now supports languages for which there are no other WordNets. New additions: Afrikaans, German, Korean, Maltese, Polish, Somali, Swahili. @@ -244,34 +270,6 @@ least one, it may help you to get a first idea of what GF is.
Abstract Syntax as Interlingua: Scaling Up the Grammatical Framework from Controlled Languages to Robust Pipelines. A paper in Computational Linguistics (2020) summarizing much of the development in GF in the past ten years.
-
2018-12-03
-
- Sixth GF Summer School in Stellenbosch (South Africa), 3–14 December 2018 -
-
2018-12-02
-
- GF 3.10 released. - Release notes -
-
2018-07-25
-
- The GF repository has been split in two: - gf-core and - gf-rgl. - The original GF repository is now archived. -
-
2017-08-11
-
- GF 3.9 released. - Release notes -
-
2017-06-29
-
- GF is moving to GitHub.
-
2017-03-13
-
- GF Summer School in Riga (Latvia), 14-25 August 2017 -

Projects

@@ -341,7 +339,7 @@ least one, it may help you to get a first idea of what GF is. Libraries are at the heart of modern software engineering. In natural language applications, libraries are a way to cope with thousands of details involved in syntax, lexicon, and inflection. The - GF resource grammar library has + GF resource grammar library (RGL) has support for an increasing number of languages, currently including Afrikaans, Amharic (partial), diff --git a/src/programs/gf-main.hs b/src/programs/gf-main.hs index 1dae54bc7..cf387d2fa 100644 --- a/src/programs/gf-main.hs +++ b/src/programs/gf-main.hs @@ -1,3 +1,5 @@ +module Main where + import qualified GF main = GF.main diff --git a/src/runtime/c/doc/README.md b/src/runtime/c/doc/README.md index 7c11b755c..7940f51f5 100644 --- a/src/runtime/c/doc/README.md +++ b/src/runtime/c/doc/README.md @@ -12,3 +12,4 @@ So, **Don't Panic!** and keep reading. This is a live document and will develop 1. [Desiderata](DESIDERATA.md) 2. [Memory Model](memory_model.md) 3. [Abstract Expressions](abstract_expressions.md) +3. [Transactions](transactions.md) diff --git a/src/runtime/c/doc/transactions.md b/src/runtime/c/doc/transactions.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/runtime/c/pgf/db.cxx b/src/runtime/c/pgf/db.cxx index b0bad20f7..ff20835a5 100644 --- a/src/runtime/c/pgf/db.cxx +++ b/src/runtime/c/pgf/db.cxx @@ -289,6 +289,7 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) { fd = -1; ms = NULL; + ref_count = 0; if (filepath == NULL) { this->filepath = NULL; diff --git a/src/runtime/c/pgf/db.h b/src/runtime/c/pgf/db.h index bfde56ebb..b7bc01482 100644 --- a/src/runtime/c/pgf/db.h +++ b/src/runtime/c/pgf/db.h @@ -65,6 +65,10 @@ private: friend class PgfReader; public: + // Here we count to how many revisions the client has access. + // When the count is zero we release the database. + int ref_count; + PGF_INTERNAL_DECL PgfDB(const char* filepath, int flags, int mode); PGF_INTERNAL_DECL ~PgfDB(); diff --git a/src/runtime/c/pgf/expr.cxx b/src/runtime/c/pgf/expr.cxx index d67ab1cd2..3bffc4713 100644 --- a/src/runtime/c/pgf/expr.cxx +++ b/src/runtime/c/pgf/expr.cxx @@ -638,8 +638,7 @@ PgfBind *PgfExprParser::parse_bind(PgfBind *next) PgfBind *bind = (PgfBind *) malloc(sizeof(PgfBind)+var->size+1); bind->bind_type = bind_type; bind->next = last; - bind->var.size = var->size; - memcpy(bind->var.text, var->text, var->size+1); + memcpy(&bind->var, var, sizeof(PgfText)+var->size+1); last = bind; token(); @@ -816,7 +815,7 @@ PgfType PgfExprParser::parse_type() PgfText *cat = NULL; size_t n_args = 0; - PgfType *args = NULL; + PgfExpr *args = NULL; for (;;) { if (token_tag == PGF_TOKEN_LPAR) { @@ -908,10 +907,14 @@ PgfType PgfExprParser::parse_type() type = u->dtyp(n_hypos,hypos,cat,n_args,args); exit: + PgfType last_type = 0; while (n_hypos > 0) { PgfTypeHypo *hypo = &hypos[--n_hypos]; - u->free_ref(hypo->type); free(hypo->cid); + if (hypo->type != last_type) { + u->free_ref(hypo->type); + last_type = hypo->type; + } } free(hypos); diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index 14a65b566..a6b228810 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -56,6 +56,7 @@ PgfDB *pgf_read_pgf(const char* fpath, *revision = pgf.as_object(); } + db->ref_count++; return db; } PGF_API_END @@ -97,6 +98,7 @@ PgfDB *pgf_boot_ngf(const char* pgf_path, const char* ngf_path, PgfDB::sync(); } + db->ref_count++; return db; } PGF_API_END @@ -130,6 +132,7 @@ PgfDB *pgf_read_ngf(const char *fpath, *revision = pgf.as_object(); } + db->ref_count++; return db; } PGF_API_END @@ -175,6 +178,7 @@ PgfDB *pgf_new_ngf(PgfText *abstract_name, PgfDB::sync(); } + db->ref_count++; return db; } PGF_API_END @@ -214,12 +218,6 @@ end: fclose(out); } -PGF_API -void pgf_free(PgfDB *db) -{ - delete db; -} - PGF_API_DECL void pgf_free_revision(PgfDB *db, PgfRevision revision) { @@ -240,9 +238,14 @@ void pgf_free_revision(PgfDB *db, PgfRevision revision) 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 @@ -601,6 +604,7 @@ PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision, 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 @@ -635,6 +639,7 @@ PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name, DB_scope scope(db, WRITER_SCOPE); ref pgf = PgfDB::get_revision(name); Node::add_value_ref(pgf); + db->ref_count++; return pgf.as_object(); } PGF_API_END diff --git a/src/runtime/c/pgf/pgf.h b/src/runtime/c/pgf/pgf.h index f9a8dd8b2..b8f866cd6 100644 --- a/src/runtime/c/pgf/pgf.h +++ b/src/runtime/c/pgf/pgf.h @@ -259,10 +259,8 @@ void pgf_write_pgf(const char* fpath, PgfDB *db, PgfRevision revision, PgfExn* err); -/* Release the database when it is no longer needed. */ -PGF_API_DECL -void pgf_free(PgfDB *pgf); - +/* Release a revision. If this is the last revision for the given + * database, then the database is released as well. */ PGF_API_DECL void pgf_free_revision(PgfDB *pgf, PgfRevision revision); diff --git a/src/runtime/haskell/PGF2.hsc b/src/runtime/haskell/PGF2.hsc index 57083d4b8..2af222f92 100644 --- a/src/runtime/haskell/PGF2.hsc +++ b/src/runtime/haskell/PGF2.hsc @@ -112,11 +112,10 @@ readPGF fpath = withCString fpath $ \c_fpath -> alloca $ \p_revision -> mask_ $ do - c_pgf <- withPgfExn "readPGF" (pgf_read_pgf c_fpath p_revision) + c_db <- withPgfExn "readPGF" (pgf_read_pgf c_fpath p_revision) c_revision <- peek p_revision - fptr1 <- newForeignPtr pgf_free_fptr c_pgf - fptr2 <- C.newForeignPtr c_revision (withForeignPtr fptr1 (\c_db -> pgf_free_revision c_db c_revision)) - return (PGF fptr1 fptr2 Map.empty) + fptr <- C.newForeignPtr c_revision (pgf_free_revision c_db c_revision) + return (PGF c_db fptr Map.empty) -- | Reads a PGF file and stores the unpacked data in an NGF file -- ready to be shared with other process, or used for quick startup. @@ -128,11 +127,10 @@ bootNGF pgf_path ngf_path = withCString ngf_path $ \c_ngf_path -> alloca $ \p_revision -> mask_ $ do - c_pgf <- withPgfExn "bootNGF" (pgf_boot_ngf c_pgf_path c_ngf_path p_revision) + c_db <- withPgfExn "bootNGF" (pgf_boot_ngf c_pgf_path c_ngf_path p_revision) c_revision <- peek p_revision - fptr1 <- newForeignPtr pgf_free_fptr c_pgf - fptr2 <- C.newForeignPtr c_revision (withForeignPtr fptr1 (\c_db -> pgf_free_revision c_db c_revision)) - return (PGF fptr1 fptr2 Map.empty) + fptr <- C.newForeignPtr c_revision (pgf_free_revision c_db c_revision) + return (PGF c_db fptr Map.empty) -- | Reads the grammar from an already booted NGF file. -- The function fails if the file does not exist. @@ -143,9 +141,8 @@ readNGF fpath = mask_ $ do c_db <- withPgfExn "readNGF" (pgf_read_ngf c_fpath p_revision) c_revision <- peek p_revision - fptr1 <- newForeignPtr pgf_free_fptr c_db - fptr2 <- C.newForeignPtr c_revision (withForeignPtr fptr1 (\c_db -> pgf_free_revision c_db c_revision)) - return (PGF fptr1 fptr2 Map.empty) + fptr <- C.newForeignPtr c_revision (pgf_free_revision c_db c_revision) + return (PGF c_db fptr Map.empty) -- | Creates a new NGF file with a grammar with the given abstract_name. -- Aside from the name, the grammar is otherwise empty but can be later @@ -159,16 +156,14 @@ newNGF abs_name mb_fpath = mask_ $ do c_db <- withPgfExn "newNGF" (pgf_new_ngf c_abs_name c_fpath p_revision) c_revision <- peek p_revision - fptr1 <- newForeignPtr pgf_free_fptr c_db - fptr2 <- C.newForeignPtr c_revision (withForeignPtr fptr1 (\c_db -> pgf_free_revision c_db c_revision)) - return (PGF fptr1 fptr2 Map.empty) + fptr <- C.newForeignPtr c_revision (pgf_free_revision c_db c_revision) + return (PGF c_db fptr Map.empty) writePGF :: FilePath -> PGF -> IO () writePGF fpath p = withCString fpath $ \c_fpath -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> - withPgfExn "writePGF" (pgf_write_pgf c_fpath c_db c_revision) + withPgfExn "writePGF" (pgf_write_pgf c_fpath (a_db p) c_revision) showPGF :: PGF -> String showPGF = error "TODO: showPGF" @@ -178,9 +173,8 @@ showPGF = error "TODO: showPGF" abstractName :: PGF -> AbsName abstractName p = unsafePerformIO $ - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> - bracket (withPgfExn "abstractName" (pgf_abstract_name c_db c_revision)) free $ \c_text -> + bracket (withPgfExn "abstractName" (pgf_abstract_name (a_db p) c_revision)) free $ \c_text -> peekText c_text -- | The start category is defined in the grammar with @@ -192,9 +186,8 @@ startCat :: PGF -> Type startCat p = unsafePerformIO $ withForeignPtr unmarshaller $ \u -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> do - c_typ <- withPgfExn "startCat" (pgf_start_cat c_db c_revision u) + c_typ <- withPgfExn "startCat" (pgf_start_cat (a_db p) c_revision u) typ <- deRefStablePtr c_typ freeStablePtr c_typ return typ @@ -204,10 +197,9 @@ functionType :: PGF -> Fun -> Maybe Type functionType p fn = unsafePerformIO $ withForeignPtr unmarshaller $ \u -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> withText fn $ \c_fn -> do - c_typ <- withPgfExn "functionType" (pgf_function_type c_db c_revision c_fn u) + c_typ <- withPgfExn "functionType" (pgf_function_type (a_db p) c_revision c_fn u) if c_typ == castPtrToStablePtr nullPtr then return Nothing else do typ <- deRefStablePtr c_typ @@ -218,27 +210,24 @@ functionIsConstructor :: PGF -> Fun -> Bool functionIsConstructor p fun = unsafePerformIO $ withText fun $ \c_fun -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> - do res <- withPgfExn "functionIsConstructor" (pgf_function_is_constructor c_db c_revision c_fun) + do res <- withPgfExn "functionIsConstructor" (pgf_function_is_constructor (a_db p) c_revision c_fun) return (res /= 0) functionProbability :: PGF -> Fun -> Float functionProbability p fun = unsafePerformIO $ withText fun $ \c_fun -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> - withPgfExn "functionProbability" (pgf_function_prob c_db c_revision c_fun) + withPgfExn "functionProbability" (pgf_function_prob (a_db p) c_revision c_fun) exprProbability :: PGF -> Expr -> Float exprProbability p e = unsafePerformIO $ - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> bracket (newStablePtr e) freeStablePtr $ \c_e -> withForeignPtr marshaller $ \m -> - withPgfExn "exprProbability" (pgf_expr_prob c_db c_revision c_e m) + withPgfExn "exprProbability" (pgf_expr_prob (a_db p) c_revision c_e m) checkExpr :: PGF -> Expr -> Type -> Either String Expr checkExpr = error "TODO: checkExpr" @@ -503,10 +492,9 @@ categories p = ref <- newIORef [] (allocaBytes (#size PgfItor) $ \itor -> bracket (wrapItorCallback (getCategories ref)) freeHaskellFunPtr $ \fptr -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> do (#poke PgfItor, fn) itor fptr - withPgfExn "categories" (pgf_iter_categories c_db c_revision itor) + withPgfExn "categories" (pgf_iter_categories (a_db p) c_revision itor) cs <- readIORef ref return (reverse cs)) where @@ -522,10 +510,9 @@ categoryContext p cat = withText cat $ \c_cat -> alloca $ \p_n_hypos -> withForeignPtr unmarshaller $ \u -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> mask_ $ do - c_hypos <- withPgfExn "categoryContext" (pgf_category_context c_db c_revision c_cat p_n_hypos u) + c_hypos <- withPgfExn "categoryContext" (pgf_category_context (a_db p) c_revision c_cat p_n_hypos u) if c_hypos == nullPtr then return Nothing else do n_hypos <- peek p_n_hypos @@ -550,9 +537,8 @@ categoryProbability :: PGF -> Cat -> Float categoryProbability p cat = unsafePerformIO $ withText cat $ \c_cat -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> - withPgfExn "categoryProbability" (pgf_category_prob c_db c_revision c_cat) + withPgfExn "categoryProbability" (pgf_category_prob (a_db p) c_revision c_cat) -- | List of all functions defined in the abstract syntax functions :: PGF -> [Fun] @@ -561,10 +547,9 @@ functions p = ref <- newIORef [] (allocaBytes (#size PgfItor) $ \itor -> bracket (wrapItorCallback (getFunctions ref)) freeHaskellFunPtr $ \fptr -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> do (#poke PgfItor, fn) itor fptr - withPgfExn "functions" (pgf_iter_functions c_db c_revision itor) + withPgfExn "functions" (pgf_iter_functions (a_db p) c_revision itor) fs <- readIORef ref return (reverse fs)) where @@ -582,10 +567,9 @@ functionsByCat p cat = (withText cat $ \c_cat -> allocaBytes (#size PgfItor) $ \itor -> bracket (wrapItorCallback (getFunctions ref)) freeHaskellFunPtr $ \fptr -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> do (#poke PgfItor, fn) itor fptr - withPgfExn "functionsByCat" (pgf_iter_functions_by_cat c_db c_revision c_cat itor) + withPgfExn "functionsByCat" (pgf_iter_functions_by_cat (a_db p) c_revision c_cat itor) fs <- readIORef ref return (reverse fs)) where @@ -599,10 +583,9 @@ globalFlag :: PGF -> String -> Maybe Literal globalFlag p name = unsafePerformIO $ withText name $ \c_name -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> withForeignPtr unmarshaller $ \u -> do - c_lit <- withPgfExn "globalFlag" (pgf_get_global_flag c_db c_revision c_name u) + c_lit <- withPgfExn "globalFlag" (pgf_get_global_flag (a_db p) c_revision c_name u) if c_lit == castPtrToStablePtr nullPtr then return Nothing else do lit <- deRefStablePtr c_lit @@ -613,10 +596,9 @@ abstractFlag :: PGF -> String -> Maybe Literal abstractFlag p name = unsafePerformIO $ withText name $ \c_name -> - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> withForeignPtr unmarshaller $ \u -> do - c_lit <- withPgfExn "abstractFlag" (pgf_get_abstract_flag c_db c_revision c_name u) + c_lit <- withPgfExn "abstractFlag" (pgf_get_abstract_flag (a_db p) c_revision c_name u) if c_lit == castPtrToStablePtr nullPtr then return Nothing else do lit <- deRefStablePtr c_lit diff --git a/src/runtime/haskell/PGF2/FFI.hsc b/src/runtime/haskell/PGF2/FFI.hsc index 3e229597b..76caeec29 100644 --- a/src/runtime/haskell/PGF2/FFI.hsc +++ b/src/runtime/haskell/PGF2/FFI.hsc @@ -23,11 +23,11 @@ type ConcName = String -- ^ Name of concrete syntax -- | An abstract data type representing multilingual grammar -- in Portable Grammar Format. -data PGF = PGF { a_db :: ForeignPtr PgfDB +data PGF = PGF { a_db :: Ptr PgfDB , revision :: ForeignPtr PgfRevision , languages:: Map.Map ConcName Concr } -data Concr = Concr {c_pgf :: ForeignPtr PgfDB, concr :: Ptr PgfConcr} +data Concr = Concr {c_pgf :: Ptr PgfDB, concr :: Ptr PgfConcr} ------------------------------------------------------------------ -- libpgf API @@ -62,9 +62,6 @@ foreign import ccall pgf_new_ngf :: Ptr PgfText -> CString -> Ptr (Ptr PgfRevisi foreign import ccall pgf_write_pgf :: CString -> Ptr PgfDB -> Ptr PgfRevision -> Ptr PgfExn -> IO () -foreign import ccall "&pgf_free" - pgf_free_fptr :: FinalizerPtr PgfDB - foreign import ccall "pgf_free_revision" pgf_free_revision :: Ptr PgfDB -> Ptr PgfRevision -> IO () diff --git a/src/runtime/haskell/PGF2/Transactions.hsc b/src/runtime/haskell/PGF2/Transactions.hsc index 2231e360f..a3f4df371 100644 --- a/src/runtime/haskell/PGF2/Transactions.hsc +++ b/src/runtime/haskell/PGF2/Transactions.hsc @@ -73,41 +73,39 @@ branchPGF p name t = branchPGF_ :: Ptr PgfText -> PGF -> Transaction a -> IO PGF branchPGF_ c_name p (Transaction f) = - withForeignPtr (a_db p) $ \c_db -> withForeignPtr (revision p) $ \c_revision -> withPgfExn "branchPGF" $ \c_exn -> mask $ \restore -> do - c_revision <- pgf_clone_revision c_db c_revision c_name c_exn + c_revision <- pgf_clone_revision (a_db p) c_revision c_name c_exn ex_type <- (#peek PgfExn, type) c_exn if (ex_type :: (#type PgfExnType)) == (#const PGF_EXN_NONE) - then do ((restore (f c_db c_revision c_exn)) + then do ((restore (f (a_db p) c_revision c_exn)) `catch` (\e -> do - pgf_free_revision c_db c_revision + pgf_free_revision (a_db p) c_revision throwIO (e :: SomeException))) ex_type <- (#peek PgfExn, type) c_exn if (ex_type :: (#type PgfExnType)) == (#const PGF_EXN_NONE) - then do pgf_commit_revision c_db c_revision c_exn + then do pgf_commit_revision (a_db p) c_revision c_exn ex_type <- (#peek PgfExn, type) c_exn if (ex_type :: (#type PgfExnType)) == (#const PGF_EXN_NONE) - then do fptr2 <- C.newForeignPtr c_revision (withForeignPtr (a_db p) (\c_db -> pgf_free_revision c_db c_revision)) - return (PGF (a_db p) fptr2 (languages p)) - else do pgf_free_revision c_db c_revision + then do fptr <- C.newForeignPtr c_revision (pgf_free_revision (a_db p) c_revision) + return (PGF (a_db p) fptr (languages p)) + else do pgf_free_revision (a_db p) c_revision return p - else do pgf_free_revision c_db c_revision + else do pgf_free_revision (a_db p) c_revision return p else return p {- | Retrieves the branch with the given name -} checkoutPGF :: PGF -> String -> IO (Maybe PGF) checkoutPGF p name = - withForeignPtr (a_db p) $ \c_db -> withText name $ \c_name -> do - c_revision <- withPgfExn "checkoutPGF" (pgf_checkout_revision c_db c_name) + c_revision <- withPgfExn "checkoutPGF" (pgf_checkout_revision (a_db p) c_name) if c_revision == nullPtr then return Nothing - else do fptr2 <- C.newForeignPtr c_revision (withForeignPtr (a_db p) (\c_db -> pgf_free_revision c_db c_revision)) - return (Just (PGF (a_db p) fptr2 (languages p))) + else do fptr <- C.newForeignPtr c_revision (pgf_free_revision (a_db p) c_revision) + return (Just (PGF (a_db p) fptr (languages p))) createFunction :: Fun -> Type -> Int -> Float -> Transaction () createFunction name ty arity prob = Transaction $ \c_db c_revision c_exn -> diff --git a/src/runtime/python/pypgf.c b/src/runtime/python/pypgf.c index 6f2d7d7cd..dbf15ee7e 100644 --- a/src/runtime/python/pypgf.c +++ b/src/runtime/python/pypgf.c @@ -13,7 +13,7 @@ static void PGF_dealloc(PGFObject *self) { - pgf_free(self->db); + pgf_free_revision(self->db, self->revision); Py_TYPE(self)->tp_free((PyObject *)self); } diff --git a/testsuite/compiler/compute/Variants.gfs b/testsuite/compiler/compute/Variants.gfs index 1f512694c..f65427e88 100644 --- a/testsuite/compiler/compute/Variants.gfs +++ b/testsuite/compiler/compute/Variants.gfs @@ -1,2 +1,12 @@ i -retain testsuite/compiler/compute/Variants.gf cc hello +cc <\x -> x++x : Str -> Str> ("a"|"b") +cc <\x -> x : Str -> Str> ("a"|"b") +cc <\x -> "c" : Str -> Str> ("a"|"b") +cc +cc +cc +cc <\x -> x.p1++x.p1 : Str*Str -> Str> <"a"|"b","c"> +cc <\x -> x.p1 : Str*Str -> Str> <"a"|"b","c"> +cc <\x -> x.p2++x.p2 : Str*Str -> Str> <"a"|"b","c"> +cc <\x -> x.p2 : Str*Str -> Str> <"a"|"b","c"> diff --git a/testsuite/compiler/compute/Variants.gfs.gold b/testsuite/compiler/compute/Variants.gfs.gold index cd74b1c23..50af5e513 100644 --- a/testsuite/compiler/compute/Variants.gfs.gold +++ b/testsuite/compiler/compute/Variants.gfs.gold @@ -1 +1,11 @@ variants {"hello"; "hello" ++ "hello"} +variants {"a" ++ "a"; "b" ++ "b"} +variants {"a"; "b"} +"c" +variants {"a"; "b"} ++ variants {"a"; "b"} +variants {"a"; "b"} +"c" +variants {"a"; "b"} ++ variants {"a"; "b"} +variants {"a"; "b"} +"c" ++ "c" +"c"