├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── History.txt ├── LICENSE ├── README.md ├── dist.info ├── doc └── index.html ├── dox └── usage.h ├── dub-2.2.5-1.rockspec ├── dub.lua ├── dub ├── CTemplate.lua ├── Class.lua ├── Function.lua ├── Inspector.lua ├── LuaBinder.lua ├── MemoryStorage.lua ├── Namespace.lua ├── OptParser.lua ├── assets │ ├── Doxyfile │ └── lua │ │ ├── class.cpp │ │ ├── dub │ │ ├── dub.cpp │ │ └── dub.h │ │ └── lib.cpp └── init.lua ├── scripts ├── build.lua └── doc.lua └── test ├── all.lua ├── class_test.lua ├── dub_test.lua ├── fixtures ├── constants │ ├── Car.h │ └── types.h ├── inherit │ ├── Child.h │ ├── ChildHelper.h │ ├── ChildHelper.yml │ ├── GrandParent.h │ ├── Object.h │ ├── Orphan.h │ ├── Parent.h │ └── child.cpp ├── inherit_hidden │ └── Mother.h ├── memory │ ├── CustomDtor.h │ ├── NoDtor.h │ ├── Nogc.h │ ├── Owner.h │ ├── Pen.h │ ├── PrivateDtor.h │ ├── Union.h │ ├── Withgc.h │ └── owner.cpp ├── namespace │ ├── A.h │ ├── A.yml │ ├── B.h │ ├── Nem.yml │ ├── Out.h │ ├── TRect.h │ ├── _global.yml │ ├── constants.h │ └── nem.h ├── path.wi$th-[pat] │ └── Pat.h ├── pointers │ ├── Abstract.h │ ├── Box.h │ ├── Custom.h │ ├── Vect.h │ └── vect.cpp ├── simple │ ├── Doxyfile │ └── include │ │ ├── Map2.H │ │ ├── Reg.h │ │ ├── simple.h │ │ └── types.h ├── template │ ├── Foo.h │ ├── TRect.h │ ├── TVect.h │ └── types.h └── thread │ ├── Callback.h │ ├── Caller.h │ └── lua_callback.cpp ├── function_test.lua ├── inspect_box2d_test.lua ├── inspect_constants_test.lua ├── inspect_inherit_test.lua ├── inspect_memory_test.lua ├── inspect_namespace_test.lua ├── inspect_pointers_test.lua ├── inspect_simple_test.lua ├── inspect_template_test.lua ├── inspect_thread_test.lua ├── lua_box2d_test.lua ├── lua_constants_test.lua ├── lua_inherit_test.lua ├── lua_memory_test.lua ├── lua_namespace_test.lua ├── lua_pat_test.lua ├── lua_pointers_test.lua ├── lua_simple_test.lua ├── lua_template_test.lua ├── lua_thread_test.lua ├── namespace_test.lua └── opt_parser_test.lua /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.o 3 | *.a 4 | *.so 5 | *.swp 6 | *.swo 7 | build 8 | test/fixtures/Box2D 9 | test/tmp 10 | tmp 11 | /html 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: erlang 2 | 3 | # Try using multiple Lua Implementations 4 | env: 5 | - LUA_VERSION='5.1' LUA="lua5.1" 6 | - LUA_VERSION='5.1' LUA="luajit" # Wee need to install lua5.1 or luarocks won't build 7 | - LUA_VERSION='5.2' LUA="lua5.2" 8 | - LUA_VERSION='5.3' LUA="lua" 9 | 10 | branches: 11 | only: 12 | - master 13 | 14 | install: 15 | - test "$LUA_VERSION" = "5.3" || sudo apt-get install lua$LUA_VERSION liblua$LUA_VERSION-dev 16 | - test "$LUA" = "luajit" && git clone http://luajit.org/git/luajit-2.0.git && cd luajit-2.0/ && sudo make install && cd .. || true 17 | - test "$LUA_VERSION" = "5.3" && wget http://www.lua.org/ftp/lua-5.3.0.tar.gz && tar xzf lua-5.3.0.tar.gz && cd lua-5.3.0 && make linux && sudo make install && cd .. || true 18 | - sudo apt-get --no-install-recommends install doxygen 19 | - git clone git://github.com/keplerproject/luarocks.git 20 | - cd luarocks 21 | - ./configure --lua-version=$LUA_VERSION --versioned-rocks-dir 22 | - make build 23 | - sudo make install 24 | - cd .. 25 | # Install testing dependency 26 | - sudo luarocks-$LUA_VERSION install lut 27 | # Build module 28 | - sudo luarocks-$LUA_VERSION make 29 | 30 | # Run tests 31 | script: 32 | - $LUA -v && $LUA test/all.lua 33 | 34 | notifications: 35 | recipients: 36 | - gaspard@teti.ch 37 | email: 38 | on_success: change 39 | on_failure: always 40 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # MACHINE GENERATED FILE. DO NOT EDIT. 3 | # 4 | # CMake build file for dub 5 | # 6 | # This file has been generated by lut.Builder 1.2.1 7 | # 8 | 9 | cmake_minimum_required(VERSION 2.8) 10 | # -------------------------------------------------------------- 11 | # dub 12 | # -------------------------------------------------------------- 13 | set(MODULE_NAME dub) 14 | 15 | # Where to install Lua files 16 | if(LUA_INSTALL_DIR) 17 | set(INSTALL_PATH ${LUA_INSTALL_DIR}) 18 | else(LUA_INSTALL_DIR) 19 | set(INSTALL_PATH "${CMAKE_BINARY_DIR}/lib" CACHE STRING "Install directory path") 20 | endif(LUA_INSTALL_DIR) 21 | message("INSTALL Lua 'dub' TO '${INSTALL_PATH}'") 22 | 23 | 24 | # -------------------------------------------------------------- 25 | # module 26 | # -------------------------------------------------------------- 27 | add_custom_target(${MODULE_NAME} true) 28 | 29 | # -------------------------------------------------------------- 30 | # install 31 | # -------------------------------------------------------------- 32 | install(DIRECTORY ${MODULE_NAME} 33 | DESTINATION ${INSTALL_PATH} 34 | ) 35 | 36 | 37 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | == 2.2.5 2 | 3 | * Adding option to use a different name for 'L' parameter (#12). 4 | 5 | == 2.2.4 2015-07-03 6 | 7 | * Adding 'unsigned' as C type for 'number' (#10). 8 | 9 | == 2.2.3 2015-06-26 10 | 11 | * Display warning instead of crash in case of missing ctype. 12 | 13 | == 2.2.2 2015-05-11 14 | 15 | * Compatibility with lua 5.3. 16 | * Fixed 'header_base' when paths contain lua pattern characters (Thanks Hendrik Muhs). 17 | * LuaBinder:bindClass now accepts an options table. 18 | 19 | == 2.2.1 2015-05-05 20 | 21 | * Fixed binding generation for Windows (missing dllexport). Thanks LPGhatguy. 22 | * Fixed string detection in overloaded function decision tree (#7). 23 | * Fixed dependency definitions. 24 | * Fixed Doxyfile to avoid doxygen warnings. 25 | * Fixed test compile warnings. 26 | 27 | == 2.2.0 2014-05-15 28 | 29 | * Major enhancement 30 | * Generate bindings compatible with Lua 5.2. 31 | * Not touching global namespace anymore: 'require' returns the library. 32 | * Moving all 'dub' C++ methods inside 'dub' namespace. 33 | * Replacing 'lubyk' dependency by 'lub'. 34 | * Functions marked as 'ignore' are no longer bound in sub-classes. 35 | * Installs with luarocks. 36 | * Removing 'lib_prefix' option and using 'no_prefix' argument instead. 37 | * Much improved documentation. 38 | * CMake build system. 39 | 40 | == 2.1.0 41 | 42 | * Major enhancement 43 | * Added support for functions (not class methods). 44 | * Anonymous union support. 45 | * Added support for Callbacks from C++. 46 | * Added support for pseudo-attributes (get/set methods). 47 | * Added support for string_format and string_args to customize __tostring from @dub. 48 | * Added support for 'register' option in @dub. 49 | * Added support for custom destructor: 'destructor' option in @dub. 50 | * Added 'namespace' option (support for namespace constants and functions. 51 | * Added :deleted() on all class bindings to detect C++ deleted objects from Lua. 52 | * Optimized 'dub_issdata' when the only type resolution involves userdata. 53 | * Automatically transform operator= to "set" method. 54 | * Added support for @dub name: "xxx" in method. 55 | 56 | * Minor enhancement 57 | * Should not add namespace to typedef of template in namespace. 58 | * Should check doxygen header versions. 59 | * Should create cast for unresolved templated parents. 60 | * Added 'ignore' setting for parser. 61 | * Ignoring 'struct' keyword in param (C++ name scoping rules apply). 62 | * Casting enum types to 'int' instead of double. 63 | * Added 'extra_headers' option to binder. 64 | * Fixed bug with unamed method parameters (Tim Mensch). 65 | * Fixed bug with void parameter (Tim Mensch). 66 | * Fixed bug where lua stack would grow during class registration (Tim Mensch). 67 | * Added 'attr_name_filter' to rename attributes. 68 | * Removed 'yaml' dependency and changed @dub options format. 69 | * Binding all classes now works inside a namespace. 70 | * Added support for custom bindings with default values. 71 | * Added @dub bind: false option to not create bindings. 72 | * Added @dub destructor: false option to not destroy from lua. 73 | * @dub ignore can be used to ignore attributes. 74 | * Warn on nested namespaces instead of crash. 75 | * Better handling of unknown (opaque) types. 76 | * Added tests for custom global function bindings. 77 | * Should list super classes in C++ visibility order (from child to parent). 78 | * Class.type should reflect class name, not registration name. 79 | * Should not create 'cast' method when superclasses have 'cast: false'. 80 | * Allow multiple 'header_base' paths to remove (removes the first one matching). 81 | * Make sure abstract types are detected even if all pure virtual functions are ignored. 82 | * Support for warn levels (5 = all, 4 = less, ..., 1 = errors). 83 | * Fixed a bug preventing dub from detecting ignored attributes. 84 | * Fixed a bug where dub would not recognize the correct super class. 85 | * Only cast to unknown classes when explicitely declared in @dub. 86 | * Including "lua.h" instead of "dub/lua.h" to not force dub's lua.h. 87 | 88 | == 2.0.0 2012-01-21 89 | * Complete rewrite in Lua 90 | * Most of the previous features are there (but not all). 91 | * Added support for attributes read/write. 92 | * Garbage collection protection for pointers. 93 | * Return value optimization. 94 | * Garbage collection optimization (an idea from Tim Mensch). 95 | * Doxygen parsing (no need to provide xml). 96 | * Added support for nested classes and namespaces. 97 | * Added support for custom bindings on attributes. 98 | * Added 'Doxyfile' option on inspector to allow custom Doxyfile. 99 | * Added support for void *userdata to store Lua types. 100 | * Added support for transparent native table wrapping. 101 | * Added support for abstract types and casting to these types. 102 | * ... 103 | 104 | == 1.1 --- Last version written in Ruby 105 | 106 | * Minor enhancement 107 | * We can omit 'return 0' when defining body with yaml. 108 | * Automatically uses luaDestroy with subclassed with LuaObject. 109 | * Fixed 'deleted' method (should be present when we use LuaObject). 110 | 111 | == 1.0.0 112 | 113 | * Major enhancement 114 | * Support for yaml definition of binding body. 115 | * Support for superclass (reuse of definitions from the super class) 116 | 117 | == 0.7.1 118 | 119 | The tests in this release do not pass, but the generator is really better and works. I just 120 | don't have the time to fix the tests. 121 | 122 | * Major enhancement 123 | * When the object inherits from a LuaObject class, it calls luaInit(L, obj, "foo.Bar") 124 | 125 | == 0.7.0 2011-08-19 126 | 127 | The tests in this release do not pass, but the generator is really better and works. I just 128 | don't have the time to fix the tests. 129 | 130 | * Major enhancements 131 | * Support for finding userdata from lua table ('super'). 132 | 133 | == 0.6.7 134 | 135 | * Major enhancements 136 | * Added support for LuaStackSize pseudo return value (enables direct stack manipulation). 137 | * Added support for Qt 'public slot:' declarations. 138 | * Added support for 'ignore' @dub setting. 139 | * Added support for custom (or no) destructors. 140 | * Fixed bugs related to overloaded methods and constructors. 141 | * Added support for const char * return type. 142 | * Added support for delete in C++ and/or Lua (DeletableOutOfLua class). 143 | * Added 'deleted' method when the class can be destroyed out of Lua. 144 | * Added support for custom constructors. 145 | * Giving access to meta-table in libname.ClassName_. 146 | * Changed LuaL_check... for dubL_check... to work in try/catch scope (thanks to Ignacio Burgueño) 147 | * Fixed a bug in argument decision tree when there are default values. 148 | * Fixed error reporting in try/catch to avoid memory leaks (thanks to Ignacio Burgueño) 149 | 150 | == 0.6.6 2010-12-16 151 | 152 | * Major enhancements 153 | * Added support for @dub custom Doxygen tag to set class options. 154 | 155 | == 0.6.5 2010-12-15 156 | 157 | * Major enhancements 158 | * Added support for custom_types (defined with Dub::Lua.function_generator.custom_type). 159 | * Added support for lib_name and other customizations through klass.opts. 160 | 161 | == 0.6.4 2010-07-14 162 | 163 | * 1 enhancement 164 | * Fixed homepage link in gem and documentation. 165 | 166 | == 0.6.3 2010-07-07 167 | 168 | * 1 enhancement 169 | * Should ignore non-public member methods. 170 | 171 | == 0.6.2 2010-07-07 172 | 173 | * 1 enhancement 174 | * Added an option define (DUB_LUA_NO_OPEN) to replace luaopen_xx by luaload_xx 175 | * Added char in the list of 'int' types. 176 | 177 | == 0.6.1 2010-03-12 178 | 179 | * 2 enhancements 180 | * Wrapping all function calls in try.. catch blocks 181 | * Added support for custome templates (customize exception handling for example) 182 | 183 | == 0.6.0 2010-03-11 184 | 185 | * 4 enhancements 186 | * added support for custom tostring methods for classes 187 | * fixed parsing of templated return types 188 | * static class methods are now registered in the namespace as Klass_method 189 | * removing functions and methods with class pointer arguments (could use lists later on) 190 | * better parsing of complex types (including nested template arguments) 191 | 192 | == 0.5.1 2010-03-05 193 | 194 | * 2 minor enhancements 195 | * if an argument is fully specified, should not append namespace 196 | * better handling of boolean values 197 | 198 | == 0.5.0 2010-03-03 199 | 200 | * 1 major enhancement 201 | * initial release and tested with OpenCV bindings for Lua 202 | 203 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | 3 | This file is part of the LUBYK project (http://lubyk.org) 4 | Copyright (c) 2007-2012 by Gaspard Bucher (http://teti.ch). 5 | 6 | ------------------------------------------------------------------------------ 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | =============================================================================== 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dub [![Build Status](https://travis-ci.org/lubyk/dub.png)](https://travis-ci.org/lubyk/dub) 2 | === 3 | 4 | Doxygen based Lua binding generator. 5 | 6 | [Documentation](http://doc.lubyk.org/dub.html). 7 | 8 | install 9 | ------- 10 | 11 | luarocks install dub 12 | 13 | 14 | Features 15 | -------- 16 | 17 | Currently, the parser supports: 18 | 19 | * public methods 20 | * public attributes read/write 21 | * pseudo-attributes read/write by calling getter/setter methods. 22 | * custom bindings (for methods and global functions). 23 | * custom read/write attributes (with void *userdata helper, union handling) 24 | * public class methods 25 | * public static attributes read/write 26 | * pointer to member (gc protected) 27 | * cast(default)/copy/disable const attribute 28 | * member pointer assignment (gc protected) 29 | * natural casting from std::string to string type (can include '\0') 30 | * class instantiation from templates through typedefs 31 | * class alias through typedefs 32 | * bindings for superclass 33 | * automatic casting to base class 34 | * default argument values 35 | * overloaded functions with optimized method selection from arguments 36 | * operator overloading (even operator[], operator() and operator+= and such) 37 | * return value optimization (no copy) 38 | * simple type garbage collection optimization (no __gc method) 39 | * namespace 40 | * nested classes 41 | * class enums 42 | * global enums 43 | * build system 44 | * group multiple bindings in a single library 45 | * rewrite class or library names 46 | * native Lua table wrapping setmetatable({super = obj}, Vect) 47 | * callback from C++ with error handling in Lua (with self.error). 48 | * error function captures current 'print' function and can be used with self._errfunc. 49 | * fully tested 50 | * custom method binding name 51 | -------------------------------------------------------------------------------- /dist.info: -------------------------------------------------------------------------------- 1 | name = "dub" 2 | version = "2.2.5" 3 | 4 | desc = "Lua binding generator from C/C++ code (uses Doxygen to parse C++ comments)." 5 | author = "Gaspard Bucher" 6 | license = "MIT" 7 | url = "http://doc.lubyk.org/dub.html" 8 | maintainer = "Gaspard Bucher" 9 | 10 | depends = { 11 | "lua >= 5.1, < 5.4", 12 | "lub >= 1.0.4, < 2", 13 | "xml ~> 1", 14 | "yaml ~> 1", 15 | } 16 | 17 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | lub 5 | 6 | 7 |

Online documentation

8 |

doc.lubyk.org/dub.html

9 | 10 |

Generate

