def parse()

in Python/libraries/recognizers-date-time/recognizers_date_time/date_time/base_merged.py [0:0]


    def parse(self, source: ExtractResult, reference: datetime = None) -> Optional[DateTimeParseResult]:
        if not reference:
            reference = datetime.now()

        # Push, save the MOD string
        has_before = False
        has_after = False
        has_since = False
        has_around = False
        has_equal = False
        has_date_after = False
        match_is_after = False

        # "inclusive_mod" means MOD should include the start/end time
        # For example, cases like "on or later than", "earlier than or in" have inclusive modifier
        has_inclusive_mod = False
        mod_str = ''
        if source.meta_data and source.meta_data.has_mod:
            before_match = RegExpUtility.match_begin(self.config.before_regex, source.text, True)
            after_match = RegExpUtility.match_begin(self.config.after_regex, source.text, True)
            since_match = RegExpUtility.match_begin(self.config.since_regex, source.text, True)

            preLength = 0
            if before_match and before_match.success:
                preLength = before_match.index + before_match.length
            elif after_match and after_match.success:
                preLength = after_match.index + after_match.length
            elif since_match and since_match.success:
                preLength = since_match.index + since_match.length
            aroundText = source.text[preLength:]
            around_match = RegExpUtility.match_begin(self.config.around_regex, aroundText, True)
            equal_match = RegExpUtility.match_begin(self.config.equal_regex, source.text, True)

            if before_match and not before_match.success:
                before_match = RegExpUtility.match_end(self.config.before_regex, source.text, True)
                match_is_after = match_is_after or before_match.success

            if after_match and not after_match.success:
                after_match = RegExpUtility.match_end(self.config.after_regex, source.text, True)
                match_is_after = match_is_after or after_match.success

            if since_match and not since_match.success:
                since_match = RegExpUtility.match_end(self.config.since_regex, source.text, True)
                match_is_after = match_is_after or since_match.success

            if around_match and not around_match.success:
                around_match = RegExpUtility.match_end(self.config.around_regex, source.text, True)
                match_is_after = match_is_after or around_match.success

            if equal_match and not equal_match.success:
                equal_match = RegExpUtility.match_end(self.config.equal_regex, source.text, True)
                match_is_after = match_is_after or equal_match.success

            if around_match and around_match.success:
                has_around = True
                source.start += 0 if match_is_after else preLength + around_match.index + around_match.length
                source.length -= around_match.length if match_is_after else preLength + around_match.index + around_match.length
                source.text = source.text[0:source.length] if match_is_after else source.text[preLength + around_match.index + around_match.length:]
                mod_str = around_match.group() if match_is_after else aroundText[0:around_match.index + around_match.length]
            if before_match and before_match.success:
                has_before = True
                if not (around_match and around_match.success):
                    source.start += 0 if match_is_after else before_match.length
                    source.length -= before_match.length
                    source.text = source.text[0:source.length] if match_is_after else source.text[before_match.length:]
                mod_str = before_match.group() + mod_str
                if RegExpUtility.get_group(before_match.match[0], "include"):
                    has_inclusive_mod = True
            elif after_match and after_match.success:
                has_after = True
                if not (around_match and around_match.success):
                    source.start += 0 if match_is_after else after_match.length
                    source.length -= after_match.length
                    source.text = source.text[0:source.length] if match_is_after else source.text[after_match.length:]
                mod_str = after_match.group() + mod_str
                if RegExpUtility.get_group(after_match.match[0], "include"):
                    has_inclusive_mod = True
            elif since_match and since_match.success:
                has_since = True
                if not (around_match and around_match.success):
                    source.start += 0 if match_is_after else since_match.length
                    source.length -= since_match.length
                    source.text = source.text[0:source.length] if match_is_after else source.text[since_match.length:]
                mod_str = since_match.group() + mod_str
            elif equal_match and equal_match.success:
                has_equal = True
                source.start += 0 if match_is_after else equal_match.length
                source.length -= equal_match.length
                source.text = source.text[0:source.length] if match_is_after else source.text[equal_match.length:]
                mod_str = equal_match.group()
            elif source.type == Constants.SYS_DATETIME_DATEPERIOD and \
                    regex.search(self.config.year_regex, source.text) or source.type == Constants.SYS_DATETIME_DATE or \
                    source.type == Constants.SYS_DATETIME_TIME:
                # This has to be put at the end of the if, or cases like "before 2012" and "after 2012"
                # would fall into this
                # 2012 or after/above
                # 3 pm or later
                match = RegExpUtility.match_end(self.config.suffix_after, source.text, True)
                if match and match.success:
                    has_date_after = True
                    source.length -= match.length
                    source.text = source.text[0:source.length]
                    mod_str = match.group()

        result = self.parse_result(source, reference)
        if not result:
            return None

        # Pop, restore the MOD string
        if has_before and result.value:
            result.length += len(mod_str)
            result.start -= 0 if match_is_after else len(mod_str)
            result.text = result.text + mod_str if match_is_after else mod_str + result.text
            val = result.value

            val.mod = self.combine_mod(val.mod, TimeTypeConstants.BEFORE_MOD if not has_inclusive_mod else
                                       TimeTypeConstants.UNTIL_MOD)
            if has_around:
                val.mod = self.combine_mod(TimeTypeConstants.APPROX_MOD, val.mod)
                has_around = False
            result.value = val

        if has_after and result.value:
            result.length += len(mod_str)
            result.start -= len(mod_str)
            result.text = mod_str + result.text
            val = result.value

            val.mod = self.combine_mod(val.mod, TimeTypeConstants.AFTER_MOD if not has_inclusive_mod else
                                       TimeTypeConstants.SINCE_MOD)
            if has_around:
                val.mod = self.combine_mod(TimeTypeConstants.APPROX_MOD, val.mod)
                has_around = False
            result.value = val

        if has_since and result.value:
            result.length += len(mod_str)
            result.start -= len(mod_str)
            result.text = mod_str + result.text
            val = result.value
            val.mod = TimeTypeConstants.SINCE_MOD
            if has_around:
                val.mod = self.combine_mod(TimeTypeConstants.APPROX_MOD, val.mod)
                has_around = False
            result.value = val

        if has_around and result.value:
            result.length += len(mod_str)
            result.start -= len(mod_str)
            result.text = mod_str + result.text
            val = result.value
            val.mod = TimeTypeConstants.APPROX_MOD
            result.value = val

        if has_equal and result.value:
            result.length += len(mod_str)
            result.start -= len(mod_str)
            result.text = mod_str + result.text

        if has_date_after and result.value:
            result.length += len(mod_str)
            result.text = result.text + mod_str
            val = result.value
            val.mod = self.combine_mod(val.mod, TimeTypeConstants.SINCE_MOD)
            result.value = val
            has_since = True

        # For cases like "3 pm or later on monday"
        match = self.config.suffix_after.match(result.text)
        if result.value and (match.start() != 0 if match else match) and \
                result.type == Constants.SYS_DATETIME_DATETIME:
            val = result.value
            val.mod = self.combine_mod(val.mod, TimeTypeConstants.SINCE_MOD)
            result.value = val
            has_since = True

        if self.options & DateTimeOptions.SPLIT_DATE_AND_TIME and result.value and result.value.sub_date_time_entities:
            result.value = self._date_time_resolution_for_split(result)
        else:
            result = self.set_parse_result(
                result, has_before, has_after, has_since)

        return result