"""
reference phonetic info from wikipedia:

# Ortography

Mirandese is written using the Latin alphabet, with a Portuguese basis for orthography due to its political situation:

| [Letters](https://en.wikipedia.org/wiki/Letter_(alphabet) "Letter (alphabet)") and [Dipgraphs](https://en.wikipedia.org/wiki/Digraph_(orthography) "Digraph (orthography)") | Names[[10]](https://en.wikipedia.org/wiki/Mirandese_language#cite_note-CDM-11) | [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet "International Phonetic Alphabet") |
| --- | --- | --- |
| Uppercase | Lowercase |
| A | a | á | /a/, /ɐ/ |
| AN | an | - | /ɐ̃(ŋ)/ |
| B | b | bé | /b/, /β/ |
| C | c | cé, qué | /k/, /s/ |
| Ç | ç | cé de cedilha | /s/, /z/ |
| D | d | dé | /d/, /ð/ |
| E | e | é | /ɛ/, /e/, /ɨ/ |
| EN | en | - | /ẽ(ŋ)//ɨ̃/ |
| F | f | fé | /f/ |
| G | g | gué | /g/, /ɣ/, /ʒ/ |
| H| h | hagá | — |
| I | i | i | /i/, /j/ |
| IN | in | - | /ĩ(ŋ)/, /ɨ̃j̃/ (Sendinese) |
| J | j | jé | /ʒ/ |
| L | l | lé | /l/, /ɫ/ |
| LH | lh | - | /ʎ/ |
| M | m | mé | /m/, /~/ |
| N | n | né | /n/, /~/, /ŋ/ |
| NH | nh | - | /ɲ/ |
| O | o | ó | /ɔ/, /o/, /u/, /ʊ/ |
| ON | on | - | /õ(ŋ)/ |
| P | p | pé | /p/ |
| Q | q | qué | /k/ |
| R | r | ré | /ɾ/, /r/ |
| RR | rr | - | /r/ |
| S | s | sé | /s̺/, /z̺/ |
| SS | s | - | /s̺/ |
| T | t | té | /t/ |
| U | u | u | /u/, /w/, /ũ/ |
| UN | un | - | /ũ(ŋ)/, /ʊ̃(ŋ)/ |
| X | x | xiç | /ʃ/ |
| Y | y | i griego | /j/ |
| Z | z | zé | /z/ |

Three variants of the Mirandese language exist: Border Mirandese (_Mirandés Raiano_), Central Mirandese (_Mirandés Central_) and Sendinese (_Sendinés_). Most speakers of Mirandese also speak Portuguese.

Despite there being a singular writing system for mirandese, there is one aspect that is written differently in different dialects. In the Sendinese dialect, many words that in other dialects are said with /ʎ/ ⟨lh⟩, are said with /l/ ⟨l⟩ (_alá_ for _alhá_ 'over there', _lado_ for _lhado_ 'side', _luç_ for _lhuç_ 'light', amongst others)


# Phonology

/s̺/ and /z̺/ indicate apico-alveolar sibilants (as in modern Catalan, northern/central peninsular Spanish and coastal northern European Portuguese), while /s̻/ and /z̻/ are dentalized laminal alveolar sibilants (as in most modern Portuguese, French and English). The unrelated Basque language also maintains a distinction between /s̺/ and /s̻/ (Basque has no voiced sibilants), which suggests that the distinction originally was an areal feature across Iberia.

Portuguese spelling still distinguishes all seven and is identical to Mirandese spelling in this respect, but in pronunciation, Portuguese has reduced them to four /s, z, ʃ, ʒ/ except in northern hinterland European Portuguese dialects, including those of the area that Mirandese is spoken. Northern/central Peninsular Spanish has also reduced them to four but in quite a different way: /tʃ, θ, s̺, x/. Western Andalusian Spanish and Latin American Spanish have further reduced them to three: /tʃ, s̻, x/.

- Retention of the initial /f/ from Latin, like nearly all dialects of Western Romance (the major maverick being Spanish, where /f/> /h/ > ∅).
- As in Leonese and Galician-Portuguese, the Latin initial consonant clusters /pl/, /kl/, /fl/ evolve into /tʃ/.
- Proto-Romance medial clusters -ly- and -cl- became medial /ʎ/.
- The cluster /-mb-/ is kept.
- Proto-Romance -mn- becomes /m/: lūm'nem > lume.
- Falling diphthongs /ei/, /ou/ preserved.
- Final -o becomes /u/.
- Voiced sibilants are still maintained.
- Retention of intervocalic /l/, /n/.
- Western Romance /ɛ/, /ɔ/ can diphthongize to /jɛ/, /wo/ (as in Italian). That happens not only before palatals, as in Aragonese, but also before nasals.
- /l/ is palatalized word-initially (as in other Astur-Leonese languages and in Catalan).

# Consonants

- the laminal dental sibilants correspond to Portuguese /s, z/. These are spelled c/ç and z. The corresponding alveolar sibilants are apical and are spelled s(s) and s. Furthermore, there is an additional palatal affricate /tʃ/ ch that is distinct from the fricative /ʃ/, spelled x. The voiced /ʒ/ is spelled j or g, as in Portuguese. Standard Portuguese has reduced all those sounds to just four fricatives: /s, z, ʃ, ʒ/.
- The "hard" or "long" R is an alveolar trill /r/, as in other varieties of Astur-Leonese and Spanish. The Portuguese uvular fricative [ʁ] is not found in Mirandese. The "soft" or "short" R is an ordinary alveolar tap [ɾ] commonly found in the Iberian Peninsula. As in other languages spoken in the region, the two contrast only in the word-internal position.
- Voiced stops /b, d, ɡ/ can be lenited as fricatives [β, ð, ɣ].

# Vowels

All oral and nasal vowel sounds and allophones are the same from Portuguese, with different allophones:

- /a/ has allophones of [ä, ɐ], /e/ with [ɛ, e, ɨ], and /o/ with [ɔ, o, u] and [ʊ]. And with the addition of nasal vowel sounds [ɨ̃] and [ɛ̃] for /ẽ/.
- Vowels /i, u/ can become glides [j, w] when preceding or following other vowels.

# Morphology

As in Portuguese, Mirandese still uses the following synthetic tenses:

. Synthetic pluperfect in -ra.
. Future subjunctive in -r(e).
. Personal infinitive in -r(e), which has the same endings as the future subjunctive but often differs as the personal infinitive always uses the infinitive stem, whereas the future subjunctive uses the past.

"""

