""" morfologi.py — Aturan morfologi verba bahasa Indonesia (TBBBI). ANTI-TRANSFORMER: Transformer: bentuk verba diputuskan via distribusi probabilitas atas vocab. AKSARA: bentuk verba ditentukan oleh aturan morfologi TBBBI yang eksplisit. Setiap perubahan bunyi punya alasan fonologis yang bisa dijelaskan. Cakupan: - Prefiks me- dengan alomorf (me/mem/men/meny/meng/menge) - Prefiks ber- dengan penghilangan /r/ pada root berawalan /r/ - Prefiks ter- (ketidaksengajaan/keadaan) - Prefiks di- (verba pasif) - Sufiks -kan (transitif/kausatif) dan -i (benefaktif/lokatif) - Konfiks me-...-kan, me-...-i, ber-...-kan - Reduplikasi: berjalan-jalan, makan-makan Justifikasi linguistik (Alwi et al. 1998 — TBBBI): Alomorf me- ditentukan oleh fonem awal root: /p,b,f/ → mem- (mempelajari, membeli, memfitnah) /t,d/ → men- (menari, mendapat) /c,j,z,sy/ → men- (mencari, menjual) /k,g,h/ → meng- (mengambil, menggali, menghitung) /vokal/ → meng- (mengambil, mengantar) /s/ → meny- + luluh /s/ (menyapu ← me+sapu) /l,m,n,r,w,y/ → me- (melipat, meminta, menari, merasa) """ from __future__ import annotations from typing import Dict, Optional, Set, Tuple # ── Alomorf prefiks me- berdasarkan fonem awal root ──────────────────────── # Kunci: fonem awal (string) → (prefiks, apakah fonem awal diluluhkan) _ALOMORF_ME: Dict[str, Tuple[str, bool]] = { # Luluh (fonem awal root hilang) "p": ("mem", True), # me+pelajari → mempelajari (p luluh menjadi m) "t": ("men", True), # me+tulis → menulis "k": ("meng", True), # me+kirim → mengirim "s": ("meny", True), # me+sapu → menyapu # Tidak luluh "b": ("mem", False), # me+beli → membeli "f": ("mem", False), # me+fitnah → memfitnah "d": ("men", False), # me+dapat → mendapat "c": ("men", False), # me+cari → mencari "j": ("men", False), # me+jual → menjual "z": ("men", False), # me+ziarahi → menziarahi "g": ("meng", False), # me+gambar → menggambar "h": ("meng", False), # me+hitung → menghitung "l": ("me", False), # me+lipat → melipat "m": ("me", False), # me+minta → meminta (bukan mem+minta) "n": ("me", False), # me+nyanyi → menyanyi "r": ("me", False), # me+rasa → merasa "w": ("me", False), # me+wakili → mewakili "y": ("me", False), # me+yakini → meyakini "sy": ("meny", False), # me+syukuri → mensyukuri } # Vokal awal → meng- (tidak luluh) _VOKAL = frozenset("aeiou") # Fonem awal yang TIDAK memicu peluluhan pada ber- (ber+r → be-) _ROOT_BERAWALAN_R = frozenset({"rasa", "renang", "rencana", "rusak", "rawat"}) # Sufiks SUFIKS_KAN = "kan" SUFIKS_I = "i" # Verba intransitif khas: tidak butuh sufiks VERBA_INTRANSITIF: Set[str] = { "lari", "tidur", "jalan", "datang", "pergi", "tiba", "duduk", "berdiri", "diam", "bangun", "terbang", "renang", "tangis", "senyum", "tawa", "nangis", "mati", "lahir", "hidup", } # Verba transitif yang sudah cukup dengan me-+root — tidak perlu sufiks -kan # Justifikasi: verba-verba ini sudah mengandung makna transitif inheren (TBBBI) VERBA_TRANSITIF_TANPA_KAN: Set[str] = { "ambil", "makan", "baca", "beli", "tulis", "lihat", "dengar", "tahu", "kenal", "ingat", "raih", "capai", "bawa", "angkat", "tarik", "dorong", "lempar", "pegang", "dapat", "terima", "minum", "pakai", "punya", "suka", "cinta", "benci", "rindu", "temukan", "cari", "pilih", "bayar", "jual", "pinjam", "sewa", "buat", "bangun", "hancur", "buka", "tutup", "simpan", "jaga", } # Verba yang secara inheren membutuhkan sufiks -i (benefaktif/lokatif, bukan -kan) VERBA_SUFIKS_I: Set[str] = { "ajar", "ikut", "beri", "bantu", "percaya", "sayang", "cinta", "terima", "hadapi", "tangani", "pimpin", "urus", "jaga", "rawat", "duduk", "tempat", "singgah", } def prefiks_me(root: str, luluhkan: bool = True) -> str: """ Terapkan prefiks me- ke root dengan alomorf yang tepat. Args: root: root kata (tanpa afiks) luluhkan: apakah fonem awal boleh diluluhkan (default True) Returns: bentuk verba dengan prefiks me- Contoh: prefiks_me("tulis") → "menulis" (t luluh, men+ulis) prefiks_me("beli") → "membeli" (tidak luluh) prefiks_me("ambil") → "mengambil" (vokal, meng+ambil) prefiks_me("sapu") → "menyapu" (s luluh, meny+apu) """ if not root: return root fonem_awal = root[0].lower() sisa = root[1:] # Cek digraf "sy" terlebih dulu if root.lower().startswith("sy"): return "meny" + root[2:] if fonem_awal in _VOKAL: return "meng" + root if fonem_awal not in _ALOMORF_ME: return "me" + root prefiks, bisa_luluh = _ALOMORF_ME[fonem_awal] if bisa_luluh and luluhkan: return prefiks + sisa return prefiks + root def prefiks_ber(root: str) -> str: """ Terapkan prefiks ber- ke root. Aturan: - root berawalan /r/ → be- (bukan ber-) contoh: ber+rasa → berasa (bukan berrasa) - selain itu → ber+root Contoh: prefiks_ber("lari") → "berlari" prefiks_ber("renang") → "berenang" prefiks_ber("jalan") → "berjalan" """ if not root: return root if root[0].lower() == "r": return "be" + root return "ber" + root def prefiks_ter(root: str) -> str: """ Terapkan prefiks ter- ke root (ketidaksengajaan/ketercapaian). Contoh: prefiks_ter("jatuh") → "terjatuh" prefiks_ter("buka") → "terbuka" """ return "ter" + root def prefiks_di(root: str) -> str: """ Terapkan prefiks di- ke root (verba pasif). Contoh: prefiks_di("beli") → "dibeli" prefiks_di("tulis") → "ditulis" """ return "di" + root def sufiks_kan(root: str) -> str: """Tambah sufiks -kan (transitif/kausatif).""" return root + "kan" def sufiks_i(root: str) -> str: """Tambah sufiks -i (benefaktif/lokatif/intensif).""" if root.endswith("i"): return root # hindari ganda: "duduki" tidak jadi "duduii" return root + "i" def bentuk_aktif_transitif(root: str) -> str: """ Bentuk verba aktif transitif: me-+root+-kan. Digunakan untuk aksi yang mengenai objek dan butuh komplemen. Contoh: jatuh → menjatuhkan, tulis → menuliskan, beli → membelikan Catatan: beberapa root tidak perlu -kan (jika transitif tanpa sufiks). """ me = prefiks_me(root) if root in VERBA_SUFIKS_I: return sufiks_i(me) return sufiks_kan(me) def bentuk_aktif_transitif_langsung(root: str) -> str: """ Bentuk verba aktif transitif tanpa sufiks: me-+root. Untuk verba yang sudah transitif tanpa -kan: Contoh: beli → membeli, makan → memakan, baca → membaca """ return prefiks_me(root) def bentuk_aktif_intransitif(root: str) -> str: """ Bentuk verba aktif intransitif: ber-+root atau me-+root. Pilih ber- jika root cenderung intransitif dengan ber-, pilih me- untuk yang lain. Contoh: lari → berlari (ber-) tangis → menangis (me-) """ # Verba dengan ber- lebih natural _BER_VERBA: Set[str] = { "lari", "jalan", "renang", "terbang", "bicara", "tanya", "juang", "gerak", "ubah", "kerja", "main", "latih", "ajar", "diri", "buat", "pikir", "satu", "sama", } if root in _BER_VERBA: return prefiks_ber(root) return prefiks_me(root) def bentuk_pasif(root: str) -> str: """ Bentuk verba pasif: di-+root+-kan atau di-+root. Contoh: jatuh → dijatuhkan, beli → dibeli, tulis → ditulis """ if root in VERBA_INTRANSITIF: return prefiks_di(root) if root in VERBA_SUFIKS_I: return sufiks_i(prefiks_di(root)) if root in VERBA_TRANSITIF_TANPA_KAN: return prefiks_di(root) return sufiks_kan(prefiks_di(root)) def reduplikasi(root: str) -> str: """ Reduplikasi penuh: root → root-root. Makna: iteratif/pluralitas tindakan. Contoh: jalan → jalan-jalan, makan → makan-makan """ return f"{root}-{root}" def pilih_bentuk_verba( root: str, transitif: bool = True, pasif: bool = False, sufiks: Optional[str] = None, ) -> str: """ Pilih bentuk verba yang tepat berdasarkan parameter gramatikal. Args: root: root verba dari KBBI transitif: True → butuh objek (menjatuhkan), False → tanpa objek (berlari) pasif: True → verba pasif di- (dijatuhkan) sufiks: "kan" / "i" / None — override sufiks Returns: Bentuk verba yang siap dipakai dalam kalimat. """ if pasif: return bentuk_pasif(root) if not transitif or root in VERBA_INTRANSITIF: return bentuk_aktif_intransitif(root) if sufiks == "i": return sufiks_i(prefiks_me(root)) if sufiks == "kan": return bentuk_aktif_transitif(root) # Verba yang sudah transitif tanpa -kan (inheren TBBBI) if root in VERBA_TRANSITIF_TANPA_KAN: return bentuk_aktif_transitif_langsung(root) # Heuristik: root pendek (≤4 huruf) cenderung tidak butuh -kan if len(root) <= 4: return bentuk_aktif_transitif_langsung(root) return bentuk_aktif_transitif(root)