use crate::*; pub fn parse_packed_binary_literal(string: &str, parent: &Tokeniser) -> PackedBinaryLiteral { use PackedBinaryLiteralParseError as ParseError; use PackedBinaryLiteralParseErrorVariant as ParseErrorVar; let mut value = 0; let mut bits = 0; let mut name = '\0'; let mut fields: Vec = Vec::new(); let mut errors: Vec = Vec::new(); macro_rules! push_field { ($source:expr) => { if fields.iter().any(|f| f.name == name) { let variant = ParseErrorVar::DuplicateFieldName(name); errors.push(ParseError { source: $source, variant }); } else { fields.push(BitField { name, source: $source, bits, shift: 0 }); } }; } let mut t = Tokeniser::new_child(string, parent); t.position.to_next_char(); // skip opening hash character while let Some(c) = t.eat_char() { // Ignore underscores. if c == '_' { t.prev_position = t.prev_prev_position; continue; } // Add a bit to the value; value <<= 1; for field in &mut fields { field.shift += 1; } // Extend the current field. if c == name { bits += 1; continue; } // Commit the current field. if bits > 0 { push_field!(t.mark_prev_end_position()); bits = 0; name = '\0'; } // Parse bit literals. if c == '0' { continue; } if c == '1' { value |= 1; continue; } t.mark_prev_start_position(); if c.is_alphabetic() { name = c; bits = 1; continue; } else { let source = t.mark_end_position(); errors.push(ParseError { source, variant: ParseErrorVar::InvalidCharacter(c) }); } } // Commit the final field. if bits > 0 { push_field!(t.mark_end_position()); } PackedBinaryLiteral { value, fields, errors } }