Skip to content
72 changes: 26 additions & 46 deletions src/ast/attribute_definition.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,43 @@
use can_dbc_pest::{Pair, Pairs, Rule};
use can_dbc_pest::{Pair, Rule};

use crate::parser::{validated_inner, DbcError};
use crate::DbcResult;
use crate::parser::{
expect_empty, inner_str, next, next_optional_rule, next_rule, validated_inner, DbcError,
};
use crate::AttributeValueType;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AttributeDefinition {
// TODO add properties
Message(String),
// TODO add properties
Node(String),
// TODO add properties
Signal(String),
EnvironmentVariable(String),
// TODO figure out name
Plain(String),
Message(String, AttributeValueType),
Node(String, AttributeValueType),
Signal(String, AttributeValueType),
EnvironmentVariable(String, AttributeValueType),
Plain(String, AttributeValueType),
}

impl TryFrom<Pair<'_, Rule>> for AttributeDefinition {
type Error = DbcError;

/// Parse attribute definition: `BA_DEF_ [object_type] attribute_name attribute_type [min max];`
fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let inner_pairs = validated_inner(value, Rule::attr_def)?;
let (definition_string, object_type) = parse_obj_type_vals(inner_pairs)?;
let mut pairs = validated_inner(value, Rule::attr_def)?;

Ok(match object_type {
"SG_" => Self::Signal(definition_string),
"BO_" => Self::Message(definition_string),
"BU_" => Self::Node(definition_string),
"EV_" => Self::EnvironmentVariable(definition_string),
_ => Self::Plain(definition_string),
})
}
}
let object_type = if let Some(v) = next_optional_rule(&mut pairs, Rule::object_type) {
v.as_str().to_string()
} else {
String::new()
};

pub(crate) fn parse_obj_type_vals(inner_pairs: Pairs<'_, Rule>) -> DbcResult<(String, &str)> {
let mut definition_string = String::new();
let mut object_type = "";
let name = inner_str(next_rule(&mut pairs, Rule::attribute_name)?);
let value = next(&mut pairs)?.try_into()?;
expect_empty(&pairs)?;

// Process all pairs
for pair in inner_pairs {
match pair.as_rule() {
Rule::object_type => {
object_type = pair.as_str();
}
Rule::attribute_name
| Rule::attribute_type_int
| Rule::attribute_type_hex
| Rule::attribute_type_float
| Rule::attribute_type_string
| Rule::attribute_type_enum => {
if !definition_string.is_empty() {
definition_string.push(' ');
}
definition_string.push_str(pair.as_str());
}
v => return Err(DbcError::UnknownRule(v)),
}
Ok(match object_type.as_str() {
"SG_" => Self::Signal(name, value),
"BO_" => Self::Message(name, value),
"BU_" => Self::Node(name, value),
"EV_" => Self::EnvironmentVariable(name, value),
_ => Self::Plain(name, value),
})
}
Ok((definition_string, object_type))
}
2 changes: 2 additions & 0 deletions src/ast/attribute_definition_for_relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use can_dbc_pest::{Pair, Rule};

use crate::parser::{inner_str, validated_inner, DbcError};

// FIXME: consider using AttributeDefinition instead

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeDefinitionForRelation {
Expand Down
17 changes: 7 additions & 10 deletions src/ast/attribute_value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use can_dbc_pest::{Pair, Rule};

use crate::parser::{inner_str, parse_float, parse_int, parse_uint, DbcError};
use crate::parser::{inner_str, DbcError};
use crate::NumericValue;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand All @@ -17,15 +18,11 @@ impl TryFrom<Pair<'_, Rule>> for AttributeValue {
fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
match value.as_rule() {
Rule::quoted_str => Ok(Self::String(inner_str(value))),
Rule::number => {
if let Ok(result) = parse_uint(&value) {
Ok(Self::Uint(result))
} else if let Ok(result) = parse_int(&value) {
Ok(Self::Int(result))
} else {
Ok(Self::Double(parse_float(&value)?))
}
}
Rule::number => Ok(match value.as_str().parse()? {
NumericValue::Uint(u) => Self::Uint(u),
NumericValue::Int(i) => Self::Int(i),
NumericValue::Double(d) => Self::Double(d),
}),
_ => Err(Self::Error::ExpectedStrNumber(value.as_rule())),
}
}
Expand Down
49 changes: 45 additions & 4 deletions src/ast/attribute_value_type.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,51 @@
// FIXME: not used!
use can_dbc_pest::{Pair, Rule};

