HUGE refactor, creating lots of modules, no code changes though!
This commit is contained in:
166
src/component.py
Normal file
166
src/component.py
Normal file
@@ -0,0 +1,166 @@
|
||||
from enum import Enum
|
||||
import logging
|
||||
|
||||
from restriction import Restriction
|
||||
from order import Order
|
||||
from representation_assigner import RepresentationAssigner
|
||||
|
||||
|
||||
class ComponentStatus(Enum):
|
||||
Optional = 0
|
||||
Required = 1
|
||||
Forbidden = 2
|
||||
|
||||
|
||||
class ComponentType(Enum):
|
||||
Other = 0
|
||||
Core = 2
|
||||
Core2w = 3
|
||||
|
||||
|
||||
class Component:
|
||||
def __init__(self, info):
|
||||
idx = info['cid']
|
||||
name = info['name'] if 'name' in info else None
|
||||
typ = ComponentType.Core if info['type'] == "core" else ComponentType.Other
|
||||
|
||||
if 'status' not in info:
|
||||
status = ComponentStatus.Required
|
||||
elif info['status'] == 'forbidden':
|
||||
status = ComponentStatus.Forbidden
|
||||
elif info['status'] == 'obligatory':
|
||||
status = ComponentStatus.Required
|
||||
elif info['status'] == 'optional':
|
||||
status = ComponentStatus.Optional
|
||||
else:
|
||||
raise NotImplementedError("strange status: {}".format(info['status']))
|
||||
|
||||
self.status = status
|
||||
self.name = name
|
||||
self.idx = idx
|
||||
self.restrictions = []
|
||||
self.next_element = []
|
||||
self.representation = []
|
||||
self.selection = {}
|
||||
self.type = typ
|
||||
|
||||
self.iter_ctr = 0
|
||||
|
||||
def add_next(self, next_component, link_label, order):
|
||||
self.next_element.append((next_component, link_label, Order.new(order)))
|
||||
|
||||
def set_restriction(self, restrictions_tag):
|
||||
if restrictions_tag is None:
|
||||
self.restrictions = [Restriction(None)]
|
||||
|
||||
elif restrictions_tag.tag == "restriction":
|
||||
self.restrictions = [Restriction(restrictions_tag)]
|
||||
|
||||
elif restrictions_tag.tag == "restriction_or":
|
||||
self.restrictions = [Restriction(el) for el in restrictions_tag]
|
||||
|
||||
else:
|
||||
raise RuntimeError("Unreachable")
|
||||
|
||||
def set_representation(self, representation):
|
||||
for rep in representation:
|
||||
crend = RepresentationAssigner()
|
||||
for feature in rep:
|
||||
crend.add_feature(feature.attrib)
|
||||
self.representation.append(crend)
|
||||
|
||||
def find_next(self, deps, comps, restrs, reprs):
|
||||
to_ret = []
|
||||
for d in deps:
|
||||
if d[0] == self.idx:
|
||||
_, idx, dep_label, order = d
|
||||
|
||||
next_component = Component(comps[idx])
|
||||
next_component.set_restriction(restrs[idx])
|
||||
next_component.set_representation(reprs[idx])
|
||||
to_ret.append(next_component)
|
||||
|
||||
self.add_next(next_component, dep_label, order)
|
||||
others = next_component.find_next(deps, comps, restrs, reprs)
|
||||
to_ret.extend(others)
|
||||
|
||||
return to_ret
|
||||
|
||||
def name_str(self):
|
||||
return "_" if self.name is None else self.name
|
||||
|
||||
def match(self, word):
|
||||
m1 = self._match_self(word)
|
||||
if m1 is None:
|
||||
return None
|
||||
|
||||
mn = self._match_next(word)
|
||||
if mn is None:
|
||||
return None
|
||||
|
||||
to_ret = [m1]
|
||||
for cmatch in mn:
|
||||
# if good match but nothing to add, just continue
|
||||
if len(cmatch) == 0:
|
||||
continue
|
||||
|
||||
# if more than one match found for particular component
|
||||
elif len(cmatch) > 1:
|
||||
# if more than one match in multiple components, NOPE!
|
||||
if len(to_ret) > 1:
|
||||
logging.warning("Strange multiple match: {}".format(
|
||||
str([w.id for w in cmatch[0].values()])))
|
||||
|
||||
for tr in to_ret:
|
||||
tr.update(cmatch[0])
|
||||
continue
|
||||
|
||||
# yeah, so we have found more than one match, =>
|
||||
# more than one element in to_ret
|
||||
to_ret = [{**dict(to_ret[0]), **m} for m in cmatch]
|
||||
|
||||
else:
|
||||
for tr in to_ret:
|
||||
tr.update(cmatch[0])
|
||||
|
||||
return to_ret
|
||||
|
||||
def _match_self(self, word):
|
||||
# matching
|
||||
for restr in self.restrictions:
|
||||
if restr.match(word): # match either
|
||||
return {self.idx: word}
|
||||
|
||||
def _match_next(self, word):
|
||||
# matches for every component in links from this component
|
||||
to_ret = []
|
||||
|
||||
# need to get all links that match
|
||||
for next, link, order in self.next_element:
|
||||
next_links = word.get_links(link)
|
||||
to_ret.append([])
|
||||
|
||||
# good flag
|
||||
good = next.status != ComponentStatus.Required
|
||||
for next_word in next_links:
|
||||
if not order.match(word, next_word):
|
||||
continue
|
||||
|
||||
match = next.match(next_word)
|
||||
|
||||
if match is not None:
|
||||
# special treatement for forbidden
|
||||
if next.status == ComponentStatus.Forbidden:
|
||||
good = False
|
||||
break
|
||||
|
||||
else:
|
||||
assert type(match) is list
|
||||
to_ret[-1].extend(match)
|
||||
good = True
|
||||
|
||||
# if none matched, nothing found!
|
||||
if not good:
|
||||
return None
|
||||
|
||||
return to_ret
|
||||
Reference in New Issue
Block a user