from collections import Counter
from mwl_phonemizer.base import MirandesePhonemizer, Dialects

import json
import os.path
import re
import string


class OrthographyRulesMWL(MirandesePhonemizer):

    def __init__(self, *args, keep_optional_phones=True, keep_stress_marks=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.keep_optional_phones = keep_optional_phones
        self.keep_stress_marks = keep_stress_marks
        # Mapping to convert graphemes to phonemes
        self._vowels = "aeiouáéíóúäɐɛɨɪɔʊ"  # Extended set of vowels for context checking
        self._voiced_consonants = "bdgjlmnrvz"  # Approximated list of voiced consonants
        with open(os.path.join(os.path.dirname(__file__), "g2p.json")) as f:
            self.MWL_ALPHABET_MAP = json.load(f)

    def _is_vowel(self, char):
        """Checks if a character is a vowel."""
        return char.lower() in self._vowels

    def _is_voiced_consonant(self, char):
        """Checks if a character is a voiced consonant."""
        return char.lower() in self._voiced_consonants

    def _post_process(self, phonemized: str,
                      keep_optional_phones=True,
                      keep_stress_marks=False) -> str:
        if not self.keep_stress_marks:
            phonemized = (phonemized.
                          replace("ˈ", "").
                          replace(".", ""))
        if self.keep_optional_phones:
            # just drop parentheses
            phonemized = (phonemized.
                          replace("(", "").
                          replace(")", ""))
        else:
            # Remove optional phonemes inside parentheses
            # This regex finds any content within parentheses and replaces the whole match with an empty string
            phonemized = re.sub(r'\([^)]*\)', '', phonemized)
        return phonemized

    def phonemize_word(self, word: str):
        """
        Phonemizes a single Mirandese word based on the provided mapping and rules,
        with support for dialectal variations.

        Args:
            word (str): The word to phonemize..
        """
        word = word.lower()

        phonemes = []
        i = 0
        while i < len(word):
            matched = False

            # Try to match multi-character graphemes first (longest first)
            # This ensures 'ch' is matched before 'c', 'lh' before 'l', etc.
            # Also handles new clusters like 'pl', 'kl', 'fl', 'mn', 'ly', 'cl', 'll', 'nn'
            for length in sorted([len(g) for g in self.MWL_ALPHABET_MAP.keys()], reverse=True):
                if i + length <= len(word):
                    grapheme = word[i:i + length].lower()

                    # Handle dialectal variations for 'l' and 'lh'
                    if self.dialect == Dialects.SENDINESE:
                        if grapheme == "lh":
                            phonemes.append(self.MWL_ALPHABET_MAP["l"][0])  # 'lh' becomes [l] in Sendinese
                            i += length
                            matched = True
                            break
                        elif grapheme == "l" and i == 0:  # Initial 'l' in Sendinese remains [l]
                            phonemes.append(self.MWL_ALPHABET_MAP["l"][0])
                            i += length
                            matched = True
                            break

                    if grapheme in self.MWL_ALPHABET_MAP:
                        # Apply specific rules for graphemes based on context
                        if grapheme == "b":
                            # Rule: b = [β] between vowels and after voiced consonants
                            if (i > 0 and self._is_vowel(word[i - 1])) and \
                                    (i + 1 < len(word) and self._is_vowel(word[i + 1])):
                                phonemes.append(self.MWL_ALPHABET_MAP["b"][1])  # [β] between vowels
                            elif i > 0 and self._is_voiced_consonant(word[i - 1]):
                                phonemes.append(self.MWL_ALPHABET_MAP["b"][1])  # [β] after voiced consonants
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["b"][0])  # [b] otherwise
                        elif grapheme == "c":
                            # Rule: c = [s̻] before e or i, [k] elsewhere
                            if (i + 1 < len(word) and word[i + 1].lower() in "ei"):
                                phonemes.append(self.MWL_ALPHABET_MAP["c"][1])  # [s̻] before e or i (second element in map)
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["c"][0])  # [k] elsewhere (first element in map)
                        elif grapheme == "ç":
                            # Rule: ç = [z̻] before words starting with voiced consonants
                            # This rule is tricky without full word context (e.g., "words starting with voiced consonants")
                            # For now, a simplified interpretation: if followed by a voiced consonant within the word.
                            # A more accurate implementation would require sentence-level context.
                            if i + 1 < len(word) and self._is_voiced_consonant(word[i + 1]):
                                phonemes.append(self.MWL_ALPHABET_MAP["ç"][0])  # [z̻]
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["ç"][0])  # Default to [z̻]
                        elif grapheme == "d":
                            # Rule: d = [ð] between vowels and after r
                            if (i > 0 and self._is_vowel(word[i - 1])) and \
                                    (i + 1 < len(word) and self._is_vowel(word[i + 1])):
                                phonemes.append(self.MWL_ALPHABET_MAP["d"][1])  # [ð] between vowels
                            elif i > 0 and word[i - 1].lower() == 'r':
                                phonemes.append(self.MWL_ALPHABET_MAP["d"][1])  # [ð] after r
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["d"][0])  # [d] otherwise
                        elif grapheme == "e":
                            # Rule: e = [ɨ/ɨ̃] before stressed syllables
                            # This rule requires stress prediction, which is beyond this rule-based phonemizer.
                            # Defaulting to the first phoneme [e].
                            phonemes.append(self.MWL_ALPHABET_MAP["e"][0])
                        elif grapheme == "g":
                            # Rule: g = [ɣ] between vowels and after r. Before e and i, g = [ʒ].
                            # g = [ɡu] in certain words, such as guira, guiron and guirica. g = [gu̯] before a
                            if (i > 0 and self._is_vowel(word[i - 1])) and \
                                    (i + 1 < len(word) and self._is_vowel(word[i + 1])):
                                phonemes.append(self.MWL_ALPHABET_MAP["g"][1])  # [ɣ] between vowels
                            elif i > 0 and word[i - 1].lower() == 'r':
                                phonemes.append(self.MWL_ALPHABET_MAP["g"][1])  # [ɣ] after r
                            elif (i + 1 < len(word) and word[i + 1].lower() in "ei"):
                                phonemes.append(self.MWL_ALPHABET_MAP["g"][2])  # [ʒ] before e and i
                            # The [ɡu] and [gu̯] rules are word-specific and complex for a simple rule-based system.
                            # Defaulting to [g] for other cases.
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["g"][0])
                        elif grapheme == "gu":
                            # Rule: gu = [ɣ] between vowels and after r
                            # Simplified: checking context around 'gu'
                            if (i > 0 and self._is_vowel(word[i - 1])) and \
                                    (i + 2 < len(word) and self._is_vowel(
                                        word[i + 2])):  # Check the character *after* 'u'
                                phonemes.append(self.MWL_ALPHABET_MAP["gu"][2])  # [ɣ] between vowels (third element in map)
                            elif i > 0 and word[i - 1].lower() == 'r':
                                phonemes.append(self.MWL_ALPHABET_MAP["gu"][2])  # [ɣ] after r
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["gu"][0])  # [g] otherwise (first element in map)
                        elif grapheme == "i":
                            # Rule: i can become glide [j] when preceding or following other vowels.
                            is_glide = False
                            # Check if 'i' is followed by a vowel
                            if i + 1 < len(word) and self._is_vowel(word[i + 1]):
                                is_glide = True
                            # Check if 'i' is preceded by a vowel
                            elif i > 0 and self._is_vowel(word[i - 1]):
                                is_glide = True

                            if is_glide:
                                phonemes.append(self.MWL_ALPHABET_MAP["i"][1])  # [j]
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["i"][0])  # [i]
                        elif grapheme == "l":
                            # This rule is now handled by the dialect-specific check above for 'sendinese'
                            if self.dialect != Dialects.SENDINESE and i == 0:
                                phonemes.append(
                                    self.MWL_ALPHABET_MAP["l"][1])  # [ʎ] at the beginning of words (non-Sendinese)
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["l"][0])  # [l] elsewhere
                        elif grapheme == "lh":
                            # This rule is now handled by the dialect-specific check above for 'sendinese'
                            if self.dialect != Dialects.SENDINESE:
                                phonemes.append(self.MWL_ALPHABET_MAP["lh"][0])  # [ʎ] for 'lh' (non-Sendinese)
                            # else: handled by the 'sendinese' block above
                        elif grapheme == "m":
                            # Rule: m is silent before nasalized front vowels, e.g. amportante
                            # Default to [m]. Nasalization of preceding vowels is handled by AN, EN, IN, ON, UN.
                            phonemes.append(self.MWL_ALPHABET_MAP["m"][0])  # [m]
                        elif grapheme == "n":
                            # Rule: n = [ŋ] before k, g, q (velar consonants), otherwise [n].
                            # Nasalization of preceding vowels is handled by AN, EN, IN, ON, UN.
                            if i + 1 < len(word) and word[i + 1].lower() in "kgq":
                                phonemes.append(self.MWL_ALPHABET_MAP["n"][1])  # [ŋ]
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["n"][0])  # [n]
                        elif grapheme == "o":
                            # Rule: o = [u] when unstressed. Also, final -o becomes /u/.
                            if i == len(word) - 1:  # If 'o' is the last character in the word
                                phonemes.append(self.MWL_ALPHABET_MAP["o"][2])  # [u] (third element in map)
                            # This rule requires stress prediction, which is beyond this rule-based phonemizer.
                            # Defaulting to the first phoneme [ɔ] for non-final 'o'.
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["o"][0])
                        elif grapheme == "qu":
                            # Rule: qu = [k] before e and i, and [kṷ] before a and en
                            if (i + 2 < len(word) and word[i + 2].lower() in "ei"):
                                phonemes.append(self.MWL_ALPHABET_MAP["qu"][0])  # [k] before e and i
                            elif (i + 2 < len(word) and word[i + 2].lower() == "a") or \
                                    (i + 2 < len(word) - 1 and word[i + 2:i + 4].lower() == "en"):
                                phonemes.append(self.MWL_ALPHABET_MAP["qu"][1])  # [kṷ] before a or en
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["qu"][0])  # default to [k]
                        elif grapheme == "r":
                            # Rule: r = [rr] at the beginning of words and after n
                            # The "hard" or "long" R is an alveolar trill /r/. The "soft" or "short" R is an alveolar tap [ɾ].
                            # The map has ["ɾ", "r", "rr"]. So "r" is the trill, "ɾ" is the tap.
                            if i == 0 or (i > 0 and word[i - 1].lower() == 'n'):  # At beginning or after n
                                phonemes.append(self.MWL_ALPHABET_MAP["r"][1])  # [r] (second element in map, the trill)
                            else:
                                phonemes.append(
                                    self.MWL_ALPHABET_MAP["r"][0])  # [ɾ] elsewhere (first element in map, the tap)
                        elif grapheme == "s":
                            # Rule: s = [s̺] when in initial position and before silent consonants.
                            # Between vowels and before voiced consonants, s = [z̺]
                            if i == 0 or (i + 1 < len(word) and not self._is_vowel(
                                    word[i + 1])):  # Initial or before non-vowel (simplified 'silent consonant')
                                phonemes.append(self.MWL_ALPHABET_MAP["s"][0])  # [s̺]
                            elif (i > 0 and self._is_vowel(word[i - 1])) and \
                                    (i + 1 < len(word) and self._is_voiced_consonant(word[i + 1])):
                                phonemes.append(
                                    self.MWL_ALPHABET_MAP["s"][1])  # [z̺] between vowels and before voiced consonants
                            elif (i > 0 and self._is_vowel(word[i - 1])) and \
                                    (i + 1 < len(word) and self._is_vowel(word[i + 1])):
                                phonemes.append(self.MWL_ALPHABET_MAP["s"][1])  # [z̺] between vowels
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["s"][0])  # Default [s̺]
                        elif grapheme == "u":
                            # Rule: u can become glide [w] when preceding or following other vowels.
                            is_glide = False
                            # Check if 'u' is followed by a vowel
                            if i + 1 < len(word) and self._is_vowel(word[i + 1]):
                                is_glide = True
                            # Check if 'u' is preceded by a vowel
                            elif i > 0 and self._is_vowel(word[i - 1]):
                                is_glide = True

                            if is_glide:
                                phonemes.append(self.MWL_ALPHABET_MAP["u"][1])  # [w]
                            else:
                                phonemes.append(self.MWL_ALPHABET_MAP["u"][0])  # [u]
                        # For v and w, the map has multiple options, but Wikipedia implies primarily for loanwords.
                        # Sticking to the first phoneme in the map as default for simplicity.
                        elif grapheme == "v":
                            phonemes.append(self.MWL_ALPHABET_MAP["v"][0])
                        elif grapheme == "w":
                            phonemes.append(self.MWL_ALPHABET_MAP["w"][0])
                        # --- cluster rules ---
                        elif grapheme in ["pl", "kl", "fl", "mn", "ly", "cl", "ll", "nn"]:
                            phonemes.append(self.MWL_ALPHABET_MAP[grapheme][0])
                        else:
                            # For other graphemes, take the first phoneme in the list as default
                            phonemes.append(self.MWL_ALPHABET_MAP[grapheme][0])

                        i += length
                        matched = True
                        break  # Break from the inner loop (grapheme lengths) once a match is found

            # If no multi-character grapheme matched, try single character
            if not matched:
                if word[i].lower() in self.MWL_ALPHABET_MAP:
                    phonemes.append(self.MWL_ALPHABET_MAP[word[i].lower()][0])
                elif word[i] in string.punctuation + string.whitespace:
                    phonemes.append(word[i])  # Keep punctuation as is
                else:
                    phonemes.append(word[i])  # Fallback for any unmapped character
                i += 1
        phonemized = "".join(phonemes)
        return self._post_process(phonemized)

    def phonemize_sentence(self,  text: str):
        text = text.replace("-", " ")
        words = re.findall(r"\b\w+\b|[\W_]+", text)  # Split by words and keep punctuation/spaces
        phonemized_parts = []
        for word_or_punc in words:
            if word_or_punc.isalpha():
                phonemized_parts.append(
                    self.phonemize_word(word_or_punc))
            else:
                phonemized_parts.append(word_or_punc)  # Keep punctuation and spaces as is
        return "".join(phonemized_parts)

    # -------------------------
    # Phonemizer interface
    # -------------------------
    def phonemize(self, word: str, lookup_word: bool = True) -> str:
        """Phonemize a single Mirandese word via espeak + correction rules."""
        if lookup_word and word.lower() in GOLD:
            return self.GOLD[word.lower()]
        return self.phonemize_word(word)


