Skip to content

Commit 8cde542

Browse files
committed
Supports the new idiomatic .new() for constructors
1 parent c0c14d7 commit 8cde542

26 files changed

Lines changed: 350 additions & 352 deletions

Distribution/LuaBridge/LuaBridge.h

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8813,7 +8813,7 @@ int constructor_container_proxy(lua_State* L)
88138813
try
88148814
{
88158815
#endif
8816-
object = constructor<T, Args>::construct(detail::make_arguments_list<Args, 2>(L));
8816+
object = constructor<T, Args>::construct(detail::make_arguments_list<Args, 1>(L));
88178817

88188818
#if LUABRIDGE_HAS_EXCEPTIONS
88198819
}
@@ -8833,7 +8833,7 @@ int constructor_container_proxy(lua_State* L)
88338833
template <class T, class Args>
88348834
int constructor_placement_proxy(lua_State* L)
88358835
{
8836-
auto args = make_arguments_list<Args, 2>(L);
8836+
auto args = make_arguments_list<Args, 1>(L);
88378837

88388838
std::error_code ec;
88398839
auto* value = UserdataValue<T>::place(L, ec);
@@ -8873,7 +8873,7 @@ struct constructor_forwarder
88738873
using FnTraits = function_traits<F>;
88748874
using FnArgs = remove_first_type_t<typename FnTraits::argument_types>;
88758875

8876-
auto args = make_arguments_list<FnArgs, 2>(L);
8876+
auto args = make_arguments_list<FnArgs, 1>(L);
88778877

88788878
std::error_code ec;
88798879
auto* value = UserdataValue<T>::place(L, ec);
@@ -8988,7 +8988,7 @@ struct container_forwarder
89888988
try
89898989
{
89908990
#endif
8991-
object = container_constructor<C>::construct(m_func, make_arguments_list<FnArgs, 2>(L));
8991+
object = container_constructor<C>::construct(m_func, make_arguments_list<FnArgs, 1>(L));
89928992

89938993
#if LUABRIDGE_HAS_EXCEPTIONS
89948994
}
@@ -9408,7 +9408,7 @@ inline ClassInspectInfo inspectClassFromStaticTable(lua_State* L, int stIdx)
94089408
{
94099409
MemberInfo m;
94109410
m.name = key;
9411-
if (key == "__call")
9411+
if (key == "new")
94129412
m.kind = MemberKind::Constructor;
94139413
else if (key.size() >= 2 && key[0] == '_' && key[1] == '_')
94149414
m.kind = MemberKind::Metamethod;
@@ -10072,10 +10072,10 @@ class LuaProxyVisitor : public InspectVisitor
1007210072
{
1007310073
case MemberKind::Constructor:
1007410074

10075-
out_ << "setmetatable(" << qname << ", {__call = function(t";
10075+
out_ << qname << ".new = function(";
1007610076
if (!m.overloads[0].params.empty())
10077-
out_ << ", " << paramNames(m.overloads[0].params);
10078-
out_ << ")\n return setmetatable({}, t)\nend})\n\n";
10077+
out_ << paramNames(m.overloads[0].params);
10078+
out_ << ") end\n\n";
1007910079
break;
1008010080

1008110081
case MemberKind::Method:
@@ -13412,10 +13412,10 @@ class Namespace : public detail::Registrar
1341213412
1341313413
} (), ...);
1341413414
13415-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
13415+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
1341613416
}
1341713417
13418-
rawsetfield(L, -2, "__call");
13418+
rawsetfield(L, -2, "new");
1341913419
1342013420
return *this;
1342113421
}
@@ -13509,10 +13509,10 @@ class Namespace : public detail::Registrar
1350913509
1351013510
} (), ...);
1351113511
13512-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
13512+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
1351313513
}
1351413514
13515-
rawsetfield(L, -2, "__call");
13515+
rawsetfield(L, -2, "new");
1351613516
1351713517
return *this;
1351813518
}
@@ -13558,10 +13558,10 @@ class Namespace : public detail::Registrar
1355813558
1355913559
} (), ...);
1356013560
13561-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
13561+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
1356213562
}
1356313563
13564-
rawsetfield(L, -2, "__call");
13564+
rawsetfield(L, -2, "new");
1356513565
1356613566
return *this;
1356713567
}
@@ -13623,10 +13623,10 @@ class Namespace : public detail::Registrar
1362313623
1362413624
} (), ...);
1362513625
13626-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
13626+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
1362713627
}
1362813628
13629-
rawsetfield(L, -2, "__call");
13629+
rawsetfield(L, -2, "new");
1363013630
1363113631
return *this;
1363213632
}
@@ -13659,7 +13659,7 @@ class Namespace : public detail::Registrar
1365913659
1366013660
lua_newuserdata_aligned<F>(L, F(std::move(allocator), std::move(deallocator)));
1366113661
lua_pushcclosure_x(L, &detail::invoke_proxy_constructor<F>, className, 1);
13662-
rawsetfield(L, -2, "__call");
13662+
rawsetfield(L, -2, "new");
1366313663
1366413664
return *this;
1366513665
}

