generator: expressions can generate pre-code

This patch provides a mechanism for generating
preparatory code for expressions.

This is e.g. necessary when an expression needs computations
which cannot be done in a C-Expression, like for-loops.

This will be used for sumof expressions but may be useful
elsewhere.

Note: Patch 2 of this series has been removed during the review process.

V2: adapt to changes in previous patches

V3: some style and formatting changes according to suggestions from Ran Benita.

Signed-off-by: Christian Linhart <chris@DemoRecorder.com>
Reviewed-by: Ran Benita <ran234@gmail.com>

Message-ID: <54562769.3090405@DemoRecorder.com>
Patch-Thread-Subject: [Xcb] [PATCHSET] ListInputDevices revision 2
Patch-Set: ListInputDevices
Patch-Number: libxcb 3/9
Patch-Version: V3
This commit is contained in:
Christian Linhart 2014-11-02 13:45:29 +01:00 committed by Christian Linhart
parent 265d38882c
commit fda1fb4ed4

View File

@ -58,6 +58,107 @@ def _hc(fmt, *args):
_h(fmt, *args)
_c(fmt, *args)
def _c_wr_stringlist(indent, strlist):
'''
Writes the given list of strings to the source file.
Each line is prepended by the indent string
'''
for str in strlist:
_c("%s%s", indent, str)
class PreCode(object):
'''
For pre-code generated by expression generation
(for example, the for-loop of a sumof)
This has to account for recursiveness of the expression
generation, i.e., there may be pre-code for pre-code.
Therefore this is implemented as a stack of lists of lines.
If redirection is switched on, then all output is collected in
self.redirect_code and self.redirect_tempvars instead of
being sent to the output via _h und _c.
'''
def __init__(self):
self.nesting_level = 0
self.tempvars = []
self.codelines = []
self.redirect_code = None
self.redirect_tempvars = None
self.indent_str = ' '
self.indent_stack = []
self.tempvar_num = 0
# start and end of pre-code blocks
def start(self):
self.nesting_level += 1
def end(self):
self.nesting_level -= 1
if self.nesting_level == 0:
# lowest pre-code level is finished -> output to source
if self.redirect_tempvars is None:
_c_wr_stringlist('', self.tempvars)
self.tempvars = []
else:
self.redirect_tempvars.extend(self.tempvars)
self.tempvars = []
if self.redirect_code == None:
_c_wr_stringlist('', self.codelines)
self.codelines = []
else:
self.redirect_code.extend(self.codelines)
self.codelines = []
def output_tempvars(self):
if self.redirect_code == None:
_c_wr_stringlist('', self.tempvars)
self.tempvars = []
# output to precode
def code(self, fmt, *args):
self.codelines.append(self.indent_str + fmt % args)
def tempvar(self, fmt, *args):
self.tempvars.append(' ' + (fmt % args))
# get a unique name for a temporary variable
def get_tempvarname(self):
self.tempvar_num += 1
return "xcb_pre_tmp_%d" % self.tempvar_num
# indentation
def push_indent(self, indentstr):
self.indent_stack.append(self.indent_str)
self.indent_str = indentstr
def push_addindent(self, indent_add_str):
self.push_indent(self.indent_str + indent_add_str)
def indent(self):
self.push_addindent(' ')
def pop_indent(self):
self.indent_str = self.indent_stack.pop()
# redirection to lists
def redirect_start(self, redirect_code, redirect_tempvars=None):
self.redirect_code = redirect_code
self.redirect_tempvars = redirect_tempvars
if redirect_tempvars is not None:
self.tempvar_num = 0
def redirect_end(self):
self.redirect_code = None
self.redirect_tempvars = None
# global PreCode handler
_c_pre = PreCode()
# XXX See if this level thing is really necessary.
def _h_setlevel(idx):
'''
@ -1024,6 +1125,8 @@ def _c_serialize_helper_fields(context, self,
need_padding = False
prev_field_was_variable = False
_c_pre.push_indent(space + ' ')
for field in self.fields:
if not field.visible:
if not ((field.wire and not field.auto) or 'unserialize' == context):
@ -1112,6 +1215,8 @@ def _c_serialize_helper_fields(context, self,
if self.c_var_followed_by_fixed_fields:
need_padding = False
_c_pre.pop_indent()
return count
# _c_serialize_helper_fields()
@ -1210,6 +1315,8 @@ def _c_serialize(context, self):
temp_vars = []
prefix = []
_c_pre.redirect_start(code_lines, temp_vars)
if 'serialize' == context:
if not self.is_switch and not self.c_var_followed_by_fixed_fields:
_c(' %s *xcb_out = *_buffer;', self.c_type)
@ -1255,11 +1362,13 @@ def _c_serialize(context, self):
_c(' %s _aux;', self.c_type)
_c(' return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
_c('}')
_c_pre.redirect_end()
return
elif self.c_var_followed_by_fixed_fields:
# special case: call _unserialize()
_c(' return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
_c('}')
_c_pre.redirect_end()
return
else:
_c(' char *xcb_tmp = (char *)_buffer;')
@ -1295,6 +1404,8 @@ def _c_serialize(context, self):
_c(' unsigned int xcb_pad = 0;')
_c(' unsigned int xcb_align_to = 0;')
_c_pre.redirect_end()
_c('')
for t in temp_vars:
_c(t)
@ -1684,12 +1795,11 @@ def _c_accessors_list(self, field):
spacing = ' '*(len(field.c_length_name)+2)
_h('%sconst %s *S /**< */);', spacing, S_obj.c_type)
_c('%sconst %s *S /**< */)', spacing, S_obj.c_type)
length = _c_accessor_get_expr(field.type.expr, fields)
else:
_h('%s (const %s *R /**< */);', field.c_length_name, c_type)
_c('%s (const %s *R /**< */)', field.c_length_name, c_type)
length = _c_accessor_get_expr(field.type.expr, fields)
_c('{')
length = _c_accessor_get_expr(field.type.expr, fields)
_c(' return %s;', length)
_c('}')
@ -1739,10 +1849,15 @@ def _c_accessors_list(self, field):
_c('{')
_c(' %s i;', field.c_iterator_type)
_c_pre.start()
length_expr_str = _c_accessor_get_expr(field.type.expr, fields)
if switch_obj is not None:
_c_pre.end()
_c(' i.data = %s;', fields[field.c_field_name][0])
_c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
_c(' i.rem = %s;', length_expr_str)
elif field.prev_varsized_field == None:
_c_pre.end()
_c(' i.data = (%s *) (R + 1);', field.c_field_type)
else:
(prev_varsized_field, align_pad) = get_align_pad(field)
@ -1753,11 +1868,12 @@ def _c_accessors_list(self, field):
_c(' xcb_generic_iterator_t prev = %s;',
_c_iterator_get_end(prev_varsized_field, 'R'))
_c_pre.end()
_c(' i.data = (%s *) ((char *) prev.data + %s);',
field.c_field_type, align_pad)
if switch_obj is None:
_c(' i.rem = %s;', _c_accessor_get_expr(field.type.expr, fields))
_c(' i.rem = %s;', length_expr_str)
_c(' i.index = (char *) i.data - (char *) %s;', 'R' if switch_obj is None else 'S' )
_c(' return i;')
_c('}')