Source code for rhoknp.cohesion.argument
from abc import ABC, abstractmethod
from enum import Enum
from typing import TYPE_CHECKING
from rhoknp.cohesion.exophora import ExophoraReferent
from rhoknp.cohesion.predicate import Predicate
if TYPE_CHECKING:
from rhoknp.cohesion.pas import Pas
from rhoknp.units.base_phrase import BasePhrase
from rhoknp.units.clause import Clause
from rhoknp.units.document import Document
from rhoknp.units.phrase import Phrase
from rhoknp.units.sentence import Sentence
_HIRAGANA = "ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろわをんーゎゐゑゕゖゔゝゞ"
_KATAKANA = "ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロワヲンーヮヰヱヵヶヴヽヾ"
HIRA2KATA = str.maketrans(_HIRAGANA, _KATAKANA)
[docs]
class ArgumentType(Enum):
"""項のタイプ."""
CASE_EXPLICIT = "C" #: 直接係り受けをもつ格要素(格は明示されている).
CASE_HIDDEN = "N" #: 直接係り受けをもつ格要素(格は明示されていない).
OMISSION = "O" #: 省略の指示対象.
DEMONSTRATIVE = "D" #: 指示詞の指示対象.
EXOPHORA = "E" #: 特殊(不特定:人など).
UNASSIGNED = "U" #: 格要素の割り当てなし.
[docs]
class BaseArgument(ABC):
"""項の基底クラス.
Args:
case: 述語に対する格.
arg_type: 項のタイプ.
"""
def __init__(self, case: str, arg_type: ArgumentType) -> None:
self.case: str = case #: 述語に対する格.
self.type: ArgumentType = arg_type #: 項のタイプ.
self.optional: bool = False #: 修飾的な項かどうか.
self._pas: "Pas" | None = None
@abstractmethod
def __str__(self) -> str:
raise NotImplementedError
@abstractmethod
def __repr__(self) -> str:
raise NotImplementedError
@abstractmethod
def __hash__(self) -> int:
raise NotImplementedError
@abstractmethod
def __eq__(self, other: object) -> bool:
raise NotImplementedError
@property
def pas(self) -> "Pas":
"""述語項構造."""
assert self._pas is not None
return self._pas
@pas.setter
def pas(self, pas: "Pas") -> None:
"""述語項構造."""
self._pas = pas
[docs]
def is_special(self) -> bool:
"""外界照応なら True."""
return self.type == ArgumentType.EXOPHORA
[docs]
class EndophoraArgument(BaseArgument):
"""文脈中の基本句に対応する項を表すクラス.
Args:
case: 述語に対する格.
base_phrase: 項の核となる基本句.
arg_type: 項のタイプ.
"""
def __init__(
self,
case: str,
base_phrase: "BasePhrase",
predicate: Predicate,
arg_type: ArgumentType | None = None,
) -> None:
super().__init__(case, arg_type or self._get_arg_type(predicate, base_phrase, case))
self.base_phrase = base_phrase #: 項の核となる基本句.
def __repr__(self) -> str:
return f"<{self.__module__}.{self.__class__.__name__}: {self.case!r}, {self.base_phrase.text!r}>"
def __str__(self) -> str:
return self.base_phrase.text
def __hash__(self) -> int:
return hash((self.case, self.base_phrase, self.pas.predicate if self._pas is not None else None))
def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
return False
if self._pas is not None and other._pas is not None:
if self.pas.predicate != other.pas.predicate:
return False
return self.case == other.case and self.base_phrase == other.base_phrase
@property
def document(self) -> "Document":
"""項の核となる基本句が属する文書.
Raises:
AttributeError: 解析結果にアクセスできない場合.
"""
return self.base_phrase.document
@property
def sentence(self) -> "Sentence":
"""項の核となる基本句が属する文."""
return self.base_phrase.sentence
@property
def clause(self) -> "Clause":
"""項の核となる基本句が属する節.
Raises:
AttributeError: 解析結果にアクセスできない場合.
"""
return self.base_phrase.clause
@property
def phrase(self) -> "Phrase":
"""項の核となる基本句が属する文節."""
return self.base_phrase.phrase
@staticmethod
def _get_arg_type(predicate: Predicate, arg_base_phrase: "BasePhrase", case: str) -> ArgumentType:
if predicate.base_phrase.parent_index is None:
return ArgumentType.UNASSIGNED
if arg_base_phrase in predicate.base_phrase.children:
tail_morpheme = arg_base_phrase.morphemes[-1]
if tail_morpheme.subpos == "格助詞" and tail_morpheme.text.translate(HIRA2KATA) == case:
return ArgumentType.CASE_EXPLICIT
else:
return ArgumentType.CASE_HIDDEN
elif predicate.base_phrase.parent and predicate.base_phrase.parent == arg_base_phrase:
return ArgumentType.CASE_HIDDEN
else:
return ArgumentType.OMISSION
[docs]
class ExophoraArgument(BaseArgument):
"""外界照応の照応先に対応する項を表すクラス.
Args:
case: 述語に対する格.
exophora_referent: 外界照応における照応先(不特定:人など).
eid: エンティティID.
"""
def __init__(self, case: str, exophora_referent: ExophoraReferent, eid: int) -> None:
super().__init__(case, ArgumentType.EXOPHORA)
self.exophora_referent = exophora_referent #: 外界照応における照応先.
self.eid = eid #: エンティティID.
def __repr__(self) -> str:
return (
f"{self.__class__.__name__}(case={self.case!r}, exophora_referent={self.exophora_referent!r}, "
f"eid={self.eid!r})"
)
def __str__(self) -> str:
return str(self.exophora_referent)
def __hash__(self) -> int:
return hash((self.case, self.exophora_referent, self.pas.predicate if self._pas is not None else None))
def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
return False
if self._pas is not None and other._pas is not None:
if self.pas.predicate != other.pas.predicate:
return False
return self.case == other.case and self.exophora_referent == other.exophora_referent
Argument = EndophoraArgument | ExophoraArgument