283 lines
7.6 KiB
Python
283 lines
7.6 KiB
Python
"""
|
|
GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
|
|
Atlanta, Georgia 30332-0415
|
|
All Rights Reserved
|
|
|
|
See LICENSE for the license information
|
|
|
|
Parser classes and rules for parsing C++ classes.
|
|
|
|
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
|
|
"""
|
|
|
|
from typing import List, Union
|
|
|
|
from pyparsing import Optional, ZeroOrMore
|
|
|
|
from .function import ArgumentList, ReturnType
|
|
from .template import Template
|
|
from .tokens import (CLASS, COLON, CONST, IDENT, LBRACE, LPAREN, RBRACE,
|
|
RPAREN, SEMI_COLON, STATIC, VIRTUAL)
|
|
from .type import Type, Typename
|
|
|
|
|
|
class Method:
|
|
"""
|
|
Rule to parse a method in a class.
|
|
|
|
E.g.
|
|
```
|
|
class Hello {
|
|
void sayHello() const;
|
|
};
|
|
```
|
|
"""
|
|
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: str,
|
|
name: str,
|
|
return_type: ReturnType,
|
|
args: ArgumentList,
|
|
is_const: str,
|
|
parent: Union[str, "Class"] = ''):
|
|
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) -> str:
|
|
return "Method: {} {} {}({}){}".format(
|
|
self.template,
|
|
self.return_type,
|
|
self.name,
|
|
self.args,
|
|
self.is_const,
|
|
)
|
|
|
|
|
|
class StaticMethod:
|
|
"""
|
|
Rule to parse all the static methods in a class.
|
|
|
|
E.g.
|
|
```
|
|
class Hello {
|
|
static void changeGreeting();
|
|
};
|
|
```
|
|
"""
|
|
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: str,
|
|
return_type: ReturnType,
|
|
args: ArgumentList,
|
|
parent: Union[str, "Class"] = ''):
|
|
self.name = name
|
|
self.return_type = return_type
|
|
self.args = args
|
|
|
|
self.parent = parent
|
|
|
|
def __repr__(self) -> str:
|
|
return "static {} {}{}".format(self.return_type, self.name, self.args)
|
|
|
|
def to_cpp(self) -> str:
|
|
"""Generate the C++ code for wrapping."""
|
|
return self.name
|
|
|
|
|
|
class Constructor:
|
|
"""
|
|
Rule to parse the class constructor.
|
|
Can have 0 or more arguments.
|
|
"""
|
|
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: str,
|
|
args: ArgumentList,
|
|
parent: Union["Class", str] = ''):
|
|
self.name = name
|
|
self.args = args
|
|
|
|
self.parent = parent
|
|
|
|
def __repr__(self) -> str:
|
|
return "Constructor: {}".format(self.name)
|
|
|
|
|
|
class Property:
|
|
"""
|
|
Rule to parse the variable members of a class.
|
|
|
|
E.g.
|
|
```
|
|
class Hello {
|
|
string name; // This is a property.
|
|
};
|
|
````
|
|
"""
|
|
rule = (
|
|
Type.rule("ctype") #
|
|
+ IDENT("name") #
|
|
+ SEMI_COLON #
|
|
).setParseAction(lambda t: Property(t.ctype, t.name))
|
|
|
|
def __init__(self, ctype: Type, name: str, parent=''):
|
|
self.ctype = ctype
|
|
self.name = name
|
|
self.parent = parent
|
|
|
|
def __repr__(self) -> str:
|
|
return '{} {}'.format(self.ctype.__repr__(), self.name)
|
|
|
|
|
|
def collect_namespaces(obj):
|
|
"""
|
|
Get the chain of namespaces from the lowest to highest for the given object.
|
|
|
|
Args:
|
|
obj: Object of type Namespace, Class or InstantiatedClass.
|
|
"""
|
|
namespaces = []
|
|
ancestor = obj.parent
|
|
while ancestor and ancestor.name:
|
|
namespaces = [ancestor.name] + namespaces
|
|
ancestor = ancestor.parent
|
|
return [''] + namespaces
|
|
|
|
|
|
class Class:
|
|
"""
|
|
Rule to parse a class defined in the interface file.
|
|
|
|
E.g.
|
|
```
|
|
class Hello {
|
|
...
|
|
};
|
|
```
|
|
"""
|
|
class MethodsAndProperties:
|
|
"""
|
|
Rule for all the methods and properties within a class.
|
|
"""
|
|
rule = ZeroOrMore(Constructor.rule ^ StaticMethod.rule ^ Method.rule
|
|
^ Property.rule).setParseAction(
|
|
lambda t: Class.MethodsAndProperties(t.asList()))
|
|
|
|
def __init__(self, methods_props: List[Union[Constructor, Method,
|
|
StaticMethod, Property]]):
|
|
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: Template,
|
|
is_virtual: str,
|
|
name: str,
|
|
parent_class: list,
|
|
ctors: List[Constructor],
|
|
methods: List[Method],
|
|
static_methods: List[StaticMethod],
|
|
properties: List[Property],
|
|
parent: str = '',
|
|
):
|
|
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) -> list:
|
|
"""Get the namespaces which this class is nested under as a list."""
|
|
return collect_namespaces(self)
|
|
|
|
def __repr__(self):
|
|
return "Class: {self.name}".format(self=self)
|