pub use super::consonant::*;
use super::{
stream::ParseError,
traits::{FromToken, IntoToken},
};
use crate::category::{HFormDegree, HFormSequence, VowelFormDegree, VowelFormSequence};
use std::{
error::Error,
fmt,
ops::{Deref, DerefMut},
str::FromStr,
};
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct OwnedConsonantForm(pub String);
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct VowelForm {
pub has_glottal_stop: bool,
pub sequence: VowelFormSequence,
pub degree: VowelFormDegree,
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ÜA;
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Schwa;
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct HForm {
pub sequence: HFormSequence,
pub degree: HFormDegree,
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hh;
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hr;
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum WYForm {
W,
Y,
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[non_exhaustive] pub struct NumeralForm {
pub integer_part: u64,
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct GlottalStop;
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Token {
C(OwnedConsonantForm),
V(VowelForm),
H(HForm),
N(NumeralForm),
ÜA,
Schwa,
GlottalStop,
}
impl Token {
pub fn is_valid_word_initial(&self) -> bool {
match self {
Self::C(cs) => cs.is_valid_word_initial(),
Self::N(NumeralForm { integer_part }) => *integer_part < 16,
_ => true,
}
}
pub fn is_valid_word_final(&self) -> bool {
match self {
Self::C(cs) => cs.is_valid_word_final(),
Self::N(NumeralForm { integer_part }) => *integer_part < 16,
Self::H(_) => false,
_ => true,
}
}
}
impl IntoToken for Token {
fn into_token(self) -> Token {
self
}
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ParseVowelFormError;
impl fmt::Display for ParseVowelFormError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid vowel form")
}
}
impl Error for ParseVowelFormError {}
impl VowelForm {
pub fn merge_vcvk_glottal_stop(&mut self, has_glottal_stop: bool) -> Result<(), ParseError> {
if has_glottal_stop {
if self.has_glottal_stop {
Err(ParseError::DoublyGlottalizedFormative)
} else {
self.has_glottal_stop = true;
Ok(())
}
} else {
Ok(())
}
}
pub fn as_str_after(&self, string_before: &str, is_word_final: bool) -> &'static str {
let data = if string_before.ends_with("w") {
if self.has_glottal_stop {
if is_word_final {
vowel_sequence::AFTER_W_WORD_FINAL_GLOTTAL_STOP
} else {
vowel_sequence::AFTER_W_GLOTTAL_STOP
}
} else {
vowel_sequence::AFTER_W
}
} else if string_before.ends_with("y") {
if self.has_glottal_stop {
if is_word_final {
vowel_sequence::AFTER_Y_WORD_FINAL_GLOTTAL_STOP
} else {
vowel_sequence::AFTER_Y_GLOTTAL_STOP
}
} else {
vowel_sequence::AFTER_Y
}
} else {
if self.has_glottal_stop {
if is_word_final {
vowel_sequence::STANDARD_WORD_FINAL_GLOTTAL_STOP
} else {
vowel_sequence::STANDARD_GLOTTAL_STOP
}
} else {
vowel_sequence::STANDARD
}
};
data[self.sequence as usize][self.degree as usize]
}
}
mod vowel_sequence {
pub const STANDARD: [[&str; 10]; 4] = [
["ae", "a", "ä", "e", "i", "ëi", "ö", "o", "ü", "u"],
["ea", "ai", "au", "ei", "eu", "ëu", "ou", "oi", "iu", "ui"],
["üo", "ia", "ie", "io", "iö", "eë", "uö", "uo", "ue", "ua"],
["üö", "ao", "aö", "eo", "ëo", "oë", "öe", "oe", "öa", "oa"],
];
pub const AFTER_W: [[&str; 10]; 4] = [
["ae", "a", "ä", "e", "i", "ëi", "ö", "o", "ü", "u"],
["ea", "ai", "au", "ei", "eu", "ëu", "ou", "oi", "iu", "ui"],
["üo", "ia", "ie", "io", "iö", "eë", "öë", "öä", "ië", "iä"],
["üö", "ao", "aö", "eo", "ëo", "oë", "öe", "oe", "öa", "oa"],
];
pub const AFTER_Y: [[&str; 10]; 4] = [
["ae", "a", "ä", "e", "i", "ëi", "ö", "o", "ü", "u"],
["ea", "ai", "au", "ei", "eu", "ëu", "ou", "oi", "iu", "ui"],
["üo", "uä", "uë", "üä", "üë", "eë", "uö", "uo", "ue", "ua"],
["üö", "ao", "aö", "eo", "ëo", "oë", "öe", "oe", "öa", "oa"],
];
pub const STANDARD_GLOTTAL_STOP: [[&str; 10]; 4] = [
["a'e", "a'", "ä'", "e'", "i'", "ëi'", "ö'", "o'", "ü'", "u'"],
[
"e'a", "ai'", "au'", "ei'", "eu'", "ëu'", "ou'", "oi'", "iu'", "ui'",
],
[
"ü'o", "i'a", "i'e", "i'o", "i'ö", "e'ë", "u'ö", "u'o", "u'e", "u'a",
],
[
"ü'ö", "a'o", "a'ö", "e'o", "ë'o", "o'ë", "ö'e", "o'e", "ö'a", "o'a",
],
];
pub const AFTER_W_GLOTTAL_STOP: [[&str; 10]; 4] = [
["a'e", "a'", "ä'", "e'", "i'", "ëi'", "ö'", "o'", "ü'", "u'"],
[
"e'a", "ai'", "au'", "ei'", "eu'", "ëu'", "ou'", "oi'", "iu'", "ui'",
],
[
"ü'o", "i'a", "i'e", "i'o", "i'ö", "e'ë", "ö'ë", "ö'ä", "i'ë", "i'ä",
],
[
"ü'ö", "a'o", "a'ö", "e'o", "ë'o", "o'ë", "ö'e", "o'e", "ö'a", "o'a",
],
];
pub const AFTER_Y_GLOTTAL_STOP: [[&str; 10]; 4] = [
["a'e", "a'", "ä'", "e'", "i'", "ëi'", "ö'", "o'", "ü'", "u'"],
[
"e'a", "ai'", "au'", "ei'", "eu'", "ëu'", "ou'", "oi'", "iu'", "ui'",
],
[
"ü'o", "u'ä", "u'ë", "ü'ä", "ü'ë", "e'ë", "u'ö", "u'o", "u'e", "u'a",
],
[
"ü'ö", "a'o", "a'ö", "e'o", "ë'o", "o'ë", "ö'e", "o'e", "ö'a", "o'a",
],
];
pub const STANDARD_WORD_FINAL_GLOTTAL_STOP: [[&str; 10]; 4] = [
[
"a'e", "a'a", "ä'ä", "e'e", "i'i", "ë'i", "ö'ö", "o'o", "ü'ü", "u'u",
],
[
"e'a", "a'i", "a'u", "e'i", "e'u", "ë'u", "o'u", "o'i", "i'u", "u'i",
],
[
"ü'o", "i'a", "i'e", "i'o", "i'ö", "e'ë", "u'ö", "u'o", "u'e", "u'a",
],
[
"ü'ö", "a'o", "a'ö", "e'o", "ë'o", "o'ë", "ö'e", "o'e", "ö'a", "o'a",
],
];
pub const AFTER_W_WORD_FINAL_GLOTTAL_STOP: [[&str; 10]; 4] = [
[
"a'e", "a'a", "ä'ä", "e'e", "i'i", "ë'i", "ö'ö", "o'o", "ü'ü", "u'u",
],
[
"e'a", "a'i", "a'u", "e'i", "e'u", "ë'u", "o'u", "o'i", "i'u", "u'i",
],
[
"ü'o", "i'a", "i'e", "i'o", "i'ö", "e'ë", "ö'ë", "ö'ä", "i'ë", "i'ä",
],
[
"ü'ö", "a'o", "a'ö", "e'o", "ë'o", "o'ë", "ö'e", "o'e", "ö'a", "o'a",
],
];
pub const AFTER_Y_WORD_FINAL_GLOTTAL_STOP: [[&str; 10]; 4] = [
[
"a'e", "a'a", "ä'ä", "e'e", "i'i", "ë'i", "ö'ö", "o'o", "ü'ü", "u'u",
],
[
"e'a", "a'i", "a'u", "e'i", "e'u", "ë'u", "o'u", "o'i", "i'u", "u'i",
],
[
"ü'o", "u'ä", "u'ë", "ü'ä", "ü'ë", "e'ë", "u'ö", "u'o", "u'e", "u'a",
],
[
"ü'ö", "a'o", "a'ö", "e'o", "ë'o", "o'ë", "ö'e", "o'e", "ö'a", "o'a",
],
];
}
impl FromStr for VowelForm {
type Err = ParseVowelFormError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let has_glottal_stop = s.contains('\'');
let (sequence, degree) = match &s.replace('\'', "")[..] {
"ae" => (VowelFormSequence::S1, VowelFormDegree::D0),
"a" => (VowelFormSequence::S1, VowelFormDegree::D1),
"ä" => (VowelFormSequence::S1, VowelFormDegree::D2),
"e" => (VowelFormSequence::S1, VowelFormDegree::D3),
"i" => (VowelFormSequence::S1, VowelFormDegree::D4),
"ëi" => (VowelFormSequence::S1, VowelFormDegree::D5),
"ö" => (VowelFormSequence::S1, VowelFormDegree::D6),
"o" => (VowelFormSequence::S1, VowelFormDegree::D7),
"ü" => (VowelFormSequence::S1, VowelFormDegree::D8),
"u" => (VowelFormSequence::S1, VowelFormDegree::D9),
"aa" => (VowelFormSequence::S1, VowelFormDegree::D1),
"ää" => (VowelFormSequence::S1, VowelFormDegree::D2),
"ee" => (VowelFormSequence::S1, VowelFormDegree::D3),
"ii" => (VowelFormSequence::S1, VowelFormDegree::D4),
"öö" => (VowelFormSequence::S1, VowelFormDegree::D6),
"oo" => (VowelFormSequence::S1, VowelFormDegree::D7),
"üü" => (VowelFormSequence::S1, VowelFormDegree::D8),
"uu" => (VowelFormSequence::S1, VowelFormDegree::D9),
"ea" => (VowelFormSequence::S2, VowelFormDegree::D0),
"ai" => (VowelFormSequence::S2, VowelFormDegree::D1),
"au" => (VowelFormSequence::S2, VowelFormDegree::D2),
"ei" => (VowelFormSequence::S2, VowelFormDegree::D3),
"eu" => (VowelFormSequence::S2, VowelFormDegree::D4),
"ëu" => (VowelFormSequence::S2, VowelFormDegree::D5),
"ou" => (VowelFormSequence::S2, VowelFormDegree::D6),
"oi" => (VowelFormSequence::S2, VowelFormDegree::D7),
"iu" => (VowelFormSequence::S2, VowelFormDegree::D8),
"ui" => (VowelFormSequence::S2, VowelFormDegree::D9),
"üo" => (VowelFormSequence::S3, VowelFormDegree::D0),
"ia" => (VowelFormSequence::S3, VowelFormDegree::D1),
"uä" => (VowelFormSequence::S3, VowelFormDegree::D1),
"ie" => (VowelFormSequence::S3, VowelFormDegree::D2),
"uë" => (VowelFormSequence::S3, VowelFormDegree::D2),
"io" => (VowelFormSequence::S3, VowelFormDegree::D3),
"üä" => (VowelFormSequence::S3, VowelFormDegree::D3),
"iö" => (VowelFormSequence::S3, VowelFormDegree::D4),
"üë" => (VowelFormSequence::S3, VowelFormDegree::D4),
"eë" => (VowelFormSequence::S3, VowelFormDegree::D5),
"uö" => (VowelFormSequence::S3, VowelFormDegree::D6),
"öë" => (VowelFormSequence::S3, VowelFormDegree::D6),
"uo" => (VowelFormSequence::S3, VowelFormDegree::D7),
"öä" => (VowelFormSequence::S3, VowelFormDegree::D7),
"ue" => (VowelFormSequence::S3, VowelFormDegree::D8),
"ië" => (VowelFormSequence::S3, VowelFormDegree::D8),
"ua" => (VowelFormSequence::S3, VowelFormDegree::D9),
"iä" => (VowelFormSequence::S3, VowelFormDegree::D9),
"üö" => (VowelFormSequence::S4, VowelFormDegree::D0),
"ao" => (VowelFormSequence::S4, VowelFormDegree::D1),
"aö" => (VowelFormSequence::S4, VowelFormDegree::D2),
"eo" => (VowelFormSequence::S4, VowelFormDegree::D3),
"eö" => (VowelFormSequence::S4, VowelFormDegree::D4),
"oë" => (VowelFormSequence::S4, VowelFormDegree::D5),
"öe" => (VowelFormSequence::S4, VowelFormDegree::D6),
"oe" => (VowelFormSequence::S4, VowelFormDegree::D7),
"öa" => (VowelFormSequence::S4, VowelFormDegree::D8),
"oa" => (VowelFormSequence::S4, VowelFormDegree::D9),
value => {
eprintln!("{value:?}");
return Err(ParseVowelFormError);
}
};
Ok(Self {
has_glottal_stop,
sequence,
degree,
})
}
}
impl FromToken for VowelForm {
fn from_token(token: &Token) -> Option<Self> {
match token {
Token::V(vx) => Some(*vx),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ParseHFormError;
impl fmt::Display for ParseHFormError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid h-form")
}
}
impl Error for ParseHFormError {}
impl FromStr for HForm {
type Err = ParseHFormError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (sequence, degree) = match s {
"h" => (HFormSequence::S0, HFormDegree::D1),
"hl" => (HFormSequence::S0, HFormDegree::D2),
"hr" => (HFormSequence::S0, HFormDegree::D3),
"hm" => (HFormSequence::S0, HFormDegree::D4),
"hn" => (HFormSequence::S0, HFormDegree::D5),
"hň" => (HFormSequence::S0, HFormDegree::D6),
"w" => (HFormSequence::SW, HFormDegree::D1),
"hw" => (HFormSequence::SW, HFormDegree::D2),
"hrw" => (HFormSequence::SW, HFormDegree::D3),
"hmw" => (HFormSequence::SW, HFormDegree::D4),
"hnw" => (HFormSequence::SW, HFormDegree::D5),
"hňw" => (HFormSequence::SW, HFormDegree::D6),
"y" => (HFormSequence::SY, HFormDegree::D1),
_ => return Err(ParseHFormError),
};
Ok(Self { sequence, degree })
}
}
impl Deref for OwnedConsonantForm {
type Target = ConsonantForm;
fn deref(&self) -> &Self::Target {
ConsonantForm::new(&self.0)
}
}
impl DerefMut for OwnedConsonantForm {
fn deref_mut(&mut self) -> &mut Self::Target {
(&mut self.0[..]).into()
}
}
impl<T: Into<String>> From<T> for OwnedConsonantForm {
fn from(value: T) -> Self {
OwnedConsonantForm(value.into())
}
}
impl HForm {
pub const H: Self = Self {
sequence: HFormSequence::S0,
degree: HFormDegree::D1,
};
pub const HL: Self = Self {
sequence: HFormSequence::S0,
degree: HFormDegree::D2,
};
pub const HR: Self = Self {
sequence: HFormSequence::S0,
degree: HFormDegree::D3,
};
pub const HM: Self = Self {
sequence: HFormSequence::S0,
degree: HFormDegree::D4,
};
pub const HN: Self = Self {
sequence: HFormSequence::S0,
degree: HFormDegree::D5,
};
pub const HŇ: Self = Self {
sequence: HFormSequence::S0,
degree: HFormDegree::D6,
};
pub const W: Self = Self {
sequence: HFormSequence::SW,
degree: HFormDegree::D1,
};
pub const HW: Self = Self {
sequence: HFormSequence::SW,
degree: HFormDegree::D2,
};
pub const HRW: Self = Self {
sequence: HFormSequence::SW,
degree: HFormDegree::D3,
};
pub const HMW: Self = Self {
sequence: HFormSequence::SW,
degree: HFormDegree::D4,
};
pub const HNW: Self = Self {
sequence: HFormSequence::SW,
degree: HFormDegree::D5,
};
pub const HŇW: Self = Self {
sequence: HFormSequence::SW,
degree: HFormDegree::D6,
};
pub const Y: Self = Self {
sequence: HFormSequence::SY,
degree: HFormDegree::D1,
};
pub const HW_ALT: Self = Self {
sequence: HFormSequence::SY,
degree: HFormDegree::D2,
};
pub const HRW_ALT: Self = Self {
sequence: HFormSequence::SY,
degree: HFormDegree::D3,
};
pub const HMW_ALT: Self = Self {
sequence: HFormSequence::SY,
degree: HFormDegree::D4,
};
pub const HNW_ALT: Self = Self {
sequence: HFormSequence::SY,
degree: HFormDegree::D5,
};
pub const HŇW_ALT: Self = Self {
sequence: HFormSequence::SY,
degree: HFormDegree::D6,
};
pub const fn as_str(self) -> &'static str {
match self {
HForm::H => "h",
HForm::HL => "hl",
HForm::HR => "hr",
HForm::HM => "hm",
HForm::HN => "hn",
HForm::HŇ => "hň",
HForm::W => "w",
HForm::Y => "y",
HForm::HW | HForm::HW_ALT => "hw",
HForm::HRW | HForm::HRW_ALT => "hrw",
HForm::HMW | HForm::HMW_ALT => "hmw",
HForm::HNW | HForm::HNW_ALT => "hnw",
HForm::HŇW | HForm::HŇW_ALT => "hňw",
}
}
}