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