Manual.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -732,12 +732,12 @@ luabridge::getGlobalNamespace (L)
732732
.endNamespace ();
733733
```
734734
735-
Constructors added in this fashion are called from Lua using the fully qualified name of the class. This Lua code will create instances of `A` and `B`.
735+
Constructors added in this fashion are called from Lua using the `.new` field on the class. This Lua code will create instances of `A` and `B`.
736736
737737
```lua
738-
a = test.A () -- Create a new A.
739-
b = test.B ("hello", 5) -- Create a new B.
740-
b = test.B () -- Error: expected string in argument 1
738+
a = test.A.new () -- Create a new A.
739+
b = test.B.new ("hello", 5) -- Create a new B.
740+
b = test.B.new () -- Error: expected string in argument 1
741741
```
742742

743743
### 2.6.1 - Constructor Proxies
@@ -764,16 +764,16 @@ luabridge::getGlobalNamespace (L)
764764
Then in lua:
765765
766766
```lua
767-
hard = test.HardToCreate (5) -- Create a new HardToCreate.
767+
hard = test.HardToCreate.new (5) -- Create a new HardToCreate.
768768
```
769769

770-
The `addConstructor` overload taking a generic functor also accepts a `lua_State*` as last parameter in order to be used for constructors that needs to be overloaded by different numbers of arguments (arguments will start at index 2 of the stack):
770+
The `addConstructor` overload taking a generic functor also accepts a `lua_State*` as last parameter in order to be used for constructors that needs to be overloaded by different numbers of arguments (arguments will start at index 1 of the stack):
771771

772772
```cpp
773773
luabridge::getGlobalNamespace (L)
774774
.beginNamespace ("test")
775775
.beginClass<HardToCreate> ("HardToCreate")
776-
.addConstructor ([] (void* ptr, lua_State* L) { return new (ptr) HardToCreate (shouldNotSeeMe, lua_checkinteger (L, 2)); })
776+
.addConstructor ([] (void* ptr, lua_State* L) { return new (ptr) HardToCreate (shouldNotSeeMe, lua_checkinteger (L, 1)); })
777777
.endClass ()
778778
.endNamespace ();
779779
```
@@ -826,7 +826,7 @@ luabridge::getGlobalNamespace (L)
826826
The object is the perfectly instantiable through lua:
827827
828828
```lua
829-
a = test.Object () -- Create a new Object using objectFactoryAllocator
829+
a = test.Object.new () -- Create a new Object using objectFactoryAllocator
830830
a = nil -- Remove any reference count
831831
collectgarbage ("collect") -- The object is garbage collected using objectFactoryDeallocator
832832
```

Source/LuaBridge/Inspect.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ inline ClassInspectInfo inspectClassFromStaticTable(lua_State* L, int stIdx)
468468
{
469469
MemberInfo m;
470470
m.name = key;
471-
if (key == "__call")
471+
if (key == "new")
472472
m.kind = MemberKind::Constructor;
473473
else if (key.size() >= 2 && key[0] == '_' && key[1] == '_')
474474
m.kind = MemberKind::Metamethod;
@@ -1008,7 +1008,7 @@ class LuaLSVisitor : public InspectVisitor
10081008
case MemberKind::Constructor:
10091009
{
10101010
// Represent the constructor as @overload annotations before the local declaration.
1011-
// LuaBridge constructors are called as ClassName(args), not ClassName.new(args).
1011+
// LuaBridge constructors are called as ClassName.new(args).
10121012
std::string qname = qualifiedName(cls.name);
10131013
for (const auto& ov : m.overloads)
10141014
out_ << "---@overload fun(" << overloadParams(ov.params) << "): " << qname << "\n";
@@ -1202,11 +1202,11 @@ class LuaProxyVisitor : public InspectVisitor
12021202
switch (m.kind)
12031203
{
12041204
case MemberKind::Constructor:
1205-
// LuaBridge constructors are called as ClassName(args) via __call metamethod.
1206-
out_ << "setmetatable(" << qname << ", {__call = function(t";
1205+
// LuaBridge constructors are called as ClassName.new(args).
1206+
out_ << qname << ".new = function(";
12071207
if (!m.overloads[0].params.empty())
1208-
out_ << ", " << paramNames(m.overloads[0].params);
1209-
out_ << ")\n return setmetatable({}, t)\nend})\n\n";
1208+
out_ << paramNames(m.overloads[0].params);
1209+
out_ << ") end\n\n";
12101210
break;
12111211

12121212
case MemberKind::Method:

Source/LuaBridge/detail/CFunctions.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,8 +2009,6 @@ bool overload_type_checker(lua_State* L, int start)
20092009
* 2. Type check via Stack<T>::isInstance in C++ (no pcall) — skips clearly mismatched overloads.
20102010
* 3. Only calls lua_pcall for type-matched candidates, eliminating failed pcalls for type mismatches.
20112011
*/
2012-
2013-
20142012
template <bool Member>
20152013
inline int try_overload_functions(lua_State* L)
20162014
{
@@ -2890,7 +2888,7 @@ int constructor_container_proxy(lua_State* L)
28902888
try
28912889
{
28922890
#endif
2893-
object = constructor<T, Args>::construct(detail::make_arguments_list<Args, 2>(L));
2891+
object = constructor<T, Args>::construct(detail::make_arguments_list<Args, 1>(L));
28942892

28952893
#if LUABRIDGE_HAS_EXCEPTIONS
28962894
}
@@ -2913,7 +2911,7 @@ int constructor_container_proxy(lua_State* L)
29132911
template <class T, class Args>
29142912
int constructor_placement_proxy(lua_State* L)
29152913
{
2916-
auto args = make_arguments_list<Args, 2>(L);
2914+
auto args = make_arguments_list<Args, 1>(L);
29172915

29182916
std::error_code ec;
29192917
auto* value = UserdataValue<T>::place(L, ec);
@@ -2957,7 +2955,7 @@ struct constructor_forwarder
29572955
using FnTraits = function_traits<F>;
29582956
using FnArgs = remove_first_type_t<typename FnTraits::argument_types>;
29592957

2960-
auto args = make_arguments_list<FnArgs, 2>(L);
2958+
auto args = make_arguments_list<FnArgs, 1>(L);
29612959

29622960
std::error_code ec;
29632961
auto* value = UserdataValue<T>::place(L, ec);
@@ -3084,7 +3082,7 @@ struct container_forwarder
30843082
try
30853083
{
30863084
#endif
3087-
object = container_constructor<C>::construct(m_func, make_arguments_list<FnArgs, 2>(L));
3085+
object = container_constructor<C>::construct(m_func, make_arguments_list<FnArgs, 1>(L));
30883086

30893087
#if LUABRIDGE_HAS_EXCEPTIONS
30903088
}

Source/LuaBridge/detail/Namespace.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,7 @@ class Namespace : public detail::Registrar
12621262
/**
12631263
* @brief Add or replace a primary Constructor.
12641264
*
1265-
* The primary Constructor is invoked when calling the class type table like a function.
1265+
* The primary Constructor is invoked by calling `ClassName.new(args...)`.
12661266
*
12671267
* The template parameter should be a function pointer type that matches the desired Constructor (since you can't take the
12681268
* address of a Constructor and pass it as an argument).
@@ -1337,10 +1337,10 @@ class Namespace : public detail::Registrar
13371337

13381338
} (), ...);
13391339

1340-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
1340+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
13411341
}
13421342

1343-
rawsetfield(L, -2, "__call");
1343+
rawsetfield(L, -2, "new");
13441344

13451345
return *this;
13461346
}
@@ -1349,10 +1349,10 @@ class Namespace : public detail::Registrar
13491349
/**
13501350
* @brief Add or replace a placement constructor.
13511351
*
1352-
* The primary placement constructor is invoked when calling the class type table like a function.
1352+
* The primary placement constructor is invoked by calling `ClassName.new(args...)`.
13531353
*
13541354
* The provider of the Function argument is responsible of doing placement new of the type T over the void* pointer provided to
1355-
* the method as first argument.
1355+
* the method as first argument. Invoked by calling `ClassName.new(args...)`.
13561356
*/
13571357
template <class... Functions>
13581358
auto addConstructor(Functions... functions)
@@ -1445,10 +1445,10 @@ class Namespace : public detail::Registrar
14451445

14461446
} (), ...);
14471447

1448-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
1448+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
14491449
}
14501450

1451-
rawsetfield(L, -2, "__call"); // Stack: co, cl, st
1451+
rawsetfield(L, -2, "new"); // Stack: co, cl, st
14521452

14531453
return *this;
14541454
}
@@ -1499,10 +1499,10 @@ class Namespace : public detail::Registrar
14991499

15001500
} (), ...);
15011501

1502-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
1502+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
15031503
}
15041504

1505-
rawsetfield(L, -2, "__call");
1505+
rawsetfield(L, -2, "new");
15061506

15071507
return *this;
15081508
}
@@ -1571,10 +1571,10 @@ class Namespace : public detail::Registrar
15711571

15721572
} (), ...);
15731573

1574-
lua_pushcclosure_x(L, &detail::try_overload_functions<true>, className, 2);
1574+
lua_pushcclosure_x(L, &detail::try_overload_functions<false>, className, 2);
15751575
}
15761576

1577-
rawsetfield(L, -2, "__call"); // Stack: co, cl, st
1577+
rawsetfield(L, -2, "new"); // Stack: co, cl, st
15781578

15791579
return *this;
15801580
}
@@ -1603,7 +1603,7 @@ class Namespace : public detail::Registrar
16031603
/**
16041604
* @brief Add or replace a factory.
16051605
*
1606-
* The primary Constructor is invoked when calling the class type table like a function.
1606+
* The factory is invoked by calling `ClassName.new()`.
16071607
*
16081608
* The template parameter should be a function pointer type that matches the desired Constructor (since you can't take the
16091609
* address of a Constructor and pass it as an argument).
@@ -1617,7 +1617,7 @@ class Namespace : public detail::Registrar
16171617

16181618
lua_newuserdata_aligned<F>(L, F(std::move(allocator), std::move(deallocator))); // Stack: co, cl, st, upvalue
16191619
lua_pushcclosure_x(L, &detail::invoke_proxy_constructor<F>, className, 1); // Stack: co, cl, st, function
1620-
rawsetfield(L, -2, "__call"); // Stack: co, cl, st
1620+
rawsetfield(L, -2, "new"); // Stack: co, cl, st
16211621

16221622
return *this;
16231623
}

Tests/Source/ArrayTests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ TEST_F(ArrayTests, PassFromLua)
117117
.addFunction("processPointers", &processPointers<3>);
118118

119119
resetResult();
120-
runLua("result = processValues ({Data (-1), Data (2), Data (5)})");
120+
runLua("result = processValues ({Data.new(-1), Data.new(2), Data.new(5)})");
121121

122122
ASSERT_EQ((std::array<Data, 3>({-1, 2, 5})), (result<std::array<Data, 3>>()));
123123

124124
resetResult();
125-
runLua("result = processPointers ({Data (-3), Data (4), Data (9)})");
125+
runLua("result = processPointers ({Data.new(-3), Data.new(4), Data.new(9)})");
126126

127127
ASSERT_EQ((std::array<Data, 3>({-3, 4, 9})), (result<std::array<Data, 3>>()));
128128
}

0 commit comments

Comments
 (0)