From 2b4e522b12a7eb87e91cd1cdc56064ee429a5212 Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Tue, 11 Feb 2025 14:00:20 +1300 Subject: Initial commit --- src/parsers/packed_binary_literal.rs | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/parsers/packed_binary_literal.rs (limited to 'src/parsers/packed_binary_literal.rs') diff --git a/src/parsers/packed_binary_literal.rs b/src/parsers/packed_binary_literal.rs new file mode 100644 index 0000000..9704fc4 --- /dev/null +++ b/src/parsers/packed_binary_literal.rs @@ -0,0 +1,80 @@ +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 } +} -- cgit v1.2.3-70-g09d2