From fc39b97d4249d4b4c1488153e2c1e3eade0e8551 Mon Sep 17 00:00:00 2001 From: "Mike D. Lowis" Date: Wed, 11 Apr 2012 16:54:11 -0400 Subject: [PATCH] 100% test coverage dlparser and dllexer --- source/dlparser/dlparser.cpp | 26 +-- source/dlparser/dlparser.h | 1 - source/dlparser/macro/pattern.cpp | 52 +++-- source/dlparser/macro/pattern.h | 1 + tests/test_dlparser.cpp | 354 ++++++++++++++++++++++++++---- 5 files changed, 352 insertions(+), 82 deletions(-) diff --git a/source/dlparser/dlparser.cpp b/source/dlparser/dlparser.cpp index fb35b95..ecd93d5 100644 --- a/source/dlparser/dlparser.cpp +++ b/source/dlparser/dlparser.cpp @@ -140,10 +140,6 @@ AST* DLParser::MacroPatternMatch(Pattern patt) case EXPR_TYP: param = LogicalExpr(); break; - - default: - throw Exception( lookaheadToken(1) ); - break; } if( !isSpeculating() ) @@ -181,24 +177,6 @@ bool DLParser::speculate_GroupExpr(void) return success; } -bool DLParser::speculate_MapLiteral(void) -{ - bool success = true; - - mark(); - try - { - delete MapLiteral(); - } - catch (Exception e) - { - success = false; - } - release(); - - return success; -} - AST* DLParser::Program(void) { AST* node = _new AST( PROGRAM ); @@ -560,7 +538,9 @@ Pattern DLParser::MacroPattern(void) } else { - throw Exception( lookaheadToken(1) ); + Exception ex( lookaheadToken(1) ); + ex << "Unrecognized macro parameter type: " << lookaheadToken(1).text(); + throw ex; } } while( lookaheadType(1) == ID ); diff --git a/source/dlparser/dlparser.h b/source/dlparser/dlparser.h index 5053a1c..8fc3530 100644 --- a/source/dlparser/dlparser.h +++ b/source/dlparser/dlparser.h @@ -17,7 +17,6 @@ class DLParser : public BTParser void parse(void); bool isMacro(Token& token); bool speculate_GroupExpr(void); - bool speculate_MapLiteral(void); bool speculate_MacroPatternMatch(Pattern patt); /********************************************************************** diff --git a/source/dlparser/macro/pattern.cpp b/source/dlparser/macro/pattern.cpp index 15dfce7..0eb4575 100644 --- a/source/dlparser/macro/pattern.cpp +++ b/source/dlparser/macro/pattern.cpp @@ -41,21 +41,9 @@ void Pattern::apply(AST* cur,std::vector& params) { if ((*it)->type() == SYMBOL) { - unsigned int arg; - istringstream((*it)->text()) >> arg; - - if (arg <= params.size()) - { - AST* temp = *it; - *it = params[ arg - 1 ]; - delete temp; - } - else - { - Exception ex; - ex << "Invalid parameter number"; - throw ex; - } + AST* temp = *it; + *it = expand( *it, params ); + delete temp; } else { @@ -65,10 +53,40 @@ void Pattern::apply(AST* cur,std::vector& params) } } +AST* Pattern::expand(const AST* cur,std::vector& params) +{ + AST* ret = NULL; + unsigned int arg; + istringstream(cur->text()) >> arg; + + if (arg <= params.size()) + { + ret = params[ arg - 1 ]; + } + else + { + Exception ex; + ex << "Invalid parameter number"; + throw ex; + } + + return ret; +} + AST* Pattern::accept(std::vector& params) { - AST* ret = expr_ast->clone(); - apply( ret, params ); + AST* ret = NULL; + + if( expr_ast->type() == SYMBOL ) + { + ret = expand( expr_ast, params ); + } + else + { + ret = expr_ast->clone(); + apply( ret, params ); + } + return ret; } diff --git a/source/dlparser/macro/pattern.h b/source/dlparser/macro/pattern.h index 33c9be4..512270e 100644 --- a/source/dlparser/macro/pattern.h +++ b/source/dlparser/macro/pattern.h @@ -31,6 +31,7 @@ class Pattern { std::list::iterator begin(); std::list::iterator end(); AST* accept(std::vector& params); + AST* expand(const AST* cur, std::vector& params); }; #endif diff --git a/tests/test_dlparser.cpp b/tests/test_dlparser.cpp index 5f8a6d9..1b0e356 100644 --- a/tests/test_dlparser.cpp +++ b/tests/test_dlparser.cpp @@ -53,23 +53,21 @@ void TestParserWithInput(std::string& input, eTokenTypes expected_types[]) parser.process( tester ); } -//void TestParserThrowsException(std::string& input) -//{ -// // Setup -// //std::istringstream input_stream(input); -// //DLLexer* lexer = new DLLexer(input_stream); -// -// //CHECK_THROW( lexer->next(), Exception ); -// -// // Cleanup -// //delete lexer; -//} +void TestParserThrowsException(std::string& input) +{ + // Setup + std::istringstream input_stream(input); + DLParser parser; + + // Parse the test input + parser.input( new DLLexer( input_stream ) ); + CHECK_THROW( parser.parse(), Exception ); +} //----------------------------------------------------------------------------- // Begin Unit Tests //----------------------------------------------------------------------------- namespace { - //------------------------------------------------------------------------- // Test Parsing of Data Type Literals //------------------------------------------------------------------------- @@ -360,25 +358,35 @@ namespace { // Grouping Expression //-------------------- - //TEST(Parse_A_Grouping_Expression_With_A_Lower_Priority_Statement) - //{ - // std::string input("(foo.bar).somethin"); - // eTokenTypes expected[] = { - // ID, ID, MEMB, ID, MEMB, - // PROGRAM - // }; - // TestParserWithInput( input, expected ); - //} - - //TEST(Parse_A_Grouping_Expression_With_A_Higher_Priority_Statement) - //{ - // std::string input("(1+1).somethin"); - // eTokenTypes expected[] = { - // NUM, NUM, ADD, ID, MEMB, - // PROGRAM - // }; - // TestParserWithInput( input, expected ); - //} + TEST(Parse_A_Grouping_Expression) + { + std::string input("( 1 + 1 )"); + eTokenTypes expected[] = { + NUM, NUM, ADD, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Parse_A_Grouping_Expression_With_A_Lower_Priority_Statement) + { + std::string input("(1 + 2) * 3"); + eTokenTypes expected[] = { + NUM, NUM, ADD, NUM, MUL, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Parse_A_Grouping_Expression_With_A_Higher_Priority_Statement) + { + std::string input("1 + (2 * 3)"); + eTokenTypes expected[] = { + NUM, NUM, NUM, MUL, ADD, + PROGRAM + }; + TestParserWithInput( input, expected ); + } // Function Application //--------------------- @@ -562,104 +570,362 @@ namespace { TestParserWithInput( input, expected ); } + TEST(Parse_An_Assignment_To_An_Array_Member) + { + std::string input("foo[1] = bar"); + eTokenTypes expected[] = { + ID, NUM, ID, MUTATE, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Parse_An_Assignment_To_A_Map_Member) + { + std::string input("foo[\"bar\"] = bar"); + eTokenTypes expected[] = { + ID, STRING, ID, MUTATE, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + //------------------------------------------------------------------------- // Test Macro Definition and Expansion //------------------------------------------------------------------------- + + // Map + //---- TEST(Parse_A_Macro_Taking_One_Map) { std::string input("\% foo [ (M) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_Map_Parameter) + { + std::string input( + "\% foo [ (M) : $1 ]\n" + "foo @{}" + ); + eTokenTypes expected[] = { + MACRO, + MAP, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Vector + //------- TEST(Parse_A_Macro_Taking_One_Vector) { std::string input("\% foo [ (V) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_Vector_Parameter) + { + std::string input( + "\% foo [ (V) : $1 ]\n" + "foo []" + ); + eTokenTypes expected[] = { + MACRO, + VECTOR, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // List + //----- TEST(Parse_A_Macro_Taking_One_List) { std::string input("\% foo [ (L) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_List_Parameter) + { + std::string input( + "\% foo [ (L) : $1 ]\n" + "foo ()" + ); + eTokenTypes expected[] = { + MACRO, + LIST, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Block + //------ TEST(Parse_A_Macro_Taking_One_Block) { std::string input("\% foo [ (B) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_Block_Parameter) + { + std::string input( + "\% foo [ (B) : $1 ]\n" + "foo {}" + ); + eTokenTypes expected[] = { + MACRO, + PARAMS, BLOCK, FUNC, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Id + //--- TEST(Parse_A_Macro_taking_One_Id) { std::string input("\% foo [ (I) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_Id_Parameter) + { + std::string input( + "\% foo [ (I) : $1 ]\n" + "foo bar" + ); + eTokenTypes expected[] = { + MACRO, + ID, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Number + //------- TEST(Parse_A_Macro_Taking_One_Number) { std::string input("\% foo [ (N) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Use_A_Macro_With_A_Number_Parameter) + { + std::string input( + "\% foo [ (N) : $1 ]\n" + "foo 1.0" + ); + eTokenTypes expected[] = { + MACRO, + NUM, PROGRAM }; TestParserWithInput( input, expected ); } + // Character + //---------- TEST(Parse_A_Macro_Taking_One_Character) { std::string input("\% foo [ (C) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_Character_Parameter) + { + std::string input( + "\% foo [ (C) : $1 ]\n" + "foo 'a'" + ); + eTokenTypes expected[] = { + MACRO, + CHAR, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // String + //------- TEST(Parse_A_Macro_Taking_One_String) { std::string input("\% foo [ (St) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_String_Parameter) + { + std::string input( + "\% foo [ (St) : $1 ]\n" + "foo \"\"" + ); + eTokenTypes expected[] = { + MACRO, + STRING, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Symbol + //------- TEST(Parse_A_Macro_Taking_One_Symbol) { std::string input("\% foo [ (Sy) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, PROGRAM }; TestParserWithInput( input, expected ); } + TEST(Use_A_Macro_With_A_Symbol_Parameter) + { + std::string input( + "\% foo [ (Sy) : $1 ]\n" + "foo $bar" + ); + eTokenTypes expected[] = { + MACRO, + SYMBOL, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Expression + //----------- TEST(Parse_A_Macro_Taking_One_Expression) { std::string input("\% foo [ (E) : $1 ]"); eTokenTypes expected[] = { - ID, ID, ASSIGN, + MACRO, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Use_A_Macro_With_A_Expression_Parameter) + { + std::string input( + "\% foo [ (E) : $1 ]\n" + "foo 1 + 1" + ); + eTokenTypes expected[] = { + MACRO, + NUM, NUM, ADD, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + // Corner Cases + //------------- + TEST(Throw_Exception_When_Invalid_Macro_Param_Type_Used) + { + std::string input("\% foo [ (Z) : $1 ]"); + TestParserThrowsException(input); + } + + TEST(Throw_Exception_When_No_Macro_Pattern_Matches) + { + std::string input( + "\% foo [ (I) : $1 ]\n" + "foo 1.0" //Expecting and ID but a number is given + ); + TestParserThrowsException(input); + } + + TEST(Parse_A_Macro_With_Multiple_Parameter_Types) + { + std::string input("\% tuple [ (E E) : ($1,$2) ]"); + eTokenTypes expected[] = { + MACRO, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Use_A_Macro_With_Multiple_Parameter_Types) + { + std::string input( + "\% tuple [ (E E) : ($1,$2) ]\n" + "tuple 1.0 'a'" + ); + eTokenTypes expected[] = { + MACRO, + NUM, CHAR, LIST, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Parse_A_Macro_With_Multiple_Patterns) + { + std::string input( + // Emulate an If statement + "\% if [\n" + " (E B B) : exec_if($1,$2,$3),\n" + " (E B) : exec_if($1,$2)\n" + "]" + ); + eTokenTypes expected[] = { + MACRO, + PROGRAM + }; + TestParserWithInput( input, expected ); + } + + TEST(Use_A_Macro_With_Multiple_Patterns) + { + std::string input( + // Emulate an If statement + "\% if [\n" + " (E B B) : exec_if($1,$2,$3),\n" + " (E B) : exec_if($1,$2)\n" + "]\n" + "if (1 == 1) {}\n" + "if (1 == 1) {} {}\n" + ); + eTokenTypes expected[] = { + MACRO, + ID, NUM, NUM, EQ, PARAMS, BLOCK, FUNC, LIST, FN_CALL, + ID, NUM, NUM, EQ, PARAMS, BLOCK, FUNC, PARAMS, BLOCK, FUNC, LIST, FN_CALL, PROGRAM }; TestParserWithInput( input, expected ); @@ -674,4 +940,10 @@ namespace { eTokenTypes expected[] = { PROGRAM }; TestParserWithInput( input, expected ); } + + TEST(Throw_Exception_When_Literal_On_Left_Side_Of_Assignment) + { + std::string input("[] = 5"); + TestParserThrowsException(input); + } } -- 2.52.0