You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.3 KiB
108 lines
3.3 KiB
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Processor functions
|
|
"""
|
|
from logging import getLogger
|
|
|
|
from .utils import IdentitySet
|
|
|
|
from .rules import Rule, RemoveMatch
|
|
|
|
log = getLogger(__name__).log
|
|
|
|
DEFAULT = '__default__'
|
|
|
|
POST_PROCESS = -2048
|
|
PRE_PROCESS = 2048
|
|
|
|
|
|
def _default_conflict_solver(match, conflicting_match):
|
|
"""
|
|
Default conflict solver for matches, shorter matches if they conflicts with longer ones
|
|
|
|
:param conflicting_match:
|
|
:type conflicting_match:
|
|
:param match:
|
|
:type match:
|
|
:return:
|
|
:rtype:
|
|
"""
|
|
if len(conflicting_match.initiator) < len(match.initiator):
|
|
return conflicting_match
|
|
if len(match.initiator) < len(conflicting_match.initiator):
|
|
return match
|
|
return None
|
|
|
|
|
|
class ConflictSolver(Rule):
|
|
"""
|
|
Remove conflicting matches.
|
|
"""
|
|
priority = PRE_PROCESS
|
|
|
|
consequence = RemoveMatch
|
|
|
|
@property
|
|
def default_conflict_solver(self):
|
|
"""
|
|
Default conflict solver to use.
|
|
"""
|
|
return _default_conflict_solver
|
|
|
|
def when(self, matches, context):
|
|
# pylint:disable=too-many-nested-blocks
|
|
to_remove_matches = IdentitySet()
|
|
|
|
public_matches = [match for match in matches if not match.private]
|
|
public_matches.sort(key=len)
|
|
|
|
for match in public_matches:
|
|
conflicting_matches = matches.conflicting(match)
|
|
|
|
if conflicting_matches:
|
|
# keep the match only if it's the longest
|
|
conflicting_matches = [conflicting_match for conflicting_match in conflicting_matches if
|
|
not conflicting_match.private]
|
|
conflicting_matches.sort(key=len)
|
|
|
|
for conflicting_match in conflicting_matches:
|
|
conflict_solvers = [(self.default_conflict_solver, False)]
|
|
|
|
if match.conflict_solver:
|
|
conflict_solvers.append((match.conflict_solver, False))
|
|
if conflicting_match.conflict_solver:
|
|
conflict_solvers.append((conflicting_match.conflict_solver, True))
|
|
|
|
for conflict_solver, reverse in reversed(conflict_solvers):
|
|
if reverse:
|
|
to_remove = conflict_solver(conflicting_match, match)
|
|
else:
|
|
to_remove = conflict_solver(match, conflicting_match)
|
|
if to_remove == DEFAULT:
|
|
continue
|
|
if to_remove and to_remove not in to_remove_matches:
|
|
both_matches = [match, conflicting_match]
|
|
both_matches.remove(to_remove)
|
|
to_keep = both_matches[0]
|
|
|
|
if to_keep not in to_remove_matches:
|
|
log(self.log_level, "Conflicting match %s will be removed in favor of match %s",
|
|
to_remove, to_keep)
|
|
|
|
to_remove_matches.add(to_remove)
|
|
break
|
|
return to_remove_matches
|
|
|
|
|
|
class PrivateRemover(Rule):
|
|
"""
|
|
Removes private matches rule.
|
|
"""
|
|
priority = POST_PROCESS
|
|
|
|
consequence = RemoveMatch
|
|
|
|
def when(self, matches, context):
|
|
return [match for match in matches if match.private]
|