2 # (C) Copyright IBM Corporation 2004, 2005
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # on the rights to use, copy, modify, merge, publish, distribute, sub
9 # license, and/or sell copies of the Software, and to permit persons to whom
10 # the Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 # Ian Romanick <idr@us.ibm.com>
27 from __future__
import print_function
29 from collections
import OrderedDict
30 from decimal
import Decimal
31 import xml
.etree
.ElementTree
as ET
38 def parse_GL_API( file_name
, factory
= None ):
41 factory
= gl_item_factory()
43 api
= factory
.create_api()
44 api
.parse_file( file_name
)
46 # After the XML has been processed, we need to go back and assign
47 # dispatch offsets to the functions that request that their offsets
48 # be assigned by the scripts. Typically this means all functions
49 # that are not part of the ABI.
51 for func
in api
.functionIterateByCategory():
52 if func
.assign_offset
and func
.offset
< 0:
53 func
.offset
= api
.next_offset
;
59 def is_attr_true( element
, name
, default
= "false" ):
60 """Read a name value from an element's attributes.
62 The value read from the attribute list must be either 'true' or
63 'false'. If the value is 'false', zero will be returned. If the
64 value is 'true', non-zero will be returned. An exception will be
65 raised for any other value."""
67 value
= element
.get( name
, default
)
70 elif value
== "false":
73 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value
, name
))
76 class gl_print_base(object):
77 """Base class of all API pretty-printers.
79 In the model-view-controller pattern, this is the view. Any derived
80 class will want to over-ride the printBody, printRealHader, and
81 printRealFooter methods. Some derived classes may want to over-ride
82 printHeader and printFooter, or even Print (though this is unlikely).
86 # Name of the script that is generating the output file.
87 # Every derived class should set this to the name of its
93 # License on the *generated* source file. This may differ
94 # from the license on the script that is generating the file.
95 # Every derived class should set this to some reasonable
98 # See license.py for an example of a reasonable value.
100 self
.license
= "The license for this file is unspecified."
103 # The header_tag is the name of the C preprocessor define
104 # used to prevent multiple inclusion. Typically only
105 # generated C header files need this to be set. Setting it
106 # causes code to be generated automatically in printHeader
109 self
.header_tag
= None
112 # List of file-private defines that must be undefined at the
113 # end of the file. This can be used in header files to define
114 # names for use in the file, then undefine them at the end of
121 def Print(self
, api
):
128 def printHeader(self
):
129 """Print the header associated with all files and call the printRealHeader method."""
131 print('/* DO NOT EDIT - This file generated automatically by %s script */' \
135 print((' * ' + self
.license
.replace('\n', '\n * ')).replace(' \n', '\n'))
139 print('#if !defined( %s )' % (self
.header_tag
))
140 print('# define %s' % (self
.header_tag
))
142 self
.printRealHeader();
146 def printFooter(self
):
147 """Print the header associated with all files and call the printRealFooter method."""
149 self
.printRealFooter()
153 for u
in self
.undef_list
:
154 print("# undef %s" % (u
))
158 print('#endif /* !defined( %s ) */' % (self
.header_tag
))
161 def printRealHeader(self
):
162 """Print the "real" header for the created file.
164 In the base class, this function is empty. All derived
165 classes should over-ride this function."""
169 def printRealFooter(self
):
170 """Print the "real" footer for the created file.
172 In the base class, this function is empty. All derived
173 classes should over-ride this function."""
178 """Conditionally define `PURE' function attribute.
180 Conditionally defines a preprocessor macro `PURE' that wraps
181 GCC's `pure' function attribute. The conditional code can be
182 easilly adapted to other compilers that support a similar
185 The name is also added to the file's undef_list.
187 self
.undef_list
.append("PURE")
188 print("""# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
189 # define PURE __attribute__((pure))
196 def printFastcall(self
):
197 """Conditionally define `FASTCALL' function attribute.
199 Conditionally defines a preprocessor macro `FASTCALL' that
200 wraps GCC's `fastcall' function attribute. The conditional
201 code can be easilly adapted to other compilers that support a
204 The name is also added to the file's undef_list.
207 self
.undef_list
.append("FASTCALL")
208 print("""# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
209 # define FASTCALL __attribute__((fastcall))
216 def printVisibility(self
, S
, s
):
217 """Conditionally define visibility function attribute.
219 Conditionally defines a preprocessor macro name S that wraps
220 GCC's visibility function attribute. The visibility used is
221 the parameter s. The conditional code can be easilly adapted
222 to other compilers that support a similar feature.
224 The name is also added to the file's undef_list.
227 self
.undef_list
.append(S
)
228 print("""# if defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
229 # define %s __attribute__((visibility("%s")))
232 # endif""" % (S
, s
, S
))
236 def printNoinline(self
):
237 """Conditionally define `NOINLINE' function attribute.
239 Conditionally defines a preprocessor macro `NOINLINE' that
240 wraps GCC's `noinline' function attribute. The conditional
241 code can be easilly adapted to other compilers that support a
244 The name is also added to the file's undef_list.
247 self
.undef_list
.append("NOINLINE")
248 print("""# if defined(__GNUC__)
249 # define NOINLINE __attribute__((noinline))
256 def real_function_name(element
):
257 name
= element
.get( "name" )
258 alias
= element
.get( "alias" )
266 def real_category_name(c
):
267 if re
.compile("[1-9][0-9]*[.][0-9]+").match(c
):
268 return "GL_VERSION_" + c
.replace(".", "_")
273 def classify_category(name
, number
):
274 """Based on the category name and number, select a numerical class for it.
276 Categories are divided into four classes numbered 0 through 3. The
279 0. Core GL versions, sorted by version number.
280 1. ARB extensions, sorted by extension number.
281 2. Non-ARB extensions, sorted by extension number.
282 3. Un-numbered extensions, sorted by extension name.
286 core_version
= float(name
)
290 if core_version
> 0.0:
293 elif name
.startswith("GL_ARB_") or name
.startswith("GLX_ARB_") or name
.startswith("WGL_ARB_"):
305 return [cat_type
, key
]
308 def create_parameter_string(parameters
, include_names
):
309 """Create a parameter string from a list of gl_parameters."""
317 list.append( p
.string() )
319 list.append( p
.type_string() )
321 if len(list) == 0: list = ["void"]
323 return ", ".join(list)
326 class gl_item(object):
327 def __init__(self
, element
, context
, category
):
328 self
.context
= context
329 self
.name
= element
.get( "name" )
330 self
.category
= real_category_name( category
)
335 class gl_type( gl_item
):
336 def __init__(self
, element
, context
, category
):
337 gl_item
.__init
__(self
, element
, context
, category
)
338 self
.size
= int( element
.get( "size" ), 0 )
340 te
= typeexpr
.type_expression( None )
341 tn
= typeexpr
.type_node()
342 tn
.size
= int( element
.get( "size" ), 0 )
343 tn
.integer
= not is_attr_true( element
, "float" )
344 tn
.unsigned
= is_attr_true( element
, "unsigned" )
345 tn
.pointer
= is_attr_true( element
, "pointer" )
346 tn
.name
= "GL" + self
.name
347 te
.set_base_type_node( tn
)
353 def get_type_expression(self
):
354 return self
.type_expr
357 class gl_enum( gl_item
):
358 def __init__(self
, element
, context
, category
):
359 gl_item
.__init
__(self
, element
, context
, category
)
360 self
.value
= int( element
.get( "value" ), 0 )
362 temp
= element
.get( "count" )
363 if not temp
or temp
== "?":
364 self
.default_count
= -1
369 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp
, self
.name
, n
))
371 self
.default_count
= c
377 """Calculate a 'priority' for this enum name.
379 When an enum is looked up by number, there may be many
380 possible names, but only one is the 'prefered' name. The
381 priority is used to select which name is the 'best'.
383 Highest precedence is given to core GL name. ARB extension
384 names have the next highest, followed by EXT extension names.
385 Vendor extension names are the lowest.
388 if self
.name
.endswith( "_BIT" ):
393 if self
.category
.startswith( "GL_VERSION_" ):
395 elif self
.category
.startswith( "GL_ARB_" ):
397 elif self
.category
.startswith( "GL_EXT_" ):
402 return priority
+ bias
406 class gl_parameter(object):
407 def __init__(self
, element
, context
):
408 self
.name
= element
.get( "name" )
410 ts
= element
.get( "type" )
411 self
.type_expr
= typeexpr
.type_expression( ts
, context
)
413 temp
= element
.get( "variable_param" )
415 self
.count_parameter_list
= temp
.split( ' ' )
417 self
.count_parameter_list
= []
419 # The count tag can be either a numeric string or the name of
420 # a variable. If it is the name of a variable, the int(c)
421 # statement will throw an exception, and the except block will
424 c
= element
.get( "count" )
434 self
.marshal_count
= element
.get("marshal_count")
435 self
.count_scale
= int(element
.get( "count_scale", "1" ))
437 elements
= (count
* self
.count_scale
)
441 #if ts == "GLdouble":
442 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
443 # print '/* # elements = %u */' % (elements)
444 self
.type_expr
.set_elements( elements
)
445 #if ts == "GLdouble":
446 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
448 self
.is_client_only
= is_attr_true( element
, 'client_only' )
449 self
.is_counter
= is_attr_true( element
, 'counter' )
450 self
.is_output
= is_attr_true( element
, 'output' )
453 # Pixel data has special parameters.
455 self
.width
= element
.get('img_width')
456 self
.height
= element
.get('img_height')
457 self
.depth
= element
.get('img_depth')
458 self
.extent
= element
.get('img_extent')
460 self
.img_xoff
= element
.get('img_xoff')
461 self
.img_yoff
= element
.get('img_yoff')
462 self
.img_zoff
= element
.get('img_zoff')
463 self
.img_woff
= element
.get('img_woff')
465 self
.img_format
= element
.get('img_format')
466 self
.img_type
= element
.get('img_type')
467 self
.img_target
= element
.get('img_target')
469 self
.img_pad_dimensions
= is_attr_true( element
, 'img_pad_dimensions' )
470 self
.img_null_flag
= is_attr_true( element
, 'img_null_flag' )
471 self
.img_send_null
= is_attr_true( element
, 'img_send_null' )
473 self
.is_padding
= is_attr_true( element
, 'padding' )
477 def compatible(self
, other
):
482 return self
.is_pointer()
485 def is_pointer(self
):
486 return self
.type_expr
.is_pointer()
496 def is_variable_length(self
):
497 return len(self
.count_parameter_list
) or self
.counter
or self
.marshal_count
501 count
= self
.type_expr
.get_element_count()
503 if (self
.size() / count
) == 8:
513 return self
.type_expr
.original_string
+ " " + self
.name
516 def type_string(self
):
517 return self
.type_expr
.original_string
520 def get_base_type_string(self
):
521 return self
.type_expr
.get_base_name()
524 def get_dimensions(self
):
526 return [ 0, "0", "0", "0", "0" ]
546 return [ dim
, w
, h
, d
, e
]
549 def get_stack_size(self
):
550 return self
.type_expr
.get_stack_size()
557 return self
.type_expr
.get_element_size()
560 def get_element_count(self
):
561 c
= self
.type_expr
.get_element_count()
568 def size_string(self
, use_parens
= 1, marshal
= 0):
571 count
= self
.get_element_count()
573 base_size_str
= "%d * " % count
575 base_size_str
+= "sizeof(%s)" % ( self
.get_base_type_string() )
577 if self
.counter
or self
.count_parameter_list
or (self
.marshal_count
and marshal
):
578 list = [ "compsize" ]
580 if self
.marshal_count
and marshal
:
581 list = [ self
.marshal_count
]
582 elif self
.counter
and self
.count_parameter_list
:
583 list.append( self
.counter
)
585 list = [ self
.counter
]
588 list.append( base_size_str
)
590 if len(list) > 1 and use_parens
:
591 return "safe_mul(%s)" % ", ".join(list)
593 return " * ".join(list)
595 elif self
.is_image():
601 def format_string(self
):
602 if self
.type_expr
.original_string
== "GLenum":
605 return self
.type_expr
.format_string()
608 class gl_function( gl_item
):
609 def __init__(self
, element
, context
):
610 self
.context
= context
613 self
.entry_points
= []
614 self
.return_type
= "void"
619 self
.exec_flavor
= 'mesa'
621 self
.deprecated
= None
622 self
.has_no_error_variant
= False
624 # self.api_map[api] is a decimal value indicating the earliest
625 # version of the given API in which ANY alias for the function
626 # exists. The map only lists APIs which contain the function
627 # in at least one version. For example, for the ClipPlanex
628 # function, self.api_map == { 'es1':
632 self
.assign_offset
= False
634 self
.static_entry_points
= []
636 # Track the parameter string (for the function prototype)
637 # for each entry-point. This is done because some functions
638 # change their prototype slightly when promoted from extension
639 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
640 # are good examples of this. Scripts that need to generate
641 # code for these differing aliases need to real prototype
642 # for each entry-point. Otherwise, they may generate code
643 # that won't compile.
645 self
.entry_point_parameters
= {}
647 self
.process_element( element
)
652 def process_element(self
, element
):
653 name
= element
.get( "name" )
654 alias
= element
.get( "alias" )
656 if name
in static_data
.functions
:
657 self
.static_entry_points
.append(name
)
659 self
.entry_points
.append( name
)
661 for api
in ('es1', 'es2'):
662 version_str
= element
.get(api
, 'none')
663 assert version_str
is not None
664 if version_str
!= 'none':
665 version_decimal
= Decimal(version_str
)
666 if api
not in self
.api_map
or \
667 version_decimal
< self
.api_map
[api
]:
668 self
.api_map
[api
] = version_decimal
670 exec_flavor
= element
.get('exec')
672 self
.exec_flavor
= exec_flavor
674 deprecated
= element
.get('deprecated', 'none')
675 if deprecated
!= 'none':
676 self
.deprecated
= Decimal(deprecated
)
678 if not is_attr_true(element
, 'desktop', 'true'):
681 if self
.has_no_error_variant
or is_attr_true(element
, 'no_error'):
682 self
.has_no_error_variant
= True
684 self
.has_no_error_variant
= False
691 # Only try to set the offset when a non-alias entry-point
692 # is being processed.
694 if name
in static_data
.offsets
and static_data
.offsets
[name
] <= static_data
.MAX_OFFSETS
:
695 self
.offset
= static_data
.offsets
[name
]
696 elif name
in static_data
.offsets
and static_data
.offsets
[name
] > static_data
.MAX_OFFSETS
:
697 self
.offset
= static_data
.offsets
[name
]
698 self
.assign_offset
= True
700 if self
.exec_flavor
!= "skip":
701 raise RuntimeError("Entry-point %s is missing offset in static_data.py. Add one at the bottom of the list." % (name
))
702 self
.assign_offset
= self
.exec_flavor
!= "skip" or name
in static_data
.unused_functions
705 self
.name
= true_name
706 elif self
.name
!= true_name
:
707 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self
.name
, true_name
))
710 # There are two possible cases. The first time an entry-point
711 # with data is seen, self.initialized will be 0. On that
712 # pass, we just fill in the data. The next time an
713 # entry-point with data is seen, self.initialized will be 1.
714 # On that pass we have to make that the new values match the
715 # valuse from the previous entry-point.
719 for child
in element
.getchildren():
720 if child
.tag
== "return":
721 return_type
= child
.get( "type", "void" )
722 elif child
.tag
== "param":
723 param
= self
.context
.factory
.create_parameter(child
, self
.context
)
724 parameters
.append( param
)
728 if self
.return_type
!= return_type
:
729 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name
, self
.return_type
, return_type
))
731 if len(parameters
) != len(self
.parameters
):
732 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name
, len(self
.parameters
), len(parameters
)))
734 for j
in range(0, len(parameters
)):
736 p2
= self
.parameters
[j
]
737 if not p1
.compatible( p2
):
738 raise RuntimeError( 'Parameter type mismatch in %s. "%s" was "%s", now "%s".' % (name
, p2
.name
, p2
.type_expr
.original_string
, p1
.type_expr
.original_string
))
741 if true_name
== name
or not self
.initialized
:
742 self
.return_type
= return_type
743 self
.parameters
= parameters
745 for param
in self
.parameters
:
747 self
.images
.append( param
)
749 if element
.getchildren():
751 self
.entry_point_parameters
[name
] = parameters
753 self
.entry_point_parameters
[name
] = []
757 def filter_entry_points(self
, entry_point_list
):
758 """Filter out entry points not in entry_point_list."""
759 if not self
.initialized
:
760 raise RuntimeError('%s is not initialized yet' % self
.name
)
763 for ent
in self
.entry_points
:
764 if ent
not in entry_point_list
:
765 if ent
in self
.static_entry_points
:
766 self
.static_entry_points
.remove(ent
)
767 self
.entry_point_parameters
.pop(ent
)
769 entry_points
.append(ent
)
772 raise RuntimeError('%s has no entry point after filtering' % self
.name
)
774 self
.entry_points
= entry_points
775 if self
.name
not in entry_points
:
776 # use the first remaining entry point
777 self
.name
= entry_points
[0]
778 self
.parameters
= self
.entry_point_parameters
[entry_points
[0]]
780 def get_images(self
):
781 """Return potentially empty list of input images."""
785 def parameterIterator(self
, name
= None):
787 return iter(self
.entry_point_parameters
[name
]);
789 return iter(self
.parameters
);
792 def get_parameter_string(self
, entrypoint
= None):
794 params
= self
.entry_point_parameters
[ entrypoint
]
796 params
= self
.parameters
798 return create_parameter_string( params
, 1 )
800 def get_called_parameter_string(self
):
804 for p
in self
.parameterIterator():
807 p_string
= p_string
+ comma
+ p
.name
814 return (self
.offset
>= 0 and not self
.assign_offset
)
816 def is_static_entry_point(self
, name
):
817 return name
in self
.static_entry_points
819 def dispatch_name(self
):
820 if self
.name
in self
.static_entry_points
:
823 return "_dispatch_stub_%u" % (self
.offset
)
825 def static_name(self
, name
):
826 if name
in self
.static_entry_points
:
829 return "_dispatch_stub_%u" % (self
.offset
)
831 class gl_item_factory(object):
832 """Factory to create objects derived from gl_item."""
834 def create_function(self
, element
, context
):
835 return gl_function(element
, context
)
837 def create_type(self
, element
, context
, category
):
838 return gl_type(element
, context
, category
)
840 def create_enum(self
, element
, context
, category
):
841 return gl_enum(element
, context
, category
)
843 def create_parameter(self
, element
, context
):
844 return gl_parameter(element
, context
)
846 def create_api(self
):
850 class gl_api(object):
851 def __init__(self
, factory
):
852 self
.functions_by_name
= OrderedDict()
853 self
.enums_by_name
= {}
854 self
.types_by_name
= {}
856 self
.category_dict
= {}
857 self
.categories
= [{}, {}, {}, {}]
859 self
.factory
= factory
863 typeexpr
.create_initial_types()
866 def parse_file(self
, file_name
):
867 doc
= ET
.parse( file_name
)
868 self
.process_element(file_name
, doc
)
871 def process_element(self
, file_name
, doc
):
872 element
= doc
.getroot()
873 if element
.tag
== "OpenGLAPI":
874 self
.process_OpenGLAPI(file_name
, element
)
878 def process_OpenGLAPI(self
, file_name
, element
):
879 for child
in element
.getchildren():
880 if child
.tag
== "category":
881 self
.process_category( child
)
882 elif child
.tag
== "OpenGLAPI":
883 self
.process_OpenGLAPI( file_name
, child
)
884 elif child
.tag
== '{http://www.w3.org/2001/XInclude}include':
885 href
= child
.get('href')
886 href
= os
.path
.join(os
.path
.dirname(file_name
), href
)
887 self
.parse_file(href
)
892 def process_category(self
, cat
):
893 cat_name
= cat
.get( "name" )
894 cat_number
= cat
.get( "number" )
896 [cat_type
, key
] = classify_category(cat_name
, cat_number
)
897 self
.categories
[cat_type
][key
] = [cat_name
, cat_number
]
899 for child
in cat
.getchildren():
900 if child
.tag
== "function":
901 func_name
= real_function_name( child
)
903 temp_name
= child
.get( "name" )
904 self
.category_dict
[ temp_name
] = [cat_name
, cat_number
]
906 if func_name
in self
.functions_by_name
:
907 func
= self
.functions_by_name
[ func_name
]
908 func
.process_element( child
)
910 func
= self
.factory
.create_function( child
, self
)
911 self
.functions_by_name
[ func_name
] = func
913 if func
.offset
>= self
.next_offset
:
914 self
.next_offset
= func
.offset
+ 1
917 elif child
.tag
== "enum":
918 enum
= self
.factory
.create_enum( child
, self
, cat_name
)
919 self
.enums_by_name
[ enum
.name
] = enum
920 elif child
.tag
== "type":
921 t
= self
.factory
.create_type( child
, self
, cat_name
)
922 self
.types_by_name
[ "GL" + t
.name
] = t
927 def functionIterateByCategory(self
, cat
= None):
928 """Iterate over functions by category.
930 If cat is None, all known functions are iterated in category
931 order. See classify_category for details of the ordering.
932 Within a category, functions are sorted by name. If cat is
933 not None, then only functions in that category are iterated.
935 lists
= [{}, {}, {}, {}]
937 for func
in self
.functionIterateAll():
938 [cat_name
, cat_number
] = self
.category_dict
[func
.name
]
940 if (cat
== None) or (cat
== cat_name
):
941 [func_cat_type
, key
] = classify_category(cat_name
, cat_number
)
943 if key
not in lists
[func_cat_type
]:
944 lists
[func_cat_type
][key
] = {}
946 lists
[func_cat_type
][key
][func
.name
] = func
950 for func_cat_type
in range(0,4):
951 keys
= sorted(lists
[func_cat_type
].keys())
954 names
= sorted(lists
[func_cat_type
][key
].keys())
957 functions
.append(lists
[func_cat_type
][key
][name
])
959 return iter(functions
)
962 def functionIterateByOffset(self
):
964 for func
in self
.functions_by_name
.values():
965 if func
.offset
> max_offset
:
966 max_offset
= func
.offset
969 temp
= [None for i
in range(0, max_offset
+ 1)]
970 for func
in self
.functions_by_name
.values():
971 if func
.offset
!= -1:
972 temp
[ func
.offset
] = func
976 for i
in range(0, max_offset
+ 1):
983 def functionIterateAll(self
):
984 return self
.functions_by_name
.values()
987 def enumIterateByName(self
):
988 keys
= sorted(self
.enums_by_name
.keys())
992 list.append( self
.enums_by_name
[ enum
] )
997 def categoryIterate(self
):
998 """Iterate over categories.
1000 Iterate over all known categories in the order specified by
1001 classify_category. Each iterated value is a tuple of the
1002 name and number (which may be None) of the category.
1006 for cat_type
in range(0,4):
1007 keys
= sorted(self
.categories
[cat_type
].keys())
1010 list.append(self
.categories
[cat_type
][key
])
1015 def get_category_for_name( self
, name
):
1016 if name
in self
.category_dict
:
1017 return self
.category_dict
[name
]
1019 return ["<unknown category>", None]
1022 def typeIterate(self
):
1023 return self
.types_by_name
.values()
1026 def find_type( self
, type_name
):
1027 if type_name
in self
.types_by_name
:
1028 return self
.types_by_name
[ type_name
].type_expr
1030 print("Unable to find base type matching \"%s\"." % (type_name
))