Skip to content

Variant.__call metamethod that calls Callable values #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,28 @@ Godot 4.1.2+ native extension for using the Lua programming language.
var lua = LuaState.new()
lua.open_libraries() # this imports Lua and Godot APIs to the state

# Run Lua code using `LuaState.do_string` or `LuaState.do_file`
var result = lua.do_string("""
local vector = Vector2(1, 2)
return {
this_is_a_table = true,
vector = vector,
}
""")
# When error ocurrs in Lua code, it returns an instance of `LuaError`
if result is LuaError:
printerr("Error: ", result)
printerr("Error in Lua code: ", result)
else:
print(result) # [LuaTable:0x556069ee50ab]
print(result["this_is_a_table"]) # true
print(result["vector"]) # (1, 2)
print(result["invalid key"]) # <null>

# Access the global _G table via `LuaState.globals` property
lua.globals["a_godot_callable"] = func(): print("Hello from GDScript!")
lua.do_string("""
a_godot_callable() -- 'Hello from GDScript!'
""")
```
- Bindings for all Variant types and classes.
Methods are dispatched dynamically at runtime, so that all classes are supported, even those registered at runtime like ones implemented via GDExtension.
Expand Down Expand Up @@ -84,6 +92,7 @@ Godot 4.1.2+ native extension for using the Lua programming language.


## TODO
- [X] Bind Variant types to Lua
- [X] Bind utility functions to Lua
- [X] Bind enums and constants to Lua
- [X] Add support for getting global singletons from Lua
Expand Down
31 changes: 21 additions & 10 deletions src/luaopen/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ sol::stack_object evaluate_unary_operator(sol::this_state state, const sol::stac
return to_lua(state, result);
}

sol::stack_object variant_index(sol::this_state state, const Variant& variant, const sol::stack_object& key) {
sol::stack_object variant__index(sol::this_state state, const Variant& variant, const sol::stack_object& key) {
bool is_valid;
if (key.get_type() == sol::type::string) {
StringName string_name = key.as<StringName>();
Expand All @@ -96,7 +96,7 @@ sol::stack_object variant_index(sol::this_state state, const Variant& variant, c
return to_lua(state, result);
}

void variant_newindex(sol::this_state state, Variant& variant, const sol::stack_object& key, const sol::stack_object& value) {
void variant__newindex(sol::this_state state, Variant& variant, const sol::stack_object& key, const sol::stack_object& value) {
bool is_valid;
Variant var_key = to_variant(key);
Variant var_value = to_variant(value);
Expand All @@ -113,15 +113,15 @@ void variant_newindex(sol::this_state state, Variant& variant, const sol::stack_
}
}

sol::stack_object variant_length(sol::this_state state, Variant& variant) {
sol::stack_object variant__length(sol::this_state state, Variant& variant) {
return variant_call_string_name(state, variant, "size", sol::variadic_args(state, 0));
}

String variant_concat(const sol::stack_object& a, const sol::stack_object& b) {
String variant__concat(const sol::stack_object& a, const sol::stack_object& b) {
return String(to_variant(a)) + String(to_variant(b));
}

std::tuple<sol::object, sol::object> variant_pairs(sol::this_state state, const Variant& variant) {
std::tuple<sol::object, sol::object> variant__pairs(sol::this_state state, const Variant& variant) {
if (variant.get_type() == Variant::DICTIONARY) {
return DictionaryIterator::dictionary_pairs(state, variant);
}
Expand Down Expand Up @@ -160,6 +160,16 @@ bool variant_is(const Variant& variant, const sol::stack_object& type) {
return false;
}

sol::stack_object variant__call(sol::this_state state, const Variant& variant, sol::variadic_args args) {
if (variant.get_type() != Variant::CALLABLE) {
luaL_error(state, "attempt to call a %s value", get_type_name(variant).ascii().get_data());
}
Callable callable = variant;
VariantArguments var_args = args;
Variant result = callable.callv(var_args.get_array());
return to_lua(state, result);
}

}

using namespace luagdextension;
Expand Down Expand Up @@ -208,11 +218,12 @@ extern "C" int luaopen_godot_variant(lua_State *L) {
sol::meta_function::bitwise_xor, &evaluate_binary_operator<Variant::OP_BIT_XOR>,
sol::meta_function::bitwise_not, &evaluate_unary_operator<Variant::OP_BIT_NEGATE>,
// misc
sol::meta_function::index, &variant_index,
sol::meta_function::new_index, &variant_newindex,
sol::meta_function::length, &variant_length,
sol::meta_function::concatenation, &variant_concat,
sol::meta_function::pairs, &variant_pairs,
sol::meta_function::call, &variant__call,
sol::meta_function::index, &variant__index,
sol::meta_function::new_index, &variant__newindex,
sol::meta_function::length, &variant__length,
sol::meta_function::concatenation, &variant__concat,
sol::meta_function::pairs, &variant__pairs,
sol::meta_function::to_string, &Variant::operator String
);

Expand Down
6 changes: 5 additions & 1 deletion src/utils/VariantArguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ VariantArguments::VariantArguments(const sol::variadic_args& args) {
variants.append(to_variant(it));
}
for (int i = 0; i < variants.size(); i++) {
variant_pointers.append(variants.ptr() + i);
variant_pointers.append(&variants[i]);
}
}

Expand All @@ -45,4 +45,8 @@ const Variant *const *VariantArguments::argv() const {
return variant_pointers.ptr();
}

const Array& VariantArguments::get_array() const {
return variants;
}

}
3 changes: 2 additions & 1 deletion src/utils/VariantArguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace luagdextension {
* Convert between sol::variadic_args to Variant argc/argv.
*/
class VariantArguments {
Vector<Variant> variants;
Array variants;
Vector<const Variant *> variant_pointers;

public:
Expand All @@ -44,6 +44,7 @@ class VariantArguments {
int argc() const;
const Variant **argv();
const Variant *const *argv() const;
const Array& get_array() const;
};

}
Expand Down
4 changes: 2 additions & 2 deletions src/utils/convert_godot_lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ sol::stack_object variant_static_call_string_name(sol::this_state state, Variant
Variant::call_static(type, method, variant_args.argv(), variant_args.argc(), result, error);
if (error.error != GDEXTENSION_CALL_OK) {
String message = String("Invalid static call to method '{0}' in type {1}").format(Array::make(method, Variant::get_type_name(type)));
lua_error(args.lua_state(), error, message);
lua_error(state, error, message);
}
return to_lua(state, result);
}
Expand All @@ -219,7 +219,7 @@ sol::stack_object variant_call_string_name(sol::this_state state, Variant& varia
variant.call(method, variant_args.argv(), variant_args.argc(), result, error);
if (error.error != GDEXTENSION_CALL_OK) {
String message = String("Invalid call to method '{0}' in object of type {1}").format(Array::make(method, get_type_name(variant)));
lua_error(args.lua_state(), error, message);
lua_error(state, error, message);
}
return to_lua(state, result);
}
Expand Down
2 changes: 2 additions & 0 deletions test/lua_tests/callable.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local callable = Callable(OS, "get_name")
assert(callable() == OS:get_name())