dump-typelib.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #! /usr/bin/env lua
  2. ------------------------------------------------------------------------------
  3. --
  4. -- LGI tools for dumping typelib fragments into readable text format.
  5. --
  6. -- Copyright (c) 2010, 2011 Pavel Holejsovsky
  7. -- Licensed under the MIT license:
  8. -- http://www.opensource.org/licenses/mit-license.php
  9. --
  10. ------------------------------------------------------------------------------
  11. local lgi_core = require 'lgi.core'
  12. local gi = lgi_core.gi
  13. require 'debugger'
  14. -- Implements BaseInfo object, capable of dump itself.
  15. local infos = {}
  16. infos.base = { attrs = { 'name', 'namespace', 'type', 'deprecated' },
  17. cats = {}, }
  18. infos.base.__index = infos.base
  19. -- Creates new info wrapper according to info type.
  20. function infos.new(info)
  21. if info then
  22. return setmetatable({ info = info }, infos[info.type] or infos.base)
  23. end
  24. end
  25. -- Derives new baseinfo subtype.
  26. function infos.base:derive(attrs, cats)
  27. local new_attrs = {}
  28. for _, val in ipairs(self.attrs) do new_attrs[#new_attrs + 1] = val end
  29. for _, val in ipairs(attrs or {}) do new_attrs[#new_attrs + 1] = val end
  30. local new_cats = {}
  31. for _, val in ipairs(self.cats) do new_cats[#new_cats + 1] = val end
  32. for _, val in ipairs(cats or {}) do new_cats[#new_cats + 1] = val end
  33. local new = setmetatable({ attrs = new_attrs, cats = new_cats }, self)
  34. new.__index = new
  35. return new
  36. end
  37. -- Gets given attribute or category.
  38. function infos.base:get(name, depth)
  39. local item = self.info[name]
  40. if gi.isinfo(item) then
  41. item = infos.new(item)
  42. if depth then item = item:dump(depth) end
  43. else
  44. for _, cat in pairs(self.cats) do
  45. if cat == name then item = infos.category.new(item) end
  46. end
  47. end
  48. return item
  49. end
  50. -- Dumps all attributes into the target table.
  51. function infos.base:dump_attrs(target, depth)
  52. for _, attr in ipairs(self.attrs) do
  53. target[attr] = self:get(attr, depth - 1)
  54. end
  55. return attrs
  56. end
  57. -- Dumps all categories into the target table.
  58. function infos.base:dump_cats(target, depth)
  59. local cats = {}
  60. for _, cat in ipairs(self.cats) do
  61. target[cat] = self:get(cat):dump(depth - 1)
  62. end
  63. return cats
  64. end
  65. function infos.base:dump(depth)
  66. if depth <= 0 then return '...' end
  67. local t = {}
  68. self:dump_attrs(t, depth)
  69. local cats = {}
  70. self:dump_cats(cats, depth)
  71. if next(cats) then t.cats = cats end
  72. return t
  73. end
  74. -- Implementation of 'subcategory' pseudoinfo.
  75. infos.category = infos.base:derive()
  76. function infos.category.new(category)
  77. return setmetatable({ info = category }, infos.category)
  78. end
  79. function infos.category:dump(depth)
  80. local t = {}
  81. for i = 1, #self.info do
  82. t[i] = infos.new(self.info[i]):dump(depth)
  83. end
  84. return t
  85. end
  86. infos.type = infos.base:derive(
  87. { 'tag', 'is_basic', 'interface', 'array_type',
  88. 'is_zero_terminated', 'array_length', 'fixed_size', 'is_pointer' },
  89. { 'params' })
  90. function infos.type:dump_cats(target, depth)
  91. local params = {}
  92. for i, param in ipairs(self.info.params or {}) do
  93. params[i] = infos.new(param):dump(depth - 1)
  94. end
  95. if next(params) then target.params = params end
  96. end
  97. infos.registered = infos.base:derive({ 'gtype' }, {})
  98. infos.object = infos.registered:derive(
  99. { 'parent', 'type_struct', },
  100. { 'interfaces', 'fields', 'vfuncs', 'methods', 'constants', 'properties',
  101. 'signals' })
  102. infos.interface = infos.registered:derive(
  103. { 'type_struct', },
  104. { 'prerequisites', 'vfuncs', 'methods', 'constants', 'properties',
  105. 'signals' })
  106. infos.property = infos.base:derive({ 'typeinfo', 'flags', 'transfer' })
  107. infos.callable = infos.base:derive(
  108. { 'return_type', 'return_transfer' },
  109. { 'args' })
  110. infos['function'] = infos.callable:derive({ 'flags' })
  111. infos.signal = infos.callable:derive({ 'flags' })
  112. infos.callback = infos.callable:derive()
  113. infos.vfunc = infos.callable:derive()
  114. infos.arg = infos.base:derive(
  115. { 'typeinfo', 'direction', 'transfer', 'optional', 'typeinfo' }
  116. )
  117. infos.struct = infos.registered:derive({ 'is_gtype_struct', 'size' },
  118. { 'fields', 'methods' })
  119. infos.union = infos.registered:derive({ 'size' }, { 'fields', 'methods' })
  120. infos.field = infos.base:derive({ 'typeinfo', 'flags', 'size', 'offset' })
  121. infos.enum = infos.registered:derive({ 'storage' }, { 'values' })
  122. infos.value = infos.base:derive({ 'value' })
  123. infos.constant = infos.base:derive({ 'typeinfo', 'value' })
  124. -- Implementation of info wrapper for namespace pseudoinfo.
  125. infos.namespace = infos.base:derive({ 'name', 'version', 'dependencies' })
  126. function infos.namespace:get(name)
  127. local item = self.info[name]
  128. return item and infos.new(item)
  129. end
  130. function infos.namespace:dump_cats(target, depth)
  131. if depth <= 0 then return '...' end
  132. for i = 1, #self.info do
  133. local info = self.info[i]
  134. target[info.name] = infos.new(info):dump(depth - 1)
  135. end
  136. end
  137. function infos.namespace.new(info)
  138. return setmetatable({ info = info }, infos.namespace)
  139. end
  140. -- Implementation of root element pseudoinfo.
  141. infos.root = infos.base:derive()
  142. function infos.root:get(name)
  143. return infos.namespace.new(gi.require(name))
  144. end
  145. -- Commandline processing
  146. arg = arg or {}
  147. paths = {}
  148. depth = 3
  149. for i = 1, #arg do
  150. if tonumber(arg[i]) then depth = tonumber(arg[i])
  151. else paths[#paths + 1] = arg[i] end
  152. end
  153. -- Go through all paths and dump them.
  154. for _, path in ipairs(paths) do
  155. local info = infos.root
  156. for name in path:gmatch('([^%.]+)%.?') do
  157. info = info:get(name)
  158. if not info then break end
  159. end
  160. if not info then error(('%s not found'):format(path)) end
  161. dump(info:dump(depth), depth * 2)
  162. end