[Xcb] [PATCH libxcb 3/6] generator: expressions can generate pre-code

Christian Linhart chris at demorecorder.com
Wed Sep 3 04:22:38 PDT 2014


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.
---
 src/c_client.py | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 115 insertions(+), 4 deletions(-)

diff --git a/src/c_client.py b/src/c_client.py
index 35c975f..193e050 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -54,14 +54,110 @@ def _c(fmt, *args):
 def _hc(fmt, *args):
     '''
     Writes the given line to both the header and source files.
     '''
     _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)
+
+
+#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.
+#
+class PreCode:
+    def __init__(self):
+        self.nestingLevel = 0
+        self.tempvars = []
+        self.codelines = []
+        self.redirect_code = None
+        self.redirect_tempvars = None
+        self.indent_str = '    '
+        self.indent_stack = []
+        self.tempvarNum = 0
+
+
+    #start and end of pre-code blocks
+    def start(self):
+        self.nestingLevel += 1
+
+    def end(self):
+        self.nestingLevel -= 1
+        if ( self.nestingLevel == 0 ):
+            #lowest pre-code level is finished -> output to source
+            if self.redirect_tempvars == 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.tempvarNum += 1
+        return "xcb_pre_tmp_%d" % self.tempvarNum
+
+    #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, redirectCode, redirectTempvars = None):
+        self.redirect_code = redirectCode
+        self.redirect_tempvars = redirectTempvars
+        if redirectTempvars != None:
+            self.tempvarNum = 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):
     '''
     Changes the array that header lines are written to.
     Supports writing different sections of the header file.
     '''
     global _hlevel
@@ -1006,14 +1102,16 @@ def _c_serialize_helper_fields_variable_size(context, self, field,
 def _c_serialize_helper_fields(context, self,
                                code_lines, temp_vars,
                                space, prefix, is_case_or_bitcase):
     count = 0
     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):
                 continue
 
         # switch/bitcase: fixed size fields must be considered explicitly
         if field.type.fixed_size():
@@ -1092,14 +1190,16 @@ def _c_serialize_helper_fields(context, self,
                   if field.c_field_type == 'void' or field.type.is_switch
                   else field.c_field_type))
 
         need_padding = True
         if self.c_var_followed_by_fixed_fields:
             need_padding = False
 
+    _c_pre.pop_indent()
+
     return count
 # _c_serialize_helper_fields()
 
 def _c_serialize_helper(context, complex_type,
                         code_lines, temp_vars,
                         space='', prefix=[]):
     # count tracks the number of fields to serialize
@@ -1191,14 +1291,16 @@ def _c_serialize(context, self):
     _c("%s)" % param_str[-1].rstrip(','))
     _c('{')
 
     code_lines = []
     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)
             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
             _c('    unsigned int xcb_align_to = 0;')
         else:
@@ -1240,19 +1342,21 @@ def _c_serialize(context, self):
     elif 'sizeof' == context:
         param_names = [p[2] for p in params]
         if self.is_switch:
             # switch: call _unpack()
             _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;')
             prefix = [('_aux', '->', self)]
             _c('    unsigned int xcb_padding_offset = 0;')
 
     count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
@@ -1279,14 +1383,16 @@ def _c_serialize(context, self):
                     _c('    %s *_aux = malloc(sizeof(%s));', self.c_type, self.c_type)
 
             _c('    unsigned int xcb_buffer_len = 0;')
             _c('    unsigned int xcb_block_len = 0;')
             _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)
     _c('')
     for l in code_lines:
         _c(l)
 
@@ -1668,20 +1774,19 @@ def _c_accessors_list(self, field):
     _hc('')
     _hc('int')
     if switch_obj is not None:
         _hc('%s (const %s *R  /**< */,', field.c_length_name, R_obj.c_type)
         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('}')
 
     if field.type.member.is_simple:
         _hc('')
         _hc('xcb_generic_iterator_t')
         if switch_obj is not None:
@@ -1723,33 +1828,39 @@ def _c_accessors_list(self, field):
             _c('%sconst %s *S  /**< */)', spacing, S_obj.c_type)
         else:
             _h('%s (const %s *R  /**< */);', field.c_iterator_name, c_type)
             _c('%s (const %s *R  /**< */)', field.c_iterator_name, c_type)
         _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)
 
             if align_pad is None:
                 align_pad = ('XCB_TYPE_PAD(%s, prev.index)' %
                     type_pad_type(field.c_field_type))
 
             _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('}')
 
 def _c_accessors(self, name, base):
     '''
     Declares the accessor functions for the fields of a structure.
-- 
2.0.1



More information about the Xcb mailing list