Skip to content

Reflecting C++ classes in Lua scripts #81

Closed

Description

@rpatters1

Before 2019 or so, it was possible to get the _class, _propget, and _propset tables for a class and for a namespace. This allowed Lua scripts to reflect classes and instances, which I used for diagnostic and regression testing. (Also for a class browser to facility easier programming.) However, this access was closed down due (apparently) to security concerns. I now build in extra tables that allow for reflection when I register the classes, but this complicates my registration process when I want to add in a new C++ framework that has challenges (such as overloaded functions) that make it difficult or impossible to include in my standard registration process.

I can imagine that in many contexts (I am thinking games) the Lua environment needs to be relatively locked down. But I am working in a non-hostile environment where the user has to opt in to the Lua environment by installing the Lua plugin, and even then there is little motivation to cheat the system. So I am wondering if LuaBridge3 has an option to expose the class tables and if not, would you consider adding it?

Activity

  1. kunitoki commented on Apr 1, 2023

    @kunitoki
    Owner

    Should be possible by accessing class metatable and using the internal keys luabridge use. Will try to provide some working snippets as soon as i'm back to the laptop.

  2. kunitoki commented on Apr 1, 2023

    @kunitoki
    Owner

    Do you need to access them from lua or c++ ?

  3. kunitoki commented on Apr 1, 2023

    @kunitoki
    Owner
        luabridge::setHideMetatables(false);
    
        luabridge::getGlobalNamespace(L)
            .addFunction("getMetatableClass", [](const luabridge::LuaRef& ref) -> luabridge::LuaRef
            {
                if (!ref.isTable())
                    return luabridge::LuaRef(ref.state());
    
                ref.push();
                luabridge::lua_rawgetp(ref.state(), -1, luabridge::detail::getClassKey());
    
                auto mt = luabridge::LuaRef::fromStack(ref.state(), 1);
    
                for (const auto& p : luabridge::pairs(mt))
                    std::cout << p.first << " " << p.second << std::endl;
    
                return mt;
            })
            .beginClass<ExampleStringifiableClass>("ExampleStringifiableClass")
                .addConstructor<void(*) ()>()
                .addFunction("nonConstMethod", [](ExampleStringifiableClass*) {})
                .addFunction("constMethod", [](const ExampleStringifiableClass*) {})
            .endClass();
    
        runLua(R"(
            local t = ExampleStringifiableClass()
            local mt = getmetatable(t)
    
            getMetatableClass(mt)
        )");

    this will print:

    userdata: 0xc07 table: 0x6000017084c0
    "__gc" function: 0x600000c09aa0
    "nonConstMethod" function: 0x600001708780
    userdata: 0x71 "ExampleStringifiableClass"
    userdata: 0x5e7 table: 0x600001708600
    userdata: 0x6e7 table: 0x6000017085c0
    "__newindex" function: 0x600000c09ad0
    "__index" function: 0x600000c09b00
    "constMethod" function: 0x600001708800
    

    Will provide some facilities to extract this kind of information in a more straight forward way

  4. rpatters1 commented on Apr 1, 2023

    @rpatters1
    ContributorAuthor

    I need to access them from Lua. It is a powerful tool for verifying the correctness of the LuaBridge implementation, as well as presenting the class framework to users as a learning aid.

  5. kunitoki commented on Apr 1, 2023

    @kunitoki
    Owner

    We can design a specific help table for that. So registering a method could push an entry in the table with the description of the method and argument type as seen from c++ (but not name) registered in the class

  6. rpatters1 commented on Apr 1, 2023

    @rpatters1
    ContributorAuthor

    Pre-2019, instead of hard-coded usersdata values the tables above had string keys, _class, _propget, _propset, and _static. (They may have been a _const key too, but if so I never used it.) I only need to be able to iterate them and get their names. I don't need to modify or call the values.

    I am currently doing exactly what you suggested and adding helper tables as I register the classes. I use refl-cpp to reflect the C++ classes at compile time so that all of my registrations use the same code. The challenge with refl-cpp is that lack of useful support for overloaded methods. The current support would require me to know and hardcode the function signatures in the central routine where I'm processing them rather than in the lists where I list them, so right now I can't use refl-cpp for everything.

  7. Repository owner locked and limited conversation to collaborators on Apr 1, 2023
  8. converted this issue into a discussion #88 on Apr 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions