replace lalrpop message parser with ros_message

This commit is contained in:
Alex Mikhalev 2021-11-18 15:56:02 -08:00
parent eef7484866
commit 5bff865da4
9 changed files with 60 additions and 257 deletions

View File

@ -2,22 +2,19 @@
name = "rsbag"
version = "0.1.0"
edition = "2018"
build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bytes = "1.1.0"
lalrpop-util = "0.19.6"
log = "0.4.14"
nom = "7.0.0"
num_enum = "0.5.4"
regex = "1.5.4"
ros_message = "0.1.0"
smallvec = "1.6.1"
thiserror = "1.0.28"
[dev-dependencies]
env_logger = "0.9.0"
eyre = "0.6.5"
[build-dependencies]
lalrpop = "0.19.6"

View File

@ -1,6 +0,0 @@
fn main() {
lalrpop::Configuration::new()
.generate_in_source_tree()
.process()
.unwrap();
}

View File

@ -1,8 +1,46 @@
use std::{env::args, fs::File};
use std::{convert::TryFrom, env::args, fs::File};
use log::{error, info, trace};
use nom::Parser;
use rsbag::{index::BagIndex, reader::IoReader};
use regex::Regex;
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() {
env_logger::init();
@ -20,15 +58,23 @@ fn main() {
match BagIndex::read_all(&mut bag_reader) {
Ok(index) => {
for conn in &index.connections {
let msgdef = conn.message_definition().unwrap();
trace!("message definition: {}", msgdef);
let parser = rsbag::message_definition::grammar::MessageDefinitionParser::new();
match parser.parse(&msgdef) {
Ok(def) => info!("message definition parsed: {}", def),
Err(err) => error!("message definition parse error: {}", err),
match parse_message_definitions(conn) {
Ok(msgs) => {
for msg in &msgs {
info!(
"message definition parsed: {:#?}",
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),
}
}

View File

@ -41,8 +41,8 @@ impl<'a> From<nom::Err<parse::Error<parse::Input<'a>>>> for Error {
}
impl Error {
pub fn other<S: Into<String>>(message: S) -> Self {
Error::Other(message.into())
pub fn other<S: ToString>(message: S) -> Self {
Error::Other(message.to_string())
}
}

View File

@ -2,6 +2,5 @@ mod error;
pub mod index;
pub mod parse;
pub mod reader;
pub mod message_definition;
pub use error::{Error, Result};

View File

@ -1,2 +0,0 @@
pub mod ast;
pub mod grammar;

View File

@ -1 +0,0 @@
/grammar.rs

View File

@ -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)>,
}

View File

@ -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 { <> };