diff options
author | Christian Linhart <chris@DemoRecorder.com> | 2014-11-02 13:45:29 +0100 |
---|---|---|
committer | Christian Linhart <chris@demorecorder.com> | 2014-11-03 11:23:16 +0100 |
commit | fda1fb4ed47a705744677a0074d83464af7aa4eb (patch) | |
tree | 107660afd63356fb0651c70788ac1d5dca6bb8e5 | |
parent | 265d38882cffce597367cc8bb2160b9e2482a80f (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.py | 124 |
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('}') |