diff options
Diffstat (limited to 'dcoppython/shell/gen_marshal_code.py')
-rw-r--r-- | dcoppython/shell/gen_marshal_code.py | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/dcoppython/shell/gen_marshal_code.py b/dcoppython/shell/gen_marshal_code.py new file mode 100644 index 00000000..73cb1fd0 --- /dev/null +++ b/dcoppython/shell/gen_marshal_code.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python +# Julian Rockey 2003 +# Generate marshall/demarshal functions from marshal_funcs.data file + +import sys +import re + +def cap_first(str): + """Capitalise first letter of string.""" + return str[0].upper() + str[1:] + +def set_method(attr): + """Return the name for a QT class setter method for an attribute.""" + return "set" + cap_first(attr) + +class DictMaker: + """Generate code for marshalling/demarshalling types using Python dictionaries.""" + + supported_types = ['string'] + re_dictmap = re.compile("%dict\-map(.*)") + re_dictmap_constructor = re.compile("%constructor (.+)") + + def __init__(self): + self.attr_list = [] + self.current_type = None + self.operation = None + self.constructor = None + + self.type_handlers = {} + for type in self.supported_types: + self.type_handlers[type] = (eval('self.handle_%s_marsh' % type), + eval('self.handle_%s_demarsh' % type)) + + def handle_string_marsh(self, attribute): + """Handle marshalling of string item from the dictionary.""" + return ["if (%s && !PyString_Check(%s)) return false;" % (attribute, attribute), + "if (%s) { qobj.%s(QString(PyString_AsString(%s)));" % (attribute, set_method(attribute), attribute), + "PyDict_DelItemString(dict,(char*)\"%s\"); } " % (attribute)] + + def handle_string_demarsh(self, attribute): + """Handle demarshalling of string items into the dictionary.""" + return ["PyObject *%s = PyString_FromString(qobj.%s().utf8().data() );" % (attribute ,attribute), + "PyDict_SetItemString(dict, (char*)\"%s\", %s);" % (attribute, attribute) + ] + + def pre_code_for(self, operation, attribute): + + if operation==MARSHAL: + return ["PyObject *%s = PyDict_GetItemString(dict,(char*)\"%s\");" % (attribute, attribute) ] + + return [] + + def post_code_for(self, operation, attribute): + return [] + + def code_for(self, operation, type, attribute): + if operation!=None and (type in self.type_handlers): + return self.pre_code_for(operation, attribute) + \ + self.type_handlers[type][not not operation](attribute) + \ + self.post_code_for(operation, attribute) + + return [] + + def set_current_type(self, current_type): + self.current_type = current_type + self.constructor = ""; + + def set_operation(self, operation): + if operation in [None, MARSHAL, DEMARSHAL]: + self.operation = operation + + def check_dictmap(self, line): + + if self.operation not in [MARSHAL,DEMARSHAL]: return [] + + m=self.re_dictmap_constructor.match(line) + if m: + self.constructor = m.groups()[0] + return [''] + + m=self.re_dictmap.match(line) + if not m: return [] + + if self.operation==MARSHAL: + result = ["{", + "if (!PyDict_Check(obj)) return false;", + "%s qobj%s;" % (self.current_type,self.constructor), + "PyObject *dict = PyDict_Copy(obj);" + ] + if self.operation==DEMARSHAL: + result = ["{", + "PyObject *dict = PyDict_New();", + "if (!dict) return NULL;", + "%s qobj%s;" % (self.current_type,self.constructor), + "(*str) >> qobj;" + ] + + if m.groups()[0].strip(): + self.attr_list = [tuple(x.split(':')) for x in m.groups()[0].strip().split(',') ] + + for attribute, type in self.attr_list: + result += self.code_for(self.operation, type, attribute) + + if self.operation==MARSHAL: + result += ["if (str) (*str) << qobj;", + "Py_DECREF(dict);", + "return true;", + "}" + ] + if self.operation==DEMARSHAL: + result += ["return dict;", + "}" + ] + + return result + +class DocType: + """A class to hold documentation information for each type.""" + + def __init__(self, type): + self.type = type + self.demarshal_as = None + self.as = [] + self.info = [] + + def add_as(self, as): + if self.demarshal_as == None: self.demarshal_as = as + self.as += [as] + + def add_info(self,info): + self.info += [info] + + def xml(self): + return ['<type dcoptype="%s">' % self.type, + ' <demarshal-as>%s</demarshal-as>' % self.demarshal_as] + \ + [' <marshal-as>%s</marshal-as>' % as for as in self.as ] + \ + [' <info>%s</info>' % info for info in self.info ] + \ + ['</type>'] + + +MARSHAL, DEMARSHAL, TOPYOBJ, FROMPYOBJ = 0,1,2,3 + +if len(sys.argv)!=4: + print "Use: gen_marshal_code.py <input file> <output file> <doc-xml-output file>" + raise RuntimeError + +nowt, in_name, code_name, doc_xml_name = tuple(sys.argv) + +##in_name, code_name, doc_xml_name = "marshal_funcs.data", "marshal_funcs.h", "marshal_funcs_doc.xml" + +gen_code_comments = ['/*', + ' * This code was generated by gen_marshal_code.py', + ' * Please do not modify, or it\'ll be overwritten!', + ' */', + ' ', + ] + +re_type = re.compile(r"type\: *([^\s]+).*") +re_marshDemarsh = re.compile("%% *(de)?marshal *.*") +re_tofromPyobj = re.compile("%% *(to|from)_pyobj *.*") +re_defaultCode = re.compile("%defaultcode *.*") +re_docInfo = re.compile("%doc *([^ ]+) *(.*)") + +in_file = open(in_name,"r") +code = [] + +types = {} +doc_types = {} +current_operation = None + +dict_maker = DictMaker() + +for l in in_file.readlines(): + l=l[:-1] + + # match a "type:" line + m=re_type.match(l) + if m: + current_type = m.groups()[0] + types[current_type]={} + doc_types[current_type] = DocType(current_type) + dict_maker.set_current_type(current_type) + continue + + m=re_docInfo.match(l) + if m: + doc_cmd, rest = m.groups() + if doc_cmd=="as": + doc_types[current_type].add_as(rest) + if doc_cmd=="info": + doc_types[current_type].add_info(rest) + continue + + # match a "%% marshal" or "%% demarshal" line + m=re_marshDemarsh.match(l) + if m: + if m.groups()[0]: + current_operation = DEMARSHAL + code.append("PyObject *demarshal_" + current_type + \ + "(QDataStream *str)") + else: + current_operation = MARSHAL + code.append("bool marshal_" + current_type + \ + "(PyObject *obj, QDataStream *str)") + dict_maker.set_operation(current_operation) + continue + + m=re_tofromPyobj.match(l) + if m: + if m.groups()[0]=='to': + current_operation = TOPYOBJ + code += ["PyObject *toPyObject_%s(%s val)" % (current_type,current_type)] + elif m.groups()[0]=='from': + current_operation = FROMPYOBJ + code += ["%s fromPyObject_%s(PyObject *obj, bool *ok)" % (current_type,current_type)] + continue + + + if l.strip()=='%%': + current_operation = None + dict_maker.set_operation(current_operation) + + if current_operation!=None: + types[current_type][current_operation]=1 + + dict_code = dict_maker.check_dictmap(l) + if dict_code: + code += dict_code + continue + + m=re_defaultCode.match(l) + if m: + if current_operation==MARSHAL: + code += [ + "{", + " bool ok;", + " %s qobj=fromPyObject_%s(obj,&ok);" % (current_type,current_type), + " if (ok && str) (*str) << qobj;", + " return ok;", + "}" + ] + continue + if current_operation==DEMARSHAL: + code += [ + "{", + " %s qobj;" % current_type, + " (*str) >> qobj;", + " return toPyObject_%s(qobj);" % current_type, + "}" + ] + continue + + code.append(l) + +in_file.close() + +code.append("void Marshaller::initFuncs() {") +for t in types: + if MARSHAL in types[t]: + code.append("m_marsh_funcs[\"" + t + "\"]=marshal_" + t + ";") + if DEMARSHAL in types[t]: + code.append("m_demarsh_funcs[\"" + t + "\"]=demarshal_" + t + ";") +code.append("}") + +out_file = open(code_name,"w") +out_file.writelines([x + '\n' for x in gen_code_comments]) +out_file.writelines([x + '\n' for x in code]) +out_file.close() + +xml_file = file(doc_xml_name,"w") +print >>xml_file, '<?xml version="1.0" ?>' +print >>xml_file, '<!-- This file was auto-generated by gen_marshal_code.py. Changes will be lost! -->' +print >>xml_file, "<types>" +[ [xml_file.write(x+"\n") for x in doc.xml()] for doc in doc_types.values() ] # silly one-liner +print >>xml_file, "</types>" +xml_file.close() |