SethVan

format_test3

Sep 23rd, 2022 (edited)
1,244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.16 KB | None | 0 0
  1. /* SPDX-License-Identifier: GPL-3.0-only or GPL-3.0-or-later */
  2. /*
  3.  * mutator.cpp: This class mutates the source input using the selected mutations from the MutationsSelector class.
  4.  *
  5.  * Copyright (c) 2022 RightEnd
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation, either version 3 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  19.  */
  20.  
  21. #include "commands/mutate/mutator.hpp"
  22.  
  23. #include <algorithm>
  24. #include <cassert>
  25. #include <set>
  26. #include <sstream>
  27. #include <string_view>
  28.  
  29. #include "commands/mutate/jpcre2.hpp"
  30. #include "common.hpp"
  31. #include "excepts.hpp"
  32.  
  33. #define INCREMENT_POS_AND_CONTINUE \
  34.     {                              \
  35.         ++pos;                     \
  36.         continue;                  \
  37.     }
  38.  
  39. typedef jpcre2::select<char> jp;
  40.  
  41. Mutator::Mutator( std::string _sourceString, std::string& _outputString, SelectedMutVec _selectedMutations,
  42.                   CLIOptions* _opts )
  43.     : sourceString{ _sourceString },
  44.       outputString{ _outputString },
  45.       selectedMutations{ _selectedMutations },
  46.       opts{ _opts } {
  47.     mutate();
  48. }
  49.  
  50. void Mutator::mutate() {
  51.     std::string strippedStr = removeSrcStrComments();
  52.     for ( const auto& sm : selectedMutations ) {
  53.         if ( sm.data.isRegex ) {
  54.             regexReplace( strippedStr, sm );
  55.         }
  56.         else if ( isMultilineString( sm.pattern ) ) {
  57.             multilineReplace( strippedStr, sm );
  58.         }
  59.         else {
  60.             singleLineReplace( strippedStr, sm );
  61.         }
  62.     }
  63.     outputString = strippedStr;
  64. }
  65.  
  66. // adapted from https://stackoverflow.com/questions/4643512/replace-substring-with-another-substring-c/14678946#14678946
  67. void Mutator::singleLineReplace( std::string& subject, const SelectedMutation& sm ) {
  68.     int matches = 0;
  69.     size_t pos = 0;
  70.     std::string::iterator begin, end;
  71.  
  72.     while ( ( pos = subject.find( sm.pattern, pos ) ) != std::string::npos ) {
  73.         begin = end = subject.begin() + pos;
  74.         std::string patternString{ sm.pattern };
  75.         std::string permutationString;
  76.         size_t lengthToRemove = sm.pattern.length();
  77.  
  78.         while ( *( begin - 1 ) != '\n' ) {
  79.             --begin;
  80.         }
  81.  
  82.         if ( !edgesGoodAndReplacementSuccessful( begin, end, patternString, subject, sm, permutationString, pos,
  83.                                                  lengthToRemove, matches ) ) {
  84.             INCREMENT_POS_AND_CONTINUE;
  85.         }
  86.     }
  87.     checkCountOfMatches( matches, sm );
  88. }
  89.  
  90. void Mutator::regexReplace( std::string& subject, const SelectedMutation& sm ) {
  91.     size_t index = sm.pattern.find_last_of( '/' );
  92.     if ( index == std::string::npos ) {
  93.         std::ostringstream os;
  94.         os << "Regex pattern cell in row beginning on line number " << sm.data.lineNumber << " is missing final \'/\'."
  95.            << std::endl;
  96.         throw TSVParsingException( os.str() );
  97.     }
  98.  
  99.     auto [pattern, modifiers] = getPatternAndModifiers( index, sm );
  100.     std::set<std::string> matches = getRegexMatches( pattern, subject, modifiers );
  101.  
  102.     for ( const auto& str : matches ) {
  103.         std::string regexMutation = jp::Regex( pattern ).replace( str, sm.mutation, modifiers );
  104.         SelectedMutation regexSm( str, regexMutation, sm.data );
  105.         if ( regexSm.pattern.size() ) {
  106.             if ( isMultilineString( regexSm.pattern ) ) {
  107.                 multilineReplace( subject, regexSm );
  108.             }
  109.             else {
  110.                 singleLineReplace( subject, regexSm );
  111.             }
  112.         }
  113.     }
  114. }
  115.  
  116. // This is just a temporary stand in method to use until we have better regex patterns
  117. // So that we can continue developing meanwhile
  118. std::string Mutator::removeSrcStrComments() {
  119.     std::string subject = jp::Regex( "\\/\\*.*\\*\\/" ).replace( sourceString, "", "gm" );
  120.     subject = jp::Regex( ";.*?\\/\\/[^\"\n]*\n" ).replace( subject, ";\n", "gm" );
  121.     subject = jp::Regex( "({\\s*?\\/\\/[^\"\n]*\n)" ).replace( subject, "{\n", "gm" );
  122.     subject = jp::Regex( "()\\s*?\\/\\/[^\"\n]*\n)" ).replace( subject, ")\n", "gm" );
  123.     subject = jp::Regex( "\n\\s*?\\/\\/.*\n" ).replace( subject, "\n", "gm" );
  124.     return subject;
  125. }
  126.  
  127. // Does not consider consecutive newlines '\n' to mean multi line if they are at the beginning or end
  128. bool Mutator::isMultilineString( std::string str ) const {
  129.     auto it = str.begin();
  130.     if ( ( it + 1 ) != str.end() ) {
  131.         while ( ( it + 2 ) != str.end() ) {
  132.             ++it;
  133.             if ( ( *it == '\n' || *it == '\r' ) && ( *( it - 1 ) != '\n' ) && ( *( it - 1 ) != '\r' ) &&
  134.                  ( *( it + 1 ) != '\n' ) && ( *( it + 1 ) != '\r' ) ) {
  135.                 return true;
  136.             }
  137.         }
  138.     }
  139.     return false;
  140. }
  141.  
  142. std::vector<std::string> Mutator::separateLinesIntoVector( std::string str ) {
  143.     std::istringstream is{ str };
  144.     std::string line;
  145.     std::vector<std::string> vec;
  146.  
  147.     while ( std::getline( is, line ) ) {
  148.         vec.push_back( line + "\n" );
  149.     }
  150.     vec.back().pop_back();
  151.     return vec;
  152. }
  153.  
  154. void Mutator::multilineReplace( std::string& subject, const SelectedMutation& sm ) {
  155.     int matches = 0, indentation = 0;
  156.     size_t pos = 0;
  157.     std::string::iterator begin, end, startPos;
  158.     std::vector<std::string> lines = separateLinesIntoVector( sm.pattern );
  159.  
  160.     while ( ( pos = subject.find( lines[0], pos ) ) != std::string::npos ) {
  161.         begin = end = startPos = subject.begin() + pos;
  162.         indentation = 0;
  163.         while ( *( begin - 1 ) != '\n' ) {
  164.             --begin;
  165.             ++indentation;
  166.         }
  167.         size_t lengthToRemove = sm.pattern.length();
  168.         std::string patternString{ sm.pattern };
  169.         std::string permutationString;
  170.  
  171.         if ( substringIsMatch( subject, startPos, patternString ) ) {
  172.             if ( !edgesGoodAndReplacementSuccessful( begin, end, patternString, subject, sm, permutationString, pos,
  173.                                                      lengthToRemove, matches ) ) {
  174.                 ++pos;
  175.             }
  176.             continue;
  177.         }
  178.         std::string indent( begin, end );  // to use later if first check of second line does not match
  179.         auto linesIt = lines.begin();
  180.  
  181.         if ( !lineEdgesAreGood( begin, end, *linesIt, subject ) ) {
  182.             INCREMENT_POS_AND_CONTINUE;
  183.         }
  184.         // At this point lines[0] has matched its line
  185.         bool addIndentation = false;
  186.  
  187.         if ( !line2IsGood( subject, end, linesIt, indentation, addIndentation, begin ) ) {
  188.             INCREMENT_POS_AND_CONTINUE;
  189.         }
  190.         if ( !lines3AndOnAreGood( addIndentation, indentation, subject, begin, end, linesIt, lines.end() ) ) {
  191.             INCREMENT_POS_AND_CONTINUE;
  192.         }
  193.         lengthToRemove = end - startPos;
  194.  
  195.         setPermutationIndentation( sm, addIndentation, permutationString, indent );
  196.  
  197.         ++matches;
  198.         if ( sm.data.isNewLined ) {
  199.             pos = end - subject.begin() + 1;
  200.             permutationString.push_back( '\n' );
  201.             lengthToRemove = 0;
  202.         }
  203.         subject.replace( pos, lengthToRemove, permutationString );
  204.         pos += permutationString.length();
  205.     }
  206.     checkCountOfMatches( matches, sm );
  207. }
  208.  
  209. bool Mutator::lineEdgesAreGood( std::string::iterator& begin, std::string::iterator& end, const std::string& str,
  210.                                 const std::string& subject ) {
  211.     if ( lastNonWhiteSpace( begin, end ) != std::string::npos ) {
  212.         return false;
  213.     }
  214.     begin = ( end += ( str.size() ) );
  215.     if ( *( begin - 1 ) == '\n' ) {
  216.         return true;
  217.     }
  218.     while ( ( *end != '\n' ) && ( end != subject.end() ) ) {
  219.         ++end;
  220.     }
  221.     return ( lastNonWhiteSpace( begin, end ) == std::string::npos );
  222. }
  223.  
  224. bool Mutator::substringIsMatch( const std::string& subject, std::string::iterator it, const std::string& str ) {
  225.     if ( str.size() ) {
  226.         for ( const auto& c : str ) {
  227.             if ( it != subject.end() ) {
  228.                 if ( *it != c ) {
  229.                     return false;
  230.                 }
  231.                 ++it;
  232.             }
  233.             else {
  234.                 return false;
  235.             }
  236.         }
  237.     };
  238.     return true;
  239. }
  240.  
  241. void Mutator::setPermutationIndentation( const SelectedMutation& sm, bool addIndentation,
  242.                                          std::string& permutationString, const std::string& indent ) {
  243.     if ( sm.data.isNewLined ) {
  244.         permutationString = indent;
  245.     }
  246.     if ( isMultilineString( sm.mutation ) && addIndentation ) {
  247.         std::vector<std::string> permLines = separateLinesIntoVector( sm.mutation );
  248.         permutationString += permLines[0];
  249.  
  250.         for ( size_t i = 1; i < permLines.size(); ++i ) {
  251.             permutationString += indent + permLines[i];
  252.         }
  253.     }
  254.     else {
  255.         permutationString += std::string( sm.mutation );
  256.     }
  257. }
  258.  
  259. bool Mutator::edgesGoodAndReplacementSuccessful( std::string::iterator& begin, std::string::iterator& end,
  260.                                                  std::string& patternString, std::string& subject,
  261.                                                  const SelectedMutation& sm, std::string& permutationString,
  262.                                                  size_t& pos, size_t lengthToRemove, int& matches ) {
  263.     std::string indent( begin, end );
  264.     if ( !lineEdgesAreGood( begin, end, patternString, subject ) ) {
  265.         return false;
  266.     }
  267.     bool addIndentation = !isMultilineString( sm.pattern );
  268.  
  269.     setPermutationIndentation( sm, addIndentation, permutationString, indent );
  270.  
  271.     if ( sm.data.isNewLined ) {
  272.         permutationString.push_back( '\n' );
  273.         if ( end == subject.end() ) {
  274.             subject.push_back( '\n' );
  275.             end = subject.end() - 1;
  276.         }
  277.         pos = end - subject.begin() + 1;
  278.         lengthToRemove = 0;
  279.     }
  280.  
  281.     ++matches;
  282.     subject.replace( pos, lengthToRemove, permutationString );
  283.     pos += permutationString.length();
  284.     return true;
  285. }
  286.  
  287. void Mutator::checkCountOfMatches( int matches, const SelectedMutation& sm ) {
  288.     if ( !matches ) {
  289.         opts->addNoMatchLine( sm.data.lineNumber );
  290.     }
  291.     if ( matches > 1 ) {
  292.         opts->addMultipleMatchLine( sm.data.lineNumber );
  293.     }
  294. }
  295.  
  296. bool Mutator::lines3AndOnAreGood( bool addIndentation, int indentation, const std::string& subject,
  297.                                   std::string::iterator& begin, std::string::iterator& end,
  298.                                   std::vector<std::string>::iterator& linesIt,
  299.                                   const std::vector<std::string>::iterator& vecEnd ) {
  300.     while ( ++linesIt != vecEnd ) {
  301.         if ( !wholeSublineOfMultilineIsMatch( addIndentation, indentation, subject, begin, end, *linesIt ) ) {
  302.             return false;
  303.         }
  304.     }
  305.     return true;
  306. }
  307.  
  308. bool Mutator::wholeSublineOfMultilineIsMatch( bool addIndentation, int indentation, const std::string& subject,
  309.                                               std::string::iterator& begin, std::string::iterator& end,
  310.                                               const std::string& str ) {
  311.     if ( addIndentation ) {
  312.         end = begin + indentation;
  313.     }
  314.     if ( !substringIsMatch( subject, end, str ) ) {
  315.         return false;
  316.     }
  317.     if ( addIndentation ) {
  318.         end = begin + indentation;
  319.     }
  320.     if ( !lineEdgesAreGood( begin, end, str, subject ) ) {
  321.         return false;
  322.     }
  323.     return true;
  324. }
  325.  
  326. bool Mutator::line2IsGood( const std::string& subject, std::string::iterator& end,
  327.                            std::vector<std::string>::iterator& linesIt, int indentation, bool& addIndentation,
  328.                            std::string::iterator& begin ) {
  329.     if ( !substringIsMatch( subject, end, *( ++linesIt ) ) ) {
  330.         if ( indentation ) {
  331.             addIndentation = true;  // try again but now indented
  332.         }
  333.         else {
  334.             return false;
  335.         }
  336.  
  337.         if ( !wholeSublineOfMultilineIsMatch( addIndentation, indentation, subject, begin, end, *linesIt ) ) {
  338.             return false;
  339.         }
  340.     }
  341.     else if ( !lineEdgesAreGood( begin, end, *linesIt, subject ) ) {
  342.         return false;
  343.     }
  344.     return true;
  345. }
  346.  
  347. std::tuple<std::string, std::string> Mutator::getPatternAndModifiers( size_t index, const SelectedMutation& sm ) {
  348.     std::string defaultFlags( "AFgnm" );
  349.     std::string pattern{ sm.pattern, 0, index };
  350.     std::string userModifierInput( sm.pattern.begin() + index + 1, sm.pattern.end() );
  351.     std::string modifiers;
  352.     index = userModifierInput.find_first_of( '-' );
  353.     if ( index != std::string::npos ) {
  354.         std::string additionalModFlags( userModifierInput, 0, index );
  355.         std::string flagsToBeRemoved( userModifierInput.begin() + index + 1, userModifierInput.end() );
  356.         if ( additionalModFlags.size() ) {
  357.             modifiers.append( additionalModFlags );
  358.         }
  359.         for ( const auto& c : defaultFlags ) {
  360.             if ( ( index = flagsToBeRemoved.find_first_of( c ) ) == std::string::npos ) {
  361.                 modifiers.push_back( c );
  362.             }
  363.         }
  364.     }
  365.     else {
  366.         modifiers = userModifierInput + defaultFlags;
  367.     }
  368.     return { pattern, modifiers };
  369. }
  370.  
  371. std::set<std::string> Mutator::getRegexMatches( const std::string& pattern, const std::string& subject,
  372.                                                 const std::string& modifiers ) {
  373.     jp::VecNum vec_num;
  374.     jp::Regex re( pattern );
  375.     jp::RegexMatch rr;
  376.     rr.setRegexObject( &re )
  377.         .setSubject( &subject )
  378.         .addModifier( modifiers )
  379.         .setNumberedSubstringVector( &vec_num )
  380.         .match();
  381.  
  382.     std::set<std::string> strSet;
  383.     for ( auto& vec : vec_num ) {
  384.         for ( auto& n : vec ) {
  385.             strSet.insert( n );
  386.         }
  387.     }
  388.  
  389.     return strSet;
  390. }
Advertisement
Add Comment
Please, Sign In to add comment