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/>.
21 import groovy
.xml
.XmlParser
24 * These methods are somewhat ugly because they have been copied out of
25 * the Swig source code and simply made compilable with groovy. They could
26 * all be much cleaner and smaller if they were completely groovyfied but
27 * I have no intention of doing that since they are complicated and they work
28 * and I don't want to try to trace down problems that would be inevitable
29 * with such a refactor.
31 public class SwigTypeParser
34 * This holds a mapping for typedefs from a type to it's base type.
36 private static Map typeTable
= [:]
39 * Add a typedef node to the global list of typedefs to be used later in
42 public static void appendTypeTable(Node typetab
) { typetab
.each
{ typeTable
[it
.@namespace + it
.@type] = it
.@basetype } }
45 * Convert the type to an ltype considering the overloaded conversions.
47 public static String
convertTypeToLTypeForParam(String ty
)
49 // in the case where we're converting from a type to an ltype for a parameter,
50 // and the type is a r.*, we are going to assume the ltype is
51 // a "pass-by-value" on the stack.
52 return (ty
.trim().startsWith('r.') ? SwigTypeParser
.SwigType_ltype(ty
.trim().substring(2)) : SwigTypeParser
.SwigType_ltype(ty
.trim()))
56 * This method will return the base type for the provided type string. For example,
57 * if the type string is p.MyType you will get MyType. If the string is
58 * p.q(const).int you will get 'int'
60 public static String
getRootType(String ty
)
62 int li
= ty
.lastIndexOf('.')
63 return li
>= 0 ? ty
.substring(li
+ 1) : ty
69 * Create a C string representation of a datatype.
71 public static String
SwigType_str(String ty
, String id
= null)
73 String result
= id ? id
: ''
76 List elements
= SwigType_split(ty
)
77 if (elements
== null) elements
= []
78 int nelements
= elements
.size()
79 String element
= nelements
> 0 ? elements
[0] : null
81 /* Now, walk the type list and start emitting */
82 for (int i
= 0; i
< nelements
; i
++) {
83 if (i
< (nelements
- 1)) {
84 nextelement
= elements
[i
+ 1]
85 forwardelement
= nextelement
86 if (nextelement
.startsWith('q(')) {
87 if (i
< (nelements
- 2)) forwardelement
= elements
[i
+ 2]
93 if (element
.startsWith('q(')) {
94 String q
= SwigType_parm(element
)
95 result
= q
+ ' ' + result
96 } else if (SwigType_ispointer(element
)) {
98 if ((forwardelement
) && ((SwigType_isfunction(forwardelement
) || (SwigType_isarray(forwardelement
))))) {
99 result
= "(" + result
+ ")"
101 } else if (SwigType_ismemberpointer(element
)) {
102 String q
= SwigType_parm(element
);
103 result
= q
+ "::*" + result
104 if ((forwardelement
) && ((SwigType_isfunction(forwardelement
) || (SwigType_isarray(forwardelement
))))) {
105 result
= '(' + result
+ ')'
107 } else if (SwigType_isreference(element
)) {
108 result
= '&' + result
109 if ((forwardelement
) && ((SwigType_isfunction(forwardelement
) || (SwigType_isarray(forwardelement
))))) {
110 result
= '(' + result
+ ')'
112 } else if (SwigType_isarray(element
)) {
113 result
+= '[' + SwigType_parm(element
) + ']'
114 } else if (SwigType_isfunction(element
)) {
116 List parms
= SwigType_parmlist(element
)
117 boolean didOne
= false
118 for (String cur
: parms
) {
119 String p
= SwigType_str(cur
)
120 result
+= (didOne ?
',' : '') + p
125 if (element
.startsWith("v(...)")) result
= result
+ "..."
127 String bs
= SwigType_namestr(element
);
128 result
= bs
+ ' ' + result
131 element
= nextelement
;
133 // convert template parameters
134 return result
.replaceAll('<\\(', '<').replaceAll('\\)>', '>')
138 * This will resolve the typedefs given the parameter passed is a simple type.
139 * see SwigType_resolve_all_typedefs which will handle qualifiers, pointers,
140 * references, and typedef of typedefs to resolve all the way down to the
143 public static String
SwigType_typedef_resolve(String t
)
145 String td
= typeTable
[t
]
146 String ret
= td
== null ? t
: td
151 * This will resolve typedefs and handle qualifiers, pointers,
152 * references, and typedef of typedefs to resolve all the way down to the
155 public static String
SwigType_resolve_all_typedefs(String s
)
160 /* Nuke all leading qualifiers, appending them to the result*/
161 while (SwigType_isqualifier(tc
)) {
162 List tmpl
= SwigType_pop(tc
)
167 if (SwigType_issimple(tc
)) {
168 /* Resolve any typedef definitions */
171 while ((td
= SwigType_typedef_resolve(tt
)) != tt
) {
176 else if (td
!= tt
) tt
= td
183 List tmpl
= SwigType_pop(tc
)
185 result
+= SwigType_resolve_all_typedefs(tmpl
[1])
190 * SwigType_ltype(const SwigType *ty)
192 * Create a locally assignable type
194 public static String
SwigType_ltype(String s
) {
198 /* Nuke all leading qualifiers */
199 while (SwigType_isqualifier(tc
)) {
200 tc
= SwigType_pop(tc
)[1]
203 if (SwigType_issimple(tc
)) {
204 /* Resolve any typedef definitions */
207 while ((td
= SwigType_typedef_resolve(tt
)) != tt
) {
208 if ((td
!= tt
) && (SwigType_isconst(td
) || SwigType_isarray(td
) || SwigType_isreference(td
))) {
209 /* We need to use the typedef type */
213 else if (td
!= tt
) tt
= td
217 List elements
= SwigType_split(tc
)
218 int nelements
= elements
.size()
220 /* Now, walk the type list and start emitting */
221 boolean notypeconv
= false
222 boolean firstarray
= true
223 for (int i
= 0; i
< nelements
; i
++) {
224 String element
= elements
[i
]
225 /* when we see a function, we need to preserve the following types */
226 if (SwigType_isfunction(element
)) {
229 if (SwigType_isqualifier(element
)) {
230 /* Do nothing. Ignore */
231 } else if (SwigType_ispointer(element
)) {
233 // this is a bit of a short circuit to avoid having to import the entire SwigType_typedef_resolve method which
234 // handles pointers to typedefed types, etc.
235 // collapse the rest of the list
237 for (int j
= i
+ 1; j
< nelements
; j
++) tmps
+= elements
[j
]
238 return result
+ SwigType_ltype(tmps
)
240 } else if (SwigType_ismemberpointer(element
)) {
243 } else if (SwigType_isreference(element
)) {
250 } else if (SwigType_isarray(element
) && firstarray
) {
257 } else if (SwigType_isenum(element
)) {
258 boolean anonymous_enum
= (element
== "enum ")
259 if (notypeconv
|| !anonymous_enum
) {
270 // convert template parameters
271 //return result.replaceAll('<\\(', '<').replaceAll('\\)>', '>')
275 * SwigType_lrtype(const SwigType *ty)
277 * Create a locally assignable reference type
279 public static String
SwigType_lrtype(String s
) {
280 String ltype
= SwigType_ltype(s
);
281 if (SwigType_ispointer(s
)) {
289 * This creates the C++ declaration for a valid ltype for the type string
290 * given. For example, if the type is a "const char*" which is equivalent
291 * to the type string 'p.q(const).char', the return value from this method
294 public static String
SwigType_lstr(String type
)
296 return SwigType_str(convertTypeToLTypeForParam(type
))
299 public static boolean SwigType_ispointer(String t
)
301 if (t
.startsWith('q(')) t
= t
.substring(t
.indexOf('.') + 1)
302 return t
.startsWith('p.')
305 public static String
SwigType_makepointer(String t
)
307 String prefix
= (t
.startsWith('q(')) ? t
.substring(0,t
.indexOf('.') + 1) : ""
308 String remainder
= (t
.startsWith('q(')) ? t
.substring(t
.indexOf('.') + 1) : t
310 return prefix
+ "p." + remainder
313 public static boolean SwigType_isarray(String t
) { return t
.startsWith('a(') }
315 public static boolean SwigType_ismemberpointer(String t
) { return t?
.startsWith('m(') }
317 public static boolean SwigType_isqualifier(String t
) { return t?
.startsWith('q(') }
319 public static boolean SwigType_isreference(String t
) { return t
.startsWith('r.') }
321 public static boolean SwigType_isenum(String t
) { return t
.startsWith('enum') }
323 public static String
SwigType_istemplate(String t
) {
324 int c
= t
.indexOf("<(")
325 return (c
>= 0 && t
.indexOf(')>',c
+2) >= 0)
328 public static boolean SwigType_isfunction(String t
)
330 if (t
.startsWith('q(')) t
= t
.substring(t
.indexOf('.') + 1,)
331 return t
.startsWith('f(')
334 public static boolean SwigType_isconst(String t
) {
336 if (t
== null) return false
337 if (t
.substring(c
).startsWith("q(")) {
338 String q
= SwigType_parm(t
)
339 if (q
.indexOf("const") >= 0) return true
341 /* Hmmm. Might be const through a typedef */
342 if (SwigType_issimple(t
)) {
343 String td
= SwigType_typedef_resolve(t
)
344 if (td
!= t
) return SwigType_isconst(td
)
350 private static String
SwigType_parm(String t
) {
351 int start
= t
.indexOf("(")
352 if (start
< 0) return null
356 while (c
< t
.length()) {
357 if (t
.charAt(c
) == ')') {
358 if (nparens
== 0) break;
361 else if (t
.charAt(c
) == '(') nparens
++
364 return t
.substring(start
,c
)
367 public static List
SwigType_templateparmlist(String t
)
369 int i
= t
.indexOf('<');
370 return SwigType_parmlist(t
.substring(i
))
373 /* -----------------------------------------------------------------------------
374 * SwigType_parmlist()
376 * Splits a comma separated list of parameters into its component parts
377 * The input is expected to contain the parameter list within () brackets
378 * Returns 0 if no argument list in the input, ie there are no round brackets ()
379 * Returns an empty List if there are no parameters in the () brackets
382 * Foo(std::string,p.f().Bar<(int,double)>)
384 * returns 2 elements in the list:
386 * p.f().Bar<(int,double)>
387 * ----------------------------------------------------------------------------- */
389 private static List
SwigType_parmlist(String p
) {
393 assert p
, "Cannot pass null to SwigType_parmlist"
394 itemstart
= p
.indexOf('(')
395 assert p
.indexOf('.') == -1 || p
.indexOf('.') > itemstart
, p
+ " is expected to contain sub elements of a type"
398 while (c
< p
.length()) {
399 if (p
.charAt(c
) == ',') {
400 list
.add(p
.substring(itemstart
,c
))
402 } else if (p
.charAt(c
) == '(') {
405 while (c
< p
.length()) {
406 if (p
.charAt(c
) == '(') nparens
++
407 if (p
.charAt(c
) == ')') {
409 if (nparens
== 0) break
413 } else if (p
.charAt(c
) == ')') {
416 if (c
< p
.length()) c
++
419 if (c
!= itemstart
) {
420 list
.add(p
.substring(itemstart
,c
))
425 /* -----------------------------------------------------------------------------
428 * Returns a string of the base type. Takes care of template expansions
429 * ----------------------------------------------------------------------------- */
431 private static String
SwigType_namestr(String t
) {
433 int c
= t
.indexOf("<(")
435 if (c
< 0 || t
.indexOf(')>',c
+2) < 0) return t
437 String r
= t
.substring(0,c
)
438 if (t
.charAt(c
- 1) == '<') r
+= ' '
441 List p
= SwigType_parmlist(t
.substring(c
+ 1))
442 for (int i
= 0; i
< p
.size(); i
++) {
443 String str
= SwigType_str(p
[i
], null);
444 /* Avoid creating a <: token, which is the same as [ in C++ - put a space after '<'. */
445 if (i
== 0 && str
.length() > 0) r
+= ' '
447 if ((i
+ 1) < p
.size()) r
+= ','
450 String suffix
= SwigType_templatesuffix(t
);
451 if (suffix
.length() > 0) {
452 String suffix_namestr
= SwigType_namestr(suffix
);
460 /* -----------------------------------------------------------------------------
461 * SwigType_templatesuffix()
463 * Returns text after a template substitution. Used to handle scope names
469 * ----------------------------------------------------------------------------- */
471 private static String
SwigType_templatesuffix(String t
) {
473 while (c
< t
.length()) {
474 if ((t
.charAt(c
) == '<') && (t
.charAt(c
+ 1) == '(')) {
477 while (c
< t
.length() && nest
!= 0) {
478 if (t
.charAt(c
) == '<') nest
++
479 if (t
.charAt(c
) == '>') nest
--
482 return t
.substring(c
)
489 /* -----------------------------------------------------------------------------
492 * Splits a type into it's component parts and returns a list of string.
493 * ----------------------------------------------------------------------------- */
495 private static List
SwigType_split(String t
) {
500 while (c
< t
.length()) {
501 len
= element_size(t
.substring(c
))
502 String item
= t
.substring(c
,c
+ len
)
505 if (c
< t
.length() && t
.charAt(c
) == '.') c
++
510 /* -----------------------------------------------------------------------------
511 * static element_size()
513 * This utility function finds the size of a single type element in a type string.
514 * Type elements are always delimited by periods, but may be nested with
515 * parentheses. A nested element is always handled as a single item.
517 * Returns the integer size of the element (which can be used to extract a
518 * substring, to chop the element off, or for other purposes).
519 * ----------------------------------------------------------------------------- */
521 private static int element_size(String s
) {
524 while (c
< s
.length()) {
525 if (s
.charAt(c
) == '.') {
528 } else if (s
.charAt(c
) == '(') {
531 while (c
< s
.length()) {
532 if (s
.charAt(c
) == '(') nparen
++
533 if (s
.charAt(c
) == ')') {
535 if (nparen
== 0) break
540 if (c
< s
.length()) c
++
545 /* -----------------------------------------------------------------------------
548 * Pop one type element off the type.
549 * Example: t in: q(const).p.Integer
552 * ----------------------------------------------------------------------------- */
554 private static Tuple
SwigType_pop(String t
) {
561 int sz
= element_size(t
.substring(c
))
562 return [ t
.substring(c
,c
+ sz
), t
.substring(c
+sz
) ]
565 private static boolean SwigType_issimple(String t
) {
568 while (c
< t
.length()) {
569 if (t
.charAt(c
) == '<') {
572 while (c
< t
.length() && nest
!= 0) {
573 if (t
.charAt(c
) == '<') nest
++
574 if (t
.charAt(c
) == '>') nest
--
579 if (t
.charAt(c
) == '.')
587 public static void main(String
[] args
)
591 <entry basetype="std::vector<(p.XBMCAddon::xbmcgui::ListItem)>" type="ListItemList" namespace="XBMCAddon::xbmcgui::"/>
594 Node xml
= new XmlParser().parseText(xmlText
)
596 SwigTypeParser
.appendTypeTable(xml
)
598 // testPrint('f(int,int,int)','foo')
599 // testPrint('p.a(10).p.f(int,p.f(int).int)','foo')
600 // testPrint('p.q(const).char','foo')
601 // testPrint('f(r.q(const).String,p.q(const).XBMCAddon::xbmcgui::ListItem,bool)','foo')
602 // testPrint('r.q(const).String','foo')
603 // testPrint('q(const).p.q(const).char','foo')
604 //testPrint('std::vector<(p.String)>','foo')
605 // testPrint('r.q(const).String')
606 //System.out.println "${convertTypeToLType('bool')}"
607 //testPrint('p.q(const).XBMCAddon::xbmcgui::ListItemList')
608 //testPrint('p.q(const).XBMCAddon::xbmcgui::ListItemList')
609 //testPrint(SwigTypeParser.SwigType_makepointer('r.q(const).std::map<(String,String)>'), 'foo')
610 testPrint(SwigTypeParser
.SwigType_makepointer('q(const).p.q(const).char'),'bfoo')
613 private static void testPrint(String ty
, String id
= 'foo')
615 println SwigTypeParser
.SwigType_ltype(ty
) + "|" + SwigTypeParser
.SwigType_str(SwigTypeParser
.SwigType_ltype(ty
),id
) + ' ' + " = " + ty
+ '|' + SwigTypeParser
.SwigType_str(ty
,id
)