From 2b21dd45c380a3459a2dc5f7f8c5b65b134fcf7c Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 08:19:27 +1300 Subject: [PATCH 1/9] Add generator test to produce generated code using interfaceCode API and GeneratorProfile::Profile enumeration. --- tests/generator/generator.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/generator/generator.cpp b/tests/generator/generator.cpp index 00282fe33..411080c52 100644 --- a/tests/generator/generator.cpp +++ b/tests/generator/generator.cpp @@ -1732,3 +1732,25 @@ TEST(Generator, modelWithComplexUnitsOutOfScope) EXPECT_EQ_FILE_CONTENTS("generator/cellml_slc_example/model.py", generator->implementationCode(analyserModel, profile)); } + +TEST(Generator, generateCodeUsingProfileEnum) +{ + auto parser = libcellml::Parser::create(); + auto model = parser->parseModel(fileContents("generator/algebraic_eqn_computed_var_on_rhs/model.cellml")); + + EXPECT_EQ(size_t(0), parser->issueCount()); + + auto analyser = libcellml::Analyser::create(); + + analyser->analyseModel(model); + + EXPECT_EQ(size_t(0), analyser->errorCount()); + + auto analyserModel = analyser->analyserModel(); + auto generator = libcellml::Generator::create(); + + EXPECT_EQ_FILE_CONTENTS("generator/algebraic_eqn_computed_var_on_rhs/model.h", generator->interfaceCode(analyserModel, libcellml::GeneratorProfile::Profile::C)); + EXPECT_EQ_FILE_CONTENTS("generator/algebraic_eqn_computed_var_on_rhs/model.c", generator->implementationCode(analyserModel, libcellml::GeneratorProfile::Profile::C)); + + EXPECT_EQ_FILE_CONTENTS("generator/algebraic_eqn_computed_var_on_rhs/model.py", generator->implementationCode(analyserModel, libcellml::GeneratorProfile::Profile::PYTHON)); +} From d141d18e26fbb107fcf977224a5c19f7d8ab6015 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 08:45:04 +1300 Subject: [PATCH 2/9] Add implementation of generating code using profile enumeration in the C++ library. --- src/api/libcellml/generator.h | 28 +++++++++++++++++++++++++++- src/bindings/interface/generator.i | 1 + src/generator.cpp | 10 ++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/api/libcellml/generator.h b/src/api/libcellml/generator.h index d9fb7debb..d5e93c9ce 100644 --- a/src/api/libcellml/generator.h +++ b/src/api/libcellml/generator.h @@ -16,7 +16,7 @@ limitations under the License. #pragma once -#include "libcellml/generatorvariabletracker.h" +#include "libcellml/generatorprofile.h" #include "libcellml/logger.h" namespace libcellml { @@ -74,6 +74,19 @@ class LIBCELLML_EXPORT Generator: public Logger std::string interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile); + /** + * @brief Get the interface code for the @ref AnalyserModel. + * + * Return the interface code for the @ref AnalyserModel, using the @ref GeneratorProfile. + * + * @param analyserModel The @ref AnalyserModel for which we want to generate some interface code. + * @param generatorProfile The @ref GeneratorProfile to use to generate the interface code. + * + * @return The interface code as a @c std::string. + */ + + std::string interfaceCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile); + /** * @brief Get the interface code for the @ref AnalyserModel. * @@ -125,6 +138,19 @@ class LIBCELLML_EXPORT Generator: public Logger std::string implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile); + /** + * @brief Get the implementation code for the @ref AnalyserModel. + * + * Return the implementation code for the @ref AnalyserModel, using the @ref GeneratorProfile::Profile. + * + * @param analyserModel The @ref AnalyserModel for which we want to generate some implementation code. + * @param profile The @ref GeneratorProfile::Profile type to use to generate the implementation code. + * + * @return The implementation code as a @c std::string. + */ + + std::string implementationCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile); + /** * @brief Get the implementation code for the @ref AnalyserModel. * diff --git a/src/bindings/interface/generator.i b/src/bindings/interface/generator.i index 68cc1624b..851b8b2a6 100644 --- a/src/bindings/interface/generator.i +++ b/src/bindings/interface/generator.i @@ -45,6 +45,7 @@ %{ #include "libcellml/generator.h" +#include "libcellml/generatorvariabletracker.h" %} %pythoncode %{ diff --git a/src/generator.cpp b/src/generator.cpp index 8b184649e..3cdd5f701 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -2293,6 +2293,11 @@ std::string Generator::interfaceCode(const AnalyserModelPtr &analyserModel, cons return interfaceCode(analyserModel, generatorProfile, nullptr); } +std::string Generator::interfaceCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile) +{ + return interfaceCode(analyserModel, GeneratorProfile::create(profile), nullptr); +} + std::string Generator::interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorVariableTrackerPtr &generatorVariableTracker) { @@ -2420,6 +2425,11 @@ std::string Generator::implementationCode(const AnalyserModelPtr &analyserModel, return implementationCode(analyserModel, generatorProfile, nullptr); } +std::string Generator::implementationCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile) +{ + return implementationCode(analyserModel, GeneratorProfile::create(profile), nullptr); +} + std::string Generator::implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorVariableTrackerPtr &generatorVariableTracker) { return implementationCode(analyserModel, pFunc()->mDefaultProfile, generatorVariableTracker); From ed11b735feba174b89b0410ef27c8b44a736a950 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 08:48:07 +1300 Subject: [PATCH 3/9] Add Python documentation for new API in generator class. --- src/bindings/interface/generator.i | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bindings/interface/generator.i b/src/bindings/interface/generator.i index 851b8b2a6..17916c03a 100644 --- a/src/bindings/interface/generator.i +++ b/src/bindings/interface/generator.i @@ -19,6 +19,9 @@ %feature("docstring") libcellml::Generator::interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile) "Returns the interface code for the analyser model using the generator profile."; +%feature("docstring") libcellml::Generator::interfaceCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile) +"Returns the interface code for the analyser model using the generator profile enumeration type."; + %feature("docstring") libcellml::Generator::interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorVariableTrackerPtr &generatorVariableTracker) "Returns the interface code for the analyser model using the generator variable tracker."; @@ -31,6 +34,9 @@ %feature("docstring") libcellml::Generator::implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile) "Returns the implementation code for the analyser model using the generator profile."; +%feature("docstring") libcellml::Generator::implementationCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile) +"Returns the implementation code for the analyser model using the generator profile enumeration type."; + %feature("docstring") libcellml::Generator::implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorVariableTrackerPtr &generatorVariableTracker) "Returns the implementation code for the analyser model using the generator variable tracker."; From 985d9627d5e9e115acf65aaf7e8e99cbe2a7a2bd Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 08:48:37 +1300 Subject: [PATCH 4/9] Add Doxygen @overload directive to overloaded methods in generator.h. --- src/api/libcellml/generator.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/api/libcellml/generator.h b/src/api/libcellml/generator.h index d5e93c9ce..7e9b7915d 100644 --- a/src/api/libcellml/generator.h +++ b/src/api/libcellml/generator.h @@ -62,6 +62,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile, const GeneratorVariableTrackerPtr &generatorVariableTracker); /** + * @overload + * * @brief Get the interface code for the @ref AnalyserModel. * * Return the interface code for the @ref AnalyserModel, using the @ref GeneratorProfile. @@ -75,6 +77,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile); /** + * @overload + * * @brief Get the interface code for the @ref AnalyserModel. * * Return the interface code for the @ref AnalyserModel, using the @ref GeneratorProfile. @@ -88,6 +92,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string interfaceCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile); /** + * @overload + * * @brief Get the interface code for the @ref AnalyserModel. * * Return the interface code for the @ref AnalyserModel, using the @ref GeneratorVariableTracker. @@ -101,6 +107,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string interfaceCode(const AnalyserModelPtr &analyserModel, const GeneratorVariableTrackerPtr &generatorVariableTracker); /** + * @overload + * * @brief Get the interface code for the @ref AnalyserModel. * * Return the interface code for the @ref AnalyserModel, using the @ref GeneratorProfile. @@ -126,6 +134,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile, const GeneratorVariableTrackerPtr &generatorVariableTracker); /** + * @overload + * * @brief Get the implementation code for the @ref AnalyserModel. * * Return the implementation code for the @ref AnalyserModel, using the @ref GeneratorProfile. @@ -139,6 +149,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorProfilePtr &generatorProfile); /** + * @overload + * * @brief Get the implementation code for the @ref AnalyserModel. * * Return the implementation code for the @ref AnalyserModel, using the @ref GeneratorProfile::Profile. @@ -152,6 +164,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string implementationCode(const AnalyserModelPtr &analyserModel, GeneratorProfile::Profile profile); /** + * @overload + * * @brief Get the implementation code for the @ref AnalyserModel. * * Return the implementation code for the @ref AnalyserModel, using the @ref GeneratorVariableTracker. @@ -165,6 +179,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string implementationCode(const AnalyserModelPtr &analyserModel, const GeneratorVariableTrackerPtr &generatorVariableTracker); /** + * @overload + * * @brief Get the implementation code for the @ref AnalyserModel. * * Return the implementation code for the @ref AnalyserModel, using the @ref GeneratorProfile. @@ -176,6 +192,8 @@ class LIBCELLML_EXPORT Generator: public Logger std::string implementationCode(const AnalyserModelPtr &analyserModel); /** + * @overload + * * @brief Get the equation code for the given @ref AnalyserEquationAst. * * Return the equation code for the given @ref AnalyserEquationAst using @ref GeneratorProfile. @@ -190,6 +208,8 @@ class LIBCELLML_EXPORT Generator: public Logger const GeneratorProfilePtr &generatorProfile); /** + * @overload + * * @brief Get the equation code for the given @ref AnalyserEquationAst using a default @ref GeneratorProfile. * * Return the equation code for the given @ref AnalyserEquationAst using a default @ref GeneratorProfile. From 6d98e69001b90635da6ca91e04a0c59c01f1a3eb Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 09:01:55 +1300 Subject: [PATCH 5/9] Add javascript tests for new generator API. --- tests/bindings/javascript/generator.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/bindings/javascript/generator.test.js b/tests/bindings/javascript/generator.test.js index ee61d1d37..ffe10b34f 100644 --- a/tests/bindings/javascript/generator.test.js +++ b/tests/bindings/javascript/generator.test.js @@ -51,6 +51,9 @@ describe("Generator tests", () => { const interface_lines_profile = g.interfaceCodeByProfile(am, gp).split('\n') expect(interface_lines_profile.length).toBe(38) + const interface_lines_profile = g.interfaceCodeByProfileEnumeration(am, libcellml.GeneratorProfile.Profile.C).split('\n') + expect(interface_lines_profile.length).toBe(38) + const gvt = new libcellml.GeneratorVariableTracker() const interface_lines_variable_tracker = g.interfaceCodeByVariableTracker(am, gvt).split('\n') @@ -65,6 +68,9 @@ describe("Generator tests", () => { const implementation_lines_profile = g.implementationCodeByProfile(am, gp).split('\n') expect(implementation_lines_profile.length).toBe(97) + const implementation_lines_profile = g.implementationCodeByProfileEnumeration(am, libcellml.GeneratorProfile.Profile.C).split('\n') + expect(implementation_lines_profile.length).toBe(97) + const implementation_lines_variable_tracker = g.implementationCodeByVariableTracker(am, gvt).split('\n') expect(implementation_lines_variable_tracker.length).toBe(97) From c5e7d32354be19764a43bd04c7476d6f1fe7b906 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 09:02:27 +1300 Subject: [PATCH 6/9] Add python tests for new generator API. --- tests/bindings/python/test_generator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/bindings/python/test_generator.py b/tests/bindings/python/test_generator.py index 65435a9fd..e0aca348d 100644 --- a/tests/bindings/python/test_generator.py +++ b/tests/bindings/python/test_generator.py @@ -41,6 +41,9 @@ def test_algebraic_eqn_computed_var_on_rhs(self): self.assertEqual("", g.interfaceCode(am, profile)) self.assertEqual(file_contents("generator/algebraic_eqn_computed_var_on_rhs/model.py"), g.implementationCode(am, profile)) + self.assertEqual("", g.interfaceCode(am, GeneratorProfile.Profile.PYTHON)) + self.assertEqual(file_contents("generator/algebraic_eqn_computed_var_on_rhs/model.py"), g.implementationCode(am, GeneratorProfile.Profile.PYTHON)) + variable_tracker = GeneratorVariableTracker() self.assertEqual("", g.interfaceCode(am, profile, variable_tracker)) From 0488a28cbe7e564568ac52a85d785591b9a6e767 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 09:03:40 +1300 Subject: [PATCH 7/9] Add javascript function bindings for generator implementationCode and interfaceCode methods. --- src/bindings/javascript/generator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bindings/javascript/generator.cpp b/src/bindings/javascript/generator.cpp index 678e0bb83..e23838a46 100644 --- a/src/bindings/javascript/generator.cpp +++ b/src/bindings/javascript/generator.cpp @@ -29,10 +29,12 @@ EMSCRIPTEN_BINDINGS(libcellml_generator) .smart_ptr_constructor("Generator", &libcellml::Generator::create) .function("interfaceCode", select_overload(&libcellml::Generator::interfaceCode)) .function("interfaceCodeByProfile", select_overload(&libcellml::Generator::interfaceCode)) + .function("interfaceCodeByProfileEnumeration", select_overload(&libcellml::Generator::interfaceCode)) .function("interfaceCodeByVariableTracker", select_overload(&libcellml::Generator::interfaceCode)) .function("interfaceCodeByProfileAndVariableTracker", select_overload(&libcellml::Generator::interfaceCode)) .function("implementationCode", select_overload(&libcellml::Generator::implementationCode)) .function("implementationCodeByProfile", select_overload(&libcellml::Generator::implementationCode)) + .function("implementationCodeByProfileEnumeration", select_overload(&libcellml::Generator::implementationCode)) .function("implementationCodeByVariableTracker", select_overload(&libcellml::Generator::implementationCode)) .function("implementationCodeByProfileAndVariableTracker", select_overload(&libcellml::Generator::implementationCode)) .class_function("equationCode", select_overload(&libcellml::Generator::equationCode)) From feb4d0f7130ce7bcaf9e222e3fa5c191a5d35274 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 09:19:36 +1300 Subject: [PATCH 8/9] Change name of already in use variable name in generator.test.js. --- tests/bindings/javascript/generator.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bindings/javascript/generator.test.js b/tests/bindings/javascript/generator.test.js index ffe10b34f..c44411df0 100644 --- a/tests/bindings/javascript/generator.test.js +++ b/tests/bindings/javascript/generator.test.js @@ -51,8 +51,8 @@ describe("Generator tests", () => { const interface_lines_profile = g.interfaceCodeByProfile(am, gp).split('\n') expect(interface_lines_profile.length).toBe(38) - const interface_lines_profile = g.interfaceCodeByProfileEnumeration(am, libcellml.GeneratorProfile.Profile.C).split('\n') - expect(interface_lines_profile.length).toBe(38) + const interface_lines_profile_enumeration = g.interfaceCodeByProfileEnumeration(am, libcellml.GeneratorProfile.Profile.C).split('\n') + expect(interface_lines_profile_enumeration.length).toBe(38) const gvt = new libcellml.GeneratorVariableTracker() From 46ba3ea0e5af24fb77fade4b12cc60cef4467e43 Mon Sep 17 00:00:00 2001 From: Hugh Sorby Date: Wed, 26 Nov 2025 09:21:35 +1300 Subject: [PATCH 9/9] Change name of already in use variable name in generator.test.js. --- tests/bindings/javascript/generator.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bindings/javascript/generator.test.js b/tests/bindings/javascript/generator.test.js index c44411df0..2c328e6ff 100644 --- a/tests/bindings/javascript/generator.test.js +++ b/tests/bindings/javascript/generator.test.js @@ -68,8 +68,8 @@ describe("Generator tests", () => { const implementation_lines_profile = g.implementationCodeByProfile(am, gp).split('\n') expect(implementation_lines_profile.length).toBe(97) - const implementation_lines_profile = g.implementationCodeByProfileEnumeration(am, libcellml.GeneratorProfile.Profile.C).split('\n') - expect(implementation_lines_profile.length).toBe(97) + const implementation_lines_profile_enumeration = g.implementationCodeByProfileEnumeration(am, libcellml.GeneratorProfile.Profile.C).split('\n') + expect(implementation_lines_profile_enumeration.length).toBe(97) const implementation_lines_variable_tracker = g.implementationCodeByVariableTracker(am, gvt).split('\n') expect(implementation_lines_variable_tracker.length).toBe(97)