diff options
Diffstat (limited to 'src/parsers/packed_binary_literal.rs')
-rw-r--r-- | src/parsers/packed_binary_literal.rs | 80 |
1 files changed, 80 insertions, 0 deletions
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<BitField> = Vec::new(); + let mut errors: Vec<ParseError> = 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 } +} |