Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 19110 → Rev 19111

/trunk/Scribus/codegen/fromrelaxng/generate.py
0,0 → 1,128
# author: Andreas Vox, May 2012
 
import os
import sys
 
from xml.etree.ElementTree import ElementTree
from Cheetah.Template import Template
 
from impldescription import *
from parserng import*
 
class Generator(object):
def __init__(self, templdir, odir):
self._templatedir = templdir
self.outdir = odir
self._headerfiles = []
self._sourcefiles = []
self._templateSets = {}
def getfilename(self, fname):
if fname[-2:] == ".h" or fname[-2:] == ".H" or fname[-3:] == ".hh" or fname[-4:] == ".hxx":
self._headerfiles.append(fname)
elif fname[-2:] == ".c" or fname[-2:] == ".C" or fname[-4:] == ".cpp" or fname[-4:] == ".cxx":
self._sourcefiles.append(fname)
return os.path.join(self.outdir, fname)
def writefilelist(self, prefix, outfile):
fname = os.path.join(self.outdir, outfile);
oldlist = []
if os.path.exists(fname):
of = open(fname, "r")
oldlist = of.readlines();
of.close()
newlist = ["# Generated file, do not edit!\n"]
newlist.append("SET(%s_HEADERS\n" % prefix)
for h in self._headerfiles:
newlist.append("\t%s\n" % h)
newlist.append(")\n");
newlist.append("SET(%s_SOURCES\n" % prefix)
for s in self._sourcefiles:
newlist.append("\t%s\n" % s)
newlist.append(")\n")
if (oldlist != newlist):
nf = open(fname, "w")
nf.writelines(newlist)
nf.close()
def generate(self, classDesc):
print classDesc.xmlName, ":", classDesc.datatype, classDesc.name, "=", classDesc.template
name = classDesc.template
if name not in self._templateSets:
self._templateSets[name] = TemplateSet(self._templatedir, name)
self._templateSets[name].generate(classDesc, self)
class TemplateSet(object):
def __init__(self, dir, name):
self.name = name
self.templates = []
for f in os.listdir(dir):
if f[:len(name)] == name and f[-5:] == ".tmpl":
fpath = os.path.join(dir, f)
pair = (Template(file=fpath), f[len(name):-5])
self.templates.append(pair)
def generate(self, classDesc, generator):
if len(self.templates) == 0:
raise AssertionError("No '%s' templates found" % self.name)
if (self.name != classDesc.template):
raise NameError("Template names don't match: %s vs. %s" % (self.name, classDesc.template))
for (t,n) in self.templates:
t.c = classDesc
fname = generator.getfilename(classDesc.name + n)
oldcontent = "";
if os.path.exists(fname):
oldf = open(fname, "r")
oldcontent = oldf.read();
oldf.close()
newcontent = str(t)
if oldcontent != newcontent:
print "\t>>", fname
s = open(fname, "w")
s.write(newcontent)
s.close()
else:
print "\tskipping:", fname
def Main(file, templdir, outdir):
spec = ElementTree();
spec.parse(file);
parser = RNG_Parser(os.path.dirname(file))
parser.parsePattern(spec.getroot(), False, False)
generator = Generator(templdir, outdir)
for c in parser.classes:
parser.imports[c.name] = c.name + ".h"
for c in parser.classes:
c.addIncludes(parser.imports, parser.refnames)
generator.generate(c)
generator.writefilelist("SCRIBUS_RELAXNG", "generatedfiles.cmake")
rngfile = sys.argv[1]
if rngfile[-4:] == ".rnc":
rncfile = rngfile
rngfile = rngfile[:-4] + ".rng"
cwd = os.path.dirname(sys.argv[0])
err = os.system("java -jar %s/../trang/trang.jar %s %s" % (cwd, rncfile, rngfile))
if err != 0:
print "aborting"
exit(err)
templatedir = os.path.dirname(rngfile)
outdir = templatedir
if len(sys.argv) > 2:
templatedir = sys.argv[2]
if len(sys.argv) > 3:
outdir = sys.argv[3]
Main(rngfile, templatedir, outdir);
 
/trunk/Scribus/codegen/fromrelaxng/impldescription.py
0,0 → 1,151
# author: Andreas Vox, May 2012
 
from xml.etree.ElementTree import ElementTree
 
# our namespaces:
_namespaces = {}
_namespaces[''] = "http://relaxng.org/ns/structure/1.0"
_namespaces['rng'] = "http://relaxng.org/ns/structure/1.0"
_namespaces['a'] = "http://relaxng.org/ns/compatibility/annotations/1.0"
_namespaces['impl'] = "http://www.scribus.info/RelaxNG/implementation"
 
def qn(name):
if name.find(":") >= 0:
prefix,n = name.split(":")
return "{%s}%s" % (_namespaces[prefix], n)
else:
# use the default namespace
return "{%s}%s" % (_namespaces[''], name)
 
