2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 * These methods are somewhat ugly because they have been copied out of
23 * the Swig source code and simply made compilable with groovy. They could
24 * all be much cleaner and smaller if they were completely groovyfied but
25 * I have no intention of doing that since they are complicated and they work
26 * and I don't want to try to trace down problems that would be inevitable
27 * with such a refactor.
29 public class SwigTypeParser
32 * This holds a mapping for typedefs from a type to it's base type.
34 private static Map typeTable = [:]
37 * Add a typedef node to the global list of typedefs to be used later in
40 public static void appendTypeTable(Node typetab) { typetab.each { typeTable[it.@namespace + it.@type] = it.@basetype } }
43 * Convert the type to an ltype considering the overloaded conversions.
45 public static String convertTypeToLTypeForParam(String ty)
47 // in the case where we're converting from a type to an ltype for a parameter,
48 // and the type is a r.*, we are going to assume the ltype is
49 // a "pass-by-value" on the stack.
50 return (ty.trim().startsWith('r.') ? SwigTypeParser.SwigType_ltype(ty.trim().substring(2)) : SwigTypeParser.SwigType_ltype(ty.trim()))
54 * This method will return the base type for the provided type string. For example,
55 * if the type string is p.MyType you will get MyType. If the string is
56 * p.q(const).int you will get 'int'
58 public static String getRootType(String ty)
60 int li = ty.lastIndexOf('.')
61 return li >= 0 ? ty.substring(li + 1) : ty
67 * Create a C string representation of a datatype.
69 public static String SwigType_str(String ty, String id = null)
71 String result = id ? id : ''
74 List elements = SwigType_split(ty)
75 if (elements == null) elements = []
76 int nelements = elements.size()
77 String element = nelements > 0 ? elements[0] : null
79 /* Now, walk the type list and start emitting */
80 for (int i = 0; i < nelements; i++) {
81 if (i < (nelements - 1)) {
82 nextelement = elements[i + 1]
83 forwardelement = nextelement
84 if (nextelement.startsWith('q(')) {
85 if (i < (nelements - 2)) forwardelement = elements[i + 2]
91 if (element.startsWith('q(')) {
92 String q = SwigType_parm(element)
93 result = q + ' ' + result
94 } else if (SwigType_ispointer(element)) {
96 if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
97 result = "(" + result + ")"
99 } else if (SwigType_ismemberpointer(element)) {
100 String q = SwigType_parm(element);
101 result = q + "::*" + result
102 if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
103 result = '(' + result + ')'
105 } else if (SwigType_isreference(element)) {
106 result = '&' + result
107 if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) {
108 result = '(' + result + ')'
110 } else if (SwigType_isarray(element)) {
111 result += '[' + SwigType_parm(element) + ']'
112 } else if (SwigType_isfunction(element)) {
114 List parms = SwigType_parmlist(element)
115 boolean didOne = false
116 for (String cur : parms) {
117 String p = SwigType_str(cur)
118 result += (didOne ? ',' : '') + p
123 if (element.startsWith("v(...)")) result = result + "..."
125 String bs = SwigType_namestr(element);
126 result = bs + ' ' + result
129 element = nextelement;
131 // convert template parameters
132 return result.replaceAll('<\\(', '<').replaceAll('\\)>', '>')
136 * This will resolve the typedefs given the parameter passed is a simple type.
137 * see SwigType_resolve_all_typedefs which will handle qualifiers, pointers,
138 * references, and typedef of typedefs to resolve all the way down to the
141 public static String SwigType_typedef_resolve(String t)
143 String td = typeTable[t]
144 String ret = td == null ? t : td
149 * This will resolve typedefs anbd handle qualifiers, pointers,
150 * references, and typedef of typedefs to resolve all the way down to the
153 public static String SwigType_resolve_all_typedefs(String s)
158 /* Nuke all leading qualifiers, appending them to the result*/
159 while (SwigType_isqualifier(tc)) {
160 List tmpl = SwigType_pop(tc)
165 if (SwigType_issimple(tc)) {
166 /* Resolve any typedef definitions */
169 while ((td = SwigType_typedef_resolve(tt)) != tt) {
174 else if (td != tt) tt = td
181 List tmpl = SwigType_pop(tc)
183 result += SwigType_resolve_all_typedefs(tmpl[1])
188 * SwigType_ltype(const SwigType *ty)
190 * Create a locally assignable type
192 public static String SwigType_ltype(String s) {
196 /* Nuke all leading qualifiers */
197 while (SwigType_isqualifier(tc)) {
198 tc = SwigType_pop(tc)[1]
201 if (SwigType_issimple(tc)) {
202 /* Resolve any typedef definitions */
205 while ((td = SwigType_typedef_resolve(tt)) != tt) {
206 if ((td != tt) && (SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td))) {
207 /* We need to use the typedef type */
211 else if (td != tt) tt = td
215 List elements = SwigType_split(tc)
216 int nelements = elements.size()
218 /* Now, walk the type list and start emitting */
219 boolean notypeconv = false
220 boolean firstarray = true
221 for (int i = 0; i < nelements; i++) {
222 String element = elements[i]
223 /* when we see a function, we need to preserve the following types */
224 if (SwigType_isfunction(element)) {
227 if (SwigType_isqualifier(element)) {
228 /* Do nothing. Ignore */
229 } else if (SwigType_ispointer(element)) {
231 // this is a bit of a short circuit to avoid having to import the entire SwigType_typedef_resolve method which
232 // handles pointers to typedefed types, etc.
233 // collapse the rest of the list
235 for (int j = i + 1; j < nelements; j++) tmps += elements[j]
236 return result + SwigType_ltype(tmps)
238 } else if (SwigType_ismemberpointer(element)) {
241 } else if (SwigType_isreference(element)) {
248 } else if (SwigType_isarray(element) && firstarray) {
255 } else if (SwigType_isenum(element)) {
256 boolean anonymous_enum = (element == "enum ")
257 if (notypeconv || !anonymous_enum) {
268 // convert template parameters
269 //return result.replaceAll('<\\(', '<').replaceAll('\\)>', '>')
273 * This creates the C++ declaration for a valid ltype for the type string
274 * given. For example, if the type is a "const char*" which is equivalent
275 * to the type string 'p.q(const).char', the return value from this method
278 public static String SwigType_lstr(String type)
280 return SwigType_str(convertTypeToLTypeForParam(type))
283 public static boolean SwigType_ispointer(String t)
285 if (t.startsWith('q(')) t = t.substring(t.indexOf('.') + 1)
286 return t.startsWith('p.')
289 public static String SwigType_makepointer(String t)
291 String prefix = (t.startsWith('q(')) ? t.substring(0,t.indexOf('.') + 1) : ""
292 String remainder = (t.startsWith('q(')) ? t.substring(t.indexOf('.') + 1) : t
294 return prefix + "p." + remainder
297 public static boolean SwigType_isarray(String t) { return t.startsWith('a(') }
299 public static boolean SwigType_ismemberpointer(String t) { return t?.startsWith('m(') }
301 public static boolean SwigType_isqualifier(String t) { return t?.startsWith('q(') }
303 public static boolean SwigType_isreference(String t) { return t.startsWith('r.') }
305 public static boolean SwigType_isenum(String t) { return t.startsWith('enum') }
307 public static String SwigType_istemplate(String t) {
308 int c = t.indexOf("<(")
309 return (c >= 0 && t.indexOf(')>',c+2) >= 0)
312 public static boolean SwigType_isfunction(String t)
314 if (t.startsWith('q(')) t = t.substring(t.indexOf('.') + 1,)
315 return t.startsWith('f(')
318 public static boolean SwigType_isconst(String t) {
320 if (t == null) return false
321 if (t.substring(c).startsWith("q(")) {
322 String q = SwigType_parm(t)
323 if (q.indexOf("const") >= 0) return true
325 /* Hmmm. Might be const through a typedef */
326 if (SwigType_issimple(t)) {
327 String td = SwigType_typedef_resolve(t)
328 if (td != t) return SwigType_isconst(td)
334 private static String SwigType_parm(String t) {
335 int start = t.indexOf("(")
336 if (start < 0) return null
340 while (c < t.length()) {
341 if (t.charAt(c) == ')') {
342 if (nparens == 0) break;
345 else if (t.charAt(c) == '(') nparens++
348 return t.substring(start,c)
351 public static List SwigType_templateparmlist(String t)
353 int i = t.indexOf('<');
354 return SwigType_parmlist(t.substring(i))
357 /* -----------------------------------------------------------------------------
358 * SwigType_parmlist()
360 * Splits a comma separated list of parameters into its component parts
361 * The input is expected to contain the parameter list within () brackets
362 * Returns 0 if no argument list in the input, ie there are no round brackets ()
363 * Returns an empty List if there are no parameters in the () brackets
366 * Foo(std::string,p.f().Bar<(int,double)>)
368 * returns 2 elements in the list:
370 * p.f().Bar<(int,double)>
371 * ----------------------------------------------------------------------------- */
373 private static List SwigType_parmlist(String p) {
377 assert p, "Cannot pass null to SwigType_parmlist"
378 itemstart = p.indexOf('(')
379 assert p.indexOf('.') == -1 || p.indexOf('.') > itemstart, p + " is expected to contain sub elements of a type"
382 while (c < p.length()) {
383 if (p.charAt(c) == ',') {
384 list.add(p.substring(itemstart,c))
386 } else if (p.charAt(c) == '(') {
389 while (c < p.length()) {
390 if (p.charAt(c) == '(') nparens++
391 if (p.charAt(c) == ')') {
393 if (nparens == 0) break
397 } else if (p.charAt(c) == ')') {
400 if (c < p.length()) c++
403 if (c != itemstart) {
404 list.add(p.substring(itemstart,c))
409 /* -----------------------------------------------------------------------------
412 * Returns a string of the base type. Takes care of template expansions
413 * ----------------------------------------------------------------------------- */
415 private static String SwigType_namestr(String t) {
417 int c = t.indexOf("<(")
419 if (c < 0 || t.indexOf(')>',c+2) < 0) return t
421 String r = t.substring(0,c)
422 if (t.charAt(c - 1) == '<') r += ' '
425 List p = SwigType_parmlist(t.substring(c + 1))
426 for (int i = 0; i < p.size(); i++) {
427 String str = SwigType_str(p[i], null);
428 /* Avoid creating a <: token, which is the same as [ in C++ - put a space after '<'. */
429 if (i == 0 && str.length() > 0) r += ' '
431 if ((i + 1) < p.size()) r += ','
434 String suffix = SwigType_templatesuffix(t);
435 if (suffix.length() > 0) {
436 String suffix_namestr = SwigType_namestr(suffix);
444 /* -----------------------------------------------------------------------------
445 * SwigType_templatesuffix()
447 * Returns text after a template substitution. Used to handle scope names
453 * ----------------------------------------------------------------------------- */
455 private static String SwigType_templatesuffix(String t) {
457 while (c < t.length()) {
458 if ((t.charAt(c) == '<') && (t.charAt(c + 1) == '(')) {
461 while (c < t.length() && nest != 0) {
462 if (t.charAt(c) == '<') nest++
463 if (t.charAt(c) == '>') nest--
466 return t.substring(c)
473 /* -----------------------------------------------------------------------------
476 * Splits a type into it's component parts and returns a list of string.
477 * ----------------------------------------------------------------------------- */
479 private static List SwigType_split(String t) {
484 while (c < t.length()) {
485 len = element_size(t.substring(c))
486 String item = t.substring(c,c + len)
489 if (c < t.length() && t.charAt(c) == '.') c++
494 /* -----------------------------------------------------------------------------
495 * static element_size()
497 * This utility function finds the size of a single type element in a type string.
498 * Type elements are always delimited by periods, but may be nested with
499 * parentheses. A nested element is always handled as a single item.
501 * Returns the integer size of the element (which can be used to extract a
502 * substring, to chop the element off, or for other purposes).
503 * ----------------------------------------------------------------------------- */
505 private static int element_size(String s) {
508 while (c < s.length()) {
509 if (s.charAt(c) == '.') {
512 } else if (s.charAt(c) == '(') {
515 while (c < s.length()) {
516 if (s.charAt(c) == '(') nparen++
517 if (s.charAt(c) == ')') {
519 if (nparen == 0) break
524 if (c < s.length()) c++
529 /* -----------------------------------------------------------------------------
532 * Pop one type element off the type.
533 * Example: t in: q(const).p.Integer
536 * ----------------------------------------------------------------------------- */
538 private static Tuple SwigType_pop(String t) {
545 int sz = element_size(t.substring(c))
546 return [ t.substring(c,c + sz), t.substring(c+sz) ]
549 private static boolean SwigType_issimple(String t) {
552 while (c < t.length()) {
553 if (t.charAt(c) == '<') {
556 while (c < t.length() && nest != 0) {
557 if (t.charAt(c) == '<') nest++
558 if (t.charAt(c) == '>') nest--
563 if (t.charAt(c) == '.')
571 public static void main(String[] args)
575 <entry basetype="std::vector<(p.XBMCAddon::xbmcgui::ListItem)>" type="ListItemList" namespace="XBMCAddon::xbmcgui::"/>
578 Node xml = new XmlParser().parseText(xmlText)
580 SwigTypeParser.appendTypeTable(xml)
582 // testPrint('f(int,int,int)','foo')
583 // testPrint('p.a(10).p.f(int,p.f(int).int)','foo')
584 // testPrint('p.q(const).char','foo')
585 // testPrint('f(r.q(const).String,p.q(const).XBMCAddon::xbmcgui::ListItem,bool)','foo')
586 // testPrint('r.q(const).String','foo')
587 // testPrint('q(const).p.q(const).char','foo')
588 //testPrint('std::vector<(p.String)>','foo')
589 // testPrint('r.q(const).String')
590 //System.out.println "${convertTypeToLType('bool')}"
591 //testPrint('p.q(const).XBMCAddon::xbmcgui::ListItemList')
592 //testPrint('p.q(const).XBMCAddon::xbmcgui::ListItemList')
593 //testPrint(SwigTypeParser.SwigType_makepointer('r.q(const).std::map<(String,String)>'), 'foo')
594 testPrint(SwigTypeParser.SwigType_makepointer('q(const).p.q(const).char'),'bfoo')
597 private static void testPrint(String ty, String id = 'foo')
599 println SwigTypeParser.SwigType_ltype(ty) + "|" + SwigTypeParser.SwigType_str(SwigTypeParser.SwigType_ltype(ty),id) + ' ' + " = " + ty + '|' + SwigTypeParser.SwigType_str(ty,id)