Skip to content
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

Initial version of new style Lua argument parsing #973

Merged
merged 25 commits into from
Apr 5, 2020

Conversation

sbx320
Copy link
Member

@sbx320 sbx320 commented May 30, 2019

Initial stuff for automated Lua argument parsing by applying template magic.

Basically this allows us to directly use C++ functions without needing to handle the argument parsing via argstreams. For example

int CLuaCryptDefs::Hash(lua_State* luaVM)
{
    //  string hash ( string type, string data )
    EHashFunctionType hashFunction;
    SString           strSourceData;

    CScriptArgReader argStream(luaVM);
    argStream.ReadEnumString(hashFunction);
    argStream.ReadString(strSourceData);

    if (!argStream.HasErrors())
    {
        SString strResult = GenerateHashHexString(hashFunction, strSourceData);
        lua_pushstring(luaVM, strResult.ToLower());
        return 1;
    }
    else
        m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());

    lua_pushboolean(luaVM, false);
    return 1;
}

becomes

std::string CLuaCryptDefs::Hash(EHashFunctionType hashFunction, std::string strSourceData)
{
    return GenerateHashHexString(hashFunction, strSourceData);
}

which avoids error and reduces the required amount of code massively.

This PR also allows registering functions via the ArgumentParser template (rather than the ArgumentParserWarn template), which causes usage mistakes to be considered a hard error in accordance with #821. As a usage example I mostly converted CLuaCryptDefs to use the new style.

Supported Types:

  • bool
  • int, (todo: ushort, char, uchar)
  • std::string (todo: SString?)
  • CLuaFunctionRef (argument only)
  • enums (with StringToEnum)
  • Script entities (via UserDataCast)
  • std::vector<T> if T is supported (expects a table with consistent value types) (todo: as result)
  • std::unordered_map<K, V> if K and V are supported (todo: as result)
  • std::optional<T> if T is supported (expects either a T or nil/none) (todo: as result)
  • std::variant<Ts...> if all Ts... are supported
  • nullptr (return type only) to indicate nil

Additionally a lua_State* may be taken as an argument, which will be passed through directly. (We use that in some places to access things based on the running script VM)

Restrictions:

  • Currently this only supports default-constructible complex types. For example one can not read a std::unique_ptr (unlikely to change)
  • No full support for overloads yet. Using std::variant and std::optional we have some support for overloading, but a function that expects very different types is not fun to handle
  • No vararg support (yet)

Notes:

  • See CLuaCryptDefs for usage examples
  • Functions may throw a std::invalid_argument exception to indicate argument failures inside the functions.
  • This requires VS2019 on Windows with the v142 toolset (VS2017 does not work due to compiler bugs)

Todos:

  • Add debug assertions for Lua stack manipulation (compare gettop vs the expected value)
  • Support additional types (see above, maybe more?)
  • Figure out a way to handle overloads nicely
  • Error messages are not generated yet
  • Test on Linux
  • Figure out why LuaBasic.h is detected as ObjectiveC by clang format (help?)

@patrikjuvonen patrikjuvonen added the enhancement New feature or request label May 30, 2019
@sbx320 sbx320 marked this pull request as ready for review June 4, 2019 19:30
@ghost
Copy link

ghost commented Jun 6, 2019

Brilliant! So, will we be using ArgumentParserWarn for old functions and ArgumentParser for newer ones?

@ghost ghost requested review from jushar and qaisjp June 6, 2019 16:06
@sbx320
Copy link
Member Author

sbx320 commented Jun 6, 2019

Yes that is the plan. We need to be careful with converting existing code though, as the behavior of this new stuff may be different in some edge cases.

@sbx320 sbx320 force-pushed the feature/luaargparser branch from cdadfb9 to 734f018 Compare June 8, 2019 20:30
Copy link
Contributor

@qaisjp qaisjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Almost all of these suggestions are readability/documentation related - I've gone with the approach that if I am having trouble skim-reading something, it should probably be explained in a comment. I hope that's OK.

I've also pointed out some methods that would benefit from guarding (or "short-circuiting"... I'm not really sure what it's called). I think it reduces cognitive load. Let me know what you think about this style.

Also, note that my suggestions to Client/.../CLuaDefs.h also apply to Server/.../CLuaDefs.h.

Still to review:

  • I have not (yet) checked to make sure you exhaust all types and include the full range of types in all areas of TypeMatch/Push/Pop.
  • Deeper read into CLuaFunctionParser::PopUnsafe, CLuaFunctionParser::Call, and CLuaOverloadParser.

Optional:

  • Include a short guide somewhere that tells you what you need to edit when adding a new type. This is probably unnecessary as you cover types in the most general case.

@sbx320
Copy link
Member Author

sbx320 commented Jun 11, 2019

Thanks for the review. I applied some changes to resolve most of it.

I have not (yet) checked to make sure you exhaust all types and include the full range of types in all areas of TypeMatch/Push/Pop.

