Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 715 |
1 files changed, 715 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4b9585d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,715 @@ +pub mod recognizer; + +mod utf8; + +const CLASS_TABLE: [Class; 0x80] = [ + Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 , + Class::C0S,Class::C0S,Class::C0S,Class::C0S,Class::C0S,Class::C0S,Class::C0 ,Class::C0 , + + Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 , + Class::C0 ,Class::C0 ,Class::C0 ,Class::ESC,Class::C0 ,Class::C0 ,Class::C0 ,Class::C0 , + + Class::INT,Class::INT,Class::INT,Class::INT,Class::INT,Class::INT,Class::INT,Class::INT, + Class::INT,Class::INT,Class::INT,Class::INT,Class::INT,Class::INT,Class::INT,Class::INT, + + Class::PAR,Class::PAR,Class::PAR,Class::PAR,Class::PAR,Class::PAR,Class::PAR,Class::PAR, + Class::PAR,Class::PAR,Class::SEP,Class::SEP,Class::PRI,Class::PRI,Class::PRI,Class::PRI, + + Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 , + Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 , + + Class::CSO,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 ,Class::C1 , + Class::SOS,Class::C1 ,Class::SCI,Class::CSI,Class::ST ,Class::CSO,Class::CSO,Class::CSO, + + Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF, + Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF, + + Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF, + Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::ICF,Class::DEL, +]; + +const STATE_TABLE: [State; 0xE0] = [ + State::C0Control, // Ground + C0 + State::C0Control, // Ground + C0S + State::StartEscape, // Ground + ESC + State::Char, // Ground + INT + State::Char, // Ground + PAR + State::Char, // Ground + SEP + State::Char, // Ground + PRI + State::Char, // Ground + C1 + State::Char, // Ground + CSO + State::Char, // Ground + SOS + State::Char, // Ground + SCI + State::Char, // Ground + CSI + State::Char, // Ground + ST + State::Char, // Ground + ICF + State::Ground, // Ground + DEL + State::Ground, // Ground + PAD + + State::C0Control, // Escape + C0 + State::C0Control, // Escape + C0S + State::StartEscape, // Escape + ESC + State::PushIntermediateByte, // Escape + INT + State::FinishSequence, // Escape + PAR + State::FinishSequence, // Escape + SEP + State::FinishSequence, // Escape + PRI + State::C1Control, // Escape + C1 + State::StartCommandString, // Escape + CSO + State::StartCharacterString, // Escape + SOS + State::StartSingleCharacter, // Escape + SCI + State::StartControlSequence, // Escape + CSI + State::C1Control, // Escape + ST + State::FinishSequence, // Escape + ICF + State::Ground, // Escape + DEL + State::Ground, // Escape + PAD + + State::ControlFunctionError, // ControlFunction + C0 + State::ControlFunctionError, // ControlFunction + C0S + State::ControlFunctionError, // ControlFunction + ESC + State::PushIntermediateByte, // ControlFunction + INT + State::FinishSequence, // ControlFunction + PAR + State::FinishSequence, // ControlFunction + SEP + State::FinishSequence, // ControlFunction + PRI + State::FinishSequence, // ControlFunction + C1 + State::FinishSequence, // ControlFunction + CSO + State::FinishSequence, // ControlFunction + SOS + State::FinishSequence, // ControlFunction + SCI + State::FinishSequence, // ControlFunction + CSI + State::FinishSequence, // ControlFunction + ST + State::FinishSequence, // ControlFunction + ICF + State::Ground, // ControlFunction + DEL + State::ControlFunctionError, // ControlFunction + PAD + + State::ControlFunctionError, // ControlFunctionError + C0 + State::ControlFunctionError, // ControlFunctionError + C0S + State::ControlFunctionError, // ControlFunctionError + ESC + State::ControlFunctionError, // ControlFunctionError + INT + State::Ground, // ControlFunctionError + PAR + State::Ground, // ControlFunctionError + SEP + State::Ground, // ControlFunctionError + PRI + State::Ground, // ControlFunctionError + C1 + State::Ground, // ControlFunctionError + CSO + State::Ground, // ControlFunctionError + SOS + State::Ground, // ControlFunctionError + SCI + State::Ground, // ControlFunctionError + CSI + State::Ground, // ControlFunctionError + ST + State::Ground, // ControlFunctionError + ICF + State::ControlFunctionError, // ControlFunctionError + DEL + State::ControlFunctionError, // ControlFunctionError + PAD + + State::ControlStringError, // CommandString + C0 + State::PushCommandString, // CommandString + C0S + State::CommandStringEscape, // CommandString + ESC + State::PushCommandString, // CommandString + INT + State::PushCommandString, // CommandString + PAR + State::PushCommandString, // CommandString + SEP + State::PushCommandString, // CommandString + PRI + State::PushCommandString, // CommandString + C1 + State::PushCommandString, // CommandString + CSO + State::PushCommandString, // CommandString + SOS + State::PushCommandString, // CommandString + SCI + State::PushCommandString, // CommandString + CSI + State::PushCommandString, // CommandString + ST + State::PushCommandString, // CommandString + ICF + State::ControlStringError, // CommandString + DEL + State::ControlStringError, // CommandString + PAD + + State::ControlStringError, // CommandStringEscape + C0 + State::ControlStringError, // CommandStringEscape + C0S + State::ControlStringError, // CommandStringEscape + ESC + State::ControlStringError, // CommandStringEscape + INT + State::ControlStringError, // CommandStringEscape + PAR + State::ControlStringError, // CommandStringEscape + SEP + State::ControlStringError, // CommandStringEscape + PRI + State::ControlStringError, // CommandStringEscape + C1 + State::ControlStringError, // CommandStringEscape + CSO + State::ControlStringError, // CommandStringEscape + SOS + State::ControlStringError, // CommandStringEscape + SCI + State::ControlStringError, // CommandStringEscape + CSI + State::FinishSequence, // CommandStringEscape + ST + State::ControlStringError, // CommandStringEscape + ICF + State::ControlStringError, // CommandStringEscape + DEL + State::ControlStringError, // CommandStringEscape + PAD + + State::PushCharacterString, // CharacterString + C0 + State::PushCharacterString, // CharacterString + C0S + State::CharacterStringEscape, // CharacterString + ESC + State::PushCharacterString, // CharacterString + INT + State::PushCharacterString, // CharacterString + PAR + State::PushCharacterString, // CharacterString + SEP + State::PushCharacterString, // CharacterString + PRI + State::PushCharacterString, // CharacterString + C1 + State::PushCharacterString, // CharacterString + CSO + State::PushCharacterString, // CharacterString + SOS + State::PushCharacterString, // CharacterString + SCI + State::PushCharacterString, // CharacterString + CSI + State::PushCharacterString, // CharacterString + ST + State::PushCharacterString, // CharacterString + ICF + State::PushCharacterString, // CharacterString + DEL + State::ControlStringError, // CharacterString + PAD + + State::PushCharacterStringEscape, // CharacterStringEscape + C0 + State::PushCharacterStringEscape, // CharacterStringEscape + C0S + State::PushCharacterStringEscape, // CharacterStringEscape + ESC + State::PushCharacterStringEscape, // CharacterStringEscape + INT + State::PushCharacterStringEscape, // CharacterStringEscape + PAR + State::PushCharacterStringEscape, // CharacterStringEscape + SEP + State::PushCharacterStringEscape, // CharacterStringEscape + PRI + State::PushCharacterStringEscape, // CharacterStringEscape + C1 + State::PushCharacterStringEscape, // CharacterStringEscape + CSO + State::ControlStringError, // CharacterStringEscape + SOS + State::PushCharacterStringEscape, // CharacterStringEscape + SCI + State::PushCharacterStringEscape, // CharacterStringEscape + CSI + State::FinishSequence, // CharacterStringEscape + ST + State::PushCharacterStringEscape, // CharacterStringEscape + ICF + State::PushCharacterStringEscape, // CharacterStringEscape + DEL + State::ControlStringError, // CharacterStringEscape + PAD + + State::ControlStringError, // ControlStringError + C0 + State::ControlStringError, // ControlStringError + C0S + State::ControlStringError, // ControlStringError + ESC + State::ControlStringError, // ControlStringError + INT + State::ControlStringError, // ControlStringError + PAR + State::ControlStringError, // ControlStringError + SEP + State::ControlStringError, // ControlStringError + PRI + State::ControlStringError, // ControlStringError + C1 + State::ControlStringError, // ControlStringError + CSO + State::ControlStringError, // ControlStringError + SOS + State::ControlStringError, // ControlStringError + SCI + State::ControlStringError, // ControlStringError + CSI + State::Ground, // ControlStringError + ST + State::ControlStringError, // ControlStringError + ICF + State::ControlStringError, // ControlStringError + DEL + State::ControlStringError, // ControlStringError + PAD + + State::Ground, // SingleCharacter + C0 + State::FinishSequence, // SingleCharacter + C0S + State::Ground, // SingleCharacter + ESC + State::FinishSequence, // SingleCharacter + INT + State::FinishSequence, // SingleCharacter + PAR + State::FinishSequence, // SingleCharacter + SEP + State::FinishSequence, // SingleCharacter + PRI + State::FinishSequence, // SingleCharacter + C1 + State::FinishSequence, // SingleCharacter + CSO + State::FinishSequence, // SingleCharacter + SOS + State::FinishSequence, // SingleCharacter + SCI + State::FinishSequence, // SingleCharacter + CSI + State::FinishSequence, // SingleCharacter + ST + State::FinishSequence, // SingleCharacter + ICF + State::Ground, // SingleCharacter + DEL + State::Ground, // SingleCharacter + PAD + + State::ControlSequenceError, // ControlSequence + C0 + State::ControlSequenceError, // ControlSequence + C0S + State::ControlSequenceError, // ControlSequence + ESC + State::ControlSequencePushIntermediate, // ControlSequence + INT + State::ControlSequenceAddParameter, // ControlSequence + PAR + State::ControlSequencePushParameter, // ControlSequence + SEP + State::PrivateControlSequence, // ControlSequence + PRI + State::FinishControlSequence, // ControlSequence + C1 + State::FinishControlSequence, // ControlSequence + CSO + State::FinishControlSequence, // ControlSequence + SOS + State::FinishControlSequence, // ControlSequence + SCI + State::FinishControlSequence, // ControlSequence + CSI + State::FinishControlSequence, // ControlSequence + ST + State::FinishControlSequence, // ControlSequence + ICF + State::ControlSequenceError, // ControlSequence + DEL + State::ControlSequenceError, // ControlSequence + PAD + + State::ControlSequenceError, // ControlSequenceParameter + C0 + State::ControlSequenceError, // ControlSequenceParameter + C0S + State::ControlSequenceError, // ControlSequenceParameter + ESC + State::ControlSequenceParameterIntermediate, // ControlSequenceParameter + INT + State::ControlSequenceAddParameter, // ControlSequenceParameter + PAR + State::ControlSequencePushParameter, // ControlSequenceParameter + SEP + State::ControlSequenceError, // ControlSequenceParameter + PRI + State::FinishControlSequence, // ControlSequenceParameter + C1 + State::FinishControlSequence, // ControlSequenceParameter + CSO + State::FinishControlSequence, // ControlSequenceParameter + SOS + State::FinishControlSequence, // ControlSequenceParameter + SCI + State::FinishControlSequence, // ControlSequenceParameter + CSI + State::FinishControlSequence, // ControlSequenceParameter + ST + State::FinishControlSequence, // ControlSequenceParameter + ICF + State::ControlSequenceError, // ControlSequenceParameter + DEL + State::ControlSequenceError, // ControlSequenceParameter + PAD + + State::ControlSequenceError, // ControlSequenceIntermediate + C0 + State::ControlSequenceError, // ControlSequenceIntermediate + C0S + State::ControlSequenceError, // ControlSequenceIntermediate + ESC + State::ControlSequencePushIntermediate, // ControlSequenceIntermediate + INT + State::ControlSequenceError, // ControlSequenceIntermediate + PAR + State::ControlSequenceError, // ControlSequenceIntermediate + SEP + State::ControlSequenceError, // ControlSequenceIntermediate + PRI + State::FinishControlSequence, // ControlSequenceIntermediate + C1 + State::FinishControlSequence, // ControlSequenceIntermediate + CSO + State::FinishControlSequence, // ControlSequenceIntermediate + SOS + State::FinishControlSequence, // ControlSequenceIntermediate + SCI + State::FinishControlSequence, // ControlSequenceIntermediate + CSI + State::FinishControlSequence, // ControlSequenceIntermediate + ST + State::FinishControlSequence, // ControlSequenceIntermediate + ICF + State::ControlSequenceError, // ControlSequenceIntermediate + DEL + State::ControlSequenceError, // ControlSequenceIntermediate + PAD + + State::ControlSequenceError, // ControlSequenceError + C0 + State::ControlSequenceError, // ControlSequenceError + C0S + State::ControlSequenceError, // ControlSequenceError + ESC + State::ControlSequenceError, // ControlSequenceError + INT + State::ControlSequenceError, // ControlSequenceError + PAR + State::ControlSequenceError, // ControlSequenceError + SEP + State::ControlSequenceError, // ControlSequenceError + PRI + State::Ground, // ControlSequenceError + C1 + State::Ground, // ControlSequenceError + CSO + State::Ground, // ControlSequenceError + SOS + State::Ground, // ControlSequenceError + SCI + State::Ground, // ControlSequenceError + CSI + State::Ground, // ControlSequenceError + ST + State::Ground, // ControlSequenceError + ICF + State::ControlSequenceError, // ControlSequenceError + DEL + State::ControlSequenceError, // ControlSequenceError + PAD +]; + +#[repr(u8)] +#[derive(Copy, Clone)] +enum Class { + /// C0 Control Functions + /// + /// 00..1F + C0, + + /// C0 Control Functions permitted in Control Strings + /// + /// 08..0D + C0S, + + /// ESCAPE + /// + /// 1B + ESC, + + /// Control Function / Control Sequence Intermediate Bytes + /// + /// 20..2F + INT, + + /// Control Sequence Parameter Bytes + /// + /// 30..39 + PAR, + + /// Control Sequence Parameter Separators + /// + /// 3A..3B + SEP, + + /// Control Sequence Private Parameter String Indicator + /// + /// 3C..3F + PRI, + + /// C1 Control Functions + /// + /// ESC 40..5F + C1, + + /// Command String Opening Delimiter + /// + /// ESC 50, ESC 5D..5F + CSO, + + /// Start Of String + /// + /// ESC 58 + SOS, + + /// Single Character Introducer + /// + /// ESC 5A + SCI, + + /// Control Sequence Introducer + /// + /// ESC 5B + CSI, + + /// String Terminator + /// + /// ESC 5C + ST, + + /// Independent Control Function Final Bytes + /// + /// 60..7E + ICF, + + /// DELETE + /// + /// 7F + DEL, +} + +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +enum State { + // All base states + + Ground = 0x00, + Escape = 0x10, + ControlFunction = 0x20, + ControlFunctionError = 0x30, + CommandString = 0x40, + CommandStringEscape = 0x50, + CharacterString = 0x60, + CharacterStringEscape = 0x70, + ControlStringError = 0x80, + SingleCharacter = 0x90, + ControlSequence = 0xA0, + ControlSequenceParameter = 0xB0, + ControlSequenceIntermediate = 0xC0, + ControlSequenceError = 0xD0, + + // All action states + // The upper 4 bits set a base state to return to (see above), + // the lower 4 bits set an action to perform (see below) + // Base states impicitly have Action::Continue. + + C0Control = + State::Ground as u8 | Action::C01Control as u8, + + Char = + State::Ground as u8 | Action::Char as u8, + + StartEscape = + State::Escape as u8 | Action::StartSequence as u8, + + PushIntermediateByte = + State::ControlFunction as u8 | Action::PushByte as u8, + + C1Control = + State::Escape as u8 | Action::C01Control as u8, + + FinishSequence = + State::Ground as u8 | Action::FinishSequence as u8, + + StartCommandString = + State::CommandString as u8 | Action::StartSequence as u8, + + StartCharacterString = + State::CharacterString as u8 | Action::StartSequence as u8, + + StartSingleCharacter = + State::SingleCharacter as u8 | Action::StartSequence as u8, + + StartControlSequence = + State::ControlSequence as u8 | Action::StartSequence as u8, + + PushCommandString = + State::CommandString as u8 | Action::PushByte as u8, + + PushCharacterString = + State::CharacterString as u8 | Action::PushByte as u8, + + PushCharacterStringEscape = + State::CharacterString as u8 | Action::PushByteWithEscape as u8, + + PrivateControlSequence = + State::ControlSequence as u8 | Action::SetPrivate as u8, + + ControlSequencePushParameter = + State::ControlSequence as u8 | Action::PushParam as u8, + + ControlSequenceAddParameter = + State::ControlSequenceParameter as u8 | Action::AddParamValue as u8, + + ControlSequenceParameterIntermediate = + State::ControlSequenceIntermediate as u8 | Action::PushParamAndByte as u8, + + ControlSequencePushIntermediate = + State::ControlSequenceIntermediate as u8 | Action::PushByte as u8, + + FinishControlSequence = + State::Ground as u8 | Action::PushParamAndEndSequence as u8, +} + +#[repr(u8)] +#[derive(Copy, Clone)] +enum Action { + // Variant is never constructed, but is matched on + #[allow(dead_code)] + /// Return Continue + Continue, + + /// Return Char + Char, + + /// Set `start`, return Control + C01Control, + + /// Set `start`, return Continue + StartSequence, + + /// Set `end`, return Control + FinishSequence, + + /// Push `byte`, return Continue + PushByte, + + /// Push `Escape`, push `byte`, return Continue + PushByteWithEscape, + + /// Set `private`, return Continue + SetPrivate, + + /// Add to parameter value, return Continue + AddParamValue, + + /// Push `param`, return Continue + PushParam, + + /// Push `param`, push `byte`, return Continue + PushParamAndByte, + + /// Push `param`, set `end`, return Control + PushParamAndEndSequence, +} + +impl State { + /// Decomposes a state into base state and parser action. + fn decompose(self) -> (State, Action) { + use std::mem::transmute as cast; + + unsafe { + (cast(self as u8 & 0xF0), cast(self as u8 & 0x0F)) + } + } + + /// Poisons the state + fn poison(&mut self) { + *self = STATE_TABLE[*self as usize + 0xF]; + } +} + +impl Default for State { + fn default() -> State { + State::Ground + } +} + + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +/// A control sequence parameter. +pub enum Parameter { + /// A for the control sequence appropriate default value should be used. + Default, + /// The parameter has a value. + Value(u16) +} + +impl Parameter { + pub fn new(v: u16) -> Self { + Self::Value(v) + } + + /// Returns the value of the parameter, if present, otherwise returns the given default. + pub fn value_or(&self, or: u16) -> u16 { + match self { + Self::Default => or, + Self::Value(v) => *v, + } + } + + /// Parsing parameters requires an [`atoi`]-like loop. + /// + /// Parameter value overflow causes the sequence to be rejected. + /// + /// [`atoi`]: https://en.cppreference.com/w/c/string/byte/atoi + pub fn add(&mut self, x: u16) -> bool { + match self { + Self::Default => { + *self = Self::Value(x); + false + }, + + Self::Value(v) => { + let (v2, oflw) = v.overflowing_add(x); + *v = v2; + oflw + } + } + } +} + +impl Default for Parameter { + fn default() -> Self { + Self::Default + } +} + +#[derive(Clone, Eq, PartialEq, Debug, Default)] +pub struct ControlFunction { + /// The start of the control function. + /// + /// For C0 and C1 controls, which are only 1 byte, + /// this is the only necessary field. + start: u8, + /// Whether this control sequence has a private parameter string. + private: bool, + /// The parameters of the control sequence, if it is one. + params: Vec<Parameter>, + /// If this function is a control string, + /// this is the string's content. + /// + /// Otherwise, it's the intermediate bytes of the function. + /// For control sequences with private parameters, this contains the raw parameter string. + bytes: Vec<u8>, + /// The final byte of the control function. + /// + /// For C0 and C1 controls, as well as control strings, + /// this field is left unset. + end: u8, +} + +#[derive(Clone, Eq, PartialEq, Debug)] +pub enum TerminalInput<'a> { + Continue, + Char(char), + // If the UTF-8 decoder had to synchronize, two characters have to be inserted + SyncChar(char, char), + // FIXME: Passing this by reference saves on allocations, + // but currently requires that it is fully processed before parsing can continue. + // For performance, it may be better to pass a clone by value, and use a queue to avoid + // the input buffer getting clogged. Relevant for stuff that may take longer to evaluate, + // like SIXEL strings. + // Will require benchmarking though. + Control(&'a ControlFunction), + + SyncControl(char, &'a ControlFunction) +} + +#[derive(Clone, Debug, Default)] +pub struct TerminalInputParser { + /// The current parsing state. + state: State, + /// Container for parsed control function data. + ctl: ControlFunction, + /// Accumulator for current control sequence parameter. + pacc: Parameter, + /// UTF-8 character decoder. + utf8: utf8::UTF8Decoder +} + +impl TerminalInputParser { + pub fn new() -> Self { + Self::default() + } + + pub fn parse_byte(&mut self, byte: u8) -> TerminalInput { + if byte >= 0x80 { + if self.state != State::Ground { + self.state.poison(); + return TerminalInput::Continue; + } + + // UTF-8 here + match self.utf8.decode_byte(byte) { + utf8::DecodeState::Continue => TerminalInput::Continue, + utf8::DecodeState::Done(c) => TerminalInput::Char(c), + utf8::DecodeState::Error => TerminalInput::Char('\u{FFFD}'), + utf8::DecodeState::Rewind => { + // Recurse, but only once + let again = self.parse_byte(byte); + + match again { + TerminalInput::Continue => TerminalInput::Char('\u{FFFD}'), + TerminalInput::Char(c) => TerminalInput::SyncChar('\u{FFFD}', c), + TerminalInput::Control(ctl) => TerminalInput::SyncControl('\u{FFFD}', ctl), + // We can't hit UTF-8 Rewind from the base state, + // so we can never produce SyncChar or SyncControl here + _ => unsafe { std::hint::unreachable_unchecked() } + } + } + } + } else { + let class = CLASS_TABLE[byte as usize] as usize; + + let state = unsafe { + *STATE_TABLE.get_unchecked(self.state as usize + class) + }; + + let (base, action) = state.decompose(); + + self.state = base; + + match action { + Action::Continue => TerminalInput::Continue, + Action::Char => TerminalInput::Char(byte as char), + Action::C01Control => { + self.ctl.start = byte; + TerminalInput::Control(&self.ctl) + }, + + Action::StartSequence => { + self.ctl.start = byte; + self.ctl.params.clear(); + self.ctl.bytes.clear(); + TerminalInput::Continue + }, + + Action::FinishSequence => { + self.ctl.end = byte; + TerminalInput::Control(&self.ctl) + }, + + Action::PushByte => { + self.ctl.bytes.push(byte); + TerminalInput::Continue + }, + + Action::PushByteWithEscape => { + self.ctl.bytes.push(0x1B); + self.ctl.bytes.push(byte); + TerminalInput::Continue + }, + + Action::SetPrivate => { + self.ctl.private = true; + TerminalInput::Continue + }, + + Action::AddParamValue => { + let oflw = self.pacc.add(byte as u16 - 0x30); + + // You can theoretically do this if-less + // using something like state ^= (0x70 * oflw) + // It just turns the branch into a conditional move and a xor. + if oflw { + self.state = State::ControlSequenceError; + } + + TerminalInput::Continue + }, + + Action::PushParam => { + self.ctl.params.push(self.pacc); + self.pacc = Parameter::Default; + + TerminalInput::Continue + }, + + Action::PushParamAndByte => { + self.ctl.bytes.push(byte); + self.ctl.params.push(self.pacc); + self.pacc = Parameter::Default; + + TerminalInput::Continue + }, + + Action::PushParamAndEndSequence => { + self.ctl.params.push(self.pacc); + self.pacc = Parameter::Default; + self.ctl.end = byte; + TerminalInput::Control(&self.ctl) + } + } + } + } +} |