<commit_before>__author__ = 'kevin'

import re

from attacksurfacemeter.loaders.base_line_parser import BaseLineParser


class GprofLineParser(BaseLineParser):
    """"""
    _instance = None

    @staticmethod
    def get_instance(gprof_line=None):
        if GprofLineParser._instance is None:
            GprofLineParser._instance = GprofLineParser()

        GprofLineParser._instance.load(gprof_line)

        return GprofLineParser._instance

    def __init__(self):
        super(GprofLineParser, self).__init__()

    def load(self, gprof_line):
        self.__init__()

        match = re.search(r"(\[\d+\])( +)((\d+\.\d+)( +)){3}(\d*\+*\d*)( +)([\w.]+)( +)(.*)", gprof_line)

        if not match:
            match = re.search(r"(\[\d+)( +)((\d+\.\d+)( +)){3}([\d\+]*)( +)([\w.]+)( +)(.*)", gprof_line)

        if match:
            self._function_name = match.group(8)
            self._function_signature = GprofLineParser._get_file_name(match.group(10))
        else:
            match = re.search(r"( +)((\d+\.\d+)( +)){2}(\d+/\d+)( +)([\w.]+)( +)(.*)", gprof_line)

            if match:
                self._function_name = match.group(7)
                self._function_signature = GprofLineParser._get_file_name(match.group(9))
            else:
                match = re.search(r"( +)(\d+)( +)(\w+)( +)(.*)", gprof_line)

                if match:
                    try:
                        self._function_name = match.group(4)
                        self._function_signature = GprofLineParser._get_file_name(match.group(6))
                    except:
                        raise ValueError("Can not parse a call from the received text.")
                else:
                    raise ValueError("Can not parse a call from the received text.")

    @staticmethod
    def _get_file_name(text_fragment):
        """
            Obtains the name of the file where the function represented is defined.

            Args:
               text_fragment: A String containing a fragment from a line of gprof's output.

            Returns:
                A String containing the name of the file where the function detailed in the fragment is defined.
        """
        regex = r"([-.\w\/]+\.(?:c|asm|h))"

        match = re.search(regex, text_fragment)

        if match:
            return re.search(regex, text_fragment).group(0)
        else:
            return ""
<commit_msg>gprof line parsing now uses fewer regexes<commit_after>import re

from attacksurfacemeter.loaders.base_line_parser import BaseLineParser

# Regular expression to parse the name field from gprof call graph
RE_NAME = re.compile('^(\w+)(?:(?:\(?.*\)?\s\()([\w\.\-\/]+\.\w+))?')


class GprofLineParser(BaseLineParser):
    """"""
    _instance = None

    @staticmethod
    def get_instance(gprof_line=None):
        if GprofLineParser._instance is None:
            GprofLineParser._instance = GprofLineParser()

        GprofLineParser._instance.load(gprof_line)

        return GprofLineParser._instance

    def __init__(self):
        super(GprofLineParser, self).__init__()

    def load(self, gprof_line):
        self.__init__()

        # The field in the gprof call graph that contains the name of the
        # function and the file containing the function begins at column 46 
        # (deduced from gprof source code)
        name = gprof_line[45:]
        match = RE_NAME.match(name.strip())
        
        if match:
            groups = match.groups(default='')
            self._function_name = groups[0]
            self._function_signature = groups[1]
        else:
            raise ValueError(
                'Unable to parse gprof line - "{0}"'.format(gprof_line)
            )


{'fraction_non_alphanumeric': 0.13311775801670708, 'fraction_numerical': 0.004850444624090542, 'mean_word_length': 2.1010860484544693, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2882453', 'n_tokens_mistral': 1123, 'n_tokens_neox': 1074, 'n_words': 258}