| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- #!/usr/bin/python3
- # Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- # All rights reserved.
- # Code licensed under the BSD License.
- # http://www.anki3d.org/LICENSE
- import optparse
- import xml.etree.ElementTree as et
- import os
- import copy
- class Context:
- __slots__ = ["input_filenames", "output_filename", "output_file", "identation_level"]
- def __init__(self):
- self.input_filenames = None
- self.output_filename = None
- self.output_file = None
- self.identation_level = 0
- ctx = Context()
- class MemberInfo:
- __slots__ = ["name", "base_type", "array_size", "comment", "pointer", "constructor"]
- def __init__(self):
- self.name = None
- self.base_type = None
- self.array_size = "1"
- self.comment = None
- self.pointer = False
- self.constructor = None
- def is_dynamic_array(self, member_arr):
- if not self.pointer:
- return False
- for member in member_arr:
- if member.name == self.array_size:
- return True
- return False
- def is_pointer(self, member_arr):
- return self.pointer and not self.is_dynamic_array(member_arr)
- def parse_commandline():
- """ Parse the command line arguments """
- parser = optparse.OptionParser(usage="usage: %prog [options]", description="Create serialization code using XML")
- parser.add_option("-i",
- "--input",
- dest="inp",
- type="string",
- help="specify the XML files to parse. Seperate with :")
- parser.add_option("-o", "--output", dest="out", type="string", help="specify the .h file to populate")
- (options, args) = parser.parse_args()
- if not options.inp or not options.out:
- parser.error("argument is missing")
- global ctx
- ctx.input_filenames = options.inp.split(":")
- ctx.output_filename = options.out
- def writeln(txt):
- """ Write generated code to the output """
- global ctx
- ctx.output_file.write("%s%s\n" % ("\t" * ctx.identation_level, txt))
- def ident(number):
- """ Increase or recrease identation for the writeln """
- global ctx
- ctx.identation_level += number
- def gen_class(root_el):
- """ Parse a "class" element and generate the code. """
- name = root_el.get("name")
- # Write doxygen
- if not root_el.get("comment"):
- writeln("/// %s class." % name)
- else:
- writeln("/// %s." % root_el.get("comment"))
- # Body start
- writeln("class %s" % name)
- writeln("{")
- writeln("public:")
- # Parse members
- member_arr = []
- members_el = root_el.find("members")
- for member_el in members_el:
- member = MemberInfo()
- member.name = member_el.get("name")
- member.base_type = member_el.get("type")
- member.array_size = member_el.get("array_size")
- if not member.array_size:
- member.array_size = "1"
- if member_el.get("pointer") and member_el.get("pointer") == "true":
- member.pointer = True
- else:
- member.pointer = False
- if member_el.get("comment"):
- member.comment = member_el.get("comment")
- if member_el.get("constructor"):
- member.constructor = member_el.get("constructor")
- member_arr.append(member)
- # Write members
- ident(1)
- for member in member_arr:
- if member.comment:
- writeln("")
- writeln("/// %s." % member.comment)
- if member.constructor:
- constructor = " %s" % member.constructor
- else:
- constructor = ""
- if member.pointer:
- writeln("%s* %s%s;" % (member.base_type, member.name, constructor))
- elif member.array_size != "1":
- writeln("Array<%s, %s> %s%s;" % (member.base_type, member.array_size, member.name, constructor))
- else:
- writeln("%s %s%s;" % (member.base_type, member.name, constructor))
- if member.comment:
- writeln("")
- ident(-1)
- # Before serialize make sure the dynamic arrays are last
- member_arr_copy = member_arr.copy()
- member_arr.sort(key=lambda x: x.is_dynamic_array(member_arr_copy))
- # Write the serialization and deserialization code
- writeln("")
- ident(1)
- writeln("template<typename TSerializer, typename TClass>")
- writeln("static void serializeCommon(TSerializer& s, TClass self)")
- writeln("{")
- ident(1)
- for member in member_arr:
- if member.is_pointer(member_arr_copy):
- writeln("s.doPointer(\"%s\", offsetof(%s, %s), self.%s);" % (member.name, name, member.name, member.name))
- elif member.is_dynamic_array(member_arr_copy):
- writeln("s.doDynamicArray(\"%s\", offsetof(%s, %s), self.%s, self.%s);" %
- (member.name, name, member.name, member.name, member.array_size))
- elif member.array_size != "1":
- writeln("s.doArray(\"%s\", offsetof(%s, %s), &self.%s[0], self.%s.getSize());" %
- (member.name, name, member.name, member.name, member.name))
- else:
- writeln("s.doValue(\"%s\", offsetof(%s, %s), self.%s);" % (member.name, name, member.name, member.name))
- ident(-1)
- writeln("}")
- ident(-1)
- # Write the methods
- writeln("")
- ident(1)
- writeln("template<typename TDeserializer>")
- writeln("void deserialize(TDeserializer& deserializer)")
- writeln("{")
- ident(1)
- writeln("serializeCommon<TDeserializer, %s&>(deserializer, *this);" % name)
- ident(-1)
- writeln("}")
- writeln("")
- writeln("template<typename TSerializer>")
- writeln("void serialize(TSerializer& serializer) const")
- writeln("{")
- ident(1)
- writeln("serializeCommon<TSerializer, const %s&>(serializer, *this);" % name)
- ident(-1)
- writeln("}")
- ident(-1)
- # Body end
- writeln("};")
- writeln("")
- def gen_file(filename):
- """ Parse an XML file and generate the code. """
- tree = et.parse(filename)
- root = tree.getroot()
- for incs in root.iter("includes"):
- for inc in incs.iter("include"):
- writeln("#include %s" % inc.get("file"))
- writeln("")
- writeln("namespace anki")
- writeln("{")
- writeln("")
- doxygen_group_el = root.find("doxygen_group")
- if doxygen_group_el is not None:
- doxygen_group = doxygen_group_el.get("name")
- writeln("/// @addtogroup %s" % doxygen_group)
- writeln("/// @{")
- writeln("")
- prefix_code = root.find("prefix_code")
- if prefix_code is not None:
- writeln("%s" % prefix_code.text)
- for cls in root.iter("classes"):
- for cl in cls.iter("class"):
- gen_class(cl)
- if doxygen_group_el is not None:
- writeln("/// @}")
- writeln("")
- writeln("} // end namespace anki")
- def main():
- parse_commandline()
- ctx.output_file = open(ctx.output_filename, "w")
- ctx.output_file.write("""// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- // WARNING: This file is auto generated.
- #pragma once
- """)
- for filename in ctx.input_filenames:
- gen_file(filename)
- if __name__ == "__main__":
- main()
|