parse_utils.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2023 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include "parse_utils.h"
11 
12 #include <mrpt/core/exceptions.h>
13 #include <mrpt/core/get_env.h>
14 #include <mrpt/expr/CRuntimeCompiledExpression.h>
15 #include <mrpt/random/RandomGenerators.h>
16 #include <mrpt/system/filesystem.h>
17 #include <mrpt/system/os.h>
18 #include <mrpt/system/string_utils.h>
19 #include <mrpt/version.h>
20 
21 #include <algorithm>
22 #include <cstdlib>
23 #include <iostream>
24 #include <sstream>
25 
26 thread_local const bool MVSIM_VERBOSE_PARSE =
27  mrpt::get_env<bool>("MVSIM_VERBOSE_PARSE", false);
28 
29 using namespace mvsim;
30 
31 static std::string parseEnvVars(const std::string& text)
32 {
33  MRPT_TRY_START
34 
35  const auto start = text.find("$env{");
36  if (start == std::string::npos) return text;
37 
38  const std::string pre = text.substr(0, start);
39  const std::string post = text.substr(start + 5);
40 
41  const auto post_end = post.find('}');
42  if (post_end == std::string::npos)
43  {
44  THROW_EXCEPTION_FMT(
45  "Column=%u: Cannot find matching `}` for `$env{` in: `%s`",
46  static_cast<unsigned int>(start), text.c_str());
47  }
48 
49  const auto varname = post.substr(0, post_end);
50  std::string varvalue;
51  const char* v = ::getenv(varname.c_str());
52  if (v != nullptr)
53  varvalue = std::string(v);
54  else
55  {
56  THROW_EXCEPTION_FMT(
57  "parseEnvVars(): Undefined environment variable found: $env{%s}",
58  varname.c_str());
59  }
60 
61  return parseEnvVars(pre + varvalue + post.substr(post_end + 1));
62  MRPT_TRY_END
63 }
64 
65 static std::string parseVars(
66  const std::string& text,
67  const std::map<std::string, std::string>& variableNamesValues)
68 {
69  MRPT_TRY_START
70 
71  const auto start = text.find("${");
72  if (start == std::string::npos) return text;
73 
74  const std::string pre = text.substr(0, start);
75  const std::string post = text.substr(start + 2);
76 
77  const auto post_end = post.find('}');
78  if (post_end == std::string::npos)
79  {
80  THROW_EXCEPTION_FMT(
81  "Column=%u: Cannot find matching `}` for `${` in: `%s`",
82  static_cast<unsigned int>(start), text.c_str());
83  }
84 
85  const auto varname = post.substr(0, post_end);
86  std::string varvalue;
87  if (const auto it = variableNamesValues.find(varname);
88  it != variableNamesValues.end())
89  {
90  varvalue = it->second;
91  }
92  else
93  {
94  THROW_EXCEPTION_FMT(
95  "parseEnvVars(): Undefined variable found: ${%s}", varname.c_str());
96  }
97 
98  return parseEnvVars(pre + varvalue + post.substr(post_end + 1));
99  MRPT_TRY_END
100 }
101 
102 static std::string parseCmdRuns(const std::string& text)
103 {
104  MRPT_TRY_START
105 
106  const auto start = text.find("$(");
107  if (start == std::string::npos) return text;
108 
109  const std::string pre = text.substr(0, start);
110  const std::string post = text.substr(start + 2);
111 
112  const auto post_end = post.find(')');
113  if (post_end == std::string::npos)
114  {
115  THROW_EXCEPTION_FMT(
116  "Column=%u: Cannot find matching `)` for `$(` in: `%s`",
117  static_cast<unsigned int>(start), text.c_str());
118  }
119 
120  const auto cmd = post.substr(0, post_end);
121 
122  // Launch command and get console output:
123  std::string cmdOut;
124 
125  int ret = mrpt::system::executeCommand(cmd, &cmdOut);
126  if (ret != 0)
127  {
128  THROW_EXCEPTION_FMT(
129  "Error (retval=%i) executing external command: `%s`", ret,
130  cmd.c_str());
131  }
132  // Clear whitespaces:
133  cmdOut = mrpt::system::trim(cmdOut);
134  cmdOut.erase(std::remove(cmdOut.begin(), cmdOut.end(), '\r'), cmdOut.end());
135  cmdOut.erase(std::remove(cmdOut.begin(), cmdOut.end(), '\n'), cmdOut.end());
136 
137  return parseCmdRuns(pre + cmdOut + post.substr(post_end + 1));
138  MRPT_TRY_END
139 }
140 
141 #if MRPT_VERSION >= 0x258
142 static double my_rand()
143 {
144  auto& rng = mrpt::random::getRandomGenerator();
145  return rng.drawUniform(0.0, 1.0);
146 }
147 static double my_unifrnd(double xMin, double xMax)
148 {
149  auto& rng = mrpt::random::getRandomGenerator();
150  return rng.drawUniform(xMin, xMax);
151 }
152 static double randn()
153 {
154  auto& rng = mrpt::random::getRandomGenerator();
155  return rng.drawGaussian1D_normalized();
156 }
157 #endif
158 
159 // Examples: "$f{180/5}", "$f{ ${MAX_SPEED} * sin(deg2rad(45)) }"
160 static std::string parseMathExpr(
161  const std::string& text,
162  const std::map<std::string, std::string>& variableNamesValues)
163 {
164  MRPT_TRY_START
165 
166  const auto start = text.find("$f{");
167  if (start == std::string::npos) return text;
168 
169  const std::string pre = text.substr(0, start);
170  const std::string post = text.substr(start + 3);
171 
172  const auto post_end = post.find('}');
173  if (post_end == std::string::npos)
174  {
175  THROW_EXCEPTION_FMT(
176  "Column=%u: Cannot find matching `}` for `${` in: `%s`",
177  static_cast<unsigned int>(start), text.c_str());
178  }
179 
180  const auto sExpr = post.substr(0, post_end);
181 
182  mrpt::expr::CRuntimeCompiledExpression expr;
183 
184 #if MRPT_VERSION >= 0x258
185  expr.register_function("rand", &my_rand);
186  expr.register_function("unifrnd", &my_unifrnd);
187  expr.register_function("randn", &randn);
188 #endif
189 
190  std::map<std::string, double> numericVars;
191  for (const auto& kv : variableNamesValues)
192  {
193  std::stringstream ss(kv.second);
194 
195  double val = 0;
196  if (!(ss >> val)) continue;
197 
198  numericVars[kv.first] = val;
199  }
200 
201  // Compile expression (will throw on syntax error):
202  expr.compile(sExpr, numericVars);
203  const double val = expr.eval();
204 
205  return parseCmdRuns(
206  pre + mrpt::format("%g", val) + post.substr(post_end + 1));
207 
208  MRPT_TRY_END
209 }
210 
211 std::string mvsim::parse(
212  const std::string& input,
213  const std::map<std::string, std::string>& variableNamesValues)
214 {
216  {
217  std::cout << "[mvsim::parse] Input : '" << input << "' "
218  << " with these variables: ";
219  for (const auto& kv : variableNamesValues)
220  std::cout << kv.first << ", ";
221  std::cout << "\n";
222  }
223 
224  std::string s = input;
225 
226  std::string prevValue = s;
227  for (int iter = 0; iter < 10; iter++)
228  {
229  s = parseVars(s, variableNamesValues);
230  s = parseEnvVars(s);
231  s = parseCmdRuns(s);
232  s = parseMathExpr(s, variableNamesValues);
233  // We may need to iterate since, in general, each expression generator
234  // might generate another kind of expression:
235  if (s == prevValue) break;
236  prevValue = s;
237  }
238 
240  {
241  std::cout << "[mvsim::parse] Output: '" << s << "'\n";
242  }
243 
244  return s;
245 }
ROSCPP_DECL void start()
static std::string parseMathExpr(const std::string &text, const std::map< std::string, std::string > &variableNamesValues)
string cmd
XmlRpcServer s
static std::string parseCmdRuns(const std::string &text)
static std::string parseVars(const std::string &text, const std::map< std::string, std::string > &variableNamesValues)
Definition: parse_utils.cpp:65
std::string parse(const std::string &input, const std::map< std::string, std::string > &variableNamesValues={})
static std::string parseEnvVars(const std::string &text)
Definition: parse_utils.cpp:31
thread_local const bool MVSIM_VERBOSE_PARSE
Definition: parse_utils.cpp:26


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:21