def an(name):
if name.find(":") >= 0:
prefix,n = name.split(":")
ns = _namespaces[prefix]
# special case: for attributes we don't include the default namespace
if ns == _namespaces['']:
return n
else:
return "{%s}%s" % (ns, n)
else:
return name
 
# helper
def pick(a, b):
if a is None:
return b
else:
return a
 
 
# implementation details for a ScribusIO class
class Class(object):
def __init__(self, xml):
self.xmlName = xml.get(an('name'))
self.name = xml.get(an('impl:name'), self.xmlName)
self.template = xml.get(an('impl:template'))
self.datatype = xml.get(an('impl:datatype'), self.name)
self.refname = None
self.properties = []
self.includes = []
self.classreferences = []
self.classincludes = []
def addIncludes(self, datatypes, refnames):
#print datatypes, refnames
for p in self.properties:
if p.datatype == None and p.refname in refnames:
p.datatype = refnames[p.refname].datatype
if p.datatype == None:
print "X>>>", p.name, p.refname, refnames
if p.datatype.find("<") > 0:
wrapper,lt,args = p.datatype[:-1].partition("<")
dts = [wrapper]
for arg in args.split(","):
dts.append(arg.strip());
else:
dts = [p.datatype]
#print "DTS:", p.name, p.datatype, dts
for dt in dts:
reference = None
include = None
if dt[-1] == "&" or dt[-1] == "*":
# pointer only needs reference in header file
dt = dt[:-1]
if dt not in ['int', 'long', 'uint', 'bool', 'double', 'float']:
reference = dt
if dt in datatypes:
include = datatypes[dt]
elif dt in datatypes:
# full type needs include
include = datatypes[dt]
elif dt[0:4] == "Qt::":
# Qt global enums
include = "<Qt>"
elif dt[0] == "Q":
# Qt types are easy
include = "<" + dt + ">"
elif dt not in ['int', 'long', 'uint', 'bool', 'double', 'float']:
# this might not be enough:
reference = dt
if include != None and include[0] != "<" and include[0] != '"':
include = '"' + include + '"'
 
if reference != None:
if reference not in self.classreferences:
self.classreferences.append(reference)
if include != None and include not in self.classincludes and include not in self.includes:
self.classincludes.append(include)
else:
if include != None and include not in self.includes:
self.includes.append(include)
if include in self.classincludes:
self.classincludes.remove(include)
#implementation details for a property of a ScribusIO class
class Property(object):
 
dataTypes = {'integer': "int", 'boolean': "bool", 'decimal': "double" , 'string': "QString" }
def __init__(self, xml, optional, isCollection = False):
self.xmlName = xml.get(an('name'))
self.name = xml.get(an('impl:name'), self.xmlName)
self.optional = xml.get(an('impl:optional'), optional)
self.type = xml.get(an('impl:type'), "coll" if isCollection else "value") # value, struct, collection
self.datatype = xml.get(an('impl:datatype'))
self.refname = None
self.fromString = xml.get(an('impl:fromstring'))
self.toString = xml.get(an('impl:tostring'))
self.getter = xml.get(an('impl:getter'), "get" +self.name)
self.setter = xml.get(an('impl:setter'), "set" + self.name[0:1].capitalize() + self.name[1:])
self.resetter = xml.get(an('impl:resetter'), "reset" + self.name[0:1].capitalize() + self.name[1:])
self.initial = xml.get(an('impl:initial'))
self.builder = xml.get(an('impl:builder'))
if self.builder is not None:
args = self.builder.split(";")
self.builder = args[0]
self.builderargs = []
for i in range(1, len(args)):
arg = args[i]
p = arg.find('|')
comma = "," if i < len(args)-1 else ""
if p >= 0:
p2 = arg.rfind('|')
triple = (arg[:p] + '(', arg[p+1: p2], ')' + arg[p2+1:] + comma)
else:
triple = ("", arg, comma)
self.builderargs.append(triple)
if self.datatype is None:
dt = xml.find(qn('rng:data'))
if dt != None:
xsltype = dt.get(an('type'))
self.datatype = xsltype if xsltype not in self.dataTypes else self.dataTypes[xsltype]
/trunk/Scribus/codegen/fromrelaxng/parserng.py
0,0 → 1,164
# author: Andreas Vox, May 2012
 
from xml.etree.ElementTree import ElementTree
import os
 
from impldescription import *
 
class RNG_Parser(object):
def __init__(self, dir):
self.basedir = dir
self.definitions = {}
self.refnames = {}
self.imports = {}
self.classes = []
self.currentClass = None
def parsePattern(self, pattern, isOptional, isCollection):
if pattern.tag == qn('element'):
if pattern.get(an('impl:type')) == "ignore":
pass;
elif pattern.get(an('impl:template')) != None:
c = self.currentClass
self.currentClass = Class(pattern)
self.classes.append(self.currentClass)
self.parsePatterns(pattern.getchildren(), False, False)
self.currentClass = c
elif self.currentClass != None:
newProp = Property(pattern, isOptional, isCollection)
if newProp.datatype == None:
ref = pattern.getchildren()[0]
if ref.tag == qn('rng:ref'):
newProp.refname = ref.get(an('name'))
self.currentClass.properties.append(newProp)
else:
self.parsePatterns(pattern.getchildren(), isOptional, isCollection)
 
