IRSOL
C++ code implementing socket server for interacting with Baumer camera.
parser.cpp
Go to the documentation of this file.
2
3#include "irsol/logging.hpp"
5
6#include <regex>
7
8namespace irsol {
9namespace protocol {
10std::optional<InMessage>
11Parser::parse(const std::string& line)
12{
13 IRSOL_LOG_TRACE("Parsing string '{}' for message", line);
14 std::string s = utils::trim(line);
15 IRSOL_LOG_TRACE("Trimmed result: '{}'", s);
16 std::vector<std::string> errorMessages;
17 errorMessages.reserve(3);
18 if(auto asg = parseAssignment(s)) {
20 "String '{}' parsed as assignment message: '{}'", line, asg.getMessage().toString());
21 return asg.getMessage();
22 } else {
23 errorMessages.push_back(asg.getError());
24 }
25 if(auto inq = parseInquiry(s)) {
26 IRSOL_LOG_TRACE("String '{}' parsed as inquiry message: {}", line, inq.getMessage().toString());
27 return inq.getMessage();
28 } else {
29 errorMessages.push_back(inq.getError());
30 }
31 if(auto cmd = parseCommand(s)) {
32 IRSOL_LOG_TRACE("String '{}' parsed as command message: {}", line, cmd.getMessage().toString());
33 return cmd.getMessage();
34 } else {
35 errorMessages.push_back(cmd.getError());
36 }
37
38 std::string fullErrorMessage = "";
39 for(const auto& errorMessage : errorMessages) {
40 fullErrorMessage += errorMessage + "; ";
41 }
43 "String '{}' could not be parsed as any known message type. {}", line, fullErrorMessage);
44 return std::nullopt;
45}
46
48Parser::parseAssignment(const std::string& line)
49{
50 // An assignment line looks like:
51 // <identifier>=<value>
52 // where:
53 // <identifier> is a string of alphanumeric characters and underscores (no spaces allowed), with
54 // optional array-indexing <value> is a string that is dynamically interpreted as an integer,
55 // double, or string The '=' is mandatory.
56
57 // Example valid assignment lines:
58 // foo=32
59 // bar=53.6
60 // qux_123=0.432
61 // _underscore=43
62 // array_like[1]=hello
63 // nested_array_like[1][2]=0 -> TODO: multidimensional has commas for indices and not multiple
64 // brackets. single_quote='single quote' double_quote="double quote" braces={sting value}
65 static const std::regex re(R"(^([a-zA-Z]+[a-zA-Z0-9_]*(?:\[\d+\])*)=(.+)$)");
66 std::smatch m;
67 std::string errorMessage;
68 if(std::regex_match(line, m, re)) {
69 try {
70 return {Assignment{utils::trim(m[1]), parseValue(utils::trim(m[2]))}};
71 } catch(const std::invalid_argument& e) {
72 errorMessage = e.what();
73 }
74 } else {
75 errorMessage = "Regex pattern for Assignment did not match";
76 }
77 return {std::move(errorMessage)};
78}
79
81Parser::parseInquiry(const std::string& line)
82{
83 // An inquiry line looks like:
84 // <identifier>?
85 // where:
86 // <identifier> is a string of alphanumeric characters and underscores (no spaces allowed), with
87 // optional array-indexing The '?' is mandatory.
88
89 // Example valid inquiry lines:
90 // foo?
91 // bar?
92 // qux_123?
93 // _underscore?
94 // array_like[1]?
95 // nested_array_like[1][2]?
96
97 static const std::regex re(R"(^([a-zA-Z]+[a-zA-Z0-9_]*(?:\[\d+\])*)\?$)");
98 std::smatch m;
99 std::string errorMessage;
100 if(std::regex_match(line, m, re)) {
101 try {
102 return {Inquiry{utils::trim(m[1])}};
103 } catch(const std::invalid_argument& e) {
104 errorMessage = e.what();
105 }
106 } else {
107 errorMessage = "Regex pattern for Inquiry did not match";
108 }
109 return {std::move(errorMessage)};
110}
111
113Parser::parseCommand(const std::string& line)
114{
115 // A command line looks like:
116 // <identifier>
117 // where:
118 // <identifier> is a string of alphanumeric characters and underscores (no spaces allowed)
119
120 // Example valid command lines:
121 // foo
122 // bar
123 // qux_123
124 // _underscore
125
126 static const std::regex re(R"(^([a-zA-Z]+[a-zA-Z0-9_]*)$)");
127 std::smatch m;
128 std::string errorMessage;
129 if(std::regex_match(line, m, re)) {
130 try {
131 return {Command{utils::trim(m[1])}};
132 } catch(const std::invalid_argument& e) {
133 errorMessage = e.what();
134 }
135 } else {
136 errorMessage = "Regex pattern for Command did not match";
137 }
138 return {std::move(errorMessage)};
139}
140
142Parser::parseValue(const std::string& valStr)
143{
144 // Try double first (more general)
145 try {
146 double d = utils::fromString<double>(valStr);
147
148 // Heuristic: if the string contains a '.' or 'e'/'E', treat it as double
149 // This allows to parse a value such as '5.0' as a double, not an int.
150 if(
151 valStr.find('.') != std::string::npos || valStr.find('e') != std::string::npos ||
152 valStr.find('E') != std::string::npos) {
153 return d;
154 }
155
156 // Otherwise, treat as int if within range
157 if(d >= std::numeric_limits<int>::min() && d <= std::numeric_limits<int>::max()) {
158 return static_cast<int>(d);
159 }
160
161 return d;
162 } catch(...) {
163 // Fall through
164 }
165
166 // Else, string (strip quotes/braces if needed)
167 if(
168 !valStr.empty() && ((valStr.front() == '"' && valStr.back() == '"') ||
169 (valStr.front() == '\'' && valStr.back() == '\'') ||
170 (valStr.front() == '{' && valStr.back() == '}'))) {
171 return valStr.substr(1, valStr.size() - 2);
172 }
173
174 return valStr;
175}
176
177}
178}
static internal::ParserResult< Inquiry > parseInquiry(const std::string &line)
Parses an inquiry message from a protocol line.
Definition parser.cpp:81
static irsol::types::protocol_value_t parseValue(const std::string &valueString)
Attempts to parse a raw value string into a typed protocol value.
Definition parser.cpp:142
static std::optional< InMessage > parse(const std::string &line)
Attempts to parse a single protocol input line into a structured InMessage.
Definition parser.cpp:11
static internal::ParserResult< Assignment > parseAssignment(const std::string &line)
Parses an assignment message from a protocol line.
Definition parser.cpp:48
static internal::ParserResult< Command > parseCommand(const std::string &line)
Parses a command message from a protocol line.
Definition parser.cpp:113
Wrapper for the result of a protocol parsing attempt.
#define IRSOL_LOG_WARN(...)
Logs a warning-level message using the default logger.
Definition logging.hpp:93
#define IRSOL_LOG_TRACE(...)
Logs a trace-level message using the default logger.
Definition logging.hpp:90
Logging utilities and configuration for the irsol library.
std::string trim(const std::string &s)
Remove leading and trailing whitespace from a string.
Definition utils.hpp:122
std::variant< int, double, std::string > protocol_value_t
Variant type representing protocol values that can be one of several types.
Definition types.hpp:150
Parses raw protocol input strings into structured messages.
Utility functions for protocol string handling and validation in the irsol library.
Represents an assignment operation in the protocol.
Represents a command invocation in the protocol.
Definition command.hpp:33
Represents a value inquiry in the protocol.
Definition inquiry.hpp:32
irsol::protocol::Assignment m(identifier, value)
auto asg