use crate::parser::{expect_empty, inner_str, next_rule};
use crate::{DbcError, DbcResult, NumericValue};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AttributeValueType {
Int(i64, i64),
Hex(i64, i64),
Float(f64, f64),
Int(NumericValue, NumericValue),
Hex(NumericValue, NumericValue),
Float(NumericValue, NumericValue),
String,
Enum(Vec<String>),
}

impl TryFrom<Pair<'_, Rule>> for AttributeValueType {
type Error = DbcError;

fn try_from(pair: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
Ok(match rule {
Rule::attribute_type_int | Rule::attribute_type_hex | Rule::attribute_type_float => {
let mut pairs = pair.into_inner();
let min = next_rule(&mut pairs, Rule::minimum)?.as_str().parse()?;
let max = next_rule(&mut pairs, Rule::maximum)?.as_str().parse()?;
expect_empty(&pairs)?;
match rule {
Rule::attribute_type_int => AttributeValueType::Int(min, max),
Rule::attribute_type_hex => AttributeValueType::Hex(min, max),
Rule::attribute_type_float => AttributeValueType::Float(min, max),
_ => unreachable!(),
}
}
Rule::attribute_type_string => AttributeValueType::String,
Rule::attribute_type_enum => {
let enum_values: DbcResult<_> = pair
.into_inner()
.map(|pair| {
if pair.as_rule() == Rule::quoted_str {
Ok(inner_str(pair))
} else {
Err(DbcError::ExpectedRule(Rule::quoted_str, pair.as_rule()))
}
})
.collect();
AttributeValueType::Enum(enum_values?)
}
v => return Err(DbcError::UnknownRule(v)),
})
}
}
3 changes: 2 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Re-export all types from individual files
mod access_node;
mod access_type;
mod attr_default;
Expand All @@ -25,6 +24,7 @@ mod message_id;
mod message_transmitter;
mod multiplex_indicator;
mod node;
mod numeric_value;
mod signal;
mod signal_attribute_value;
mod signal_extended_value_type;
Expand Down Expand Up @@ -67,6 +67,7 @@ pub use message_id::*;
pub use message_transmitter::*;
pub use multiplex_indicator::*;
pub use node::*;
pub use numeric_value::*;
pub use signal::*;
pub use signal_attribute_value::*;
pub use signal_extended_value_type::*;
Expand Down
27 changes: 27 additions & 0 deletions src/ast/numeric_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::str::FromStr;

use crate::DbcError;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NumericValue {
Uint(u64),
Int(i64),
Double(f64),
}

impl FromStr for NumericValue {
type Err = DbcError;

fn from_str(value: &str) -> Result<Self, Self::Err> {
if let Ok(v) = value.parse::<u64>() {
Ok(NumericValue::Uint(v))
} else if let Ok(v) = value.parse::<i64>() {
Ok(NumericValue::Int(v))
} else if let Ok(v) = value.parse::<f64>() {
Ok(NumericValue::Double(v))
} else {
Err(DbcError::InvalidNumericValue(value.to_string()))
}
}
}
2 changes: 2 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub enum DbcError {
UnknownMultiplexIndicator(String),
#[error("Unknown rule: {0:?}")]
UnknownRule(Rule),
#[error("Invalid numeric value: '{0}'")]
InvalidNumericValue(String),
}

