diff --git a/etc/tst-local-vars.py b/etc/tst-local-vars.py index 792474f7a..915c453b7 100755 --- a/etc/tst-local-vars.py +++ b/etc/tst-local-vars.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """ -TODO +This simple script adds the local variables used in a GAP tst file to the top +of the file. """ import os import re @@ -24,10 +25,7 @@ def main(): lvars.extend([x.group(1) for x in re.finditer(pattern1, lines)]) lvars.extend([x.group(1) for x in re.finditer(pattern2, lines)]) lvars = ", ".join(sorted([*{*lvars}])) - lvars = [ - x if x[-1] != "," else x[:-1] - for x in textwrap.wrap(lvars, width=72) - ] + lvars = [x if x[-1] != "," else x[:-1] for x in textwrap.wrap(lvars, width=72)] lvars = [""] + ["#@local " + x for x in lvars] lines = lines.split("\n") pos = next(i for i in range(len(lines)) if "START_TEST" in lines[i]) diff --git a/etc/tst-unbind-local-vars.py b/etc/tst-unbind-local-vars.py new file mode 100755 index 000000000..0ce912013 --- /dev/null +++ b/etc/tst-unbind-local-vars.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +""" +This simple script adds the "Unbind" statements to the end of a GAP tst file. +""" +import os +import re +import sys +import textwrap + +import yaml +from bs4 import BeautifulSoup + + +def main(): + if sys.version_info[0] < 3: + raise Exception("Python 3 is required") + args = sys.argv[1:] + pattern1 = re.compile(r"(\w+)\s*:=") + pattern2 = re.compile(r"for (\w+) in") + for fname in args: + lvars = [] + with open(fname, "r") as f: + lines = f.read() + lvars.extend([x.group(1) for x in re.finditer(pattern1, lines)]) + lvars.extend([x.group(1) for x in re.finditer(pattern2, lines)]) + lvars = sorted([*{*lvars}]) + lvars = [ + "# Unbind local variables, auto-generated by etc/tst-unbind-local-vars.py" + ] + [f"gap> Unbind({lvar});" for lvar in lvars] + lvars.append("") + lines = lines.split("\n") + pos1 = next(i for i in range(len(lines)) if "STOP_TEST" in lines[i]) - 1 + try: + pos0 = next( + i + for i in range(len(lines)) + if "etc/tst-unbind-local-vars.py" in lines[i] + ) + except StopIteration: + pos0 = pos1 + lines = lines[:pos0] + lvars + lines[pos1:] + lines = "\n".join(lines) + with open(fname, "w") as f: + print(f"Writing local variables to {fname}...") + f.write(lines) + + +if __name__ == "__main__": + main() diff --git a/gapbind14/include/gapbind14/gapbind14.hpp b/gapbind14/include/gapbind14/gapbind14.hpp index 79ab19e5d..86200ea3c 100644 --- a/gapbind14/include/gapbind14/gapbind14.hpp +++ b/gapbind14/include/gapbind14/gapbind14.hpp @@ -187,6 +187,9 @@ namespace gapbind14 { : SubtypeBase(nm, sbtyp) {} void free(Obj o) override { + static_assert(IsGapBind14Type::value, + "template parameter T must satisfy IsGapbind14Type"); + GAPBIND14_ASSERT(obj_subtype(o) == module().subtype()); delete detail::obj_cpp_ptr(o); } }; @@ -214,12 +217,12 @@ namespace gapbind14 { _subtypes(), _type_to_subtype() {} - Module(Module const&) = delete; - Module(Module&&) = delete; + Module(Module const&) = delete; + Module(Module&&) = delete; Module& operator=(Module const&) = delete; - Module& operator=(Module&&) = delete; + Module& operator=(Module&&) = delete; - ~Module() = default; + ~Module(); void clear(); diff --git a/gapbind14/include/gapbind14/to_cpp.hpp b/gapbind14/include/gapbind14/to_cpp.hpp index 79e6aa21c..3ce81e820 100644 --- a/gapbind14/include/gapbind14/to_cpp.hpp +++ b/gapbind14/include/gapbind14/to_cpp.hpp @@ -87,7 +87,8 @@ namespace gapbind14 { std::string operator()(Obj o) const { if (TNUM_OBJ(o) != T_STRING) { - ErrorQuit("expected string, found %s", (Int) TNAM_OBJ(o), 0L); + throw std::runtime_error(std::string("expected string, found ") + + TNAM_OBJ(o)); } return std::string(CSTR_STRING(o), GET_LEN_STRING(o)); } @@ -106,7 +107,8 @@ namespace gapbind14 { Int operator()(Obj o) const { if (TNUM_OBJ(o) != T_INT) { - ErrorQuit("expected int, found %s", (Int) TNAM_OBJ(o), 0L); + throw std::runtime_error(std::string("expected int, found ") + + TNAM_OBJ(o)); } return INT_INTOBJ(o); } @@ -123,7 +125,8 @@ namespace gapbind14 { bool operator()(Obj o) const { if (TNUM_OBJ(o) != T_BOOL) { - ErrorQuit("expected bool, found %s", (Int) TNAM_OBJ(o), 0L); + throw std::runtime_error(std::string("expected bool, found ") + + TNAM_OBJ(o)); } return o == True ? true : false; } @@ -140,7 +143,8 @@ namespace gapbind14 { std::vector operator()(Obj o) const { if (!IS_LIST(o)) { - ErrorQuit("expected list, found %s", (Int) TNAM_OBJ(o), 0L); + throw std::runtime_error(std::string("expected list, found ") + + TNAM_OBJ(o)); } size_t const N = LEN_LIST(o); diff --git a/gapbind14/src/gapbind14.cpp b/gapbind14/src/gapbind14.cpp index a04f092ee..c7b12a966 100644 --- a/gapbind14/src/gapbind14.cpp +++ b/gapbind14/src/gapbind14.cpp @@ -18,9 +18,9 @@ #include "gapbind14/gapbind14.hpp" -#include // for fprintf, stderr -#include // for memcpy, strchr, strrchr - // +#include // for fprintf, stderr +#include // for memcpy, strchr, strrchr + #include // for unordered_set, unordered_set<>::iterator #include "gapbind14/gap_include.hpp" // for Obj etc @@ -93,10 +93,32 @@ namespace gapbind14 { // Module implementations + Module::~Module() { + clear(); + for (auto *subtype : _subtypes) { + delete subtype; + } + } + void Module::clear() { + for (auto &func : _funcs) { + delete func.name; + if (func.nargs != 0) { + delete func.args; + } + delete func.cookie; + } _funcs.clear(); - for (auto &funcs : _mem_funcs) { - funcs.clear(); + + for (auto &vec : _mem_funcs) { + for (auto &func : vec) { + delete func.name; + if (func.nargs != 0) { + delete func.args; + } + delete func.cookie; + } + vec.clear(); } } @@ -266,7 +288,7 @@ namespace gapbind14 { first_call = false; InitGVarFuncsFromTable(GVarFuncs); } - auto & m = module(); + auto &m = module(); StructGVarFunc const *tab = m.funcs(); // init functions from m in the record named name diff --git a/tst/standard/attributes/homomorph.tst b/tst/standard/attributes/homomorph.tst index 2c33e70c3..9ca14fd3f 100644 --- a/tst/standard/attributes/homomorph.tst +++ b/tst/standard/attributes/homomorph.tst @@ -8,6 +8,11 @@ ## ############################################################################# ## + +## We don't use local variables in this test file because it doesn't play nice +## with something in this test file. + +# gap> START_TEST("Semigroups package: standard/attributes/homomorph.tst"); gap> LoadPackage("semigroups", false);; @@ -1079,6 +1084,51 @@ gap> hom2 := SemigroupHomomorphismByImages(S, S, GeneratorsOfSemigroup(S), gap> hom1 = hom2; false +# Unbind local variables, auto-generated by etc/tst-unbind-local-vars.py +gap> Unbind(BruteForceHomoCheck); +gap> Unbind(BruteForceInverseCheck); +gap> Unbind(BruteForceIsoCheck); +gap> Unbind(F); +gap> Unbind(J); +gap> Unbind(K); +gap> Unbind(S); +gap> Unbind(T); +gap> Unbind(U); +gap> Unbind(V); +gap> Unbind(acting); +gap> Unbind(cong); +gap> Unbind(congs); +gap> Unbind(g); +gap> Unbind(gens); +gap> Unbind(gens1); +gap> Unbind(gens2); +gap> Unbind(gens3); +gap> Unbind(gensS); +gap> Unbind(gensT); +gap> Unbind(gensU); +gap> Unbind(gensV); +gap> Unbind(h); +gap> Unbind(hom); +gap> Unbind(hom1); +gap> Unbind(hom1bf); +gap> Unbind(hom1bfbi); +gap> Unbind(hom2); +gap> Unbind(hom3); +gap> Unbind(images); +gap> Unbind(images1); +gap> Unbind(images2); +gap> Unbind(images3); +gap> Unbind(imgs); +gap> Unbind(imgs2); +gap> Unbind(inv); +gap> Unbind(iso); +gap> Unbind(j); +gap> Unbind(map); +gap> Unbind(relations); +gap> Unbind(x); +gap> Unbind(y); +gap> Unbind(z); + # gap> SEMIGROUPS.StopTest(); gap> STOP_TEST("Semigroups package: standard/attributes/homomorph.tst"); diff --git a/tst/standard/semigroups/semifp.tst b/tst/standard/semigroups/semifp.tst index e0f155462..665af9739 100644 --- a/tst/standard/semigroups/semifp.tst +++ b/tst/standard/semigroups/semifp.tst @@ -7,6 +7,10 @@ ## ############################################################################# ## + +## We don't use local variables in this test file because it doesn't play nice +## with AssignGeneratorVariables, which is used repeatedly here. + gap> START_TEST("Semigroups package: standard/semigroups/semifp.tst"); gap> LoadPackage("semigroups", false);; @@ -2666,23 +2670,33 @@ true gap> IsSubsemigroupOfFpMonoid(Range(map)); true -# SEMIGROUPS_UnbindVariables -gap> Unbind(a); -gap> Unbind(b); +# Unbind local variables, auto-generated by etc/tst-unbind-local-vars.py gap> Unbind(BruteForceInverseCheck); gap> Unbind(BruteForceIsoCheck); -gap> Unbind(f); gap> Unbind(F); gap> Unbind(G); +gap> Unbind(LoopIterator); +gap> Unbind(Noop); gap> Unbind(R); gap> Unbind(S); gap> Unbind(T); +gap> Unbind(TestEnumerator); +gap> Unbind(TestIterator); +gap> Unbind(a); +gap> Unbind(b); +gap> Unbind(f); +gap> Unbind(factorizable); gap> Unbind(inv); +gap> Unbind(iso); +gap> Unbind(len); gap> Unbind(map); gap> Unbind(rels); +gap> Unbind(s); +gap> Unbind(tst); +gap> Unbind(valid); +gap> Unbind(w); gap> Unbind(x); gap> Unbind(y); # -gap> SEMIGROUPS.StopTest(); gap> STOP_TEST("Semigroups package: standard/semigroups/semifp.tst"); diff --git a/tst/standard/tools/display.tst b/tst/standard/tools/display.tst index ab7c4daf8..9c252d0e6 100644 --- a/tst/standard/tools/display.tst +++ b/tst/standard/tools/display.tst @@ -7,6 +7,11 @@ ## ############################################################################# ## + +## We don't use local variables in this test file because it doesn't play nice +## with something in this test file. + +# gap> START_TEST("Semigroups package: standard/tools/display.tst"); gap> LoadPackage("semigroups", false);; @@ -1025,7 +1030,8 @@ gap> TikzRightCayleyDigraph(S); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 2nd choice method found for `TikzString' on 1 arguments -# SEMIGROUPS_UnbindVariables +# Unbind local variables, auto-generated by etc/tst-unbind-local-vars.py +gap> Unbind(S); gap> Unbind(x); gap> Unbind(y);