if __name__ == "__main__":

    pho = OrthographyRulesMWL()

    stats = pho.evaluate_on_gold(limit=None, detailed=False, show_changes=False)

    # --- Compute PER (Phoneme Error Rate) ---  # TODO - move this to evaluate_on_gold
    total_ref_len_stress = sum(len(v) for v in pho.GOLD.values())
    total_ref_len_no_stress = sum(len(pho.strip_stress(v)) for v in pho.GOLD.values())

    per = stats['avg_edit_distance'] * stats['counts'] / total_ref_len_stress

    per_no_stress = stats['avg_edit_distance_no_stress'] * stats['counts'] / total_ref_len_no_stress

    # --- Print Summary Metrics ---
    print("\n" + "=" * 50)
    print("      Mirandese Phonemizer Rule Evaluation")
    print("=" * 50)
    print(f"Total Words Evaluated: {stats['counts']}\n")

    print("## Phoneme Error Rate (PER, Full IPA Match, includes stress)")
    print(f"PER:    {per:.2%}")

    print("\n## Phoneme Error Rate (PER, Stress-Agnostic)")
    print(f"PER:    {per_no_stress:.2%}")

    # --- Print only 'wrong' words (ED > 0) ---
    print("\n--- Incorrectly Phonemized Words (Full IPA Match ED > 0) ---")
    wrong_words = stats.get("details", [])

    if wrong_words:
        print(f"Total Incorrect: {len(wrong_words)} words\n")

        # Print a header for the detailed list
        print(f"{'Word':<20} | {'Gold':<15} | {'Phonemized':<15} | {'ED After':<8}")
        print("-" * 75)

        # Print the detailed list
        for d in wrong_words:
            print(
                f"{d['word']:<20} | {d['gold']:<15} | {d['phonemes']:<15} | {d['ed']:<8}")
    else:
        print("All words achieved an exact match (100% Accuracy)!")

    # ==================================================
    #       Mirandese Phonemizer Orthography Rules Evaluation
    # ==================================================
    # Total Words Evaluated: 145
    #
    # ## Phoneme Error Rate (PER, Full IPA Match, includes stress)
    # PER:    39.04%
    #
    # ## Phoneme Error Rate (PER, Stress-Agnostic)
    # PER:    31.99%
    #
    # --- Incorrectly Phonemized Words (Full IPA Match ED > 0) ---
    # Total Incorrect: 136 words
    #
    # Word                 | Gold            | Phonemized      | ED After
    # ---------------------------------------------------------------------------
    # más                  | mas̺            | mɐ̃s̺           | 2
    # alhá                 | ɐˈʎa            | aʎɐ̃            | 4
    # deimingo             | dejˈmĩgʊ        | dejmĩŋgu        | 3
    # abandono             | abɐ̃ˈdonu       | abɐ̃dõŋu        | 3
    # adbertido            | ɐdbɨɾˈtidu      | adβeɾtiðu       | 5
    # adulto               | ɐˈdultu         | aðultu          | 3
    # afamado              | ɐfɐˈmadu        | afɐ̃ŋaðu        | 4
    # afeito               | ɐˈfejtʊ         | afejtu          | 3
    # afelhado             | ɐfɨˈʎadu        | afɨʎaðu         | 3
    # alternatibo          | altɨɾnɐˈtibu    | alteɾnatiβu     | 4
    # amarielho            | ɐmɐˈɾjɛʎu       | ɐ̃ŋaɾjeʎu       | 4
    # ambesible            | ɐ̃bɨˈs̺iblɨ     | ɐ̃ŋβɨz̺iblɨ     | 4
    # amouchado            | amowˈtʃaðu      | ɐ̃ŋowtʃaðu      | 4
    # amportante           | ɐ̃puɾˈtɐ̃tɨ     | ɐ̃ŋpɔɾtɐ̃ŋte    | 5
    # ampossible           | ɐ̃puˈsiblɨ      | ɐ̃ŋpɔs̺iblɨ     | 4
    # ampressionante       | ɐ̃pɾɨsjuˈnɐ̃tɨ  | ɐ̃ŋpɾes̺jõŋɐ̃ŋte | 8
    # anchir               | ɐ̃ˈtʃiɾ         | ɐ̃ŋtʃiɾ         | 1
    # antender             | ɐ̃tɨ̃ˈdeɾ       | ɐ̃ŋtẽŋdeɾ       | 4
    # arena                | ɐˈɾenɐ          | aɾẽŋa           | 5
    # açpuis               | ɐsˈpujs̺        | ɐspujs̺         | 1
    # berde                | ˈveɾdɨ          | beɾðe           | 4
    # besible              | bɨˈz̺iblɨ       | bɨz̺iblɨ        | 1
    # bexanar              | bɨʃɐˈnaɾ        | beʃɐ̃ŋaɾ        | 3
    # bibal                | biˈβaɫ          | biβal           | 2
    # bielho               | bjɛʎu           | bjeʎu           | 1
    # biolento             | bjuˈlẽtu        | bjɔlẽŋtu        | 3
    # biúba                | biˈuβɐ          | bjuβa           | 3
    # brabo                | bɾabu           | bɾaβu           | 1
    # burmeilho            | buɾˈmɐjʎu       | buɾmejʎu        | 2
    # cabresto             | kɐˈbɾeʃtu       | kabɾeʃtu        | 2
    # canhona              | kɐˈɲonɐ         | kɐ̃ŋõŋa         | 5
    # cheno                | ˈtʃenu          | tʃenu           | 1
    # chober               | tʃuˈβeɾ         | tʃuβeɾ          | 1
    # ciguonha             | s̻iˈɣwoɲɐ       | s̻iɣwoɲa        | 2
    # dafeito              | ðɐˈfejtʊ        | dafejtu         | 4
    # defrente             | dɨˈfɾẽtɨ        | defɾẽŋte        | 4
    # defícel              | dɨˈfisɛl        | defis̻el        | 4
    # drento               | ˈdɾẽtu          | dɾẽŋtu          | 2
    # eigual               | ɐjˈɡwal         | ejɡwal          | 2
    # era                  | ˈɛɾɐ            | eɾa             | 3
    # eras                 | ˈɛɾɐs̺          | eɾas̺           | 3
    # feliç                | fɨˈlis̻         | fɨlis̻          | 1
    # fierro               | ˈfjɛru          | fjɛru           | 1
    # francesa             | fɾɐ̃ˈsɛzɐ       | fɾɐ̃ŋs̻ez̺a     | 5
    # francesas            | fɾɐ̃ˈsɛzɐs̺     | fɾɐ̃ŋs̻ezɐs̺    | 3
    # franceses            | fɾɐ̃ˈsɛzɨs̺     | fɾɐ̃ŋs̻ezɨs̺    | 3
    # francés              | fɾɐ̃ˈsɛs̺       | fɾɐ̃ŋsɛs        | 2
    # fumos                | ˈfumus̺         | fumus̺          | 1
    # fuogo                | fwoɣʊ           | fwoɣu           | 1
    # fuonte               | ˈfwõtɨ          | fwonte          | 4
    # fuorte               | ˈfwɔɾtɨ         | fwɔɾte          | 2
    # fuortemente          | fwɔɾtɨˈmẽtɨ     | fwɔɾtemẽte      | 3
    # fuorça               | ˈfwɔɾs̻ɐ        | fwɔɾz̻a         | 3
    # fuste                | ˈfus̺tɨ         | fus̺te          | 2
    # fácele               | ˈfasɨlɨ         | fɐ̃s̻ele        | 6
    # guapo                | ˈɡwapu          | ɡwapu           | 1
    # haber                | ɐˈβeɾ           | aβeɾ            | 2
    # houmano              | owˈmɐnu         | owmɐ̃ŋu         | 3
    # l                    | l̩              | ʎ               | 2
    # lhabrar              | ʎɐˈbɾaɾi        | ʎabɾaɾ          | 3
    # lhimpo               | ˈʎĩpʊ           | ʎimpu           | 4
    # lhobo                | ˈʎobʊ           | ʎɔβu            | 4
    # lhuç                 | ˈʎus̻           | ʎuz̻            | 2
    # lhéngua              | ˈʎɛ̃ɡwɐ         | ʎɛŋɡwa          | 3
    # luç                  | ˈʎus̻           | ʎuz̻            | 2
    # macado               | mɐˈkadu         | makaðu          | 3
    # maias                | ˈmajɐs̺         | majas̺          | 2
    # mirandés             | miɾɐ̃ˈdes̺      | miɾɐ̃ŋdɛs̺      | 2
    # molineiro            | mʊliˈnei̯rʊ     | mɔlĩŋejɾu       | 8
    # molino               | muˈlinu         | mɔlĩŋu          | 4
    # muola                | ˈmu̯olɐ         | mwola           | 4
    # ne l                 | nɨl             | ne ʎ            | 3
    # neçairo              | nɨˈsajɾu        | nez̻ajɾu        | 3
    # nuobo                | ˈnwoβʊ          | nwoβu           | 2
    # nó                   | ˈnɔ             | nɔ              | 1
    # onte                 | ˈõtɨ            | õŋte            | 3
    # oucidental           | ows̻idẽˈtal     | ows̻iðẽŋtal     | 2
    # oufecialmente        | owfɨˌsjalˈmẽtɨ  | owfɨs̻jalmẽte   | 4
    # ourdenhar            | ou̯ɾdɨˈɲaɾ      | owɾðẽŋaɾ        | 6
    # oureginal            | owɾɨʒiˈnal      | owɾeɣĩŋal       | 5
    # ourganizaçon         | ou̯rɡɐnizɐˈsõ   | owɾɣɐ̃ŋizɐsõŋ   | 8
    # ouropeu              | owɾuˈpew        | owɾɔpew         | 2
    # ourriêta             | ˈowrjetɐ        | owrjeta         | 2
    # paxarina             | pɐʃɐˈɾinɐ       | paʃaɾĩŋa        | 6
    # pequeinho            | pɨˈkɐiɲu        | pekɨĩŋu         | 5
    # piranha              | piˈraɲɐ         | piɾɐ̃ŋa         | 5
    # puis                 | ˈpujs̺          | pujs̺           | 1
    # pul                  | ˈpul            | pul             | 1
    # puorta               | ˈpwoɾtɐ         | pwoɾta          | 2
    # purmeiro             | puɾˈmɐjɾu       | puɾmejɾu        | 2
    # quaije               | ˈkwajʒɨ         | kwajʒe          | 2
    # quando               | ˈkwɐ̃du         | kwɐ̃du          | 1
    # quelobrinas          | kɨluˈbrinas̺    | kɨlɔbɾĩŋas̺     | 5
    # quemun               | kɨˈmun          | kɨmũŋ           | 3
    # rabielho             | rɐˈβjeʎu        | raβjeʎu         | 2
    # rico                 | ˈriku           | riku            | 1
    # salir                | s̺ɐˈliɾ         | s̺aliɾ          | 2
    # screbir              | s̺krɨˈβiɾ       | s̺kɾeβiɾ        | 3
    # segar                | s̺ɨˈɣaɾ         | s̺eɣaɾ          | 2
    # sendo                | ˈsẽdu           | s̺ẽŋdu          | 3
    # ser                  | ˈseɾ            | s̺eɾ            | 2
    # sida                 | ˈsidɐ           | s̺iða           | 4
    # sidas                | ˈsidɐs̺         | s̺iðas̺         | 4
    # sido                 | ˈsidu           | s̺iðu           | 3
    # sidos                | ˈsidus̺         | s̺iðɔs̺         | 4
    # simple               | ˈs̺ĩplɨ         | s̺imple         | 4
    # sobrino              | s̺uˈbɾinu       | s̺ɔbɾĩŋu        | 4
    # sodes                | ˈsodɨs̺         | s̺ɔðes̺         | 5
    # somos                | ˈsomus̺         | s̺ɔmus̺         | 3
    # son                  | ˈsõ             | s̺õŋ            | 3
    # sou                  | ˈsow            | s̺ow            | 2
    # spanha               | ˈs̺pɐɲɐ         | s̺pɐ̃ŋa         | 4
    # squierdo             | ˈs̺kjeɾdu       | s̺kjeɾðu        | 2
    # sós                  | ˈs̺ɔs̺          | s̺ɔs̺           | 1
    # talbeç               | talˈbes         | talbes          | 1
    # tamien               | tɐˈmjẽ          | tɐ̃ŋjẽŋ         | 3
    # tascar               | tɐs̺ˈkaɾ        | tas̺kaɾ         | 2
    # tener                | tɨˈneɾ          | tẽŋeɾ           | 3
    # trasdonte            | ˈtɾɐz̺dõtɨ      | tɾas̺dõŋte      | 5
    # trasdontonte         | ˈtɾɐz̺dõtõtɨ    | tɾas̺dõŋtõŋte   | 6
    # ye                   | ˈje             | je              | 1
    # yê                   | ˈje             | jê              | 2
    # zastre               | ˈzas̺tɾɨ        | zas̺tɾɨ         | 1
    # zeigual              | zɐjˈɡwal        | zɐjɡwal         | 1
    # zenhar               | zɨˈɲaɾ          | zẽŋaɾ           | 3
    # áfrica               | ˈafɾikɐ         | ɐ̃fɾika         | 3
    # çcansar              | skɐ̃ˈs̺aɾ       | skɐ̃ŋs̺aɾ       | 1
    # çcrebir              | skɾɨˈβiɾ        | skɾeβiɾ         | 2
    # çcriçon              | skɾiˈsõ         | skɾisõ          | 1
    # çtinto               | ˈstĩtu          | z̻tĩŋtu         | 3
    # érades               | ˈɛɾɐdɨs̺        | ɛɾaðes̺         | 4
    # éramos               | ˈɛɾɐmus̺        | ɛɾɐ̃ŋɔs̺        | 4
    # éran                 | ˈɛɾɐn           | ɛɾɐ̃ŋ           | 3
    # ũ                    | ˈũ              | ũ               | 1
    # ũa                   | ˈũŋɐ            | ũŋɐ             | 1
    # ua                   | ˈũŋɐ            | wa              | 4