189 lines
5.9 KiB
Python
189 lines
5.9 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++ functions.
|
|
|
|
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
|
|
"""
|
|
|
|
from typing import Any, Iterable, List, Union
|
|
|
|
from pyparsing import Optional, ParseResults, delimitedList # type: ignore
|
|
|
|
from .template import Template
|
|
from .tokens import (COMMA, DEFAULT_ARG, EQUAL, IDENT, LOPBRACK, LPAREN, PAIR,
|
|
ROPBRACK, RPAREN, SEMI_COLON)
|
|
from .type import TemplatedType, Type
|
|
|
|
|
|
class Argument:
|
|
"""
|
|
The type and name of a function/method argument.
|
|
|
|
E.g.
|
|
```
|
|
void sayHello(/*`s` is the method argument with type `const string&`*/ const string& s);
|
|
```
|
|
"""
|
|
rule = ((Type.rule ^ TemplatedType.rule)("ctype") #
|
|
+ IDENT("name") #
|
|
+ Optional(EQUAL + DEFAULT_ARG)("default")
|
|
).setParseAction(lambda t: Argument(
|
|
t.ctype, #
|
|
t.name, #
|
|
t.default[0] if isinstance(t.default, ParseResults) else None))
|
|
|
|
def __init__(self,
|
|
ctype: Union[Type, TemplatedType],
|
|
name: str,
|
|
default: ParseResults = None):
|
|
if isinstance(ctype, Iterable):
|
|
self.ctype = ctype[0] # type: ignore
|
|
else:
|
|
self.ctype = ctype
|
|
self.name = name
|
|
self.default = default
|
|
self.parent: Union[ArgumentList, None] = None
|
|
|
|
def __repr__(self) -> str:
|
|
return self.to_cpp()
|
|
|
|
def to_cpp(self) -> str:
|
|
"""Return full C++ representation of argument."""
|
|
return '{} {}'.format(repr(self.ctype), self.name)
|
|
|
|
|
|
class ArgumentList:
|
|
"""
|
|
List of Argument objects for all arguments in a function.
|
|
"""
|
|
rule = Optional(delimitedList(Argument.rule)("args_list")).setParseAction(
|
|
lambda t: ArgumentList.from_parse_result(t.args_list))
|
|
|
|
def __init__(self, args_list: List[Argument]):
|
|
self.args_list = args_list
|
|
for arg in args_list:
|
|
arg.parent = self
|
|
# The parent object which contains the argument list
|
|
# E.g. Method, StaticMethod, Template, Constructor, GlobalFunction
|
|
self.parent: Any = None
|
|
|
|
@staticmethod
|
|
def from_parse_result(parse_result: ParseResults):
|
|
"""Return the result of parsing."""
|
|
if parse_result:
|
|
return ArgumentList(parse_result.asList())
|
|
else:
|
|
return ArgumentList([])
|
|
|
|
def __repr__(self) -> str:
|
|
return repr(tuple(self.args_list))
|
|
|
|
def __len__(self) -> int:
|
|
return len(self.args_list)
|
|
|
|
def names(self) -> List[str]:
|
|
"""Return a list of the names of all the arguments."""
|
|
return [arg.name for arg in self.args_list]
|
|
|
|
def list(self) -> List[Argument]:
|
|
"""Return a list of the names of all the arguments."""
|
|
return self.args_list
|
|
|
|
def to_cpp(self, use_boost: bool) -> List[str]:
|
|
"""Generate the C++ code for wrapping."""
|
|
return [arg.ctype.to_cpp(use_boost) for arg in self.args_list]
|
|
|
|
|
|
class ReturnType:
|
|
"""
|
|
Rule to parse the return type.
|
|
|
|
The return type can either be a single type or a pair such as <type1, type2>.
|
|
"""
|
|
_pair = (
|
|
PAIR.suppress() #
|
|
+ LOPBRACK #
|
|
+ Type.rule("type1") #
|
|
+ COMMA #
|
|
+ Type.rule("type2") #
|
|
+ ROPBRACK #
|
|
)
|
|
rule = (_pair ^
|
|
(Type.rule ^ TemplatedType.rule)("type1")).setParseAction( # BR
|
|
lambda t: ReturnType(t.type1, t.type2))
|
|
|
|
def __init__(self, type1: Union[Type, TemplatedType], type2: Type):
|
|
# If a TemplatedType, the return is a ParseResults, so we extract out the type.
|
|
self.type1 = type1[0] if isinstance(type1, ParseResults) else type1
|
|
self.type2 = type2
|
|
# The parent object which contains the return type
|
|
# E.g. Method, StaticMethod, Template, Constructor, GlobalFunction
|
|
self.parent: Any = None
|
|
|
|
def is_void(self) -> bool:
|
|
"""
|
|
Check if the return type is void.
|
|
"""
|
|
return self.type1.typename.name == "void" and not self.type2
|
|
|
|
def __repr__(self) -> str:
|
|
return "{}{}".format(
|
|
self.type1, (', ' + self.type2.__repr__()) if self.type2 else '')
|
|
|
|
def to_cpp(self, use_boost: bool) -> str:
|
|
"""
|
|
Generate the C++ code for wrapping.
|
|
|
|
If there are two return types, we return a pair<>,
|
|
otherwise we return the regular return type.
|
|
"""
|
|
if self.type2:
|
|
return "std::pair<{type1},{type2}>".format(
|
|
type1=self.type1.to_cpp(use_boost),
|
|
type2=self.type2.to_cpp(use_boost))
|
|
else:
|
|
return self.type1.to_cpp(use_boost)
|
|
|
|
|
|
class GlobalFunction:
|
|
"""
|
|
Rule to parse functions defined in the global scope.
|
|
"""
|
|
rule = (
|
|
Optional(Template.rule("template")) + ReturnType.rule("return_type") #
|
|
+ IDENT("name") #
|
|
+ LPAREN #
|
|
+ ArgumentList.rule("args_list") #
|
|
+ RPAREN #
|
|
+ SEMI_COLON #
|
|
).setParseAction(lambda t: GlobalFunction(t.name, t.return_type, t.
|
|
args_list, t.template))
|
|
|
|
def __init__(self,
|
|
name: str,
|
|
return_type: ReturnType,
|
|
args_list: ArgumentList,
|
|
template: Template,
|
|
parent: Any = ''):
|
|
self.name = name
|
|
self.return_type = return_type
|
|
self.args = args_list
|
|
self.template = template
|
|
|
|
self.parent = parent
|
|
self.return_type.parent = self
|
|
self.args.parent = self
|
|
|
|
def __repr__(self) -> str:
|
|
return "GlobalFunction: {}{}({})".format(self.return_type, self.name,
|
|
self.args)
|
|
|
|
def to_cpp(self) -> str:
|
|
"""Generate the C++ code for wrapping."""
|
|
return self.name
|