757 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			757 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Python
		
	
	
| """
 | |
| GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
 | |
| Atlanta, Georgia 30332-0415
 | |
| All Rights Reserved
 | |
| 
 | |
| See LICENSE for the license information
 | |
| 
 | |
| Parser to get the interface of a C++ source file
 | |
| Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar and Frank Dellaert
 | |
| """
 | |
| import os
 | |
| import sys
 | |
| 
 | |
| from pyparsing import (
 | |
|     alphas,
 | |
|     alphanums,
 | |
|     cppStyleComment,
 | |
|     delimitedList,
 | |
|     empty,
 | |
|     nums,
 | |
|     stringEnd,
 | |
|     CharsNotIn,
 | |
|     Forward,
 | |
|     Group,
 | |
|     Keyword,
 | |
|     Literal,
 | |
|     OneOrMore,
 | |
|     Optional,
 | |
|     Or,
 | |
|     ParseException,
 | |
|     ParserElement,
 | |
|     Suppress,
 | |
|     Word,
 | |
|     ZeroOrMore,
 | |
| )
 | |
| 
 | |
| ParserElement.enablePackrat()
 | |
| 
 | |
| IDENT = Word(alphas + '_', alphanums + '_') ^ Word(nums)
 | |
| POINTER, REF = map(Literal, "*&")
 | |
| LPAREN, RPAREN, LBRACE, RBRACE, COLON, SEMI_COLON = map(Suppress, "(){}:;")
 | |
| LOPBRACK, ROPBRACK, COMMA, EQUAL = map(Suppress, "<>,=")
 | |
| CONST, VIRTUAL, CLASS, STATIC, PAIR, TEMPLATE, TYPEDEF, INCLUDE = map(
 | |
|     Keyword,
 | |
|     [
 | |
|         "const",
 | |
|         "virtual",
 | |
|         "class",
 | |
|         "static",
 | |
|         "pair",
 | |
|         "template",
 | |
|         "typedef",
 | |
|         "#include",
 | |
|     ],
 | |
| )
 | |
| NAMESPACE = Keyword("namespace")
 | |
| BASIS_TYPES = map(
 | |
|     Keyword,
 | |
|     [
 | |
|         "void",
 | |
|         "bool",
 | |
|         "unsigned char",
 | |
|         "char",
 | |
|         "int",
 | |
|         "size_t",
 | |
|         "double",
 | |
|         "float",
 | |
|         "string",
 | |
|     ],
 | |
| )
 | |
| 
 | |
| 
 | |
| class Typename(object):
 | |
|     """
 | |
|     Type's name with full namespaces.
 | |
|     """
 | |
| 
 | |
|     namespaces_name_rule = delimitedList(IDENT, "::")
 | |
|     instantiation_name_rule = delimitedList(IDENT, "::")
 | |
|     rule = Forward()
 | |
| 
 | |
|     rule << (
 | |
|         namespaces_name_rule("namespaces_name")
 | |
|         + Optional(
 | |
|             (LOPBRACK + delimitedList(rule, ",")("instantiations") + ROPBRACK)
 | |
|         )
 | |
|     ).setParseAction(lambda t: Typename(t.namespaces_name, t.instantiations))
 | |
| 
 | |
|     def __init__(self, namespaces_name, instantiations=[]):
 | |
|         self.namespaces = namespaces_name[:-1]
 | |
|         self.name = namespaces_name[-1]
 | |
| 
 | |
|         if instantiations:
 | |
|             if not isinstance(instantiations, list):
 | |
|                 self.instantiations = instantiations.asList()
 | |
|             else:
 | |
|                 self.instantiations = instantiations
 | |
|         else:
 | |
|             self.instantiations = []
 | |
|         if self.name in ["Matrix", "Vector"] and not self.namespaces:
 | |
|             self.namespaces = ["gtsam"]
 | |
| 
 | |
|     @staticmethod
 | |
|     def from_parse_result(parse_result):
 | |
|         return parse_result[0]
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return self.to_cpp()
 | |
| 
 | |