11 |
lua scripts/doc.lua && open html/index.html
12 |     
13 | 14 | 15 | -------------------------------------------------------------------------------- /dox/usage.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * WARING: THIS IS OLD DOCUMENTATION. We keep it here until we have merged all 4 | * content in source code comments. 5 | * 6 | * 7 | * @page dub_usage Dub Usage 8 | * 9 | * @section custom_bindings Custom Class, Function, and Attribute Bindings 10 | * 11 | * @warning Whether a binding has a semicolon changes its behavior, at least in 12 | * accessor bindings. Should talk about this more, and see where the 13 | * behavior changes. 14 | * 15 | * @subsection dub_method_overrides Method Overrides 16 | * 17 | * @subsubsection dub_gc Mark this function as factory method. 18 | * 19 | * \@dub gc: true 20 | * 21 | * Set this value in a method to mark it as a factory method: In other words, 22 | * it's creating a new object that should be managed by Lua. Only makes sense on 23 | * functions that return a pointer generated by new. 24 | * 25 | * @subsection dub_class_overrides Class Overrides 26 | * 27 | * @subsubsection dub_register Change the name of a class 28 | * 29 | * @paragraph dub_register_1 30 | * 31 | * \@dub register: AlternateName 32 | * 33 | * Registers the class using the given AlternateName instead of its actual name. 34 | * Doesn't change the name of the associated metatable, though. 35 | * 36 | * @subsubsection dub_ignore Ignore a member function 37 | * 38 | * @paragraph dub_ignore_1 39 | * 40 | * \@dub ignore: memberName[, memberName2 ...] 41 | * 42 | * Tell Dub to ignore a member; in other words, don't generate any binding 43 | * information for any functions or member variables with matching names. 44 | * 45 | * @subsubsection dub_super Add parent class information 46 | * 47 | * @paragraph dub_super_1 48 | * 49 | * \@dub super: ParentClass[, ParentClass2] 50 | * 51 | * Set parent classes in Dub that Doxygen doesn't know about. Can also be used 52 | * to add mixins to a class. 53 | * 54 | * @subsubsection dub_bind Set binding for a class. 55 | * 56 | * @paragraph dub_bind_1 57 | * 58 | * \@dub bind: false 59 | * 60 | * Setting to false disables binding. 61 | * 62 | * @subsubsection dub_cast Set casting for a class. 63 | * 64 | * @paragraph dub_cast_1 65 | * 66 | * \@dub cast: false 67 | * 68 | * Setting to false disables casting. 69 | * 70 | * @subsubsection dub_push Mark a function as a "push" function 71 | * 72 | * @paragraph dub_push_1 73 | * 74 | * \@dub push: functionName -- typically "push" 75 | * 76 | * Set the name of the function to push this class onto the Lua stack. The 77 | * signature of the function should match: 78 | * 79 | * @code 80 | * void pushobject(lua_State* L, void* thisPtr, 81 | * const char * className, bool shouldGC); 82 | * @endcode 83 | * 84 | * Instead of "void *", the thisPtr can be defined as a pointer to the 85 | * current class. In most cases the pointer here will be the same as 86 | * this. 87 | * 88 | * The className will be passed in as the string that Dub uses 89 | * to identify the class in question. 90 | * 91 | * The boolean shouldGC will be true if Dub believes Lua should garbage-collect 92 | * the value. In practice this means that the call is being made in the 93 | * constructor of the class, or a method 94 | * 95 | * @subsubsection dub_destructor Set the destructor function for a class. 96 | * 97 | * @paragraph dub_destructor_1 98 | * 99 | * \@dub destructor: functionName 100 | * 101 | * The name of the member function to call to destroy the class. Should call 102 | * "delete this" if that's needed to destroy the underlying object. 103 | * 104 | * @subsubsection dub_destroy_free POD Class Optimization/Destructor Disabling 105 | * 106 | * @paragraph dub_destroy_free_1 Dub Command 107 | * \@dub destroy: 'free' 108 | * 109 | * @paragraph dub_destroy_free_1 Inspector Command 110 | * @code 111 | * local a = inspector.find("classname"); 112 | * a.dub = { destroy = "free" } 113 | * @endcode 114 | * 115 | * This enables objects to be created with in-place new, preventing an 116 | * allocation and a copy, and it also completely disables the __gc garbage 117 | * collection callback for the class. 118 | * 119 | * Ideal for POD types that support operators. A vector class Vec2 that supports 120 | * operator+, for example, would be able to create a single extra Lua USERDATA 121 | * with an embedded Vec2 result constructed right in the USERDATA. 122 | * 123 | * @subsubsection dub_class_init Post-Creation Init 124 | * 125 | * @paragraph dub_class_init_1 Dub Command 126 | * @code 127 | * \@dub init: 'luaInit' 128 | * @endcode 129 | * 130 | * @paragraph dub_class_init_2 Inspector Command 131 | * @code 132 | * local a = inspector.find("classname"); 133 | * a.dub = { init = "luaInit" } 134 | * @endcode 135 | * 136 | * @paragraph dub_class_init_3 Inspector Command 137 | * Causes Dub to call luaInit function after creating an instance of classname. 138 | * The luaInit function has the form: 139 | * 140 | * @code 141 | * int luaInit( lua_State * L ); 142 | * @endcode 143 | * 144 | * This function can be used to do extra post-construction initialization for a 145 | * class. 146 | */ 147 | -------------------------------------------------------------------------------- /dub-2.2.5-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "dub" 2 | version = "2.2.5-1" 3 | source = { 4 | url = 'git://github.com/lubyk/dub', 5 | tag = 'REL-2.2.5', 6 | dir = 'dub', 7 | } 8 | description = { 9 | summary = "Lua binding generator from C/C++ code (uses Doxygen to parse C++ comments).", 10 | detailed = [[ 11 | A powerful binding generator for C/C++ code with support for attributes, 12 | callbacks, errors on callbacks, enums, nested classes, operators, public 13 | attributes, etc. 14 | 15 | Full documentation: http://doc.lubyk.org/dub.html 16 | ]], 17 | homepage = "http://doc.lubyk.org/dub.html", 18 | license = "MIT" 19 | } 20 | 21 | dependencies = { 22 | "lua >= 5.1, < 5.4", 23 | "lub >= 1.0.4, < 2", 24 | "xml ~> 1", 25 | "yaml ~> 1", 26 | } 27 | build = { 28 | type = 'builtin', 29 | modules = { 30 | -- Plain Lua files 31 | ['dub' ] = 'dub/init.lua', 32 | ['dub.Class' ] = 'dub/Class.lua', 33 | ['dub.CTemplate' ] = 'dub/CTemplate.lua', 34 | ['dub.Function' ] = 'dub/Function.lua', 35 | ['dub.Inspector' ] = 'dub/Inspector.lua', 36 | ['dub.LuaBinder' ] = 'dub/LuaBinder.lua', 37 | ['dub.MemoryStorage'] = 'dub/MemoryStorage.lua', 38 | ['dub.Namespace' ] = 'dub/Namespace.lua', 39 | ['dub.OptParser' ] = 'dub/OptParser.lua', 40 | }, 41 | install = { 42 | -- Assets needed by library. 43 | lua = { 44 | ['dub.assets.Doxyfile' ] = 'dub/assets/Doxyfile', 45 | ['dub.assets.lua.class_cpp' ] = 'dub/assets/lua/class.cpp', 46 | ['dub.assets.lua.dub.dub_cpp' ] = 'dub/assets/lua/dub/dub.cpp', 47 | ['dub.assets.lua.dub.dub_h' ] = 'dub/assets/lua/dub/dub.h', 48 | ['dub.assets.lua.lib_cpp' ] = 'dub/assets/lua/lib.cpp', 49 | }, 50 | }, 51 | } 52 | 53 | -------------------------------------------------------------------------------- /dub.lua: -------------------------------------------------------------------------------- 1 | dub/init.lua -------------------------------------------------------------------------------- /dub/CTemplate.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | # A C++ template definition. 4 | 5 | (internal) C++ template definition. This is a sub-class of dub.Class. 6 | 7 | --]]------------------------------------------------------ 8 | local lub = require 'lub' 9 | local dub = require 'dub' 10 | local lib = lub.class 'dub.CTemplate' 11 | local private = {} 12 | 13 | -- nodoc 14 | lib.template = true 15 | 16 | -- CTemplate is a sub-class of dub.Class 17 | setmetatable(lib, dub.Class) 18 | 19 | -- # Constructor 20 | -- The Constructor is never used. We transform a dub.Class while parsing 21 | -- template parameters. 22 | 23 | -- Returns a dub.Class by resolving the template parameters. 24 | function lib:resolveTemplateParams(parent, name, types) 25 | local name_to_type = {} 26 | name_to_type[self.name] = name 27 | local all_resolved = true 28 | for i, param in ipairs(self.template_params) do 29 | local typ = types[i] 30 | if typ then 31 | name_to_type[param] = typ 32 | else 33 | all_resolved = false 34 | end 35 | end 36 | if all_resolved then 37 | -- Make class 38 | local class = dub.Class { 39 | db = self.db, 40 | parent = parent or self.parent, 41 | name = name, 42 | } 43 | -- Rebuild methods 44 | private.resolveMethods(self, class, name_to_type) 45 | -- Rebuild attributes 46 | if self.has_variables then 47 | private.resolveAttributes(self, class, name_to_type) 48 | end 49 | return class 50 | else 51 | -- Make another template 52 | end 53 | end 54 | 55 | -- nodoc 56 | lib.fullname = dub.Class.fullname 57 | 58 | --=============================================== PRIVATE 59 | 60 | function private:resolveMethods(class, name_to_type) 61 | for method in self:methods() do 62 | local opts = { 63 | db = self.db, 64 | parent = class, 65 | name = method.name, 66 | params_list = private.resolveParams(method, name_to_type), 67 | return_value = private.resolveType(method.return_value, name_to_type), 68 | definition = method.definition, 69 | argsstring = method.argsstring, 70 | location = method.location, 71 | desc = method.desc, 72 | static = method.static, 73 | xml = method.xml, 74 | member = method.member, 75 | dtor = method.dtor, 76 | ctor = method.ctor, 77 | dub = method.dub, 78 | is_set_attr = method.is_set_attr, 79 | is_get_attr = method.is_get_attr, 80 | is_cast = method.is_cast, 81 | } 82 | if method.ctor then 83 | opts.name = class.name 84 | opts.return_value = dub.MemoryStorage.makeType(class.name .. ' *') 85 | elseif method.dtor then 86 | opts.name = '~' .. class.name 87 | end 88 | 89 | local m = dub.Function(opts) 90 | class.cache[m.name] = m 91 | table.insert(class.functions_list, m) 92 | end 93 | end 94 | 95 | function private:resolveAttributes(class, name_to_type) 96 | class.has_variables = true 97 | local list = class.variables_list 98 | for attr in self:attributes() do 99 | table.insert(list, { 100 | type = 'dub.Attribute', 101 | parent = class, 102 | name = attr.name, 103 | ctype = private.resolveType(attr.ctype, name_to_type), 104 | }) 105 | end 106 | end 107 | 108 | function private:resolveParams(name_to_type) 109 | local res = {} 110 | for _, param in ipairs(self.params_list) do 111 | local p = { 112 | type = 'dub.Param', 113 | name = param.name, 114 | position = param.position, 115 | ctype = private.resolveType(param.ctype, name_to_type), 116 | } 117 | table.insert(res, p) 118 | end 119 | return res 120 | end 121 | 122 | function private.resolveType(ctype, name_to_type) 123 | if not ctype then 124 | return 125 | end 126 | local resolv = name_to_type[ctype.name] 127 | 128 | if resolv then 129 | local t = dub.MemoryStorage.makeType(resolv) 130 | return dub.MemoryStorage.makeType(resolv) 131 | else 132 | return ctype 133 | end 134 | end 135 | 136 | return lib 137 | -------------------------------------------------------------------------------- /dub/Class.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | # C++ Class definition. 3 | 4 | (internal) A C++ class/struct definition. 5 | 6 | --]]------------------------------------------------------ 7 | 8 | local lub = require 'lub' 9 | local dub = require 'dub' 10 | local lib = lub.class('dub.Class', { 11 | is_class = true, 12 | is_scope = true, 13 | SET_ATTR_NAME = '_set_', 14 | GET_ATTR_NAME = '_get_', 15 | CAST_NAME = '_cast_', 16 | -- Can be overwritten by dub.cast parameter 17 | should_cast = true, 18 | }) 19 | local private = {} 20 | 21 | -- # Constructor 22 | 23 | -- Create a new class definition. Most of the attributes are passed with 24 | -- `def`. Usage example: 25 | -- 26 | -- local class = dub.Class { 27 | -- -- self can be a class or db (root) 28 | -- db = self.db or self, 29 | -- parent = parent, 30 | -- name = name, 31 | -- xml = elem, 32 | -- xml_headers = { 33 | -- {path = header.dir .. lub.Dir.sep .. elem.refid .. '.xml', dir = header.dir} 34 | -- }, 35 | -- } 36 | function lib.new(def) 37 | local self = def or {} 38 | self.cache = {} 39 | self.sorted_cache = {} 40 | self.functions_list = {} 41 | self.variables_list = {} 42 | self.constants_list = {} 43 | self.super_list = {} 44 | 45 | self.xml_headers = self.xml_headers or {} 46 | setmetatable(self, lib) 47 | self:setOpt(self.dub or {}) 48 | self:setName(self.name) 49 | if self.dub.ignore == true then 50 | return nil 51 | else 52 | return self 53 | end 54 | end 55 | 56 | -- # Accessors 57 | 58 | -- The fullname of the class in the form of @parent::ClassName@. 59 | function lib:fullname() 60 | if self.parent and self.parent.name then 61 | return self.parent:fullname() .. '::' .. self.name 62 | else 63 | return self.name 64 | end 65 | end 66 | 67 | -- Returns true if the class has variables (public C attributes). 68 | function lib:hasVariables() 69 | if self.has_variables then 70 | return true 71 | end 72 | -- Look in inheritance chain 73 | for super in self:superclasses() do 74 | if super:hasVariables() then 75 | self.has_variables = true 76 | return true 77 | end 78 | end 79 | return false 80 | end 81 | 82 | -- Return true if the class needs a cast method (it has 83 | -- known superclasses). 84 | function lib:needCast() 85 | for super in self:superclasses() do 86 | return true 87 | end 88 | return false 89 | end 90 | 91 | -- Return true if the given function name should be ignored (do not create 92 | -- bindings). 93 | function lib:ignoreFunc(name) 94 | return self.ignore[name] or name == self.dub.push 95 | end 96 | 97 | -- Set the class name and C++ object creation type. 98 | function lib:setName(name) 99 | if not name then 100 | return 101 | end 102 | self.name = name 103 | -- Remove namespace from name 104 | local create_name = '' 105 | local current = self 106 | while current and current.is_scope do 107 | if current ~= self then 108 | create_name = '::' .. create_name 109 | end 110 | create_name = current.name .. create_name 111 | current = current.parent 112 | if current and current.type == 'dub.Namespace' then 113 | break 114 | end 115 | end 116 | self.create_name = create_name .. ' *' 117 | end 118 | 119 | -- Set options (usually from parsed C++ class comment). 120 | function lib:setOpt(opt) 121 | self.dub = opt or {} 122 | self.dub_type = self.dub.type 123 | self.ignore = self.dub.ignore or {} 124 | if type(self.ignore) == 'string' then 125 | self.ignore = { self.ignore, 126 | [self.ignore] = true, 127 | } 128 | end 129 | 130 | if type(self.dub.super) == 'string' then 131 | self.dub.super = { self.dub.super } 132 | end 133 | 134 | if self.dub.abstract then 135 | self.abstract = true 136 | end 137 | 138 | local dtor = self.dub.destructor 139 | if dtor == false then 140 | self.ignore['~'..self.name] = true 141 | elseif dtor then 142 | self.ignore[dtor] = true 143 | end 144 | 145 | -- cast 146 | if self.dub.cast == false then 147 | self.should_cast = false 148 | end 149 | end 150 | 151 | -- # Find 152 | 153 | -- Return the enclosing namespace or nil if none found. 154 | function lib:namespace() 155 | local p = self.parent 156 | while p do 157 | if p.type == 'dub.Namespace' then 158 | return p 159 | else 160 | p = p.parent 161 | end 162 | end 163 | end 164 | 165 | -- Return a child element named `name` or nil if nothing is found. Uses the 166 | -- database internally. 167 | function lib:findChild(name) 168 | private.makeSpecialMethods(self) 169 | return self.db:findChildFor(self, name) 170 | end 171 | 172 | -- Return a method from a given @name@. 173 | -- function lib:method(name) 174 | 175 | -- nodoc 176 | lib.method = lib.findChild 177 | 178 | -- # Iterators 179 | 180 | -- Return an iterator over the superclasses of this class. 181 | function lib:superclasses() 182 | return self.db:superclasses(self) 183 | end 184 | 185 | -- Return an iterator over the constants defined in this class. 186 | function lib:constants() 187 | return self.db:constants(self) 188 | end 189 | 190 | -- Return an iterator over the methods of this class. 191 | function lib:methods() 192 | -- Create --get--, --set-- and ~Destructor if needed. 193 | private.makeSpecialMethods(self) 194 | return self.db:functions(self) 195 | end 196 | 197 | -- Return an iterator over the attributes of this class. 198 | function lib:attributes() 199 | return self.db:variables(self) 200 | end 201 | 202 | -- nodoc 203 | function lib.__call(lib, ...) 204 | -- This lets sub-classes of dub.Class like dub.Namespace or dub.CTemplate 205 | -- use the same call convention to create new objects. 206 | return lib.new(...) 207 | end 208 | 209 | --=============================================== PRIVATE 210 | 211 | function private:makeSpecialMethods() 212 | if self.made_special_methods then 213 | return 214 | end 215 | self.made_special_methods = true 216 | dub.MemoryStorage.makeSpecialMethods(self) 217 | end 218 | 219 | return lib 220 | -------------------------------------------------------------------------------- /dub/Function.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | # C++ Function definition. 3 | 4 | (internal) A public C++ function or method definition. 5 | 6 | --]]------------------------------------------------------ 7 | local lub = require 'lub' 8 | local dub = require 'dub' 9 | local lib = lub.class 'dub.Function' 10 | local private = {} 11 | 12 | -- Create a new function object with `def` settings. Some important fields in 13 | -- `def`: 14 | -- 15 | -- + name : Function name. 16 | -- + db : Storage engine (dub.MemoryStorage). 17 | -- + parent : Parent or storage engine if the function is defined in root. 18 | -- + header : Path to C++ header file where this function is declared. 19 | -- + params_list : List of dub.Param definitions for the function arguments. 20 | -- + return_value : Return type definition (see dub.MemoryStorage.makeType). 21 | -- + definition : Full function name as defined (used in comment). 22 | -- + argsstring : Arguments as a single string (used in comment). 23 | -- + location : A String representing the function source file and line. 24 | -- + desc : String description (will be used in a C++ comment in 25 | -- bindings). 26 | -- + static : True if the function is static (static class function or 27 | -- C function). 28 | -- + xml : An xml object representing the function definition. 29 | -- + member : True if the function is a member function (static or not). 30 | -- + dtor : True if the function is the destructor. 31 | -- + ctor : True if the function is a constructor. 32 | -- + dub : "dub" options as parsed from the "dub" C++ comment. 33 | -- + pure_virtual : True if the function is a pure virtual. 34 | function lib.new(def) 35 | local self = def 36 | self.dub = self.dub or {} 37 | self.member = self.parent.is_class and not (self.static or self.ctor) 38 | self.has_defaults = self.params_list.first_default and true 39 | self.header = self.header or self.parent.header 40 | if self.has_defaults then 41 | self.first_default = self.params_list.first_default 42 | -- minimal number of arguments 43 | self.min_arg_size = self.first_default - 1 44 | else 45 | self.min_arg_size = #self.params_list 46 | end 47 | setmetatable(self, lib) 48 | if not self:setName(self.name) then 49 | -- invalid name (usually an unknown operator) 50 | return nil 51 | end 52 | 53 | if self.db:ignored(self:fullname()) or 54 | self.dub.ignore == true or 55 | (self.parent.is_class and self.parent:ignoreFunc(self.name)) then 56 | return nil 57 | end 58 | 59 | self.sign = private.makeSignature(self) 60 | return self 61 | end 62 | 63 | -- # Operator overloading 64 | -- Read this table as 'operator[KEY]' translates into lua function '__[VALUE]'. 65 | -- For example `operator+` becomes `__add`. This works for most methods except 66 | -- for some operators which do not have a lua equivalent (+=, -=, etc). 67 | 68 | lib.OP_TO_NAME = { -- doc 69 | -- local v = foo + bar 70 | ['+'] = 'add', 71 | -- local v = foo - bar 72 | ['-'] = 'sub', 73 | -- local bar = -foo 74 | ['- '] = 'unm', 75 | -- local v = foo * bar 76 | ['*'] = 'mul', 77 | -- local v = foo / bar 78 | ['/'] = 'div', 79 | -- if (foo == bar) ... 80 | ['=='] = 'eq', 81 | -- if (foo < bar) ... 82 | ['<'] = 'lt', 83 | -- if (foo <= bar) ... 84 | ['<='] = 'le', 85 | -- This is the call on the object itself. Example: 86 | -- 87 | -- local foo = Foo() 88 | -- foo() --> call 89 | ['()'] = 'call', 90 | -- Table access. When binding this method, integer access is very fast but we 91 | -- must also hand-code metatable access (to get methods) and attribute access. 92 | -- 93 | -- It is thus better to avoid this operator for it has a non-negligible cost. 94 | -- 95 | -- local x = foo[4] 96 | ['[]'] = 'index', 97 | -- This is not supported in lua due to the fact that all variables are 98 | -- references to objects and the equal sign is used to assign reference. We 99 | -- must therefore use 'set': 100 | -- 101 | -- local foo, bar = Simple('I am foo'), Simple('I am bar') 102 | -- -- foo = bar would make 'foo' a pointer to bar, not assign 103 | -- -- values of bar into foo. We must use: 104 | -- foo:set(bar) 105 | -- --> C++ foo.operator=(bar) 106 | ['='] = 'sete', 107 | -- Mutable operator. No equivalent in Lua. 108 | -- 109 | -- -- Add 50 into foo, mutating foo. 110 | -- foo:adde(50) 111 | ['+='] = 'adde', 112 | -- Mutable operator. No equivalent in Lua. 113 | -- 114 | -- -- Remove 50 from foo, mutating foo. 115 | -- foo:sube(50) 116 | ['-='] = 'sube', 117 | -- Mutable operator. No equivalent in Lua. 118 | -- 119 | -- -- Scale foo by 50, mutating foo. 120 | -- foo:mule(50) 121 | ['*='] = 'mule', 122 | -- Mutable operator. No equivalent in Lua. 123 | -- 124 | -- -- Divide foo by 50, mutating foo. 125 | -- foo:dive(50) 126 | ['/='] = 'dive', 127 | } 128 | 129 | -- # Accessors 130 | 131 | -- Return the full name of the function (with enclosing namespaces separated 132 | -- by '::'. Example: `foo::Bar::drawLine`. 133 | -- function lib:fullname() 134 | 135 | -- nodoc 136 | lib.fullname = dub.Class.fullname 137 | 138 | -- Full C name for function. This is like #fullname but with the C names in 139 | -- case binding names are different. 140 | function lib:fullcname() 141 | if self.parent and self.parent.name then 142 | return self.parent:fullname() .. '::' .. self.cname 143 | else 144 | return self.cname 145 | end 146 | end 147 | 148 | 149 | -- String representation of the function name with arguments (used in comments). 150 | -- Example: `drawLine(int x, int y, int x2, int y2, const foo.Pen &pen)` 151 | function lib:nameWithArgs() 152 | return self.definition .. self.argsstring 153 | end 154 | 155 | -- Returns true if the function does not throw any C++ exception. 156 | function lib:neverThrows() 157 | return self.throw == 'throw ()' or 158 | self.is_set_attr or 159 | self.is_get_attr or 160 | self.is_cast 161 | end 162 | 163 | -- Set function name and C name. 164 | function lib:setName(name) 165 | self.name = name 166 | if string.match(self.name, '^~') then 167 | self.destructor = true 168 | self.cname = string.gsub(self.name, '~', '_') 169 | elseif string.match(name, '^operator') then 170 | local n = string.match(name, '^operator(.+)$') 171 | local op = self.OP_TO_NAME[n] 172 | if op then 173 | self.cname = 'operator_' .. op 174 | else 175 | return false 176 | end 177 | else 178 | self.cname = self.name 179 | end 180 | return true 181 | end 182 | 183 | -- # Iterators 184 | 185 | -- Return an iterator over the parameters of this function. 186 | function lib:params() 187 | local co = coroutine.create(private.paramsIterator) 188 | return function() 189 | local ok, value = coroutine.resume(co, self) 190 | if ok then 191 | return value 192 | end 193 | end 194 | end 195 | 196 | --=============================================== PRIVATE 197 | 198 | function private:paramsIterator() 199 | for _, param in ipairs(self.params_list) do 200 | coroutine.yield(param) 201 | end 202 | end 203 | 204 | -- Create a string identifying the met type for overloading. This is just 205 | -- a concatenation of param type names. 206 | function private.makeSignature(met) 207 | local res = '' 208 | for param in met:params() do 209 | if res ~= '' then 210 | res = res .. ', ' 211 | end 212 | res = res .. param.ctype.name 213 | end 214 | return res 215 | end 216 | 217 | return lib 218 | -------------------------------------------------------------------------------- /dub/Inspector.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | # Inspector 4 | 5 | The Inspector 'knows' about the functions and classes 6 | and can answer queries. 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local dub = require 'dub' 11 | local lib = lub.class 'dub.Inspector' 12 | local private = {} 13 | 14 | 15 | -- Create a new inspector by providing sources to scan. All upercase fields in 16 | -- `opts` correspond to options used by Doxygen. The `opts` table can 17 | -- contain the following keys (keys in parenthesis are optional): 18 | -- 19 | -- + INPUT : List of source files separated by spaces (doxygen format). The 20 | -- sources can also be passed as a table. 21 | -- + (html) : Generate html documentation along the way (implies `keep_xml`). 22 | -- + (keep_xml) : Keep xml generated by Doxygen (used for debugging purposes). 23 | -- + (Doxyfile) : Custom Doxyfile to pass to Doxygen parser. 24 | -- + (PREDEFINED) : Defines to use by Doxygen during parsing (usually to remove 25 | -- unwanted clutter from "ATTRIBUTE_ALIGNED16" or 26 | -- "SIMD_FORCE_INLINE" kind of macros. 27 | -- + (EXCLUDE_PATTERNS) : Doxygen option to exclude files and/or directories. 28 | -- + (FILE_PATTERNS) : Doxygen option for header file name patterns such as `*.h *.hpp`. 29 | -- + (doc_dir) : Directory to store generated xml and html. 30 | -- + (ignore) : List of root level classes or functions to ignore. 31 | function lib.new(opts) 32 | local self = {db = dub.MemoryStorage()} 33 | setmetatable(self, lib) 34 | private.parse(self, opts) 35 | return self 36 | end 37 | 38 | -- The command used to call doxygen. 39 | lib.DOXYGEN_CMD = 'doxygen' 40 | 41 | 42 | -- Return a class or function from its name. A class in a namespace is 43 | -- queried with 'foo::Bar'. Uses dub.MemoryStorage.findByFullname. 44 | function lib:find(name) 45 | -- A 'child' of the Inspector can be anything so we 46 | -- have to walk through the files to find what we 47 | -- are asked for. 48 | -- Object lives at the root of the name space. 49 | return self.db:findByFullname(name) 50 | end 51 | 52 | -- Return an interator on all children known to the inspector (can be a function 53 | -- or class). Uses dub.MemoryStorage.children. 54 | function lib:children() 55 | return self.db:children() 56 | end 57 | 58 | -- Try to follow typedefs to resolve a type. Uses dub.MemoryStorage.resolveType 59 | -- internally. 60 | function lib:resolveType(name) 61 | return self.db:resolveType(self.db, name) 62 | end 63 | 64 | 65 | --=============================================== PRIVATE 66 | 67 | -- Add xml headers to the database. If `not_lazy` is set, parse everything 68 | -- directly (not when needed). 69 | function private:parseXml(xml_dir, not_lazy, ignore_list) 70 | self.db:parse(xml_dir, not_lazy, ignore_list) 71 | end 72 | 73 | function private:parse(opts) 74 | if type(opts) == 'string' then 75 | opts = {INPUT = opts} 76 | end 77 | assert(opts and opts.INPUT, "Missing 'INPUT' field") 78 | 79 | if not opts.FILE_PATTERNS then 80 | opts.FILE_PATTERNS = [[ 81 | *.c \ 82 | *.cc \ 83 | *.cxx \ 84 | *.cpp \ 85 | *.c++ \ 86 | *.d \ 87 | *.java \ 88 | *.ii \ 89 | *.ixx \ 90 | *.ipp \ 91 | *.i++ \ 92 | *.inl \ 93 | *.h \ 94 | *.H \ 95 | *.hh \ 96 | *.hxx \ 97 | *.hpp \ 98 | *.h++ \ 99 | *.idl \ 100 | *.odl \ 101 | *.cs \ 102 | *.php \ 103 | *.php3 \ 104 | *.inc \ 105 | *.m \ 106 | *.mm \ 107 | *.dox \ 108 | *.py \ 109 | *.f90 \ 110 | *.f \ 111 | *.for \ 112 | *.vhd \ 113 | *.vhdl 114 | ]] 115 | end 116 | 117 | if opts.html then 118 | opts.GENERATE_HTML = 'YES' 119 | opts.keep_xml = true 120 | end 121 | 122 | local doc_dir = opts.doc_dir 123 | if opts.keep_xml and not doc_dir then 124 | doc_dir = 'dub-doc' 125 | elseif not doc_dir then 126 | doc_dir = 'dub-tmp' 127 | local i = 0 128 | while true do 129 | if lub.exist(doc_dir) then 130 | i = i + 1 131 | doc_dir = string.format('dub-tmp-%i', i) 132 | else 133 | break 134 | end 135 | end 136 | end 137 | 138 | private.execute('mkdir -p ' .. doc_dir) 139 | 140 | local doxypath = opts.Doxyfile 141 | if not doxypath then 142 | doxypath = doc_dir .. '/Doxyfile' 143 | local doxyfile = io.open(doxypath, 'w') 144 | 145 | local doxytemplate = lub.Template {path = lub.path('|assets/Doxyfile')} 146 | if type(opts.INPUT) == 'table' then 147 | opts.INPUT = lub.join(opts.INPUT, ' ') 148 | end 149 | if not opts.EXCLUDE_PATTERNS then 150 | opts.EXCLUDE_PATTERNS = '' 151 | elseif type(opts.EXCLUDE_PATTERNS) == 'table' then 152 | opts.EXCLUDE_PATTERNS = lub.join(opts.EXCLUDE_PATTERNS, ' ') 153 | end 154 | if type(opts.FILE_PATTERNS) == 'table' then 155 | opts.FILE_PATTERNS = lub.join(opts.FILE_PATTERNS, ' ') 156 | end 157 | if type(opts.PREDEFINED) == 'table' then 158 | opts.PREDEFINED = lub.join(opts.PREDEFINED, ' \\\n ') 159 | end 160 | 161 | -- Generate Doxyfile 162 | doxyfile:write(doxytemplate:run({doc_dir = doc_dir, opts = opts})) 163 | doxyfile:close() 164 | end 165 | 166 | -- Generate xml 167 | private.execute(self.DOXYGEN_CMD .. ' ' .. doxypath) 168 | -- Parse xml 169 | private.parseXml(self, doc_dir .. '/xml', true, opts.ignore) 170 | if not opts.keep_xml then 171 | if not opts.doc_dir then 172 | lub.rmTree(doc_dir, true) 173 | else 174 | lub.rmTree(doc_dir .. '/xml', true) 175 | end 176 | end 177 | end 178 | 179 | function private.execute(cmd) 180 | os.execute(cmd) 181 | end 182 | 183 | return lib 184 | -------------------------------------------------------------------------------- /dub/Namespace.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | # C++ Namespace definition. 4 | 5 | (internal) A C++ namespace definition with nested classes, enums 6 | and functions. 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local dub = require 'dub' 11 | local lib = lub.class('dub.Namespace', { 12 | is_class = false, 13 | }) 14 | local private = {} 15 | 16 | -- Behaves like a class by default 17 | setmetatable(lib, dub.Class) 18 | 19 | --=============================================== dub.Namespace() 20 | function lib.new(self) 21 | local self = self or {} 22 | local name = self.name 23 | self.name = nil 24 | self.const_headers = {} 25 | self = dub.Class(self) 26 | setmetatable(self, lib) 27 | self:setName(name) 28 | return self 29 | end 30 | 31 | function lib:namespaces() 32 | return self.db:namespaces() 33 | end 34 | 35 | function lib:functions() 36 | return self.db:functions(self) 37 | end 38 | 39 | --=============================================== PUBLIC METHODS 40 | 41 | function lib:setName(name) 42 | self.name = name 43 | end 44 | 45 | function lib:fullname() 46 | if self.parent and self.parent.type ~= 'dub.MemoryStorage' then 47 | return self.parent:fullname() .. '::' .. self.name 48 | else 49 | return self.name 50 | end 51 | end 52 | 53 | function lib:children() 54 | return self.db:children(self) 55 | end 56 | 57 | return lib 58 | -------------------------------------------------------------------------------- /dub/OptParser.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | # "dub" options parser 4 | 5 | (internal) Simplified yaml parser to retrieve @dub inline options. 6 | 7 | --]]------------------------------------------------------ 8 | local lub = require 'lub' 9 | local lib = lub.class 'dub.OptParser' 10 | local insert, match = table.insert, string.match 11 | local private = {} 12 | 13 | --=============================================== dub.Class() 14 | function lib.new(str) 15 | return lib.parse(str) 16 | end 17 | 18 | function lib.parse(str) 19 | local res = {} 20 | for line in str:gmatch("[^\r\n]+") do 21 | local key, value = line:match(' *([A-Za-z_]+): *(.-) *$') 22 | if not key then 23 | return nil 24 | end 25 | local str = value:match('^"(.*)"$') or 26 | value:match("^'(.*)'$") 27 | if str then 28 | -- string 29 | value = str 30 | elseif value == 'false' then 31 | value = false 32 | elseif value == 'true' then 33 | value = true 34 | elseif value:match('^[0-9.]+$') then 35 | value = value * 1 36 | elseif value:match(',') then 37 | local list = {} 38 | for elem in value:gmatch('[^,]+') do 39 | elem = private.strip(elem) 40 | insert(list, elem) 41 | list[elem] = true 42 | end 43 | value = list 44 | end 45 | 46 | res[key] = value 47 | end 48 | return res 49 | end 50 | 51 | --=============================================== PRIVATE 52 | 53 | function private.strip(str) 54 | return match(str, '^ *(.-) *$') 55 | end 56 | 57 | return lib 58 | -------------------------------------------------------------------------------- /dub/assets/Doxyfile: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.7.5.1 2 | DOXYFILE_ENCODING = UTF-8 3 | PROJECT_NAME = "Dub Bindings" 4 | PROJECT_NUMBER = 5 | PROJECT_BRIEF = 6 | PROJECT_LOGO = 7 | OUTPUT_DIRECTORY = "{{doc_dir}}" 8 | CREATE_SUBDIRS = NO 9 | OUTPUT_LANGUAGE = English 10 | BRIEF_MEMBER_DESC = YES 11 | REPEAT_BRIEF = YES 12 | ABBREVIATE_BRIEF = "The $name class" \ 13 | "The $name widget" \ 14 | "The $name file" \ 15 | is \ 16 | provides \ 17 | specifies \ 18 | contains \ 19 | represents \ 20 | a \ 21 | an \ 22 | the 23 | ALWAYS_DETAILED_SEC = NO 24 | INLINE_INHERITED_MEMB = NO 25 | FULL_PATH_NAMES = YES 26 | STRIP_FROM_PATH = 27 | STRIP_FROM_INC_PATH = 28 | SHORT_NAMES = NO 29 | JAVADOC_AUTOBRIEF = NO 30 | QT_AUTOBRIEF = NO 31 | MULTILINE_CPP_IS_BRIEF = NO 32 | INHERIT_DOCS = YES 33 | SEPARATE_MEMBER_PAGES = NO 34 | TAB_SIZE = 8 35 | ALIASES = "dub=\par Bindings info:\n" 36 | OPTIMIZE_OUTPUT_FOR_C = NO 37 | OPTIMIZE_OUTPUT_JAVA = NO 38 | OPTIMIZE_FOR_FORTRAN = NO 39 | OPTIMIZE_OUTPUT_VHDL = NO 40 | EXTENSION_MAPPING = 41 | BUILTIN_STL_SUPPORT = NO 42 | CPP_CLI_SUPPORT = NO 43 | SIP_SUPPORT = NO 44 | IDL_PROPERTY_SUPPORT = YES 45 | DISTRIBUTE_GROUP_DOC = NO 46 | SUBGROUPING = YES 47 | INLINE_GROUPED_CLASSES = NO 48 | TYPEDEF_HIDES_STRUCT = NO 49 | EXTRACT_ALL = YES 50 | EXTRACT_PRIVATE = NO 51 | EXTRACT_STATIC = NO 52 | EXTRACT_LOCAL_CLASSES = YES 53 | EXTRACT_LOCAL_METHODS = NO 54 | EXTRACT_ANON_NSPACES = NO 55 | HIDE_UNDOC_MEMBERS = NO 56 | HIDE_UNDOC_CLASSES = NO 57 | HIDE_FRIEND_COMPOUNDS = NO 58 | HIDE_IN_BODY_DOCS = NO 59 | INTERNAL_DOCS = NO 60 | CASE_SENSE_NAMES = NO 61 | HIDE_SCOPE_NAMES = NO 62 | SHOW_INCLUDE_FILES = YES 63 | FORCE_LOCAL_INCLUDES = NO 64 | INLINE_INFO = YES 65 | SORT_MEMBER_DOCS = YES 66 | SORT_BRIEF_DOCS = NO 67 | SORT_MEMBERS_CTORS_1ST = NO 68 | SORT_GROUP_NAMES = NO 69 | SORT_BY_SCOPE_NAME = NO 70 | STRICT_PROTO_MATCHING = NO 71 | GENERATE_TODOLIST = YES 72 | GENERATE_TESTLIST = YES 73 | GENERATE_BUGLIST = YES 74 | GENERATE_DEPRECATEDLIST= YES 75 | ENABLED_SECTIONS = 76 | MAX_INITIALIZER_LINES = 30 77 | SHOW_USED_FILES = YES 78 | SHOW_FILES = YES 79 | SHOW_NAMESPACES = YES 80 | FILE_VERSION_FILTER = 81 | LAYOUT_FILE = 82 | QUIET = YES 83 | WARNINGS = YES 84 | WARN_IF_UNDOCUMENTED = NO 85 | WARN_IF_DOC_ERROR = NO 86 | WARN_NO_PARAMDOC = NO 87 | WARN_FORMAT = "$file:$line: $text" 88 | WARN_LOGFILE = 89 | INPUT = {{opts.INPUT}} 90 | INPUT_ENCODING = UTF-8 91 | FILE_PATTERNS = {{opts.FILE_PATTERNS}} 92 | RECURSIVE = {{opts.RECURSIVE or 'NO'}} 93 | EXCLUDE = 94 | EXCLUDE_SYMLINKS = NO 95 | EXCLUDE_PATTERNS = {{opts.EXCLUDE_PATTERNS}} 96 | EXCLUDE_SYMBOLS = 97 | EXAMPLE_PATH = 98 | EXAMPLE_PATTERNS = * 99 | EXAMPLE_RECURSIVE = NO 100 | IMAGE_PATH = 101 | INPUT_FILTER = 102 | FILTER_PATTERNS = 103 | FILTER_SOURCE_FILES = NO 104 | FILTER_SOURCE_PATTERNS = 105 | SOURCE_BROWSER = NO 106 | INLINE_SOURCES = NO 107 | STRIP_CODE_COMMENTS = YES 108 | REFERENCED_BY_RELATION = NO 109 | REFERENCES_RELATION = NO 110 | REFERENCES_LINK_SOURCE = YES 111 | USE_HTAGS = NO 112 | VERBATIM_HEADERS = YES 113 | ALPHABETICAL_INDEX = YES 114 | COLS_IN_ALPHA_INDEX = 5 115 | IGNORE_PREFIX = 116 | GENERATE_HTML = {{opts.GENERATE_HTML or 'NO'}} 117 | HTML_OUTPUT = html 118 | HTML_FILE_EXTENSION = .html 119 | HTML_HEADER = 120 | HTML_FOOTER = 121 | HTML_STYLESHEET = 122 | HTML_EXTRA_FILES = 123 | HTML_COLORSTYLE_HUE = 220 124 | HTML_COLORSTYLE_SAT = 100 125 | HTML_COLORSTYLE_GAMMA = 80 126 | HTML_TIMESTAMP = YES 127 | HTML_DYNAMIC_SECTIONS = NO 128 | GENERATE_DOCSET = NO 129 | DOCSET_FEEDNAME = "Doxygen generated docs" 130 | DOCSET_BUNDLE_ID = org.doxygen.Project 131 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 132 | DOCSET_PUBLISHER_NAME = Publisher 133 | GENERATE_HTMLHELP = NO 134 | CHM_FILE = 135 | HHC_LOCATION = 136 | GENERATE_CHI = NO 137 | CHM_INDEX_ENCODING = 138 | BINARY_TOC = NO 139 | TOC_EXPAND = NO 140 | GENERATE_QHP = NO 141 | QCH_FILE = 142 | QHP_NAMESPACE = org.doxygen.Project 143 | QHP_VIRTUAL_FOLDER = doc 144 | QHP_CUST_FILTER_NAME = 145 | QHP_CUST_FILTER_ATTRS = 146 | QHP_SECT_FILTER_ATTRS = 147 | QHG_LOCATION = 148 | GENERATE_ECLIPSEHELP = NO 149 | ECLIPSE_DOC_ID = org.doxygen.Project 150 | DISABLE_INDEX = NO 151 | ENUM_VALUES_PER_LINE = 4 152 | GENERATE_TREEVIEW = NO 153 | TREEVIEW_WIDTH = 250 154 | EXT_LINKS_IN_WINDOW = NO 155 | FORMULA_FONTSIZE = 10 156 | FORMULA_TRANSPARENT = YES 157 | MATHJAX_RELPATH = http://www.mathjax.org/mathjax 158 | SEARCHENGINE = NO 159 | SERVER_BASED_SEARCH = NO 160 | GENERATE_LATEX = {{opts.GENERATE_LATEX or 'NO'}} 161 | LATEX_OUTPUT = latex 162 | LATEX_CMD_NAME = latex 163 | MAKEINDEX_CMD_NAME = makeindex 164 | COMPACT_LATEX = NO 165 | PAPER_TYPE = a4 166 | EXTRA_PACKAGES = 167 | LATEX_HEADER = 168 | LATEX_FOOTER = 169 | PDF_HYPERLINKS = YES 170 | USE_PDFLATEX = YES 171 | LATEX_BATCHMODE = NO 172 | LATEX_HIDE_INDICES = NO 173 | LATEX_SOURCE_CODE = NO 174 | GENERATE_RTF = NO 175 | RTF_OUTPUT = rtf 176 | COMPACT_RTF = NO 177 | RTF_HYPERLINKS = NO 178 | RTF_STYLESHEET_FILE = 179 | RTF_EXTENSIONS_FILE = 180 | GENERATE_MAN = NO 181 | MAN_OUTPUT = man 182 | MAN_EXTENSION = .3 183 | MAN_LINKS = NO 184 | GENERATE_XML = YES 185 | XML_OUTPUT = xml 186 | XML_PROGRAMLISTING = NO 187 | GENERATE_AUTOGEN_DEF = NO 188 | GENERATE_PERLMOD = NO 189 | PERLMOD_LATEX = NO 190 | PERLMOD_PRETTY = YES 191 | PERLMOD_MAKEVAR_PREFIX = 192 | ENABLE_PREPROCESSING = YES 193 | MACRO_EXPANSION = YES 194 | EXPAND_ONLY_PREDEF = YES 195 | SEARCH_INCLUDES = YES 196 | INCLUDE_PATH = 197 | INCLUDE_FILE_PATTERNS = 198 | PREDEFINED = {{opts.PREDEFINED}} 199 | EXPAND_AS_DEFINED = 200 | SKIP_FUNCTION_MACROS = YES 201 | TAGFILES = 202 | GENERATE_TAGFILE = 203 | ALLEXTERNALS = NO 204 | EXTERNAL_GROUPS = YES 205 | PERL_PATH = /usr/bin/perl 206 | CLASS_DIAGRAMS = NO 207 | MSCGEN_PATH = 208 | HIDE_UNDOC_RELATIONS = YES 209 | HAVE_DOT = NO 210 | DOT_NUM_THREADS = 0 211 | DOT_FONTNAME = Helvetica 212 | DOT_FONTSIZE = 10 213 | DOT_FONTPATH = 214 | CLASS_GRAPH = YES 215 | COLLABORATION_GRAPH = YES 216 | GROUP_GRAPHS = YES 217 | UML_LOOK = NO 218 | TEMPLATE_RELATIONS = NO 219 | INCLUDE_GRAPH = YES 220 | INCLUDED_BY_GRAPH = YES 221 | CALL_GRAPH = NO 222 | CALLER_GRAPH = NO 223 | GRAPHICAL_HIERARCHY = YES 224 | DIRECTORY_GRAPH = YES 225 | DOT_IMAGE_FORMAT = png 226 | DOT_PATH = 227 | DOTFILE_DIRS = 228 | MSCFILE_DIRS = 229 | DOT_GRAPH_MAX_NODES = 50 230 | MAX_DOT_GRAPH_DEPTH = 0 231 | DOT_TRANSPARENT = NO 232 | DOT_MULTI_TARGETS = NO 233 | GENERATE_LEGEND = YES 234 | DOT_CLEANUP = YES 235 | -------------------------------------------------------------------------------- /dub/assets/lua/class.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * MACHINE GENERATED FILE. DO NOT EDIT. 4 | * 5 | * Bindings for class {{class.name}} 6 | * 7 | * This file has been generated by dub {{dub.VERSION}}. 8 | */ 9 | #include "dub/dub.h" 10 | {% for h in self:headers(class) do %} 11 | #include "{{self:header(h)}}" 12 | {% end %} 13 | 14 | {% if class:namespace() then %} 15 | using namespace {{class:namespace().name}}; 16 | {% end %} 17 | 18 | {% for method in class:methods() do %} 19 | /** {{method:nameWithArgs()}} 20 | * {{method.location}} 21 | */ 22 | static int {{class.name}}_{{method.cname}}(lua_State *{{self.L}}) { 23 | {% if method:neverThrows() then %} 24 | 25 | {| self:functionBody(class, method) |} 26 | {% else %} 27 | try { 28 | {| self:functionBody(class, method) |} 29 | } catch (std::exception &e) { 30 | lua_pushfstring({{self.L}}, "{{self:bindName(method)}}: %s", e.what()); 31 | } catch (...) { 32 | lua_pushfstring({{self.L}}, "{{self:bindName(method)}}: Unknown exception"); 33 | } 34 | return dub::error({{self.L}}); 35 | {% end %} 36 | } 37 | 38 | {% end %} 39 | 40 | {% if not class:method('__tostring') then %} 41 | 42 | // --=============================================== __tostring 43 | static int {{class.name}}___tostring(lua_State *{{self.L}}) { 44 | {| self:toStringBody(class) |} 45 | return 1; 46 | } 47 | {% end %} 48 | 49 | // --=============================================== METHODS 50 | 51 | static const struct luaL_Reg {{class.name}}_member_methods[] = { 52 | {% for method in class:methods() do %} 53 | { {{string.format('%-15s, %-20s', '"'..self:bindName(method)..'"', class.name .. '_' .. method.cname)}} }, 54 | {% end %} 55 | {% if not class:method('__tostring') then %} 56 | { {{string.format('%-15s, %-20s', '"__tostring"', class.name .. '___tostring')}} }, 57 | {% end %} 58 | { "deleted" , dub::isDeleted }, 59 | { NULL, NULL}, 60 | }; 61 | 62 | {% if class.has_constants then %} 63 | // --=============================================== CONSTANTS 64 | static const struct dub::const_Reg {{class.name}}_const[] = { 65 | {% for name, scope in class:constants() do %} 66 | { {{string.format('%-15s, %-20s', '"'.. self:constName(name, scope) ..'"', scope .. '::' .. name)}} }, 67 | {% end %} 68 | { NULL, 0}, 69 | }; 70 | {% end %} 71 | 72 | DUB_EXPORT int luaopen_{{self:openName(class)}}(lua_State *{{self.L}}) 73 | { 74 | // Create the metatable which will contain all the member methods 75 | luaL_newmetatable({{self.L}}, "{{self:libName(class)}}"); 76 | // 77 | {% if class.has_constants then %} 78 | // register class constants 79 | dub::register_const({{self.L}}, {{class.name}}_const); 80 | {% end %} 81 | 82 | // register member methods 83 | dub::fregister({{self.L}}, {{ class.name }}_member_methods); 84 | // setup meta-table 85 | dub::setup({{self.L}}, "{{self:libName(class)}}"); 86 | // 87 | return 1; 88 | } 89 | -------------------------------------------------------------------------------- /dub/assets/lua/dub/dub.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | This file is part of the DUB bindings generator (http://lubyk.org/dub) 5 | Copyright (c) 2007-2012 by Gaspard Bucher (http://teti.ch). 6 | 7 | ------------------------------------------------------------------------------ 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | ============================================================================== 28 | */ 29 | #ifndef DUB_BINDING_GENERATOR_DUB_H_ 30 | #define DUB_BINDING_GENERATOR_DUB_H_ 31 | 32 | #include // strlen strcmp 33 | 34 | #ifndef DUB_ASSERT_KEY 35 | #define DUB_ASSERT_KEY(k, m) strcmp(k, m) 36 | // Use this to avoid the overhead of strcmp in get/set of public attributes. 37 | // if you avoid strcmp, bad keys can map to any other key. 38 | //#define DUB_ASSERT_KEY(k, m) false 39 | #endif 40 | #define KEY_EXCEPTION_MSG "invalid key '%s'" 41 | 42 | typedef int LuaStackSize; 43 | 44 | #ifndef DUB_EXPORT 45 | #ifdef _WIN32 46 | #define DUB_EXPORT extern "C" __declspec(dllexport) 47 | #else 48 | #define DUB_EXPORT extern "C" 49 | #endif 50 | #endif 51 | 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | // We need C linkage because lua lib is compiled as C code 56 | #include 57 | #include 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #include // std::string for Exception 63 | #include // std::exception 64 | 65 | // Helpers to check for explicit 'false' or 'true' return values. 66 | #define lua_isfalse(L,i) (lua_isboolean(L,i) && !lua_toboolean(L,i)) 67 | #define lua_istrue(L,i) (lua_isboolean(L,i) && lua_toboolean(L,i)) 68 | #define luaL_checkboolean(L,n) (lua_toboolean(L,n)) 69 | 70 | struct DubUserdata { 71 | void *ptr; 72 | bool gc; 73 | }; 74 | 75 | // ====================================================================== 76 | // =============================================== dub::Exception 77 | // ====================================================================== 78 | namespace dub { 79 | 80 | /** All exceptions raised by dub::check.. are instances of this class. All 81 | * exceptions deriving from std::exception have their message displayed 82 | * in Lua (through lua_error). 83 | */ 84 | class Exception : public std::exception { 85 | std::string message_; 86 | public: 87 | explicit Exception(const char *format, ...); 88 | ~Exception() throw(); 89 | const char* what() const throw(); 90 | }; 91 | 92 | class TypeException : public Exception { 93 | public: 94 | explicit TypeException(lua_State *L, int narg, const char *type, bool is_super = false); 95 | }; 96 | 97 | /** This class allows an object to be deleted from either C++ or Lua. 98 | * When Lua deletes the object, dub_destroy is called. When C++ deletes 99 | * the object, the related userdata is invalidated. 100 | */ 101 | class Object { 102 | public: 103 | Object() : dub_userdata_(NULL) {} 104 | 105 | /** The destructor marks the userdata as deleted so that Lua no 106 | * longer tries to access it. 107 | */ 108 | virtual ~Object() { 109 | if (dub_userdata_) { 110 | // Protect from gc. 111 | dub_userdata_->gc = false; 112 | // Invalidate Lua userdata. 113 | dub_userdata_->ptr = NULL; 114 | } 115 | } 116 | 117 | /** This is called on object instanciation by dub instead of 118 | * dub::pushudata to setup dub_userdata_. 119 | * 120 | */ 121 | void dub_pushobject(lua_State *L, void *ptr, const char *type_name, bool gc = true); 122 | 123 | protected: 124 | /** Pointer to the userdata. *userdata => pointer to C++ object. 125 | */ 126 | DubUserdata *dub_userdata_; 127 | }; 128 | 129 | /** This class creates a 'self' table and prepares a thread 130 | * that can be used for callbacks from C++ to Lua. 131 | */ 132 | class Thread : public Object { 133 | public: 134 | Thread() 135 | : dub_L(NULL) {} 136 | /** This is called on object instanciation by dub to create the lua 137 | * thread, prepare the table and setup metamethods. This is 138 | * called instead of dub::pushudata. 139 | * 140 | */ 141 | void dub_pushobject(lua_State *L, void *ptr, const char *type_name, bool gc = true); 142 | 143 | /** Push function 'name' found in on the stack with as 144 | * first argument. 145 | * 146 | * Constness is there to make it easy to implement callbacks like 147 | * int rowCount() const, without requiring users to fiddle with constness 148 | * which is not a notion part of Lua anyway. 149 | */ 150 | bool dub_pushcallback(const char *name) const; 151 | 152 | /** Push any lua value from self on the stack. 153 | */ 154 | void dub_pushvalue(const char *name) const; 155 | 156 | /** Execute the protected call. If an error occurs, dub tries to find 157 | * an 'error' function in and calls this function with the 158 | * error string. If no error function is found, the error message is 159 | * just printed out to stderr. 160 | */ 161 | bool dub_call(int param_count, int retval_count) const; 162 | 163 | /** Lua thread that contains on stack position 1. This lua thread 164 | * is public to ease object state manipulation from C++ (but stack *must 165 | * not* be messed up). 166 | */ 167 | lua_State *dub_L; 168 | 169 | protected: 170 | /** Type name (allows faster check for cast). 171 | */ 172 | const char *dub_typename_; 173 | }; 174 | 175 | // ====================================================================== 176 | // =============================================== dub::pushclass 177 | // ====================================================================== 178 | 179 | // To ease storing a LuaRef in a void* pointer. 180 | struct DubRef { 181 | int ref; 182 | 183 | static int set(lua_State *L, void **ptr, int id) { 184 | if (lua_isnil(L, id)) { 185 | cleanup(L, ptr); 186 | } else { 187 | DubRef *ref; 188 | if (*ptr) { 189 | ref = (DubRef*)*ptr; 190 | luaL_unref(L, LUA_REGISTRYINDEX, ref->ref); 191 | } else { 192 | ref = new DubRef(); 193 | *ptr = ref; 194 | } 195 | ref->ref = luaL_ref(L, LUA_REGISTRYINDEX); 196 | } 197 | return 0; 198 | } 199 | 200 | static int push(lua_State *L, void *ptr) { 201 | if (ptr) { 202 | DubRef *ref = (DubRef*)ptr; 203 | lua_rawgeti(L, LUA_REGISTRYINDEX, ref->ref); 204 | return 1; 205 | } else { 206 | return 0; 207 | } 208 | } 209 | 210 | static void cleanup(lua_State *L, void **ptr) { 211 | if (*ptr) { 212 | DubRef *ref = (DubRef*)*ptr; 213 | luaL_unref(L, LUA_REGISTRYINDEX, ref->ref); 214 | delete ref; 215 | *ptr = NULL; 216 | } 217 | } 218 | }; 219 | 220 | /** Push a custom type on the stack. 221 | * Since the value is passed as a pointer, we assume it has been created 222 | * using 'new' and Lua can safely call delete when it needs to garbage- 223 | * -collect it. 224 | * 225 | * Constness: we const cast all passed values to ease passing read-only 226 | * arguments without requiring users to fiddle with constness which is not 227 | * a notion part of Lua anyway. 228 | */ 229 | void pushudata(lua_State *L, const void *ptr, const char *type_name, bool gc = true); 230 | 231 | template 232 | struct DubFullUserdata { 233 | T *ptr; 234 | T obj; 235 | }; 236 | 237 | template 238 | void pushfulldata(lua_State *L, const T &obj, const char *type_name) { 239 | DubFullUserdata *copy = (DubFullUserdata*)lua_newuserdata(L, sizeof(DubFullUserdata)); 240 | copy->obj = obj; 241 | // now **copy gives back the object. 242 | copy->ptr = ©->obj; 243 | 244 | // the userdata is now on top of the stack 245 | 246 | // set metatable (contains methods) 247 | luaL_getmetatable(L, type_name); 248 | lua_setmetatable(L, -2); 249 | } 250 | 251 | template 252 | void pushclass(lua_State *L, const T &obj, const char *type_name) { 253 | T *copy = new T(obj); 254 | pushudata(L, (void*)copy, type_name); 255 | } 256 | 257 | // ====================================================================== 258 | // =============================================== dub::pushclass2 259 | // ====================================================================== 260 | 261 | /** Push a custom type on the stack and give it the pointer to the userdata. 262 | * Passing the userdata enables early deletion from C++ that safely 263 | * invalidates the userdatum by calling 264 | */ 265 | template 266 | void pushclass2(lua_State *L, T *ptr, const char *type_name) { 267 | T **userdata = (T**)lua_newuserdata(L, sizeof(T*)); 268 | *userdata = ptr; 269 | 270 | // Store pointer in class so that it can set it to NULL on destroy with 271 | // *userdata = NULL 272 | ptr->luaInit((void**)userdata); 273 | // 274 | luaL_getmetatable(L, type_name); 275 | // 276 | lua_setmetatable(L, -2); 277 | // 278 | } 279 | 280 | // ====================================================================== 281 | // =============================================== constants 282 | // ====================================================================== 283 | 284 | typedef struct const_Reg { 285 | const char *name; 286 | double value; 287 | } const_Reg; 288 | 289 | // register constants in the table at the top 290 | void register_const(lua_State *L, const const_Reg *l); 291 | 292 | // ====================================================================== 293 | // =============================================== dub_check ... 294 | // ====================================================================== 295 | 296 | // These provide the same funcionality as their equivalent luaL_check... but they 297 | // throw std::exception which can be caught (eventually to call lua_error). 298 | lua_Number checknumber(lua_State *L, int narg) throw(dub::TypeException); 299 | lua_Integer checkinteger(lua_State *L, int narg) throw(dub::TypeException); 300 | const char *checklstring(lua_State *L, int narg, size_t *len) throw(dub::TypeException); 301 | void **checkudata(lua_State *L, int ud, const char *tname, bool keep_mt = false) throw(dub::Exception); 302 | 303 | // Super aware userdata calls (finds userdata inside provided table with table.super). 304 | void **checksdata(lua_State *L, int ud, const char *tname, bool keep_mt = false) throw(dub::Exception); 305 | // Super aware userdata calls that DOES NOT check for dangling pointers (used in 306 | // __gc binding). 307 | void **checksdata_d(lua_State *L, int ud, const char *tname) throw(dub::Exception); 308 | // Return pointer if the type is correct. Used to resolve overloaded functions when there 309 | // is no other alternative (arg count, native types). We return the pointer so that we can 310 | // optimize away the corresponding 'dub_checksdata'. 311 | void **issdata(lua_State *L, int ud, const char *tname, int type); 312 | // Does not throw exceptions. This method behaves exactly like luaL_checkudata but searches 313 | // for table.super before calling lua_error. We cannot use throw() because of differing 314 | // implementations for luaL_error (luajit throws an exception on luaL_error). 315 | void **checksdata_n(lua_State *L, int ud, const char *tname, bool keep_mt = false); 316 | 317 | inline const char *checkstring(lua_State *L, int narg) throw(dub::TypeException) { 318 | return checklstring(L, narg, NULL); 319 | } 320 | 321 | inline int checkboolean(lua_State *L, int narg) throw() { 322 | return lua_toboolean(L, narg); 323 | } 324 | 325 | // This calls lua_Error after preparing the error message with line 326 | // and number. 327 | int error(lua_State *L); 328 | 329 | // This is a Lua binding called whenever we ask for obj:deleted() in Lua 330 | int isDeleted(lua_State *L); 331 | 332 | /** Protect garbage collection from pointers stored in objects or 333 | * retrieved in userdata copies. 334 | */ 335 | void protect(lua_State *L, int owner, int original, const char *key); 336 | 337 | /** Prepare index function, setup 'type' field and __call metamethod. 338 | */ 339 | void setup(lua_State *L, const char *class_name); 340 | 341 | // sdbm function: taken from http://www.cse.yorku.ca/~oz/hash.html 342 | // This version is slightly adapted to cope with different 343 | // hash sizes (and to be easy to write in Lua). 344 | int hash(const char *str, int sz); 345 | 346 | // Simple debugging function to print stack content. 347 | void printStack(lua_State *L, const char *msg = NULL); 348 | 349 | // Compatibility with luaL_register on lua 5.1 and 5.2 350 | void fregister(lua_State *L, const luaL_Reg *l); 351 | 352 | 353 | } // dub 354 | 355 | #endif // DUB_BINDING_GENERATOR_DUB_H_ 356 | 357 | -------------------------------------------------------------------------------- /dub/assets/lua/lib.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * MACHINE GENERATED FILE. DO NOT EDIT. 4 | * 5 | * Bindings for library {{lib_name}} 6 | * 7 | * This file has been generated by dub {{dub.VERSION}}. 8 | */ 9 | #include "dub/dub.h" 10 | {% for h in self:headers() do %} 11 | #include "{{self:header(h)}}" 12 | {% end %} 13 | 14 | {% for namespace in lib:namespaces() do %} 15 | using namespace {{namespace.name}}; 16 | {% end %} 17 | 18 | extern "C" { 19 | {% for _, class in ipairs(classes) do %} 20 | int luaopen_{{self:openName(class)}}(lua_State *{{self.L}}); 21 | {% end %} 22 | } 23 | 24 | {% for method in lib:functions() do %} 25 | /** {{method:nameWithArgs()}} 26 | * {{method.location}} 27 | */ 28 | static int {{string.gsub(method:fullcname(), '::', '_')}}(lua_State *{{self.L}}) { 29 | {% if method:neverThrows() then %} 30 | 31 | {| self:functionBody(method) |} 32 | {% else %} 33 | try { 34 | {| self:functionBody(method) |} 35 | } catch (std::exception &e) { 36 | lua_pushfstring({{self.L}}, "{{self:libName(method)}}: %s", e.what()); 37 | } catch (...) { 38 | lua_pushfstring({{self.L}}, "{{self:libName(method)}}: Unknown exception"); 39 | } 40 | return lua_error({{self.L}}); 41 | {% end %} 42 | } 43 | 44 | {% end %} 45 | // --=============================================== FUNCTIONS 46 | {% if lib.type == 'dub.Namespace' then %} 47 | // Functions from namespace {{lib.name}} 48 | {% end %} 49 | static const struct luaL_Reg {{lib_name}}_functions[] = { 50 | {% for method in lib:functions() do %} 51 | { {{string.format('%-15s, %-20s', '"'..self:bindName(method)..'"', string.gsub(method:fullcname(), '::', '_'))}} }, 52 | {% end %} 53 | { NULL, NULL}, 54 | }; 55 | 56 | {% if lib.has_constants then %} 57 | // --=============================================== CONSTANTS 58 | {% if lib.type == 'dub.Namespace' then %} 59 | // Functions from namespace {{lib.name}} 60 | {% end %} 61 | static const struct dub::const_Reg {{lib_name}}_const[] = { 62 | {% for name, scope in lib:constants() do %} 63 | { {{string.format('%-15s, %-20s', '"'.. self:constName(name, scope) ..'"', scope .. '::' .. name)}} }, 64 | {% end %} 65 | { NULL, 0}, 66 | }; 67 | {% end %} 68 | 69 | DUB_EXPORT int luaopen_{{self.options.luaopen or lib_name}}(lua_State *{{self.L}}) { 70 | lua_newtable({{self.L}}); 71 | // 72 | {% if lib.has_constants then %} 73 | // register global constants 74 | dub::register_const({{self.L}}, {{lib_name}}_const); 75 | {% end %} 76 | dub::fregister({{self.L}}, {{lib_name}}_functions); 77 | // 78 | 79 | {{ self:openClasses(classes) }} 80 | // 81 | return 1; 82 | } 83 | -------------------------------------------------------------------------------- /scripts/build.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Update build files for this project 3 | -- 4 | local lut = require 'lut' 5 | local lib = require 'dub' 6 | 7 | lut.Builder(lib):make() 8 | -------------------------------------------------------------------------------- /scripts/doc.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Generate documentation for this project into 'html' folder 3 | -- 4 | local lut = require 'lut' 5 | lut.Doc.make { 6 | sources = { 7 | 'dub', 8 | }, 9 | target = 'html', 10 | format = 'html', 11 | header = [[