I most likely do not cover all of them yet. Adding further types is fairly simple though, so I'd suggest we just add them as we go.

Deeper read into CLuaFunctionParser::PopUnsafe, CLuaFunctionParser::Call, and CLuaOverloadParser.

If you have questions, ask me :)

Include a short guide somewhere that tells you what you need to edit when adding a new type. This is probably unnecessary as you cover types in the most general case.

Adding new types is rare, as we usually only introduce new script entities which are all handled already. But as a quick reference for the future:

  • New arguments would need to be added in TypeMatch (check if type is valid here), TypeToName (for error messages) and PopUnsafe (read type from Lua stack).
  • New return types would need to be added as a Push overload.

Details of these operations depend heavily on the type that is to be added.

}
else
{
return Call(L, ps..., Pop<typename nth_element_impl<sizeof...(Params), Args...>::type>(L, iIndex));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call recursively calls itself until it has reached the desired number of arguments. In each step we pop the next parameter from the Lua stack and append it to the list of arguments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then Push the return value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. So if we're trying to call int foo(std::string, float) we get the following calls:
Call(L);
Call(L, str); (with str being the string returned from Pop)
Call(L, str, flt) (flt being the float from Pop)
Push(Func(str, flt));

@qaisjp
Copy link
Contributor

qaisjp commented Sep 2, 2019

What's blocking this?

@ghost
Copy link

ghost commented Sep 3, 2019

What's blocking this?

Some DX rendering stuff gets broken, if you compile MTA with VS 2019. Other than that, this PR looks complete.

@sbx320
Copy link
Member Author

sbx320 commented Sep 3, 2019

What's blocking this?

VS2019 on the build server is the big thing.

But if @saml1er knows about some rendering issues we should investigate those first before upgrading. Probably some new optimization breaking some wrong code. Could you file an issue for those @saml1er so we can track/investigate them?

@qaisjp
Copy link
Contributor

qaisjp commented Sep 3, 2019

Some DX rendering stuff gets broken

I think @botder fixed one of them in 53121a3. I don't know what the others are

@Dutchman101
Copy link
Member

Dutchman101 commented Oct 24, 2019

Now that VS2019 is on the build server, and no one created new issues for any DX issues (nor did I observe any bugs in recent nightlies as a result of using vs2019), can we get a fresh look on what's required to proceed with this?

Edit: wait for #1135 results

@sbx320
Copy link
Member Author

sbx320 commented Oct 27, 2019

I'd want to get proper handling for std::string_view in (should be significantly faster than using std::string as it avoids copying the Lua string) as well as some useful tests for the crypt defs before merging it.

But no real blockers other than that anymore.

@qaisjp
Copy link
Contributor

qaisjp commented Mar 11, 2020

clang complains

/mtasa/blue/Build/../Shared/mods/deathmatch/logic/lua/LuaBasic.h:25:14: warning: inline function 'lua::PopPrimitive<std::__1::basic_string<char> >' is not defined
      [-Wundefined-inline]
    inline T PopPrimitive(lua_State* L, std::size_t& index);
             ^
../Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h:263:25: note: used here
            return lua::PopPrimitive<T>(L, index);
                        ^

@qaisjp qaisjp modified the milestones: Backlog, 1.6 Mar 23, 2020
@ghost
Copy link

ghost commented Mar 27, 2020

clang complains

Any other issue? I want to merge this.

@ghost
Copy link

ghost commented Mar 30, 2020

I'd want to get proper handling for std::string_view in (should be significantly faster than using std::string as it avoids copying the Lua string) as well as some useful tests for the crypt defs before merging it.

After reading more about std::string_view, looks like we can easily replace const string & with std::string_view. Should I do it for this PR? @sbx320

@sbx320 sbx320 force-pushed the feature/luaargparser branch from 607d15b to 9e4e501 Compare April 2, 2020 22:36
@sbx320 sbx320 force-pushed the feature/luaargparser branch from 3dc1497 to db261d5 Compare April 3, 2020 22:06
sbx320 and others added 24 commits April 4, 2020 18:13
Implement Pop for variant, float, double, unsigned int, bool
Fix bug introduced when cleaning up error types
Attempt to fix Linux compilation
Fix map/vector to conform to existing behavior (keep reading on failure, skipping invalid values)
Add value notes to errors
Only works for overloads with the same number of parameters
Remove fixme
Fix naming convention
Co-Authored-By: Qais Patankar <qaisjp@gmail.com>
Add overload for std::string_view to PopPrimitive
Add missing if constexpr for std::string_view
@sbx320 sbx320 force-pushed the feature/luaargparser branch from db261d5 to 8d6f6a1 Compare April 4, 2020 16:18
Co-Authored-By: Qais Patankar <qaisjp@gmail.com>
@sbx320 sbx320 merged commit 586b869 into master Apr 5, 2020
@sbx320 sbx320 deleted the feature/luaargparser branch April 5, 2020 17:42
@Citizen01
Copy link
Member

🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants