1-- tolua: basic utility functions
2-- Written by Waldemar Celes
3-- TeCGraf/PUC-Rio
4-- Jul 1998
5-- Last update: Apr 2003
6-- $Id: $
7
8-- This code is free software; you can redistribute it and/or modify it.
9-- The software provided hereunder is on an "as is" basis, and
10-- the author has no obligation to provide maintenance, support, updates,
11-- enhancements, or modifications.
12
13
14-- Basic C types and their corresponding Lua types
15-- All occurrences of "char*" will be replaced by "_cstring",
16-- and all occurrences of "void*" will be replaced by "_userdata"
17_basic = {
18 ['void'] = '',
19 ['char'] = 'number',
20 ['int'] = 'number',
21 ['short'] = 'number',
22 ['long'] = 'number',
23 ['unsigned'] = 'number',
24 ['float'] = 'number',
25 ['double'] = 'number',
26 ['_cstring'] = 'string',
27 ['_userdata'] = 'userdata',
28 ['char*'] = 'string',
29 ['void*'] = 'userdata',
30 ['bool'] = 'boolean',
31 ['lua_Object'] = 'value',
32 ['LUA_VALUE'] = 'value',    -- for compatibility with tolua 4.0
33 ['lua_State*'] = 'state',
34 ['_lstate'] = 'state',
35 ['lua_Function'] = 'value',
36}
37
38_basic_ctype = {
39 number = "lua_Number",
40 string = "const char*",
41 userdata = "void*",
42 boolean = "bool",
43 value = "int",
44 state = "lua_State*",
45}
46
47-- functions the are used to do a 'raw push' of basic types
48_basic_raw_push = {}
49
50-- List of user defined types
51-- Each type corresponds to a variable name that stores its tag value.
52_usertype = {}
53
54-- List of types that have to be collected
55_collect = {}
56
57-- List of types
58_global_types = {n=0}
59_global_types_hash = {}
60
61-- list of classes
62_global_classes = {}
63
64-- List of enum constants
65_global_enums = {}
66
67-- List of auto renaming
68_renaming = {}
69function appendrenaming (s)
70 local b,e,old,new = strfind(s,"%s*(.-)%s*@%s*(.-)%s*$")
71	if not b then
72	 error("#Invalid renaming syntax; it should be of the form: pattern@pattern")
73	end
74	tinsert(_renaming,{old=old, new=new})
75end
76
77function applyrenaming (s)
78	for i,v in ipairs(_renaming) do
79	 local m,n = gsub(s,v.old,v.new)
80		if n ~= 0 then
81		 return m
82		end
83	end
84	return nil
85end
86
87-- Error handler
88function tolua_error (s,f)
89if _curr_code then
90	print("***curr code for error is "..tostring(_curr_code))
91	print(debug.traceback())
92end
93 local out = _OUTPUT
94 _OUTPUT = _STDERR
95 if strsub(s,1,1) == '#' then
96  write("\n** tolua: "..strsub(s,2)..".\n\n")
97  if _curr_code then
98   local _,_,s = strfind(_curr_code,"^%s*(.-\n)") -- extract first line
99   if s==nil then s = _curr_code end
100   s = gsub(s,"_userdata","void*") -- return with 'void*'
101   s = gsub(s,"_cstring","char*")  -- return with 'char*'
102   s = gsub(s,"_lstate","lua_State*")  -- return with 'lua_State*'
103   write("Code being processed:\n"..s.."\n")
104  end
105 else
106 if not f then f = "(f is nil)" end
107  print("\n** tolua internal error: "..f..s..".\n\n")
108  return
109 end
110 _OUTPUT = out
111end
112
113function warning (msg)
114 if flags.q then return end
115 local out = _OUTPUT
116 _OUTPUT = _STDERR
117 write("\n** tolua warning: "..msg..".\n\n")
118 _OUTPUT = out
119end
120
121-- register an user defined type: returns full type
122function regtype (t)
123	--if isbasic(t) then
124	--	return t
125	--end
126	local ft = findtype(t)
127
128	if not _usertype[ft] then
129		return appendusertype(t)
130	end
131	return ft
132end
133
134-- return type name: returns full type
135function typevar(type)
136	if type == '' or type == 'void' then
137		return type
138	else
139		local ft = findtype(type)
140		if ft then
141			return ft
142		end
143		_usertype[type] = type
144		return type
145	end
146end
147
148-- check if basic type
149function isbasic (type)
150 local t = gsub(type,'const ','')
151 local m,t = applytypedef('', t)
152 local b = _basic[t]
153 if b then
154  return b,_basic_ctype[b]
155 end
156 return nil
157end
158
159-- split string using a token
160function split (s,t)
161 local l = {n=0}
162 local f = function (s)
163  l.n = l.n + 1
164  l[l.n] = s
165  return ""
166 end
167 local p = "%s*(.-)%s*"..t.."%s*"
168 s = gsub(s,"^%s+","")
169 s = gsub(s,"%s+$","")
170 s = gsub(s,p,f)
171 l.n = l.n + 1
172 l[l.n] = gsub(s,"(%s%s*)$","")
173 return l
174end
175
176-- splits a string using a pattern, considering the spacial cases of C code (templates, function parameters, etc)
177-- pattern can't contain the '^' (as used to identify the begining of the line)
178-- also strips whitespace
179function split_c_tokens(s, pat)
180
181	s = string.gsub(s, "^%s*", "")
182	s = string.gsub(s, "%s*$", "")
183
184	local token_begin = 1
185	local token_end = 1
186	local ofs = 1
187	local ret = {n=0}
188
189	function add_token(ofs)
190
191		local t = string.sub(s, token_begin, ofs)
192		t = string.gsub(t, "^%s*", "")
193		t = string.gsub(t, "%s*$", "")
194		ret.n = ret.n + 1
195		ret[ret.n] = t
196	end
197
198	while ofs <= string.len(s) do
199
200		local sub = string.sub(s, ofs, -1)
201		local b,e = string.find(sub, "^"..pat)
202		if b then
203			add_token(ofs-1)
204			ofs = ofs+e
205			token_begin = ofs
206		else
207			local char = string.sub(s, ofs, ofs)
208			if char == "(" or char == "<" then
209
210				local block
211				if char == "(" then block = "^%b()" end
212				if char == "<" then block = "^%b<>" end
213
214				b,e = string.find(sub, block)
215				if not b then
216					-- unterminated block?
217					ofs = ofs+1
218				else
219					ofs = ofs + e
220				end
221
222			else
223				ofs = ofs+1
224			end
225		end
226
227	end
228	add_token(ofs)
229	--if ret.n == 0 then
230
231	--	ret.n=1
232	--	ret[1] = ""
233	--end
234
235	return ret
236
237end
238
239-- concatenate strings of a table
240function concat (t,f,l,jstr)
241	jstr = jstr or " "
242 local s = ''
243 local i=f
244 while i<=l do
245  s = s..t[i]
246  i = i+1
247  if i <= l then s = s..jstr end
248 end
249 return s
250end
251
252-- concatenate all parameters, following output rules
253function concatparam (line, ...)
254 local i=1
255 local arg={...}
256 while i<=#arg do
257  if _cont and not strfind(_cont,'[%(,"]') and
258     strfind(arg[i],"^[%a_~]") then
259	    line = line .. ' '
260  end
261  line = line .. arg[i]
262  if arg[i] ~= '' then
263   _cont = strsub(arg[i],-1,-1)
264  end
265  i = i+1
266 end
267 if strfind(arg[#arg],"[%/%)%;%{%}]$") then
268  _cont=nil line = line .. '\n'
269 end
270	return line
271end
272
273-- output line
274function output (...)
275 local i=1
276 local arg = {...}
277 while i<=#arg do
278  if _cont and not strfind(_cont,'[%(,"]') and
279     strfind(arg[i],"^[%a_~]") then
280	    write(' ')
281  end
282  write(arg[i])
283  if arg[i] ~= '' then
284   _cont = strsub(arg[i],-1,-1)
285  end
286  i = i+1
287 end
288 if strfind(arg[#arg],"[%/%)%;%{%}]$") then
289  _cont=nil write('\n')
290 end
291end
292
293function get_property_methods(ptype, name)
294
295	if get_property_methods_hook and get_property_methods_hook(ptype,name) then
296		return get_property_methods_hook(ptype, name)
297	end
298
299	if ptype == "default" then -- get_name, set_name
300		return "get_"..name, "set_"..name
301	end
302
303	if ptype == "qt" then -- name, setName
304		return name, "set"..string.upper(string.sub(name, 1, 1))..string.sub(name, 2, -1)
305	end
306
307	if ptype == "overload" then -- name, name
308		return name,name
309	end
310
311	return nil
312end
313
314-------------- the hooks
315
316-- called right after processing the $[ichl]file directives,
317-- right before processing anything else
318-- takes the package object as the parameter
319function preprocess_hook(p)
320	-- p.code has all the input code from the pkg
321end
322
323
324-- called for every $ifile directive
325-- takes a table with a string called 'code' inside, the filename, and any extra arguments
326-- passed to $ifile. no return value
327function include_file_hook(t, filename, ...)
328
329end
330
331-- called after processing anything that's not code (like '$renaming', comments, etc)
332-- and right before parsing the actual code.
333-- takes the Package object with all the code on the 'code' key. no return value
334function preparse_hook(package)
335
336end
337
338-- called before starting output
339function pre_output_hook(package)
340
341end
342
343-- called after writing all the output.
344-- takes the Package object
345function post_output_hook(package)
346
347end
348
349
350-- called from 'get_property_methods' to get the methods to retrieve a property
351-- according to its type
352function get_property_methods_hook(property_type, name)
353
354end
355
356-- called from ClassContainer:doparse with the string being parsed
357-- return nil, or a substring
358function parser_hook(s)
359
360	return nil
361end
362
363-- called from classFunction:supcode, before the call to the function is output
364function pre_call_hook(f)
365
366end
367
368-- called from classFunction:supcode, after the call to the function is output
369function post_call_hook(f)
370
371end
372
373-- called before the register code is output
374function pre_register_hook(package)
375
376end
377
378
379-- called to output an error message
380function output_error_hook(...)
381	return string.format(table.unpack{...})
382end
383
384-- custom pushers
385
386_push_functions = {}
387_is_functions = {}
388_to_functions = {}
389
390_base_push_functions = {}
391_base_is_functions = {}
392_base_to_functions = {}
393
394local function search_base(t, funcs)
395
396	local class = _global_classes[t]
397
398	while class do
399		if funcs[class.type] then
400			return funcs[class.type]
401		end
402		class = _global_classes[class.btype]
403	end
404	return nil
405end
406
407function get_push_function(t)
408	return _push_functions[t] or search_base(t, _base_push_functions) or "tolua_pushusertype"
409end
410
411function get_to_function(t)
412	return _to_functions[t] or search_base(t, _base_to_functions) or "tolua_tousertype"
413end
414
415function get_is_function(t)
416	return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype"
417end
418