- changed handling of anchestor types (may be more than one now)
[free-sw/xcb/proto] / xcbgen / state.py
1 '''
2 This module contains the namespace class and the singleton module class.
3 '''
4 from os.path import dirname, basename
5 from xml.etree.cElementTree import parse
6
7 import matcher
8 from error import *
9 from xtypes import *
10
11 import __main__
12
13 class Namespace(object):
14     '''
15     Contains the naming information for an extension.
16
17     Public fields:
18
19     header is the header attribute ("header file" name).
20     is_ext is true for extensions, false for xproto.
21     major_version and minor_version are extension version info.
22     ext_xname is the X extension name string.
23     ext_name is the XCB extension name prefix.
24     '''
25     def __init__(self, filename):
26         # Path info
27         self.path = filename
28         self.dir = dirname(filename)
29         self.file = basename(filename)
30
31         # Parse XML
32         self.root = parse(filename).getroot()
33         self.header = self.root.get('header')
34         self.ns = self.header + ':'
35         
36         # Get root element attributes
37         if self.root.get('extension-xname', False): 
38             self.is_ext = True
39             self.major_version = self.root.get('major-version')
40             self.minor_version = self.root.get('minor-version')
41             self.ext_xname = self.root.get('extension-xname')
42             self.ext_name = self.root.get('extension-name')
43             self.prefix = ('xcb', self.ext_name)
44         else:
45             self.is_ext = False
46             self.ext_name = ''
47             self.prefix = ('xcb',)
48
49
50 class Module(object):
51     '''
52     This is the grand, encompassing class that represents an entire XCB specification.
53     Only gets instantiated once, in the main() routine.
54
55     Don't need to worry about this much except to declare it and to get the namespace.
56
57     Public fields:
58     namespace contains the namespace info for the spec.
59     '''
60     open = __main__.output['open']
61     close = __main__.output['close']
62
63     def __init__(self, filename, output):
64         self.namespace = Namespace(filename)
65         self.output = output
66
67         self.imports = []
68         self.types = {}
69         self.events = {}
70         self.errors = {}
71         self.all = []
72
73         # Register some common types
74         self.add_type('CARD8', '', ('uint8_t',), tcard8)
75         self.add_type('CARD16', '', ('uint16_t',), tcard16)
76         self.add_type('CARD32', '', ('uint32_t',), tcard32)
77         self.add_type('INT8', '', ('int8_t',), tint8)
78         self.add_type('INT16', '', ('int16_t',), tint16)
79         self.add_type('INT32', '', ('int32_t',), tint32)
80         self.add_type('BYTE', '', ('uint8_t',), tcard8)
81         self.add_type('BOOL', '', ('uint8_t',), tcard8)
82         self.add_type('char', '', ('char',), tchar)
83         self.add_type('float', '', ('float',), tfloat)
84         self.add_type('double', '', ('double',), tdouble)
85         self.add_type('void', '', ('void',), tcard8)
86
87     # This goes out and parses the rest of the XML
88     def register(self):
89         matcher.execute(self, self.namespace)
90
91     # Recursively resolve all types
92     def resolve(self):
93         for (name, item) in self.all:
94             item.resolve(self)
95
96     # Call all the output methods
97     def generate(self):
98         self.open()
99
100         for (name, item) in self.all:
101             item.out(name)
102
103         self.close()
104
105     # Keeps track of what's been imported so far.
106     def add_import(self, name, namespace):
107         self.imports.append((name, namespace.header))
108
109     def has_import(self, name):
110         for (name_, header) in self.imports:
111             if name_ == name:
112                 return True
113         return False
114
115     # Keeps track of non-request/event/error datatypes
116     def add_type(self, id, ns, name, item):
117         key = ns + id
118         if key in self.types:
119             return
120         self.types[key] = (name, item)
121         if name[:-1] == self.namespace.prefix:
122             self.all.append((name, item))
123
124     def get_type_impl(self, id, idx):
125         key = id
126         if key in self.types:
127             return self.types[key][idx]
128
129         key = self.namespace.ns + id
130         if key in self.types:
131             return self.types[key][idx]
132
133         for key in self.types.keys():
134             if key.rpartition(':')[2] == id:
135                 return self.types[key][idx]
136
137         raise ResolveException('Type %s not found' % id)
138
139     def get_type(self, id):
140         return self.get_type_impl(id, 1)
141
142     def get_type_name(self, id):
143         return self.get_type_impl(id, 0)
144
145     # Keeps track of request datatypes
146     def add_request(self, id, name, item):
147         if name[:-1] == self.namespace.prefix:
148             self.all.append((name, item))
149
150     # Keeps track of event datatypes
151     def add_event(self, id, name, item):
152         self.events[id] = (name, item)
153         if name[:-1] == self.namespace.prefix:
154             self.all.append((name, item))
155
156     def get_event(self, id):
157         return self.events[id][1]
158
159     # Keeps track of error datatypes
160     def add_error(self, id, name, item):
161         self.errors[id] = (name, item)
162         if name[:-1] == self.namespace.prefix:
163             self.all.append((name, item))
164
165     def get_error(self, id):
166         return self.errors[id][1]