replace lalrpop message parser with ros_message
This commit is contained in:
		
							parent
							
								
									eef7484866
								
							
						
					
					
						commit
						5bff865da4
					
				@ -2,22 +2,19 @@
 | 
				
			|||||||
name = "rsbag"
 | 
					name = "rsbag"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
edition = "2018"
 | 
					edition = "2018"
 | 
				
			||||||
build = "build.rs"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
bytes = "1.1.0"
 | 
					bytes = "1.1.0"
 | 
				
			||||||
lalrpop-util = "0.19.6"
 | 
					 | 
				
			||||||
log = "0.4.14"
 | 
					log = "0.4.14"
 | 
				
			||||||
nom = "7.0.0"
 | 
					nom = "7.0.0"
 | 
				
			||||||
num_enum = "0.5.4"
 | 
					num_enum = "0.5.4"
 | 
				
			||||||
 | 
					regex = "1.5.4"
 | 
				
			||||||
 | 
					ros_message = "0.1.0"
 | 
				
			||||||
smallvec = "1.6.1"
 | 
					smallvec = "1.6.1"
 | 
				
			||||||
thiserror = "1.0.28"
 | 
					thiserror = "1.0.28"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dev-dependencies]
 | 
					[dev-dependencies]
 | 
				
			||||||
env_logger = "0.9.0"
 | 
					env_logger = "0.9.0"
 | 
				
			||||||
eyre = "0.6.5"
 | 
					eyre = "0.6.5"
 | 
				
			||||||
 | 
					 | 
				
			||||||
[build-dependencies]
 | 
					 | 
				
			||||||
lalrpop = "0.19.6"
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								build.rs
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								build.rs
									
									
									
									
									
								
							@ -1,6 +0,0 @@
 | 
				
			|||||||