|     def instantiated_name(self):
 | |
|         res = self.name
 | |
|         for instantiation in self.instantiations:
 | |
|             res += instantiation.instantiated_name()
 | |
|         return res
 | |
| 
 | |
|     def to_cpp(self):
 | |
|         idx = 1 if self.namespaces and not self.namespaces[0] else 0
 | |
|         if self.instantiations:
 | |
|             cpp_name = self.name + "<{}>".format(
 | |
|                 ", ".join([inst.to_cpp() for inst in self.instantiations])
 | |
|             )
 | |
|         else:
 | |
|             cpp_name = self.name
 | |
|         return '{}{}{}'.format(
 | |
|             "::".join(self.namespaces[idx:]),
 | |
|             "::" if self.namespaces[idx:] else "",
 | |
|             cpp_name,
 | |
|         )
 | |
| 
 | |
|     def __eq__(self, other):
 | |
|         if isinstance(other, Typename):
 | |
|             return str(self) == str(other)
 | |
|         else:
 | |
|             return NotImplemented
 | |
| 
 | |
|     def __ne__(self, other):
 | |
|         res = self.__eq__(other)
 | |
|         if res is NotImplemented:
 | |
|             return res
 | |
|         return not res
 | |
| 
 | |
| 
 | |
| class Type(object):
 | |
|     class _QualifiedType(object):
 | |
|         """
 | |
|         Type with qualifiers.
 | |
|         """
 | |
| 
 | |
