moved code
[lqt.git] / new / generator.lua
blob092422aa23d3792c2ee2684dbbfb9128d5082605
1 #!/usr/bin/lua
3 local my = {
4 readfile = function(fn) local f = assert(io.open(fn)) local s = f:read'*a' f:close() return s end
7 local entities = dofile'entities.lua'
8 assert_function = function(f)
9 assert(entities.is_function(f), 'argument is not a function')
10 end
12 local filename = ...
13 local path = string.match(arg[0], '(.*/)[^%/]+') or ''
14 local xmlstream = dofile(path..'xml.lua')(my.readfile(filename))
15 local code = xmlstream[1]
17 local decompound = function(n)
18 -- test function pointer
19 local r, a = string.match(n, '(.-) %(%*%) (%b())')
20 if r and a then
21 -- only single arguments are supported
22 return 'function', r, string.match(a, '%(([^,]*)%))')
23 end
24 return nil
25 end
28 local base_types = dofile'types.lua'
31 local t = {}
32 for _, v in pairs(xmlstream.byid) do if v.xarg.fullname then
33 local o = t[v.xarg.fullname] or {}
34 table.insert(o, v)
35 t[v.xarg.fullname] = o
36 end end
37 get_from_fullname = function(n)
38 return t[n]
39 end
40 --name_list = t
41 end
44 type_on_stack = function(t)
45 local typename = type(t)=='string' and t or t.xarg.type_name
46 if rawget(base_types, typename) then
47 local ret = rawget(base_types, typename).on_stack
48 return ret
49 end
50 if type(t)=='string' or t.xarg.type_base==typename then
51 local identifier = get_from_fullname(typename)
52 assert(identifier and #identifier==1, 'cannot resolve base type: '..typename)
53 identifier = identifier[1]
54 if identifier.label=='Enum' then
55 return 'string;'
56 elseif identifier.label=='Class' then
57 return typename..'*;'
58 else
59 error('unknown identifier type: '..identifier.label)
60 end
61 else
62 if t.xarg.array then
63 error'I cannot manipulate arrays'
64 elseif string.match(typename, '%(%*%)') then
65 -- function pointer type
66 -- FIXME: the XML description does not contain this info
67 error'I cannot manipulate function pointers'
68 elseif t.xarg.indirections then
69 if t.xarg.indirections=='1' then
70 local b = assert(get_from_fullname(t.xarg.type_base), 'unknown type base')[1]
71 if b.label=='Class' then
72 return t.xarg.type_base..'*;'
73 else
74 error('I cannot manipulate pointers to '..t.xarg.type_base)
75 end
76 end
77 error'I cannot manipulate double pointers'
78 else
79 -- this is any combination of constant, volatile and reference
80 -- we ignore this info and treat this as normal value
81 return type_on_stack(t.xarg.type_base)
82 end
83 end
84 end
86 local get_enum = function(fullname)
87 return function(i,j)
88 j = j or -i
89 return fullname .. ' arg' .. tostring(i) .. ' = static_cast< ' ..
90 fullname .. ' >(LqtGetEnumType(L, '..tostring(j)..', "' .. fullname .. '"));'
91 end
92 end
93 local get_pointer = function(fullname)
94 return function(i,j)
95 j = j or -i
96 return fullname .. ' arg' .. tostring(i) .. '* = static_cast< ' ..
97 fullname .. ' *>(LqtGetClassType(L, '..tostring(j)..', "' .. fullname .. '*"));'
98 end
99 end
100 local get_class = function(fullname)
101 return function(i,j)
102 j = j or -i
103 return fullname .. ' arg' .. tostring(i) .. ' = *static_cast< ' ..
104 fullname .. ' *>(LqtGetClassType(L, '..tostring(j)..', "' .. fullname .. '*"));'
107 local get_constref = function(fullname)
108 return function(i,j)
109 j = j or -i
110 return fullname .. ' const& arg' .. tostring(i) .. ' = *static_cast< ' ..
111 fullname .. ' *>(LqtGetClassType(L, '..tostring(j)..', "' .. fullname .. '*"));'
114 local get_ref = function(fullname)
115 return function(i,j)
116 j = j or -i
117 return fullname .. '& arg' .. tostring(i) .. ' = *static_cast< ' ..
118 fullname .. ' *>(LqtGetClassType(L, '..tostring(j)..', "' .. fullname .. '*"));'
122 type_properties = function(t)
123 local typename = type(t)=='string' and t or t.xarg.type_name
125 if rawget(base_types, typename) then
126 local ret = rawget(base_types, typename)
127 return ret.on_stack, ret.get
130 -- not a base type
131 if type(t)=='string' or t.xarg.type_base==typename then
132 local identifier = get_from_fullname(typename)
133 assert(identifier and #identifier==1, 'cannot resolve base type: '..typename)
134 identifier = identifier[1]
135 if identifier.label=='Enum' then
136 return 'string;', get_enum(identifier.xarg.fullname)
137 elseif identifier.label=='Class' then
138 return typename..'*;', get_class(identifier.xarg.fullname)
139 else
140 error('unknown identifier type: '..identifier.label)
142 elseif t.xarg.array then
143 error'I cannot manipulate arrays'
144 elseif string.match(typename, '%(%*%)') then
145 -- function pointer type
146 -- FIXME: the XML description does not contain this info
147 error'I cannot manipulate function pointers'
148 elseif t.xarg.indirections then
149 if t.xarg.indirections=='1' then
150 local b = get_from_fullname(t.xarg.type_base)
151 b = assert(b, 'unknown base type '..t.xarg.type_base)[1]
152 if b.label=='Class' then
153 -- TODO: check if other modifiers are in place?
154 return t.xarg.type_base..'*;', get_pointer(t.xarg.type_base)
155 else
156 error('I cannot manipulate pointers to '..t.xarg.type_base)
159 error'I cannot manipulate double pointers'
160 else
161 -- this is any combination of constant, volatile and reference
162 local ret_get = nil
163 if typename==(t.xarg.type_base..' const&') then
164 ret_get = get_constref(t.xarg.type_base)
165 elseif typename==(t.xarg.type_base..'&') then
166 ret_get = get_ref(t.xarg.type_base)
168 assert(ret_get, 'cannot get non-base type '..typename..' from stack')
169 return type_properties(t.xarg.type_base), ret_get
173 entities.return_type = function(f)
174 assert_function(f)
175 if entities.is_destructor(f) then
176 return nil
177 elseif entities.is_constructor(f) then
178 -- FIXME: hack follows!
179 assert(f.xarg.type_name==f.xarg.type_base, 'return type of constructor is strange')
180 f.xarg.type_name = f.xarg.type_base..'*'
181 f.xarg.indirections='1'
182 return f
183 elseif f.xarg.type_name=='' or f.xarg.type_name=='void' then
184 return nil
185 else
186 return f
191 local arguments_on_stack = function(f)
192 assert_function(f)
193 local args_on_stack = ''
194 --print('=====', f.xarg.fullname)
195 for _,a in ipairs(f) do
196 --local st, err = pcall(type_on_stack, a)
197 --if not st then table.foreach(a, print) end
198 --assert(st, err)
199 local err = type_properties(a)
200 args_on_stack = args_on_stack .. err
202 if entities.takes_this_pointer(f) then
203 args_on_stack = f.xarg.member_of .. '*;' .. args_on_stack
205 return args_on_stack
208 function_description = function(f)
209 assert_function(f)
210 local args_on_stack = arguments_on_stack(f)
211 return f.xarg.type_name .. ' ' .. f.xarg.fullname .. ' (' .. args_on_stack .. ')'..
212 (f.xarg.static=='1' and ' [static]' or '')..
213 (f.xarg.virtual=='1' and ' [virtual]' or '')..
214 (entities.is_constructor(f) and ' [constructor]' or '')..
215 (entities.is_destructor(f) and ' [destructor]' or '')..
216 ' [in ' .. tostring(f.xarg.member_of) .. ']'
219 -- TODO: must wait for a way to specify pushing base types
220 local calling_code = function(f)
221 assert_function(f)
222 local ret, indent = '', ' '
223 local n = 0
224 for _,a in ipairs(f) do if a.label=='Argument' then
225 n = n + 1
226 local d, g, p = type_properties(a)
227 ret = ret .. indent .. g(n) .. '\n'
228 end end
229 if entities.is_constructor(f) then
230 elseif entities.is_constructor(f) then
231 elseif entities.takes_this_pointer(f) then
232 else
233 local args = ''
234 for i = 1,n do
235 args = args .. (i > 1 and ', arg' or 'arg') .. tostring(i)
237 args = '('..args..')';
238 local ret_type = entities.return_type(f)
239 ret_type = ret_type and ret_type.xarg.type_name or nil
240 local call_line = (ret_type and (ret_type..' ret = ') or '')
241 call_line = call_line .. f.xarg.fullname .. args
242 ret = ret .. indent .. call_line .. ';\n'
244 return ret
247 for _, v in pairs(xmlstream.byid) do
248 if string.find(v.label, 'Function')==1 then
249 local status, err = pcall(function_description, v)
250 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
251 if status then
252 local s, e = pcall(calling_code, v)
253 io[s and 'stdout' or 'stderr']:write((s and ''
254 or ('error calling '..v.xarg.fullname..': '))..e..(s and '' or '\n'))
256 --io[status and 'stdout' or 'stderr']:write((status and '' or v.xarg.fullname..': ')..err..'\n')
259 --table.foreach(name_list, print)