elif pattern.tag == qn('attribute'):
if pattern.get(an('impl:type')) == "ignore":
pass;
elif self.currentClass != None:
self.currentClass.properties.append(Property(pattern, isOptional, isCollection))
elif pattern.tag == qn('group'):
self.parsePatterns(pattern.getchildren(), isOptional, isCollection)
elif pattern.tag == qn('interleave'):
self.parsePatterns(pattern.getchildren(), isOptional, isCollection)
elif pattern.tag == qn('choice'):
self.parsePatterns(pattern.getchildren(), True, isCollection)
elif pattern.tag == qn('optional'):
self.parsePatterns(pattern.getchildren(), True, isCollection)
elif pattern.tag == qn('zeroOrMore'):
self.parsePatterns(pattern.getchildren(), isOptional, True)
elif pattern.tag == qn('oneOrMore'):
self.parsePatterns(pattern.getchildren(), isOptional, True)
elif pattern.tag == qn('list'):
raise NotImplementedError
elif pattern.tag == qn('mixed'):
self.parsePatterns(pattern.getchildren(), isOptional, isCollection)
elif pattern.tag == qn('ref'):
if pattern.get(an('impl:type')) != "ignore":
self.parsePatterns(self.definitions[pattern.get(an('name'))], isOptional, isCollection)
elif pattern.tag == qn('parentRef'):
if pattern.get(an('impl:type')) != "ignore":
self.parsePatterns(self.definitions[pattern.get(an('name'))], isOptional, isCollection)
elif pattern.tag == qn('empty'):
pass
elif pattern.tag == qn('text'):
pass
elif pattern.tag == qn('value'):
raise NotImplementedError
elif pattern.tag == qn('data'):
raise NotImplementedError
elif pattern.tag == qn('notAllowed'):
pass
elif pattern.tag == qn('externalRef'):
raise NotImplementedError
elif pattern.tag == qn('grammar'):
self.parseGrammar(pattern.getchildren())
elif pattern.tag == qn('impl:import'):
self.parseImport(pattern)
else:
pass
 
def parseImport(self, pattern):
self.imports[pattern.get(an('impl:datatype'))] = pattern.get(an('impl:headerfile'))
 
def parsePatterns(self, patterns, isOptional, isCollection):
for p in patterns:
self.parsePattern(p, isOptional, isCollection)
def parseGrammar(self, grammar):
for rule in grammar:
if rule.tag == qn('define'):
self.parseDefine(rule)
elif rule.tag == qn('start'):
self.parsePatterns(rule.getchildren(), False, False)
elif rule.tag == qn('div'):
self.parseGrammar(rule)
elif rule.tag == qn('include'):
xgrammar = ElementTree()
file = os.path.join(self.basedir, rule.get(an('href')))
xgrammar.parse(file)
self.parseGrammar(xgrammar.getroot())
elif rule.tag == qn('impl:import'):
self.parseImport(rule)
else:
raise NotImplementedError
def parseDefine(self, rule):
self.definitions[rule.get(an('name'))] = rule.getchildren()
if rule.get(an('impl:type')) == "ignore":
pass
elif rule.get(an('impl:template')) != None:
c = self.currentClass
self.currentClass = Class(rule)
self.refnames[rule.get(an('name'))] = self.currentClass
self.classes.append(self.currentClass)
self.parsePatterns(rule.getchildren(), False, False)
self.currentClass = c
else:
self.parsePatterns(rule.getchildren(), False, False)
 
 
 
def dumpTree(i, tree):
print i*" " + tree.tag + " " + str(tree.attrib) + " " + repr(tree.text)
for e in tree.getchildren():
dumpTree(i+1, e)
def testParser(file):
self.spec = ElementTree()
spec.parse(file)
x = RNG_Parser(os.path.dirname(file))
x.parsePattern(spec.getroot(), False, False)
for c in x.classes:
x.imports[c.datatype] = c.name + ".h"
for c in x.classes:
c.addIncludes(x.imports, x.refnames)
 
for c in x.classes:
print "%s (%s) TEMPL %s" % (c.name, c.datatype, c.template)
print "\t#imports", c.includes
print "\tclass", c.classreferences, ";"
print " Properties:"
for p in c.properties:
print "\t%s (%s) %s\t|%s|\t INIT %s" % (p.name, p.datatype, "OPT" if p.optional else "", p.type, p.initial)
 
def testmain():
import sys
import os
rncfile = sys.argv[1]
rngfile = rncfile[:-4] + ".rng"
cwd = os.path.dirname(sys.argv[0])
err = os.system("java -jar %s/../trang/trang.jar %s %s" % (cwd, rncfile, rngfile))
if err != 0:
print "aborting"
exit(err)
testParser(rngfile)
#testmain()