|         rule = (
 | |
|             Optional(CONST("is_const"))
 | |
|             + Typename.rule("typename")
 | |
|             + Optional(POINTER("is_ptr") | REF("is_ref"))
 | |
|         ).setParseAction(
 | |
|             lambda t: Type._QualifiedType(
 | |
|                 Typename.from_parse_result(t.typename),
 | |
|                 t.is_const,
 | |
|                 t.is_ptr,
 | |
|                 t.is_ref,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         def __init__(self, typename, is_const, is_ptr, is_ref):
 | |
|             self.typename = typename
 | |
|             self.is_const = is_const
 | |
|             self.is_ptr = is_ptr
 | |
|             self.is_ref = is_ref
 | |
| 
 | |
|     class _BasisType(object):
 | |
|         """
 | |
|         Basis types don't have qualifiers and only allow copy-by-value.
 | |
|         """
 | |
| 
 | |
|         rule = Or(BASIS_TYPES).setParseAction(lambda t: Typename(t))
 | |
| 
 | |
|     rule = (
 | |
|         _BasisType.rule("basis") | _QualifiedType.rule("qualified")  # BR
 | |
|     ).setParseAction(lambda t: Type.from_parse_result(t))
 | |
| 
 | |
|     def __init__(self, typename, is_const, is_ptr, is_ref, is_basis):
 | |
|         self.typename = typename
 | |
|         self.is_const = is_const
 | |
|         self.is_ptr = is_ptr
 | |
|         self.is_ref = is_ref
 | |
|         self.is_basis = is_basis
 | |
| 
 | |
|     @staticmethod
 | |
|     def from_parse_result(t):
 | |
|         if t.basis:
 | |
|             return Type(
 | |
|                 typename=t.basis,
 | |
|                 is_const='',
 | |
|                 is_ptr='',
 | |
|                 is_ref='',
 | |
|                 is_basis=True,
 | |
|             )
 | |
|         elif t.qualified:
 | |
|             return Type(
 | |
|                 typename=t.qualified.typename,
 | |
|                 is_const=t.qualified.is_const,
 | |
|                 is_ptr=t.qualified.is_ptr,
 | |
|                 is_ref=t.qualified.is_ref,
 | |
|                 is_basis=False,
 | |
|             )
 | |
|         else:
 | |
|             raise ValueError("Parse result is not a Type?")
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '{} {}{}{}'.format(
 | |
|             self.typename, self.is_const, self.is_ptr, self.is_ref
 | |
|         )
 | |
| 
 | |
|     def to_cpp(self, use_boost):
 | |
|         """
 | |
|         Treat all pointers as "const shared_ptr<T>&"
 | |
|         Treat Matrix and Vector as "const Matrix&" and "const Vector&" resp.
 | |
|         """
 | |
|         shared_ptr_ns = "boost" if use_boost else "std"
 | |
|         return (
 | |
|             "{const} {shared_ptr}{typename}"
 | |
|             "{shared_ptr_ropbracket}{ref}".format(
 | |
|                 const="const"
 | |
|                 if self.is_const
 | |
|                 or self.is_ptr
 | |
|                 or self.typename.name in ["Matrix", "Vector"]
 | |
|                 else "",
 | |
|                 typename=self.typename.to_cpp(),
 | |
|                 shared_ptr="{}::shared_ptr<".format(shared_ptr_ns)
 | |
|                 if self.is_ptr
 | |
|                 else "",
 | |
|                 shared_ptr_ropbracket=">" if self.is_ptr else "",
 | |
|                 ref="&"
 | |
|                 if self.is_ref
 | |
|                 or self.is_ptr
 | |
|                 or self.typename.name in ["Matrix", "Vector"]
 | |
|                 else "",
 | |
|             )
 | |
|         )
 | |
| 
 | |
| 
 | |
| class Argument(object):
 | |
|     rule = (Type.rule("ctype") + IDENT("name")).setParseAction(
 | |
|         lambda t: Argument(t.ctype, t.name)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, ctype, name):
 | |
|         self.ctype = ctype
 | |
|         self.name = name
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '{} {}'.format(self.ctype.__repr__(), self.name)
 | |
| 
 | |
| 
 | |
| class ArgumentList(object):
 | |
|     rule = Optional(delimitedList(Argument.rule)("args_list")).setParseAction(
 | |
|         lambda t: ArgumentList.from_parse_result(t.args_list)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, args_list):
 | |
|         self.args_list = args_list
 | |
|         for arg in args_list:
 | |
|             arg.parent = self
 | |
| 
 | |
|     @staticmethod
 | |
|     def from_parse_result(parse_result):
 | |
|         if parse_result:
 | |
|             return ArgumentList(parse_result.asList())
 | |
|         else:
 | |
|             return ArgumentList([])
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return self.args_list.__repr__()
 | |
| 
 | |
|     def args_names(self):
 | |
|         return [arg.name for arg in self.args_list]
 | |
| 
 | |
|     def to_cpp(self, use_boost):
 | |
|         return [arg.ctype.to_cpp(use_boost) for arg in self.args_list]
 | |
| 
 | |
| 
 | |
| class ReturnType(object):
 | |
|     _pair = (
 | |
|         PAIR.suppress()
 | |
|         + LOPBRACK
 | |
|         + Type.rule("type1")
 | |
|         + COMMA
 | |
|         + Type.rule("type2")
 | |
|         + ROPBRACK
 | |
|     )
 | |
|     rule = (_pair ^ Type.rule("type1")).setParseAction(  # BR
 | |
|         lambda t: ReturnType(t.type1, t.type2)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, type1, type2):
 | |
|         self.type1 = type1
 | |
|         self.type2 = type2
 | |
| 
 | |
|     def is_void(self):
 | |
|         return self.type1.typename.name == "void" and not self.type2
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "{}{}".format(
 | |
|             self.type1, (', ' + self.type2.__repr__()) if self.type2 else ''
 | |
|         )
 | |
| 
 | |
|     def to_cpp(self):
 | |
|         if self.type2:
 | |
|             return "std::pair<{type1},{type2}>".format(
 | |
|                 type1=self.type1.to_cpp(), type2=self.type2.to_cpp()
 | |
|             )
 | |
|         else:
 | |
|             return self.type1.to_cpp()
 | |
| 
 | |
| 
 | |
| class Template(object):
 | |
|     class TypenameAndInstantiations(object):
 | |
|         rule = (
 | |
|             IDENT("typename")
 | |
|             + Optional(
 | |
|                 EQUAL
 | |
|                 + LBRACE
 | |
|                 + ((delimitedList(Typename.rule)("instantiations")))
 | |
|                 + RBRACE
 | |
|             )
 | |
|         ).setParseAction(
 | |
|             lambda t: Template.TypenameAndInstantiations(
 | |
|                 t.typename, t.instantiations
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         def __init__(self, typename, instantiations):
 | |
|             self.typename = typename
 | |
| 
 | |
|             if instantiations:
 | |
|                 self.instantiations = instantiations.asList()
 | |
|             else:
 | |
|                 self.instantiations = []
 | |
| 
 | |
|     rule = (  # BR
 | |
|         TEMPLATE
 | |
|         + LOPBRACK
 | |
|         + delimitedList(TypenameAndInstantiations.rule)(
 | |
|             "typename_and_instantiations_list"
 | |
|         )
 | |
|         + ROPBRACK  # BR
 | |
|     ).setParseAction(
 | |
|         lambda t: Template(t.typename_and_instantiations_list.asList())
 | |
|     )
 | |
| 
 | |
|     def __init__(self, typename_and_instantiations_list):
 | |
|         ti_list = typename_and_instantiations_list
 | |
|         self.typenames = [ti.typename for ti in ti_list]
 | |
|         self.instantiations = [ti.instantiations for ti in ti_list]
 | |
| 
 | |
| 
 | |
| class Method(object):
 | |
|     rule = (
 | |
|         Optional(Template.rule("template"))
 | |
|         + ReturnType.rule("return_type")
 | |
|         + IDENT("name")
 | |
|         + LPAREN
 | |
|         + ArgumentList.rule("args_list")
 | |
|         + RPAREN
 | |
|         + Optional(CONST("is_const"))
 | |
|         + SEMI_COLON  # BR
 | |
|     ).setParseAction(
 | |
|         lambda t: Method(
 | |
|             t.template, t.name, t.return_type, t.args_list, t.is_const
 | |
|         )
 | |
|     )
 | |
| 
 | |
|     def __init__(self, template, name, return_type, args, is_const, parent=''):
 | |
|         self.template = template
 | |
|         self.name = name
 | |
|         self.return_type = return_type
 | |
|         self.args = args
 | |
|         self.is_const = is_const
 | |
| 
 | |
|         self.parent = parent
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "Method: {} {} {}({}){}".format(
 | |
|             self.template,
 | |
|             self.return_type,
 | |
|             self.name,
 | |
|             self.args,
 | |
|             self.is_const,
 | |
|         )
 | |
| 
 | |
| 
 | |
| class StaticMethod(object):
 | |
|     rule = (
 | |
|         STATIC
 | |
|         + ReturnType.rule("return_type")
 | |
|         + IDENT("name")
 | |
|         + LPAREN
 | |
|         + ArgumentList.rule("args_list")
 | |
|         + RPAREN
 | |
|         + SEMI_COLON  # BR
 | |
|     ).setParseAction(
 | |
|         lambda t: StaticMethod(t.name, t.return_type, t.args_list)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, name, return_type, args, parent=''):
 | |
|         self.name = name
 | |
|         self.return_type = return_type
 | |
|         self.args = args
 | |
| 
 | |
|         self.parent = parent
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "static {} {}{}".format(self.return_type, self.name, self.args)
 | |
| 
 | |
|     def to_cpp(self):
 | |
|         return self.name
 | |
| 
 | |
| 
 | |
| class Constructor(object):
 | |
|     rule = (
 | |
|         IDENT("name")
 | |
|         + LPAREN
 | |
|         + ArgumentList.rule("args_list")
 | |
|         + RPAREN
 | |
|         + SEMI_COLON  # BR
 | |
|     ).setParseAction(lambda t: Constructor(t.name, t.args_list))
 | |
| 
 | |
|     def __init__(self, name, args, parent=''):
 | |
|         self.name = name
 | |
|         self.args = args
 | |
| 
 | |
|         self.parent = parent
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "Constructor: {}".format(self.name)
 | |
| 
 | |
| 
 | |
| class Property(object):
 | |
|     rule = (Type.rule("ctype") + IDENT("name") + SEMI_COLON).setParseAction(
 | |
|         lambda t: Property(t.ctype, t.name)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, ctype, name, parent=''):
 | |
|         self.ctype = ctype
 | |
|         self.name = name
 | |
|         # Check type constraints: no pointer, no ref.
 | |
|         if self.ctype.is_ptr or self.ctype.is_ref:
 | |
|             raise ValueError("Can't deal with pointer/ref class properties.")
 | |
| 
 | |
|         self.parent = parent
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '{} {}'.format(self.ctype.__repr__(), self.name)
 | |
| 
 | |
| 
 | |
| def collect_namespaces(obj):
 | |
|     namespaces = []
 | |
|     ancestor = obj.parent
 | |
|     while ancestor and ancestor.name:
 | |
|         namespaces = [ancestor.name] + namespaces
 | |
|         ancestor = ancestor.parent
 | |
|     return [''] + namespaces
 | |
| 
 | |
| 
 | |
| class Class(object):
 | |
|     class MethodsAndProperties(object):
 | |
|         rule = ZeroOrMore(
 | |
|             Constructor.rule ^ StaticMethod.rule ^ Method.rule ^ Property.rule
 | |
|         ).setParseAction(lambda t: Class.MethodsAndProperties(t.asList()))
 | |
| 
 | |
|         def __init__(self, methods_props):
 | |
|             self.ctors = []
 | |
|             self.methods = []
 | |
|             self.static_methods = []
 | |
|             self.properties = []
 | |
|             for m in methods_props:
 | |
|                 if isinstance(m, Constructor):
 | |
|                     self.ctors.append(m)
 | |
|                 elif isinstance(m, Method):
 | |
|                     self.methods.append(m)
 | |
|                 elif isinstance(m, StaticMethod):
 | |
|                     self.static_methods.append(m)
 | |
|                 elif isinstance(m, Property):
 | |
|                     self.properties.append(m)
 | |
| 
 | |
|     _parent = COLON + Typename.rule("parent_class")
 | |
|     rule = (
 | |
|         Optional(Template.rule("template"))
 | |
|         + Optional(VIRTUAL("is_virtual"))
 | |
|         + CLASS
 | |
|         + IDENT("name")
 | |
|         + Optional(_parent)
 | |
|         + LBRACE
 | |
|         + MethodsAndProperties.rule("methods_props")
 | |
|         + RBRACE
 | |
|         + SEMI_COLON  # BR
 | |
|     ).setParseAction(
 | |
|         lambda t: Class(
 | |
|             t.template,
 | |
|             t.is_virtual,
 | |
|             t.name,
 | |
|             t.parent_class,
 | |
|             t.methods_props.ctors,
 | |
|             t.methods_props.methods,
 | |
|             t.methods_props.static_methods,
 | |
|             t.methods_props.properties,
 | |
|         )
 | |
|     )
 | |
| 
 | |
|     def __init__(
 | |
|         self,
 | |
|         template,
 | |
|         is_virtual,
 | |
|         name,
 | |
|         parent_class,
 | |
|         ctors,
 | |
|         methods,
 | |
|         static_methods,
 | |
|         properties,
 | |
|         parent='',
 | |
|     ):
 | |
|         self.template = template
 | |
|         self.is_virtual = is_virtual
 | |
|         self.name = name
 | |
|         if parent_class:
 | |
|             self.parent_class = Typename.from_parse_result(parent_class)
 | |
|         else:
 | |
|             self.parent_class = ''
 | |
| 
 | |
|         self.ctors = ctors
 | |
|         self.methods = methods
 | |
|         self.static_methods = static_methods
 | |
|         self.properties = properties
 | |
|         self.parent = parent
 | |
|         # Make sure ctors' names and class name are the same.
 | |
|         for ctor in self.ctors:
 | |
|             if ctor.name != self.name:
 | |
|                 raise ValueError(
 | |
|                     "Error in constructor name! {} != {}".format(
 | |
|                         ctor.name, self.name
 | |
|                     )
 | |
|                 )
 | |
| 
 | |
|         for ctor in self.ctors:
 | |
|             ctor.parent = self
 | |
|         for method in self.methods:
 | |
|             method.parent = self
 | |
|         for static_method in self.static_methods:
 | |
|             static_method.parent = self
 | |
|         for _property in self.properties:
 | |
|             _property.parent = self
 | |
| 
 | |
|     def namespaces(self):
 | |
|         return collect_namespaces(self)
 | |
| 
 | |
| 
 | |
| class TypedefTemplateInstantiation(object):
 | |
|     rule = (
 | |
|         TYPEDEF + Typename.rule("typename") + IDENT("new_name") + SEMI_COLON
 | |
|     ).setParseAction(
 | |
|         lambda t: TypedefTemplateInstantiation(
 | |
|             Typename.from_parse_result(t.typename), t.new_name
 | |
|         )
 | |
|     )
 | |
| 
 | |
|     def __init__(self, typename, new_name, parent=''):
 | |
|         self.typename = typename
 | |
|         self.new_name = new_name
 | |
|         self.parent = parent
 | |
| 
 | |
| 
 | |
| class Include(object):
 | |
|     rule = (
 | |
|         INCLUDE + LOPBRACK + CharsNotIn('>')("header") + ROPBRACK
 | |
|     ).setParseAction(lambda t: Include(t.header))
 | |
| 
 | |
|     def __init__(self, header, parent=''):
 | |
|         self.header = header
 | |
|         self.parent = parent
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "#include <{}>".format(self.header)
 | |
| 
 | |
| 
 | |
| class ForwardDeclaration(object):
 | |
|     rule = (
 | |
|         Optional(VIRTUAL("is_virtual"))
 | |
|         + CLASS
 | |
|         + Typename.rule("name")
 | |
|         + Optional(COLON + Typename.rule("parent_type"))
 | |
|         + SEMI_COLON
 | |
|     ).setParseAction(
 | |
|         lambda t: ForwardDeclaration(t.is_virtual, t.name, t.parent_type)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, is_virtual, name, parent_type, parent=''):
 | |
|         self.is_virtual = is_virtual
 | |
|         self.name = name
 | |
|         if parent_type:
 | |
|             self.parent_type = Typename.from_parse_result(parent_type)
 | |
|         else:
 | |
|             self.parent_type = ''
 | |
|         self.parent = parent
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "ForwardDeclaration: {} {}({})".format(
 | |
|             self.is_virtual, self.name, self.parent
 | |
|         )
 | |
| 
 | |
| 
 | |
| class GlobalFunction(object):
 | |
|     rule = (
 | |
|         ReturnType.rule("return_type")
 | |
|         + IDENT("name")
 | |
|         + LPAREN
 | |
|         + ArgumentList.rule("args_list")
 | |
|         + RPAREN
 | |
|         + SEMI_COLON
 | |
|     ).setParseAction(
 | |
|         lambda t: GlobalFunction(t.name, t.return_type, t.args_list)
 | |
|     )
 | |
| 
 | |
|     def __init__(self, name, return_type, args_list, parent=''):
 | |
|         self.name = name
 | |
|         self.return_type = return_type
 | |
|         self.args = args_list
 | |
|         self.is_const = None
 | |
| 
 | |
|         self.parent = parent
 | |
|         self.return_type.parent = self
 | |
|         self.args.parent = self
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "GlobalFunction:  {}{}({})".format(
 | |
|             self.return_type, self.name, self.args
 | |
|         )
 | |
| 
 | |
|     def to_cpp(self):
 | |
|         return self.name
 | |
| 
 | |
| 
 | |
| def find_sub_namespace(namespace, str_namespaces):
 | |
|     if not str_namespaces:
 | |
|         return [namespace]
 | |
| 
 | |
|     sub_namespaces = (
 | |
|         ns for ns in namespace.content if isinstance(ns, Namespace)
 | |
|     )
 | |
| 
 | |
|     found_namespaces = [
 | |
|         ns for ns in sub_namespaces if ns.name == str_namespaces[0]
 | |
|     ]
 | |
|     if not found_namespaces:
 | |
|         return None
 | |
| 
 | |
|     res = []
 | |
|     for found_namespace in found_namespaces:
 | |
|         ns = find_sub_namespace(found_namespace, str_namespaces[1:])
 | |
|         if ns:
 | |
|             res += ns
 | |
|     return res
 | |
| 
 | |
| 
 | |
| class Namespace(object):
 | |
|     rule = Forward()
 | |
|     rule << (
 | |
|         NAMESPACE
 | |
|         + IDENT("name")
 | |
|         + LBRACE
 | |
|         + ZeroOrMore(  # BR
 | |
|             ForwardDeclaration.rule
 | |
|             ^ Include.rule
 | |
|             ^ Class.rule
 | |
|             ^ TypedefTemplateInstantiation.rule
 | |
|             ^ GlobalFunction.rule
 | |
|             ^ rule
 | |
|         )(
 | |
|             "content"
 | |
|         )  # BR
 | |
|         + RBRACE
 | |
|     ).setParseAction(lambda t: Namespace.from_parse_result(t))
 | |
| 
 | |
|     def __init__(self, name, content, parent=''):
 | |
|         self.name = name
 | |
|         self.content = content
 | |
|         self.parent = parent
 | |
|         for child in self.content:
 | |
|             child.parent = self
 | |
| 
 | |
|     @staticmethod
 | |
|     def from_parse_result(t):
 | |
|         if t.content:
 | |
|             content = t.content.asList()
 | |
|         else:
 | |
|             content = []
 | |
|         return Namespace(t.name, content)
 | |
| 
 | |
|     def find_class(self, typename):
 | |
|         """
 | |
|         Find the Class object given its typename.
 | |
|         We have to traverse the tree of namespaces.
 | |
|         """
 | |
|         found_namespaces = find_sub_namespace(self, typename.namespaces)
 | |
|         res = []
 | |
|         for namespace in found_namespaces:
 | |
|             classes = (c for c in namespace.content if isinstance(c, Class))
 | |
|             res += [c for c in classes if c.name == typename.name]
 | |
|         if not res:
 | |
|             raise ValueError(
 | |
|                 "Cannot find class {} in module!".format(typename.name)
 | |
|             )
 | |
|         elif len(res) > 1:
 | |
|             raise ValueError(
 | |
|                 "Found more than one classes {} in module!".format(
 | |
|                     typename.name
 | |
|                 )
 | |
|             )
 | |
|         else:
 | |
|             return res[0]
 | |
| 
 | |
|     def top_level(self):
 | |
|         if self.name == '' or self.parent == '':
 | |
|             return self
 | |
|         else:
 | |
|             return self.parent.top_level()
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return "Namespace: {}\n\t{}".format(self.name, self.content)
 | |
| 
 | |
|     def full_namespaces(self):
 | |
|         ancestors = collect_namespaces(self)
 | |
|         if self.name:
 | |
|             ancestors.append(self.name)
 | |
|         return ancestors
 | |
| 
 | |
| 
 | |
| class Module(object):
 | |
|     """
 | |
|     Module is just a global namespace.
 | |
|     """
 | |
| 
 | |
|     rule = (
 | |
|         ZeroOrMore(
 | |
|             ForwardDeclaration.rule
 | |
|             ^ Include.rule
 | |
|             ^ Class.rule
 | |
|             ^ TypedefTemplateInstantiation.rule
 | |
|             ^ GlobalFunction.rule
 | |
|             ^ Namespace.rule
 | |
|         ).setParseAction(lambda t: Namespace('', t.asList()))
 | |
|         + stringEnd
 | |
|     )
 | |
| 
 | |
|     rule.ignore(cppStyleComment)
 | |
| 
 | |
|     @staticmethod
 | |
|     def parseString(str):
 | |
|         return Module.rule.parseString(str)[0]
 |