gtsam/wrap/gtwrap/interface_parser/namespace.py

131 lines
4.0 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
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 #
^ 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