impl From<PestError<Rule>> for DbcError {
Expand Down
13 changes: 10 additions & 3 deletions src/parser_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,8 @@ BA_DEF_ BO_ "GenMsgSendType" STRING ;
"#;
let pair = parse(def.trim_start(), Rule::attr_def).unwrap();
let val = test_into::<AttributeDefinition>(&pair);
let exp = AttributeDefinition::Message(r#""GenMsgSendType" STRING"#.to_string());
let exp =
AttributeDefinition::Message("GenMsgSendType".to_string(), AttributeValueType::String);
assert_eq!(val, exp);
}

Expand All @@ -636,7 +637,10 @@ BA_DEF_ BU_ "BuDef1BO" INT 0 1000000;
"#;
let pair = parse(def.trim_start(), Rule::attr_def).unwrap();
let val = test_into::<AttributeDefinition>(&pair);
let exp = AttributeDefinition::Node(r#""BuDef1BO" INT 0 1000000"#.to_string());
let exp = AttributeDefinition::Node(
"BuDef1BO".to_string(),
AttributeValueType::Int(NumericValue::Uint(0), NumericValue::Uint(1_000_000)),
);
assert_eq!(val, exp);
}

Expand All @@ -647,7 +651,10 @@ BA_DEF_ SG_ "SgDef1BO" INT 0 1000000;
"#;
let pair = parse(def.trim_start(), Rule::attr_def).unwrap();
let val = test_into::<AttributeDefinition>(&pair);
let exp = AttributeDefinition::Signal(r#""SgDef1BO" INT 0 1000000"#.to_string());
let exp = AttributeDefinition::Signal(
"SgDef1BO".to_string(),
AttributeValueType::Int(NumericValue::Uint(0), NumericValue::Uint(1_000_000)),
);
assert_eq!(val, exp);
}

Expand Down
7 changes: 5 additions & 2 deletions tests/snapshots/dbc-cantools/BU_BO_REL_.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: tests/snapshots.rs
assertion_line: 152
---
version: ""
new_symbols:
Expand Down Expand Up @@ -57,7 +56,11 @@ messages:
receivers:
- Vector__XXX
attribute_definitions:
- Message: "\"GenMsgCycleTime\" INT 0 65535"
- Message:
- GenMsgCycleTime
- Int:
- Uint: 0
- Uint: 65535
relation_attribute_definitions:
- name: MsgProject
value_spec: "\"MsgProject\" ENUM \"A\",\"B\",\"C\""
Expand Down
7 changes: 5 additions & 2 deletions tests/snapshots/dbc-cantools/BU_BO_REL_Message.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: tests/snapshots.rs
assertion_line: 152
---
version: ""
new_symbols:
Expand Down Expand Up @@ -58,7 +57,11 @@ messages:
receivers:
- ECU2
attribute_definitions:
- Message: "\"GenMsgCycleTime\" INT 0 65535"
- Message:
- GenMsgCycleTime
- Int:
- Uint: 0
- Uint: 65535
relation_attribute_definitions:
- name: MsgProject
value_spec: "\"MsgProject\" ENUM \"A\",\"B\",\"C\""
Expand Down
30 changes: 27 additions & 3 deletions tests/snapshots/dbc-cantools/abs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1682,9 +1682,33 @@ comments:
name: P_RA
comment: Brake pressure on the rear axle.
attribute_definitions:
- Message: "\"GenMsgCycleTime\" INT 1 3000"
- Message: "\"VFrameFormat\" ENUM \"StandardCAN\",\"ExtendedCAN\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"reserved\",\"StandardCAN_FD\",\"ExtendedCAN_FD\""
- Plain: "\"BusType\" STRING"
- Message:
- GenMsgCycleTime
- Int:
- Uint: 1
- Uint: 3000
- Message:
- VFrameFormat
- Enum:
- StandardCAN
- ExtendedCAN
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- reserved
- StandardCAN_FD
- ExtendedCAN_FD
- Plain:
- BusType
- String
attribute_defaults:
- name: GenMsgCycleTime
value:
Expand Down
10 changes: 8 additions & 2 deletions tests/snapshots/dbc-cantools/attribute_Event.snap
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ messages:
receivers:
- Vector__XXX
attribute_definitions:
- Message: "\"GenMsgSendType\" STRING"
- Message: "\"GenMsgCycleTime\" INT 0 100"
- Message:
- GenMsgSendType
- String
- Message:
- GenMsgCycleTime
- Int:
- Uint: 0
- Uint: 100
attribute_values_message:
- name: GenMsgSendType
message_id:
Expand Down
Loading
Loading