""" 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 List, Union from pyparsing import Optional, ParseResults, delimitedList from .template import Template from .tokens import (COMMA, IDENT, LOPBRACK, LPAREN, PAIR, ROPBRACK, RPAREN, SEMI_COLON) from .type import 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("ctype") + IDENT("name")).setParseAction(lambda t: Argument(t.ctype, t.name)) def __init__(self, ctype: Type, name: str): self.ctype = ctype self.name = name self.parent: Union[ArgumentList, None] = None def __repr__(self) -> str: return '{} {}'.format(self.ctype.__repr__(), 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 = 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 self.args_list.__repr__() def __len__(self) -> int: return len(self.args_list) def args_names(self) -> List[str]: """Return a list of the names of all the arguments.""" return [arg.name for arg in 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 . """ _pair = ( PAIR.suppress() # + LOPBRACK # + Type.rule("type1") # + COMMA # + Type.rule("type2") # + ROPBRACK # ) rule = (_pair ^ Type.rule("type1")).setParseAction( # BR lambda t: ReturnType(t.type1, t.type2)) def __init__(self, type1: Type, type2: Type): self.type1 = type1 self.type2 = type2 # The parent object which contains the return type # E.g. Method, StaticMethod, Template, Constructor, GlobalFunction self.parent = 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: str = ''): 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