Lubyk documentation

]], 12 | index = [=[ 13 | --[[-- 14 | # Lubyk documentation 15 | 16 | ## List of available modules 17 | --]]-- 18 | ]=] 19 | } 20 | -------------------------------------------------------------------------------- /test/all.lua: -------------------------------------------------------------------------------- 1 | local lub = require 'lub' 2 | local lut = require 'lut' 3 | local dub = require 'dub' 4 | 5 | dub.warn_level = 4 6 | dub_test = {} 7 | 8 | for _, k in ipairs(arg) do 9 | if k == '--speed' then 10 | test_speed = true 11 | end 12 | end 13 | 14 | lut.Test.files(lub.path '|') 15 | 16 | -------------------------------------------------------------------------------- /test/class_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Class 4 | --------- 5 | 6 | ... 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local lut = require 'lut' 11 | local dub = require 'dub' 12 | 13 | local should = lut.Test 'dub.Class' 14 | 15 | local ins = dub.Inspector { 16 | doc_dir = 'test/tmp', 17 | INPUT = { 18 | 'test/fixtures/simple/include', 19 | 'test/fixtures/constants', 20 | 'test/fixtures/namespace', 21 | 'test/fixtures/inherit', 22 | }, 23 | } 24 | 25 | local Simple = ins:find('Simple') 26 | local Car = ins:find('Car') 27 | local A = ins:find('Nem::A') 28 | local Child = ins:find('Child') 29 | 30 | --=============================================== TESTS 31 | function should.autoload() 32 | assertType('table', dub.Class) 33 | end 34 | 35 | function should.createClass() 36 | local c = dub.Class() 37 | assertEqual('dub.Class', c.type) 38 | end 39 | 40 | function should.inheritNewInSubClass() 41 | local Sub = setmetatable({}, dub.Class) 42 | local c = Sub() 43 | assertEqual('dub.Class', c.type) 44 | end 45 | 46 | function should.beAClass() 47 | assertEqual('dub.Class', Simple.type) 48 | end 49 | 50 | function should.detectConscructor() 51 | local method = Simple:method('Simple') 52 | assertTrue(method.ctor) 53 | end 54 | 55 | function should.detectDestructor() 56 | local method = Simple:method('~Simple') 57 | assertTrue(method.dtor) 58 | end 59 | 60 | function should.listMethods() 61 | local m 62 | for method in Simple:methods() do 63 | if method.name == 'setValue' then 64 | m = method 65 | break 66 | end 67 | end 68 | assertEqual(m, Simple:method('setValue')) 69 | end 70 | 71 | function should.notListIgnoredMethods() 72 | local m 73 | for method in Child:methods() do 74 | if method.name == 'virtFunc' then 75 | fail("Method 'virtFunc' ignored but listed by 'methods()' iterator") 76 | end 77 | end 78 | assertTrue(true) 79 | end 80 | 81 | function should.haveHeader() 82 | local path = lub.absolutizePath(lub.path '|fixtures/simple/include/simple.h') 83 | assertEqual(path, Simple.header) 84 | end 85 | 86 | function should.detectDestructor() 87 | local method = Simple:method('~Simple') 88 | assertTrue(Simple:isDestructor(method)) 89 | end 90 | 91 | function should.respondToAttributes() 92 | local r = {} 93 | for att in Car:attributes() do 94 | lub.insertSorted(r, att.name) 95 | end 96 | assertValueEqual({ 97 | 'brand', 98 | 'name_', 99 | }, r) 100 | end 101 | 102 | function should.respondToAttributes() 103 | local r = {} 104 | for att in car:attributes() do 105 | lub.insertSorted(r, att.name) 106 | end 107 | assertValueEqual({ 108 | 'brand', 109 | 'name_', 110 | }, r) 111 | end 112 | 113 | function should.respondToConstants() 114 | local r = {} 115 | for c in Car:constants() do 116 | lub.insertSorted(r, c) 117 | end 118 | assertValueEqual({ 119 | 'Dangerous', 120 | 'Noisy', 121 | 'Polluty', 122 | 'Smoky', 123 | }, r) 124 | end 125 | 126 | function should.respondToFindChild() 127 | local f = Car:findChild 'setBrand' 128 | assertEqual('dub.Function', f.type) 129 | end 130 | 131 | function should.respondToNamespace() 132 | local n = A:namespace() 133 | assertEqual('dub.Namespace', n.type) 134 | end 135 | 136 | function should.respondToNeedCast() 137 | assertFalse(A:needCast()) 138 | assertTrue(Child:needCast()) 139 | end 140 | 141 | should:test() 142 | 143 | -------------------------------------------------------------------------------- /test/dub_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub test 4 | -------- 5 | 6 | Run all tests, test some helpers. 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local lut = require 'lut' 11 | local dub = require 'dub' 12 | 13 | local should = lut.Test 'dub' 14 | 15 | -- These functions are private: no coverage testing. 16 | should.ignore.warn = true 17 | should.ignore.printWarn = true 18 | should.ignore.silentWarn = true 19 | 20 | function should.findMinHash() 21 | assertEqual(6, dub.minHash {'a', 'b', 'ab', 'ca'}) 22 | assertEqual(14, dub.minHash {'a', 'b', 'ab', 'ac', 'ca'}) 23 | assertEqual(14, dub.minHash {'a', 'b', 'ab', 'ac', 'ca', 'bobli'}) 24 | assertEqual(14, dub.minHash {'a', 'b', 'ab', 'ac', 'ca', 'bobli', 'malc'}) 25 | assertEqual(3, dub.minHash {'name_', 'size_'}) 26 | end 27 | 28 | function should.findMinHashWithDuplicates() 29 | assertEqual(6, dub.minHash {'a', 'a', 'b', 'ab', 'ca'}) 30 | end 31 | 32 | function should.returnNilMinHashOnEmptyList() 33 | assertNil(dub.minHash {}) 34 | end 35 | 36 | function should.hash() 37 | local sz = 14 38 | assertEqual(13, dub.hash('a',14)) 39 | assertEqual(0, dub.hash('b',14)) 40 | assertEqual(5, dub.hash('ab',14)) 41 | assertEqual(6, dub.hash('ac',14)) 42 | assertEqual(8, dub.hash('ca',14)) 43 | assertEqual(0, dub.hash('name_',5)) 44 | assertEqual(1, dub.hash('birth_year',2)) 45 | end 46 | 47 | should:test() 48 | 49 | -------------------------------------------------------------------------------- /test/fixtures/constants/Car.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_CAR_H_ 2 | #define CONSTANTS_CAR_H_ 3 | 4 | #include 5 | 6 | /** This class is used to test: 7 | * * class constants (enums). 8 | * * enum attributes read/write. 9 | * * alternate binding definition (using Car.new instead of Car()) 10 | * * rename attribute filter. 11 | */ 12 | class Car { 13 | public: 14 | 15 | /** List of Car brands. 16 | */ 17 | enum Brand { 18 | Smoky, 19 | Polluty, 20 | Noisy, 21 | Dangerous, 22 | }; 23 | 24 | /** Accessors should understand that Brand is an integer. 25 | */ 26 | Brand brand; 27 | 28 | std::string name_; 29 | 30 | Car(const char * n, Brand b = Polluty) 31 | : brand(b) 32 | , name_(n) { 33 | } 34 | 35 | void setBrand(Brand b) { 36 | brand = b; 37 | } 38 | 39 | const char *brandName() { 40 | switch(brand) { 41 | case Smoky: 42 | return "Smoky"; 43 | case Polluty: 44 | return "Polluty"; 45 | case Noisy: 46 | return "Noisy"; 47 | case Dangerous: 48 | return "Dangerous"; 49 | default: 50 | return "???"; 51 | } 52 | } 53 | }; 54 | 55 | #endif // CONSTANTS_CAR_H_ 56 | 57 | -------------------------------------------------------------------------------- /test/fixtures/constants/types.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_TYPES_H_ 2 | #define CONSTANTS_TYPES_H_ 3 | 4 | /** Constants that should be accessible by libname.ConstName 5 | * or GlobalConstant.ConstName if no lib is provided. 6 | */ 7 | enum GlobalConstant { 8 | One = 1, 9 | Two, 10 | Three = 55, 11 | }; 12 | 13 | #endif // CONSTANTS_TYPES_H_ 14 | -------------------------------------------------------------------------------- /test/fixtures/inherit/Child.h: -------------------------------------------------------------------------------- 1 | #ifndef INHERIT_CHILD_H_ 2 | #define INHERIT_CHILD_H_ 3 | 4 | // Simulate complex inclusion (think external lib) 5 | // This class needs the "../inherit_hidden/Mother.h" header to compile. 6 | class Mother; 7 | 8 | #include "Parent.h" 9 | 10 | #include 11 | 12 | /** This class is used to test: 13 | * * attribute inheritance 14 | * * method inheritance 15 | * * custom bindings 16 | * * unknown types 17 | * * ignore methods from parent 18 | * 19 | * Since Doxygen does not know that Mother is a Parent, we tell this. We also 20 | * use 'mixin' of custom bindings from ChildHelper. 21 | * @dub super: Parent, ChildHelper, Mother 22 | * ignore: virtFunc 23 | */ 24 | class Child : public Mother { 25 | // Private attribute 26 | double pos_x_; 27 | double pos_y_; 28 | public: 29 | // public attribute (child should inherit this) 30 | double teeth; 31 | 32 | Child(const std::string &name, MaritalStatus s, int birth_year, double x, double y); 33 | 34 | virtual ~Child() {} 35 | 36 | double x() { 37 | return pos_x_; 38 | } 39 | 40 | double y() { 41 | return pos_y_; 42 | } 43 | 44 | /** Unknown Unk1 type. 45 | */ 46 | Unk1 returnUnk1(double value) { 47 | return Unk1(value); 48 | } 49 | 50 | /** Unknown Unk2 type. 51 | */ 52 | Unk2 returnUnk2(double value) { 53 | return Unk2(value); 54 | } 55 | 56 | /** Unknown arguments. 57 | */ 58 | double methodWithUnknown(Unk1 x, Unk2 *y) { 59 | return x.value() + y->value(); 60 | } 61 | 62 | /** Should not inherit overloaded/virtuals twice. 63 | */ 64 | std::string name(); 65 | }; 66 | 67 | /** This class should have set/get methods defined 68 | * because it inherits attributes from its parents. 69 | */ 70 | class GrandChild : public Child { 71 | public: 72 | }; 73 | #endif // INHERIT_CHILD_H_ 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/fixtures/inherit/ChildHelper.h: -------------------------------------------------------------------------------- 1 | /** This is not a real C++ class. It is used to add custom methods to Child. 2 | * 3 | * This tells to not make bindings for this class and not try to cast. 4 | * @dub bind: false 5 | * cast: false 6 | */ 7 | class ChildHelper { 8 | public: 9 | // Special method with multiple return values. 10 | LuaStackSize position(); 11 | 12 | // Custom bindings with default values. 13 | double addToX(double n=4); 14 | }; 15 | -------------------------------------------------------------------------------- /test/fixtures/inherit/ChildHelper.yml: -------------------------------------------------------------------------------- 1 | lua: 2 | methods: 3 | position: | 4 | lua_pushnumber(L, self->x()); 5 | lua_pushnumber(L, self->y()); 6 | return 2; 7 | addToX: 8 | arg0: | 9 | lua_pushnumber(L, self->x() + 4.0); 10 | return 1; 11 | arg1: | 12 | lua_pushnumber(L, self->x() + n); 13 | return 1; 14 | -------------------------------------------------------------------------------- /test/fixtures/inherit/GrandParent.h: -------------------------------------------------------------------------------- 1 | #ifndef INHERIT_GRAND_PARENT_H_ 2 | #define INHERIT_GRAND_PARENT_H_ 3 | 4 | #include "Object.h" 5 | #include 6 | 7 | /** This class is used to test: 8 | * * attribute inheritance 9 | * * method inheritance 10 | */ 11 | class GrandParent : protected Object { 12 | public: 13 | // public attribute (all children should inherit this) 14 | double birth_year; 15 | 16 | GrandParent(int y) 17 | : birth_year(y) {} 18 | 19 | /** Method that should be inherited by all children. 20 | */ 21 | int computeAge(int current_year) { 22 | return current_year - birth_year; 23 | } 24 | }; 25 | 26 | #endif // INHERIT_GRAND_PARENT_H_ 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/fixtures/inherit/Object.h: -------------------------------------------------------------------------------- 1 | #ifndef INHERIT_OBJECT_H_ 2 | #define INHERIT_OBJECT_H_ 3 | 4 | #include 5 | 6 | /** This class is used to test: 7 | * * make sure non public inheritance is not followed. 8 | */ 9 | class Object { 10 | public: 11 | // public attribute (all children should inherit this) 12 | double memory; 13 | 14 | void checkMemory() { 15 | if (!memory) { 16 | printf("None left!\n"); 17 | } 18 | } 19 | }; 20 | 21 | #endif // INHERIT_OBJECT_H_ 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/fixtures/inherit/Orphan.h: -------------------------------------------------------------------------------- 1 | #ifndef INHERIT_UNKNOWN_PARENT_H_ 2 | #define INHERIT_UNKNOWN_PARENT_H_ 3 | 4 | // Simulate complex inclusion (think external lib) 5 | #include "../inherit_hidden/Mother.h" 6 | 7 | #include 8 | 9 | template 10 | class Foo { 11 | }; 12 | 13 | class Bar { 14 | }; 15 | /** This class is used to test: 16 | * * unresolved super class (no typedef). 17 | * * multiple super classes. 18 | * 19 | * @dub super: Foo< int > 20 | */ 21 | class Orphan : public Foo, public Bar { 22 | public: 23 | Orphan() {} 24 | }; 25 | 26 | #endif // INHERIT_UNKNOWN_PARENT_H_ 27 | 28 | -------------------------------------------------------------------------------- /test/fixtures/inherit/Parent.h: -------------------------------------------------------------------------------- 1 | #ifndef INHERIT_PARENT_H_ 2 | #define INHERIT_PARENT_H_ 3 | 4 | #include "GrandParent.h" 5 | 6 | #include 7 | 8 | /** This class is used to test: 9 | * * attribute inheritance 10 | * * method inheritance 11 | */ 12 | class Parent : public GrandParent { 13 | // Private attribute 14 | std::string name_; 15 | public: 16 | enum MaritalStatus { 17 | Single, 18 | Married, 19 | Poly, 20 | Depends, 21 | }; 22 | 23 | // public attribute (child should inherit this) 24 | MaritalStatus status; 25 | 26 | // test boolean attribute 27 | bool happy; 28 | 29 | Parent(const std::string &name, MaritalStatus status_, int birth_year) 30 | : GrandParent(birth_year) 31 | , name_(name) 32 | , status(status_) 33 | , happy(true) 34 | {} 35 | 36 | virtual ~Parent() {} 37 | 38 | /** Method that should be inherited by child. 39 | */ 40 | std::string name() { 41 | return name_; 42 | } 43 | 44 | /** Static method that should not be inherited. 45 | */ 46 | static std::string getName(Parent *parent) { 47 | return parent->name_; 48 | } 49 | 50 | virtual void virtFunc() { 51 | } 52 | }; 53 | 54 | #endif // INHERIT_PARENT_H_ 55 | 56 | 57 | -------------------------------------------------------------------------------- /test/fixtures/inherit/child.cpp: -------------------------------------------------------------------------------- 1 | #include "../inherit_hidden/Mother.h" 2 | #include "Child.h" 3 | #include 4 | 5 | Child::Child(const std::string &name, MaritalStatus s, int birth_year, double x, double y) 6 | : Mother(name, s, birth_year) 7 | , pos_x_(x) 8 | , pos_y_(y) {} 9 | 10 | std::string Child::name() { 11 | return std::string("Child ").append(Parent::name()); 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/inherit_hidden/Mother.h: -------------------------------------------------------------------------------- 1 | #ifndef INHERIT_HIDDEN_MOTHER_H_ 2 | #define INHERIT_HIDDEN_MOTHER_H_ 3 | 4 | #include "Parent.h" 5 | 6 | #include 7 | 8 | /** This class is not seen by Doxygen and is used to 'explain' inheritance 9 | * of Parent by Child through the 'super' key in dub header doc. 10 | */ 11 | class Mother : public Parent { 12 | public: 13 | Mother(const std::string &name, MaritalStatus s, int birth_year) 14 | : Parent(name, s, birth_year) {} 15 | }; 16 | 17 | 18 | /** This class is not seed by Doxygen or Dub. Instances of this class 19 | * are passed around as opaque types. 20 | */ 21 | class Unk1 { 22 | double v_; 23 | public: 24 | Unk1(double v) : v_(v) {} 25 | double value() { 26 | return v_; 27 | } 28 | }; 29 | 30 | typedef Unk1 Unk2; 31 | 32 | #endif // INHERIT_HIDDEN_MOTHER_H_ 33 | 34 | -------------------------------------------------------------------------------- /test/fixtures/memory/CustomDtor.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_CUSTOM_DTOR_H_ 2 | #define MEMORY_CUSTOM_DTOR_H_ 3 | 4 | #include "dub/dub.h" 5 | 6 | /** This class is used to test: 7 | * * Custom destructors. 8 | * 9 | * @dub push: dub_pushobject 10 | * destructor: finalize 11 | */ 12 | class CustomDtor : public dub::Thread { 13 | public: 14 | CustomDtor() {} 15 | 16 | ~CustomDtor() {} 17 | 18 | void finalize() { 19 | if (dub_pushcallback("callback")) { 20 | // 21 | dub_call(1, 0); 22 | } 23 | delete this; 24 | } 25 | }; 26 | #endif // MEMORY_CUSTOM_DTOR_H_ 27 | -------------------------------------------------------------------------------- /test/fixtures/memory/NoDtor.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_NO_DTOR_H_ 2 | #define MEMORY_NO_DTOR_H_ 3 | 4 | #include "dub/dub.h" 5 | 6 | class NoDtor; 7 | 8 | /** @dub push: dub_pushobject 9 | * ignore: dead 10 | */ 11 | class NoDtorCleaner : public dub::Thread { 12 | NoDtor *ndt_; 13 | public: 14 | NoDtorCleaner(NoDtor *ndt); 15 | 16 | ~NoDtorCleaner() { 17 | cleanup(); 18 | } 19 | 20 | void cleanup(); 21 | 22 | void dead(NoDtor *obj); 23 | }; 24 | 25 | /** This class is used to test: 26 | * * Removing destructor. 27 | * 28 | * @dub destructor: false 29 | * ignore: s_ 30 | */ 31 | class NoDtor { 32 | friend class NoDtorCleaner; 33 | NoDtorCleaner *cleaner_; 34 | public: 35 | std::string s_; 36 | 37 | NoDtor(const char *s) 38 | : cleaner_(NULL) 39 | , s_(s) { 40 | } 41 | 42 | ~NoDtor() { 43 | if (cleaner_) { 44 | cleaner_->dead(this); 45 | } 46 | } 47 | }; 48 | 49 | inline NoDtorCleaner::NoDtorCleaner(NoDtor *ndt) 50 | : ndt_(ndt) { 51 | ndt->cleaner_ = this; 52 | } 53 | 54 | inline void NoDtorCleaner::dead(NoDtor *obj) { 55 | if (dub_pushcallback("callback")) { 56 | lua_pushstring(dub_L, obj->s_.c_str()); 57 | // 58 | dub_call(2, 0); 59 | } 60 | } 61 | 62 | inline void NoDtorCleaner::cleanup() { 63 | if (ndt_) { 64 | delete ndt_; 65 | ndt_ = NULL; 66 | } 67 | } 68 | 69 | #endif // MEMORY_NO_DTOR_H_ 70 | 71 | -------------------------------------------------------------------------------- /test/fixtures/memory/Nogc.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_NOGC_H_ 2 | #define MEMORY_NOGC_H_ 3 | 4 | /** This class is used to test: 5 | * * no gc optimization 6 | * 7 | * @dub destroy: 'free' 8 | */ 9 | struct Nogc { 10 | double x; 11 | double y; 12 | 13 | Nogc(double x_, double y_) 14 | : x(x_) 15 | , y(y_) 16 | {} 17 | 18 | double surface() { 19 | return x * y; 20 | } 21 | 22 | Nogc operator+(const Nogc &v) { 23 | return Nogc(x + v.x, y + v.y); 24 | } 25 | }; 26 | 27 | #endif // MEMORY_NOGC_H_ 28 | 29 | -------------------------------------------------------------------------------- /test/fixtures/memory/Owner.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_OWNER_H_ 2 | #define MEMORY_OWNER_H_ 3 | 4 | #include 5 | class Pen; 6 | 7 | /** This class is used to monitor: 8 | * * Deletion from C++. 9 | * * Deletion from the scripting language. 10 | */ 11 | class Owner { 12 | Pen *pen_; 13 | public: 14 | std::string message_; 15 | 16 | Owner(Pen *pen = NULL); 17 | 18 | ~Owner(); 19 | 20 | void own(Pen *pen); 21 | 22 | void setMessage(const std::string &msg) { 23 | message_ = msg; 24 | } 25 | 26 | void destroyPen(); 27 | }; 28 | #endif // MEMORY_OWNER_H_ 29 | -------------------------------------------------------------------------------- /test/fixtures/memory/Pen.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_PEN_H_ 2 | #define MEMORY_PEN_H_ 3 | 4 | #include "Owner.h" 5 | 6 | #include "dub/dub.h" 7 | #include 8 | 9 | #define SOME_FUNCTION_MACRO(x) 10 | #define OTHER_FUNCTION_MACRO(x) 11 | 12 | /** This class is used to test: 13 | * * when an object owned by the scripting language is deleted in C++. 14 | * * when an object owned by C++ is deleted in the scripting language. 15 | * * macro expansion setting 16 | * 17 | * @dub push: dub_pushobject 18 | */ 19 | class Pen : public dub::Object { 20 | std::string name_; 21 | Owner *owner_; 22 | public: 23 | Pen(const char *name) 24 | : name_(name) 25 | , owner_(NULL) {} 26 | 27 | void setOwner(Owner *owner) { 28 | owner_ = owner; 29 | } 30 | 31 | ~Pen() { 32 | if (owner_) { 33 | owner_->setMessage(std::string("Pen '").append(name_).append("' is dying...")); 34 | } 35 | } 36 | 37 | const std::string &name() { 38 | return name_; 39 | } 40 | 41 | SOME_FUNCTION_MACRO(int x); 42 | 43 | OTHER_FUNCTION_MACRO(x); 44 | 45 | /** We declare this method so that Doxygen sees it (Doxygen does not parse 46 | * dub::Object) and adds the method to the generated xml. We can then ensure 47 | * that the 'push' method is ignored even if seen. 48 | */ 49 | virtual void dub_pushobject(lua_State *L, void *ptr, const char *type_name, bool gc = true) { 50 | dub::Object::dub_pushobject(L, ptr, type_name, gc); 51 | } 52 | 53 | }; 54 | 55 | #endif // MEMORY_PEN_H_ 56 | -------------------------------------------------------------------------------- /test/fixtures/memory/PrivateDtor.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_PRIVATE_DTOR_H_ 2 | #define MEMORY_PRIVATE_DTOR_H_ 3 | 4 | #include "dub/dub.h" 5 | 6 | /** This class is used to test: 7 | * * private destructors. 8 | */ 9 | class PrivateDtor { 10 | public: 11 | PrivateDtor() {} 12 | 13 | private: 14 | ~PrivateDtor() {} 15 | }; 16 | 17 | #endif // MEMORY_PRIVATE_DTOR_H_ 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/memory/Union.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_UNION_H_ 2 | #define MEMORY_UNION_H_ 3 | 4 | #include "dub/dub.h" 5 | #include 6 | 7 | #include 8 | 9 | /** This class is used to test: 10 | * * access to anonymous union members (custom bindings) 11 | */ 12 | class Union { 13 | public: 14 | /** Anonymous union. 15 | */ 16 | union { 17 | struct { 18 | uint8_t h; 19 | uint8_t s; 20 | uint8_t v; 21 | uint8_t a; 22 | }; 23 | uint32_t c; 24 | }; 25 | 26 | Union(uint8_t _h, uint8_t _s, uint8_t _v, uint8_t _a) { 27 | h = _h; 28 | s = _s; 29 | v = _v; 30 | a = _a; 31 | } 32 | }; 33 | 34 | #endif // MEMORY_UNION_H_ 35 | 36 | -------------------------------------------------------------------------------- /test/fixtures/memory/Withgc.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_WITHGC_H_ 2 | #define MEMORY_WITHGC_H_ 3 | 4 | /** This class is used to compare execution with a __gc method 5 | * or without (Nogc version). 6 | * * no gc optimization (this one has a __gc method) 7 | * 8 | */ 9 | struct Withgc { 10 | double x; 11 | double y; 12 | 13 | Withgc(double x_, double y_) 14 | : x(x_) 15 | , y(y_) 16 | {} 17 | 18 | double surface() { 19 | return x * y; 20 | } 21 | 22 | Withgc operator+(const Withgc &v) { 23 | return Withgc(x + v.x, y + v.y); 24 | } 25 | }; 26 | 27 | #endif // MEMORY_WITHGC_H_ 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/fixtures/memory/owner.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Owner.h" 3 | #include "Pen.h" 4 | // This is only required to monitor object destruction. 5 | Owner::Owner(Pen * pen) : pen_(pen) { 6 | if (pen_) pen_->setOwner(this); 7 | } 8 | 9 | void Owner::own(Pen *pen) { 10 | pen_ = pen; 11 | pen_->setOwner(this); 12 | } 13 | 14 | Owner::~Owner() { 15 | if (pen_) { 16 | pen_->setOwner(NULL); 17 | } 18 | } 19 | 20 | void Owner::destroyPen() { 21 | if (pen_) { 22 | delete pen_; 23 | pen_ = NULL; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/fixtures/namespace/A.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMESPACE_A_H_ 2 | #define NAMESPACE_A_H_ 3 | 4 | #include "TRect.h" 5 | #include "B.h" 6 | #include 7 | 8 | namespace Nem { 9 | 10 | /** When resolving TRect to Rect, we remember the header where this 11 | * resolution happened. 12 | */ 13 | typedef TRect Rect; 14 | 15 | /** This class is used to test: 16 | * * classes in namespace 17 | * * custom __tostring method 18 | * * lua_State pseudo-parameter 19 | * * custom accessor 20 | * * overwriten methods 21 | */ 22 | class A { 23 | public: 24 | std::string name; 25 | 26 | /** We will attach any Lua value to this by writing a custom 27 | * accessor (see A.yml). 28 | */ 29 | void *userdata; 30 | 31 | A(const char *name_ = "") 32 | : name(name_) 33 | , userdata(NULL) 34 | {} 35 | 36 | LuaStackSize __tostring(lua_State *L) { 37 | lua_pushfstring(L, "", this, name.c_str()); 38 | return 1; 39 | } 40 | 41 | std::string over(A *a) { 42 | return "A"; 43 | } 44 | 45 | std::string over(B *b) { 46 | return "B"; 47 | } 48 | 49 | }; 50 | 51 | /** Nested namespace. Ignored for now. 52 | */ 53 | namespace SubNem { 54 | class X {}; 55 | } // SubNem 56 | } // Nem 57 | 58 | #endif // NAMESPACE_A_H_ 59 | -------------------------------------------------------------------------------- /test/fixtures/namespace/A.yml: -------------------------------------------------------------------------------- 1 | lua: 2 | methods: 3 | '~A': 4 | cleanup: | 5 | dub::DubRef::cleanup(L, &self->userdata); 6 | attributes: 7 | userdata: 8 | # This is an experimental feature to allow arbitrary values attached to 9 | # void* pointers. 10 | set: | 11 | return dub::DubRef::set(L, &self->userdata, 3); 12 | get: | 13 | return dub::DubRef::push(L, self->userdata); 14 | -------------------------------------------------------------------------------- /test/fixtures/namespace/B.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMESPACE_B_H_ 2 | #define NAMESPACE_B_H_ 3 | 4 | namespace Nem { 5 | 6 | class A; 7 | 8 | /** This class is used to test: 9 | * * classes in namespace 10 | * * nested classes 11 | * * custom __tostring method 12 | * * lua_State pseudo-parameter 13 | */ 14 | class B { 15 | public: 16 | int nb_; 17 | A *a; 18 | 19 | /** Nested public class. 20 | */ 21 | class C { 22 | int nb_; 23 | friend class B; 24 | public: 25 | C(int nb) 26 | : nb_(nb) 27 | {} 28 | 29 | LuaStackSize __tostring(lua_State *L) { 30 | lua_pushfstring(L, "", this, nb_); 31 | return 1; 32 | } 33 | 34 | int nb() { 35 | return nb_; 36 | } 37 | }; 38 | 39 | C *c; 40 | 41 | B(int nb) 42 | : nb_(nb) 43 | , a(NULL) 44 | , c(NULL) 45 | {} 46 | 47 | B(C *c_) 48 | : nb_(c_->nb_) 49 | , a(NULL) 50 | , c(c_) 51 | {} 52 | 53 | LuaStackSize __tostring(lua_State *L) { 54 | lua_pushfstring(L, "", this, nb_); 55 | return 1; 56 | } 57 | 58 | C *getC() { 59 | return c; 60 | } 61 | }; 62 | 63 | } // Nem 64 | #endif // NAMESPACE_B_H_ 65 | 66 | -------------------------------------------------------------------------------- /test/fixtures/namespace/Nem.yml: -------------------------------------------------------------------------------- 1 | # Custom lua bindings for Nem namespace 2 | lua: 3 | methods: 4 | customGlobal: | 5 | lua_pushnumber(L, a + b); 6 | lua_pushstring(L, "custom global"); 7 | return 2; 8 | -------------------------------------------------------------------------------- /test/fixtures/namespace/Out.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMESPACE_OUT_H_ 2 | #define NAMESPACE_OUT_H_ 3 | 4 | namespace Nem { 5 | 6 | /** A typedef defined inside the namespace. 7 | */ 8 | typedef TRect Rectf; 9 | 10 | } // Nem 11 | 12 | /** A typedef defined outside the namespace. 13 | */ 14 | typedef Nem::TRect nmRectf; 15 | 16 | #endif // NAMESPACE_OUT_H_ 17 | -------------------------------------------------------------------------------- /test/fixtures/namespace/TRect.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMESPACE_T_RECT_H_ 2 | #define NAMESPACE_T_RECT_H_ 3 | 4 | #include 5 | 6 | namespace Nem { 7 | 8 | /** This class is used to test: 9 | * * template in namespace 10 | */ 11 | template 12 | class TRect { 13 | public: 14 | T w; 15 | T h; 16 | 17 | TRect(T w_, T h_) 18 | : w(w_) 19 | , h(h_) 20 | {} 21 | }; 22 | 23 | } // Nem 24 | #endif // NAMESPACE_T_RECT_H_ 25 | 26 | -------------------------------------------------------------------------------- /test/fixtures/namespace/_global.yml: -------------------------------------------------------------------------------- 1 | lua: 2 | methods: 3 | customGlobalOut: | 4 | lua_pushnumber(L, a + b); 5 | lua_pushstring(L, "custom global out"); 6 | return 2; 7 | 8 | -------------------------------------------------------------------------------- /test/fixtures/namespace/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMESPACE_CONSTANTS_H_ 2 | #define NAMESPACE_CONSTANTS_H_ 3 | 4 | namespace Nem { 5 | 6 | /** Constants that should be accessible by Nem.ConstName 7 | */ 8 | enum NamespaceConstant { 9 | One = 1, 10 | Two, 11 | Three = 55, 12 | }; 13 | 14 | } // Nem 15 | 16 | #endif // NAMESPACE_CONSTANTS_H_ 17 | 18 | -------------------------------------------------------------------------------- /test/fixtures/namespace/nem.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMESPACE_NEM_H_ 2 | #define NAMESPACE_NEM_H_ 3 | 4 | #include "B.h" 5 | #include 6 | 7 | namespace Nem { 8 | 9 | /** Function inside the namespace. 10 | */ 11 | double addTwo(const B &a, const B &b) { 12 | return a.nb_ + b.nb_; 13 | } 14 | 15 | /** Global function with custom bindings. 16 | */ 17 | LuaStackSize customGlobal(float a, float b); 18 | } // Nem 19 | 20 | /** Function outside the namespace. 21 | */ 22 | double addTwoOut(const Nem::B &a, const Nem::B &b) { 23 | return a.nb_ + b.nb_; 24 | } 25 | 26 | /** Function outside the namespace with custom bindings. The custom bindings 27 | * for global methods must live in [name of lib].yml 28 | */ 29 | LuaStackSize customGlobalOut(float a, float b); 30 | 31 | 32 | #endif // NAMESPACE_NEM_H_ 33 | 34 | -------------------------------------------------------------------------------- /test/fixtures/path.wi$th-[pat]/Pat.h: -------------------------------------------------------------------------------- 1 | #ifndef PATH_WITH_PAT_PAT_H_ 2 | #define PATH_WITH_PAT_PAT_H_ 3 | 4 | #include 5 | #include 6 | 7 | /** This class is used to test 8 | * * header_base with Lua pattern characters in path. 9 | * 10 | */ 11 | class Pat { 12 | int value_; 13 | public: 14 | Pat(int v) 15 | : value_(v) 16 | {} 17 | 18 | void setValue(int v) { 19 | value_ = v; 20 | } 21 | 22 | int value() { 23 | return value_; 24 | } 25 | }; 26 | 27 | #endif // PATH_WITH_PAT_PAT_H_ 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/fixtures/pointers/Abstract.h: -------------------------------------------------------------------------------- 1 | #ifndef POINTERS_ABSTRACT_H_ 2 | #define POINTERS_ABSTRACT_H_ 3 | 4 | /** This class is used to make sure abstract types are not 5 | * instanciated and that we can cast to abstract types 6 | * and call methods on them. 7 | */ 8 | struct Abstract { 9 | Abstract() {} 10 | virtual ~Abstract() {} 11 | virtual double pureVirtual(double d) = 0; 12 | }; 13 | 14 | /** Make sure abstract types are detected even if all pure virtual functions 15 | * are ignored. 16 | * 17 | * @dub ignore: pureVirtual 18 | */ 19 | struct AbstractIgnored { 20 | AbstractIgnored() {} 21 | virtual ~AbstractIgnored() {} 22 | virtual double pureVirtual(double d) = 0; 23 | }; 24 | 25 | class AbstractSub : public Abstract { 26 | double n_; 27 | public: 28 | AbstractSub(double n) 29 | : n_(n) {} 30 | virtual double pureVirtual(double d) { 31 | return n_ + d; 32 | } 33 | }; 34 | 35 | class AbstractHolder { 36 | Abstract *a_ptr_; 37 | public: 38 | AbstractHolder(Abstract *a) 39 | : a_ptr_(a) {} 40 | 41 | Abstract *getPtr() { 42 | return a_ptr_; 43 | } 44 | }; 45 | 46 | #endif // POINTERS_ABSTRACT_H_ 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/fixtures/pointers/Box.h: -------------------------------------------------------------------------------- 1 | #ifndef POINTERS_BOX_H_ 2 | #define POINTERS_BOX_H_ 3 | 4 | #include "Vect.h" 5 | #include 6 | 7 | typedef struct Vect Vortex; 8 | 9 | /** This class is used to test: 10 | * * passing classes around as arguments. 11 | * * casting script strings to std::string. 12 | * * casting std::string to script strings. 13 | * * accessing complex public members. 14 | * * custom public member accessors. 15 | * * pointer member types and gc. 16 | * * complex default values. 17 | * * customized __tostring from dub settings. 18 | * 19 | * @dub string_format: '%%s' %%fx%%f 20 | * string_args: self->name_.c_str(), self->size_.x, self->size_.y 21 | */ 22 | struct Box { 23 | 24 | std::string name_; 25 | 26 | /** Full other type (copy). 27 | */ 28 | Vortex size_; 29 | 30 | /** Pointer to other type. 31 | */ 32 | Vect *position; 33 | 34 | /** Const version (should return a copy) 35 | */ 36 | const Vect *const_vect; 37 | 38 | Box(const std::string &name, const Vect &size = Vect(0,0)) 39 | : name_(name) 40 | , size_(size) 41 | , position(NULL) 42 | , const_vect(NULL) 43 | {} 44 | 45 | /** Set gc to on. 46 | * 47 | * @dub gc: true 48 | */ 49 | static Box *MakeBox(const char *name, Vect *size) { 50 | Box *b = new Box(std::string(name), *size); 51 | return b; 52 | } 53 | 54 | /** Test cast from std::string to scripting language string. 55 | */ 56 | std::string name() { 57 | return name_; 58 | } 59 | 60 | double surface() { 61 | return size_.surface(); 62 | } 63 | 64 | // Should not gc. 65 | Vect *size() { 66 | return &size_; 67 | } 68 | 69 | // Should not gc either. 70 | Vect &sizeRef() { 71 | return size_; 72 | } 73 | 74 | // Should not gc. 75 | const Vect &constRef() { 76 | return size_; 77 | } 78 | 79 | /** Copy of size pointer. Should be garbage collected. 80 | * @dub gc: true 81 | */ 82 | Vect *copySize() { 83 | return new Vect(size_); 84 | } 85 | }; 86 | 87 | #endif // POINTERS_BOX_H_ 88 | 89 | -------------------------------------------------------------------------------- /test/fixtures/pointers/Custom.h: -------------------------------------------------------------------------------- 1 | #ifndef POINTERS_CUSTOM_H_ 2 | #define POINTERS_CUSTOM_H_ 3 | 4 | #include 5 | 6 | /** This class is used to test: 7 | * * get/set functions as attributes 8 | */ 9 | class Custom { 10 | std::string url_; 11 | public: 12 | Custom(const std::string &url, double value) 13 | : url_(url) 14 | {} 15 | 16 | std::string getUrl() const { 17 | return std::string("/root/").append(url_); 18 | } 19 | 20 | void setUrl(const std::string &url) { 21 | url_ = url; 22 | } 23 | }; 24 | 25 | class SubCustom : public Custom { 26 | public: 27 | SubCustom(const std::string &url, double value) 28 | : Custom(url, value) 29 | {} 30 | }; 31 | #endif // POINTERS_CUSTOM_H_ 32 | 33 | -------------------------------------------------------------------------------- /test/fixtures/pointers/Vect.h: -------------------------------------------------------------------------------- 1 | #ifndef POINTERS_VECT_H_ 2 | #define POINTERS_VECT_H_ 3 | 4 | #include 5 | #include // size_t 6 | #define MAX_DIM 3 7 | 8 | /** This class is used to test: 9 | * * accessing public attributes 10 | * * return value optimization 11 | * * basic memory leakage 12 | * * operator overloading 13 | * * C array attributes 14 | * * unamed and void parameters 15 | * * ignore attributes 16 | * 17 | * @dub ignore: z 18 | */ 19 | struct Vect { 20 | double x; 21 | double y; 22 | double z; 23 | 24 | double d[MAX_DIM]; 25 | 26 | // static member access 27 | static size_t create_count; 28 | static size_t copy_count; 29 | static size_t destroy_count; 30 | 31 | Vect(double tx, double ty) 32 | : x(tx) 33 | , y(ty) { 34 | // to test return value optimization. 35 | // and memory leakage. 36 | ++create_count; 37 | for (size_t i=0; ix) 51 | , y(v->y) { 52 | // To test return value optimization. 53 | // and memory leakage. 54 | ++copy_count; 55 | } 56 | 57 | ~Vect() { 58 | // To test return value optimization. 59 | // and memory leakage. 60 | ++destroy_count; 61 | } 62 | 63 | double surface() const { 64 | return x * y; 65 | } 66 | 67 | // operator overloading 68 | 69 | void operator=(const Vect &v) { 70 | x = v.x; 71 | y = v.y; 72 | } 73 | 74 | Vect operator+(const Vect &v) { 75 | return Vect(x + v.x, y + v.y); 76 | } 77 | 78 | void operator+=(const Vect &v) { 79 | x += v.x; 80 | y += v.y; 81 | } 82 | 83 | Vect operator-(const Vect &v) { 84 | return Vect(x - v.x, y - v.y); 85 | } 86 | 87 | /** Unary minus. 88 | */ 89 | Vect operator-() { 90 | return Vect(-x, -y); 91 | } 92 | 93 | void operator-=(const Vect &v) { 94 | x -= v.x; 95 | y -= v.y; 96 | } 97 | 98 | Vect operator*(double d) { 99 | return Vect(d*x, d*y); 100 | } 101 | 102 | // overloaded operators 103 | // cross product 104 | double operator*(const Vect &v) { 105 | return x*v.y - y*v.x; 106 | } 107 | 108 | Vect operator/(double d) { 109 | return Vect(x/d, y/d); 110 | } 111 | 112 | bool operator<(const Vect &s) { 113 | return surface() < s.surface(); 114 | } 115 | 116 | bool operator<=(const Vect &s) { 117 | return surface() <= s.surface(); 118 | } 119 | 120 | bool operator==(const Vect &s) { 121 | return s.x == x && s.y == y; 122 | } 123 | 124 | // return element at position i 125 | double operator()(int i) { 126 | if (i == 1) { 127 | return x; 128 | } else if (i == 2) { 129 | return y; 130 | } else { 131 | return 0; 132 | } 133 | } 134 | 135 | // return element at position i 136 | double operator[](int i) { 137 | if (i == 1) { 138 | return x; 139 | } else if (i == 2) { 140 | return y; 141 | } else { 142 | return 0; 143 | } 144 | } 145 | 146 | // unknown operator should be ignored. 147 | Vect& operator=( int px ) { 148 | x = px; 149 | return *this; 150 | } 151 | 152 | // char mapped to number 153 | char someChar(char c) { 154 | return c; 155 | } 156 | 157 | // const char * mapped to string 158 | const char *someStr(const char *s) { 159 | return s; 160 | } 161 | 162 | /** Unamed parameters. 163 | */ 164 | double unamed(double, int); 165 | 166 | int noparam(void) { 167 | return 1; 168 | } 169 | }; 170 | 171 | 172 | #endif // POINTERS_VECT_H_ 173 | 174 | -------------------------------------------------------------------------------- /test/fixtures/pointers/vect.cpp: -------------------------------------------------------------------------------- 1 | #include "Vect.h" 2 | size_t Vect::create_count = 0; 3 | size_t Vect::copy_count = 0; 4 | size_t Vect::destroy_count = 0; 5 | 6 | double Vect::unamed(double d, int i) { 7 | return d + 2 * i; 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/simple/include/Map2.H: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_INCLUDE_MAP_H_ 2 | #define SIMPLE_INCLUDE_MAP_H_ 3 | 4 | #include 5 | #include 6 | 7 | /** This class is used to test 8 | * * custom get/set suffix without public attributes. 9 | * * changed method name with "name". 10 | * 11 | * @dub ignore: getVal, setVal 12 | */ 13 | class Map { 14 | typedef std::string Str; 15 | std::map map_; 16 | typedef std::pair Pair; 17 | public: 18 | // Should create default ctor 19 | 20 | bool getVal(const char *key, std::string *lhs) { 21 | if (map_.count(key) > 0) { 22 | *lhs = map_[key]; 23 | return true; 24 | } else { 25 | return false; 26 | } 27 | }; 28 | 29 | void setVal(const char *key, const char *value) { 30 | map_.insert(Pair(key, value)); 31 | } 32 | 33 | /** Change this method's name in the bindings and ensure 'unsigned' is seen as 34 | * an alias for unsigned int. 35 | * 36 | * @dub name: bar 37 | */ 38 | unsigned foo(int x) { 39 | return x; 40 | } 41 | 42 | /** Test methods with lua_State parameter and LuaStackSize 43 | * return value. 44 | */ 45 | LuaStackSize map(lua_State *L) { 46 | lua_newtable(L); 47 | std::map::iterator it; 48 | for (it = map_.begin(); it != map_.end(); ++it) { 49 | lua_pushlstring(L, it->first.data(), it->first.length()); 50 | lua_pushlstring(L, it->second.data(), it->second.length()); 51 | // 'key' 'value' 52 | lua_rawset(L, -3); 53 | } 54 | return 1; 55 | } 56 | }; 57 | 58 | /** Should inherit pseudo accessor 'map'. 59 | */ 60 | class SubMap : public Map { 61 | }; 62 | #endif // SIMPLE_INCLUDE_MAP_H_ 63 | 64 | -------------------------------------------------------------------------------- /test/fixtures/simple/include/Reg.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_INCLUDE_REG_H_ 2 | #define SIMPLE_INCLUDE_REG_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace reg { 8 | 9 | /** This class is used to test 10 | * * custom registration name: require registers Reg_core 11 | * instead of Reg (but metatable is 'Reg'). 12 | * 13 | * @dub register: Reg_core 14 | */ 15 | class Reg { 16 | std::string name_; 17 | public: 18 | Reg(const char *name) : name_(name) {} 19 | Reg(const Reg ®) : name_(reg.name_) {} 20 | 21 | 22 | const std::string name() const { 23 | return name_; 24 | } 25 | }; 26 | 27 | } // reg 28 | #endif // SIMPLE_INCLUDE_REG_H_ 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/fixtures/simple/include/simple.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_INCLUDE_SIMPLE_H_ 2 | #define SIMPLE_INCLUDE_SIMPLE_H_ 3 | 4 | #include "types.h" 5 | 6 | #include 7 | 8 | /** This class is used to test 9 | * * simple bindings 10 | * * default parameters 11 | * * overloaded methods. 12 | * * char/ const char* types 13 | * * private and public ctor 14 | * * neverThrows 15 | * * parameter named L 16 | * 17 | * @dub ignore: shouldBeIgnored, publicButInternal 18 | */ 19 | class Simple { 20 | 21 | double value_; 22 | /** Private ctor should not confuse parser. 23 | */ 24 | Simple() : value_(0) {} 25 | public: 26 | Simple(double v) : value_(v) {} 27 | 28 | ~Simple() {} 29 | 30 | double value() throw() { 31 | return value_; 32 | } 33 | 34 | /** Test typedef resolution in methods and 35 | * default values in arguments. 36 | */ 37 | MyFloat add(MyFloat v, double w = 10) { 38 | return v + w; 39 | } 40 | 41 | /** Test method overloading with default parameters. 42 | */ 43 | Simple add(const Simple &o) { 44 | return Simple(value_ + o.value_); 45 | } 46 | 47 | /** Method overloading without default parameters. 48 | */ 49 | Simple mul(const Simple &o) { 50 | return Simple(value_ + o.value_); 51 | } 52 | 53 | double mul(double d, const char* c) { 54 | return value_ + d + strlen(c); 55 | } 56 | 57 | double mul(double d, double d2) { 58 | return d * d2; 59 | } 60 | 61 | double mul() { 62 | return 0; 63 | } 64 | 65 | /** Method with parameter named L. 66 | */ 67 | double lmet(double L) { 68 | return L + 2; 69 | } 70 | 71 | /** Overloaded method that can be decided by arg size. 72 | */ 73 | int testA(Foo *f) { 74 | return 1; 75 | } 76 | 77 | int testA(Bar *b, double d) { 78 | return 2; 79 | } 80 | 81 | /** Overloaded method that can be only be decided by arg type. 82 | */ 83 | int testB(Foo *f, double d) { 84 | return 1; 85 | } 86 | 87 | int testB(Bar *b, double d) { 88 | return 2; 89 | } 90 | 91 | int testB(Bar *b, const char *c) { 92 | return 3; 93 | } 94 | 95 | // to test deep nesting overloaded decision tree 96 | double addAll(double d, double d2, double d3) { 97 | return d + d2 + d3; 98 | } 99 | 100 | // to test deep nesting overloaded decision tree 101 | double addAll(double d, double d2, double d3, const char *msg) { 102 | return d + d2 + d3 + strlen(msg); 103 | } 104 | 105 | void setValue(double v) { 106 | value_ = v; 107 | } 108 | 109 | /** To test simple static methods. 110 | */ 111 | static double pi() { 112 | return 3.14; 113 | } 114 | 115 | bool isZero() { 116 | return value_ == 0; 117 | } 118 | 119 | struct MyBuf { 120 | double d; 121 | }; 122 | 123 | /** Struct by value parameter. 124 | */ 125 | double showBuf(MyBuf buf) { 126 | return buf.d; 127 | } 128 | 129 | /** Class by value. 130 | */ 131 | double showSimple(Simple p) { 132 | return p.value_; 133 | } 134 | 135 | void shouldBeIgnored() { 136 | } 137 | 138 | void publicButInternal() { 139 | } 140 | 141 | // ignored in inspector 142 | void ignoreInInspector() { 143 | } 144 | 145 | protected: 146 | bool somethingNotToBind(double d) { 147 | return false; 148 | } 149 | 150 | private: 151 | bool someOtherThingNotToBind() { 152 | return false; 153 | } 154 | }; 155 | 156 | void badFuncToIgnore(const char *foo) { 157 | } 158 | 159 | #endif // SIMPLE_INCLUDE_SIMPLE_H_ 160 | -------------------------------------------------------------------------------- /test/fixtures/simple/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_INCLUDE_TYPES_H_ 2 | #define SIMPLE_INCLUDE_TYPES_H_ 3 | 4 | /** A simple typedef to have something not in any 5 | * class or namespace. 6 | */ 7 | typedef double MyFloat; 8 | 9 | struct Foo { 10 | }; 11 | 12 | struct Bar { 13 | }; 14 | 15 | #endif // SIMPLE_INCLUDE_TYPES_H_ 16 | -------------------------------------------------------------------------------- /test/fixtures/template/Foo.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_FOO_H_ 2 | #define TEMPLATE_FOO_H_ 3 | 4 | /** This class is used to test: 5 | * * template member functions = ignored 6 | */ 7 | struct Foo { 8 | template 9 | void addOne(const T &a) { 10 | a += 1; 11 | } 12 | }; 13 | 14 | #endif // TEMPLATE_FOO_H_ 15 | 16 | -------------------------------------------------------------------------------- /test/fixtures/template/TRect.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_TRECT_H_ 2 | #define TEMPLATE_TRECT_H_ 3 | 4 | namespace Nem { 5 | 6 | /** Test resolution of template inside a namespace. 7 | */ 8 | template 9 | class TRect { 10 | public: 11 | T x1; 12 | T y1; 13 | T x2; 14 | T y2; 15 | }; 16 | 17 | } // Nem 18 | 19 | typedef Nem::TRect nmRect32; 20 | 21 | #endif // TEMPLATE_TRECT_H_ 22 | -------------------------------------------------------------------------------- /test/fixtures/template/TVect.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_TVECT_H_ 2 | #define TEMPLATE_TVECT_H_ 3 | 4 | /** This class is used to test: 5 | * * template resolution 6 | * * = Should behave like the pointers/TVect class. 7 | */ 8 | template 9 | struct TVect { 10 | T x; 11 | T y; 12 | TVect(T tx, T ty) 13 | : x(tx) 14 | , y(ty) { 15 | // TO TEST return value optimization 16 | //printf(" TVect(%f,%f)\n", x, y); 17 | } 18 | TVect(const TVect &sz) 19 | : x(sz.x) 20 | , y(sz.y) { 21 | // TO TEST return value optimization 22 | //printf("copy TVect(%f,%f)\n",x, y); 23 | } 24 | 25 | T surface() const { 26 | return x * y; 27 | } 28 | 29 | TVect operator+(const TVect &sz) { 30 | return TVect(x + sz.x, y + sz.y); 31 | } 32 | 33 | T addToX(T a) { 34 | return x + a; 35 | } 36 | 37 | static T addTwo(T a, T b) { 38 | return a + b; 39 | } 40 | 41 | }; 42 | 43 | #endif // TEMPLATE_TVECT_H_ 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/fixtures/template/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_TYPES_H_ 2 | #define TEMPLATE_TYPES_H_ 3 | 4 | #include "TVect.h" 5 | 6 | /** This should resolve as a complete Vect class 7 | * with float for element storage. 8 | */ 9 | typedef TVect Vectf; 10 | 11 | /** This should resolve as a complete Vect class 12 | * with int for element storage. 13 | */ 14 | typedef TVect Vect2i; 15 | 16 | /** Test chained typedef. 17 | */ 18 | typedef Vect2i Vi; 19 | 20 | #endif // TEMPLATE_TYPES_H_ 21 | 22 | -------------------------------------------------------------------------------- /test/fixtures/thread/Callback.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_CALLBACK_H_ 2 | #define THREAD_CALLBACK_H_ 3 | 4 | #include "dub/dub.h" 5 | 6 | #include 7 | class Caller; 8 | 9 | /** When adding a second parent, casting is triggered for dub::Thread. 10 | */ 11 | class Foo { 12 | }; 13 | 14 | /** This class is used to test: 15 | * * read values defined in the scripting language (self access from C++). 16 | * * execute callbacks from C++. 17 | * 18 | * @dub push: dub_pushobject 19 | */ 20 | class Callback : public Foo, public dub::Thread { 21 | public: 22 | static int destroy_count; 23 | 24 | Callback(const std::string &name_) 25 | : name(name_) { 26 | } 27 | 28 | ~Callback() { 29 | ++destroy_count; 30 | } 31 | /** Test C++ attributes mixed with Lua values. 32 | */ 33 | std::string name; 34 | 35 | /** Read a value from the scripting language. 36 | */ 37 | double getValue(const std::string &key); 38 | 39 | double anyMethod(double d) { 40 | return d + 100; 41 | } 42 | 43 | std::string getName() { 44 | return name; 45 | } 46 | 47 | private: 48 | friend class Caller; 49 | /** Simulate a call from C++ 50 | * Call implementation depends on scripting language (see [lang]_callback.cpp). 51 | */ 52 | void call(const std::string &msg); 53 | }; 54 | 55 | #endif // THREAD_CALLBACK_H_ 56 | 57 | -------------------------------------------------------------------------------- /test/fixtures/thread/Caller.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_CALLER_H_ 2 | #define THREAD_CALLER_H_ 3 | 4 | #include "Callback.h" 5 | 6 | #include 7 | 8 | /** This class is used to simulate a call from C++. 9 | */ 10 | class Caller { 11 | public: 12 | Callback *clbk_; 13 | 14 | Caller(Callback *c=NULL) 15 | : clbk_(c) {} 16 | 17 | /** Simulate a call from C++ 18 | */ 19 | void call(const std::string &msg) { 20 | if (clbk_) { 21 | clbk_->call(msg); 22 | } 23 | } 24 | 25 | /** Simulate delete from C++ 26 | */ 27 | void destroyCallback() { 28 | if (clbk_) { 29 | delete clbk_; 30 | clbk_ = NULL; 31 | } 32 | } 33 | }; 34 | 35 | #endif // THREAD_CALLER_H_ 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/fixtures/thread/lua_callback.cpp: -------------------------------------------------------------------------------- 1 | #include "Callback.h" 2 | 3 | void Callback::call(const std::string &msg) { 4 | if (!dub_pushcallback("callback")) return; 5 | // 6 | lua_pushlstring(dub_L, msg.data(), msg.length()); 7 | // 8 | dub_call(2, 0); 9 | } 10 | 11 | double Callback::getValue(const std::string &key) { 12 | lua_State *L = dub_L; 13 | double d = 0; 14 | dub_pushvalue(key.c_str()); 15 | if (lua_isnumber(L, -1)) { 16 | // ... 17 | d = lua_tonumber(L, -1); 18 | } 19 | lua_pop(L, 1); 20 | return d; 21 | } 22 | 23 | int Callback::destroy_count = 0; 24 | -------------------------------------------------------------------------------- /test/function_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Function 4 | ------------ 5 | 6 | ... 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local lut = require 'lut' 11 | local dub = require 'dub' 12 | 13 | local should = lut.Test 'dub.Function' 14 | 15 | local ins = dub.Inspector { 16 | doc_dir = 'test/tmp', 17 | INPUT = 'test/fixtures/simple/include', 18 | } 19 | 20 | local Simple = ins:find 'Simple' 21 | local add = Simple:method 'add' 22 | 23 | function should.autoload() 24 | assertType('table', dub.Function) 25 | end 26 | 27 | function should.beAFunction() 28 | assertEqual('dub.Function', add.type) 29 | end 30 | 31 | function should.haveParams() 32 | local res = {} 33 | local i = 0 34 | for param in add:params() do 35 | i = i + 1 36 | table.insert(res, {i, param.name}) 37 | end 38 | assertValueEqual({{1, 'v'}, {2, 'w'}}, res) 39 | end 40 | 41 | function should.haveMinArgSize() 42 | assertEqual('(MyFloat v, double w=10)', add.argsstring) 43 | assertTrue(add.has_defaults) 44 | assertEqual(1, add.min_arg_size) 45 | end 46 | 47 | function should.haveReturnValue() 48 | local ret = add.return_value 49 | assertEqual('MyFloat', ret.name) 50 | end 51 | 52 | function should.notHaveReturnValueForSetter() 53 | local func = Simple:method 'setValue' 54 | assertNil(func.return_value) 55 | end 56 | 57 | function should.haveLocation() 58 | assertMatch('test/fixtures/simple/include/simple.h:[0-9]+', add.location) 59 | end 60 | 61 | function should.haveDefinition() 62 | assertMatch('MyFloat Simple::add', add.definition) 63 | end 64 | 65 | function should.haveArgsString() 66 | assertMatch('%(MyFloat v, double w=10%)', add.argsstring) 67 | end 68 | 69 | function should.markConstructorAsStatic() 70 | local func = Simple:method 'Simple' 71 | assertTrue(func.static) 72 | end 73 | 74 | function should.haveSignature() 75 | assertEqual('MyFloat, double', add.sign) 76 | end 77 | 78 | function should.respondToNew() 79 | local f = dub.Function { 80 | name = 'hop', 81 | definition = 'hop', 82 | argsstring = '(int i)', 83 | db = Simple.db, 84 | parent = Simple, 85 | params_list = { 86 | { type = 'dub.Param', 87 | name = 'i', 88 | position = 1, 89 | ctype = { 90 | name = 'int', 91 | }, 92 | } 93 | }, 94 | } 95 | assertEqual('dub.Function', f.type) 96 | assertEqual('hop(int i)', f:nameWithArgs()) 97 | end 98 | 99 | function should.respondToFullname() 100 | assertEqual('Simple::add', add:fullname()) 101 | end 102 | 103 | function should.respondToNameWithArgs() 104 | assertEqual('MyFloat Simple::add(MyFloat v, double w=10)', add:nameWithArgs()) 105 | end 106 | 107 | function should.respondToFullcname() 108 | assertEqual('Simple::add', add:fullcname()) 109 | end 110 | 111 | function should.respondToNeverThrows() 112 | local value = Simple:method 'value' 113 | assertTrue(value:neverThrows()) 114 | assertFalse(add:neverThrows()) 115 | end 116 | 117 | function should.respondToSetName() 118 | end 119 | 120 | should:test() 121 | -------------------------------------------------------------------------------- /test/inspect_box2d_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | box2d dub.Inspector test 4 | ------------------------ 5 | 6 | Test introspective operations with 'box2d' headers. To 7 | enable these tests, download Box2D into 8 | test/fixtures/Box2D. 9 | 10 | --]]------------------------------------------------------ 11 | local lub = require 'lub' 12 | local lut = require 'lut' 13 | local dub = require 'dub' 14 | 15 | --=============================================== Only if Box2D present 16 | local box2d_path = lub.path '|fixtures/Box2D' 17 | if not lub.exist(box2d_path) then 18 | return 19 | end 20 | 21 | local should = lut.Test('dub.Inspector - Box2D', {coverage = false}) 22 | 23 | local ins = dub.Inspector { 24 | INPUT = { 25 | box2d_path .. '/Box2D/Common', 26 | box2d_path .. '/Box2D/Collision', 27 | box2d_path .. '/Box2D/Dynamics', 28 | }, 29 | doc_dir = lub.path '|tmp', 30 | } 31 | 32 | function should.ignoreFunctionsWithComplexParams() 33 | local res = {} 34 | for func in ins.db:functions() do 35 | res[func.name] = func 36 | end 37 | assertNil(res.b2GetPointStates) 38 | assertEqual('dub.Function', res.b2PairLessThan.type) 39 | end 40 | 41 | --=============================================== TESTS 42 | function should.parseClasses() 43 | local b2Vec2 = ins:find('b2Vec2') 44 | assertType('table', b2Vec2) 45 | local res = {} 46 | for met in b2Vec2:methods() do 47 | table.insert(res, met.name) 48 | end 49 | assertValueEqual({ 50 | '~b2Vec2', 51 | b2Vec2.SET_ATTR_NAME, 52 | b2Vec2.GET_ATTR_NAME, 53 | 'b2Vec2', 54 | 'SetZero', 55 | 'Set', 56 | 'operator- ', 57 | 'operator()', 58 | 'operator+=', 59 | 'operator-=', 60 | 'operator*=', 61 | 'Length', 62 | 'LengthSquared', 63 | 'Normalize', 64 | 'IsValid', 65 | 'Skew', 66 | }, res) 67 | end 68 | 69 | should:test() 70 | 71 | 72 | -------------------------------------------------------------------------------- /test/inspect_constants_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector test 4 | ------------------ 5 | 6 | Test introspective operations with the 'constants' group 7 | of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - constants', {coverage = false}) 15 | 16 | local ins = dub.Inspector { 17 | INPUT = 'test/fixtures/constants', 18 | doc_dir = lub.path '|tmp', 19 | } 20 | 21 | local Car = ins:find('Car') 22 | 23 | --=============================================== TESTS 24 | 25 | function should.resolveEnumType() 26 | local db = ins.db 27 | local Car = ins:find('Car') 28 | local b = db:resolveType(Car, 'Brand') 29 | assertValueEqual({ 30 | name = 'int', 31 | def = 'int', 32 | create_name = 'Car::Brand ', 33 | cast = 'Car::Brand', 34 | -- This is used to output default enum values. 35 | scope = 'Car', 36 | }, b) 37 | end 38 | 39 | function should.findCarClass() 40 | assertEqual('dub.Class', Car.type) 41 | end 42 | 43 | function should.haveConstants() 44 | assertTrue(Car.has_constants) 45 | end 46 | 47 | function should.findGlobalEnum() 48 | local enum = ins:find('GlobalConstant') 49 | assertEqual('dub.Enum', enum.type) 50 | end 51 | 52 | function should.haveGlobalConstants() 53 | assertTrue(ins.db.has_constants) 54 | end 55 | 56 | function should.listGlobalConstants() 57 | local res = {} 58 | for const in ins.db:constants() do 59 | table.insert(res, const) 60 | end 61 | assertValueEqual({ 62 | 'One', 63 | 'Two', 64 | 'Three', 65 | }, res) 66 | end 67 | 68 | function should.listConstHeaders() 69 | local res = {} 70 | for h in ins.db:headers({}) do 71 | local name = string.match(h, '/([^/]+/[^/]+)$') 72 | table.insert(res, name) 73 | end 74 | assertValueEqual({ 75 | 'constants/Car.h', 76 | 'constants/types.h', 77 | }, res) 78 | end 79 | 80 | function should.findEnumByFullname() 81 | local Brand = ins:find('Car::Brand') 82 | assertEqual('Brand', Brand.name) 83 | assertMatch('test/fixtures/constants/Car.h:17', Brand.location) 84 | end 85 | 86 | function should.listConstants() 87 | local res = {} 88 | for name in Car:constants() do 89 | table.insert(res, name) 90 | end 91 | assertValueEqual({ 92 | 'Smoky', 93 | 'Polluty', 94 | 'Noisy', 95 | 'Dangerous', 96 | }, res) 97 | end 98 | 99 | should:test() 100 | 101 | -------------------------------------------------------------------------------- /test/inspect_inherit_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector test 4 | ------------------ 5 | 6 | Test introspective operations with the 'inherit' group 7 | of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - inherit', {coverage = false}) 15 | 16 | local ins = dub.Inspector { 17 | INPUT = 'test/fixtures/inherit', 18 | doc_dir = lub.path '|tmp', 19 | } 20 | 21 | --=============================================== TESTS 22 | 23 | function should.listSuperClasses() 24 | local Child = ins:find 'Child' 25 | local res = {} 26 | for elem in Child:superclasses() do 27 | table.insert(res, elem.name) 28 | end 29 | assertValueEqual({ 30 | 'Parent', 31 | 'GrandParent', 32 | 'ChildHelper', 33 | 'Mother', 34 | }, res) 35 | end 36 | 37 | function should.teardown() 38 | dub.warn = dub.printWarn 39 | end 40 | 41 | function should.listUnknownParentsDeclaredInDubComment() 42 | dub.warn = dub.silentWarn 43 | local Orphan = ins:find 'Orphan' 44 | local res = {} 45 | for elem in Orphan:superclasses() do 46 | table.insert(res, elem.name) 47 | end 48 | assertValueEqual({ 49 | 'Bar', 50 | 'Foo< int >', 51 | }, res) 52 | dub.warn = dub.printWarn 53 | end 54 | 55 | function should.haveCastForUnknownParent() 56 | local Orphan = ins:find 'Orphan' 57 | local res = {} 58 | for elem in Orphan:methods() do 59 | table.insert(res, elem.name) 60 | end 61 | assertValueEqual({ 62 | '~Orphan', 63 | '_cast_', 64 | 'Orphan', 65 | }, res) 66 | end 67 | 68 | function should.listSuperMethods() 69 | local Child = ins:find 'Child' 70 | local res = {} 71 | for elem in Child:methods() do 72 | table.insert(res, elem.name) 73 | end 74 | assertValueEqual({ 75 | '_set_', 76 | '_get_', 77 | '_cast_', 78 | 'Child', 79 | '~Child', 80 | 'x', 81 | 'y', 82 | 'returnUnk1', 83 | 'returnUnk2', 84 | 'methodWithUnknown', 85 | 'name', 86 | 'computeAge', 87 | 'position', 88 | 'addToX', 89 | }, res) 90 | end 91 | 92 | function should.listSuperAttributes() 93 | local Child = ins:find 'Child' 94 | local res = {} 95 | for elem in Child:attributes() do 96 | table.insert(res, elem.name) 97 | end 98 | assertValueEqual({ 99 | 'teeth', 100 | 'status', 101 | 'happy', 102 | 'birth_year', 103 | }, res) 104 | end 105 | 106 | function should.haveVariables() 107 | local GrandChild = ins:find 'GrandChild' 108 | assertTrue(GrandChild:hasVariables()) 109 | local res = {} 110 | for elem in GrandChild:attributes() do 111 | table.insert(res, elem.name) 112 | end 113 | assertValueEqual({ 114 | 'teeth', 115 | 'status', 116 | 'happy', 117 | 'birth_year', 118 | }, res) 119 | end 120 | 121 | function should.getDubInfoInHelper() 122 | local ChildHelper = ins:find 'ChildHelper' 123 | assertEqual(false, ChildHelper.dub.bind) 124 | assertEqual(false, ChildHelper.dub.cast) 125 | end 126 | 127 | function should.resolveEnumWithParent() 128 | local Child = ins:find 'Child' 129 | local Parent = ins:find 'Parent' 130 | local b = ins.db:resolveType(Child, 'MaritalStatus') 131 | assertValueEqual({ 132 | name = 'int', 133 | def = 'int', 134 | create_name = 'Parent::MaritalStatus ', 135 | cast = 'Parent::MaritalStatus', 136 | -- This is used to output default enum values. 137 | scope = 'Parent', 138 | }, b) 139 | local c = ins.db:resolveType(Parent, 'MaritalStatus') 140 | assertValueEqual(b, c) 141 | end 142 | 143 | should:test() 144 | 145 | -------------------------------------------------------------------------------- /test/inspect_memory_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector test 4 | ------------------ 5 | 6 | Test introspective operations with the 'memory' group 7 | of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - memory', {coverage = false}) 15 | 16 | local ins = dub.Inspector { 17 | INPUT = lub.path '|fixtures/memory', 18 | doc_dir = lub.path '|tmp', 19 | PREDEFINED = { 20 | 'SOME_FUNCTION_MACRO(x)=', 21 | 'OTHER_FUNCTION_MACRO(x)=', 22 | }, 23 | } 24 | 25 | --=============================================== TESTS 26 | 27 | function should.notHaveADestructor() 28 | local Nogc = ins:find('Nogc') 29 | local res = {} 30 | for meth in Nogc:methods() do 31 | local name = meth.name 32 | if meth.static then 33 | name = name .. ':static' 34 | end 35 | table.insert(res, name) 36 | end 37 | assertValueEqual({ 38 | -- No ~Nogc destructor 39 | Nogc.SET_ATTR_NAME, 40 | Nogc.GET_ATTR_NAME, 41 | 'Nogc:static', 42 | 'surface', 43 | 'operator+', 44 | }, res) 45 | end 46 | 47 | function should.notHavePrivateDestructor() 48 | local PrivateDtor = ins:find('PrivateDtor') 49 | local res = {} 50 | for meth in PrivateDtor:methods() do 51 | local name = meth.name 52 | if meth.static then 53 | name = name .. ':static' 54 | end 55 | table.insert(res, name) 56 | end 57 | assertValueEqual({ 58 | -- No ~Nogc destructor 59 | 'PrivateDtor:static', 60 | }, res) 61 | end 62 | 63 | function should.notHaveMacroFunctions() 64 | local Pen = ins:find('Pen') 65 | local res = {} 66 | for met in Pen:methods() do 67 | local name = met.name 68 | if met.static then 69 | name = name .. ':static' 70 | end 71 | table.insert(res, name) 72 | end 73 | assertValueEqual({ 74 | 'Pen:static', 75 | 'setOwner', 76 | '~Pen', 77 | 'name', 78 | -- no SOME_FUNCTION_MACRO or OTHER_FUNCTION_MACRO 79 | -- no pushobject 80 | }, res) 81 | end 82 | 83 | function should.notSeeMacroAsAttribute() 84 | local Pen = ins:find('Pen') 85 | assertFalse(Pen.has_variables) 86 | end 87 | 88 | --=============================================== UNION 89 | 90 | local Union = ins:find('Union') 91 | 92 | function should.parseUnionMembers() 93 | local uni_a = Union.variables_list[1] 94 | local res = {} 95 | for var in Union:attributes() do 96 | table.insert(res, var.name..':'..var.ctype.name) 97 | end 98 | assertValueEqual({ 99 | 'h:uint8_t', 100 | 's:uint8_t', 101 | 'v:uint8_t', 102 | 'a:uint8_t', 103 | 'c:uint32_t', 104 | }, res) 105 | end 106 | 107 | --=============================================== Custo dtor 108 | 109 | local CustomDtor = ins:find('CustomDtor') 110 | 111 | function should.parseDub() 112 | assertEqual('finalize', CustomDtor.dub.destructor) 113 | end 114 | 115 | function should.ignoreDtor() 116 | local res = {} 117 | for m in CustomDtor:methods() do 118 | table.insert(res, m.name) 119 | end 120 | 121 | assertValueEqual({ 122 | 'CustomDtor', 123 | '~CustomDtor', 124 | -- No 'finalize' 125 | }, res) 126 | end 127 | 128 | --=============================================== No dtor 129 | 130 | local NoDtor = ins:find('NoDtor') 131 | 132 | function should.parseNoDtorDub() 133 | assertEqual(false, NoDtor.dub.destructor) 134 | end 135 | 136 | function should.ignoreFalseDtor() 137 | local res = {} 138 | for m in NoDtor:methods() do 139 | table.insert(res, m.name) 140 | end 141 | 142 | assertValueEqual({ 143 | 'NoDtor', 144 | -- No '~NoDtor' 145 | }, res) 146 | end 147 | 148 | should:test() 149 | 150 | -------------------------------------------------------------------------------- /test/inspect_namespace_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector test 4 | ------------------ 5 | 6 | Test introspective operations with the 'namespace' group 7 | of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - namespace', {coverage = false}) 15 | 16 | local ins 17 | 18 | function should.setup() 19 | dub.warn = dub.silentWarn 20 | if not ins then 21 | ins = dub.Inspector { 22 | INPUT = { 23 | lub.path '|fixtures/namespace', 24 | }, 25 | doc_dir = lub.path '|tmp', 26 | } 27 | end 28 | end 29 | 30 | function should.teardown() 31 | dub.warn = dub.printWarn 32 | end 33 | --=============================================== TESTS 34 | 35 | function should.findNamespace() 36 | local Nem = ins:find('Nem') 37 | assertEqual('dub.Namespace', Nem.type) 38 | end 39 | 40 | function should.listNamespaces() 41 | local res = {} 42 | for nm in ins.db:namespaces() do 43 | table.insert(res, nm.name) 44 | end 45 | assertValueEqual({ 46 | 'Nem', 47 | }, res) 48 | end 49 | 50 | function should.listHeaders() 51 | local res = {} 52 | -- It does not matter which namespace we use in 'headers'. We will 53 | for h in ins.db:headers(ins:find('Nem::A')) do 54 | local name = string.match(h, '/([^/]+/[^/]+)$') 55 | table.insert(res, name) 56 | end 57 | assertValueEqual({ 58 | 'namespace/A.h', 59 | 'namespace/B.h', 60 | 'namespace/Out.h', 61 | 'namespace/TRect.h', 62 | 'namespace/constants.h', 63 | 'namespace/nem.h', 64 | }, res) 65 | end 66 | 67 | function should.findByFullname() 68 | local A = ins:find('Nem::A') 69 | assertEqual('dub.Class', A.type) 70 | end 71 | 72 | function should.findNamespace() 73 | local A = ins:find('Nem::A') 74 | assertEqual('Nem', A:namespace().name) 75 | end 76 | 77 | function should.findTemplate() 78 | local TRect = ins:find('Nem::TRect') 79 | assertEqual('TRect', TRect.name) 80 | assertEqual('dub.CTemplate', TRect.type) 81 | end 82 | 83 | function should.findTypdefByFullname() 84 | local Rect = ins:find('Nem::Rect') 85 | assertEqual('Rect', Rect.name) 86 | assertEqual('Nem', Rect:namespace().name) 87 | assertEqual('dub.Class', Rect.type) 88 | end 89 | 90 | function should.findNestedClassByFullname() 91 | local C = ins:find('Nem::B::C') 92 | assertEqual('dub.Class', C.type) 93 | assertEqual('C', C.name) 94 | end 95 | 96 | function should.findNamespaceFromNestedClass() 97 | local C = ins:find('Nem::B::C') 98 | assertEqual('Nem', C:namespace().name) 99 | end 100 | 101 | function should.haveFullypeReturnValueInCtor() 102 | local C = ins:find('Nem::B::C') 103 | local met = C:method('C') 104 | assertEqual('B::C *', met.return_value.create_name) 105 | end 106 | 107 | function should.prefixInnerClassInTypes() 108 | local C = ins:find('Nem::B::C') 109 | assertEqual('B::C *', C.create_name) 110 | end 111 | 112 | function should.properlyResolveType() 113 | local C = ins:find('Nem::B::C') 114 | local t = ins.db:resolveType(C, 'Nem::B::C') 115 | assertEqual(C, t) 116 | t = ins.db:resolveType(C, 'B::C') 117 | assertEqual(C, t) 118 | t = ins.db:resolveType(C, 'C') 119 | assertEqual(C, t) 120 | end 121 | 122 | function should.findAttributesInParent() 123 | local B = ins:find('Nem::B') 124 | local res = {} 125 | for var in B:attributes() do 126 | table.insert(res, var.name) 127 | end 128 | assertValueEqual({ 129 | 'nb_', 130 | 'a', 131 | 'c', 132 | }, res) 133 | end 134 | 135 | function should.resolveElementsOutOfNamespace() 136 | local e = ins:find('nmRectf') 137 | assertEqual('dub.Class', e.type) 138 | assertEqual('nmRectf', e:fullname()) 139 | end 140 | 141 | function should.resolveElementsOutOfNamespace() 142 | local e = ins:find('Nem::Rectf') 143 | assertEqual('dub.Class', e.type) 144 | assertEqual('Nem::Rectf', e:fullname()) 145 | end 146 | 147 | function should.notUseSingleLibNameInNamespace() 148 | ins.db.name = 'foo' 149 | local e = ins:find('Nem') 150 | assertEqual('dub.Namespace', e.type) 151 | assertEqual('Nem', e:fullname()) 152 | ins.db.name = nil 153 | end 154 | 155 | function should.findMethodsInParent() 156 | local B = ins:find('Nem::B') 157 | local res = {} 158 | for met in B:methods() do 159 | table.insert(res, met.name) 160 | end 161 | assertValueEqual({ 162 | '~B', 163 | B.SET_ATTR_NAME, 164 | B.GET_ATTR_NAME, 165 | 'B', 166 | '__tostring', 167 | 'getC', 168 | }, res) 169 | end 170 | 171 | --=============================================== namespace functions 172 | 173 | function should.listNamespaceFunctions() 174 | local res = {} 175 | for func in ins.db:functions() do 176 | lub.insertSorted(res, func:fullcname()) 177 | end 178 | assertValueEqual({ 179 | 'Nem::addTwo', 180 | 'Nem::customGlobal', 181 | 'addTwoOut', 182 | 'customGlobalOut', 183 | }, res) 184 | end 185 | 186 | function should.setFlagsOnNamespaceFunction() 187 | local addTwo = ins:find('Nem::addTwo') 188 | assertEqual('dub.Function', addTwo.type) 189 | assertEqual(false, addTwo.member) 190 | end 191 | 192 | --=============================================== namespace constants 193 | 194 | function should.findNamespaceConstants() 195 | local n = ins:find('Nem') 196 | local enum = ins:find('Nem::NamespaceConstant') 197 | assertEqual('dub.Enum', enum.type) 198 | assertTrue(n.has_constants) 199 | end 200 | 201 | function should.listNamespaceConstants() 202 | local n = ins:find('Nem') 203 | local res = {} 204 | for const in n:constants() do 205 | lub.insertSorted(res, const) 206 | end 207 | assertValueEqual({ 208 | 'One', 209 | 'Three', 210 | 'Two', 211 | }, res) 212 | end 213 | 214 | function should.listAllConstants() 215 | local res = {} 216 | for const in ins.db:constants() do 217 | lub.insertSorted(res, const) 218 | end 219 | assertValueEqual({ 220 | 'One', 221 | 'Three', 222 | 'Two', 223 | }, res) 224 | end 225 | 226 | should:test() 227 | 228 | -------------------------------------------------------------------------------- /test/inspect_pointers_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector test 4 | ------------------ 5 | 6 | Test introspective operations with the 'pointers' group 7 | of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - pointers', {coverage = false}) 15 | 16 | local ins = dub.Inspector { 17 | INPUT = 'test/fixtures/pointers', 18 | doc_dir = lub.path '|tmp', 19 | } 20 | 21 | local Vect = ins:find('Vect') 22 | local Box = ins:find('Box') 23 | local Vortex = ins:find('Vortex') 24 | 25 | --=============================================== TESTS 26 | 27 | function should.notHaveCtorForAbstractTypes() 28 | local Abstract = ins:find('Abstract') 29 | assertTrue(Abstract.abstract) 30 | local res = {} 31 | for met in Abstract:methods() do 32 | table.insert(res, met.name) 33 | end 34 | assertValueEqual({ 35 | '~Abstract', 36 | 'pureVirtual', 37 | }, res) 38 | end 39 | 40 | function should.notHaveCtorForAbstractTypesWithIgnoredMethods() 41 | local Abstract = ins:find('AbstractIgnored') 42 | assertTrue(Abstract.abstract) 43 | local res = {} 44 | for met in Abstract:methods() do 45 | table.insert(res, met.name) 46 | end 47 | assertValueEqual({ 48 | '~AbstractIgnored', 49 | }, res) 50 | end 51 | 52 | 53 | function should.detectPureVirtualFunctions() 54 | local Abstract = ins:find('Abstract') 55 | local pureVirtual = Abstract:method('pureVirtual') 56 | assertTrue(pureVirtual.pure_virtual) 57 | end 58 | 59 | function should.findVectClass() 60 | assertEqual('dub.Class', Vect.type) 61 | end 62 | 63 | function should.parseParamTypes() 64 | local ctor = Box:method('Box') 65 | local p1 = ctor.params_list[1] 66 | local p2 = ctor.params_list[2] 67 | assertEqual('name', p1.name) 68 | assertEqual('std::string', p1.ctype.name) 69 | assertTrue(p1.ctype.const) 70 | assertTrue(p1.ctype.ref) 71 | assertEqual('const std::string ', p1.ctype.create_name) 72 | assertEqual('size', p2.name) 73 | assertEqual('Vect', p2.ctype.name) 74 | end 75 | 76 | function should.assignDefaultNamesToParams() 77 | local met = Vect:method('unamed') 78 | local p1 = met.params_list[1] 79 | local p2 = met.params_list[2] 80 | assertEqual('p1', p1.name) 81 | assertEqual('double', p1.ctype.name) 82 | assertEqual('p2', p2.name) 83 | assertEqual('int', p2.ctype.name) 84 | end 85 | 86 | function should.notConfuseVoidAsType() 87 | local met = Vect:method('noparam') 88 | assertEqual(0, #met.params_list) 89 | end 90 | 91 | function should.parsePointerParamTypes() 92 | local met = Box:method('MakeBox') 93 | local p1 = met.params_list[1] 94 | local p2 = met.params_list[2] 95 | assertEqual('name', p1.name) 96 | assertEqual('char', p1.ctype.name) 97 | assertTrue(p1.ctype.const) 98 | assertTrue(p1.ctype.ptr) 99 | assertFalse(p1.ctype.ref) 100 | assertEqual('const char *', p1.ctype.create_name) 101 | assertEqual('size', p2.name) 102 | assertEqual('Vect', p2.ctype.name) 103 | assertEqual('Vect *', p2.ctype.create_name) 104 | end 105 | 106 | function should.listBoxAttributes() 107 | local res = {} 108 | for attr in Box:attributes() do 109 | local name = attr.name 110 | if attr.static then 111 | name = name .. ':static' 112 | end 113 | table.insert(res, name) 114 | end 115 | assertValueEqual({ 116 | 'name_', 117 | 'size_', 118 | 'position', 119 | 'const_vect', 120 | }, res) 121 | end 122 | 123 | function should.markConstMembers() 124 | local attr = Box:findChild('const_vect') 125 | assertTrue(attr.ctype.const) 126 | end 127 | 128 | function should.markPointerMembers() 129 | local attr = Box:findChild('position') 130 | assertTrue(attr.ctype.ptr) 131 | end 132 | 133 | function should.listVectAttributes() 134 | local res = {} 135 | for attr in Vect:attributes() do 136 | local name = attr.name 137 | if attr.static then 138 | name = name .. ':static' 139 | end 140 | table.insert(res, name) 141 | end 142 | assertValueEqual({ 143 | 'x', 144 | 'y', 145 | 'create_count:static', 146 | 'copy_count:static', 147 | 'destroy_count:static', 148 | }, res) 149 | end 150 | 151 | function should.detectArrayAttributes() 152 | local d = Vect:findChild('d') 153 | assertEqual('d', d.name) 154 | assertEqual('MAX_DIM', d.array_dim) 155 | end 156 | 157 | function should.listMethods() 158 | local res = {} 159 | for meth in Vect:methods() do 160 | local name = meth.name 161 | if meth.static then 162 | name = name .. ':static' 163 | end 164 | table.insert(res, name) 165 | end 166 | assertValueEqual({ 167 | Vect.SET_ATTR_NAME, 168 | 'd', 169 | 'Vect:static', 170 | '~Vect', 171 | -- 'd_set', 172 | 'surface', 173 | 'operator=', 174 | 'operator+', 175 | 'operator+=', 176 | 'operator-', 177 | -- unary minus 178 | 'operator- ', 179 | 'operator-=', 180 | 'operator*', 181 | 'operator/', 182 | 'operator<', 183 | 'operator<=', 184 | 'operator==', 185 | 'operator()', 186 | Vect.GET_ATTR_NAME, 187 | 'someChar', 188 | 'someStr', 189 | 'unamed', 190 | 'noparam', 191 | }, res) 192 | end 193 | 194 | function should.listStaticMethods() 195 | local Box = ins:find('Box') 196 | local res = {} 197 | for meth in Box:methods() do 198 | local name = meth.name 199 | if meth.static then 200 | name = name .. ':static' 201 | end 202 | table.insert(res, name) 203 | end 204 | assertValueEqual({ 205 | '~Box', 206 | Box.SET_ATTR_NAME, 207 | Box.GET_ATTR_NAME, 208 | 'Box:static', 209 | 'name', 210 | 'surface', 211 | 'size', 212 | 'sizeRef', 213 | 'constRef', 214 | 'copySize', 215 | 'MakeBox:static', 216 | }, res) 217 | end 218 | 219 | function should.staticMethodShouldBeStatic() 220 | local Box = ins:find('Box') 221 | local met = Box:method('MakeBox') 222 | assertTrue(met.static) 223 | end 224 | 225 | function should.haveSetMethod() 226 | local set = Vect:method(Vect.SET_ATTR_NAME) 227 | assertTrue(set.is_set_attr) 228 | end 229 | 230 | function should.haveGetMethod() 231 | local set = Vect:method(Vect.GET_ATTR_NAME) 232 | assertTrue(set.is_get_attr) 233 | end 234 | 235 | function should.parseCompoundNameInDefault() 236 | local Box = ins:find('Box') 237 | local met = Box:method('Box') 238 | local p = met.params_list[2] 239 | assertEqual('Vect(0, 0)', p.default) 240 | end 241 | 242 | function should.parseAddOperator() 243 | local met = Vect:method('operator+') 244 | assertTrue(met.member) 245 | assertEqual('operator+', met.name) 246 | assertEqual('operator_add', met.cname) 247 | end 248 | 249 | function should.parseSubOperator() 250 | local met = Vect:method('operator-') 251 | assertTrue(met.member) 252 | assertEqual('operator-', met.name) 253 | assertEqual('operator_sub', met.cname) 254 | end 255 | 256 | --function should.parseUnmOperator() 257 | -- local met = Vect:method('operator+') 258 | -- assertTrue(met.member) 259 | -- assertEqual('operator+', met.name) 260 | -- assertEqual('operator_plus', met.cname) 261 | --end 262 | 263 | function should.parseMulOperator() 264 | local met = Vect:method('operator*') 265 | assertTrue(met.member) 266 | assertEqual('operator*', met.name) 267 | assertEqual('operator_mul', met.cname) 268 | end 269 | 270 | function should.parseDivOperator() 271 | local met = Vect:method('operator/') 272 | assertTrue(met.member) 273 | assertEqual('operator/', met.name) 274 | assertEqual('operator_div', met.cname) 275 | end 276 | 277 | function should.parseLtOperator() 278 | local met = Vect:method('operator<') 279 | assertTrue(met.member) 280 | assertEqual('operator<', met.name) 281 | assertEqual('operator_lt', met.cname) 282 | end 283 | 284 | function should.parseLteOperator() 285 | local met = Vect:method('operator<=') 286 | assertTrue(met.member) 287 | assertEqual('operator<=', met.name) 288 | assertEqual('operator_le', met.cname) 289 | end 290 | 291 | function should.parseEqOperator() 292 | local met = Vect:method('operator==') 293 | assertTrue(met.member) 294 | assertEqual('operator==', met.name) 295 | assertEqual('operator_eq', met.cname) 296 | end 297 | 298 | function should.ignoreOverloadedWithSameType() 299 | -- Vect(double x, double y) 300 | -- Vect(const Vect &v) 301 | -- Vect(const Vect *v) 302 | local met = Vect:method('Vect') 303 | assertTrue(met.overloaded) 304 | assertEqual(2, #met.overloaded) 305 | end 306 | 307 | function should.parseStringArgs() 308 | assertEqual("'%s' %fx%f", Box.dub.string_format) 309 | assertValueEqual({ 310 | 'self->name_.c_str()', 311 | 'self->size_.x', 312 | 'self->size_.y', 313 | ['self->name_.c_str()'] = true, 314 | ['self->size_.x'] = true, 315 | ['self->size_.y'] = true, 316 | }, Box.dub.string_args) 317 | end 318 | 319 | function should.parseTypedef() 320 | assertEqual('dub.Typedef', Vortex.type) 321 | assertEqual('Vect', Vortex.ctype.name) 322 | end 323 | 324 | should:test() 325 | 326 | -------------------------------------------------------------------------------- /test/inspect_simple_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector 4 | ------------- 5 | 6 | Test basic parsing and introspective operations with 7 | the 'simple' class. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - simple', {coverage = false}) 15 | 16 | local tmp_path = lub.path '|tmp' 17 | lub.rmTree(tmp_path, true) 18 | os.execute('mkdir -p '..tmp_path) 19 | 20 | local ins = dub.Inspector { 21 | INPUT = lub.path '|fixtures/simple/include', 22 | doc_dir = lub.path '|tmp', 23 | ignore = { 24 | Simple = { 25 | 'ignoreInInspector', 26 | }, 27 | 'badFuncToIgnore', 28 | }, 29 | } 30 | 31 | --=============================================== TESTS 32 | function should.loadDub() 33 | assertType('table', dub) 34 | end 35 | 36 | function should.createInspector() 37 | local foo = dub.Inspector(lub.path '|fixtures/simple/include') 38 | assertType('table', foo) 39 | end 40 | 41 | function should.findSimpleClass() 42 | local simple = ins:find('Simple') 43 | assertEqual('dub.Class', simple.type) 44 | end 45 | 46 | function should.findReturnValueOfCtor() 47 | local Simple = ins:find('Simple') 48 | local ctor = Simple:method('Simple') 49 | assertEqual('Simple *', ctor.return_value.create_name) 50 | end 51 | 52 | function should.findReturnValue() 53 | local Simple = ins:find('Simple') 54 | local ctor = Simple:method('add') 55 | assertEqual('MyFloat ', ctor.return_value.create_name) 56 | end 57 | 58 | function should.findTypedef() 59 | local obj = ins:find('MyFloat') 60 | assertEqual('dub.Typedef', obj.type) 61 | end 62 | 63 | function should.resolveTypes() 64 | local Simple = ins:find('Simple') 65 | local db = ins.db 66 | assertEqual(Simple, db:resolveType(db, 'Simple')) 67 | assertEqual(Simple, db:resolveType(Simple, 'Simple')) 68 | assertValueEqual({ 69 | name = 'double', 70 | def = 'double', 71 | create_name = 'MyFloat ', 72 | }, db:resolveType(Simple, 'MyFloat')) 73 | 74 | assertValueEqual({ 75 | name = 'double', 76 | def = 'double', 77 | create_name = 'MyFloat ', 78 | }, db:resolveType(db, 'MyFloat')) 79 | end 80 | 81 | function should.findMemberMethod() 82 | local Simple = ins:find('Simple') 83 | local met = Simple:method('value') 84 | assertEqual('dub.Function', met.type) 85 | assertEqual(Simple, met.parent) 86 | assertTrue(met.member) 87 | assertFalse(met.ctor) 88 | assertFalse(met.dtor) 89 | end 90 | 91 | function should.findStaticMemberMethod() 92 | local Simple = ins:find('Simple') 93 | local met = Simple:method('pi') 94 | assertTrue(met.static) 95 | assertEqual('dub.Function', met.type) 96 | end 97 | 98 | function should.markCtorAsStatic() 99 | local Simple = ins:find('Simple') 100 | local met = Simple:method('Simple') 101 | assertTrue(met.static) 102 | assertTrue(met.ctor) 103 | assertEqual('dub.Function', met.type) 104 | end 105 | 106 | function should.listMembers() 107 | local res = {} 108 | for child in ins:children() do 109 | lub.insertSorted(res, child.name) 110 | end 111 | assertValueEqual({ 112 | 'Bar', 113 | 'Foo', 114 | 'Map', 115 | 'MyFloat', 116 | 'Simple', 117 | 'SubMap', 118 | 'reg', 119 | }, res) 120 | end 121 | 122 | function should.listMemberMethods() 123 | local Simple = ins:find('Simple') 124 | local res = {} 125 | for meth in Simple:methods() do 126 | table.insert(res, meth.name) 127 | end 128 | assertValueEqual({ 129 | 'Simple', 130 | '~Simple', 131 | 'value', 132 | 'add', 133 | 'mul', 134 | 'lmet', 135 | 'testA', 136 | 'testB', 137 | 'addAll', 138 | 'setValue', 139 | 'isZero', 140 | 'showBuf', 141 | 'showSimple', 142 | 'pi', 143 | }, res) 144 | end 145 | 146 | function should.listParamsOnMethod() 147 | local Simple = ins:find('Simple') 148 | local add = Simple:method('add') 149 | local names = {} 150 | local types = {} 151 | for param in add:params() do 152 | table.insert(names, param.name) 153 | table.insert(types, param.ctype.name) 154 | end 155 | assertValueEqual({'v', 'w'}, names) 156 | assertValueEqual({'MyFloat', 'double'}, types) 157 | end 158 | 159 | function should.getDefaultParamsInMethod() 160 | local Simple = ins:find('Simple') 161 | local met = Simple:method('add') 162 | local p1 = met.params_list[1] 163 | local p2 = met.params_list[2] 164 | assertEqual('v', p1.name) 165 | assertNil(p1.default) 166 | assertEqual('w', p2.name) 167 | assertEqual('10', p2.default) 168 | end 169 | 170 | function should.markFunctionWithDefaults() 171 | local Simple = ins:find('Simple') 172 | local met = Simple:method('add') 173 | assertTrue(met.has_defaults) 174 | met = Simple:method('Simple') 175 | assertFalse(met.has_defaults) 176 | end 177 | 178 | function should.setFirstDefaultPositionInFunction() 179 | local Simple = ins:find('Simple') 180 | local met = Simple:method('add') 181 | assertTrue(met.has_defaults) 182 | assertEqual(2, met.first_default) 183 | met = Simple:method('Simple') 184 | assertFalse(met.has_defaults) 185 | end 186 | 187 | function should.detectOverloadFunctions() 188 | local Simple = ins:find('Simple') 189 | local met = Simple:method('add') 190 | assertTrue(met.overloaded) 191 | local met = Simple:method('mul') 192 | assertEqual(4, #met.overloaded) 193 | end 194 | 195 | --=============================================== Overloaded 196 | 197 | function should.haveOverloadedList() 198 | local Simple = ins:find('Simple') 199 | local met = Simple:method('add') 200 | local res = {} 201 | for _, m in ipairs(met.overloaded) do 202 | table.insert(res, m.sign) 203 | end 204 | assertValueEqual({ 205 | 'MyFloat, double', 206 | 'Simple', 207 | }, res) 208 | 209 | met = Simple:method('mul') 210 | res = {} 211 | for _, m in ipairs(met.overloaded) do 212 | table.insert(res, m.sign) 213 | end 214 | assertValueEqual({ 215 | 'Simple', 216 | 'double, char', 217 | 'double, double', 218 | '', 219 | }, res) 220 | 221 | met = Simple:method('addAll') 222 | res = {} 223 | for _, m in ipairs(met.overloaded) do 224 | table.insert(res, m.sign) 225 | end 226 | assertValueEqual({ 227 | 'double, double, double', 228 | 'double, double, double, char', 229 | }, res) 230 | end 231 | 232 | function should.resolveNativeTypes() 233 | assertEqual('double', ins:resolveType('MyFloat').name) 234 | end 235 | 236 | --=============================================== struct by value 237 | function should.parseStructParam() 238 | local Simple = ins:find('Simple') 239 | local met = Simple:method('showBuf') 240 | local p = met.params_list[1] 241 | assertEqual('MyBuf', p.ctype.name) 242 | assertFalse(p.ctype.ptr) 243 | assertEqual('MyBuf ', p.ctype.create_name) 244 | end 245 | 246 | function should.parseClassByValueParam() 247 | local Simple = ins:find('Simple') 248 | local met = Simple:method('showSimple') 249 | local p = met.params_list[1] 250 | assertEqual('Simple', p.ctype.name) 251 | assertFalse(p.ctype.ptr) 252 | assertEqual('Simple ', p.ctype.create_name) 253 | end 254 | 255 | --=============================================== method name 256 | 257 | function should.parseRegistrationName() 258 | local c = ins:find('Map') 259 | local m = c:method('foo') 260 | assertEqual('bar', m.dub.name) 261 | end 262 | 263 | --=============================================== registration name 264 | 265 | function should.parseRegistrationName() 266 | local c = ins:find('Reg') 267 | assertEqual('Reg_core', c.dub.register) 268 | end 269 | 270 | should:test() 271 | -------------------------------------------------------------------------------- /test/inspect_template_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector 4 | ------------- 5 | 6 | Test template parsing and introspective operations with 7 | the 'template' group of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - template', {coverage = false}) 15 | 16 | local ins = dub.Inspector { 17 | INPUT = 'test/fixtures/template', 18 | doc_dir = lub.path '|tmp', 19 | } 20 | 21 | --=============================================== TESTS 22 | function should.findCTemplate() 23 | local TVect = ins:find('TVect') 24 | assertEqual('dub.CTemplate', TVect.type) 25 | end 26 | 27 | function should.haveCTemplateParams() 28 | local TVect = ins:find('TVect') 29 | local res = {} 30 | assertValueEqual({'T'}, TVect.template_params) 31 | end 32 | 33 | function should.findCTemplateInNamespace() 34 | local obj = ins:find('Nem::TRect') 35 | assertEqual('dub.CTemplate', obj.type) 36 | end 37 | 38 | function should.haveAttributes() 39 | local obj = ins:find('TVect') 40 | local res = {} 41 | for attr in obj:attributes() do 42 | table.insert(res, attr.name .. ':' .. attr.ctype.name) 43 | end 44 | assertValueEqual({'x:T', 'y:T'}, res) 45 | end 46 | 47 | function should.haveAttributesInNamespace() 48 | local obj = ins:find('Nem::TRect') 49 | local res = {} 50 | for attr in obj:attributes() do 51 | table.insert(res, attr.name .. ':' .. attr.ctype.name) 52 | end 53 | assertValueEqual({ 54 | 'x1:T', 55 | 'y1:T', 56 | 'x2:T', 57 | 'y2:T', 58 | }, res) 59 | end 60 | 61 | function should.resolveTypedef() 62 | local obj = ins:find('Vectf') 63 | assertEqual('dub.Class', obj.type) 64 | assertEqual('Vectf', obj.name) 65 | end 66 | 67 | function should.resolveAttributeTypes() 68 | local obj = ins:find('Vectf') 69 | local res = {} 70 | for attr in obj:attributes() do 71 | table.insert(res, attr.name .. ':' .. attr.ctype.name) 72 | end 73 | assertValueEqual({ 74 | 'x:float', 75 | 'y:float', 76 | }, res) 77 | end 78 | 79 | function should.resolveTypedefInNamespace() 80 | local obj = ins:find('nmRect32') 81 | assertEqual('dub.Class', obj.type) 82 | assertEqual('nmRect32', obj.name) 83 | end 84 | 85 | function should.resolveAttributeTypesInNamespace() 86 | local obj = ins:find('nmRect32') 87 | local res = {} 88 | for attr in obj:attributes() do 89 | table.insert(res, attr.name .. ':' .. attr.ctype.name) 90 | end 91 | assertValueEqual({ 92 | 'x1:int32_t', 93 | 'y1:int32_t', 94 | 'x2:int32_t', 95 | 'y2:int32_t', 96 | }, res) 97 | end 98 | 99 | function should.resolveParamTypes() 100 | local Vectf = ins:find('Vectf') 101 | local met = Vectf:method('addToX') 102 | local p = met.params_list[1] 103 | assertEqual('float', p.ctype.name) 104 | end 105 | 106 | function should.resolveReturnValue() 107 | local Vectf = ins:find('Vectf') 108 | local met = Vectf:method('surface') 109 | assertEqual('float', met.return_value.name) 110 | met = Vectf:method('addToX') 111 | assertEqual('float', met.return_value.name) 112 | end 113 | 114 | function should.resolveParamTypesInStatic() 115 | local Vectf = ins:find('Vectf') 116 | local met = Vectf:method('addTwo') 117 | local p = met.params_list[1] 118 | assertEqual('float', p.ctype.name) 119 | assertEqual('float', met.return_value.name) 120 | end 121 | 122 | function should.resolveConstParam() 123 | local Vectf = ins:find('Vectf') 124 | local met = Vectf:method('operator+') 125 | local p = met.params_list[1] 126 | assertEqual('Vectf', p.ctype.name) 127 | assertEqual('Vectf', met.return_value.name) 128 | end 129 | 130 | function should.listMethods() 131 | local Vectf = ins:find('Vectf') 132 | local res = {} 133 | for meth in Vectf:methods() do 134 | table.insert(res, meth.name) 135 | end 136 | assertValueEqual({ 137 | '~Vectf', 138 | Vectf.SET_ATTR_NAME, 139 | Vectf.GET_ATTR_NAME, 140 | 'Vectf', 141 | 'surface', 142 | 'operator+', 143 | 'addToX', 144 | 'addTwo', 145 | }, res) 146 | end 147 | 148 | function should.ignoreTemplatedMembers() 149 | local Foo = ins:find('Foo') 150 | local res = {} 151 | for meth in Foo:methods() do 152 | table.insert(res, meth.name) 153 | end 154 | assertValueEqual({ 155 | '~Foo', 156 | }, res) 157 | end 158 | 159 | should:test() 160 | 161 | -------------------------------------------------------------------------------- /test/inspect_thread_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Inspector test 4 | ------------------ 5 | 6 | Test introspective operations with the 'thread' group 7 | of classes. 8 | 9 | --]]------------------------------------------------------ 10 | local lub = require 'lub' 11 | local lut = require 'lut' 12 | local dub = require 'dub' 13 | 14 | local should = lut.Test('dub.Inspector - thread', {coverage = false}) 15 | 16 | local ins = dub.Inspector { 17 | INPUT = 'test/fixtures/thread', 18 | doc_dir = lub.path '|tmp', 19 | } 20 | 21 | local Callback = ins:find('Callback') 22 | --=============================================== TESTS 23 | 24 | function should.useCustomPush() 25 | assertEqual('dub_pushobject', Callback.dub.push) 26 | end 27 | 28 | should:test() 29 | 30 | -------------------------------------------------------------------------------- /test/lua_box2d_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | box2d dub.Inspector test 4 | ------------------------ 5 | 6 | Test introspective operations with 'box2d' headers. To 7 | enable these tests, download Box2D into 8 | test/fixtures/Box2D. 9 | 10 | --]]------------------------------------------------------ 11 | local lub = require 'lub' 12 | local lut = require 'lut' 13 | local dub = require 'dub' 14 | 15 | local should = lut.Test('dub.LuaBinder - Box2D', {coverage = false}) 16 | 17 | --=============================================== Only if Box2D present 18 | local box2d_path = lub.path '|fixtures/Box2D' 19 | if not lub.exist(box2d_path) then 20 | return 21 | end 22 | 23 | local should = test.Suite('dub.Inspector - Box2D') 24 | 25 | local ins = dub.Inspector { 26 | INPUT = { 27 | box2d_path .. '/Box2D/Common', 28 | box2d_path .. '/Box2D/Collision', 29 | box2d_path .. '/Box2D/Collision/Shapes', 30 | box2d_path .. '/Box2D/Dynamics', 31 | }, 32 | doc_dir = lub.path '|tmp', 33 | } 34 | local binder = dub.LuaBinder() 35 | 36 | 37 | function should.resolveUint8() 38 | local b2ContactFeature = ins:find('b2ContactFeature') 39 | local indexA = b2ContactFeature.variables_list[1] 40 | assertEqual('indexA', indexA.name) 41 | assertEqual('uint8', indexA.ctype.name) 42 | local rtype = binder:luaType(b2ContactFeature, indexA.ctype) 43 | assertEqual('number', rtype.type) 44 | end 45 | 46 | function should.resolveUnsignedInt() 47 | local b2ContactID = ins:find('b2ContactID') 48 | local key = b2ContactID.variables_list[2] 49 | assertEqual('key', key.name) 50 | assertEqual('uint32', key.ctype.name) 51 | local rtype = binder:luaType(b2ContactID, key.ctype) 52 | assertEqual('number', rtype.type) 53 | end 54 | 55 | --=============================================== Build 56 | 57 | function should.bindCompileAndLoad() 58 | -- create tmp directory 59 | local tmp_path = lub.path '|tmp' 60 | lub.rmTree(tmp_path, true) 61 | os.execute('mkdir -p ' .. tmp_path) 62 | 63 | -- How to avoid this step ? 64 | local c = ins:find('b2Vec2') 65 | 66 | binder:bind(ins, { 67 | output_directory = tmp_path, 68 | only = { 69 | 'b2Vec2', 70 | 'b2World', 71 | 'b2BodyDef', 72 | 'b2Body', 73 | 'b2Shape', 74 | 'b2PolygonShape', 75 | 'b2CircleShape', 76 | 'b2FixtureDef', 77 | }, 78 | -- Remove this part in headers 79 | header_base = box2d_path, 80 | -- Execute all lua_open in a single go 81 | -- with lua_openb2 (creates b2.cpp). 82 | single_lib = 'b2', 83 | 84 | -- Class and function name alterations 85 | name_filter = function(elem) 86 | local name = elem.name 87 | if name then 88 | name = string.match(name, '^b2(.+)') or name 89 | end 90 | return name 91 | end, 92 | 93 | const_name_filter = function(name) 94 | name = string.match(name, '^b2_(.+)') or name 95 | return name 96 | end, 97 | 98 | }) 99 | 100 | local cpath_bak = package.cpath 101 | assertPass(function() 102 | -- Build static lib 103 | 104 | -- Build b2Vec2.so 105 | binder:build { 106 | output = 'test/tmp/b2.so', 107 | inputs = { 108 | -- Build this one with cmake 109 | 'test/fixtures/Box2D/libBox2D.a', 110 | 'test/tmp/dub/dub.cpp', 111 | 'test/tmp/*.cpp', 112 | }, 113 | includes = { 114 | 'test/tmp', 115 | -- This is for lua.h 116 | 'test/tmp/dub', 117 | box2d_path, 118 | 'test/fixtures/Box2D', 119 | }, 120 | } 121 | package.cpath = tmp_path .. '/?.so' 122 | --require 'Box' 123 | require 'b2' 124 | assertType('table', b2.Vec2) 125 | end, function() 126 | -- teardown 127 | package.loaded.b2 = nil 128 | package.cpath = cpath_bak 129 | if not b2.Vec2 then 130 | lut.Test.abort = true 131 | end 132 | end) 133 | end 134 | 135 | --=============================================== Box2D Hello World 136 | 137 | function should.loadLib() 138 | local v = b2.Vec2(0, -10) 139 | assertEqual(0, v(0)) 140 | end 141 | 142 | function should.runHelloWorld() 143 | -- Define the gravity vector. 144 | local gravity = b2.Vec2(0.0, -10.0) 145 | 146 | -- Construct a world object, which will hold and simulate the rigid bodies. 147 | local world = b2.World(gravity) 148 | 149 | -- Define the ground body. 150 | local groundBodyDef = b2.BodyDef() 151 | groundBodyDef.position:Set(0.0, -10.0) 152 | -- Call the body factory which allocates memory for the ground body 153 | -- from a pool and creates the ground box shape (also from a pool). 154 | -- The body is also added to the world. 155 | local groundBody = world:CreateBody(groundBodyDef) 156 | 157 | -- Define the ground box shape. 158 | local groundBox = b2.PolygonShape() 159 | -- The extents are the half-widths of the box. 160 | groundBox:SetAsBox(50.0, 10.0) 161 | 162 | -- Add the ground fixture to the ground body. 163 | groundBody:CreateFixture(groundBox, 0.0) 164 | 165 | -- Define the dynamic body. We set its position and call the body factory. 166 | local bodyDef = b2.BodyDef() 167 | bodyDef.type = b2.dynamicBody 168 | bodyDef.position:Set(0.0, 4.0) 169 | local body = world:CreateBody(bodyDef) 170 | -- Define another box shape for our dynamic body. 171 | local dynamicBox = b2.PolygonShape() 172 | dynamicBox:SetAsBox(1.0, 1.0) 173 | 174 | -- Define the dynamic body fixture. 175 | local fixtureDef = b2.FixtureDef() 176 | 177 | fixtureDef.shape = dynamicBox 178 | 179 | -- Set the box density to be non-zero, so it will be dynamic. 180 | fixtureDef.density = 1.0 181 | 182 | -- Override the default friction. 183 | fixtureDef.friction = 0.3 184 | 185 | -- Add the shape to the body. 186 | body:CreateFixture(fixtureDef) 187 | -- Prepare for simulation. Typically we use a time step of 1/60 of a 188 | -- second (60Hz) and 10 iterations. This provides a high quality simulation 189 | -- in most game scenarios. 190 | local timeStep = 1.0 / 60.0 191 | local velocityIterations = 6 192 | local positionIterations = 2 193 | 194 | -- This is our little game loop. 195 | for i=1,60 do 196 | -- Instruct the world to perform a single step of simulation. 197 | -- It is generally best to keep the time step and iterations fixed. 198 | world:Step(timeStep, velocityIterations, positionIterations) 199 | 200 | -- Now print the position and angle of the body. 201 | local position = body:GetPosition() 202 | local angle = body:GetAngle() 203 | 204 | --printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle) 205 | end 206 | 207 | -- When the world destructor is called, all bodies and joints are freed. This can 208 | -- create orphaned pointers, so be careful about your world management. 209 | end 210 | 211 | should:test() 212 | 213 | -------------------------------------------------------------------------------- /test/lua_constants_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | param_ 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test binding with the 'constants' group of classes: 7 | 8 | * passing classes around as arguments. 9 | * casting script strings to std::string. 10 | * casting std::string to script strings. 11 | * accessing complex public members. 12 | * accessing public members 13 | * return value optimization 14 | 15 | --]]------------------------------------------------------ 16 | local lub = require 'lub' 17 | local lut = require 'lut' 18 | local dub = require 'dub' 19 | 20 | local should = lut.Test('dub.LuaBinder - constants', {coverage = false}) 21 | 22 | local binder = dub.LuaBinder() 23 | -- dummy 24 | local elapsed = function() return 0 end 25 | 26 | local ins = dub.Inspector { 27 | INPUT = lub.path '|fixtures/constants', 28 | doc_dir = lub.path '|tmp', 29 | } 30 | 31 | local traffic 32 | 33 | --=============================================== Constants in mt table 34 | function should.haveConstantsInMetatable() 35 | local Car = ins:find('Car') 36 | local res = binder:bindClass(Car) 37 | assertMatch('"Smoky".*Car::Smoky', res) 38 | end 39 | 40 | function should.resolveEnumTypeAsNumber() 41 | local Car = ins:find('Car') 42 | local res = binder:bindClass(Car) 43 | local met = Car:method(Car.SET_ATTR_NAME) 44 | local lua = binder:luaType(Car, {name = 'Brand'}) 45 | assertEqual('number', lua.type) 46 | assertEqual('integer', lua.check) 47 | assertEqual('Car::Brand', lua.rtype.cast) 48 | end 49 | 50 | function should.resolveGlobalEnumTypeAsNumber() 51 | local Car = ins:find('Car') 52 | local lua = binder:luaType(Car, {name = 'GlobalConstant'}) 53 | assertEqual('number', lua.type) 54 | assertEqual('GlobalConstant', lua.rtype.cast) 55 | end 56 | 57 | --=============================================== Set/Get enum type. 58 | function should.castValueForEnumTypes() 59 | local Car = ins:find('Car') 60 | -- __newindex for simple (native) types 61 | local Car = ins:find('Car') 62 | local set = Car:method(Car.SET_ATTR_NAME) 63 | local res = binder:functionBody(set) 64 | assertMatch('self%->brand = %(Car::Brand%)luaL_checkinteger%(L, 3%);', res) 65 | end 66 | 67 | --=============================================== Build 68 | function should.bindCompileAndLoad() 69 | local ins = dub.Inspector { 70 | INPUT = lub.path '|fixtures/constants', 71 | doc_dir = lub.path '|tmp', 72 | } 73 | 74 | -- create tmp directory 75 | local tmp_path = lub.path '|tmp' 76 | os.execute("mkdir -p "..tmp_path) 77 | 78 | binder:bind(ins, { 79 | output_directory = tmp_path, 80 | -- Execute all lua_open in a single go 81 | -- with lua_openb2 (creates traffic.cpp). 82 | single_lib = 'traffic', 83 | -- Attribute name filter 84 | attr_name_filter = function(attr) 85 | return attr.name:match('^(.*)_') or attr.name 86 | end, 87 | }) 88 | 89 | local cpath_bak = package.cpath 90 | assertPass(function() 91 | 92 | -- Build traffic.so 93 | binder:build { 94 | output = lub.path '|tmp/traffic.so', 95 | inputs = { 96 | lub.path '|tmp/dub/dub.cpp', 97 | lub.path '|tmp/traffic_Car.cpp', 98 | lub.path '|tmp/traffic.cpp', 99 | }, 100 | includes = { 101 | lub.path '|tmp', 102 | -- This is for lua.h 103 | lub.path '|tmp/dub', 104 | lub.path '|fixtures/constants', 105 | }, 106 | } 107 | 108 | package.cpath = tmp_path .. '/?.so' 109 | -- Must require Car first because Box depends on Car class and 110 | -- only Car.so has static members for Car. 111 | traffic = require 'traffic' 112 | assertType('table', traffic.Car) 113 | end, function() 114 | -- teardown 115 | package.loaded.traffic = nil 116 | package.cpath = cpath_bak 117 | if not traffic or not traffic.Car then 118 | lut.Test.abort = true 119 | else 120 | Car = traffic.Car 121 | end 122 | end) 123 | --lk.rmTree(tmp_path, true) 124 | end 125 | 126 | --=============================================== Constants access 127 | 128 | function should.createCarObject() 129 | local c = Car('any') 130 | assertType('userdata', c) 131 | assertEqual('any', c.name) 132 | end 133 | 134 | function should.castInputParams() 135 | local c = Car('any', Car.Smoky) 136 | assertEqual(Car.Smoky, c.brand) 137 | c:setBrand(Car.Dangerous) 138 | assertEqual('Dangerous', c:brandName()) 139 | end 140 | 141 | function should.readEnumAttribute() 142 | local c = Car('any', Car.Smoky) 143 | assertEqual(Car.Smoky, c.brand) 144 | assertEqual('Smoky', c:brandName()) 145 | end 146 | 147 | function should.writeEnumAttribute() 148 | local c = Car('any', Car.Smoky) 149 | c.brand = Car.Dangerous 150 | assertEqual(Car.Dangerous, c.brand) 151 | assertEqual('Dangerous', c:brandName()) 152 | end 153 | 154 | function should.writeBadEnumValue() 155 | local c = Car('any', Car.Smoky) 156 | c.brand = 938 157 | assertEqual(938, c.brand) 158 | assertEqual('???', c:brandName()) 159 | end 160 | 161 | function should.readGlobalConstant() 162 | assertEqual(1, traffic.One) 163 | assertEqual(2, traffic.Two) 164 | assertEqual(55, traffic.Three) 165 | end 166 | 167 | --=============================================== Car alternate binding style 168 | 169 | function should.respondToNew() 170 | local Car = Car 171 | local c = Car.new('any', Car.Dangerous) 172 | assertEqual('Dangerous', c:brandName()) 173 | c.brand = Car.Noisy 174 | assertEqual('Noisy', c:brandName()) 175 | end 176 | 177 | --=============================================== Compare speed with extra metatable 178 | 179 | local function createMany(ctor) 180 | local Noisy = Car.Noisy 181 | local t = {} 182 | collectgarbage('stop') 183 | local start = elapsed() 184 | for i = 1,100000 do 185 | table.insert(t, ctor('simple string', Noisy)) 186 | end 187 | local elapsed = elapsed() - start 188 | t = nil 189 | collectgarbage('collect') 190 | return elapsed 191 | end 192 | 193 | local function runGcTest(ctor, fmt) 194 | -- warmup 195 | createMany(ctor) 196 | local vm_size = collectgarbage('count') 197 | if fmt then 198 | local t = createMany(ctor) 199 | printf(fmt, t) 200 | else 201 | createMany(ctor) 202 | end 203 | assertEqual(vm_size, collectgarbage('count'), 1.5) 204 | end 205 | 206 | 207 | function should.createAndDestroy() 208 | if test_speed then 209 | local lens = require 'lens' 210 | elapsed = lens.elapsed 211 | runGcTest(Car.new, "Car.new: create 100'000 elements: %.2f ms.") 212 | runGcTest(Car, "Car: create 100'000 elements: %.2f ms.") 213 | else 214 | runGcTest(Car) 215 | end 216 | end 217 | 218 | should:test() 219 | 220 | -------------------------------------------------------------------------------- /test/lua_inherit_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | param_ 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test binding with the 'inherit' group of classes: 7 | 8 | * binding attributes accessor with super attributes. 9 | * binding methods from super classes. 10 | * custom bindings. 11 | * cast to super type when needed. 12 | 13 | --]]------------------------------------------------------ 14 | local lub = require 'lub' 15 | local lut = require 'lut' 16 | local dub = require 'dub' 17 | 18 | local should = lut.Test('dub.LuaBinder - inherit', {coverage = false}) 19 | local binder = dub.LuaBinder() 20 | 21 | local ins = dub.Inspector { 22 | INPUT = lub.path '|fixtures/inherit', 23 | doc_dir = lub.path '|tmp', 24 | } 25 | 26 | local Child, Parent, Orphan 27 | 28 | function should.setup() 29 | dub.warn = dub.silentWarn 30 | end 31 | 32 | function should.teardown() 33 | dub.warn = dub.printWarn 34 | end 35 | 36 | --=============================================== Set/Get vars. 37 | function should.bindSetMethodWithSuperAttrs() 38 | -- __newindex for simple (native) types 39 | local Child = ins:find('Child') 40 | local set = Child:method(Child.SET_ATTR_NAME) 41 | local res = binder:bindClass(Child) 42 | assertMatch('__newindex.*Child__set_', res) 43 | local res = binder:functionBody(Child, set) 44 | assertMatch('self%->birth_year = luaL_checknumber%(L, 3%);', res) 45 | end 46 | 47 | function should.bindGetMethodWithSuperAttrs() 48 | -- __newindex for simple (native) types 49 | local Child = ins:find('Child') 50 | local get = Child:method(Child.GET_ATTR_NAME) 51 | local res = binder:bindClass(Child) 52 | assertMatch('__index.*Child__get_', res) 53 | local res = binder:functionBody(Child, get) 54 | assertMatch('lua_pushnumber%(L, self%->birth_year%);', res) 55 | end 56 | 57 | function should.bindCastWithTemplateParent() 58 | -- __newindex for simple (native) types 59 | local Orphan = ins:find('Orphan') 60 | local met = Orphan:method(Orphan.CAST_NAME) 61 | local res = binder:functionBody(Orphan, met) 62 | assertMatch('%*retval__ = static_cast %*>%(self%);', res) 63 | end 64 | 65 | function should.notBindSuperStaticMethods() 66 | local Child = ins:find('Child') 67 | local res = binder:bindClass(Child) 68 | assertNotMatch('getName', res) 69 | end 70 | 71 | --=============================================== Unknown type 72 | 73 | function should.properlyBindUnknownTypes() 74 | local Child = ins:find('Child') 75 | local met = Child:method('methodWithUnknown') 76 | local res = binder:functionBody(Child, met) 77 | assertMatch('Unk1 %*x = %*%(%(Unk1 %*%*%)dub::checksdata%(L, 2, "Unk1"%)%);', res) 78 | assertMatch('Unk2 %*y = %*%(%(Unk2 %*%*%)dub::checksdata%(L, 3, "Unk2"%)%);', res) 79 | assertMatch('methodWithUnknown%(%*x, y%)', res) 80 | end 81 | 82 | --=============================================== Compile 83 | 84 | function should.bindCompileAndLoad() 85 | local tmp_path = lub.path '|tmp' 86 | -- create tmp directory 87 | lub.rmTree(tmp_path, true) 88 | os.execute('mkdir -p '..tmp_path) 89 | 90 | binder:bind(ins, { 91 | output_directory = lub.path '|tmp', 92 | custom_bindings = lub.path '|fixtures/inherit', 93 | extra_headers = { 94 | Child = { 95 | lub.path "|fixtures/inherit_hidden/Mother.h", 96 | } 97 | } 98 | }) 99 | 100 | local cpath_bak = package.cpath 101 | local s 102 | assertPass(function() 103 | -- Build Child.so 104 | -- 105 | binder:build { 106 | output = lub.path '|tmp/Child.so', 107 | inputs = { 108 | lub.path '|tmp/dub/dub.cpp', 109 | lub.path '|tmp/Child.cpp', 110 | lub.path '|fixtures/inherit/child.cpp', 111 | }, 112 | includes = { 113 | lub.path '|tmp', 114 | -- This is for lua.h 115 | lub.path '|tmp/dub', 116 | lub.path '|fixtures/inherit', 117 | }, 118 | } 119 | 120 | -- Build Parent.so 121 | binder:build { 122 | output = lub.path '|tmp/Parent.so', 123 | inputs = { 124 | lub.path '|tmp/dub/dub.cpp', 125 | lub.path '|tmp/Parent.cpp', 126 | }, 127 | includes = { 128 | lub.path '|tmp', 129 | -- This is for lua.h 130 | lub.path '|tmp/dub', 131 | lub.path '|fixtures/inherit', 132 | }, 133 | } 134 | 135 | -- Build Orphan.so 136 | binder:build { 137 | output = lub.path '|tmp/Orphan.so', 138 | inputs = { 139 | lub.path '|tmp/dub/dub.cpp', 140 | lub.path '|tmp/Orphan.cpp', 141 | }, 142 | includes = { 143 | lub.path '|tmp', 144 | -- This is for lua.h 145 | lub.path '|tmp/dub', 146 | lub.path '|fixtures/inherit', 147 | }, 148 | } 149 | 150 | package.cpath = tmp_path .. '/?.so' 151 | Child = require 'Child' 152 | Parent = require 'Parent' 153 | Orphan = require 'Orphan' 154 | assertType('table', Child) 155 | end, function() 156 | -- teardown 157 | package.loaded.Child = nil 158 | package.loaded.Parent = nil 159 | package.cpath = cpath_bak 160 | if not Child then 161 | lut.Test.abort = true 162 | end 163 | end) 164 | --lk.rmTree(tmp_path, true) 165 | end 166 | 167 | --=============================================== Inheritance 168 | 169 | function should.createChildObject() 170 | local c = Child('Romulus', Parent.Depends, -771, 1.23, 2.34) 171 | assertType('userdata', c) 172 | end 173 | 174 | function should.readChildAttributes() 175 | local c = Child('Romulus', Parent.Single, -771, 1.23, 2.34) 176 | assertEqual(-771, c.birth_year) 177 | assertTrue(c.happy) 178 | assertEqual(Child.Single) 179 | assertNil(c.asdfasd) 180 | end 181 | 182 | function should.writeChildAttributes() 183 | local c = Child('Romulus', Parent.Poly, -771, 1.23, 2.34) 184 | assertError("invalid key 'asdfasd'", function() 185 | c.asdfasd = 15 186 | end) 187 | c.birth_year = 2000 188 | assertEqual(2000, c.birth_year) 189 | c.status = Parent.Single 190 | assertEqual(Parent.Single, c.status) 191 | end 192 | 193 | function should.executeSuperMethods() 194 | local c = Child('Romulus', Parent.Poly, -771, 1.23, 2.34) 195 | assertEqual(2783, c:computeAge(2012)) 196 | end 197 | 198 | --=============================================== Cast 199 | 200 | function should.castInCalls() 201 | local c = Child('Romulus', Parent.Married, -771, 1.23, 2.34) 202 | local p = Parent('Rhea', Parent.Single, -800) 203 | assertEqual('Romulus', Parent.getName(c)) 204 | assertEqual('Rhea', Parent.getName(p)) 205 | end 206 | 207 | --=============================================== Custom bindings 208 | 209 | function should.useCustomBindings() 210 | local c = Child('Romulus', Parent.Depends, -771, 1.23, 2.34) 211 | local x, y = c:position() 212 | assertEqual(1.23, x) 213 | assertEqual(2.34, y) 214 | end 215 | 216 | function should.useCustomBindingsWithDefaultValue() 217 | local c = Child('Romulus', Parent.Depends, -771, 1.23, 2.34) 218 | assertEqual(5.23, c:addToX()) 219 | assertEqual(2.23, c:addToX(1)) 220 | end 221 | 222 | --=============================================== Unknown types 223 | 224 | function should.useUnknownTypes() 225 | local w = dub.warn 226 | dub.warn = function() end 227 | local c = Child('Romulus', Parent.Depends, -771, 1.23, 2.34) 228 | local f, b = c:returnUnk1(4), c:returnUnk2(5) 229 | dub.warn = w 230 | assertEqual(9, c:methodWithUnknown(f, b)) 231 | end 232 | 233 | should:test() 234 | 235 | -------------------------------------------------------------------------------- /test/lua_memory_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test binding with the 'memory' group of classes: 7 | 8 | * no gc optimization 9 | 10 | --]]------------------------------------------------------ 11 | local lub = require 'lub' 12 | local lut = require 'lut' 13 | local dub = require 'dub' 14 | 15 | local should = lut.Test('dub.LuaBinder - memory', {coverage = false}) 16 | 17 | local binder = dub.LuaBinder() 18 | local elapsed = function() return 0 end 19 | 20 | local ins_opts = { 21 | INPUT = lub.path '|fixtures/memory', 22 | doc_dir = lub.path '|tmp', 23 | PREDEFINED = { 24 | 'SOME_FUNCTION_MACRO(x)=', 25 | 'OTHER_FUNCTION_MACRO(x)=', 26 | } 27 | } 28 | local ins = dub.Inspector(ins_opts) 29 | 30 | local mem 31 | 32 | --=============================================== Nogc bindings 33 | 34 | function should.bindClass() 35 | local Nogc = ins:find('Nogc') 36 | local res = binder:bindClass(Nogc) 37 | assertMatch('luaopen_Nogc', res) 38 | end 39 | 40 | function should.notBindDestructor() 41 | local Nogc = ins:find('Nogc') 42 | local res = binder:bindClass(Nogc) 43 | assertNotMatch('__gc', res) 44 | end 45 | 46 | function should.pushFullUserdataInRetval() 47 | local Nogc = ins:find('Nogc') 48 | local met = Nogc:method('operator+') 49 | local res = binder:functionBody(Nogc, met) 50 | assertMatch('dub::pushfulldata%(L, self%->operator%+%(%*v%), "Nogc"%);', res) 51 | end 52 | 53 | function should.useCustomPush() 54 | local Pen = ins:find('Pen') 55 | local met = Pen:method('Pen') 56 | local res = binder:functionBody(Pen, met) 57 | assertMatch('retval__%->dub_pushobject%(L, retval__, "Pen", true%);', res) 58 | end 59 | 60 | function should.bindDestructor() 61 | local Withgc = ins:find('Withgc') 62 | local res = binder:bindClass(Withgc) 63 | assertMatch('__gc', res) 64 | end 65 | 66 | --=============================================== Build 67 | 68 | function should.bindCompileAndLoad() 69 | -- create tmp directory 70 | local tmp_path = lub.path '|tmp' 71 | lub.rmTree(tmp_path, true) 72 | os.execute("mkdir -p "..tmp_path) 73 | 74 | local ins = dub.Inspector(ins_opts) 75 | binder:bind(ins, { 76 | output_directory = tmp_path, 77 | single_lib = 'mem', 78 | attr_name_filter = function(elem) 79 | return elem.name:match('(.*)_$') or elem.name 80 | end, 81 | }) 82 | local cpath_bak = package.cpath 83 | assertPass(function() 84 | -- Build mem.so 85 | binder:build { 86 | output = lub.path '|tmp/mem.so', 87 | inputs = { 88 | lub.path '|tmp/dub/dub.cpp', 89 | lub.path '|tmp/mem_Nogc.cpp', 90 | lub.path '|tmp/mem_Withgc.cpp', 91 | lub.path '|tmp/mem_Union.cpp', 92 | lub.path '|tmp/mem_Pen.cpp', 93 | lub.path '|tmp/mem_Owner.cpp', 94 | lub.path '|tmp/mem_PrivateDtor.cpp', 95 | lub.path '|tmp/mem_CustomDtor.cpp', 96 | lub.path '|tmp/mem_NoDtor.cpp', 97 | lub.path '|tmp/mem_NoDtorCleaner.cpp', 98 | lub.path '|fixtures/memory/owner.cpp', 99 | lub.path '|tmp/mem.cpp', 100 | }, 101 | includes = { 102 | lub.path '|tmp', 103 | -- This is for lua.h 104 | lub.path '|tmp/dub', 105 | lub.path '|fixtures/memory', 106 | }, 107 | } 108 | package.cpath = tmp_path .. '/?.so' 109 | --require 'Box' 110 | mem = require 'mem' 111 | assertType('table', mem) 112 | end, function() 113 | -- teardown 114 | package.cpath = cpath_bak 115 | if not mem then 116 | lut.Test.abort = true 117 | end 118 | end) 119 | --lub.rmTree(tmp_path, true) 120 | end 121 | 122 | --=============================================== Nogc 123 | 124 | local function createAndDestroyMany(ctor) 125 | local t = {} 126 | local start = elapsed() 127 | for i = 1,100000 do 128 | table.insert(t, ctor(1,3)) 129 | end 130 | t = nil 131 | collectgarbage() 132 | collectgarbage() 133 | return elapsed() - start 134 | end 135 | 136 | local function runGcTest(ctor, fmt) 137 | -- warmup 138 | createAndDestroyMany(ctor) 139 | local vm_size = collectgarbage('count') 140 | if fmt then 141 | local t = createAndDestroyMany(ctor) 142 | printf(fmt, t) 143 | else 144 | createAndDestroyMany(ctor) 145 | end 146 | assertEqual(vm_size, collectgarbage('count'), 1.5) 147 | end 148 | 149 | function should.createAndDestroy() 150 | if test_speed then 151 | local lens = require 'lens' 152 | elapsed = lens.elapsed 153 | runGcTest(mem.Nogc.new, "__gc optimization: create and destroy 100'000 elements: %.2f ms.") 154 | runGcTest(mem.Withgc.new, "Normal __gc: create and destroy 100'000 elements: %.2f ms.") 155 | runGcTest(mem.Withgc, "Normal __gc and __call: create and destroy 100'000 elements: %.2f ms.") 156 | else 157 | runGcTest(mem.Nogc.new) 158 | runGcTest(mem.Withgc.new) 159 | end 160 | end 161 | 162 | --=============================================== UNION 163 | 164 | function should.destroyFromLua() 165 | local p = mem.Pen('Arty') 166 | local o = mem.Owner() 167 | p:setOwner(o) 168 | p = nil 169 | collectgarbage() 170 | collectgarbage() 171 | -- Destructor called in C++ 172 | assertEqual("Pen 'Arty' is dying...", o.message) 173 | end 174 | 175 | function should.destroyFromCpp() 176 | local p = mem.Pen('Arty') 177 | local o = mem.Owner(p) 178 | o:destroyPen() 179 | -- Destructor called in C++ 180 | assertEqual("Pen 'Arty' is dying...", o.message) 181 | -- Object is dead in Lua 182 | assertError('lua_memory_test.lua:[0-9]+: name: using deleted mem.Pen', function() 183 | p:name() 184 | end) 185 | assertTrue(p:deleted()) 186 | end 187 | 188 | function should.considerAnonUnionAsMembers() 189 | local u = mem.Union(10, 15, 4, 100) 190 | assertEqual(10, u.h) 191 | assertEqual(15, u.s) 192 | assertEqual(4, u.v) 193 | assertEqual(100, u.a) 194 | local c = 10 + (15 * 2^8) + (4 * 2^16) + (100 * 2^24) 195 | assertEqual(c, u.c) 196 | 197 | u.a = 11 198 | local c = 10 + (15 * 2^8) + (4 * 2^16) + (11 * 2^24) 199 | assertEqual(c, u.c) 200 | end 201 | 202 | --=============================================== Custom dtor 203 | 204 | function should.useCustomDtor() 205 | local d = mem.CustomDtor() 206 | local t 207 | function d:callback() 208 | t = true 209 | end 210 | assertNil(t) 211 | d = nil 212 | collectgarbage('collect') 213 | collectgarbage('collect') 214 | assertTrue(t) 215 | end 216 | 217 | --=============================================== No dtor 218 | 219 | function should.notUseDtor() 220 | local d = mem.NoDtor('Hulk') 221 | local cleaner = mem.NoDtorCleaner(d) 222 | local t 223 | -- When d is deleted, it calls cleaner->deleted which 224 | -- calls this callback. 225 | function cleaner:callback(s) 226 | t = s 227 | end 228 | assertNil(t) 229 | d = nil 230 | collectgarbage('collect') 231 | collectgarbage('collect') 232 | -- Callback not called: d is not deleted 233 | assertNil(t) 234 | -- Explicitely delete attached NoDtor. 235 | cleaner:cleanup() 236 | -- Callback called: d is deleted 237 | assertEqual('Hulk', t) 238 | end 239 | 240 | should:test() 241 | 242 | -------------------------------------------------------------------------------- /test/lua_namespace_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test binding with the 'namespace' group of classes: 7 | 8 | * nested classes 9 | * proper namespace in bindings 10 | 11 | --]]------------------------------------------------------ 12 | local lub = require 'lub' 13 | local lut = require 'lut' 14 | local dub = require 'dub' 15 | 16 | local should = lut.Test('dub.LuaBinder - namespace', {coverage = false}) 17 | local binder = dub.LuaBinder() 18 | 19 | binder:parseCustomBindings(lub.path '|fixtures/namespace') 20 | 21 | local ins, moo 22 | 23 | function should.setup() 24 | dub.warn = dub.silentWarn 25 | if not ins then 26 | ins = dub.Inspector { 27 | INPUT = lub.path '|fixtures/namespace', 28 | doc_dir = lub.path '|tmp', 29 | } 30 | end 31 | end 32 | 33 | function should.teardown() 34 | dub.warn = dub.printWarn 35 | end 36 | 37 | --=============================================== bindings 38 | 39 | function should.bindClass() 40 | local A = ins:find('Nem::A') 41 | local res = binder:bindClass(A) 42 | assertMatch('luaopen_A', res) 43 | end 44 | 45 | function should.useFullnameInMetaName() 46 | local A = ins:find('Nem::A') 47 | local res = binder:bindClass(A) 48 | assertMatch('dub::pushudata%(L, retval__, "Nem.A", true%);', res) 49 | end 50 | 51 | function should.bindGlobalFunction() 52 | local met = ins:find('Nem::addTwo') 53 | local res = binder:functionBody(met) 54 | assertMatch('B %*a = %*%(%(B %*%*%)dub::checksdata%(L, 1, "Nem.B"%)%);', res) 55 | assertMatch('B %*b = %*%(%(B %*%*%)dub::checksdata%(L, 2, "Nem.B"%)%);', res) 56 | assertMatch('lua_pushnumber%(L, Nem::addTwo%(%*a, %*b%)%);', res) 57 | end 58 | 59 | function should.useCustomBindingsForGlobal() 60 | local met = ins:find('Nem::customGlobal') 61 | local res = binder:functionBody(met) 62 | assertMatch('float a = dub::checknumber%(L, 1%);', res) 63 | assertMatch('float b = dub::checknumber%(L, 2%);', res) 64 | assertMatch('lua_pushnumber%(L, a %+ b%);', res) 65 | assertMatch('lua_pushstring%(L, "custom global"%);', res) 66 | assertMatch('return 2;', res) 67 | end 68 | 69 | function should.bindGlobalFunctionNotInNamespace() 70 | local met = ins:find('addTwoOut') 71 | local res = binder:functionBody(met) 72 | assertMatch('B %*a = %*%(%(B %*%*%)dub::checksdata%(L, 1, "Nem.B"%)%);', res) 73 | assertMatch('B %*b = %*%(%(B %*%*%)dub::checksdata%(L, 2, "Nem.B"%)%);', res) 74 | assertMatch('lua_pushnumber%(L, addTwoOut%(%*a, %*b%)%);', res) 75 | end 76 | 77 | function should.bindAll() 78 | local tmp_path = lub.path '|tmp' 79 | lub.rmTree(tmp_path, true) 80 | 81 | binder:bind(ins, { 82 | output_directory = tmp_path, 83 | single_lib = 'moo', 84 | no_prefix = true, 85 | }) 86 | local files = {} 87 | for file in lub.Dir(tmp_path):list() do 88 | local base, filename = lub.dir(file) 89 | lub.insertSorted(files, filename) 90 | end 91 | assertValueEqual({ 92 | 'Nem_A.cpp', 93 | 'Nem_B.cpp', 94 | 'dub', 95 | 'moo.cpp', 96 | }, files) 97 | end 98 | 99 | --=============================================== nested class 100 | 101 | function should.useFullnameInCtor() 102 | local C = ins:find('Nem::B::C') 103 | local met = C:method('C') 104 | local res = binder:functionBody(met) 105 | assertMatch('B::C %*retval__', res) 106 | assertMatch('new B::C%(', res) 107 | assertMatch('dub::pushudata%(L, retval__, "Nem.B.C", true%);', res) 108 | end 109 | 110 | function should.properlyResolveReturnTypeInMethod() 111 | local C = ins:find('Nem::B') 112 | local met = C:method('getC') 113 | local res = binder:functionBody(met) 114 | assertMatch('B::C %*retval__ = self%->getC%(%);', res) 115 | assertMatch('dub::pushudata%(L, retval__, "Nem.B.C", false%);', res) 116 | end 117 | 118 | function should.properlyResolveTypeInGetAttr() 119 | local C = ins:find('Nem::B::C') 120 | local met = C:method('C') 121 | local res = binder:functionBody(met) 122 | assertMatch('B::C %*retval__', res) 123 | assertMatch('new B::C%(', res) 124 | assertMatch('dub::pushudata%(L, retval__, "Nem.B.C", true%);', res) 125 | end 126 | 127 | --=============================================== Build 128 | 129 | function should.changeNamespaceNameOnBind() 130 | -- Cannot reuse inspector with different binder settings (Nem.B.C 131 | -- found instead of moo.B.C) 132 | local ins = dub.Inspector { 133 | INPUT = { 134 | lub.path '|fixtures/namespace', 135 | -- This is just to have the Vect class for gc testing. 136 | lub.path '|fixtures/pointers', 137 | }, 138 | doc_dir = lub.path '|tmp', 139 | } 140 | 141 | local tmp_path = lub.path '|tmp' 142 | lub.rmTree(tmp_path, true) 143 | 144 | os.execute('mkdir -p '..tmp_path) 145 | -- This is how we can change namespace scoping 146 | function binder:name(elem) 147 | if elem.name == 'Nem' then 148 | return 'moo' 149 | else 150 | return elem.name 151 | end 152 | end 153 | binder:bind(ins, { 154 | output_directory = tmp_path, 155 | -- Execute all lua_open in a single go 156 | -- with lua_MyLib. 157 | -- This creates a MyLib_open.cpp file 158 | -- that has to be included in build. 159 | single_lib = 'moo', 160 | -- This is used to bind the namespace constants and 161 | -- functions. 162 | namespace = 'Nem', 163 | -- We need this to avoid nesting prefix 164 | no_prefix = true, 165 | only = { 166 | 'Nem::A', 167 | 'Nem::B', 168 | 'Nem::B::C', 169 | 'Nem::Rect', 170 | 'Vect', 171 | }, 172 | custom_bindings = lub.path '|fixtures/namespace', 173 | }) 174 | binder.name = nil 175 | local res = lub.content(tmp_path .. '/moo_A.cpp') 176 | assertNotMatch('moo%.Nem', res) 177 | assertMatch('"moo%.A"', res) 178 | assertMatch('luaopen_moo_A', res) 179 | 180 | local res = lub.content(tmp_path .. '/moo_B_C.cpp') 181 | assertNotMatch('moo%.Nem', res) 182 | assertMatch('"moo%.B%.C"', res) 183 | assertMatch('luaopen_moo_B_C', res) 184 | 185 | -- Build 'moo.so' 186 | 187 | assertPass(function() 188 | binder:build { 189 | output = lub.path '|tmp/moo.so', 190 | inputs = { 191 | lub.path '|tmp/dub/dub.cpp', 192 | lub.path '|tmp/moo_A.cpp', 193 | lub.path '|tmp/moo_B.cpp', 194 | lub.path '|tmp/moo_B_C.cpp', 195 | lub.path '|tmp/moo.cpp', 196 | lub.path '|tmp/Vect.cpp', 197 | lub.path '|tmp/moo_Rect.cpp', 198 | lub.path '|fixtures/pointers/vect.cpp', 199 | }, 200 | includes = { 201 | lub.path '|tmp', 202 | -- This is for lua.h 203 | lub.path '|tmp/dub', 204 | lub.path '|fixtures/namespace', 205 | }, 206 | } 207 | 208 | local cpath_bak = package.cpath 209 | package.cpath = tmp_path .. '/?.so' 210 | 211 | moo = require 'moo' 212 | assertType('table', moo) 213 | assertType('table', moo.A) 214 | assertType('table', moo.B) 215 | assertType('table', moo.B.C) 216 | end, function() 217 | -- teardown 218 | package.cpath = cpath_bak 219 | -- teardown 220 | package.cpath = cpath_bak 221 | if not moo then 222 | lut.Test.abort = true 223 | end 224 | end) 225 | end 226 | 227 | function should.bindGlobalFunctions() 228 | --local res = lub.content(tmp_path .. '/moo.cpp') 229 | --assertMatch('XXXXX', res) 230 | end 231 | 232 | 233 | function should.findA() 234 | local a = moo.A() 235 | assertEqual('moo.A', a.type) 236 | end 237 | 238 | function should.findB() 239 | local b = moo.B(5) 240 | assertEqual('moo.B', b.type) 241 | end 242 | 243 | function should.findC() 244 | local c = moo.B.C(99) 245 | assertEqual('moo.B.C', c.type) 246 | end 247 | 248 | function should.findNestedClass() 249 | local c = moo.B.C(456) 250 | assertEqual(456, c:nb()) 251 | local b = moo.B(c) 252 | assertEqual(456, b.c:nb()) 253 | assertEqual(456, b.nb_) 254 | end 255 | 256 | function should.useCustomAccessor() 257 | local a = moo.A() 258 | local watch = moo.Vect(0,0) 259 | assertNil(a.userdata) 260 | collectgarbage() 261 | watch.create_count = 0 262 | watch.destroy_count = 0 263 | local v = moo.Vect(3, 4) 264 | assertEqual(1, watch.create_count) 265 | a.userdata = v 266 | assertEqual(4, a.userdata.y) 267 | assertEqual(1, watch.create_count) 268 | v = nil 269 | collectgarbage() -- should not release v 270 | assertEqual(0, watch.destroy_count) 271 | a = nil 272 | collectgarbage() -- should release v 273 | collectgarbage() -- should release v 274 | assertEqual(1, watch.destroy_count) 275 | end 276 | 277 | function should.useCustomAccessor() 278 | local a = moo.A() 279 | local watch = moo.Vect(0,0) 280 | collectgarbage() 281 | watch.create_count = 0 282 | watch.destroy_count = 0 283 | local v = moo.Vect(3, 7) 284 | assertEqual(1, watch.create_count) 285 | a.userdata = v 286 | assertEqual(1, a.userdata.x) 287 | assertEqual(1, watch.create_count) 288 | v = nil 289 | collectgarbage() -- should not release v 290 | assertEqual(3, a.userdata.x) 291 | assertEqual(0, watch.destroy_count) 292 | a.userdata = nil 293 | collectgarbage() -- should release v 294 | assertEqual(1, watch.destroy_count) 295 | end 296 | 297 | function should.setAnyLuaValue() 298 | local a = moo.A() 299 | local e = {} 300 | a.userdata = e 301 | assertEqual(e, a.userdata) 302 | a.userdata = 4.53 303 | assertEqual(4.53, a.userdata) 304 | end 305 | 306 | function should.buildTemplate() 307 | local r = moo.Rect(4,3) 308 | assertEqual(4, r.w) 309 | assertEqual(3, r.h) 310 | end 311 | 312 | function should.callNamespaceFunction() 313 | local a = moo.B(1) 314 | local b = moo.B(2) 315 | assertEqual(3, moo.addTwo(a,b)) 316 | end 317 | 318 | function should.haveFunctionOutOfNamespace() 319 | assertEqual('function', type(moo.addTwoOut)) 320 | end 321 | 322 | function should.callCustomGlobal() 323 | assertValueEqual({ 324 | 9, 325 | "custom global", 326 | }, {moo.customGlobal(4, 5)}) 327 | end 328 | 329 | function should.readNamespaceConstant() 330 | assertEqual(1, moo.One) 331 | assertEqual(2, moo.Two) 332 | assertEqual(55, moo.Three) 333 | end 334 | 335 | function should.decideOver() 336 | local a = moo.A(1) 337 | local b = moo.B(2) 338 | assertPass(function() 339 | assertEqual('A', a:over(a)) 340 | end) 341 | assertPass(function() 342 | assertEqual('B', a:over(b)) 343 | end) 344 | end 345 | 346 | should:test() 347 | 348 | -------------------------------------------------------------------------------- /test/lua_pat_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test header_base path with lua patterns. 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local lut = require 'lut' 11 | local should = lut.Test('dub.LuaBinder - pat', {coverage = false}) 12 | 13 | local dirname = 'path.wi$th-[pat]' 14 | local Pat 15 | 16 | local dub = require 'dub' 17 | local binder = dub.LuaBinder() 18 | local base = lub.path('|') 19 | local ins = dub.Inspector { 20 | INPUT = base .. '/fixtures/'..dirname, 21 | -- We use a path with lua pattern characters to test. 22 | doc_dir = base .. '/tmp-[foo]', 23 | } 24 | 25 | --=============================================== TESTS 26 | 27 | function should.bindClass() 28 | local Pat = ins:find('Pat') 29 | local res 30 | assertPass(function() 31 | res = binder:bindClass(Pat, { 32 | header_base = lub.path('|fixtures/'..dirname), 33 | }) 34 | end) 35 | assertMatch('luaopen_Pat', res) 36 | assertMatch('#include "Pat.h"', res) 37 | end 38 | 39 | --=============================================== Build 40 | 41 | function should.bindCompileAndLoad() 42 | -- create tmp directory 43 | local tmp_path = base .. '/tmp-[foo]' 44 | lub.rmTree(tmp_path, true) 45 | os.execute("mkdir -p "..tmp_path) 46 | binder:bind(ins, { 47 | output_directory = tmp_path, 48 | header_base = lub.path('|fixtures/'..dirname), 49 | }) 50 | 51 | local cpath_bak = package.cpath 52 | local s 53 | assertPass(function() 54 | binder:build { 55 | output = base .. '/tmp-[foo]/Pat.so', 56 | inputs = { 57 | base .. '/tmp-[foo]/dub/dub.cpp', 58 | base .. '/tmp-[foo]/Pat.cpp', 59 | }, 60 | includes = { 61 | base .. '/tmp-[foo]', 62 | -- This is for lua.h 63 | base .. '/tmp-[foo]/dub', 64 | base .. '/fixtures/'..dirname, 65 | }, 66 | } 67 | 68 | package.cpath = base .. '/tmp-[foo]/?.so' 69 | Pat = require 'Pat' 70 | assertType('table', Pat) 71 | end, function() 72 | -- teardown 73 | package.cpath = cpath_bak 74 | if not Pat then 75 | lut.Test.abort = true 76 | end 77 | end) 78 | lub.rmTree(tmp_path, true) 79 | end 80 | 81 | --=============================================== Pat tests 82 | 83 | function should.buildObjectByCall() 84 | local s = Pat(4) 85 | assertType('userdata', s) 86 | assertEqual(4, s:value()) 87 | assertEqual(Pat, getmetatable(s)) 88 | end 89 | 90 | should:test() 91 | 92 | -------------------------------------------------------------------------------- /test/lua_template_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test binding with the 'template' group of classes: 7 | 8 | * parameter resolution 9 | * attribute resolution 10 | * chained typedef 11 | 12 | --]]------------------------------------------------------ 13 | local lub = require 'lub' 14 | local lut = require 'lut' 15 | local dub = require 'dub' 16 | 17 | local should = lut.Test('dub.LuaBinder - template', {coverage = false}) 18 | local binder = dub.LuaBinder() 19 | 20 | local ins = dub.Inspector { 21 | INPUT = 'test/fixtures/template', 22 | doc_dir = lub.path '|tmp', 23 | } 24 | 25 | local Vectf 26 | 27 | --=============================================== Vectf bindings 28 | 29 | function should.bindClass() 30 | local obj = ins:find('Vectf') 31 | local res = binder:bindClass(obj) 32 | assertMatch('luaopen_Vect', res) 33 | end 34 | 35 | function should.bindClassFromTemplateInNamespace() 36 | local obj = ins:find('nmRect32') 37 | local res = binder:bindClass(obj) 38 | assertMatch('self%->x1 = luaL_checkinteger%(L, 3%);', res) 39 | end 40 | 41 | function should.bindMethod() 42 | local obj = ins:find('Vectf') 43 | local met = obj:method('surface') 44 | local res = binder:functionBody(obj, met) 45 | assertMatch('lua_pushnumber%(L, self%->surface%(%)%);', res) 46 | end 47 | 48 | --=============================================== Build 49 | 50 | function should.bindCompileAndLoad() 51 | -- create tmp directory 52 | local tmp_path = lub.path '|tmp' 53 | lub.rmTree(tmp_path, true) 54 | os.execute("mkdir -p "..tmp_path) 55 | 56 | -- Force resolution of typedef. How to not require this step ? 57 | ins:find('Vectf') 58 | binder:bind(ins, {output_directory = tmp_path}) 59 | local cpath_bak = package.cpath 60 | assertPass(function() 61 | -- Build Vectf.so 62 | binder:build { 63 | output = 'test/tmp/Vectf.so', 64 | inputs = { 65 | 'test/tmp/dub/dub.cpp', 66 | 'test/tmp/Vectf.cpp', 67 | }, 68 | includes = { 69 | 'test/tmp', 70 | -- This is for lua.h 71 | 'test/tmp/dub', 72 | 'test/fixtures/template', 73 | }, 74 | } 75 | package.cpath = tmp_path .. '/?.so' 76 | --require 'Box' 77 | Vectf = require 'Vectf' 78 | assertType('table', Vectf) 79 | end, function() 80 | -- teardown 81 | package.loaded.Box = nil 82 | package.loaded.Vectf = nil 83 | package.cpath = cpath_bak 84 | if not Vectf then 85 | lut.Test.abort = true 86 | end 87 | end) 88 | --lub.rmTree(tmp_path, true) 89 | end 90 | 91 | --=============================================== Vectf 92 | 93 | -- Our Lua has double precision and our typedef is on float. 94 | -- We have to use values that do not need rounding. 95 | 96 | function should.createVectObject() 97 | local v = Vectf(1.5, 44) 98 | assertType('userdata', v) 99 | end 100 | 101 | function should.readVectAttributes() 102 | local v = Vectf(1.5, 35) 103 | assertEqual(1.5, v.x) 104 | assertEqual(35, v.y) 105 | end 106 | 107 | function should.writeVectAttributes() 108 | local v = Vectf(1.5, 35) 109 | v.x = 15 110 | assertEqual(15, v.x) 111 | assertEqual(35, v.y) 112 | assertEqual(525, v:surface()) 113 | end 114 | 115 | function should.handleBadWriteVectAttr() 116 | local v = Vectf(1.5, 35) 117 | assertError("invalid key 'asdf'", function() 118 | v.asdf = 15 119 | end) 120 | assertEqual(1.5, v.x) 121 | assertEqual(35, v.y) 122 | assertEqual(nil, v.asdf) 123 | end 124 | 125 | function should.executeVectMethods() 126 | local v = Vectf(1.5, 35) 127 | assertEqual(52.5, v:surface()) 128 | end 129 | 130 | function should.overloadAdd() 131 | local v1, v2 = Vectf(1.5, -1), Vectf(4, 2) 132 | local v = v1 + v2 133 | assertEqual(5.5, v.x) 134 | assertEqual(1, v.y) 135 | assertEqual(5.5, v:surface()) 136 | end 137 | 138 | function should.executeStaticMethods() 139 | local v1, v2 = Vectf(1.5, -1), Vectf(4, 2) 140 | assertEqual(123.5, Vectf.addTwo(120, 3.5)) 141 | end 142 | 143 | should:test() 144 | 145 | -------------------------------------------------------------------------------- /test/lua_thread_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.LuaBinder 4 | ------------- 5 | 6 | Test binding with the 'thread' group of classes: 7 | 8 | * initialize object with custom method. 9 | * return table instead of userdata. 10 | * callback from C++. 11 | * custom error function in self. 12 | 13 | --]]------------------------------------------------------ 14 | local lub = require 'lub' 15 | local lut = require 'lut' 16 | local dub = require 'dub' 17 | 18 | local should = lut.Test('dub.LuaBinder - thread', {coverage = false}) 19 | local binder = dub.LuaBinder() 20 | 21 | local ins = dub.Inspector { 22 | INPUT = 'test/fixtures/thread', 23 | doc_dir = lub.path '|tmp', 24 | } 25 | 26 | local thread 27 | 28 | --=============================================== Callback bindings 29 | 30 | function should.bindClass() 31 | local Callback = ins:find('Callback') 32 | local met = Callback:method('Callback') 33 | local res = binder:functionBody(Callback, met) 34 | assertMatch('retval__%->dub_pushobject%(L, retval__, "Callback", true%);', res) 35 | end 36 | 37 | --=============================================== Build 38 | 39 | function should.bindCompileAndLoad() 40 | local ins = dub.Inspector { 41 | INPUT = 'test/fixtures/thread', 42 | doc_dir = lub.path '|tmp', 43 | } 44 | 45 | -- create tmp directory 46 | local tmp_path = lub.path '|tmp' 47 | lub.rmTree(tmp_path, true) 48 | os.execute("mkdir -p "..tmp_path) 49 | 50 | -- How to avoid this step ? 51 | ins:find('Nogc') 52 | ins:find('Withgc') 53 | binder:bind(ins, { 54 | output_directory = tmp_path, 55 | single_lib = 'thread', 56 | }) 57 | 58 | local cpath_bak = package.cpath 59 | assertPass(function() 60 | -- Build thread.so 61 | binder:build { 62 | output = 'test/tmp/thread.so', 63 | inputs = { 64 | 'test/tmp/dub/dub.cpp', 65 | 'test/tmp/thread.cpp', 66 | 'test/tmp/thread_Callback.cpp', 67 | 'test/tmp/thread_Caller.cpp', 68 | 'test/tmp/thread_Foo.cpp', 69 | 'test/fixtures/thread/lua_callback.cpp', 70 | }, 71 | includes = { 72 | 'test/tmp', 73 | -- This is for lua.h 74 | 'test/tmp/dub', 75 | 'test/fixtures/thread', 76 | }, 77 | } 78 | package.cpath = tmp_path .. '/?.so' 79 | thread = require 'thread' 80 | assertType('table', thread.Callback) 81 | assertType('table', thread.Caller) 82 | end, function() 83 | -- teardown 84 | package.cpath = cpath_bak 85 | if not thread or not thread.Callback then 86 | lut.Test.abort = true 87 | end 88 | end) 89 | --lub.rmTree(tmp_path, true) 90 | end 91 | 92 | function should.returnATable() 93 | local c = thread.Callback('Alan Watts') 94 | assertType('table', c) 95 | assertType('userdata', c.super) 96 | end 97 | 98 | function should.executeMethodsOnSelf() 99 | local c = thread.Callback('Alan Watts') 100 | assertEqual(101, c:anyMethod(1)) 101 | end 102 | 103 | function should.executeMethodsOnUserdata() 104 | local c = thread.Callback('Alan Watts') 105 | assertEqual(101, c.super:anyMethod(1)) 106 | end 107 | 108 | function should.readCppAttributes() 109 | local c = thread.Callback('Alan Watts') 110 | assertEqual('Alan Watts', c.name) 111 | end 112 | 113 | function should.writeAttributes() 114 | local c = thread.Callback('Alan Watts') 115 | assertEqual('Alan Watts', c.name) 116 | -- C++ attribute 117 | c.name = 'C++ name' 118 | assertEqual('C++ name', c:getName()) 119 | assertEqual('C++ name', c.super:getName()) 120 | end 121 | 122 | function should.readAndWriteLuaValues() 123 | local c = thread.Callback('Alan Watts') 124 | c.foo = 'Hello' 125 | assertEqual('Hello', c.foo) 126 | assertNil(c.bar) 127 | end 128 | 129 | function should.notCastDubTemplate() 130 | -- __newindex for simple (native) types 131 | local Callback = ins:find('Callback') 132 | local met = Callback:method(Callback.CAST_NAME) 133 | local res = binder:functionBody(Callback, met) 134 | assertMatch('DUB_ASSERT_KEY%(key, "Foo"%)', res) 135 | assertNotMatch('Thread', res) 136 | end 137 | --=============================================== Callback from C++ 138 | 139 | local function makeCall(c, ...) 140 | local caller = thread.Caller(c) 141 | caller:call(...) 142 | end 143 | 144 | function should.callbackFromCpp() 145 | local c = thread.Callback('Alan Watts') 146 | local r 147 | function c:callback(value) 148 | r = value 149 | end 150 | makeCall(c, 'something') 151 | assertEqual('something', r) 152 | end 153 | 154 | --=============================================== Error handling 155 | 156 | function should.useSelfErrorHandler() 157 | local c = thread.Callback('Alan Watts') 158 | local r 159 | function c:callback(value) 160 | error('Failure....') 161 | end 162 | function c:error(...) 163 | r = ... 164 | end 165 | makeCall(c, 'something') 166 | assertMatch('test/lua_thread_test.lua:%d+: Failure....', r) 167 | end 168 | 169 | function should.printErrorIfNoErrorHandler() 170 | local print_bak = print 171 | local print_out 172 | -- On object creation, the created default error handler calls print provided in 173 | -- the creation environment. 174 | function print(typ, msg) 175 | print_out = typ .. ': ' .. msg 176 | end 177 | local c = thread.Callback('Alan Watts') 178 | local r 179 | -- Print captured in c env, we can change it back. 180 | print = print_bak 181 | 182 | function c:callback(value) 183 | error('Printed error.') 184 | end 185 | assertPass(function() 186 | makeCall(c, 'something') 187 | end) 188 | assertMatch('error: .*lua_thread_test.lua.*Printed error', print_out) 189 | 190 | assertType('function', c._errfunc) 191 | c._errfunc('hello') 192 | assertMatch('error: hello', print_out) 193 | end 194 | 195 | --=============================================== Memory 196 | 197 | function should.passSameObjectWhenStoredAsPointer() 198 | local c = thread.Callback('Alan Watts') 199 | local owner = thread.Caller(c) 200 | assertEqual(c, owner.clbk_) -- same table 201 | end 202 | 203 | function should.destroyFromCpp() 204 | local c = thread.Callback('Arty') 205 | local o = thread.Caller(c) 206 | o:destroyCallback() 207 | -- Destructor called in C++ 208 | -- Object is dead in Lua 209 | assertError('using deleted thread.Callback', function() 210 | assertTrue(c:deleted()) 211 | c.name = 'foo' 212 | end) 213 | end 214 | 215 | function should.notGcWhenStored() 216 | collectgarbage() 217 | local watch = thread.Callback('Foobar') 218 | watch.destroy_count = 0 219 | local c = thread.Callback('Alan Watts') 220 | local owner = thread.Caller() 221 | -- dub only protects assignment: thread.Caller(c) is not protected 222 | owner.clbk_ = c 223 | c = nil 224 | collectgarbage() 225 | collectgarbage() 226 | assertEqual(0, watch.destroy_count) 227 | owner = nil 228 | collectgarbage() 229 | collectgarbage() 230 | assertEqual(1, watch.destroy_count) 231 | end 232 | 233 | should:test() 234 | 235 | -------------------------------------------------------------------------------- /test/namespace_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.Namespace 4 | ------------- 5 | 6 | ... 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local lut = require 'lut' 11 | local dub = require 'dub' 12 | 13 | local should = lut.Test('dub.Namespace', {coverage = false}) 14 | 15 | local ins = dub.Inspector { 16 | INPUT = { 17 | lub.path '|fixtures/namespace', 18 | }, 19 | doc_dir = lub.path '|tmp', 20 | } 21 | 22 | --=============================================== TESTS 23 | function should.autoload() 24 | assertType('table', dub.Namespace) 25 | end 26 | 27 | function should.createClass() 28 | local c = ins:find('Nem') 29 | assertEqual('dub.Namespace', c.type) 30 | end 31 | 32 | function should.returnFalseOnIsClass() 33 | local c = ins:find('Nem') 34 | assertEqual(false, c.is_class) 35 | end 36 | 37 | should:test() 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/opt_parser_test.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------------------------ 2 | 3 | dub.OptParser test 4 | ------------------ 5 | 6 | ... 7 | 8 | --]]------------------------------------------------------ 9 | local lub = require 'lub' 10 | local lut = require 'lut' 11 | local dub = require 'dub' 12 | 13 | local should = lut.Test('dub.OptParser') 14 | 15 | local opt = dub.OptParser 16 | 17 | function should.parseOneValue() 18 | assertValueEqual({ 19 | foo = 'hell', 20 | }, opt.parse('foo: hell')) 21 | end 22 | 23 | function should.parseString() 24 | assertValueEqual({ 25 | foo = 'hell on the rocks: yes', 26 | }, opt.parse('foo: "hell on the rocks: yes"')) 27 | end 28 | 29 | function should.parseUnderscoreKey() 30 | assertValueEqual({ 31 | string_format = '%s:%i', 32 | string_args = { 33 | 'self->hostname()', 34 | 'self->port()', 35 | ['self->hostname()'] = true, 36 | ['self->port()'] = true, 37 | }, 38 | }, opt.parse('string_format: %s:%i\nstring_args: self->hostname(), self->port()')) 39 | end 40 | 41 | function should.parseTrueFalse() 42 | assertValueEqual({ 43 | foo = false, 44 | bar = true, 45 | }, opt.parse('foo: false\nbar: true')) 46 | end 47 | 48 | -- Parses lists both as dict and array. 49 | function should.parseListAsHash() 50 | assertValueEqual({ 51 | list = {'Parent', 'GrandParent', 'three', 52 | Parent = true, 53 | GrandParent = true, 54 | three = true, 55 | }, 56 | }, opt.new('list: Parent, GrandParent, three')) 57 | end 58 | 59 | should:test() 60 | 61 | --------------------------------------------------------------------------------