aboutsummaryrefslogtreecommitdiff
path: root/src/tokenizer/tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tokenizer/tokens.rs')
-rw-r--r--src/tokenizer/tokens.rs202
1 files changed, 146 insertions, 56 deletions
diff --git a/src/tokenizer/tokens.rs b/src/tokenizer/tokens.rs
index fa1d7e7..d013497 100644
--- a/src/tokenizer/tokens.rs
+++ b/src/tokenizer/tokens.rs
@@ -1,74 +1,164 @@
-#[derive(Debug, PartialEq, Eq)]
+//! The voice-code alphabet.
+//!
+//! `mMsg_sound_voice_get` folds the game's 256-entry character set down to these 34
+//! values. Everything after this point — word boundaries, capitalisation, sentence
+//! structure, and any letter outside `a-z0-9` — is gone.
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControlCode {
- Melody, // 0x80
- Space, // 0x81
- Question, // 0x82
- Bang, // 0x83
- Newline, // 0x84
- Punct, // 0x85
- Bebe, // 0x86,
- Control, // -1
+ /// ♪ — plays the speaker's melody and bypasses the whole engine.
+ Melody, // 0x80
+ Space, // 0x81
+ Question, // 0x82
+ Bang, // 0x83
+ /// Injected by `mMsg_sound_voice_get2`; never present in the raw table.
+ Newline, // 0x84
+ /// The catch-all for punctuation and symbols.
+ Punct, // 0x85
+ /// The typing click. Only the interpunct (char 133) maps here.
+ Bebe, // 0x86
+ /// An empty `b` / `c` slot in a half-built window.
+ Empty, // 0xFF
+ /// `mMsg_sound_voice_get` returning `-1` for `CHAR_CONTROL_CODE` /
+ /// `CHAR_MESSAGE_TAG`. Never reaches the audio engine: `mMsg_sound_CodeVoice`
+ /// drops it, and the `c` lookahead folds it to [`ControlCode::Empty`].
+ Control, // -1
+}
+
+impl ControlCode {
+ /// [`ControlCode::Control`] has no code of its own; it reports `0xFF` because that is
+ /// what the lookahead substitutes, and it can never reach playback by any other path.
+ pub const fn code(self) -> u8 {
+ match self {
+ ControlCode::Melody => 0x80,
+ ControlCode::Space => 0x81,
+ ControlCode::Question => 0x82,
+ ControlCode::Bang => 0x83,
+ ControlCode::Newline => 0x84,
+ ControlCode::Punct => 0x85,
+ ControlCode::Bebe => 0x86,
+ ControlCode::Empty | ControlCode::Control => 0xFF,
+ }
+ }
}
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Letter {
- A, // 0x5D
- B, // 0x5E
- C, // 0x5F
- D, // 0x60
- E, // 0x61
- F, // 0x62
- G, // 0x63
- H, // 0x64
- I, // 0x65
- J, // 0x66
- K, // 0x67
- L, // 0x68
- M, // 0x69
- N, // 0x6A
- O, // 0x6B
- P, // 0x6C
- Q, // 0x6D
- R, // 0x6E
- S, // 0x6F
- T, // 0x70
- U, // 0x71
- V, // 0x72
- W, // 0x73
- X, // 0x74
- Y, // 0x75
- Z, // 0x76
+ A,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ I,
+ J,
+ K,
+ L,
+ M,
+ N,
+ O,
+ P,
+ Q,
+ R,
+ S,
+ T,
+ U,
+ V,
+ W,
+ X,
+ Y,
+ Z,
}
-#[derive(Debug, PartialEq, Eq)]
+impl Letter {
+ /// `0x5D + (letter - 'a')`.
+ pub const fn code(self) -> u8 {
+ use Letter::*;
+ match self {
+ A => 0x5D,
+ B => 0x5E,
+ C => 0x5F,
+ D => 0x60,
+ E => 0x61,
+ F => 0x62,
+ G => 0x63,
+ H => 0x64,
+ I => 0x65,
+ J => 0x66,
+ K => 0x67,
+ L => 0x68,
+ M => 0x69,
+ N => 0x6A,
+ O => 0x6B,
+ P => 0x6C,
+ Q => 0x6D,
+ R => 0x6E,
+ S => 0x6F,
+ T => 0x70,
+ U => 0x71,
+ V => 0x72,
+ W => 0x73,
+ X => 0x74,
+ Y => 0x75,
+ Z => 0x76,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Digit {
- D0, // 0x53
- D1, // 0x54
- D2, // 0x55
- D3, // 0x56
- D4, // 0x57
- D5, // 0x58
- D6, // 0x59
- D7, // 0x5A
- D8, // 0x5B
- D9, // 0x5C
+ D0,
+ D1,
+ D2,
+ D3,
+ D4,
+ D5,
+ D6,
+ D7,
+ D8,
+ D9,
+}
+
+impl Digit {
+ /// `0x53 + digit`. This is the *voice* code, not the phoneme code — see
+ /// `phonemes::digit_code` for what the conversion tables turn it into.
+ pub const fn code(self) -> u8 {
+ use Digit::*;
+ match self {
+ D0 => 0x53,
+ D1 => 0x54,
+ D2 => 0x55,
+ D3 => 0x56,
+ D4 => 0x57,
+ D5 => 0x58,
+ D6 => 0x59,
+ D7 => 0x5A,
+ D8 => 0x5B,
+ D9 => 0x5C,
+ }
+ }
}
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VoiceCode {
Letter(Letter),
ControlCode(ControlCode),
- Digit(Digit)
+ Digit(Digit),
}
-
-impl Letter {
- fn is_shiin(&self) -> bool {
- !self.is_boin()
+impl VoiceCode {
+ pub const fn code(self) -> u8 {
+ match self {
+ VoiceCode::Letter(l) => l.code(),
+ VoiceCode::ControlCode(c) => c.code(),
+ VoiceCode::Digit(d) => d.code(),
+ }
}
- fn is_boin(&self) -> bool {
- use Letter::*;
- [A, E, I, O, U, N].contains(&self)
+ /// `> 0x77` — the test several rules use to mean "punctuation, not a letter".
+ pub const fn is_punctuation(self) -> bool {
+ self.code() > 0x77
}
}