X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=bindings%2Fcxx%2Fenums.py;h=25bd6f428271a939cd7fa6a8bba2c5c5f44e7e6c;hb=444d6a3975787583494fa91cbb20c26d0ac858b5;hp=46a1472448d28734fbb0951bd3d5523a79b74405;hpb=6884b52bdefb7ed7169d557e1125f5b36276e2bf;p=libsigrok.git diff --git a/bindings/cxx/enums.py b/bindings/cxx/enums.py index 46a14724..25bd6f42 100644 --- a/bindings/cxx/enums.py +++ b/bindings/cxx/enums.py @@ -17,92 +17,96 @@ ## along with this program. If not, see . ## -import logging, warnings -from pygccxml import parser, declarations +from xml.etree import ElementTree from collections import OrderedDict import sys, os, re -class crapfilter(logging.Filter): - def filter(self, record): - if record.msg.find('GCCXML version') > -1: - return 0 - return 1 -logger = logging.getLogger('pygccxml.cxx_parser').addFilter(crapfilter()) -warnings.filterwarnings('ignore', message="unable to find out array size from expression") +index_file = sys.argv[1] # Get directory this script is in. dirname = os.path.dirname(os.path.realpath(__file__)) -# Parse GCCXML output to get declaration tree. -decls = parser.parse_xml_file( - os.path.join(dirname, "libsigrok.xml"), parser.config_t()) - -# Get global namespace from declaration tree. -ns = declarations.get_global_namespace(decls) +outdirname = "bindings/cxx" +if not os.path.exists(os.path.join(outdirname, 'include/libsigrok')): + os.makedirs(os.path.join(outdirname, 'include/libsigrok')) mapping = dict([ - ('sr_loglevel', 'LogLevel'), - ('sr_packettype', 'PacketType'), - ('sr_mq', 'Quantity'), - ('sr_unit', 'Unit'), - ('sr_mqflag', 'QuantityFlag'), - ('sr_configkey', 'ConfigKey'), - ('sr_datatype', 'DataType'), - ('sr_channeltype', 'ChannelType'), - ('sr_trigger_matches', 'TriggerMatchType')]) - -classes = OrderedDict() + ('sr_loglevel', ('LogLevel', 'Log verbosity level')), + ('sr_packettype', ('PacketType', 'Type of datafeed packet')), + ('sr_mq', ('Quantity', 'Measured quantity')), + ('sr_unit', ('Unit', 'Unit of measurement')), + ('sr_mqflag', ('QuantityFlag', 'Flag applied to measured quantity')), + ('sr_configkey', ('ConfigKey', 'Configuration key')), + ('sr_datatype', ('DataType', 'Configuration data type')), + ('sr_channeltype', ('ChannelType', 'Channel type')), + ('sr_trigger_matches', ('TriggerMatchType', 'Trigger match type'))]) + +index = ElementTree.parse(index_file) # Build mapping between class names and enumerations. -for enum in ns.enumerations(): - if enum.name in mapping: - classname = mapping[enum.name] - classes[classname] = enum -header = open(os.path.join(dirname, 'include/libsigrok/enums.hpp'), 'w') -code = open(os.path.join(dirname, 'enums.cpp'), 'w') +classes = OrderedDict() + +for compound in index.findall('compound'): + if compound.attrib['kind'] != 'file': + continue + filename = os.path.join( + os.path.dirname(index_file), + '%s.xml' % compound.attrib['refid']) + doc = ElementTree.parse(filename) + for section in doc.find('compounddef').findall('sectiondef'): + if section.attrib["kind"] != 'enum': + continue + for member in section.findall('memberdef'): + if member.attrib["kind"] != 'enum': + continue + name = member.find('name').text + if name in mapping: + classes[member] = mapping[name] + +header = open(os.path.join(outdirname, 'include/libsigrok/enums.hpp'), 'w') +code = open(os.path.join(outdirname, 'enums.cpp'), 'w') +swig = open(os.path.join(outdirname, '../swig/enums.i'), 'w') for file in (header, code): print >> file, "/* Generated file - edit enums.py instead! */" # Template for beginning of class declaration and public members. header_public_template = """ -class SR_API {classname} : public EnumValue +/** {brief} */ +class SR_API {classname} : public EnumValue<{classname}, enum {enumname}> {{ public: - static const {classname} *get(int id); """ # Template for beginning of private members. header_private_template = """ -private: - static const std::map values; - {classname}(enum {enumname} id, const char name[]); +protected: + {classname}(enum {enumname} id, const char name[]) : EnumValue(id, name) {{}} """ -# Template for class method definitions. -code_template = """ -{classname}::{classname}(enum {enumname} id, const char name[]) : - EnumValue(id, name) -{{ -}} +def get_text(node): + return str.join('\n\n', + [p.text.rstrip() for p in node.findall('para')]) -const {classname} *{classname}::get(int id) -{{ - return {classname}::values.at(static_cast<{enumname}>(id)); -}} -""" +for enum, (classname, classbrief) in classes.items(): -for classname, enum in classes.items(): + enum_name = enum.find('name').text + members = enum.findall('enumvalue') + member_names = [m.find('name').text for m in members] + trimmed_names = [re.sub("^SR_[A-Z]+_", "", n) for n in member_names] + briefs = [get_text(m.find('briefdescription')) for m in members] # Begin class and public declarations print >> header, header_public_template.format( - classname=classname, enumname=enum.name) + brief=classbrief, classname=classname, enumname=enum_name) # Declare public pointers for each enum value - for name, value in enum.values: - trimmed_name = re.sub("^SR_[A-Z]+_", "", name) - print >> header, '\tstatic const %s * const %s;' % (classname, trimmed_name) + for trimmed_name, brief in zip(trimmed_names, briefs): + if brief: + print >> header, '\t/** %s */' % brief + print >> header, '\tstatic const %s * const %s;' % ( + classname, trimmed_name) # Declare additional methods if present filename = os.path.join(dirname, "%s_methods.hpp" % classname) @@ -111,37 +115,29 @@ for classname, enum in classes.items(): # Begin private declarations print >> header, header_private_template.format( - classname=classname, enumname=enum.name) + classname=classname, enumname=enum_name) # Declare private constants for each enum value - for name, value in enum.values: - trimmed_name = re.sub("^SR_[A-Z]+_", "", name) + for trimmed_name in trimmed_names: print >> header, '\tstatic const %s _%s;' % (classname, trimmed_name) # End class declaration print >> header, '};' - # Begin class code - print >> code, code_template.format( - classname=classname, enumname=enum.name) - # Define private constants for each enum value - for name, value in enum.values: - trimmed_name = re.sub("^SR_[A-Z]+_", "", name) + for name, trimmed_name in zip(member_names, trimmed_names): print >> code, 'const %s %s::_%s = %s(%s, "%s");' % ( classname, classname, trimmed_name, classname, name, trimmed_name) # Define public pointers for each enum value - for name, value in enum.values: - trimmed_name = re.sub("^SR_[A-Z]+_", "", name) + for trimmed_name in trimmed_names: print >> code, 'const %s * const %s::%s = &%s::_%s;' % ( classname, classname, trimmed_name, classname, trimmed_name) # Define map of enum values to constants - print >> code, 'const std::map %s::values = {' % ( - enum.name, classname, classname) - for name, value in enum.values: - trimmed_name = re.sub("^SR_[A-Z]+_", "", name) + print >> code, 'template<> const std::map EnumValue<%s, enum %s>::_values = {' % ( + enum_name, classname, classname, enum_name) + for name, trimmed_name in zip(member_names, trimmed_names): print >> code, '\t{%s, %s::%s},' % (name, classname, trimmed_name) print >> code, '};' @@ -149,3 +145,16 @@ for classname, enum in classes.items(): filename = os.path.join(dirname, "%s_methods.cpp" % classname) if os.path.exists(filename): print >> code, str.join('', open(filename).readlines()) + + # Map EnumValue::id() and EnumValue::name() as SWIG attributes. + print >> swig, '%%attribute(sigrok::%s, int, id, id);' % classname + print >> swig, '%%attributestring(sigrok::%s, std::string, name, name);' % classname + + # Instantiate EnumValue template for SWIG + print >> swig, '%%template(EnumValue%s) sigrok::EnumValue;' % ( + classname, classname, enum_name) + + # Declare additional attributes if present + filename = os.path.join(dirname, "%s_methods.i" % classname) + if os.path.exists(filename): + print >> swig, str.join('', open(filename).readlines())