Using pest to Parse ROS Message Definitions
This is a continuation of the previous post using PEG.js to parse ROS message definitions. However, it is alway better if we can use Rust :)
Code
The code is hosted at https://github.com/CoreRC/rcgenmsg. For now it's only a parser adapted from the official pest documentation. The parser definition is listed below:
// ROS Message Definition Parser
// ==========================
file = {
(result)*
}
result = _{
(" " | "\t")* ~ (comment | definition)? ~ sp ~ comment? ~ linebreak+
}
sp = _{
(" " | "\t")*
}
linebreak = _{
"\n" | "\r"
}
types = {
("bool" | "uint8" | "float32" | "string" | "Header" | !("\n" | "\r" | "\t")+)
}
array = {
types ~ ("[]")
}
itype = {
array | types
}
identifier = {
('a'..'z' | 'A'..'Z' | "_")+
}
value = {
('a'..'z' | 'A'..'Z' | '0'..'9')+
}
constant = {
itype ~ sp ~ identifier ~ sp ~ "=" ~ sp ~ value
}
variable = {
itype ~ sp ~ identifier ~ sp ~ !("=")
}
definition = {
(variable | constant)
}
nonl = _{ !linebreak ~ any }
comment = { "#" ~ nonl* }
Test
We tested it with the following ROS msg definition file with constants, variables, arrays and inline comments:
# Constants are chosen to match the enums in the linux kernel
# defined in include/linux/power_supply.h as of version 3.7
# The one difference is for style reasons the constants are
# all uppercase not mixed case.
# Power supply status constants
uint8 POWER_SUPPLY_STATUS_UNKNOWN = 0
uint8 POWER_SUPPLY_STATUS_CHARGING = 1
uint8 POWER_SUPPLY_STATUS_DISCHARGING = 2
uint8 POWER_SUPPLY_STATUS_NOT_CHARGING = 3
uint8 POWER_SUPPLY_STATUS_FULL = 4
# Power supply health constants
uint8 POWER_SUPPLY_HEALTH_UNKNOWN = 0
uint8 POWER_SUPPLY_HEALTH_GOOD = 1
uint8 POWER_SUPPLY_HEALTH_OVERHEAT = 2 # test
uint8 POWER_SUPPLY_HEALTH_DEAD = 3
uint8 POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4
uint8 POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5
uint8 POWER_SUPPLY_HEALTH_COLD = 6
uint8 POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7
uint8 POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8
# Power supply technology (chemistry) constants
uint8 POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0
uint8 POWER_SUPPLY_TECHNOLOGY_NIMH = 1
uint8 POWER_SUPPLY_TECHNOLOGY_LION = 2
uint8 POWER_SUPPLY_TECHNOLOGY_LIPO = 3
uint8 POWER_SUPPLY_TECHNOLOGY_LIFE = 4
uint8 POWER_SUPPLY_TECHNOLOGY_NICD = 5
uint8 POWER_SUPPLY_TECHNOLOGY_LIMN = 6
Header header
float32 voltage # Voltage in Volts (Mandatory)
float32 current # Negative when discharging (A) (If unmeasured NaN)
float32 charge # Current charge in Ah (If unmeasured NaN)
float32 capacity # Capacity in Ah (last full capacity) (If unmeasured NaN)
float32 design_capacity # Capacity in Ah (design capacity) (If unmeasured NaN)
float32 percentage # Charge percentage on 0 to 1 range (If unmeasured NaN)
uint8 power_supply_status # The charging status as reported. Values defined above
uint8 power_supply_health # The battery health metric. Values defined above
uint8 power_supply_technology # The battery chemistry. Values defined above
bool present # True if the battery is present
float32[] cell_voltage # An array of individual cell voltages for each cell in the pack
# If individual voltages unknown but number of cells known set each to NaN
string location # The location into which the battery is inserted. (slot number or plug)
string serial_number # The best approximation of the battery serial number
And the result is here:
Processing: hello.txt
LINE: # Constants are chosen to match the enums in the linux kernel
LINE: # defined in include/linux/power_supply.h as of version 3.7
LINE: # The one difference is for style reasons the constants are
LINE: # all uppercase not mixed case.
LINE: # Power supply status constants
LINE: uint8 POWER_SUPPLY_STATUS_UNKNOWN = 0
PART itype: uint8
PART identifier: POWER_SUPPLY_STATUS_UNKNOWN
PART value: 0
LINE: uint8 POWER_SUPPLY_STATUS_CHARGING = 1
PART itype: uint8
PART identifier: POWER_SUPPLY_STATUS_CHARGING
PART value: 1
LINE: uint8 POWER_SUPPLY_STATUS_DISCHARGING = 2
PART itype: uint8
PART identifier: POWER_SUPPLY_STATUS_DISCHARGING
PART value: 2
LINE: uint8 POWER_SUPPLY_STATUS_NOT_CHARGING = 3
PART itype: uint8
PART identifier: POWER_SUPPLY_STATUS_NOT_CHARGING
PART value: 3
LINE: uint8 POWER_SUPPLY_STATUS_FULL = 4
PART itype: uint8
PART identifier: POWER_SUPPLY_STATUS_FULL
PART value: 4
LINE: # Power supply health constants
LINE: uint8 POWER_SUPPLY_HEALTH_UNKNOWN = 0
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_UNKNOWN
PART value: 0
LINE: uint8 POWER_SUPPLY_HEALTH_GOOD = 1
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_GOOD
PART value: 1
LINE: uint8 POWER_SUPPLY_HEALTH_OVERHEAT = 2
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_OVERHEAT
PART value: 2
LINE: # test
LINE: uint8 POWER_SUPPLY_HEALTH_DEAD = 3
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_DEAD
PART value: 3
LINE: uint8 POWER_SUPPLY_HEALTH_OVERVOLTAGE = 4
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_OVERVOLTAGE
PART value: 4
LINE: uint8 POWER_SUPPLY_HEALTH_UNSPEC_FAILURE = 5
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
PART value: 5
LINE: uint8 POWER_SUPPLY_HEALTH_COLD = 6
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_COLD
PART value: 6
LINE: uint8 POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE = 7
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE
PART value: 7
LINE: uint8 POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE = 8
PART itype: uint8
PART identifier: POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE
PART value: 8
LINE: # Power supply technology (chemistry) constants
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_UNKNOWN
PART value: 0
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_NIMH = 1
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_NIMH
PART value: 1
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_LION = 2
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_LION
PART value: 2
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_LIPO = 3
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_LIPO
PART value: 3
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_LIFE = 4
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_LIFE
PART value: 4
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_NICD = 5
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_NICD
PART value: 5
LINE: uint8 POWER_SUPPLY_TECHNOLOGY_LIMN = 6
PART itype: uint8
PART identifier: POWER_SUPPLY_TECHNOLOGY_LIMN
PART value: 6
LINE: Header header
PART itype: Header
PART identifier: header
LINE: float32 voltage # Voltage in Volts (Mandatory)
PART itype: float32
PART identifier: voltage
PART comment: # Voltage in Volts (Mandatory)
LINE: float32 current # Negative when discharging (A) (If unmeasured NaN)
PART itype: float32
PART identifier: current
PART comment: # Negative when discharging (A) (If unmeasured NaN)
LINE: float32 charge # Current charge in Ah (If unmeasured NaN)
PART itype: float32
PART identifier: charge
PART comment: # Current charge in Ah (If unmeasured NaN)
LINE: float32 capacity # Capacity in Ah (last full capacity) (If unmeasured NaN)
PART itype: float32
PART identifier: capacity
PART comment: # Capacity in Ah (last full capacity) (If unmeasured NaN)
LINE: float32 design_capacity # Capacity in Ah (design capacity) (If unmeasured NaN)
PART itype: float32
PART identifier: design_capacity
PART comment: # Capacity in Ah (design capacity) (If unmeasured NaN)
LINE: float32 percentage # Charge percentage on 0 to 1 range (If unmeasured NaN)
PART itype: float32
PART identifier: percentage
PART comment: # Charge percentage on 0 to 1 range (If unmeasured NaN)
LINE: uint8 power_supply_status # The charging status as reported. Values defined above
PART itype: uint8
PART identifier: power_supply_status
PART comment: # The charging status as reported. Values defined above
LINE: uint8 power_supply_health # The battery health metric. Values defined above
PART itype: uint8
PART identifier: power_supply_health
PART comment: # The battery health metric. Values defined above
LINE: uint8 power_supply_technology # The battery chemistry. Values defined above
PART itype: uint8
PART identifier: power_supply_technology
PART comment: # The battery chemistry. Values defined above
LINE: bool present # True if the battery is present
PART itype: bool
PART identifier: present
PART comment: # True if the battery is present
LINE: float32[] cell_voltage # An array of individual cell voltages for each cell in the pack
PART itype: float32[]
PART identifier: cell_voltage
PART comment: # An array of individual cell voltages for each cell in the pack
LINE: # If individual voltages unknown but number of cells known set each to NaN
LINE: string location # The location into which the battery is inserted. (slot number or plug)
PART itype: string
PART identifier: location
PART comment: # The location into which the battery is inserted. (slot number or plug)
LINE: string serial_number # The best approximation of the battery serial number
PART itype: string
PART identifier: serial_number
PART comment: # The best approximation of the battery serial number
We can see it correctly parsed both normal types and arrays correctly.