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
|
|
|
|
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]:
|
|
"""
|
|
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)))
|
|
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 leve 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
|