From 629e6608fd1c56595f5505a680faaaa326ae5ea0 Mon Sep 17 00:00:00 2001 From: Branden Butler Date: Wed, 9 Aug 2023 15:30:53 -0500 Subject: [PATCH 1/3] Add autogenerated docs to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 7cc35391..ede4cce7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ cmake-build-debug # VSCode settings .vscode + +# Autogenerated documentation +/docs/source/developer/cmakepp_lang/ From 7fb96cb67070fe529885ba3f19046185291af1ef Mon Sep 17 00:00:00 2001 From: Branden Butler Date: Wed, 9 Aug 2023 15:32:16 -0500 Subject: [PATCH 2/3] Add documentation for extension functions and attr --- docs/source/features/classes.rst | 41 +++++++++++++++++++ .../classes/define_extension_function.cmake | 26 ++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/docs/source/features/classes/define_extension_function.cmake diff --git a/docs/source/features/classes.rst b/docs/source/features/classes.rst index 195d54d7..175b0aca 100644 --- a/docs/source/features/classes.rst +++ b/docs/source/features/classes.rst @@ -455,3 +455,44 @@ or using ``ParentClass`` with a ``ChildClass`` instance: If a call is made to the ``my_virtual_fxn`` function for an instance of ``ParentClass``, CMakePP will throw an error indicating that this function is virtual and must be overridden in a derived class. + + +Extension Functions and Attributes +================================== +CMakePP classes support defining member functions and attributes +outside of the ``cpp_class``/``cpp_end_class`` fences. Such +definitions are called "extension functions" or "extension attributes." +Other languages such as Kotlin and C# have similar extension features. + +What makes extension functions and attributes special is that +they can be defined by downstream users and have zero behavioral +differences from the predefined methods and attributes. Adding +an extension function or attribute changes the shape of the class +itself, and all existing instances of the class automatically +gain access to the extension. For extension attributes, +any existing instances have the default value for the attribute. + +Constructors are also eligible for extension, and all extension constructors +and methods can overload existing methods or constructors. +Overload selection is done at time of method invocation, so +adding an extension can change which overload is selected +in the future. + +Defining an Extension +--------------------- +Defining an extension method, constructor, or attribute +is done exactly the same as defining a normal +method, constructor, or attribute, with one minor difference: +there is no surrounding :code:`cpp_class`/:code:`cpp_end_class` fence. +The extension definition *must* be in a scope where the class +being extended is visible and defined, so one cannot +make an extension to a class before the class itself has been +defined. This does not mean the extension definition has +to be in the same file; so long as the class is visible extensions +can be defined. + +Example +------- +.. literalinclude:: /../../tests/docs/source/features/classes/define_extension_function.cmake + :lines: 6-24 + :dedent: 4 diff --git a/tests/docs/source/features/classes/define_extension_function.cmake b/tests/docs/source/features/classes/define_extension_function.cmake new file mode 100644 index 00000000..597a8fc4 --- /dev/null +++ b/tests/docs/source/features/classes/define_extension_function.cmake @@ -0,0 +1,26 @@ +include(cmake_test/cmake_test) + +ct_add_test(NAME "define_extension_function") +function("${define_extension_function}") + + cpp_class(MyClass) + + # Class with no members + + cpp_end_class() + + # Adding an extension function + cpp_member(my_fxn MyClass type_a type_b) + function("${my_fxn}" self param_a param_b) + + # The body of the function + + # ${self} can be used to access the instance of MyClass + # the function is being called with + + # ${param_a} and ${param_b} can be used to access the + # values of the parameters passed into the function + + endfunction() + +endfunction() \ No newline at end of file From d3d3e682573587f83f438e606254b15d48b373ef Mon Sep 17 00:00:00 2001 From: Branden Butler Date: Wed, 9 Aug 2023 15:32:37 -0500 Subject: [PATCH 3/3] Add tests for extension functions and constructors --- tests/class/class.cmake | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/class/class.cmake b/tests/class/class.cmake index 393c7a4b..896ac69c 100644 --- a/tests/class/class.cmake +++ b/tests/class/class.cmake @@ -319,6 +319,17 @@ function(${_test_attr}) ct_assert_equal(res 3) endfunction() + ct_add_section(NAME "_attr_set_single_val_extension") + function(${_attr_set_single_val_extension}) + _attr_set_setup() + cpp_attr(MyClass c 4) + # Set attribute as single value + MyClass(SET "${my_instance}" c 3) + # Get the value and ensure it was set correctly + MyClass(GET "${my_instance}" res c) + ct_assert_equal(res 3) + endfunction() + ct_add_section(NAME "_attr_set_list") function(${_attr_set_list}) _attr_set_setup() @@ -330,6 +341,18 @@ function(${_test_attr}) ct_assert_equal(res "1;2;3") endfunction() + ct_add_section(NAME "_attr_set_list_extension") + function(${_attr_set_list_extension}) + _attr_set_setup() + cpp_attr(MyClass c "4;5") + + # Set attribute as a list of values + MyClass(SET "${my_instance}" c 1 2 3) + # Get the value and ensure it was set correctly + MyClass(GET "${my_instance}" res c) + ct_assert_equal(res "1;2;3") + endfunction() + endfunction() endfunction() @@ -423,6 +446,23 @@ function(${_test_constructor}) ct_assert_equal(res 3) endfunction() + ct_add_section(NAME "_multi_construct_third_extension_two_int_params") + function(${_multi_construct_third_extension_two_int_params}) + _constructor_multiple_customs_setup() + + cpp_constructor(CTOR MyClass int int) + function("${CTOR}" self a b) + # Change value of my_attr + math(EXPR new_val "${a} + ${b}") + MyClass(SET "${self}" my_attr "${new_val}") + endfunction() + + # Create instance and test that the 1st CTOR was called + MyClass(CTOR my_instance 3 7) + MyClass(GET "${my_instance}" res my_attr) + ct_assert_equal(res 10) + endfunction() + endfunction() ct_add_section(NAME "_construct_kwargs")