replace lalrpop message parser with ros_message
This commit is contained in:
parent
eef7484866
commit
5bff865da4
@ -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"
|
||||
|
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 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),
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,5 @@ mod error;
|
||||
pub mod index;
|
||||
pub mod parse;
|
||||
pub mod reader;
|
||||
pub mod message_definition;
|
||||
|
||||
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