Update of /cvsroot/cpptool/rfta/src/pyrfta/test/rfta/parser In directory sc8-pr-cvs1:/tmp/cvs-serv3499/src/pyrfta/test/rfta/parser Added Files: __init__.py alltests.py generateparserdebuginfo.py grammar.py grammartest.py node.py nodetest.py nodetesthelper.py parser.py parsertest.py parsertesthelper.py parsingtracker.py structuredtokenstream.py structuredtokenstreamtest.py token.py tokenizer.py tokenizertest.py Log Message: * added C++ parser in python (without C++ template for the time being), as well as a load of tests. --- NEW FILE: __init__.py --- # module --- NEW FILE: alltests.py --- #!/usr/bin/env python # # Example of assembling all available unit tests into one suite. This usually # varies greatly from one project to the next, so the code shown below will not # be incorporated into the 'unittest' module. Instead, modify it for your own # purposes. # # $Id: alltests.py,v 1.1 2003/08/24 21:00:36 blep Exp $ import unittest import nodetest import parsertest import grammartest import tokenizertest def suite(): alltests = unittest.TestSuite() alltests.addTest(unittest.findTestCases(nodetest)) alltests.addTest(unittest.findTestCases(tokenizertest)) alltests.addTest(unittest.findTestCases(parsertest)) alltests.addTest(unittest.findTestCases(grammartest)) # for module in map(__import__, modules_to_test): # alltests.addTest(unittest.findTestCases(module)) return alltests if __name__ == '__main__': unittest.TextTestRunner().run(suite()) --- NEW FILE: generateparserdebuginfo.py --- # generate parser name for debug import grammar import string for var in dir(grammar): if var.endswith('_p') or var.endswith('_pi'): print "%s.setName( '%s' )" % (var,var) --- NEW FILE: grammar.py --- # c++ grammar from parser import * # IMPORTANT NOTES: # If a parser rule is stored in a variable and is an Alternative or a Sequence parser, then it must be wrapped # in a proxy parser, other the parser rule will be extended when used within another rule. # # my_p = id_p >> '::' >> id_p # BAD # my_p = proxy_f( id_p >> '::' >> id_p ) # GOOD # other_p = my_p >> ',' # in the BAD case, the sequence parser 'my_p' would be extended # Remarks: # Because the grammar does use know declared type, it is not possible to distinguish between: # 1) In the context of an expression: # function call and object instantiation => node(1) may be either a function call, or a object instantiation, # or a functional style conversion # => in this case, the grammar create a 'call_or_conversion_expression' # 2) In the context of a declaration: # function declarator and object instantiation => node n(2); may be either a function declaration or an object instantiation. # => in this case, the grammar create a function_declaration. id_p = TerminalParser( IDENTIFIER ) eos_p = symbol_f( ';' ) pp_directive_pi = rename_f( 'preprocessor_directive', terminal_f( PP_DIRECTIVE ) ) # ############################## A.4: Program ############################ # A.4, C++PL3 p.798 declaration_seq_pi = proxy_f() translation_unit_pi = node_f( 'translation_unit', optional_f( declaration_seq_pi ) ) # ############################## A.5: Expressions ############################ # A.5, C++PL3 p.798-802 operator_function_id_pi = proxy_f() conversion_function_id_pi = proxy_f() simple_type_specifier_p = proxy_f() ptr_operator_pi = proxy_f() type_specifier_seq_pi = proxy_f() throw_expression_pi = proxy_f() class_name_pi = proxy_f() nested_name_specifier_pi = proxy_f() template_id_pi = proxy_f() type_id_pi = proxy_f() expression_pi = proxy_f() expression_list_pi = proxy_f() cast_expression_p = proxy_f() assignment_expression_pi = proxy_f() unary_expression_p = proxy_f() constant_expression_pi = proxy_f() unqualified_id_pi = proxy_f() new_type_pi = proxy_f() # define in declarators type_name_pi = proxy_f() literal_expression_p = proxy_f( ( terminal_f(INTEGER) | terminal_f(CHAR) | terminal_f(STRING) | terminal_f(FLOAT) | one_of_f( 'true false' ) ) >> rename_last_cmd( 'literal' ) ) namespace_name_pi = proxy_f( id_p ) class_or_namespace_name_p = class_name_pi | namespace_name_pi template_name_specifier_p = (symbol_f('template') >> nested_name_specifier_pi) nested_name_specifier_pi.setParser( repeat_f( 1, class_or_namespace_name_p >> '::' >> optional_f(template_name_specifier_p) ) ) # Notes: qualified_id can not include 'template' => A::template B::zozo is not parsed (IT SHOULD BE) qualified_id_p = node_f('qualified_id', ( optional_f('::') >> nested_name_specifier_pi >> optional_f('template') >> unqualified_id_pi ) | ( symbol_f('::') >> ( id_p | operator_function_id_pi | conversion_function_id_pi ) ) ) # Notes: template id not included # destructor_ref may be parsed as such while it is not a reference to a destructor (overloaded ~ operator & ()) unqualified_id_pi.setParser( id_p | operator_function_id_pi | conversion_function_id_pi \ | node_f('destructor_ref', symbol_f('~') >> id_p >> look_ahead_f( symbol_f('(') >> ')' ) ) ) # | template_id_pi id_expression_pi = longuest_f( qualified_id_p, node_f( 'unqualified_id', unqualified_id_pi ) ) # C++ Standard p65 primary_expression_p = proxy_f( literal_expression_p | ( symbol_f('this') >> rename_last_cmd( 'this_ref' ) ) | node_f('braced_expr', symbol_f('(') >> expression_pi >> symbol_f(')') ) | id_expression_pi ) # Notes: missing template in scope case pseudo_destructor_name_p = node_f( 'pseudo_destructor_name', optional_f('::') >> optional_f(nested_name_specifier_pi) >> optional_f(type_name_pi >> '::') >> symbol_f('~') >> id_p ) instance_accessor_p = one_of_f('. ->') cast_keywords_p = one_of_f('dynamic_cast static_cast reinterpret_cast const_cast') # Notes: not included in postfix_expression_p: # typename with template in scope # # postfix_expression_p as been modified to avoid the infinite left recursion. This recursion has been # moved to multiple 'optional' suffixes # array_operator_suffix_p = node_f('array_index', symbol_f('[') >> expression_pi >> ']') call_operator_suffix_p = node_f('call_parameters', symbol_f('(') >> optional_f( expression_list_pi ) >> ')') accessed_member_p = pseudo_destructor_name_p | (optional_f( 'template' ) >> optional_f( '::' ) >> id_expression_pi) member_access_suffix_p = node_f('accessed_member', instance_accessor_p >> accessed_member_p ) post_incdec_suffix_p = node_f( 'operator', one_of_f( '++ --' ) ) cppcast_expression_p = node_f('cppcast_expression', cast_keywords_p >> '<' >> type_id_pi >> '>' >> '(' >> expression_pi >> ')' ) type_id_expression_p = node_f( 'typeid_expression', symbol_f('typeid') >> '(' >> (type_id_pi | expression_pi) >> ')' ) # Notes: because of the typeless parsing a function call can not be distinguished from a # functional type conversion. In the case of a function call, the name of the function will be found in the # type id. call_or_conversion_expression_p = node_f( 'call_or_conversion_expression', ( (symbol_f('typename') >> optional_f('::') >> nested_name_specifier_pi >> id_p) | simple_type_specifier_p ) >> '(' >> optional_f( expression_list_pi ) >> ')' ) #Notes: template_id construction is missing postfix_expression_p = binary_operator_f( alternative_f( cppcast_expression_p, type_id_expression_p, call_or_conversion_expression_p, primary_expression_p ), alternative_f( make_right_op_f(array_operator_suffix_p, 'array_access'), # longuest could be removed if instance_accessor stuff are factorized into one rule make_right_op_f(call_operator_suffix_p, 'call'), make_right_op_f(member_access_suffix_p, 'member_access'), make_right_op_f(post_incdec_suffix_p, 'post_incdec') ) ) cast_expression_p = proxy_f() cast_expression_p.setParser( unary_expression_p | node_f('cast_expression', symbol_f('(') >> type_id_pi >> ')' >> node_f('casted_expression', cast_expression_p ) ) ) delete_expression_p = node_f( 'delete_operator', optional_f( '::') >> 'delete' >> optional_f(symbol_f('[') >> ']') >> cast_expression_p) new_initializer_p = node_f('new_initializer', symbol_f('(') >> optional_f( expression_list_pi ) >> ')') expression_list_pi.setParser( node_f( 'expression_list', list_f( assignment_expression_pi, ',' ) ) ) direct_new_declarator_p = repeat_f( 1, symbol_f('[') >> expression_pi >> ']' ) \ >> optional_f( symbol_f('[') >> constant_expression_pi >> ']' ) new_declarator_p = proxy_f() new_declarator_p.setParser( (ptr_operator_pi >> optional_f( new_declarator_p )) | direct_new_declarator_p ) new_type_id_p = node_f('new_type_id', new_type_pi >> optional_f( new_declarator_p )) new_type_id_alt_p = (symbol_f('(') >> new_type_id_p >> ')') \ | new_type_id_p new_placement_p = node_f('new_placement', symbol_f( '(' ) >> expression_list_pi >> ')') new_expression_p = node_f('new_operator', optional_f( '::' ) >> 'new' >> optional_alternative_f( new_placement_p, new_type_id_alt_p >> optional_f(new_initializer_p) )) # Notes: added '++' & '--' unary_operator_p = one_of_f( '++ -- * & + - ! ~' ) # Notes: sizeof( expr ) is already handled because unary_expression may be a braced expression. unary_expression_p.setParser( postfix_expression_p | node_f('unary_operator', unary_operator_p >> cast_expression_p) | node_f('sizeof_operator', symbol_f( 'sizeof' ) >> unary_expression_p) | new_expression_p | delete_expression_p ) pm_expression_p = binary_operator_f( cast_expression_p, make_right_op_f( node_f('right_operand', instance_accessor_p >> '*' >> cast_expression_p ), 'pointer_to_member_operator' ) ) ##def binary_expr_p_factory( simple_expr_parser, symbols ): ## return proxy_f( simple_expr_parser >> repeat_f( 0, one_of_f( symbols ) >> simple_expr_parser ) ) def binary_expr_p_factory( simple_expr_parser, symbols ): return binary_operator_f( simple_expr_parser, make_right_op_f( node_f('right_operand', one_of_f( symbols ) >> simple_expr_parser), 'binary_operator' ) ) multiplicative_expression_p = binary_expr_p_factory( pm_expression_p, '* / %' ) additive_expression_p = binary_expr_p_factory( multiplicative_expression_p, '+ -' ) shift_expression_p = binary_expr_p_factory( additive_expression_p, '<< >>' ) relational_expression_p = binary_expr_p_factory( shift_expression_p, '< > <= >=' ) equality_expression_p = binary_expr_p_factory( relational_expression_p, '== !=' ) and_expression_p = binary_expr_p_factory( equality_expression_p, '&' ) exclusive_or_expression_p = binary_expr_p_factory( and_expression_p, '^' ) inclusive_or_expression_p = binary_expr_p_factory( exclusive_or_expression_p, '|' ) logical_and_expression_p = binary_expr_p_factory( inclusive_or_expression_p, '&&' ) logical_or_expression_p = binary_expr_p_factory( logical_and_expression_p, '||' ) ##conditional_expression_p = proxy_f( logical_or_expression_p ## >> repeat_f( 0, symbol_f('?') >> expression_pi >> ':' >> assignment_expression_pi ) ) conditional_expression_p = binary_operator_f( logical_or_expression_p, make_right_op_f( node_f('right_operand', symbol_f('?') >> expression_pi >> ':' >> assignment_expression_pi ), 'tertiary_operator' ) ) assignment_operator_p = one_of_f( '= *= /= %= += -= >>= <<= &= ^= |=' ) assignment_expression_p = longuest_f( conditional_expression_p, (logical_or_expression_p >> assignment_operator_p >> assignment_expression_pi), throw_expression_pi ) expression_pi.setParser( node_f( 'expression', node_f( 'assignment_expression_list', list_f( assignment_expression_p, ',', 2 ) ) | assignment_expression_p ) ) assignment_expression_pi.setParser( node_f( 'assignment_expression', assignment_expression_p ) ) constant_expression_pi.setParser( node_f( 'constant_expression', conditional_expression_p ) ) # ############################## A.6: Statements ############################ # A.6, C++PL3 p.802-803 block_declaration_p = proxy_f() declarator_p = proxy_f() simple_declaration_p = proxy_f() statement_p = proxy_f() try_block_pi = proxy_f() condition_p = expression_pi \ | ( type_specifier_seq_pi >> declarator_p >> '=' >> assignment_expression_pi ) expression_statement_p = node_f( 'expression_statement', optional_f(expression_pi) >> eos_p ) jump_statement_p = node_f( 'break_statement', symbol_f('break') >> eos_p ) \ | node_f( 'continue_statement', symbol_f('continue') >> eos_p ) \ | node_f( 'return_statement', symbol_f('return') >> optional_f(expression_pi) >> eos_p) \ | node_f( 'goto_statement', symbol_f('goto') >> id_p >> eos_p) for_init_statement_p = expression_statement_p \ | simple_declaration_p iteration_statement_p = node_f('while_statement', symbol_f('while') >> '(' >> condition_p >> ')' >> statement_p) \ | node_f('dowhile_statement', symbol_f('do') >> statement_p >> 'while' >> '(' >> expression_pi >> ')' >> eos_p) \ | node_f('for_statement', symbol_f('for') >> '(' >> for_init_statement_p >> node_f('for_condition', optional_f( condition_p ) ) >> eos_p >> optional_f( expression_pi ) >> ')' >> statement_p ) selection_statement_p = node_f( 'if_statement', symbol_f('if') >> '(' >> condition_p >> ')' >> statement_p \ >> optional_f( symbol_f('else') >> statement_p ) ) \ | node_f( 'switch_statement', symbol_f('switch') >> '(' >> condition_p >> ')' >> statement_p ) error_statement_p = node_f( 'error_statement', block_error_f() ) compound_statement_pi = node_f( 'compound_statement', symbol_f('{') >> repeat_f( 0, statement_p | error_statement_p ) >> '}' ) labeled_statement_p = node_f('label_statement', id_p >> ':' >> statement_p) \ | node_f( 'case_statement', symbol_f('case') >> constant_expression_pi >> ':' >> statement_p ) \ | node_f( 'default_statement', symbol_f('default') >> ':' >> statement_p ) declaration_statement_p = node_f( 'declaration_statement', block_declaration_p ) statement_p.setParser( labeled_statement_p | compound_statement_pi | selection_statement_p | iteration_statement_p | jump_statement_p | expression_statement_p | declaration_statement_p | try_block_pi | pp_directive_pi ) # ############################## A.7.1: Declarators ############################ # A.7.1, C++PL3 p.807-808 class_key_pi = proxy_f() class_specifier_pi = proxy_f() ctor_initializer_p = proxy_f() exception_specification_pi = proxy_f() function_try_block_pi = proxy_f() abstract_declarator_p = proxy_f() direct_abstract_declarator_p = proxy_f() parameter_declaration_clause_p = proxy_f() initializer_clause_p = proxy_f() workaround_type_specifier_pi = proxy_f() cv_qualifier_p = one_of_f('const volatile' ) cv_qualifier_seq_p = node_f( 'cv_qualifiers', repeat_f( 1, cv_qualifier_p ) ) # buggy standard C++ rules. Use 'custom type parser instead' => see decl_specifiers_p, parameter_type_p, # new_type_pi, function_return_type... # decl_specifier_seq_p = buggy # repeat_f( 1, decl_specifier_p ) # decl_specifier_p = buggy #( storage_class_specifier_p # | type_specifier_p # | function_specifier_p # | rename_f( 'friend_specifier', 'friend' ) # | rename_f( 'typedef_specifier', 'typedef' ) ) # type_specifier_p = buggy #( simple_type_specifier_p # | enum_specifier_p # | longuest_f( class_specifier_pi, elaborated_type_specifier_p ) # | cv_qualifier_p) # removed left recursion direct_abstract_declarator_fn_suffix_p = proxy_f( node_f( 'function_parameters', symbol_f('(') >> parameter_declaration_clause_p >> ')' ) >> optional_f( cv_qualifier_seq_p ) >> optional_f( exception_specification_pi ) ) direct_abstract_declarator_array_suffix_p = node_f( 'abstract_array_declarator', symbol_f('[') >> optional_f( constant_expression_pi ) >> ']' ) direct_abstract_declarator_p.setParser( optional_f( symbol_f('(') >> abstract_declarator_p >> ')' ) >> repeat_f( 0, direct_abstract_declarator_fn_suffix_p | direct_abstract_declarator_array_suffix_p ) ) abstract_declarator_p.setParser( (ptr_operator_pi >> optional_f( abstract_declarator_p )) \ | direct_abstract_declarator_p ) opt_parameter_decl_assign_p = optional_f( node_f( 'parameter_default_value', symbol_f('=') >> assignment_expression_pi ) ) parameter_type_p = proxy_f( optional_f(cv_qualifier_seq_p) >> workaround_type_specifier_pi >> optional_f(cv_qualifier_seq_p) ) new_type_pi.setParser( workaround_type_specifier_pi ) parameter_declaration_p = node_f( 'function_parameter', node_f('parameter_type', parameter_type_p) >> node_f('parameter_name', declarator_p | abstract_declarator_p) >> opt_parameter_decl_assign_p ) ellipsis_parameter_declaration = node_f('ellipsis_parameter', '...' ) parameter_declaration_clause_p.setParser( ellipsis_parameter_declaration \ | (optional_f( list_f( parameter_declaration_p, ',' ) ) \ >> optional_f( symbol_f(',') >> ellipsis_parameter_declaration ) ) ) enum_name_p = id_p typedef_name_p = id_p # p793 type_name_pi.setParser( class_name_pi | enum_name_p | typedef_name_p ) # Notes: simplified, alternatives are redondant in typeless context declarator_id_p = node_f( 'declarator_id', optional_f( '::' ) >> id_expression_pi ) ptr_operator_pi.setParser( (symbol_f('*') >> optional_f( cv_qualifier_seq_p )) \ | symbol_f('&') \ | node_f('pointer_to_member', optional_f('::') >> nested_name_specifier_pi >> '*' >> optional_f( cv_qualifier_seq_p ) ) ) # defined in A71, declarators, p807 , after cv_qualifier type_id_pi.setParser( node_f( 'type_id', type_specifier_seq_pi >> optional_f( abstract_declarator_p ) ) ) # removed infinite left recursion direct_declarator_p = proxy_f( ( declarator_id_p | (symbol_f('(') >> declarator_p >> ')') ) >> repeat_f( 0, direct_abstract_declarator_fn_suffix_p | direct_abstract_declarator_array_suffix_p ) ) # Notes: inversed order to parse pointer to member correctly. declarator_p.setParser( (ptr_operator_pi >> declarator_p) | direct_declarator_p ) initializer_list_p = list_f( initializer_clause_p, ',' ) initializer_clause_p.setParser( assignment_expression_pi \ | (symbol_f('{') >> optional_f( initializer_list_p >> optional_f( ',' ) ) >> '}') ) initializer_p = node_f('assign_initializer', symbol_f('=') >> initializer_clause_p ) \ | (symbol_f('(') >> expression_list_pi >> ')') init_declarator_p = node_f( 'init_declarator', declarator_p >> optional_f( initializer_p ) ) init_declarator_list_p = node_f( 'init_declarators', list_f( init_declarator_p, ',' ) ) type_specifier_seq_pi.setParser( node_f( 'type_specifier', optional_f(cv_qualifier_seq_p) >> workaround_type_specifier_pi >> optional_f(cv_qualifier_seq_p) ) ) function_body_p = compound_statement_pi #Note: C++ standard, p140: # a declarator_p in a function definition shall have the form: # D1 ( parameter_declaration_clause ) optional_f(cv_qualifier_seq) optional_f(exception_specification) # function_declarator_p implement this instead of using a standard declarator_p. function_return_type_p = proxy_f( optional_f(cv_qualifier_seq_p) >> workaround_type_specifier_pi >> optional_f(cv_qualifier_seq_p) ) function_declarator_p = declarator_id_p >> direct_abstract_declarator_fn_suffix_p function_definition_start_p = optional_alternative_f( node_f( 'function_return_type', function_return_type_p ), function_declarator_p ) function_definition_pi = node_f('function_definition', function_definition_start_p >> ( (optional_f(ctor_initializer_p) >> function_body_p) | function_try_block_pi ) ) # ############################## A.7: Declaration ############################ declaration_pi = proxy_f() # forward declaration for recursion declaration_error_p = node_f( 'declaration_error', block_error_f() ) declaration_seq_pi.setParser( repeat_f( 1, declaration_pi | declaration_error_p ) ) # A.7, C++PL3 p.805-806 # => parse namespace declaration and namespace alias declaration # Notes: OK. No parsing issue namespace_body_p = optional_f( node_f( 'namespace_body', declaration_seq_pi ) ) qualified_namespace_specifier_p = node_f( 'namespace_specifier', optional_f('::') >> optional_f(nested_name_specifier_pi) >> namespace_name_pi ) named_namespace_definition_p = symbol_f('namespace') >> id_p >> '{' >> namespace_body_p >> '}' unnamed_namespace_definition_p = (symbol_f('namespace') >> '{' >> namespace_body_p >> '}') namespace_definition_p = node_f( 'named_namespace_def', named_namespace_definition_p) \ | node_f( 'unnamed_namespace_def', unnamed_namespace_definition_p ) namespace_alias_definition_p = node_f('namespace_alias_def', symbol_f('namespace') >> id_p >> '=' >> qualified_namespace_specifier_p >> eos_p) # A.7, C++PL3 p.806 # => parse using declaration and directive # Notes: OK. No parsing issue using_id_p = node_f( 'using_id', (optional_f('typename') >> optional_f('::') >> nested_name_specifier_pi >> unqualified_id_pi) | ( symbol_f('::') >> unqualified_id_pi ) ) using_declaration_p = node_f('using_declaration', symbol_f('using') >> using_id_p >> eos_p ) using_directive_p = symbol_f('using') >> 'namespace' >> qualified_namespace_specifier_p >> eos_p # A.7, C++PL3 p.806 # => parse asm definition asm_keyword_p = one_of_f('asm __asm') # (__asm) => Microsoft Visual C++ asm_definition_p = asm_keyword_p >> '(' >> terminal_f(STRING) >> ')' >> eos_p # A.7, C++PL3 p.806 # => parse extern specifiction linkage_specification_begin_p = symbol_f('extern') >> terminal_f(STRING) linkage_specification_p = node_f( 'linkage_specification', linkage_specification_begin_p >> ( (symbol_f('{') >> optional_f(declaration_seq_pi) >> '}') | declaration_pi ) ) # A.7, C++PL3 p.804-806 # => parse simple declaration # Notes: parsing issue in: # -simple_type_specifier_p # -enumerator_definition_p (for constant expression that contains template with multiple parameters) enumerator_p = proxy_f( id_p ) enumerator_definition_p = node_f( 'enumerator_definition', enumerator_p >> optional_f( symbol_f('=') >> constant_expression_pi ) ) enum_specifier_p = node_f( 'enum_specifier', symbol_f('enum') >> optional_f(id_p) >> '{' >> optional_f(list_f(enumerator_definition_p, ',') ) >> '}' ) forwarded_type_id_p = node_f( 'forwarded_type_id', optional_f( '::' ) >> optional_f( nested_name_specifier_pi ) >> id_p ) forward_typename_id_p = node_f( 'forwarded_type_id', optional_f( '::' ) >> optional_f( nested_name_specifier_pi ) >> ( (symbol_f('template') >> template_id_pi ) | id_p ) ) elaborated_type_specifier_p = proxy_f( node_f( 'forward_class_specifier', class_key_pi >> forwarded_type_id_p ) | node_f( 'forward_enum_specifier', symbol_f('enum') >> forwarded_type_id_p >> look_ahead_f( not_f( '(' ) ) ) | node_f( 'forward_typename_specifier', symbol_f('typename') >> forward_typename_id_p >> look_ahead_f( not_f( '(' ) ) ) ) fundamental_type = repeat_f( 1, one_of_f( 'char wchar_t bool short int long signed unsigned float double void' ) ) # Notes: possible optimization issue for type_name => may need longuest_f user_type_specifier_p = proxy_f( node_f( 'type_name', optional_f('::') >> nested_name_specifier_pi >> optional_f('template') >> template_id_pi ) | node_f( 'type_name', optional_f('::') >> optional_f(nested_name_specifier_pi) >> type_name_pi ) ) simple_type_specifier_p.setParser( node_f( 'fundamental_type_specifier', fundamental_type ) | user_type_specifier_p ) storage_class_specifier_p = rename_f('storage_class_specifier', one_of_f('auto register static extern mutable') ) function_specifier_p = rename_f('function_specifier', one_of_f('inline virtual explicit') ) # Hand made rules concerning the order of decl_specifier # Those rules allow us to detect that the type specifier of 'MyClass instance' is 'MyClass' # and not 'MyClass insance'. # typedef cv_qualifiers type cv_qualifiers # storage_class_specifier(1) function_specifiers cv_qualifiers type cv_qualifiers # friend 'storage decl' # type = repeat(1,base_type) | user_type ##decl_specifiers_p = buggy # node_f( 'decl_specifiers', repeat_f( 1, decl_specifier_p ) ) constructor_type_specifier_pi = optional_f(function_specifier_p) workaround_type_specifier_pi.setParser( simple_type_specifier_p | enum_specifier_p | longuest_f( class_specifier_pi, elaborated_type_specifier_p ) ) standard_decl_specifier_impl_p = proxy_f( optional_f( storage_class_specifier_p ) >> optional_f( function_specifier_p ) >> optional_f( cv_qualifier_seq_p ) >> workaround_type_specifier_pi >> optional_f( cv_qualifier_seq_p ) ) standard_decl_specifiers_p = node_f( 'declaration_specifier', standard_decl_specifier_impl_p ) typedef_decl_specifiers_p = node_f( 'typedef_specifier', symbol_f('typedef') >> optional_f(cv_qualifier_seq_p) >> workaround_type_specifier_pi >> optional_f(cv_qualifier_seq_p) ) friend_decl_specifiers_p = node_f( 'friend_specifier', symbol_f('friend') >> standard_decl_specifier_impl_p ) decl_specifiers_p = proxy_f( typedef_decl_specifiers_p | friend_decl_specifiers_p | standard_decl_specifiers_p ) simple_declaration_p.setParser( node_f( 'simple_declaration', optional_f( decl_specifiers_p ) >> optional_f( init_declarator_list_p ) >> eos_p ) ) # A.7, C++PL3 p.804 block_declaration_p.setParser( asm_definition_p | namespace_alias_definition_p | using_declaration_p | using_directive_p | simple_declaration_p ) declaration_pi.setParser( block_declaration_p | linkage_specification_p | namespace_definition_p | function_definition_pi | pp_directive_pi ) ## | template_declaration_p ## | explicit_instantiation_p ## | explicit_specialization_p ) # ############################## A.8: Classes ############################ # A.8, C++PL3 p.808-809 class_name_pi.setParser( id_p ) constant_initializer_p = symbol_f('=') >> constant_expression_pi pure_specifier_p = symbol_f('=') >> ZeroParser() # added, somehow the grammar is not parsing this constructor_declaration_p = constructor_type_specifier_pi >> function_declarator_p member_declarator_p = longuest_f( declarator_p >> optional_f(pure_specifier_p), declarator_p >> optional_f(constant_initializer_p), optional_f(id_p) >> ':' >> constant_expression_pi ) member_declarator_list_p = list_f( member_declarator_p, ',' ) #Notes: not included: #- opt(::) nested-name-specifier opt(template) unqualified-id member_declaration_p = proxy_f( node_f( 'member_function_definition', (function_definition_pi >> optional_f( eos_p )) ) | node_f('member_declaration', optional_f( decl_specifiers_p ) >> optional_f( member_declarator_list_p ) >> eos_p) | node_f('typeless_function_declaration', constructor_declaration_p >> eos_p) | using_declaration_p ) # | template_declaration_p access_specifier_p = one_of_f( "public protected private" ) access_specification_p = node_f( 'access_specification', access_specifier_p >> ':' ) member_specification_p = node_f('member_specification', repeat_f( 1, access_specification_p | member_declaration_p ) ) class_key_pi.setParser( one_of_f('class struct union' ) ) base_class_name_p = node_f( 'base_class_name', optional_f('::') >> optional_f(nested_name_specifier_pi) >> class_name_pi ) base_specifier_p = node_f( 'base_class_access', optional_f('virtual') >> optional_f( access_specifier_p ) >> optional_f('virtual') ) \ >> base_class_name_p # Notes: could use a subparser here: match ':' - '{' base_clause_p = node_f( 'class_bases', symbol_f(':') >> list_f( node_f( 'base_specifier', base_specifier_p ), ',' ) ) class_head_name_p = node_f( 'class_name', optional_f( nested_name_specifier_pi ) >> (id_p | template_id_pi) ) class_head_p = proxy_f( class_key_pi >> optional_f( class_head_name_p ) >> optional_f( base_clause_p ) ) class_specifier_pi.setParser( node_f( 'class_specifier', class_head_p >> '{' >> optional_f( member_specification_p ) >> '}' ) ) # ############### A.8.2: Classes, Specials Member Functions ################## # A.8.2, C++PL3 p.810 conversion_declarator_p = repeat_f( 1, ptr_operator_pi ) conversion_type_id_p = node_f('conversion_type', type_specifier_seq_pi >> optional_f( conversion_declarator_p )) conversion_function_id_pi.setParser( node_f('conversion_function_ref', symbol_f('operator') >> conversion_type_id_p) ) mem_initializer_id = node_f( 'mem_initializer_id', (optional_f('::') >> optional_f(nested_name_specifier_pi) >> class_name_pi) | id_p ) mem_initializer_p = node_f( 'mem_initializer', mem_initializer_id >> '(' >> optional_f( expression_list_pi ) >> ')' ) ctor_initializer_p.setParser( symbol_f( ':' ) >> list_f( mem_initializer_p, ',' ) ) # ############### A.8.2: Classes, OverLoading ################## # A.8.3, C++PL3 p.810 operator_p = one_of_f( '+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> () []') \ | ( one_of_f( 'new delete' ) >> optional_f( symbol_f('[') >> ']' ) ) operator_function_id_pi.setParser( node_f('operator_function_ref', symbol_f('operator') >> operator_p) ) # ############################## A.9: Templates ############################ # A.9, C++PL3 p.811 template_declaration_p = proxy_f() template_parameter_list_p = proxy_f() template_name_p = proxy_f( id_p ) template_argument_p = assignment_expression_pi | type_id_pi | template_name_p template_argument_list_p = list_f( template_argument_p, ',' ) template_id_pi.setParser( template_name_p >> '<' >> optional_f( template_argument_list_p ) >> '>' ) type_parameter_p = proxy_f( one_of_f('class typename') >> optional_f( id_p ) >> optional_f( symbol_f('=') >> type_id_pi ) | ( symbol_f('template') >> '<' >> template_parameter_list_p >> '>' >> 'class' >> optional_f(id_p) >> optional_f( symbol_f('=') >> template_name_p ) ) ) template_parameter_p = type_parameter_p | parameter_declaration_p template_parameter_list_p.setParser( list_f( template_parameter_p, ',' ) ) template_declaration_p.setParser( symbol_f('template') >> '<' >> template_parameter_list_p >> '>' >> declaration_pi ) explicit_instantiation_p = proxy_f( symbol_f('template') >> declaration_pi ) explicit_specialization_p = proxy_f( symbol_f('template') >> '<' >> '>' >> declaration_pi ) # ############################## A.10: Exceptions ############################ # A.10, C++PL3 p.812 throw_expression_pi.setParser( symbol_f('throw') >> optional_f( assignment_expression_pi ) ) exception_declaration_p = (type_specifier_seq_pi >> optional_f( declarator_p | abstract_declarator_p )) \ | '...' handler_p = node_f('exception_handler', symbol_f('catch') >> '(' >> exception_declaration_p >> ')' >> compound_statement_pi ) handler_seq_p = repeat_f( 1, handler_p ) type_id_list_p = node_f( 'type_id_list', list_f( type_id_pi, ',' ) ) exception_specification_pi.setParser( node_f('exception_specification', symbol_f( 'throw' ) >> '(' >> optional_f( type_id_list_p ) >> ')' ) ) try_block_pi.setParser( node_f( 'try_block', symbol_f('try') >> compound_statement_pi >> handler_seq_p ) ) function_try_block_pi.setParser( symbol_f('try') >> optional_f(ctor_initializer_p) >> function_body_p >> handler_seq_p ) # #################################### Debug information for parser ################### # generated using generateparserdebuginfo.py (Notes: could this be done dynamically ?) abstract_declarator_p.setName( 'abstract_declarator_p' ) access_specification_p.setName( 'access_specification_p' ) access_specifier_p.setName( 'access_specifier_p' ) accessed_member_p.setName( 'accessed_member_p' ) additive_expression_p.setName( 'additive_expression_p' ) and_expression_p.setName( 'and_expression_p' ) array_operator_suffix_p.setName( 'array_operator_suffix_p' ) asm_definition_p.setName( 'asm_definition_p' ) asm_keyword_p.setName( 'asm_keyword_p' ) assignment_expression_p.setName( 'assignment_expression_p' ) assignment_expression_pi.setName( 'assignment_expression_pi' ) assignment_operator_p.setName( 'assignment_operator_p' ) base_class_name_p.setName( 'base_class_name_p' ) base_clause_p.setName( 'base_clause_p' ) base_specifier_p.setName( 'base_specifier_p' ) block_declaration_p.setName( 'block_declaration_p' ) call_operator_suffix_p.setName( 'call_operator_suffix_p' ) call_or_conversion_expression_p.setName( 'call_or_conversion_expression_p' ) cast_expression_p.setName( 'cast_expression_p' ) cast_keywords_p.setName( 'cast_keywords_p' ) class_head_name_p.setName( 'class_head_name_p' ) class_head_p.setName( 'class_head_p' ) class_key_pi.setName( 'class_key_pi' ) class_name_pi.setName( 'class_name_pi' ) class_or_namespace_name_p.setName( 'class_or_namespace_name_p' ) class_specifier_pi.setName( 'class_specifier_pi' ) compound_statement_pi.setName( 'compound_statement_pi' ) condition_p.setName( 'condition_p' ) conditional_expression_p.setName( 'conditional_expression_p' ) constant_expression_pi.setName( 'constant_expression_pi' ) constant_initializer_p.setName( 'constant_initializer_p' ) constructor_declaration_p.setName( 'constructor_declaration_p' ) constructor_type_specifier_pi.setName( 'constructor_type_specifier_pi' ) conversion_declarator_p.setName( 'conversion_declarator_p' ) conversion_function_id_pi.setName( 'conversion_function_id_pi' ) conversion_type_id_p.setName( 'conversion_type_id_p' ) cppcast_expression_p.setName( 'cppcast_expression_p' ) ctor_initializer_p.setName( 'ctor_initializer_p' ) cv_qualifier_p.setName( 'cv_qualifier_p' ) cv_qualifier_seq_p.setName( 'cv_qualifier_seq_p' ) decl_specifiers_p.setName( 'decl_specifiers_p' ) declaration_pi.setName( 'declaration_pi' ) declaration_seq_pi.setName( 'declaration_seq_pi' ) declaration_statement_p.setName( 'declaration_statement_p' ) declarator_id_p.setName( 'declarator_id_p' ) declarator_p.setName( 'declarator_p' ) delete_expression_p.setName( 'delete_expression_p' ) direct_abstract_declarator_array_suffix_p.setName( 'direct_abstract_declarator_array_suffix_p' ) direct_abstract_declarator_fn_suffix_p.setName( 'direct_abstract_declarator_fn_suffix_p' ) direct_abstract_declarator_p.setName( 'direct_abstract_declarator_p' ) direct_declarator_p.setName( 'direct_declarator_p' ) direct_new_declarator_p.setName( 'direct_new_declarator_p' ) elaborated_type_specifier_p.setName( 'elaborated_type_specifier_p' ) end_p.setName( 'end_p' ) enum_name_p.setName( 'enum_name_p' ) enum_specifier_p.setName( 'enum_specifier_p' ) enumerator_definition_p.setName( 'enumerator_definition_p' ) enumerator_p.setName( 'enumerator_p' ) eos_p.setName( 'eos_p' ) equality_expression_p.setName( 'equality_expression_p' ) exception_declaration_p.setName( 'exception_declaration_p' ) exception_specification_pi.setName( 'exception_specification_pi' ) exclusive_or_expression_p.setName( 'exclusive_or_expression_p' ) explicit_instantiation_p.setName( 'explicit_instantiation_p' ) explicit_specialization_p.setName( 'explicit_specialization_p' ) expression_list_pi.setName( 'expression_list_pi' ) expression_pi.setName( 'expression_pi' ) expression_statement_p.setName( 'expression_statement_p' ) for_init_statement_p.setName( 'for_init_statement_p' ) forward_typename_id_p.setName( 'forward_typename_id_p' ) forwarded_type_id_p.setName( 'forwarded_type_id_p' ) friend_decl_specifiers_p.setName( 'friend_decl_specifiers_p' ) function_body_p.setName( 'function_body_p' ) function_declarator_p.setName( 'function_declarator_p' ) function_definition_pi.setName( 'function_definition_pi' ) function_definition_start_p.setName( 'function_definition_start_p' ) function_return_type_p.setName( 'function_return_type_p' ) function_specifier_p.setName( 'function_specifier_p' ) function_try_block_pi.setName( 'function_try_block_pi' ) handler_p.setName( 'handler_p' ) handler_seq_p.setName( 'handler_seq_p' ) id_expression_pi.setName( 'id_expression_pi' ) id_p.setName( 'id_p' ) inclusive_or_expression_p.setName( 'inclusive_or_expression_p' ) init_declarator_list_p.setName( 'init_declarator_list_p' ) init_declarator_p.setName( 'init_declarator_p' ) initializer_clause_p.setName( 'initializer_clause_p' ) initializer_list_p.setName( 'initializer_list_p' ) initializer_p.setName( 'initializer_p' ) instance_accessor_p.setName( 'instance_accessor_p' ) iteration_statement_p.setName( 'iteration_statement_p' ) jump_statement_p.setName( 'jump_statement_p' ) labeled_statement_p.setName( 'labeled_statement_p' ) linkage_specification_begin_p.setName( 'linkage_specification_begin_p' ) linkage_specification_p.setName( 'linkage_specification_p' ) literal_expression_p.setName( 'literal_expression_p' ) logical_and_expression_p.setName( 'logical_and_expression_p' ) logical_or_expression_p.setName( 'logical_or_expression_p' ) mem_initializer_p.setName( 'mem_initializer_p' ) member_access_suffix_p.setName( 'member_access_suffix_p' ) member_declaration_p.setName( 'member_declaration_p' ) member_declarator_list_p.setName( 'member_declarator_list_p' ) member_declarator_p.setName( 'member_declarator_p' ) member_specification_p.setName( 'member_specification_p' ) multiplicative_expression_p.setName( 'multiplicative_expression_p' ) named_namespace_definition_p.setName( 'named_namespace_definition_p' ) namespace_alias_definition_p.setName( 'namespace_alias_definition_p' ) namespace_body_p.setName( 'namespace_body_p' ) namespace_definition_p.setName( 'namespace_definition_p' ) namespace_name_pi.setName( 'namespace_name_pi' ) nested_name_specifier_pi.setName( 'nested_name_specifier_pi' ) new_declarator_p.setName( 'new_declarator_p' ) new_expression_p.setName( 'new_expression_p' ) new_initializer_p.setName( 'new_initializer_p' ) new_placement_p.setName( 'new_placement_p' ) new_type_id_alt_p.setName( 'new_type_id_alt_p' ) new_type_id_p.setName( 'new_type_id_p' ) new_type_pi.setName( 'new_type_pi' ) operator_function_id_pi.setName( 'operator_function_id_pi' ) operator_p.setName( 'operator_p' ) opt_parameter_decl_assign_p.setName( 'opt_parameter_decl_assign_p' ) parameter_declaration_clause_p.setName( 'parameter_declaration_clause_p' ) parameter_declaration_p.setName( 'parameter_declaration_p' ) parameter_type_p.setName( 'parameter_type_p' ) pm_expression_p.setName( 'pm_expression_p' ) post_incdec_suffix_p.setName( 'post_incdec_suffix_p' ) postfix_expression_p.setName( 'postfix_expression_p' ) primary_expression_p.setName( 'primary_expression_p' ) pseudo_destructor_name_p.setName( 'pseudo_destructor_name_p' ) ptr_operator_pi.setName( 'ptr_operator_pi' ) pure_specifier_p.setName( 'pure_specifier_p' ) qualified_id_p.setName( 'qualified_id_p' ) qualified_namespace_specifier_p.setName( 'qualified_namespace_specifier_p' ) relational_expression_p.setName( 'relational_expression_p' ) selection_statement_p.setName( 'selection_statement_p' ) shift_expression_p.setName( 'shift_expression_p' ) simple_declaration_p.setName( 'simple_declaration_p' ) simple_type_specifier_p.setName( 'simple_type_specifier_p' ) standard_decl_specifier_impl_p.setName( 'standard_decl_specifier_impl_p' ) standard_decl_specifiers_p.setName( 'standard_decl_specifiers_p' ) statement_p.setName( 'statement_p' ) storage_class_specifier_p.setName( 'storage_class_specifier_p' ) template_argument_list_p.setName( 'template_argument_list_p' ) template_argument_p.setName( 'template_argument_p' ) template_declaration_p.setName( 'template_declaration_p' ) template_id_pi.setName( 'template_id_pi' ) template_name_p.setName( 'template_name_p' ) template_name_specifier_p.setName( 'template_name_specifier_p' ) template_parameter_list_p.setName( 'template_parameter_list_p' ) template_parameter_p.setName( 'template_parameter_p' ) throw_expression_pi.setName( 'throw_expression_pi' ) translation_unit_pi.setName( 'translation_unit_pi' ) try_block_pi.setName( 'try_block_pi' ) type_id_expression_p.setName( 'type_id_expression_p' ) type_id_list_p.setName( 'type_id_list_p' ) type_id_pi.setName( 'type_id_pi' ) type_name_pi.setName( 'type_name_pi' ) type_parameter_p.setName( 'type_parameter_p' ) type_specifier_seq_pi.setName( 'type_specifier_seq_pi' ) typedef_decl_specifiers_p.setName( 'typedef_decl_specifiers_p' ) typedef_name_p.setName( 'typedef_name_p' ) unary_expression_p.setName( 'unary_expression_p' ) unary_operator_p.setName( 'unary_operator_p' ) unnamed_namespace_definition_p.setName( 'unnamed_namespace_definition_p' ) unqualified_id_pi.setName( 'unqualified_id_pi' ) user_type_specifier_p.setName( 'user_type_specifier_p' ) using_declaration_p.setName( 'using_declaration_p' ) using_directive_p.setName( 'using_directive_p' ) using_id_p.setName( 'using_id_p' ) workaround_type_specifier_pi.setName( 'workaround_type_specifier_pi' ) --- NEW FILE: grammartest.py --- import unittest import mock import parser import grammar import parsingtracker import string import tokenizer from parsertesthelper import * # * need to modify binary_operator right node so that the operator is a child of binary_operator node. # * end_p to terminate translation unit # * error recovery using subparsing and special 'error' matching rules. Will probably need a special parser to # skip 'a statement' (skip everything until next semi-colon while balancing braces and curly braces. stop if # closing a curly-brace (means that the end of the block is found) ) def unqualified_id_n( name ): return TestNode( 'unqualified_id', id_n(name) ) def fundamental_type_n( types ): return TestNode( 'fundamental_type_specifier', *types.split() ) def fundamental_type_specifier_n( types ): return TestNode( 'type_specifier', fundamental_type_n( types ) ) def declarator_id_n( *ids ): return TestNode( 'declarator_id', TestNode( 'unqualified_id', *ids ) ) class GrammarTest(unittest.TestCase,ParserTestHelperMixIn): """GrammarTest tests""" def setUp( self ): pass def tearDown( self ): pass # Expression def testLiteralExpression( self ): self.checkParser( '1', grammar.literal_expression_p ) self.checkParser( '1.0', grammar.literal_expression_p ) self.checkParser( '"abc"', grammar.literal_expression_p ) self.checkParser( "'a'", grammar.literal_expression_p ) self.checkParser( "true", grammar.literal_expression_p ) self.checkParser( "false", grammar.literal_expression_p ) self.checkProducedTree( 'true', grammar.literal_expression_p, ('literal','true') ) self.checkProducedTree( '123.456', grammar.literal_expression_p, ('literal','123.456') ) def testUnqualifiedId( self ): self.checkProducedNodes( 'xyz', grammar.unqualified_id_pi, id_n( 'xyz' ) ) self.checkProducedNodes( 'operator =', grammar.unqualified_id_pi, TestNode( 'operator_function_ref', 'operator', '=' ) ) self.checkProducedNodes( 'operator int', grammar.unqualified_id_pi, TestNode( 'conversion_function_ref', 'operator', TestNode( 'conversion_type', fundamental_type_specifier_n('int') ) ) ) self.checkProducedNodes( '~ClassName()', grammar.unqualified_id_pi, TestNode( 'destructor_ref', '~', id_n('ClassName') ) ) def testQualifiedId( self ): self.checkProducedNodes( '::NamespaceName::ClassName::xyz', grammar.qualified_id_p, TestNode( 'qualified_id', '::', id_n('NamespaceName'), '::', id_n('ClassName'), '::', id_n('xyz') ) ) self.checkProducedNodes( 'Name::template Class::xyz', grammar.qualified_id_p, TestNode( 'qualified_id', id_n('Name'), '::', 'template', id_n('Class'), '::', id_n('xyz') ) ) self.checkProducedNodes( '::xyz', grammar.qualified_id_p, TestNode( 'qualified_id', '::', id_n('xyz') ) ) self.checkProducedNodes( '::operator =', grammar.qualified_id_p, TestNode( 'qualified_id', '::', TestNode( 'operator_function_ref', 'operator', '=' ) ) ) self.checkProducedNodes( '::operator int', grammar.qualified_id_p, TestNode( 'qualified_id', '::', TestNode( 'conversion_function_ref', 'operator', TestNode( 'conversion_type', fundamental_type_specifier_n('int') ) ) ) ) def testPrimaryExpression( self ): # require: literal_expression_p, qualified_id_p, unqualified_id_pi, id_expression_pi, operator_function_id_p, conversion_function_id_p self.checkProducedTree( '1', grammar.primary_expression_p, ('literal','1') ) self.checkProducedTree( 'this', grammar.primary_expression_p, ('this_ref','this') ) self.checkProducedNodes( '(this)', grammar.primary_expression_p, TestNode( 'braced_expr', '(', TestNode( 'expression', ('this_ref','this') ), ')' ) ) self.checkParser( '::my_id', grammar.primary_expression_p ) self.checkParser( 'MyNamespace::my_var', grammar.primary_expression_p ) self.checkParser( '::MyNamespace::MyClass::member_', grammar.primary_expression_p ) self.checkParser( '::operator =', grammar.primary_expression_p ) self.checkParser( 'Base::operator =', grammar.primary_expression_p ) self.checkProducedNodes( 'xyz', grammar.primary_expression_p, TestNode( 'unqualified_id', id_n( 'xyz' ) ) ) self.checkProducedNodes( 'operator =', grammar.primary_expression_p, TestNode( 'unqualified_id', TestNode( 'operator_function_ref', 'operator', '=' ) ) ) self.checkProducedNodes( 'operator int', grammar.primary_expression_p, TestNode( 'unqualified_id', TestNode( 'conversion_function_ref', 'operator', TestNode( 'conversion_type', fundamental_type_specifier_n('int') ) ) ) ) self.checkProducedNodes( '~ClassName()', grammar.primary_expression_p, TestNode( 'unqualified_id', TestNode( 'destructor_ref', '~', id_n('ClassName') ) ) ) def testPostFixExpressionSuffix( self ): self.checkProducedNodes( '[123]', grammar.array_operator_suffix_p, TestNode('array_index', '[', JokerTestNode( 'expression' ), ']') ) self.checkParser( '()', grammar.call_operator_suffix_p ) self.checkParser( '(123)', grammar.call_operator_suffix_p ) self.checkParser( '(123,456)', grammar.call_operator_suffix_p ) self.checkParser( '.my_member', grammar.member_access_suffix_p ) self.checkParser( '->my_member', grammar.member_access_suffix_p ) self.checkParser( '->template Parent::my_member', grammar.member_access_suffix_p ) self.checkParser( '.~MyClass', grammar.member_access_suffix_p ) self.checkParser( '.::Base::~MyClass', grammar.member_access_suffix_p ) self.checkParser( '.MyParent::~MyClass', grammar.member_access_suffix_p ) self.checkParser( '++', grammar.post_incdec_suffix_p ) self.checkParser( '--', grammar.post_incdec_suffix_p ) def testPostFixExpression( self ): # require: primary_expression_p self.checkParser( '(this)', grammar.postfix_expression_p ) self.checkParser( 'my_id', grammar.postfix_expression_p ) self.checkProducedNodes( 'arr[1][2]', grammar.postfix_expression_p, TestNode( 'array_access', TestNode( 'array_access', JokerTestNode( 'unqualified_id' ), TestNode('array_index', '[', JokerTestNode( 'expression' ), ']') ), #[1] TestNode('array_index', '[', JokerTestNode( 'expression' ), ']') ) ) #[2] self.checkProducedTree( 'this', grammar.postfix_expression_p, ('this_ref','this') ) self.checkParser( 'int(1234)', grammar.postfix_expression_p ) self.checkParser( 'MyClass(1234)', grammar.postfix_expression_p ) self.checkParser( 'MyNamespace::MyClass(1234)', grammar.postfix_expression_p ) self.checkParser( 'typeid( 1234.0 )', grammar.postfix_expression_p ) self.checkParser( 'typeid( int )', grammar.postfix_expression_p ) self.checkParser( 'static_cast<int>(1234)', grammar.postfix_expression_p ) self.checkParser( 'dynamic_cast<Derived>(p)', grammar.postfix_expression_p ) self.checkParser( 'my_array[1]', grammar.postfix_expression_p ) self.checkParser( 'my_function(1)', grammar.postfix_expression_p ) self.checkParser( 'my_instance->my_member', grammar.postfix_expression_p ) self.checkParser( 'my_instance.BaseClass::my_member', grammar.postfix_expression_p ) self.checkParser( 'my_instance->~MyClass', grammar.postfix_expression_p ) self.checkParser( 'my_instance.MyClass::~MyClass()', grammar.postfix_expression_p, 0 ) self.checkParser( 'my_variable++', grammar.postfix_expression_p ) self.checkParser( 'my_variable--', grammar.postfix_expression_p ) self.checkParser( 'my_instance->my_member++', grammar.postfix_expression_p ) self.checkParser( '(my_instance->my_member)->my_member++', grammar.postfix_expression_p ) self.checkParser( 'typename ::Base::attribute(1,2)', grammar.postfix_expression_p ) def testDeleteExpressionParser( self ): self.checkParser( 'delete p', grammar.delete_expression_p ) self.checkParser( '::delete p', grammar.delete_expression_p ) self.checkParser( 'delete ++p', grammar.delete_expression_p ) self.checkProducedNodes( '::delete [] p', grammar.delete_expression_p, TestNode( 'delete_operator', '::', 'delete', '[', ']', unqualified_id_n('p') ) ) self.checkParser( 'delete x.z', grammar.delete_expression_p ) def testNewTypeIdParser( self ): self.checkParser( 'int', grammar.new_type_id_alt_p ) self.checkParser( 'int *', grammar.new_type_id_alt_p ) self.checkParser( 'UserType[10][5]', grammar.new_type_id_alt_p ) self.checkParser( '(UserType*[10][5])', grammar.new_type_id_alt_p ) self.checkParserFail( 'const UserType', grammar.new_type_id_alt_p ) def testNewExpressionParser( self ): self.checkProducedNodes( 'new int', grammar.new_expression_p, TestNode( 'new_operator', 'new', TestNode('new_type_id', fundamental_type_n('int') ) ) ) self.checkParser( 'new int(3)', grammar.new_expression_p ) self.checkProducedNodes( '::new (__FILE__,__LINE__) int(3)', grammar.new_expression_p, TestNode( 'new_operator', '::', 'new', TestNode( 'new_placement', '(', TestNode( 'expression_list', TestNode( 'assignment_expression', unqualified_id_n('__FILE__') ), ',', TestNode( 'assignment_expression', unqualified_id_n('__LINE__') ) ), ')'), TestNode( 'new_type_id', fundamental_type_n('int') ), TestNode( 'new_initializer', '(', TestNode( 'expression_list', TestNode( 'assignment_expression', ('literal','3') ) ), ')' ) ) ) self.checkParser( 'new (int)(3)', grammar.new_expression_p ) self.checkParser( 'new int[10](7)', grammar.new_expression_p ) self.checkParser( 'new MyType[10](7)', grammar.new_expression_p ) self.checkParser( 'new (UserType)(7)', grammar.new_expression_p ) self.checkParser( 'new (UserType(3))(UserType)(7)', grammar.new_expression_p ) # need more test concerning new_type_id (should be restricted to plain type without cv) #expression_list structure for new_initializer need to be defined def testUnaryExpressionParser( self ): #require postfix_expression_p self.checkProducedTree( 'this', grammar.unary_expression_p, ('this_ref','this') ) self.checkParser( '(this)', grammar.unary_expression_p ) self.checkProducedNodes( '++my_variable', grammar.unary_expression_p, TestNode( 'unary_operator', '++', unqualified_id_n('my_variable') ) ) self.checkProducedNodes( '!my_variable', grammar.unary_expression_p, TestNode( 'unary_operator', '!', unqualified_id_n('my_variable') ) ) self.checkParser( '--my_variable', grammar.unary_expression_p ) self.checkParser( '-my_variable', grammar.unary_expression_p ) self.checkProducedNodes( 'sizeof !my_variable', grammar.unary_expression_p, TestNode( 'sizeof_operator', 'sizeof', TestNode( 'unary_operator', '!', unqualified_id_n('my_variable') ) ) ) self.checkProducedNodes( 'sizeof(++my_variable)', grammar.unary_expression_p, TestNode( 'sizeof_operator', 'sizeof', TestNode( 'braced_expr', '(', TestNode( 'expression', TestNode( 'unary_operator', '++', unqualified_id_n('my_variable') ) ), ')' ) ) ) self.checkParser( 'new int[10]', grammar.unary_expression_p ) self.checkParser( 'delete p', grammar.unary_expression_p ) self.checkParser( '(my_instance->my_member)->my_member++', grammar.unary_expression_p ) def testPMExpression( self ): self.checkProducedTree( '1234', grammar.pm_expression_p, ('literal','1234') ) def testLogicalOrExpressionParser( self ): self.checkProducedTree( '1234', grammar.logical_or_expression_p, ('literal','1234') ) self.checkParser( 'my_instance->*my_member', grammar.logical_or_expression_p ) self.checkParser( 'sizeof ++my_variable', grammar.logical_or_expression_p ) self.checkParser( '34 * 35', grammar.logical_or_expression_p ) self.checkProducedNodes( '34 * 35', grammar.logical_or_expression_p, TestNode( 'binary_operator', ... [truncated message content] |