fn main() {
 | 
					 | 
				
			||||||
    lalrpop::Configuration::new()
 | 
					 | 
				
			||||||
        .generate_in_source_tree()
 | 
					 | 
				
			||||||
        .process()
 | 
					 | 
				
			||||||
        .unwrap();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,8 +1,46 @@
 | 
				
			|||||||
use std::{env::args, fs::File};
 | 
					use std::{convert::TryFrom, env::args, fs::File};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use log::{error, info, trace};
 | 
					use log::{error, info, trace};
 | 
				
			||||||
use nom::Parser;
 | 
					use regex::Regex;
 | 
				
			||||||
use rsbag::{index::BagIndex, reader::IoReader};
 | 
					use ros_message::{MessagePath, Msg};
 | 
				
			||||||
 | 
					use rsbag::{
 | 
				
			||||||
 | 
					    index::{BagIndex, ConnInfo},
 | 
				
			||||||
 | 
					    reader::IoReader,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_msgdef(message_name: &str, msgdef: &str) -> rsbag::Result<Msg> {
 | 
				
			||||||
 | 
					    trace!("message definition: {}", msgdef);
 | 
				
			||||||
 | 
					    let path = MessagePath::try_from(message_name).map_err(rsbag::Error::other)?;
 | 
				
			||||||
 | 
					    let msgtype = Msg::new(path, msgdef).map_err(rsbag::Error::other)?;
 | 
				
			||||||
 | 
					    Ok(msgtype)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_message_definitions(conn: &ConnInfo) -> rsbag::Result<Vec<Msg>> {
 | 
				
			||||||
 | 
					    let msgdefs = conn.message_definition()?;
 | 
				
			||||||
 | 
					    let boundary_re = Regex::new(r"\r?\n==+\r?\nMSG: ([^\r\n]+)\r?\n").unwrap();
 | 
				
			||||||
 | 
					    let mut name = conn.datatype()?;
 | 
				
			||||||
 | 
					    let mut begin = 0usize;
 | 
				
			||||||
 | 
					    let mut msgs = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for cap in boundary_re.captures_iter(&msgdefs) {
 | 
				
			||||||
 | 
					        let boundary_range = cap.get(0).unwrap();
 | 
				
			||||||
 | 
					        let end = boundary_range.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let msgdef = &msgdefs[begin..end];
 | 
				
			||||||
 | 
					        let msgtype = parse_msgdef(&name, msgdef)?;
 | 
				
			||||||
 | 
					        msgs.push(msgtype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        name = cap[1].to_string();
 | 
				
			||||||
 | 
					        begin = boundary_range.end();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let msgdef = &msgdefs[begin..];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let msg = parse_msgdef(&name, msgdef)?;
 | 
				
			||||||
 | 
					    msgs.push(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(msgs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    env_logger::init();
 | 
					    env_logger::init();
 | 
				
			||||||
@ -20,15 +58,23 @@ fn main() {
 | 
				
			|||||||
    match BagIndex::read_all(&mut bag_reader) {
 | 
					    match BagIndex::read_all(&mut bag_reader) {
 | 
				
			||||||
        Ok(index) => {
 | 
					        Ok(index) => {
 | 
				
			||||||
            for conn in &index.connections {
 | 
					            for conn in &index.connections {
 | 
				
			||||||
                let msgdef = conn.message_definition().unwrap();
 | 
					                match parse_message_definitions(conn) {
 | 
				
			||||||
                trace!("message definition: {}", msgdef);
 | 
					                    Ok(msgs) => {
 | 
				
			||||||
                let parser = rsbag::message_definition::grammar::MessageDefinitionParser::new();
 | 
					                        for msg in &msgs {
 | 
				
			||||||
                match parser.parse(&msgdef) {
 | 
					                            info!(
 | 
				
			||||||
                    Ok(def) => info!("message definition parsed: {}", def),
 | 
					                                "message definition parsed: {:#?}",
 | 
				
			||||||
                    Err(err) => error!("message definition parse error: {}", err),
 | 
					                                msg.fields()
 | 
				
			||||||
 | 
					                                    .iter()
 | 
				
			||||||
 | 
					                                    .filter(|field| !field.is_constant())
 | 
				
			||||||
 | 
					                                    .map(ToString::to_string)
 | 
				
			||||||
 | 
					                                    .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    Err(err) => error!("could not parse message definition: {}", err),
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        }
 | 
				
			||||||
        Err(err) => error!("bag parse error: {}", err),
 | 
					        Err(err) => error!("bag parse error: {}", err),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -41,8 +41,8 @@ impl<'a> From<nom::Err<parse::Error<parse::Input<'a>>>> for Error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Error {
 | 
					impl Error {
 | 
				
			||||||
    pub fn other<S: Into<String>>(message: S) -> Self {
 | 
					    pub fn other<S: ToString>(message: S) -> Self {
 | 
				
			||||||
        Error::Other(message.into())
 | 
					        Error::Other(message.to_string())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,5 @@ mod error;
 | 
				
			|||||||
pub mod index;
 | 
					pub mod index;
 | 
				
			||||||
pub mod parse;
 | 
					pub mod parse;
 | 
				
			||||||
pub mod reader;
 | 
					pub mod reader;
 | 
				
			||||||
pub mod message_definition;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use error::{Error, Result};
 | 
					pub use error::{Error, Result};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,2 +0,0 @@
 | 
				
			|||||||
pub mod ast;
 | 
					 | 
				
			||||||
pub mod grammar;
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								src/message_definition/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/message_definition/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +0,0 @@
 | 
				
			|||||||
/grammar.rs
 | 
					 | 
				
			||||||
@ -1,140 +0,0 @@
 | 
				
			|||||||
use core::fmt::{self, Write};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub type SmallStr = String;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 | 
					 | 
				
			||||||
pub enum PrimitiveType {
 | 
					 | 
				
			||||||
    Bool,
 | 
					 | 
				
			||||||
    Int8,
 | 
					 | 
				
			||||||
    Uint8,
 | 
					 | 
				
			||||||
    Int16,
 | 
					 | 
				
			||||||
    Uint16,
 | 
					 | 
				
			||||||
    Int32,
 | 
					 | 
				
			||||||
    Uint32,
 | 
					 | 
				
			||||||
    Int64,
 | 
					 | 
				
			||||||
    Uint64,
 | 
					 | 
				
			||||||
    Float32,
 | 
					 | 
				
			||||||
    Float64,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl PrimitiveType {
 | 
					 | 
				
			||||||
    fn as_str(self) -> &'static str {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            PrimitiveType::Bool => "bool",
 | 
					 | 
				
			||||||
            PrimitiveType::Int8 => "int8_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Uint8 => "uint8_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Int16 => "int16_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Uint16 => "uint16_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Int32 => "int32_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Uint32 => "uint32_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Int64 => "int64_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Uint64 => "uint64_t",
 | 
					 | 
				
			||||||
            PrimitiveType::Float32 => "float32",
 | 
					 | 
				
			||||||
            PrimitiveType::Float64 => "float64",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn size(self) -> usize {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            PrimitiveType::Bool => 1,
 | 
					 | 
				
			||||||
            PrimitiveType::Int8 => 1,
 | 
					 | 
				
			||||||
            PrimitiveType::Uint8 => 1,
 | 
					 | 
				
			||||||
            PrimitiveType::Int16 => 2,
 | 
					 | 
				
			||||||
            PrimitiveType::Uint16 => 2,
 | 
					 | 
				
			||||||
            PrimitiveType::Int32 => 4,
 | 
					 | 
				
			||||||
            PrimitiveType::Uint32 => 4,
 | 
					 | 
				
			||||||
            PrimitiveType::Int64 => 8,
 | 
					 | 
				
			||||||
            PrimitiveType::Uint64 => 8,
 | 
					 | 
				
			||||||
            PrimitiveType::Float32 => 4,
 | 
					 | 
				
			||||||
            PrimitiveType::Float64 => 8,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for PrimitiveType {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        f.write_str(self.as_str())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug, PartialEq)]
 | 
					 | 
				
			||||||
pub struct ArrayType {
 | 
					 | 
				
			||||||
    pub element_type: Box<FieldType>,
 | 
					 | 
				
			||||||
    pub length: Option<usize>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ArrayType {
 | 
					 | 
				
			||||||
    pub fn new(element_type: FieldType, length: Option<usize>) -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            element_type: Box::new(element_type),
 | 
					 | 
				
			||||||
            length,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for ArrayType {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        self.element_type.fmt(f)?;
 | 
					 | 
				
			||||||
        f.write_char('[')?;
 | 
					 | 
				
			||||||
        if let Some(length) = self.length {
 | 
					 | 
				
			||||||
            length.fmt(f)?;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        f.write_char(']')
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug, PartialEq)]
 | 
					 | 
				
			||||||
pub enum FieldType {
 | 
					 | 
				
			||||||
    Primitive(PrimitiveType),
 | 
					 | 
				
			||||||
    String,
 | 
					 | 
				
			||||||
    Time,
 | 
					 | 
				
			||||||
    Duration,
 | 
					 | 
				
			||||||
    Header,
 | 
					 | 
				
			||||||
    Array(ArrayType),
 | 
					 | 
				
			||||||
    Other(SmallStr),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for FieldType {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            FieldType::Primitive(primitive) => primitive.fmt(f),
 | 
					 | 
				
			||||||
            FieldType::String => "string".fmt(f),
 | 
					 | 
				
			||||||
            FieldType::Time => "time".fmt(f),
 | 
					 | 
				
			||||||
            FieldType::Duration => "duration".fmt(f),
 | 
					 | 
				
			||||||
            FieldType::Header => "Header".fmt(f),
 | 
					 | 
				
			||||||
            FieldType::Array(array) => array.fmt(f),
 | 
					 | 
				
			||||||
            FieldType::Other(other) => other.fmt(f),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug, PartialEq)]
 | 
					 | 
				
			||||||
pub struct MessageField {
 | 
					 | 
				
			||||||
    pub name: SmallStr,
 | 
					 | 
				
			||||||
    pub typ: FieldType,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for MessageField {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        write!(f, "{} {}", &self.typ, &self.name)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Clone, Debug, PartialEq)]
 | 
					 | 
				
			||||||
pub struct MessageDefinition {
 | 
					 | 
				
			||||||
    pub fields: Vec<MessageField>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl fmt::Display for MessageDefinition {
 | 
					 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
					 | 
				
			||||||
        for field in &self.fields {
 | 
					 | 
				
			||||||
            writeln!(f, "{}", field)?;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Ok(())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct MessageDefinitions {
 | 
					 | 
				
			||||||
    pub primary: MessageDefinition,
 | 
					 | 
				
			||||||
    pub dependencies: Vec<(String, MessageDefinition)>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,90 +0,0 @@
 | 
				
			|||||||
use super::ast::{
 | 
					 | 
				
			||||||
	PrimitiveType, ArrayType, FieldType, MessageField, MessageDefinition, MessageDefinitions
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
use std::str::FromStr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
grammar;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
match {
 | 
					 | 
				
			||||||
	"bool",
 | 
					 | 
				
			||||||
	"int8",
 | 
					 | 
				
			||||||
	"uint8",
 | 
					 | 
				
			||||||
	"int16",
 | 
					 | 
				
			||||||
	"uint16",
 | 
					 | 
				
			||||||
	"int32",
 | 
					 | 
				
			||||||
	"uint32",
 | 
					 | 
				
			||||||
	"int64",
 | 
					 | 
				
			||||||
	"uint64",
 | 
					 | 
				
			||||||
	"float32",
 | 
					 | 
				
			||||||
	"float64",
 | 
					 | 
				
			||||||
	"string",
 | 
					 | 
				
			||||||
	"time",
 | 
					 | 
				
			||||||
	"duration",
 | 
					 | 
				
			||||||
	"Header",
 | 
					 | 
				
			||||||
	"[",
 | 
					 | 
				
			||||||
	"]",
 | 
					 | 
				
			||||||
	r"==+\r?\nMSG: " => "MESSAGE_BOUNDARY",
 | 
					 | 
				
			||||||
	r"[0-9]+" => "LENGTH",
 | 
					 | 
				
			||||||
    r"[\t ]*" => { },
 | 
					 | 
				
			||||||
    r"#[^\n\r]*" => { }, // Skip `# comments`
 | 
					 | 
				
			||||||
} else {
 | 
					 | 
				
			||||||
	r"[a-zA-Z][a-zA-Z0-9_]*" => "IDENT",
 | 
					 | 
				
			||||||
} else {
 | 
					 | 
				
			||||||
	r"[a-zA-Z][a-zA-Z0-9_]*(/[a-zA-Z][a-zA-Z0-9_]*)*" => "TYPENAME",
 | 
					 | 
				
			||||||
	r"\r?\n" => "CRLF",
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PrimitiveType: PrimitiveType = {
 | 
					 | 
				
			||||||
	"bool" => PrimitiveType::Bool,
 | 
					 | 
				
			||||||
	"int8" => PrimitiveType::Int8,
 | 
					 | 
				
			||||||
	"uint8" => PrimitiveType::Uint8,
 | 
					 | 
				
			||||||
	"int16" => PrimitiveType::Int16,
 | 
					 | 
				
			||||||
	"uint16" => PrimitiveType::Uint16,
 | 
					 | 
				
			||||||
	"int32" => PrimitiveType::Int32,
 | 
					 | 
				
			||||||
	"uint32" => PrimitiveType::Uint32,
 | 
					 | 
				
			||||||
	"int64" => PrimitiveType::Int64,
 | 
					 | 
				
			||||||
	"uint64" => PrimitiveType::Uint64,
 | 
					 | 
				
			||||||
	"float32" => PrimitiveType::Float32,
 | 
					 | 
				
			||||||
	"float64" => PrimitiveType::Float64,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ArrayLength: Option<usize> = {
 | 
					 | 
				
			||||||
	"[" <"LENGTH"> "]" => Some(usize::from_str(<>).unwrap()),
 | 
					 | 
				
			||||||
	"[" "]" => None,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ArrayType: ArrayType =
 | 
					 | 
				
			||||||
	FieldType ArrayLength => ArrayType::new(<>);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Ident: String = "IDENT" => <>.to_string();
 | 
					 | 
				
			||||||
TypeName: String = {
 | 
					 | 
				
			||||||
	"TYPENAME" => <>.to_string(),
 | 
					 | 
				
			||||||
	"IDENT" => <>.to_string(),
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FieldType: FieldType = {
 | 
					 | 
				
			||||||
	PrimitiveType => FieldType::Primitive(<>),
 | 
					 | 
				
			||||||
	"string" => FieldType::String,
 | 
					 | 
				
			||||||
	"time" => FieldType::Time,
 | 
					 | 
				
			||||||
	"duration" => FieldType::Duration,
 | 
					 | 
				
			||||||
	"Header" => FieldType::Header,
 | 
					 | 
				
			||||||
	ArrayType => FieldType::Array(<>),
 | 
					 | 
				
			||||||
	TypeName => FieldType::Other(<>),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MessageField: MessageField = {
 | 
					 | 
				
			||||||
	<typ:FieldType> <name:Ident> => MessageField { <> }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MessageFields: Vec<MessageField> =
 | 
					 | 
				
			||||||
	<(<MessageField> "CRLF"+)*> => <>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub MessageDefinition: MessageDefinition =
 | 
					 | 
				
			||||||
	"CRLF"* <fields:MessageFields> => MessageDefinition { fields };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
NamedMessageDefinition: (String, MessageDefinition) =
 | 
					 | 
				
			||||||
	"MESSAGE_BOUNDARY" <TypeName> "CRLF" <MessageDefinition> => (<>);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub MessageDefinitions: MessageDefinitions =
 | 
					 | 
				
			||||||
	<primary:MessageDefinition> <dependencies:NamedMessageDefinition*>
 | 
					 | 
				
			||||||
		=> MessageDefinitions { <> };
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user