summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Linhart <chris@DemoRecorder.com>2014-11-02 13:45:29 +0100
committerChristian Linhart <chris@demorecorder.com>2014-11-03 11:23:16 +0100
commitfda1fb4ed47a705744677a0074d83464af7aa4eb (patch)
tree107660afd63356fb0651c70788ac1d5dca6bb8e5
parent265d38882cffce597367cc8bb2160b9e2482a80f (diff)
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
-rw-r--r--src/c_client.py124
1 files changed, 120 insertions, 4 deletions
diff --git a/src/c_client.py b/src/c_client.py
index ac5b6dc..789b49e 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -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('}')