133 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
"""
 | 
						|
GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
 | 
						|
Atlanta, Georgia 30332-0415
 | 
						|
All Rights Reserved
 | 
						|
 | 
						|
See LICENSE for the license information
 | 
						|
 | 
						|
Classes and rules to parse a namespace.
 | 
						|
 | 
						|
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
 | 
						|
"""
 | 
						|
 | 
						|
# pylint: disable=unnecessary-lambda, expression-not-assigned
 | 
						|
 | 
						|
from typing import List, Union
 | 
						|
 | 
						|
from pyparsing import Forward, ParseResults, ZeroOrMore  # type: ignore
 | 
						|
 | 
						|
from .classes import Class, collect_namespaces
 | 
						|
from .declaration import ForwardDeclaration, Include
 | 
						|
from .enum import Enum
 | 
						|
from .function import GlobalFunction
 | 
						|
from .template import TypedefTemplateInstantiation
 | 
						|
from .tokens import IDENT, LBRACE, NAMESPACE, RBRACE
 | 
						|
from .type import Typename
 | 
						|
from .variable import Variable
 | 
						|
 | 
						|
 | 
						|
def find_sub_namespace(namespace: "Namespace",
 | 
						|
                       str_namespaces: List["Namespace"]) -> list:
 | 
						|
    """
 | 
						|
    Get the namespaces nested under `namespace`, filtered by a list of namespace strings.
 | 
						|
 | 
						|
    Args:
 | 
						|
        namespace: The top-level namespace under which to find sub-namespaces.
 | 
						|
        str_namespaces: The list of namespace strings to filter against.
 | 
						|
    """
 | 
						|
    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 []
 | 
						|
 | 
						|
    res = []
 | 
						|
    for found_namespace in found_namespaces:
 | 
						|
        ns = find_sub_namespace(found_namespace, str_namespaces[1:])
 | 
						|
        if ns:
 | 
						|
            res += ns
 | 
						|
    return res
 | 
						|
 | 
						|
 | 
						|
class Namespace:
 | 
						|
    """Rule for parsing a namespace in the interface file."""
 | 
						|
 | 
						|
    rule = Forward()
 | 
						|
    rule << (
 | 
						|
        NAMESPACE  #
 | 
						|
        + IDENT("name")  #
 | 
						|
        + LBRACE  #
 | 
						|
        + ZeroOrMore(  # BR
 | 
						|
            ForwardDeclaration.rule  #
 | 
						|
            ^ Include.rule  #
 | 
						|
            ^ Class.rule  #
 | 
						|
            ^ TypedefTemplateInstantiation.rule  #
 | 
						|
            ^ GlobalFunction.rule  #
 | 
						|
            ^ Enum.rule  #
 | 
						|
            ^ Variable.rule  #
 | 
						|
            ^ rule  #
 | 
						|
        )("content")  # BR
 | 
						|
        + RBRACE  #
 | 
						|
    ).setParseAction(lambda t: Namespace.from_parse_result(t))
 | 
						|
 | 
						|
    def __init__(self, name: str, content: ZeroOrMore, parent=''):
 | 
						|
        self.name = name
 | 
						|
        self.content = content
 | 
						|
        self.parent = parent
 | 
						|
        for child in self.content:
 | 
						|
            child.parent = self
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def from_parse_result(t: ParseResults):
 | 
						|
        """Return the result of parsing."""
 | 
						|
        if t.content:
 | 
						|
            content = t.content.asList()
 | 
						|
        else:
 | 
						|
            content = []
 | 
						|
        return Namespace(t.name, content)
 | 
						|
 | 
						|
    def find_class_or_function(
 | 
						|
            self, typename: Typename) -> Union[Class, GlobalFunction, ForwardDeclaration]:
 | 
						|
        """
 | 
						|
        Find the Class or GlobalFunction 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_and_funcs = (c for c in namespace.content
 | 
						|
                                 if isinstance(c, (Class, GlobalFunction, ForwardDeclaration)))
 | 
						|
            res += [c for c in classes_and_funcs 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) -> "Namespace":
 | 
						|
        """Return the top level namespace."""
 | 
						|
        if self.name == '' or self.parent == '':
 | 
						|
            return self
 | 
						|
        else:
 | 
						|
            return self.parent.top_level()
 | 
						|
 | 
						|
    def __repr__(self) -> str:
 | 
						|
        return "Namespace: {}\n\t{}".format(self.name, self.content)
 | 
						|
 | 
						|
    def full_namespaces(self) -> List["Namespace"]:
 | 
						|
        """Get the full namespace list."""
 | 
						|
        ancestors = collect_namespaces(self)
 | 
						|
        if self.name:
 | 
						|
            ancestors.append(self.name)
 | 
						|
        return ancestors
 |