summaryrefslogtreecommitdiff
path: root/src/parsers/packed_binary_literal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parsers/packed_binary_literal.rs')
-rw-r--r--src/parsers/packed_binary_literal.rs80
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 }
+}