summaryrefslogtreecommitdiffstats
path: root/dcoppython/shell/gen_marshal_code.py
diff options
context:
space:
mode:
Diffstat (limited to 'dcoppython/shell/gen_marshal_code.py')
-rw-r--r--dcoppython/shell/gen_marshal_code.py276
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()