ToCppHook.lua 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. -- Copyright (c) 2008-2022 the Urho3D project
  2. -- License: MIT
  3. local toWrite = {}
  4. local currentString = ''
  5. local out
  6. local WRITE, OUTPUT = write, output
  7. function output(s)
  8. out = _OUTPUT
  9. output = OUTPUT -- restore
  10. output(s)
  11. end
  12. function write(a)
  13. if out == _OUTPUT then
  14. currentString = currentString .. a
  15. if string.sub(currentString,-1) == '\n' then
  16. toWrite[#toWrite+1] = currentString
  17. currentString = ''
  18. end
  19. else
  20. WRITE(a)
  21. end
  22. end
  23. function post_output_hook(package)
  24. local result = table.concat(toWrite)
  25. local function replace(pattern, replacement)
  26. local k = 0
  27. local nxt, currentString = 1, ''
  28. repeat
  29. local s, e = string.find(result, pattern, nxt, true)
  30. if e then
  31. currentString = currentString .. string.sub(result, nxt, s-1) .. replacement
  32. nxt = e + 1
  33. k = k + 1
  34. end
  35. until not e
  36. result = currentString..string.sub(result, nxt)
  37. end
  38. replace("\t", " ")
  39. replace([[#ifndef __cplusplus
  40. #include "stdlib.h"
  41. #endif
  42. #include "string.h"
  43. #include "tolua++.h"]], [[// Copyright (c) 2008-2022 the Urho3D project
  44. // License: MIT
  45. #include <toluapp/tolua++.h>
  46. #include "LuaScript/ToluaUtils.h"
  47. #if __clang__
  48. #pragma clang diagnostic push
  49. #pragma clang diagnostic ignored "-Wunused-function"
  50. #endif]])
  51. if not _extra_parameters["Urho3D"] then
  52. replace([[#include "LuaScript/ToluaUtils.h"]], [[#include <Urho3D/LuaScript/ToluaUtils.h>]])
  53. end
  54. -- Special handling for vector to table conversion which would simplify the implementation of the template functions
  55. result = string.gsub(result, "ToluaIs(P?O?D?)Vector([^\"]-)\"c?o?n?s?t? ?P?O?D?Vector<([^*>]-)%*?>\"", "ToluaIs%1Vector%2\"%3\"")
  56. result = string.gsub(result, "ToluaPush(P?O?D?)Vector([^\"]-)\"c?o?n?s?t? ?P?O?D?Vector<([^*>]-)%*?>\"", "ToluaPush%1Vector%2\"%3\"")
  57. result = string.gsub(result, "@1%(", "(\"\",") -- is_pointer overload uses const char* as signature
  58. result = string.gsub(result, "@2%(", "(0.f,") -- is_arithmetic overload uses double as signature
  59. -- Suppress GCC 'pedantic' warnings due to extra semicolon in the emitted code
  60. result = string.gsub(result, "TOLUA_API int luaopen_(.+)};", "TOLUA_API int luaopen_%1}")
  61. WRITE(result)
  62. WRITE([[
  63. #if __clang__
  64. #pragma clang diagnostic pop
  65. #endif]])
  66. end
  67. _push_functions['Component'] = "ToluaPushObject"
  68. _push_functions['Resource'] = "ToluaPushObject"
  69. _push_functions['UIElement'] = "ToluaPushObject"
  70. -- Is Urho3D Vector type.
  71. function urho3d_is_vector(t)
  72. return t:find("Vector<") ~= nil
  73. end
  74. -- Is Urho3D PODVector type.
  75. function urho3d_is_podvector(t)
  76. return t:find("PODVector<") ~= nil
  77. end
  78. local old_get_push_function = get_push_function
  79. local old_get_to_function = get_to_function
  80. local old_get_is_function = get_is_function
  81. function is_pointer(t)
  82. return t:find("*>")
  83. end
  84. function is_arithmetic(t)
  85. for _, type in pairs({ "char", "short", "int", "unsigned", "long", "float", "double", "bool" }) do
  86. _, pos = t:find(type)
  87. if pos ~= nil and t:sub(pos + 1, pos + 1) ~= "*" then return true end
  88. end
  89. return false
  90. end
  91. function overload_if_necessary(t)
  92. return is_pointer(t) and "@1" or (is_arithmetic(t) and "@2" or "")
  93. end
  94. function get_push_function(t)
  95. if not urho3d_is_vector(t) then
  96. return old_get_push_function(t)
  97. end
  98. local T = t:match("<.*>")
  99. if not urho3d_is_podvector(t) then
  100. return "ToluaPushVector" .. T
  101. else
  102. return "ToluaPushPODVector" .. T .. overload_if_necessary(T)
  103. end
  104. end
  105. function get_to_function(t)
  106. if not urho3d_is_vector(t) then
  107. return old_get_to_function(t)
  108. end
  109. local T = t:match("<.*>")
  110. if not urho3d_is_podvector(t) then
  111. return "ToluaToVector" .. T
  112. else
  113. return "ToluaToPODVector" .. T .. overload_if_necessary(T)
  114. end
  115. end
  116. function get_is_function(t)
  117. if not urho3d_is_vector(t) then
  118. return old_get_is_function(t)
  119. end
  120. local T = t:match("<.*>")
  121. if not urho3d_is_podvector(t) then
  122. return "ToluaIsVector" .. T
  123. else
  124. return "ToluaIsPODVector" .. T .. overload_if_necessary(T)
  125. end
  126. end
  127. function get_property_methods_hook(ptype, name)
  128. if ptype == "get_set" then
  129. local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
  130. return "Get"..Name, "Set"..Name
  131. end
  132. if ptype == "is_set" then
  133. local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
  134. return "Is"..Name, "Set"..Name
  135. end
  136. if ptype == "has_set" then
  137. local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
  138. return "Has"..Name, "Set"..Name
  139. end
  140. if ptype == "no_prefix" then
  141. local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
  142. return Name, "Set"..Name
  143. end
  144. end
  145. -- Rudimentary checker to prevent function overloads being declared in a wrong order
  146. -- The checker assumes function overloads are declared in group one after another within a same pkg file
  147. -- The checker only checks for single argument function at the moment, but it can be extended to support more when it is necessary
  148. local overload_checker = {name="", has_number=false}
  149. function pre_call_hook(self)
  150. if table.getn(self.args) ~= 1 then return end
  151. if overload_checker.name ~= self.name then
  152. overload_checker.name = self.name
  153. overload_checker.has_number = false
  154. end
  155. local t = self.args[1].type
  156. if overload_checker.has_number then
  157. if t:find("String") or t:find("char*") then warning(self:inclass() .. ":" .. self.name .. " has potential binding problem: number overload becomes dead code if it is declared before string overload") end
  158. else
  159. overload_checker.has_number = t ~= "bool" and is_arithmetic(t)
  160. end
  161. end