2 GTSAM Copyright 2010-2020, Georgia Tech Research Corporation, 
    3 Atlanta, Georgia 30332-0415 
    6 See LICENSE for the license information 
    8 Parser classes and rules for parsing C++ classes. 
   10 Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert 
   13 from typing 
import Any, Iterable, List, Union
 
   15 from pyparsing 
import ZeroOrMore  
 
   16 from pyparsing 
import Literal, Optional, Word, alphas
 
   18 from .enum 
import Enum
 
   19 from .function 
import ArgumentList, ReturnType
 
   20 from .template 
import Template
 
   21 from .tokens 
import (CLASS, COLON, CONST, DUNDER, IDENT, LBRACE, LPAREN,
 
   22                      OPERATOR, RBRACE, RPAREN, SEMI_COLON, STATIC, VIRTUAL)
 
   23 from .type 
import TemplatedType, Typename
 
   24 from .utils 
import collect_namespaces
 
   25 from .variable 
import Variable
 
   30     Rule to parse a method in a class. 
   35         void sayHello() const; 
   40         Optional(Template.rule(
"template"))  
 
   41         + ReturnType.rule(
"return_type")  
 
   44         + ArgumentList.rule(
"args_list")  
 
   46         + Optional(
CONST(
"is_const"))  
 
   48     ).setParseAction(
lambda t: 
Method(t.template, t.name, t.return_type, t.
 
   49                                       args_list, t.is_const))
 
   52                  template: Union[Template, Any],
 
   54                  return_type: ReturnType,
 
   57                  parent: Union[
"Class", Any] = 
''):
 
   67         """Generate the C++ code for wrapping.""" 
   71         return "Method: {} {} {}({}){}".
format(
 
   82     Rule to parse all the static methods in a class. 
   87         static void changeGreeting(); 
   92         Optional(Template.rule(
"template"))  
 
   94         + ReturnType.rule(
"return_type")  
 
   97         + ArgumentList.rule(
"args_list")  
 
  101         lambda t: 
StaticMethod(t.name, t.return_type, t.args_list, t.template))
 
  105                  return_type: ReturnType,
 
  107                  template: Union[Template, Any] = 
None,
 
  108                  parent: Union[
"Class", Any] = 
''):
 
  120         """Generate the C++ code for wrapping.""" 
  126     Rule to parse the class constructor. 
  127     Can have 0 or more arguments. 
  130         Optional(Template.rule(
"template"))  
 
  133         + ArgumentList.rule(
"args_list")  
 
  136     ).setParseAction(
lambda t: 
Constructor(t.name, t.args_list, t.template))
 
  141                  template: Union[Template, Any],
 
  142                  parent: Union[
"Class", Any] = 
''):
 
  155     Rule for parsing operator overloads. 
  160         Vector2 operator+(const Vector2 &v) const; 
  164         ReturnType.rule(
"return_type")  
 
  165         + Literal(
"operator")(
"name")  
 
  168         + ArgumentList.rule(
"args_list")  
 
  172     ).setParseAction(
lambda t: 
Operator(t.name, t.operator, t.return_type, t.
 
  173                                         args_list, t.is_const))
 
  178                  return_type: ReturnType,
 
  181                  parent: Union[
"Class", Any] = 
''):
 
  193             raise ValueError(
"Invalid unary operator {} used for {}".
format(
 
  197         assert 0 <= 
len(args) < 2, \
 
  198             "Operator overload should be at most 1 argument, " \
 
  199                 "{} arguments provided".
format(
len(args))
 
  202         if len(args) == 1 
and self.
operator not in (
"()", 
"[]"):
 
  203             assert args.list()[0].ctype.typename.name == return_type.type1.typename.name, \
 
  204                 "Mixed type overloading not supported. Both arg and return type must be the same." 
  207         return "Operator: {}{}{}({}) {}".
format(
 
  217     """Special Python double-underscore (dunder) methods, e.g. __iter__, __contains__""" 
  220         + (Word(alphas))(
"name")  
 
  223         + ArgumentList.rule(
"args_list")  
 
  226     ).setParseAction(
lambda t: 
DunderMethod(t.name, t.args_list))
 
  233         return f
"DunderMethod: __{self.name}__({self.args})" 
  238     Rule to parse a class defined in the interface file. 
  250         Rule for all the members within a class. 
  252         rule = ZeroOrMore(DunderMethod.rule  
 
  261         def __init__(self, members: List[Union[Constructor, Method,
 
  262                                                StaticMethod, Variable,
 
  263                                                Operator, Enum, DunderMethod]]):
 
  270             self.enums: List[Enum] = []
 
  287     _parent = COLON + (TemplatedType.rule ^ Typename.rule)(
"parent_class")
 
  289         Optional(Template.rule(
"template"))  
 
  290         + Optional(
VIRTUAL(
"is_virtual"))  
 
  295         + Members.rule(
"members")  
 
  298     ).setParseAction(
lambda t: 
Class(
 
  299         t.template, t.is_virtual, t.name, t.parent_class, t.members.ctors, t.
 
  300         members.methods, t.members.static_methods, t.members.dunder_methods, t.
 
  301         members.properties, t.members.operators, t.members.enums))
 
  305         template: Union[Template, 
None],
 
  309         ctors: List[Constructor],
 
  310         methods: List[Method],
 
  311         static_methods: List[StaticMethod],
 
  312         dunder_methods: List[DunderMethod],
 
  313         properties: List[Variable],
 
  314         operators: List[Operator],
 
  324                 parent_class = parent_class[0]  
 
  346         for ctor 
in self.
ctors:
 
  347             if ctor.name != self.
name:
 
  348                 raise ValueError(
"Error in constructor name! {} != {}".
format(
 
  349                     ctor.name, self.
name))
 
  351         for ctor 
in self.
ctors:
 
  356             static_method.parent = self
 
  358             dunder_method.parent = self
 
  360             _property.parent = self
 
  363         """Get the namespaces which this class is nested under as a list.""" 
  367         return "Class: {self.name}".
format(self=self)