ros_message.cpp
Go to the documentation of this file.
1 /***** MIT License ****
2 *
3 * Copyright (c) 2016-2022 Davide Faconti
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23 
24 #include <string_view>
25 #include <sstream>
26 #include <regex>
28 
29 namespace RosMsgParser{
30 
31 ROSMessage::ROSMessage(const std::string &msg_def)
32 {
33  std::istringstream messageDescriptor(msg_def);
34  std::match_results<std::string::const_iterator> what;
35 
36  for (std::string line; std::getline(messageDescriptor, line, '\n') ; )
37  {
38  std::string::const_iterator begin = line.begin(), end = line.end();
39 
40  // Skip empty line or one that is a comment
41  if (std::regex_search( begin, end, what,
42  std::regex("(^\\s*$|^\\s*#)")))
43  {
44  continue;
45  }
46 
47  TrimStringLeft(line);
48 
49  if( line.compare(0, 5, "MSG: ") == 0)
50  {
51  line.erase(0,5);
52  _type = ROSType(line);
53  }
54  else{
55  auto new_field = ROSField(line);
56  _fields.push_back(new_field);
57  }
58  }
59 }
60 
61 std::vector<std::string> SplitMultipleMessageDefinitions(const std::string &multi_def)
62 {
63  std::istringstream ss_msg(multi_def);
64 
65  std::vector<std::string> parts;
66  std::string part;
67 
68  for (std::string line; std::getline(ss_msg, line, '\n') ; )
69  {
70  if( line.find("========") == 0)
71  {
72  parts.emplace_back( std::move(part) );
73  part = {};
74  }
75  else{
76  part.append(line);
77  part.append("\n");
78  }
79  }
80  parts.emplace_back( std::move(part) );
81 
82  return parts;
83 }
84 
85 std::vector<ROSMessage::Ptr> ParseMessageDefinitions(
86  const std::string& multi_def,
87  const ROSType& root_type )
88 {
89  auto parts = SplitMultipleMessageDefinitions(multi_def);
90  std::vector<ROSType> known_type;
91  std::vector<ROSMessage::Ptr> parsed_msgs;
92 
93  const ROSType no_type;
94 
95  // iterating in reverse to fill known_type in the right order
96  // i.e. with no missing dependencies
97  for( int i = parts.size()-1; i>=0; i--)
98  {
99  auto msg = std::make_shared<ROSMessage>(parts[i]);
100 
101  if( i == 0 )
102  {
103  // type NOT found in the definition, but provided as argument
104  if( msg->type() == no_type && root_type != no_type )
105  {
106  msg->setType( root_type );
107  }
108  else if (msg->type() == no_type && root_type == no_type)
109  {
110  std::cout << multi_def << std::endl;
111  throw std::runtime_error("Message type unspecified");
112  }
113  }
114 
115  // add to vector
116  parsed_msgs.push_back( msg );
117  known_type.push_back( msg->type() );
118  }
119 
120  // adjust types with undefined package type
121  for (auto& msg: parsed_msgs)
122  {
123  for (ROSField& field : msg->fields())
124  {
125  // if package name is missing, try to find msgName in the list of known_type
126  if (field.type().pkgName().empty())
127  {
128  for (const ROSType& known_type : known_type)
129  {
130  if (field.type().msgName() == known_type.msgName())
131  {
132  field.changeType(known_type);
133  break;
134  }
135  }
136  }
137  }
138  }
139 
140  std::reverse(parsed_msgs.begin(), parsed_msgs.end());
141  return parsed_msgs;
142 }
143 
144 MessageSchema::Ptr BuildMessageSchema(const std::string &topic_name,
145  const std::vector<ROSMessage::Ptr>& parsed_msgs)
146 {
147  auto schema = std::make_shared<MessageSchema>();
148  schema->topic_name = topic_name;
149  schema->root_msg = parsed_msgs.front();
150 
151  for(const auto& msg: parsed_msgs )
152  {
153  schema->msg_library.insert( {msg->type(), msg} );
154  }
155 
157  std::function<void(ROSMessage::Ptr, FieldTreeNode*)> recursiveTreeCreator;
158 
159  recursiveTreeCreator = [&](ROSMessage::Ptr msg, FieldTreeNode* field_node)
160  {
161  // note: should use reserve here, NOT resize
162  const size_t NUM_FIELDS = msg->fields().size();
163  field_node->children().reserve(NUM_FIELDS);
164 
165  for (const ROSField& field : msg->fields())
166  {
167  if (field.isConstant())
168  {
169  continue;
170  }
171  // Let's add first a child to string_node
172  field_node->addChild(&field);
173  FieldTreeNode* new_string_node = &(field_node->children().back());
174 
175  // builtin types will not trigger a recursion
176  if (field.type().isBuiltin() == false)
177  {
178  auto new_msg = field.getMessagePtr(schema->msg_library);
179  if( !new_msg )
180  {
181  throw std::runtime_error("Missing ROSType in library");
182  }
183 
184  recursiveTreeCreator(new_msg, new_string_node);
185 
186  }
187  } // end of for fields
188  }; // end of recursiveTreeCreator
189 
190  // build root and start recursion
191  auto root_field = new ROSField( schema->root_msg->type(), topic_name);
192  schema->field_tree.root()->setValue( root_field );
193 
194  recursiveTreeCreator(schema->root_msg, schema->field_tree.root());
195 
196  return schema;
197 }
198 
199 } // end namespace
200 
201 
const ROSField & field(size_t i) const
Definition: ros_message.hpp:43
const std::string_view & pkgName() const
ex.: geometry_msgs/Pose -> "geometry_msgs"
Definition: ros_type.hpp:110
const std::string_view & msgName() const
ex.: geometry_msgs/Pose -> "Pose"
Definition: ros_type.hpp:105
std::shared_ptr< ROSMessage > Ptr
Definition: ros_message.hpp:37
std::shared_ptr< ROSMessage > getMessagePtr(const RosMessageLibrary &library) const
Definition: ros_field.cpp:144
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.c:221
A ROSMessage will contain one or more ROSField(s). Each field is little more than a name / type pair...
Definition: ros_field.hpp:45
MessageSchema::Ptr BuildMessageSchema(const std::string &topic_name, const std::vector< ROSMessage::Ptr > &parsed_msgs)
std::vector< ROSField > _fields
Definition: ros_message.hpp:56
void TrimStringLeft(std::string &s)
Definition: ros_field.cpp:164
std::vector< std::string > SplitMultipleMessageDefinitions(const std::string &multi_def)
Definition: ros_message.cpp:61
std::shared_ptr< MessageSchema > Ptr
Definition: ros_message.hpp:64
bool isConstant() const
True if field is a constant in message definition.
Definition: ros_field.hpp:60
bool isBuiltin() const
True if the type is ROS builtin.
Definition: ros_type.hpp:115
const T & move(const T &v)
Definition: backward.hpp:394
ROSMessage(const std::string &msg_def)
Definition: ros_message.cpp:31
std::vector< ROSMessage::Ptr > ParseMessageDefinitions(const std::string &multi_def, const ROSType &type)
Definition: ros_message.cpp:85
const ROSType & type() const
Definition: ros_field.hpp:55
Element of the tree. it has a single parent and N >= 0 children.
Definition: tree.hpp:53
void changeType(const ROSType &type)
Definition: ros_field.hpp:57


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:01:39