luau.lua 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. local preamble = [[
  2. declare extern type userdata with end
  3. declare extern type lightuserdata with end
  4. declare extern type quaternion with
  5. x: number
  6. y: number
  7. z: number
  8. w: number
  9. end
  10. type Vec2 = {number}
  11. type Vec3 = {number} | vector
  12. type Vec4 = {number}
  13. type Quat = {number} | quaternion
  14. type Mat4 = {number}
  15. declare class Joint end
  16. declare class Shape end
  17. ]]
  18. local function genType(type, optional)
  19. local suffix = optional and '?' or ''
  20. if type == 'function' then -- TODO
  21. return '() -> ()' .. suffix
  22. elseif type == '*' then
  23. return 'any' .. suffix
  24. else
  25. return type:gsub('table', '{}') .. suffix
  26. end
  27. end
  28. local function genArguments(arguments, ismethod)
  29. local t = {}
  30. for _, arg in ipairs(arguments) do
  31. local name, type = arg.name, genType(arg.type, arg.default)
  32. if name:match('%.%.%.') then
  33. if ismethod then
  34. table.insert(t, '...: ' .. type)
  35. else
  36. table.insert(t, '...' .. type)
  37. end
  38. else
  39. table.insert(t, ('%s: %s'):format(name, type))
  40. end
  41. end
  42. return table.concat(t, ', ')
  43. end
  44. local function genReturns(returns)
  45. local t = {}
  46. for _, ret in ipairs(returns) do
  47. table.insert(t, genType(ret.type))
  48. end
  49. return table.concat(t, ', ')
  50. end
  51. local function genFunctionType(fn, variant)
  52. local args = genArguments(variant.arguments)
  53. local rets = genReturns(variant.returns)
  54. if #variant.returns == 1 then
  55. return ('(%s) -> %s'):format(args, rets)
  56. else
  57. return ('(%s) -> (%s)'):format(args, rets)
  58. end
  59. end
  60. local function genMethod(method, variant)
  61. local args = genArguments(variant.arguments, true)
  62. local rets = genReturns(variant.returns)
  63. if args == '' then
  64. args = 'self'
  65. else
  66. args = 'self, ' .. args
  67. end
  68. if #variant.returns > 1 then
  69. rets = (': (%s)'):format(rets)
  70. elseif #variant.returns == 1 then
  71. rets = ': ' .. rets
  72. end
  73. return (' function %s(%s)%s'):format(method.name, args, rets)
  74. end
  75. return function(api)
  76. local directory = lovr.filesystem.getSource() .. '/luau'
  77. if lovr.system.getOS() == 'Windows' then
  78. os.execute('mkdir ' .. directory:gsub('/', '\\'))
  79. else
  80. os.execute('mkdir -p ' .. directory)
  81. end
  82. local out = {}
  83. local function write(s, ...)
  84. table.insert(out, s:format(...))
  85. end
  86. write(preamble:gsub('^%s*', ''))
  87. write('\n')
  88. local function writeFunction(fn)
  89. if #fn.variants > 1 then
  90. write(' %s:\n', fn.name)
  91. for i, variant in ipairs(fn.variants) do
  92. write(' & (%s)%s\n', genFunctionType(fn, variant), i == #fn.variants and ',' or '')
  93. end
  94. else
  95. write(' %s: %s,\n', fn.name, genFunctionType(fn, fn.variants[1]))
  96. end
  97. end
  98. for _, module in ipairs(api.modules) do
  99. for _, enum in ipairs(module.enums) do
  100. write('type %s =\n', enum.name)
  101. for _, value in ipairs(enum.values) do
  102. write(' | %q\n', value.name)
  103. end
  104. write('\n')
  105. end
  106. local ignore = {
  107. Vec2 = true,
  108. Vec3 = true,
  109. Vec4 = true,
  110. Quat = true,
  111. Mat4 = true,
  112. Vectors = true
  113. }
  114. for _, object in ipairs(module.objects) do
  115. if not ignore[object.name] then
  116. write('declare class %s', object.name)
  117. if object.extends then
  118. write(' extends %s', object.extends)
  119. end
  120. write('\n')
  121. for _, method in ipairs(object.methods) do
  122. for _, variant in ipairs(method.variants) do
  123. write('%s\n', genMethod(method, variant))
  124. end
  125. end
  126. write('end\n\n')
  127. end
  128. end
  129. if module.name ~= 'lovr' and #module.functions > 0 then
  130. write('type %sModule = {\n', module.name:gsub('^%l', string.upper))
  131. for _, fn in ipairs(module.functions) do
  132. writeFunction(fn)
  133. end
  134. write('}\n\n')
  135. end
  136. end
  137. write('declare lovr: {\n')
  138. for _, module in ipairs(api.modules) do
  139. if module.name == 'lovr' then
  140. for _, fn in ipairs(module.functions) do
  141. writeFunction(fn)
  142. end
  143. end
  144. end
  145. write('\n')
  146. for _, callback in ipairs(api.callbacks) do
  147. writeFunction(callback)
  148. end
  149. write('\n')
  150. for _, module in ipairs(api.modules) do
  151. if module.name ~= 'lovr' and #module.functions > 0 then
  152. write(' %s: %sModule,\n', module.name, module.name:gsub('^%l', string.upper))
  153. end
  154. end
  155. write('}\n')
  156. local file = assert(io.open(directory .. '/lovr.d.luau', 'w'))
  157. file:write(table.concat(out):sub(1, -2))
  158. file:close()
  159. end