1# vim: set ts=4 sws=4 sw=4:
2
3import sys # stderr
4
5_templates = {}
6
7_templates['initializer'] = \
8'''\
9typedef typename value_type<%s, ! std::is_pointer<%s>::value>::type
10          vector_type;
11std::vector<vector_type> %s =
12  { value_iterator<%s>(%s), value_iterator<%s>(%s) };
13'''
14
15def _initializer(iter_type, c_name, iter_begin, iter_end):
16    return _templates['initializer'] % \
17            ( iter_type
18            , iter_type
19            , c_name
20            , iter_type
21            , iter_begin
22            , iter_type
23            , iter_end
24            )
25
26class ParameterList(object):
27    def __init__(self):
28        self.want_wrap = False
29        self.has_defaults = False
30        self.parameter = []
31        self.wrap_calls = []
32        self.wrap_protos = []
33        self.iter_calls = []
34        self.iter_2nd_lvl_calls = []
35        self.iter_protos = []
36        self.templates = []
37        self.iterator_templates = []
38        self.initializer = []
39
40    def add(self, param):
41        self.has_defaults = param.default != None
42        self.parameter.append(param)
43
44    def comma(self):
45        return "" if len(self.parameter) == 0 else ", "
46
47    def is_reordered(self):
48        tmp = sorted(self.parameter, key=lambda p: p.default or '')
49        return tmp != self.parameter
50
51    def calls(self, sort, params=None):
52        ps = self.parameter if params == None else params
53        if sort:
54            tmp = sorted(ps, key=lambda p: p.default or '')
55            ps = tmp
56        calls = [p.call() for p in ps]
57        return ", ".join(calls)
58
59    def protos(self, sort, defaults, params=None):
60        if defaults: sort = True
61        ps = self.parameter if params == None else params
62        if sort:
63            tmp = sorted(ps, key=lambda p: p.default or '')
64            ps = tmp
65        protos = [p.proto(defaults) for p in ps]
66        return ", ".join(protos)
67
68    def iterator_initializers(self):
69        return self.initializer
70
71    def make_wrapped(self):
72        self.wrap_calls = []
73        self.wrap_protos = []
74        self.iter_calls = []
75        self.iter_2nd_lvl_calls = []
76        self.iter_protos = []
77        self.initializer = []
78        self.templates = []
79        self.iterator_templates = []
80
81        lenfields = {}
82        # if a parameter is removed, take reduced parameter size into account
83        adjust = 0
84        for index, param in enumerate(self.parameter):
85            prev = index - adjust - 1
86
87            if param.field.type.is_list:
88                name = param.field.type.expr.lenfield_name
89                if name in lenfields:
90                    lenfields[name].append(param.c_name)
91                else:
92                    lenfields[name] = [ param.c_name ]
93
94                # sys.stderr.write("list: %s %s\n\n"
95                #         % ( param.field.type.expr.lenfield_type
96                #           , param.field.type.expr.lenfield_name
97                #           ))
98
99            # SetGamma: takes 1 size, but 3 value lists
100            # if param.field.type.is_list and prev >= 0:
101            if (param.is_const and param.is_pointer
102                    and prev >= 0
103                    and self.parameter[prev].c_name == param.c_name + "_len"):
104
105                adjust = adjust + 1
106                self.want_wrap = True
107                self.wrap_calls.pop(prev)
108                self.wrap_protos.pop(prev)
109                self.iter_calls.pop(prev)
110                self.iter_2nd_lvl_calls.pop(prev)
111                self.iter_protos.pop(prev)
112
113                prev_type = self.parameter[prev].c_type
114                if param.c_type == 'char':
115
116                    def append_proto_string(list):
117                        list.append(Parameter(None, \
118                            c_type='const std::string &',
119                            c_name=param.c_name))
120
121                    def append_call_string(list):
122                        list.append(Parameter(None, \
123                            c_name="static_cast<" + prev_type + ">(" \
124                            + param.c_name + '.length())'))
125
126                        list.append(Parameter(None, \
127                            c_name=param.c_name + '.c_str()'))
128
129                    append_proto_string(self.wrap_protos)
130                    append_proto_string(self.iter_protos)
131                    append_call_string(self.wrap_calls)
132                    append_call_string(self.iter_calls)
133                    append_call_string(self.iter_2nd_lvl_calls)
134
135                else:
136                    param_type = param.c_type
137                    if param_type == "void":
138                        param_type = "Type_" + str(index)
139                        self.templates.append(param_type)
140
141                    prev_type = self.parameter[prev].c_type
142
143                    ### std::vector
144                    self.wrap_protos.append(Parameter(None, \
145                        c_type='const std::vector<' + param_type + '> &',
146                        c_name=param.c_name))
147
148                    self.wrap_calls.append(Parameter(None, \
149                      c_name="static_cast<" + prev_type + ">(" \
150                      + param.c_name + '.size())'))
151
152                    self.wrap_calls.append(Parameter(None, \
153                        c_name=param.c_name + '.data()'))
154
155                    ### Iterator
156                    iter_type = param.c_name.capitalize() + "_Iterator"
157                    iter_begin = param.c_name + "_begin"
158                    iter_end = param.c_name + "_end"
159
160                    if len(self.templates) > 0:
161                        self.templates[-1] += " = typename " + iter_type + "::value_type"
162                    self.iterator_templates.append(iter_type)
163
164                    self.iter_protos.append(Parameter(None, \
165                            c_type=iter_type,
166                            c_name=iter_begin))
167
168                    self.iter_protos.append(Parameter(None, \
169                            c_type=iter_type,
170                            c_name=iter_end))
171
172                    self.iter_calls.append(Parameter(None, \
173                            c_name="static_cast<" + prev_type + ">(" \
174                            + param.c_name + '.size())'))
175
176                    self.iter_calls.append(Parameter(None, \
177                            c_name='const_cast<const vector_type *>(' \
178                            + param.c_name + '.data())'))
179
180                    self.iter_2nd_lvl_calls.append(Parameter(None, \
181                            c_name=iter_begin))
182
183                    self.iter_2nd_lvl_calls.append(Parameter(None, \
184                            c_name=iter_end))
185
186#                     vector_type = \
187#                     '''\
188# typename value_type<%s,
189#                   ! std::is_pointer<%s>::value
190#                  >::type\
191#                     ''' % (iter_type, iter_type)
192
193                    # self.initializer.append( \
194                    #         "std::vector<%s> %s = { value_iterator<%s>(%s), \
195                    #         value_iterator<%s>(%s) };" \
196                    #         % (vector_type, param.c_name,
197                    #             iter_type, iter_begin,
198                    #             iter_type, iter_end))
199
200                    self.initializer.append(
201                            _initializer(iter_type, param.c_name, iter_begin, iter_end))
202
203            else:
204                self.wrap_calls.append(param)
205                self.wrap_protos.append(param)
206                self.iter_calls.append(param)
207                self.iter_2nd_lvl_calls.append(param)
208                self.iter_protos.append(param)
209
210        # end: for index, param in enumerate(self.parameter):
211
212        for k, v in list(lenfields.items()):
213            if len(v) > 1:
214                sys.stderr.write("list: %s, %s\n" % (k, v))
215
216
217    def wrapped_calls(self, sort):
218        return self.calls(sort, params=self.wrap_calls)
219
220    def wrapped_protos(self, sort, defaults):
221        return self.protos(sort, defaults, params=self.wrap_protos)
222
223    def iterator_calls(self, sort):
224        return self.calls(sort, params=self.iter_calls)
225
226    def iterator_2nd_lvl_calls(self, sort):
227        return self.calls(sort, params=self.iter_2nd_lvl_calls)
228
229    def iterator_protos(self, sort, defaults):
230        return self.protos(sort, defaults, params=self.iter_protos)
231
232
233
234_default_parameter_values = \
235    { "xcb_timestamp_t" : "XCB_TIME_CURRENT_TIME" }
236
237class Parameter(object):
238    def __init__(self, field, c_type="", c_name="", verbose=False):
239        self.field = field
240        if field != None:
241            self.c_type = field.c_field_type
242            self.c_name = field.c_field_name
243            self.is_const = field.c_field_const_type == "const " + field.c_field_type
244            self.is_pointer = field.c_pointer != " "
245            # self.serialize = field.type.need_serialize
246            self.default = _default_parameter_values.get(self.c_type)
247            self.with_default = True
248            if verbose:
249                sys.stderr.write("c_type: %s; c_name: %s; default: %s\n" \
250                      % (self.c_type, self.c_name, self.default))
251
252        else:
253            self.c_type = c_type
254            self.c_name = c_name
255            self.is_const = False
256            self.is_pointer = False
257            # self.serialize = field.type.need_serialize
258            self.default = _default_parameter_values.get(self.c_type)
259            self.with_default = True
260
261    def call(self):
262        return self.c_name
263
264    def proto(self, with_default):
265        c_type = ("const " if self.is_const else "") \
266             + self.c_type \
267             + (" *" if self.is_pointer else "")
268        param = " = " + self.default if with_default and self.default != None else ""
269        return c_type + " " + self.c_name + param
270