From 5c08166be139fe06e1b38cbe02cf113911ec181e Mon Sep 17 00:00:00 2001 From: Christian Linhart Date: Wed, 3 Sep 2014 13:22:38 +0200 Subject: [PATCH] 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. Message-ID: <1409743361-466-3-git-send-email-chris@demorecorder.com> Patch-Thread-Subject: [Xcb] xinput: make ListInputDevices work, sumof with nested expr, ... Patch-Set: ListInputDevices Patch-Number: libxcb 3/6 Patch-Version: V1 Signed-off-by: Christian Linhart --- 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 ee28392..bf21a70 100644 --- a/src/c_client.py +++ b/src/c_client.py @@ -58,6 +58,102 @@ 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) + + +#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): ''' @@ -1010,6 +1106,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): @@ -1096,6 +1194,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() @@ -1195,6 +1295,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) @@ -1244,11 +1346,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;') @@ -1283,6 +1387,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) @@ -1672,12 +1778,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('}') @@ -1727,10 +1832,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) @@ -1741,11 +1851,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('}') -- 2.34.1