"vscode:/vscode.git/clone" did not exist on "f31eee3a9e76253773b781f684581c3fb9377228"
Commit 81baff51 authored by peastman's avatar peastman
Browse files

Began rewriting C/Fortran wrapper generation to use Doxygen/Python instead of gccxml/XSLT

parent 9d207e8d
import sys, os
import time
import getopt
import re
import xml.etree.ElementTree as etree
def trimToSingleSpace(text):
if text is None or len(text) == 0:
return ""
t = text.strip()
if len(t) == 0:
return t
if text[0].isspace():
t = " %s" % t
if text[-1].isspace():
t = "%s " % t
return t
def getNodeText(node):
if node.text is not None:
s = node.text
else:
s = ""
for n in node:
if n.tag == "para":
s = "%s%s\n\n" % (s, getNodeText(n))
elif n.tag == "ref":
s = "%s%s" % (s, getNodeText(n))
if n.tail is not None:
s = "%s%s" % (s, n.tail)
return s
def getText(subNodePath, node):
s = ""
for n in node.findall(subNodePath):
s = "%s%s" % (s, trimToSingleSpace(getNodeText(n)))
if n.tag == "para":
s = "%s\n\n" % s
return s.strip()
def convertOpenMMPrefix(name):
return name.replace('OpenMM::', 'OpenMM_')
OPENMM_RE_PATTERN=re.compile("(.*)OpenMM:[a-zA-Z:]*:(.*)")
def stripOpenMMPrefix(name, rePattern=OPENMM_RE_PATTERN):
try:
m=rePattern.search(name)
rValue = "%s%s" % m.group(1,2)
rValue.strip()
return rValue
except:
return name
def findNodes(parent, path, **args):
nodes = []
for node in parent.findall(path):
match = True
for arg in args:
if arg not in node.attrib or node.attrib[arg] != args[arg]:
match = False
if match:
nodes.append(node)
return nodes
class WrapperGenerator:
def __init__(self, inputDirname, output):
self.skipClasses = ['OpenMM::Vec3', 'OpenMM::XmlSerializer', 'OpenMM::Kernel', 'OpenMM::KernelImpl', 'OpenMM::KernelFactory', 'OpenMM::ContextImpl', 'OpenMM::SerializationNode', 'OpenMM::SerializationProxy']
self.skipMethods = ['OpenMM::Context::getState', 'OpenMM::Platform::loadPluginsFromDirectory', 'OpenMM::Context::createCheckpoint', 'OpenMM::Context::loadCheckpoint']
self.hideClasses = ['Kernel', 'KernelImpl', 'KernelFactory', 'ContextImpl', 'SerializationNode', 'SerializationProxy']
self.typeTranslations = {'bool': 'OpenMM_Boolean',
'Vec3': 'OpenMM_Vec3',
'std::string': 'char*',
'const std::string &': 'const char*',
'std::vector< std::string >': 'OpenMM_StringArray',
'std::vector< Vec3 >': 'OpenMM_Vec3Array',
'std::vector< std::pair< int, int > >': 'OpenMM_BondArray',
'std::map< std::string, double >': 'OpenMM_ParameterArray',
'std::map< std::string, std::string >': 'OpenMM_PropertyArray',
'std::vector< double >': 'OpenMM_DoubleArray',
'std::vector< int >': 'OpenMM_IntArray',
'std::set< int >': 'OpenMM_IntSet'}
self.nodeByID={}
# Read all the XML files and merge them into a single document.
self.doc = etree.ElementTree(etree.Element('root'))
for file in os.listdir(inputDirname):
root = etree.parse(os.path.join(inputDirname, file)).getroot()
for node in root:
self.doc.getroot().append(node)
self.fOut = output
self._enumByClassname={}
self.typesByShortName = {}
self._orderedClassNodes = self._buildOrderedClassNodes()
def _getNodeByID(self, id):
if id not in self.nodeByID:
for node in findNodes(self.doc.getroot(), "compounddef", id=id):
self.nodeByID[id] = node
return self.nodeByID[id]
def _buildOrderedClassNodes(self):
orderedClassNodes=[]
for node in findNodes(self.doc.getroot(), "compounddef", kind="class", prot="public"):
self._findBaseNodes(node, orderedClassNodes)
return orderedClassNodes
def _findBaseNodes(self, node, excludedClassNodes=[]):
if node in excludedClassNodes:
return
if node.attrib['prot'] == 'private':
return
nodeName = getText("compoundname", node)
if nodeName in self.skipClasses:
return
for baseNodePnt in findNodes(node, "basecompoundref", prot="public"):
if "refid" in baseNodePnt.attrib:
baseNodeID = baseNodePnt.attrib["refid"]
baseNode = self._getNodeByID(baseNodeID)
self._findBaseNodes(baseNode, excludedClassNodes)
excludedClassNodes.append(node)
def writeGlobalConstants(self):
self.fOut.write("/* Global Constants */\n\n")
node = next((x for x in findNodes(self.doc.getroot(), "compounddef", kind="namespace") if x.findtext("compoundname") == "OpenMM"))
for section in findNodes(node, "sectiondef", kind="var"):
for memberNode in findNodes(section, "memberdef", kind="variable", mutable="no", prot="public", static="yes"):
vDef = convertOpenMMPrefix(getText("definition", memberNode))
iDef = getText("initializer", memberNode)
if iDef.startswith("="):
iDef = iDef[1:]
self.fOut.write("static %s = %s;\n" % (vDef, iDef))
def writeTypeDeclarations(self):
self.fOut.write("\n/* Type Declarations */\n\n")
for classNode in self._orderedClassNodes:
className = getText("compoundname", classNode)
shortName = stripOpenMMPrefix(className)
typeName = convertOpenMMPrefix(className)
self.fOut.write("typedef struct %s_struct %s;\n" % (typeName, typeName))
self.typesByShortName[shortName] = typeName
def writeClasses(self):
for classNode in self._orderedClassNodes:
className = stripOpenMMPrefix(getText("compoundname", classNode))
self.fOut.write("\n/* %s */\n" % className)
self.writeEnumerations(classNode)
self.writeMethods(classNode)
self.fOut.write("\n")
def writeEnumerations(self, classNode):
enumNodes = []
for section in findNodes(classNode, "sectiondef", kind="public-type"):
for node in findNodes(section, "memberdef", kind="enum", prot="public"):
enumNodes.append(node)
className = getText("compoundname", classNode)
shortClassName = stripOpenMMPrefix(className)
typeName = convertOpenMMPrefix(className)
for enumNode in enumNodes:
enumName = getText("name", enumNode)
enumTypeName = "%s_%s" % (typeName, enumName)
self.fOut.write("typedef enum {\n ")
argSep=""
for valueNode in findNodes(enumNode, "enumvalue", prot="public"):
vName = convertOpenMMPrefix(getText("name", valueNode))
vInit = getText("initializer", valueNode)
if vInit.startswith("="):
vInit = vInit[1:].strip()
self.fOut.write("%s%s_%s = %s" % (argSep, typeName, vName, vInit))
argSep=", "
self.fOut.write("\n} %s;\n" % enumTypeName)
self.typesByShortName[enumName] = enumTypeName
if len(enumNodes)>0: self.fOut.write("\n")
def getClassMethods(self, classNode):
className = getText("compoundname", classNode)
shortClassName = stripOpenMMPrefix(className)
methodList = []
for section in findNodes(classNode, "sectiondef", kind="public-static-func")+findNodes(classNode, "sectiondef", kind="public-func"):
for memberNode in findNodes(section, "memberdef", kind="function", prot="public"):
methodDefinition = getText("definition", memberNode)
shortMethodDefinition = stripOpenMMPrefix(methodDefinition)
methodName = shortMethodDefinition.split()[-1]
if className+'::'+methodName in self.skipMethods:
continue
methodList.append(memberNode)
return methodList
def writeMethods(self, classNode):
methodList = self.getClassMethods(classNode)
className = getText("compoundname", classNode)
shortClassName = stripOpenMMPrefix(className)
typeName = convertOpenMMPrefix(className)
destructorName = '~'+shortClassName
if not ('abstract' in classNode.attrib and classNode.attrib['abstract'] == 'yes'):
# Write constructors
numConstructors = 0
for methodNode in methodList:
methodDefinition = getText("definition", methodNode)
shortMethodDefinition = stripOpenMMPrefix(methodDefinition)
methodName = shortMethodDefinition.split()[-1]
if methodName == shortClassName:
if self.shouldHideMethod(methodNode):
continue
numConstructors += 1
if numConstructors == 1:
suffix = ""
else:
suffix = "_%d" % numConstructors
self.fOut.write("extern OPENMM_EXPORT %s* %s_create%s(" % (typeName, typeName, suffix))
self.writeArguments(methodNode, False)
self.fOut.write(");\n")
# Write destructor
self.fOut.write("extern OPENMM_EXPORT void %s_destroy(%s* target);\n" % (typeName, typeName))
# Write other methods
for methodNode in methodList:
methodDefinition = getText("definition", methodNode)
shortMethodDefinition = stripOpenMMPrefix(methodDefinition)
methodName = shortMethodDefinition.split()[-1]
if methodName in (shortClassName, destructorName):
continue
if self.shouldHideMethod(methodNode):
continue
returnType = self.getType(getText("type", methodNode))
self.fOut.write("extern OPENMM_EXPORT %s %s_%s(" % (returnType, typeName, methodName))
isInstanceMethod = (methodNode.attrib['static'] != 'yes')
if isInstanceMethod:
if methodNode.attrib['const'] == 'yes':
self.fOut.write('const ')
self.fOut.write("%s* target" % typeName)
self.writeArguments(methodNode, isInstanceMethod)
self.fOut.write(");\n")
def shouldHideType(self, typeName):
if typeName.startswith('const '):
typeName = typeName[6:].strip()
if typeName.endswith('&') or typeName.endswith('*'):
typeName = typeName[:-1].strip()
return typeName in self.hideClasses
def shouldHideMethod(self, methodNode):
paramList = findNodes(methodNode, 'param')
returnType = self.getType(getText("type", methodNode))
if self.shouldHideType(returnType):
return True
for node in paramList:
try:
type = getText('type', node)
except IndexError:
type = getText('type/ref', node)
if self.shouldHideType(type):
return True
return False
def writeArguments(self, methodNode, initialSeparator):
paramList = findNodes(methodNode, 'param')
if initialSeparator:
separator = ", "
else:
separator = ""
for node in paramList:
try:
type = getText('type', node)
except IndexError:
type = getText('type/ref', node)
if type == 'void':
continue
type = self.getType(type)
name = getText('declname', node)
self.fOut.write("%s%s %s" % (separator, type, name))
separator = ", "
def getType(self, type):
if type in self.typeTranslations:
return self.typeTranslations[type]
if type in self.typesByShortName:
return self.typesByShortName[type]
if type.startswith('const '):
return 'const '+self.getType(type[6:].strip())
if type.endswith('&') or type.endswith('*'):
return self.getType(type[:-1].strip())+'*'
return type
inputDirname = '/Users/peastman/workspace/openmm/bin-release/wrappers/python/src/swig_doxygen/doxygen/xml'
out = sys.stdout
builder = WrapperGenerator(inputDirname, out)
print >>out, """
#ifndef OPENMM_CWRAPPER_H_
#define OPENMM_CWRAPPER_H_
#ifndef OPENMM_EXPORT
#define OPENMM_EXPORT
#endif
"""
builder.writeGlobalConstants()
builder.writeTypeDeclarations()
print >>out, """
typedef struct OpenMM_Vec3Array_struct OpenMM_Vec3Array;
typedef struct OpenMM_StringArray_struct OpenMM_StringArray;
typedef struct OpenMM_BondArray_struct OpenMM_BondArray;
typedef struct OpenMM_ParameterArray_struct OpenMM_ParameterArray;
typedef struct OpenMM_PropertyArray_struct OpenMM_PropertyArray;
typedef struct OpenMM_DoubleArray_struct OpenMM_DoubleArray;
typedef struct OpenMM_IntArray_struct OpenMM_IntArray;
typedef struct OpenMM_IntSet_struct OpenMM_IntSet;
typedef struct {double x, y, z;} OpenMM_Vec3;
typedef enum {OpenMM_False = 0, OpenMM_True = 1} OpenMM_Boolean;
#if defined(__cplusplus)
extern "C" {
#endif
/* OpenMM_Vec3 */
extern OPENMM_EXPORT OpenMM_Vec3 OpenMM_Vec3_scale(const OpenMM_Vec3 vec, double scale);
/* OpenMM_Vec3Array */
extern OPENMM_EXPORT OpenMM_Vec3Array* OpenMM_Vec3Array_create(int size);
extern OPENMM_EXPORT void OpenMM_Vec3Array_destroy(OpenMM_Vec3Array* array);
extern OPENMM_EXPORT int OpenMM_Vec3Array_getSize(const OpenMM_Vec3Array* array);
extern OPENMM_EXPORT void OpenMM_Vec3Array_resize(OpenMM_Vec3Array* array, int size);
extern OPENMM_EXPORT void OpenMM_Vec3Array_append(OpenMM_Vec3Array* array, const OpenMM_Vec3 vec);
extern OPENMM_EXPORT void OpenMM_Vec3Array_set(OpenMM_Vec3Array* array, int index, const OpenMM_Vec3 vec);
extern OPENMM_EXPORT const OpenMM_Vec3* OpenMM_Vec3Array_get(const OpenMM_Vec3Array* array, int index);
/* OpenMM_StringArray */
extern OPENMM_EXPORT OpenMM_StringArray* OpenMM_StringArray_create(int size);
extern OPENMM_EXPORT void OpenMM_StringArray_destroy(OpenMM_StringArray* array);
extern OPENMM_EXPORT int OpenMM_StringArray_getSize(const OpenMM_StringArray* array);
extern OPENMM_EXPORT void OpenMM_StringArray_resize(OpenMM_StringArray* array, int size);
extern OPENMM_EXPORT void OpenMM_StringArray_append(OpenMM_StringArray* array, const char* string);
extern OPENMM_EXPORT void OpenMM_StringArray_set(OpenMM_StringArray* array, int index, const char* string);
extern OPENMM_EXPORT const char* OpenMM_StringArray_get(const OpenMM_StringArray* array, int index);
/* OpenMM_BondArray */
extern OPENMM_EXPORT OpenMM_BondArray* OpenMM_BondArray_create(int size);
extern OPENMM_EXPORT void OpenMM_BondArray_destroy(OpenMM_BondArray* array);
extern OPENMM_EXPORT int OpenMM_BondArray_getSize(const OpenMM_BondArray* array);
extern OPENMM_EXPORT void OpenMM_BondArray_resize(OpenMM_BondArray* array, int size);
extern OPENMM_EXPORT void OpenMM_BondArray_append(OpenMM_BondArray* array, int particle1, int particle2);
extern OPENMM_EXPORT void OpenMM_BondArray_set(OpenMM_BondArray* array, int index, int particle1, int particle2);
extern OPENMM_EXPORT void OpenMM_BondArray_get(const OpenMM_BondArray* array, int index, int* particle1, int* particle2);
/* OpenMM_ParameterArray */
extern OPENMM_EXPORT int OpenMM_ParameterArray_getSize(const OpenMM_ParameterArray* array);
extern OPENMM_EXPORT double OpenMM_ParameterArray_get(const OpenMM_ParameterArray* array, const char* name);
/* OpenMM_PropertyArray */
extern OPENMM_EXPORT int OpenMM_PropertyArray_getSize(const OpenMM_PropertyArray* array);
extern OPENMM_EXPORT const char* OpenMM_PropertyArray_get(const OpenMM_PropertyArray* array, const char* name);"""
for type in ('double', 'int'):
name = 'OpenMM_%sArray' % type.capitalize()
values = {'type':type, 'name':name}
print >>out, """
/* %(name)s */
extern OPENMM_EXPORT %(name)s* %(name)s_create(int size);
extern OPENMM_EXPORT void %(name)s_destroy(%(name)s* array);
extern OPENMM_EXPORT int %(name)s_getSize(const %(name)s* array);
extern OPENMM_EXPORT void %(name)s_resize(%(name)s* array, int size);
extern OPENMM_EXPORT void %(name)s_append(%(name)s* array, %(type)s value);
extern OPENMM_EXPORT void %(name)s_set(%(name)s* array, int index, %(type)s value);
extern OPENMM_EXPORT %(type)s %(name)s_get(const %(name)s* array, int index);""" % values
for type in ('int',):
name = 'OpenMM_%sSet' % type.capitalize()
values = {'type':type, 'name':name}
print >>out, """
/* %(name)s */
extern OPENMM_EXPORT %(name)s* %(name)s_create();
extern OPENMM_EXPORT void %(name)s_destroy(%(name)s* set);
extern OPENMM_EXPORT int %(name)s_getSize(const %(name)s* set);
extern OPENMM_EXPORT void %(name)s_insert(%(name)s* set, %(type)s value);""" % values
print >>out, """
/* These methods need to be handled specially, since their C++ APIs cannot be directly translated to C.
Unlike the C++ versions, the return value is allocated on the heap, and you must delete it yourself. */
extern OPENMM_EXPORT OpenMM_State* OpenMM_Context_getState(const OpenMM_Context* target, int types, int enforcePeriodicBox);
extern OPENMM_EXPORT OpenMM_StringArray* OpenMM_Platform_loadPluginsFromDirectory(const char* directory);"""
builder.writeClasses()
print >>out, """
#if defined(__cplusplus)
}
#endif
#endif /*OPENMM_CWRAPPER_H_*/"""
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment