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=1,getn(_renaming) do
79	 local m,n = gsub(s,_renaming[i].old,_renaming[i].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 while i<=arg.n do
256  if _cont and not strfind(_cont,'[%(,"]') and
257     strfind(arg[i],"^[%a_~]") then
258	    line = line .. ' '
259  end
260  line = line .. arg[i]
261  if arg[i] ~= '' then
262   _cont = strsub(arg[i],-1,-1)
263  end
264  i = i+1
265 end
266 if strfind(arg[arg.n],"[%/%)%;%{%}]$") then
267  _cont=nil line = line .. '\n'
268 end
269	return line
270end
271
272-- output line
273function output (...)
274 local i=1
275 while i<=arg.n do
276  if _cont and not strfind(_cont,'[%(,"]') and
277     strfind(arg[i],"^[%a_~]") then
278	    write(' ')
279  end
280  write(arg[i])
281  if arg[i] ~= '' then
282   _cont = strsub(arg[i],-1,-1)
283  end
284  i = i+1
285 end
286 if strfind(arg[arg.n],"[%/%)%;%{%}]$") then
287  _cont=nil write('\n')
288 end
289end
290
291function get_property_methods(ptype, name)
292
293	if get_property_methods_hook and get_property_methods_hook(ptype,name) then
294		return get_property_methods_hook(ptype, name)
295	end
296
297	if ptype == "default" then -- get_name, set_name
298		return "get_"..name, "set_"..name
299	end
300
301	if ptype == "qt" then -- name, setName
302		return name, "set"..string.upper(string.sub(name, 1, 1))..string.sub(name, 2, -1)
303	end
304
305	if ptype == "overload" then -- name, name
306		return name,name
307	end
308
309	return nil
310end
311
312-------------- the hooks
313
314-- called right after processing the $[ichl]file directives,
315-- right before processing anything else
316-- takes the package object as the parameter
317function preprocess_hook(p)
318	-- p.code has all the input code from the pkg
319end
320
321
322-- called for every $ifile directive
323-- takes a table with a string called 'code' inside, the filename, and any extra arguments
324-- passed to $ifile. no return value
325function include_file_hook(t, filename, ...)
326
327end
328
329-- called after processing anything that's not code (like '$renaming', comments, etc)
330-- and right before parsing the actual code.
331-- takes the Package object with all the code on the 'code' key. no return value
332function preparse_hook(package)
333
334end
335
336-- called before starting output
337function pre_output_hook(package)
338
339end
340
341-- called after writing all the output.
342-- takes the Package object
343function post_output_hook(package)
344
345end
346
347
348-- called from 'get_property_methods' to get the methods to retrieve a property
349-- according to its type
350function get_property_methods_hook(property_type, name)
351
352end
353
354-- called from ClassContainer:doparse with the string being parsed
355-- return nil, or a substring
356function parser_hook(s)
357
358	return nil
359end
360
361-- called from classFunction:supcode, before the call to the function is output
362function pre_call_hook(f)
363
364end
365
366-- called from classFunction:supcode, after the call to the function is output
367function post_call_hook(f)
368
369end
370
371-- called before the register code is output
372function pre_register_hook(package)
373
374end
375
376-- called to output an error message
377function output_error_hook(...)
378	return string.format(...)
379end
380
381-- custom pushers
382
383_push_functions = {}
384_is_functions = {}
385_to_functions = {}
386
387_base_push_functions = {}
388_base_is_functions = {}
389_base_to_functions = {}
390
391local function search_base(t, funcs)
392
393	local class = _global_classes[t]
394
395	while class do
396		if funcs[class.type] then
397			return funcs[class.type]
398		end
399		class = _global_classes[class.btype]
400	end
401	return nil
402end
403
404function get_push_function(t)
405	return _push_functions[t] or search_base(t, _base_push_functions) or "tolua_pushusertype"
406end
407
408function get_to_function(t)
409	return _to_functions[t] or search_base(t, _base_to_functions) or "tolua_tousertype"
410end
411
412function get_is_function(t)
413	return _is_functions[t] or search_base(t, _base_is_functions) or "tolua_isusertype"
414end
415