gtsam/wrap/gtwrap/interface_parser/namespace.py

129 lines
3.9 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 .function import GlobalFunction
from .template import TypedefTemplateInstantiation
from .tokens import IDENT, LBRACE, NAMESPACE, RBRACE
from .type import Typename
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 #
^ 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