///|
fn find_message_index(messages : Array[DbcMessage], id : Int) -> Int {
for index, message in messages {
if message.id() == id {
return index
}
}
-1
}
///|
fn find_signal_index(signals : Array[DbcSignal], name : String) -> Int {
for index, signal in signals {
if signal.name() == name {
return index
}
}
-1
}
///|
fn parse_message_comment(
line : String,
number : Int,
messages : Array[DbcMessage],
) -> Result[Unit, DbcError] {
let cursor = TextCursor::new(line, number)
ignore(cursor.consume_text("CM_"))
cursor.skip_spaces()
if !cursor.consume_text("BO_") {
return Err(
cursor_error(
cursor,
UnsupportedConstruct,
"only BO_ and SG_ comments are supported",
),
)
}
let id = match cursor.integer() {
Ok(value) => value
Err(error) => return Err(error)
}
let comment = match cursor.quoted() {
Ok(value) => value
Err(error) => return Err(error)
}
match cursor.finish(semicolon=true) {
Err(error) => return Err(error)
Ok(_) => ()
}
let index = find_message_index(messages, id)
if index < 0 {
return Err(
DbcError::new(
UnknownMessage,
"comment references an unknown message",
number,
1,
context=line,
),
)
}
messages[index] = messages[index].with_comment(comment)
Ok(())
}
///|
fn parse_signal_comment(
line : String,
number : Int,
messages : Array[DbcMessage],
) -> Result[Unit, DbcError] {
let cursor = TextCursor::new(line, number)
ignore(cursor.consume_text("CM_"))
cursor.skip_spaces()
if !cursor.consume_text("SG_") {
return Err(
cursor_error(
cursor,
UnsupportedConstruct,
"only BO_ and SG_ comments are supported",
),
)
}
let id = match cursor.integer() {
Ok(value) => value
Err(error) => return Err(error)
}
let name = match cursor.identifier() {
Ok(value) => value
Err(error) => return Err(error)
}
let comment = match cursor.quoted() {
Ok(value) => value
Err(error) => return Err(error)
}
match cursor.finish(semicolon=true) {
Err(error) => return Err(error)
Ok(_) => ()
}
let message_index = find_message_index(messages, id)
if message_index < 0 {
return Err(
DbcError::new(
UnknownMessage,
"comment references an unknown message",
number,
1,
context=line,
),
)
}
let message = messages[message_index]
let signals = message.signals()
let signal_index = find_signal_index(signals, name)
if signal_index < 0 {
return Err(
DbcError::new(
UnknownSignal,
"comment references an unknown signal",
number,
1,
context=line,
),
)
}
signals[signal_index] = signals[signal_index].with_comment(comment)
messages[message_index] = message.with_signals(signals)
Ok(())
}
///|
fn parse_comment_annotation(
line : String,
number : Int,
messages : Array[DbcMessage],
) -> Result[Bool, DbcError] {
let cursor = TextCursor::new(line, number)
ignore(cursor.consume_text("CM_"))
cursor.skip_spaces()
if cursor.remaining().has_prefix("BO_") {
match parse_message_comment(line, number, messages) {
Ok(_) => Ok(true)
Err(error) => Err(error)
}
} else if cursor.remaining().has_prefix("SG_") {
match parse_signal_comment(line, number, messages) {
Ok(_) => Ok(true)
Err(error) => Err(error)
}
} else {
Ok(false)
}
}
///|
fn contains_raw_value(values : Array[DbcValueDescription], raw : Int) -> Bool {
for value in values {
if value.raw() == raw {
return true
}
}
false
}
///|
fn parse_value_annotation(
line : String,
number : Int,
messages : Array[DbcMessage],
) -> Result[Unit, DbcError] {
let cursor = TextCursor::new(line, number)
ignore(cursor.consume_text("VAL_"))
let id = match cursor.integer() {
Ok(value) => value
Err(error) => return Err(error)
}
let name = match cursor.identifier() {
Ok(value) => value
Err(error) => return Err(error)
}
let values : Array[DbcValueDescription] = []
cursor.skip_spaces()
while !cursor.at_end() && cursor.peek() != 59 {
let raw = match cursor.integer() {
Ok(value) => value
Err(error) => return Err(error)
}
let label = match cursor.quoted() {
Ok(value) => value
Err(error) => return Err(error)
}
if contains_raw_value(values, raw) {
return Err(
DbcError::new(
InvalidValueTable,
"value table repeats a raw value",
number,
1,
context=line,
),
)
}
values.push(DbcValueDescription::new(raw, label))
cursor.skip_spaces()
}
if values.is_empty() {
return Err(
DbcError::new(
InvalidValueTable,
"value table must contain at least one entry",
number,
1,
context=line,
),
)
}
match cursor.finish(semicolon=true) {
Err(error) => return Err(error)
Ok(_) => ()
}
let message_index = find_message_index(messages, id)
if message_index < 0 {
return Err(
DbcError::new(
UnknownMessage,
"value table references an unknown message",
number,
1,
context=line,
),
)
}
let message = messages[message_index]
let signals = message.signals()
let signal_index = find_signal_index(signals, name)
if signal_index < 0 {
return Err(
DbcError::new(
UnknownSignal,
"value table references an unknown signal",
number,
1,
context=line,
),
)
}
signals[signal_index] = signals[signal_index].with_values(values)
messages[message_index] = message.with_signals(signals)
Ok(())
}