1use super::{
5 flags::{FromTokenFlags, IntoTokensFlags},
6 stream::ParseError,
7 stream::TokenStream,
8 token::{
9 GlottalStop, HForm, Hh, Hr, NumeralForm, OwnedConsonantForm, Schwa, Token, VowelForm,
10 WYForm, ÜA,
11 },
12 traits::{FromToken, FromTokens, IntoToken, IntoTokens, IntoVowelForm},
13};
14use crate::{
15 affix::RegularAffix,
16 category::{
17 AffixualAdjunctScope, ArbitraryMoodOrCaseScope, Aspect, Bias, Case, CaseScope, HFormDegree,
18 HFormSequence, ModularAdjunctMode, ModularAdjunctScope, Mood, MoodOrCaseScope,
19 NonAspectualVn, RegisterType, Stress, SuppletiveAdjunctMode, Vn, VowelFormDegree,
20 VowelFormSequence,
21 },
22 prelude::TokenList,
23};
24
25impl FromToken for OwnedConsonantForm {
26 fn from_token(token: &Token) -> Option<Self> {
27 match token {
28 Token::C(value) => Some(value.clone()),
29 _ => None,
30 }
31 }
32}
33
34impl IntoToken for OwnedConsonantForm {
35 fn into_token(self) -> Token {
36 Token::C(self)
37 }
38}
39
40impl IntoVowelForm for VowelForm {
41 fn into_vowel_form(self) -> VowelForm {
42 self
43 }
44}
45
46impl FromToken for ÜA {
47 fn from_token(token: &Token) -> Option<Self> {
48 match token {
49 Token::ÜA => Some(Self),
50 _ => None,
51 }
52 }
53}
54
55impl IntoToken for ÜA {
56 fn into_token(self) -> Token {
57 Token::ÜA
58 }
59}
60
61impl FromToken for Schwa {
62 fn from_token(token: &Token) -> Option<Self> {
63 match token {
64 Token::Schwa => Some(Self),
65 _ => None,
66 }
67 }
68}
69
70impl IntoToken for Schwa {
71 fn into_token(self) -> Token {
72 Token::Schwa
73 }
74}
75
76impl FromToken for HForm {
77 fn from_token(token: &Token) -> Option<Self> {
78 match token {
79 Token::H(value) => Some(*value),
80 _ => None,
81 }
82 }
83}
84
85impl IntoToken for HForm {
86 fn into_token(self) -> Token {
87 Token::H(self)
88 }
89}
90
91impl FromToken for WYForm {
92 fn from_token(token: &Token) -> Option<Self> {
93 match token {
94 Token::H(HForm::W) => Some(WYForm::W),
95 Token::H(HForm::Y) => Some(WYForm::Y),
96 _ => None,
97 }
98 }
99}
100
101impl IntoToken for WYForm {
102 fn into_token(self) -> Token {
103 match self {
104 Self::W => Token::H(HForm::W),
105 Self::Y => Token::H(HForm::Y),
106 }
107 }
108}
109
110impl FromToken for NumeralForm {
111 fn from_token(token: &Token) -> Option<Self> {
112 match token {
113 Token::N(value) => Some(*value),
114 _ => None,
115 }
116 }
117}
118
119impl IntoToken for NumeralForm {
120 fn into_token(self) -> Token {
121 Token::N(self)
122 }
123}
124
125impl FromToken for GlottalStop {
126 fn from_token(token: &Token) -> Option<Self> {
127 match token {
128 Token::GlottalStop => Some(Self),
129 _ => None,
130 }
131 }
132}
133
134impl IntoToken for GlottalStop {
135 fn into_token(self) -> Token {
136 Token::GlottalStop
137 }
138}
139
140impl IntoToken for Hh {
141 fn into_token(self) -> Token {
142 Token::H(HForm::H)
143 }
144}
145
146impl FromTokens for Hh {
147 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
148 match stream.next_any() {
149 Some(Token::H(HForm::H)) => Ok(Self),
150 _ => Err(ParseError::ExpectedHh),
151 }
152 }
153}
154
155impl IntoToken for Hr {
156 fn into_token(self) -> Token {
157 Token::H(HForm::HR)
158 }
159}
160
161impl FromTokens for Hr {
162 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
163 match stream.next_any() {
164 Some(Token::H(HForm::HR)) => Ok(Self),
165 _ => Err(ParseError::ExpectedHr),
166 }
167 }
168}
169
170impl IntoToken for Bias {
171 fn into_token(self) -> Token {
172 Token::C(self.as_cb().into())
173 }
174}
175
176impl FromTokens for Bias {
177 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
178 match stream.next_any() {
179 Some(Token::C(value)) => match value.0.parse() {
180 Ok(value) => Ok(value),
181 Err(_) => Err(ParseError::ExpectedCb),
182 },
183 _ => Err(ParseError::ExpectedCb),
184 }
185 }
186}
187
188impl IntoToken for SuppletiveAdjunctMode {
189 fn into_token(self) -> Token {
190 Token::H(match self {
191 SuppletiveAdjunctMode::CAR => HForm::HL,
192 SuppletiveAdjunctMode::QUO => HForm::HM,
193 SuppletiveAdjunctMode::NAM => HForm::HN,
194 SuppletiveAdjunctMode::PHR => HForm::HŇ,
195 })
196 }
197}
198
199impl FromTokens for SuppletiveAdjunctMode {
200 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
201 match stream.next_any() {
202 Some(Token::H(h)) => match *h {
203 HForm::HL => Ok(SuppletiveAdjunctMode::CAR),
204 HForm::HM => Ok(SuppletiveAdjunctMode::QUO),
205 HForm::HN => Ok(SuppletiveAdjunctMode::NAM),
206 HForm::HŇ => Ok(SuppletiveAdjunctMode::PHR),
207 _ => Err(ParseError::ExpectedCp),
208 },
209
210 _ => Err(ParseError::ExpectedCp),
211 }
212 }
213}
214
215impl IntoVowelForm for Case {
216 fn into_vowel_form(self) -> VowelForm {
217 let value = self as u8;
218
219 VowelForm {
220 has_glottal_stop: value >= 36,
221 sequence: match value / 9 {
222 0 | 4 => VowelFormSequence::S1,
223 1 | 5 => VowelFormSequence::S2,
224 2 | 6 => VowelFormSequence::S3,
225 3 | 7 => VowelFormSequence::S4,
226 _ => unreachable!(),
227 },
228 degree: match value % 9 {
229 0 => VowelFormDegree::D1,
230 1 => VowelFormDegree::D2,
231 2 => VowelFormDegree::D3,
232 3 => VowelFormDegree::D4,
233 4 => VowelFormDegree::D5,
234 5 => VowelFormDegree::D6,
235 6 => VowelFormDegree::D7,
236 7 => VowelFormDegree::D8,
237 8 => VowelFormDegree::D9,
238 _ => unreachable!(),
239 },
240 }
241 }
242}
243
244impl FromTokens for Case {
245 fn parse_volatile(
246 stream: &mut TokenStream,
247 _flags: FromTokenFlags,
248 ) -> Result<Self, ParseError> {
249 match stream.next_any() {
250 Some(Token::V(vc)) => Case::from_vc(*vc),
251 _ => Err(ParseError::ExpectedVc),
252 }
253 }
254}
255
256impl IntoVowelForm for RegisterType {
257 fn into_vowel_form(self) -> VowelForm {
258 match self {
259 RegisterType::DSV => VowelForm {
260 has_glottal_stop: false,
261 sequence: VowelFormSequence::S1,
262 degree: VowelFormDegree::D1,
263 },
264 RegisterType::PNT => VowelForm {
265 has_glottal_stop: false,
266 sequence: VowelFormSequence::S1,
267 degree: VowelFormDegree::D3,
268 },
269 RegisterType::SPF => VowelForm {
270 has_glottal_stop: false,
271 sequence: VowelFormSequence::S1,
272 degree: VowelFormDegree::D4,
273 },
274 RegisterType::EXM => VowelForm {
275 has_glottal_stop: false,
276 sequence: VowelFormSequence::S1,
277 degree: VowelFormDegree::D7,
278 },
279 RegisterType::CGT => VowelForm {
280 has_glottal_stop: false,
281 sequence: VowelFormSequence::S1,
282 degree: VowelFormDegree::D9,
283 },
284 RegisterType::DSV_END => VowelForm {
285 has_glottal_stop: false,
286 sequence: VowelFormSequence::S2,
287 degree: VowelFormDegree::D1,
288 },
289 RegisterType::PNT_END => VowelForm {
290 has_glottal_stop: false,
291 sequence: VowelFormSequence::S2,
292 degree: VowelFormDegree::D3,
293 },
294 RegisterType::SPF_END => VowelForm {
295 has_glottal_stop: false,
296 sequence: VowelFormSequence::S2,
297 degree: VowelFormDegree::D8,
298 },
299 RegisterType::EXM_END => VowelForm {
300 has_glottal_stop: false,
301 sequence: VowelFormSequence::S2,
302 degree: VowelFormDegree::D7,
303 },
304 RegisterType::CGT_END => VowelForm {
305 has_glottal_stop: false,
306 sequence: VowelFormSequence::S2,
307 degree: VowelFormDegree::D9,
308 },
309 RegisterType::END => VowelForm {
310 has_glottal_stop: false,
311 sequence: VowelFormSequence::S1,
312 degree: VowelFormDegree::D8,
313 },
314 }
315 }
316}
317
318impl FromTokens for RegisterType {
319 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
320 match stream.next_any() {
321 Some(Token::V(VowelForm {
322 has_glottal_stop: false,
323 sequence,
324 degree,
325 })) => match (sequence, degree) {
326 (VowelFormSequence::S1, VowelFormDegree::D1) => Ok(RegisterType::DSV),
327 (VowelFormSequence::S1, VowelFormDegree::D3) => Ok(RegisterType::PNT),
328 (VowelFormSequence::S1, VowelFormDegree::D4) => Ok(RegisterType::SPF),
329 (VowelFormSequence::S1, VowelFormDegree::D7) => Ok(RegisterType::EXM),
330 (VowelFormSequence::S1, VowelFormDegree::D9) => Ok(RegisterType::CGT),
331 (VowelFormSequence::S2, VowelFormDegree::D1) => Ok(RegisterType::DSV_END),
332 (VowelFormSequence::S2, VowelFormDegree::D3) => Ok(RegisterType::PNT_END),
333 (VowelFormSequence::S2, VowelFormDegree::D8) => Ok(RegisterType::SPF_END),
334 (VowelFormSequence::S2, VowelFormDegree::D7) => Ok(RegisterType::EXM_END),
335 (VowelFormSequence::S2, VowelFormDegree::D9) => Ok(RegisterType::CGT_END),
336 (VowelFormSequence::S1, VowelFormDegree::D8) => Ok(RegisterType::END),
337 _ => Err(ParseError::ExpectedVm),
338 },
339 _ => Err(ParseError::ExpectedVm),
340 }
341 }
342}
343
344impl IntoVowelForm for Stress {
345 fn into_vowel_form(self) -> VowelForm {
346 VowelForm {
347 has_glottal_stop: false,
348 sequence: VowelFormSequence::S1,
349 degree: match self {
350 Stress::Monosyllabic => VowelFormDegree::D1,
351 Stress::Ultimate => VowelFormDegree::D3,
352 Stress::Penultimate => VowelFormDegree::D7,
353 Stress::Antepenultimate => VowelFormDegree::D9,
354 },
355 }
356 }
357}
358
359impl FromTokens for Stress {
360 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
361 match stream.next_any() {
362 Some(Token::V(VowelForm {
363 has_glottal_stop: false,
364 sequence: VowelFormSequence::S1,
365 degree,
366 })) => match degree {
367 VowelFormDegree::D1 => Ok(Stress::Monosyllabic),
368 VowelFormDegree::D3 => Ok(Stress::Ultimate),
369 VowelFormDegree::D7 => Ok(Stress::Penultimate),
370 VowelFormDegree::D9 => Ok(Stress::Antepenultimate),
371 _ => Err(ParseError::ExpectedVp),
372 },
373 _ => Err(ParseError::ExpectedVp),
374 }
375 }
376}
377
378impl IntoVowelForm for MoodOrCaseScope {
379 fn into_vowel_form(self) -> VowelForm {
380 match self {
381 MoodOrCaseScope::Mood(Mood::FAC) => VowelForm {
382 has_glottal_stop: false,
383 sequence: VowelFormSequence::S1,
384 degree: VowelFormDegree::D1,
385 },
386 MoodOrCaseScope::Mood(Mood::SUB) => VowelForm {
387 has_glottal_stop: false,
388 sequence: VowelFormSequence::S1,
389 degree: VowelFormDegree::D3,
390 },
391 MoodOrCaseScope::Mood(Mood::ASM) => VowelForm {
392 has_glottal_stop: false,
393 sequence: VowelFormSequence::S1,
394 degree: VowelFormDegree::D4,
395 },
396 MoodOrCaseScope::Mood(Mood::SPC) => VowelForm {
397 has_glottal_stop: false,
398 sequence: VowelFormSequence::S1,
399 degree: VowelFormDegree::D7,
400 },
401 MoodOrCaseScope::Mood(Mood::COU) => VowelForm {
402 has_glottal_stop: false,
403 sequence: VowelFormSequence::S1,
404 degree: VowelFormDegree::D6,
405 },
406 MoodOrCaseScope::Mood(Mood::HYP) => VowelForm {
407 has_glottal_stop: false,
408 sequence: VowelFormSequence::S1,
409 degree: VowelFormDegree::D9,
410 },
411 MoodOrCaseScope::CaseScope(CaseScope::CCN) => VowelForm {
412 has_glottal_stop: false,
413 sequence: VowelFormSequence::S2,
414 degree: VowelFormDegree::D1,
415 },
416 MoodOrCaseScope::CaseScope(CaseScope::CCA) => VowelForm {
417 has_glottal_stop: false,
418 sequence: VowelFormSequence::S2,
419 degree: VowelFormDegree::D3,
420 },
421 MoodOrCaseScope::CaseScope(CaseScope::CCS) => VowelForm {
422 has_glottal_stop: false,
423 sequence: VowelFormSequence::S2,
424 degree: VowelFormDegree::D8,
425 },
426 MoodOrCaseScope::CaseScope(CaseScope::CCQ) => VowelForm {
427 has_glottal_stop: false,
428 sequence: VowelFormSequence::S2,
429 degree: VowelFormDegree::D7,
430 },
431 MoodOrCaseScope::CaseScope(CaseScope::CCP) => VowelForm {
432 has_glottal_stop: false,
433 sequence: VowelFormSequence::S1,
434 degree: VowelFormDegree::D8,
435 },
436 MoodOrCaseScope::CaseScope(CaseScope::CCV) => VowelForm {
437 has_glottal_stop: false,
438 sequence: VowelFormSequence::S2,
439 degree: VowelFormDegree::D9,
440 },
441 }
442 }
443}
444
445impl FromTokens for MoodOrCaseScope {
446 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
447 use VowelFormDegree as D;
448 use VowelFormSequence as S;
449
450 match stream.next_any() {
451 Some(Token::V(VowelForm {
452 has_glottal_stop: false,
453 sequence,
454 degree,
455 })) => match (sequence, degree) {
456 (S::S1, D::D1) => Ok(MoodOrCaseScope::Mood(Mood::FAC)),
457 (S::S1, D::D3) => Ok(MoodOrCaseScope::Mood(Mood::SUB)),
458 (S::S1, D::D4) => Ok(MoodOrCaseScope::Mood(Mood::ASM)),
459 (S::S1, D::D7) => Ok(MoodOrCaseScope::Mood(Mood::SPC)),
460 (S::S1, D::D6) => Ok(MoodOrCaseScope::Mood(Mood::COU)),
461 (S::S1, D::D9) => Ok(MoodOrCaseScope::Mood(Mood::HYP)),
462
463 (S::S2, D::D1) => Ok(MoodOrCaseScope::CaseScope(CaseScope::CCN)),
464 (S::S2, D::D3) => Ok(MoodOrCaseScope::CaseScope(CaseScope::CCA)),
465 (S::S2, D::D8) => Ok(MoodOrCaseScope::CaseScope(CaseScope::CCS)),
466 (S::S2, D::D7) => Ok(MoodOrCaseScope::CaseScope(CaseScope::CCQ)),
467 (S::S1, D::D8) => Ok(MoodOrCaseScope::CaseScope(CaseScope::CCP)),
468 (S::S2, D::D9) => Ok(MoodOrCaseScope::CaseScope(CaseScope::CCV)),
469
470 _ => Err(ParseError::ExpectedCn),
471 },
472 _ => Err(ParseError::ExpectedCn),
473 }
474 }
475}
476
477impl IntoTokens for ModularAdjunctMode {
478 fn append_tokens_to(&self, list: &mut TokenList, _flags: IntoTokensFlags) {
479 match self {
480 ModularAdjunctMode::Parent => list.push(WYForm::W),
481 ModularAdjunctMode::Concatenated => list.push(WYForm::Y),
482 ModularAdjunctMode::Full => {}
483 }
484 }
485}
486
487impl FromTokens for ModularAdjunctMode {
488 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
489 match stream.next() {
490 Some(WYForm::W) => Ok(ModularAdjunctMode::Parent),
491 Some(WYForm::Y) => Ok(ModularAdjunctMode::Concatenated),
492 None => Ok(ModularAdjunctMode::Full),
493 }
494 }
495}
496
497impl IntoVowelForm for NonAspectualVn {
498 fn into_vowel_form(self) -> VowelForm {
499 let (sequence, degree) = match self {
500 NonAspectualVn::Valence(value) => (VowelFormSequence::S1, value as u8),
501 NonAspectualVn::Phase(value) => (VowelFormSequence::S1, value as u8),
502 NonAspectualVn::Effect(value) => (VowelFormSequence::S1, value as u8),
503 NonAspectualVn::Level(value) => (VowelFormSequence::S1, value as u8),
504 };
505
506 VowelForm {
507 has_glottal_stop: false,
508 sequence,
509 degree: match degree {
510 0 => VowelFormDegree::D1,
511 1 => VowelFormDegree::D2,
512 2 => VowelFormDegree::D3,
513 3 => VowelFormDegree::D4,
514 4 => VowelFormDegree::D5,
515 5 => VowelFormDegree::D6,
516 6 => VowelFormDegree::D7,
517 7 => VowelFormDegree::D8,
518 8 => VowelFormDegree::D9,
519 _ => unreachable!(),
520 },
521 }
522 }
523}
524
525impl FromTokens for NonAspectualVn {
526 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
527 let vn: VowelForm = stream.next().ok_or(ParseError::ExpectedVn)?;
528 if vn.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
529 return Err(ParseError::GlottalizedVn);
530 }
531 Self::from_vowel_form(vn).ok_or(ParseError::ExpectedVn)
532 }
533}
534
535impl IntoVowelForm for Aspect {
536 fn into_vowel_form(self) -> VowelForm {
537 let value = self as u8;
538
539 VowelForm {
540 has_glottal_stop: false,
541 sequence: match value / 9 {
542 0 => VowelFormSequence::S1,
543 1 => VowelFormSequence::S2,
544 2 => VowelFormSequence::S3,
545 3 => VowelFormSequence::S4,
546 _ => unreachable!(),
547 },
548 degree: match value % 9 {
549 0 => VowelFormDegree::D1,
550 1 => VowelFormDegree::D2,
551 2 => VowelFormDegree::D3,
552 3 => VowelFormDegree::D4,
553 4 => VowelFormDegree::D5,
554 5 => VowelFormDegree::D6,
555 6 => VowelFormDegree::D7,
556 7 => VowelFormDegree::D8,
557 8 => VowelFormDegree::D9,
558 _ => unreachable!(),
559 },
560 }
561 }
562}
563
564impl FromTokens for Aspect {
565 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
566 let vn: VowelForm = stream.next().ok_or(ParseError::ExpectedVn)?;
567 if vn.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
568 return Err(ParseError::GlottalizedVn);
569 }
570 Self::from_vowel_form(vn).ok_or(ParseError::ExpectedVn)
571 }
572}
573
574impl IntoVowelForm for ModularAdjunctScope {
575 fn into_vowel_form(self) -> VowelForm {
576 VowelForm {
577 has_glottal_stop: false,
578 sequence: VowelFormSequence::S1,
579 degree: match self {
580 ModularAdjunctScope::Formative => VowelFormDegree::D1,
581 ModularAdjunctScope::MCS => VowelFormDegree::D3,
582 ModularAdjunctScope::OverAdj => VowelFormDegree::D4,
583 ModularAdjunctScope::UnderAdj => VowelFormDegree::D7,
584 },
585 }
586 }
587}
588
589impl FromTokens for ModularAdjunctScope {
590 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
591 let Some(VowelForm {
592 has_glottal_stop,
593 sequence: VowelFormSequence::S1,
594 degree,
595 }) = stream.next()
596 else {
597 return Err(ParseError::ExpectedVh);
598 };
599
600 if has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
601 return Err(ParseError::GlottalizedVh);
602 }
603
604 match degree {
605 VowelFormDegree::D1 => Ok(ModularAdjunctScope::Formative),
606 VowelFormDegree::D3 => Ok(ModularAdjunctScope::MCS),
607 VowelFormDegree::D4 | VowelFormDegree::D9 => Ok(ModularAdjunctScope::OverAdj),
608 VowelFormDegree::D7 => Ok(ModularAdjunctScope::UnderAdj),
609 _ => Err(ParseError::ExpectedVh),
610 }
611 }
612}
613
614#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
617pub struct Cn {
618 pub mcs: ArbitraryMoodOrCaseScope,
620
621 pub is_aspect: bool,
623}
624
625impl IntoToken for Cn {
626 fn into_token(self) -> Token {
627 Token::H(HForm {
628 sequence: match self.is_aspect {
629 false => HFormSequence::S0,
630 true => HFormSequence::SW,
631 },
632 degree: match self.mcs {
633 ArbitraryMoodOrCaseScope::FAC_CCN => HFormDegree::D1,
634 ArbitraryMoodOrCaseScope::SUB_CCA => HFormDegree::D2,
635 ArbitraryMoodOrCaseScope::ASM_CCS => HFormDegree::D3,
636 ArbitraryMoodOrCaseScope::SPC_CCQ => HFormDegree::D4,
637 ArbitraryMoodOrCaseScope::COU_CCP => HFormDegree::D5,
638 ArbitraryMoodOrCaseScope::HYP_CCV => HFormDegree::D6,
639 },
640 })
641 }
642}
643
644impl FromTokens for Cn {
645 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
646 let cn: HForm = stream.next().ok_or(ParseError::ExpectedCn)?;
647
648 let is_aspect = matches!(cn.sequence, HFormSequence::SW | HFormSequence::SY);
649
650 let mcs = match cn.degree {
651 HFormDegree::D1 => ArbitraryMoodOrCaseScope::FAC_CCN,
652 HFormDegree::D2 => ArbitraryMoodOrCaseScope::SUB_CCA,
653 HFormDegree::D3 => ArbitraryMoodOrCaseScope::ASM_CCS,
654 HFormDegree::D4 => ArbitraryMoodOrCaseScope::SPC_CCQ,
655 HFormDegree::D5 => ArbitraryMoodOrCaseScope::COU_CCP,
656 HFormDegree::D6 => ArbitraryMoodOrCaseScope::HYP_CCV,
657 };
658
659 Ok(Self { mcs, is_aspect })
660 }
661}
662
663#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
665pub struct Cm {
666 pub is_aspect: bool,
668}
669
670impl IntoToken for Cm {
671 fn into_token(self) -> Token {
672 Token::C(OwnedConsonantForm(
673 if self.is_aspect { "ň" } else { "n" }.to_owned(),
674 ))
675 }
676}
677
678impl FromTokens for Cm {
679 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
680 match stream.next_any() {
681 Some(Token::C(OwnedConsonantForm(source))) => match &source[..] {
682 "n" => Ok(Self { is_aspect: false }),
683 "ň" => Ok(Self { is_aspect: true }),
684 _ => Err(ParseError::ExpectedCm),
685 },
686 _ => Err(ParseError::ExpectedCm),
687 }
688 }
689}
690
691#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
693pub struct VnCn {
694 pub vn: Vn,
696
697 pub cn: ArbitraryMoodOrCaseScope,
699}
700
701impl FromTokens for VnCn {
702 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
703 let vn: VowelForm = stream.next().ok_or(ParseError::ExpectedVn)?;
704
705 if vn.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
706 return Err(ParseError::GlottalizedVn);
707 }
708
709 let cn: Cn = stream.parse(flags)?;
710
711 Ok(Self {
712 vn: Vn::from_vowel_form(vn, cn.is_aspect).ok_or(ParseError::ExpectedVn)?,
713 cn: cn.mcs,
714 })
715 }
716}
717
718impl IntoTokens for VnCn {
719 fn append_tokens_to(&self, list: &mut TokenList, _flags: IntoTokensFlags) {
720 match self.vn.as_non_aspectual_vn() {
721 Ok(non_aspectual) => {
722 list.push(non_aspectual);
723
724 list.push(Cn {
725 mcs: self.cn,
726 is_aspect: false,
727 });
728 }
729 Err(aspect) => {
730 list.push(aspect);
731 list.push(Cn {
732 mcs: self.cn,
733 is_aspect: true,
734 });
735 }
736 }
737 }
738}
739
740#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
742pub struct VnCm {
743 pub vn: Vn,
745}
746
747impl FromTokens for VnCm {
748 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
749 let vn: VowelForm = stream.next().ok_or(ParseError::ExpectedVn)?;
750
751 if vn.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
752 return Err(ParseError::GlottalizedVn);
753 }
754
755 let cm: Cm = stream.parse(flags)?;
756
757 Ok(Self {
758 vn: Vn::from_vowel_form(vn, cm.is_aspect).ok_or(ParseError::ExpectedVn)?,
759 })
760 }
761}
762
763impl IntoTokens for VnCm {
764 fn append_tokens_to(&self, list: &mut TokenList, _flags: IntoTokensFlags) {
765 match self.vn.as_non_aspectual_vn() {
766 Ok(non_aspectual) => {
767 list.push(non_aspectual);
768 list.push(Cm { is_aspect: false });
769 }
770 Err(aspect) => {
771 list.push(aspect);
772 list.push(Cm { is_aspect: true });
773 }
774 }
775 }
776}
777
778#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
780pub struct VnCnWithGlottalStop {
781 pub vn: Vn,
783
784 pub has_glottal_stop: bool,
786
787 pub cn: ArbitraryMoodOrCaseScope,
789}
790
791impl FromTokens for VnCnWithGlottalStop {
792 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
793 let vn: VowelForm = stream.next().ok_or(ParseError::ExpectedVn)?;
794
795 let cn: Cn = stream.parse(flags)?;
796
797 Ok(Self {
798 vn: Vn::from_vowel_form(vn, cn.is_aspect).ok_or(ParseError::ExpectedVn)?,
799 has_glottal_stop: vn.has_glottal_stop,
800 cn: cn.mcs,
801 })
802 }
803}
804
805impl IntoTokens for VnCnWithGlottalStop {
806 fn append_tokens_to(&self, list: &mut TokenList, _flags: IntoTokensFlags) {
807 match self.vn.as_non_aspectual_vn() {
808 Ok(vn) => {
809 let mut vn = vn.into_vowel_form();
810 vn.has_glottal_stop = self.has_glottal_stop;
811 list.push(vn);
812 list.push(Cn {
813 mcs: self.cn,
814 is_aspect: false,
815 });
816 }
817 Err(vn) => {
818 let mut vn = vn.into_vowel_form();
819 vn.has_glottal_stop = self.has_glottal_stop;
820 list.push(vn);
821 list.push(Cn {
822 mcs: self.cn,
823 is_aspect: true,
824 });
825 }
826 }
827 }
828}
829
830#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
832pub struct VxCs {
833 pub affix: RegularAffix,
835}
836
837impl FromTokens for VxCs {
838 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
839 let vx: VowelForm = stream.next().ok_or(ParseError::ExpectedVx)?;
840 if vx.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
841 return Err(ParseError::GlottalizedVx);
842 }
843 let cs = stream.next_cs().ok_or(ParseError::ExpectedCs)?;
844 Ok(VxCs {
845 affix: RegularAffix::from_vxcs(vx, &cs)?,
846 })
847 }
848}
849
850#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
852pub struct VxCsWithGlottalStop {
853 pub affix: RegularAffix,
855
856 pub has_glottal_stop: bool,
858}
859
860impl FromTokens for VxCsWithGlottalStop {
861 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
862 let vx: VowelForm = stream.next().ok_or(ParseError::ExpectedVx)?;
863 if vx.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
864 return Err(ParseError::GlottalizedVx);
865 }
866 let cs = stream.next_cs().ok_or(ParseError::ExpectedCs)?;
867 Ok(Self {
868 affix: RegularAffix::from_vxcs(vx, &cs)?,
869 has_glottal_stop: vx.has_glottal_stop,
870 })
871 }
872}
873
874#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
876pub struct CsVxWithGlottalStop {
877 pub affix: RegularAffix,
879
880 pub has_glottal_stop: bool,
882}
883
884impl FromTokens for CsVxWithGlottalStop {
885 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
886 let cs = stream.next_cs().ok_or(ParseError::ExpectedCs)?.to_owned();
887 let vx: VowelForm = stream.next().ok_or(ParseError::ExpectedVx)?;
888 if vx.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
889 return Err(ParseError::GlottalizedVx);
890 }
891 Ok(Self {
892 affix: RegularAffix::from_vxcs(vx, &cs)?,
893 has_glottal_stop: vx.has_glottal_stop,
894 })
895 }
896}
897
898#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
900pub struct Vs {
901 pub scope: AffixualAdjunctScope,
903}
904
905impl FromTokens for Vs {
906 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
907 let Some(vowel_form): Option<VowelForm> = stream.next() else {
908 return Ok(Vs {
909 scope: AffixualAdjunctScope::VDom,
910 });
911 };
912
913 if vowel_form.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
914 return Err(ParseError::GlottalizedVs);
915 }
916
917 if vowel_form.sequence != VowelFormSequence::S1 {
918 return Err(ParseError::ExpectedVs);
919 }
920
921 match vowel_form.degree {
922 VowelFormDegree::D1 => Ok(Vs {
923 scope: AffixualAdjunctScope::VDom,
924 }),
925 VowelFormDegree::D9 => Ok(Vs {
926 scope: AffixualAdjunctScope::VSub,
927 }),
928 VowelFormDegree::D3 => Ok(Vs {
929 scope: AffixualAdjunctScope::VIIDom,
930 }),
931 VowelFormDegree::D4 => Ok(Vs {
932 scope: AffixualAdjunctScope::VIISub,
933 }),
934 VowelFormDegree::D7 => Ok(Vs {
935 scope: AffixualAdjunctScope::Formative,
936 }),
937 VowelFormDegree::D6 => Ok(Vs {
938 scope: AffixualAdjunctScope::OverAdj,
939 }),
940 _ => Err(ParseError::ExpectedVs),
941 }
942 }
943}
944
945impl IntoVowelForm for Vs {
946 fn into_vowel_form(self) -> VowelForm {
947 VowelForm {
948 has_glottal_stop: false,
949 sequence: VowelFormSequence::S1,
950 degree: match self.scope {
951 AffixualAdjunctScope::VDom => VowelFormDegree::D1,
952 AffixualAdjunctScope::VSub => VowelFormDegree::D9,
953 AffixualAdjunctScope::VIIDom => VowelFormDegree::D3,
954 AffixualAdjunctScope::VIISub => VowelFormDegree::D4,
955 AffixualAdjunctScope::Formative => VowelFormDegree::D7,
956 AffixualAdjunctScope::OverAdj => VowelFormDegree::D6,
957 },
958 }
959 }
960}
961
962#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
964pub struct Vz {
965 pub scope: Option<AffixualAdjunctScope>,
967}
968
969impl FromTokens for Vz {
970 fn parse_volatile(stream: &mut TokenStream, flags: FromTokenFlags) -> Result<Self, ParseError> {
971 let Some(vowel_form): Option<VowelForm> = stream.next() else {
972 return Ok(Vz { scope: None });
973 };
974
975 if vowel_form.has_glottal_stop && !flags.matches(FromTokenFlags::PERMISSIVE) {
976 return Err(ParseError::GlottalizedVz);
977 }
978
979 if matches!(
980 vowel_form,
981 VowelForm {
982 has_glottal_stop: false,
983 sequence: VowelFormSequence::S2,
984 degree: VowelFormDegree::D1
985 }
986 ) {
987 return Ok(Vz { scope: None });
988 }
989
990 if vowel_form.sequence != VowelFormSequence::S1 {
991 return Err(ParseError::ExpectedVz);
992 }
993
994 match vowel_form.degree {
995 VowelFormDegree::D1 => Ok(Vz {
996 scope: Some(AffixualAdjunctScope::VDom),
997 }),
998 VowelFormDegree::D9 => Ok(Vz {
999 scope: Some(AffixualAdjunctScope::VSub),
1000 }),
1001 VowelFormDegree::D3 => Ok(Vz {
1002 scope: Some(AffixualAdjunctScope::VIIDom),
1003 }),
1004 VowelFormDegree::D4 => Ok(Vz {
1005 scope: Some(AffixualAdjunctScope::VIISub),
1006 }),
1007 VowelFormDegree::D7 => Ok(Vz {
1008 scope: Some(AffixualAdjunctScope::Formative),
1009 }),
1010 VowelFormDegree::D6 => Ok(Vz {
1011 scope: Some(AffixualAdjunctScope::OverAdj),
1012 }),
1013 _ => Err(ParseError::ExpectedVz),
1014 }
1015 }
1016}
1017
1018impl IntoVowelForm for Vz {
1019 fn into_vowel_form(self) -> VowelForm {
1020 match self.scope {
1021 None => VowelForm {
1022 has_glottal_stop: false,
1023 sequence: VowelFormSequence::S2,
1024 degree: VowelFormDegree::D1,
1025 },
1026 Some(AffixualAdjunctScope::VDom) => VowelForm {
1027 has_glottal_stop: false,
1028 sequence: VowelFormSequence::S1,
1029 degree: VowelFormDegree::D1,
1030 },
1031
1032 Some(AffixualAdjunctScope::VSub) => VowelForm {
1033 has_glottal_stop: false,
1034 sequence: VowelFormSequence::S1,
1035 degree: VowelFormDegree::D9,
1036 },
1037
1038 Some(AffixualAdjunctScope::VIIDom) => VowelForm {
1039 has_glottal_stop: false,
1040 sequence: VowelFormSequence::S1,
1041 degree: VowelFormDegree::D3,
1042 },
1043
1044 Some(AffixualAdjunctScope::VIISub) => VowelForm {
1045 has_glottal_stop: false,
1046 sequence: VowelFormSequence::S1,
1047 degree: VowelFormDegree::D4,
1048 },
1049
1050 Some(AffixualAdjunctScope::Formative) => VowelForm {
1051 has_glottal_stop: false,
1052 sequence: VowelFormSequence::S1,
1053 degree: VowelFormDegree::D7,
1054 },
1055
1056 Some(AffixualAdjunctScope::OverAdj) => VowelForm {
1057 has_glottal_stop: false,
1058 sequence: VowelFormSequence::S1,
1059 degree: VowelFormDegree::D6,
1060 },
1061 }
1062 }
1063}
1064
1065#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1068pub struct CsVxCz {
1069 pub affix: RegularAffix,
1071
1072 pub scope: AffixualAdjunctScope,
1074}
1075
1076impl FromTokens for CsVxCz {
1077 fn parse_volatile(stream: &mut TokenStream, _: FromTokenFlags) -> Result<Self, ParseError> {
1078 let cs = stream.next_cs().ok_or(ParseError::ExpectedCs)?.to_owned();
1079 let vx: VowelForm = stream.next().ok_or(ParseError::ExpectedVx)?;
1080 let cz: HForm = stream.next().ok_or(ParseError::ExpectedCz)?;
1081 Ok(Self {
1082 affix: RegularAffix::from_vxcs(vx, &cs)?,
1083 scope: match vx.has_glottal_stop {
1084 false => match cz {
1085 HForm::H => AffixualAdjunctScope::VDom,
1086 HForm::HW => AffixualAdjunctScope::Formative,
1087 _ => return Err(ParseError::ExpectedCz),
1088 },
1089 true => match cz {
1090 HForm::H => AffixualAdjunctScope::VSub,
1091 HForm::HL => AffixualAdjunctScope::VIIDom,
1092 HForm::HR => AffixualAdjunctScope::VIISub,
1093 HForm::HW => AffixualAdjunctScope::OverAdj,
1094 _ => return Err(ParseError::ExpectedCz),
1095 },
1096 },
1097 })
1098 }
1099}
1100
1101#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
1103pub struct Vc2 {
1104 pub case: Option<Case>,
1106}
1107
1108impl FromTokens for Vc2 {
1109 fn parse_volatile(
1110 stream: &mut TokenStream,
1111 _flags: FromTokenFlags,
1112 ) -> Result<Self, ParseError> {
1113 match stream.next_any() {
1114 Some(Token::V(VowelForm {
1115 has_glottal_stop: false,
1116 sequence: VowelFormSequence::S1,
1117 degree: VowelFormDegree::D1,
1118 })) => Ok(Vc2 { case: None }),
1119
1120 Some(Token::V(vc)) => Ok(Vc2 {
1121 case: Some(Case::from_vc(*vc)?),
1122 }),
1123
1124 Some(Token::ÜA) => Ok(Vc2 {
1125 case: Some(Case::THM),
1126 }),
1127
1128 None => Ok(Vc2 { case: None }),
1129
1130 _ => Err(ParseError::ExpectedVc2),
1131 }
1132 }
1133}