clang-format: update c/cc coding style
Update all cc code using .clang-format; please do so as well for future PRs etc.; emacs has a handy 'clang-format' mode to make this automatic. For comparing old changes with git blame, we can disregard this one using --ignore-rev (see https://www.moxio.com/blog/43/ignoring-bulk-change-commits-with-git-blame )
This commit is contained in:
456
lib/mu-parser.cc
456
lib/mu-parser.cc
@ -37,9 +37,8 @@ using namespace Mu;
|
||||
// <range> -> [field:][lower]..[upper]
|
||||
// <regex> -> [field:]/regex/
|
||||
|
||||
|
||||
#define BUG(...) Mu::Error (Error::Code::Internal, format("%u: BUG: ",__LINE__) \
|
||||
+ format(__VA_ARGS__))
|
||||
#define BUG(...) \
|
||||
Mu::Error(Error::Code::Internal, format("%u: BUG: ", __LINE__) + format(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* Get the "shortcut"/internal fields for the the given fieldstr or empty if there is none
|
||||
@ -50,187 +49,189 @@ using namespace Mu;
|
||||
* to [<"S","subject">], while "recip" could map to [<"to", "T">, <"cc", "C">, <"bcc", "B">]
|
||||
*/
|
||||
struct FieldInfo {
|
||||
const std::string field;
|
||||
const std::string prefix;
|
||||
bool supports_phrase;
|
||||
unsigned id;
|
||||
const std::string field;
|
||||
const std::string prefix;
|
||||
bool supports_phrase;
|
||||
unsigned id;
|
||||
};
|
||||
using FieldInfoVec = std::vector<FieldInfo>;
|
||||
|
||||
using Flags = Parser::Flags;
|
||||
|
||||
struct Parser::Private {
|
||||
Private(const Store& store, Flags flags):
|
||||
store_{store}, flags_{flags} {}
|
||||
Private(const Store& store, Flags flags) : store_{store}, flags_{flags} {}
|
||||
|
||||
std::vector<std::string> process_regex (const std::string& field,
|
||||
const std::regex& rx) const;
|
||||
std::vector<std::string> process_regex(const std::string& field,
|
||||
const std::regex& rx) const;
|
||||
|
||||
Mu::Tree term_1 (Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree term_2 (Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const;
|
||||
Mu::Tree factor_1 (Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree factor_2 (Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const;
|
||||
Mu::Tree unit (Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree data (Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree range (const FieldInfoVec& fields, const std::string& lower,
|
||||
const std::string& upper, size_t pos, WarningVec& warnings) const;
|
||||
Mu::Tree regex (const FieldInfoVec& fields, const std::string& v,
|
||||
size_t pos, WarningVec& warnings) const;
|
||||
Mu::Tree value (const FieldInfoVec& fields, const std::string& v,
|
||||
size_t pos, WarningVec& warnings) const;
|
||||
private:
|
||||
const Store& store_;
|
||||
const Flags flags_;
|
||||
Mu::Tree term_1(Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree term_2(Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const;
|
||||
Mu::Tree factor_1(Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree factor_2(Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const;
|
||||
Mu::Tree unit(Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree data(Mu::Tokens& tokens, WarningVec& warnings) const;
|
||||
Mu::Tree range(const FieldInfoVec& fields,
|
||||
const std::string& lower,
|
||||
const std::string& upper,
|
||||
size_t pos,
|
||||
WarningVec& warnings) const;
|
||||
Mu::Tree regex(const FieldInfoVec& fields,
|
||||
const std::string& v,
|
||||
size_t pos,
|
||||
WarningVec& warnings) const;
|
||||
Mu::Tree value(const FieldInfoVec& fields,
|
||||
const std::string& v,
|
||||
size_t pos,
|
||||
WarningVec& warnings) const;
|
||||
|
||||
private:
|
||||
const Store& store_;
|
||||
const Flags flags_;
|
||||
};
|
||||
|
||||
static MuMsgFieldId
|
||||
field_id (const std::string& field)
|
||||
field_id(const std::string& field)
|
||||
{
|
||||
if (field.empty())
|
||||
return MU_MSG_FIELD_ID_NONE;
|
||||
|
||||
if (field.empty())
|
||||
return MU_MSG_FIELD_ID_NONE;
|
||||
|
||||
MuMsgFieldId id = mu_msg_field_id_from_name (field.c_str(), FALSE);
|
||||
if (id != MU_MSG_FIELD_ID_NONE)
|
||||
return id;
|
||||
else if (field.length() == 1)
|
||||
return mu_msg_field_id_from_shortcut (field[0], FALSE);
|
||||
else
|
||||
return MU_MSG_FIELD_ID_NONE;
|
||||
MuMsgFieldId id = mu_msg_field_id_from_name(field.c_str(), FALSE);
|
||||
if (id != MU_MSG_FIELD_ID_NONE)
|
||||
return id;
|
||||
else if (field.length() == 1)
|
||||
return mu_msg_field_id_from_shortcut(field[0], FALSE);
|
||||
else
|
||||
return MU_MSG_FIELD_ID_NONE;
|
||||
}
|
||||
|
||||
static std::string
|
||||
process_value (const std::string& field, const std::string& value)
|
||||
process_value(const std::string& field, const std::string& value)
|
||||
{
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return value;
|
||||
switch(id) {
|
||||
case MU_MSG_FIELD_ID_PRIO: {
|
||||
if (!value.empty())
|
||||
return std::string(1, value[0]);
|
||||
} break;
|
||||
const auto id = field_id(field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return value;
|
||||
switch (id) {
|
||||
case MU_MSG_FIELD_ID_PRIO: {
|
||||
if (!value.empty())
|
||||
return std::string(1, value[0]);
|
||||
} break;
|
||||
|
||||
case MU_MSG_FIELD_ID_FLAGS: {
|
||||
const auto flag = mu_flag_char_from_name (value.c_str());
|
||||
if (flag)
|
||||
return std::string(1, tolower(flag));
|
||||
} break;
|
||||
case MU_MSG_FIELD_ID_FLAGS: {
|
||||
const auto flag = mu_flag_char_from_name(value.c_str());
|
||||
if (flag)
|
||||
return std::string(1, tolower(flag));
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return value; // XXX prio/flags, etc. alias
|
||||
return value; // XXX prio/flags, etc. alias
|
||||
}
|
||||
|
||||
static void
|
||||
add_field (std::vector<FieldInfo>& fields, MuMsgFieldId id)
|
||||
add_field(std::vector<FieldInfo>& fields, MuMsgFieldId id)
|
||||
{
|
||||
const auto shortcut = mu_msg_field_shortcut(id);
|
||||
if (!shortcut)
|
||||
return; // can't be searched
|
||||
const auto shortcut = mu_msg_field_shortcut(id);
|
||||
if (!shortcut)
|
||||
return; // can't be searched
|
||||
|
||||
const auto name = mu_msg_field_name (id);
|
||||
const auto pfx = mu_msg_field_xapian_prefix (id);
|
||||
const auto name = mu_msg_field_name(id);
|
||||
const auto pfx = mu_msg_field_xapian_prefix(id);
|
||||
|
||||
if (!name || !pfx)
|
||||
return;
|
||||
if (!name || !pfx)
|
||||
return;
|
||||
|
||||
fields.push_back ({{name}, {pfx},
|
||||
(bool)mu_msg_field_xapian_index(id),
|
||||
id});
|
||||
fields.push_back({{name}, {pfx}, (bool)mu_msg_field_xapian_index(id), id});
|
||||
}
|
||||
|
||||
static std::vector<FieldInfo>
|
||||
process_field (const std::string& field, Flags flags)
|
||||
process_field(const std::string& field, Flags flags)
|
||||
{
|
||||
std::vector<FieldInfo> fields;
|
||||
if (any_of(flags & Flags::UnitTest)) {
|
||||
add_field(fields, MU_MSG_FIELD_ID_MSGID);
|
||||
return fields;
|
||||
}
|
||||
std::vector<FieldInfo> fields;
|
||||
if (any_of(flags & Flags::UnitTest)) {
|
||||
add_field(fields, MU_MSG_FIELD_ID_MSGID);
|
||||
return fields;
|
||||
}
|
||||
|
||||
if (field == "contact" || field == "recip") { // multi fields
|
||||
add_field (fields, MU_MSG_FIELD_ID_TO);
|
||||
add_field (fields, MU_MSG_FIELD_ID_CC);
|
||||
add_field (fields, MU_MSG_FIELD_ID_BCC);
|
||||
if (field == "contact")
|
||||
add_field (fields, MU_MSG_FIELD_ID_FROM);
|
||||
} else if (field == "") {
|
||||
add_field (fields, MU_MSG_FIELD_ID_TO);
|
||||
add_field (fields, MU_MSG_FIELD_ID_CC);
|
||||
add_field (fields, MU_MSG_FIELD_ID_BCC);
|
||||
add_field (fields, MU_MSG_FIELD_ID_FROM);
|
||||
add_field (fields, MU_MSG_FIELD_ID_SUBJECT);
|
||||
add_field (fields, MU_MSG_FIELD_ID_BODY_TEXT);
|
||||
} else {
|
||||
const auto id = field_id (field);
|
||||
if (id != MU_MSG_FIELD_ID_NONE)
|
||||
add_field (fields, id);
|
||||
}
|
||||
if (field == "contact" || field == "recip") { // multi fields
|
||||
add_field(fields, MU_MSG_FIELD_ID_TO);
|
||||
add_field(fields, MU_MSG_FIELD_ID_CC);
|
||||
add_field(fields, MU_MSG_FIELD_ID_BCC);
|
||||
if (field == "contact")
|
||||
add_field(fields, MU_MSG_FIELD_ID_FROM);
|
||||
} else if (field == "") {
|
||||
add_field(fields, MU_MSG_FIELD_ID_TO);
|
||||
add_field(fields, MU_MSG_FIELD_ID_CC);
|
||||
add_field(fields, MU_MSG_FIELD_ID_BCC);
|
||||
add_field(fields, MU_MSG_FIELD_ID_FROM);
|
||||
add_field(fields, MU_MSG_FIELD_ID_SUBJECT);
|
||||
add_field(fields, MU_MSG_FIELD_ID_BODY_TEXT);
|
||||
} else {
|
||||
const auto id = field_id(field);
|
||||
if (id != MU_MSG_FIELD_ID_NONE)
|
||||
add_field(fields, id);
|
||||
}
|
||||
|
||||
return fields;
|
||||
return fields;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_range_field (const std::string& field)
|
||||
is_range_field(const std::string& field)
|
||||
{
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return false;
|
||||
else
|
||||
return mu_msg_field_is_range_field (id);
|
||||
const auto id = field_id(field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return false;
|
||||
else
|
||||
return mu_msg_field_is_range_field(id);
|
||||
}
|
||||
|
||||
struct MyRange {
|
||||
std::string lower;
|
||||
std::string upper;
|
||||
std::string lower;
|
||||
std::string upper;
|
||||
};
|
||||
|
||||
static MyRange
|
||||
process_range (const std::string& field, const std::string& lower,
|
||||
const std::string& upper)
|
||||
process_range(const std::string& field, const std::string& lower, const std::string& upper)
|
||||
{
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return { lower, upper };
|
||||
const auto id = field_id(field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return {lower, upper};
|
||||
|
||||
std::string l2 = lower;
|
||||
std::string u2 = upper;
|
||||
std::string l2 = lower;
|
||||
std::string u2 = upper;
|
||||
|
||||
if (id == MU_MSG_FIELD_ID_DATE) {
|
||||
l2 = Mu::date_to_time_t_string (lower, true);
|
||||
u2 = Mu::date_to_time_t_string (upper, false);
|
||||
} else if (id == MU_MSG_FIELD_ID_SIZE) {
|
||||
l2 = Mu::size_to_string (lower, true);
|
||||
u2 = Mu::size_to_string (upper, false);
|
||||
}
|
||||
if (id == MU_MSG_FIELD_ID_DATE) {
|
||||
l2 = Mu::date_to_time_t_string(lower, true);
|
||||
u2 = Mu::date_to_time_t_string(upper, false);
|
||||
} else if (id == MU_MSG_FIELD_ID_SIZE) {
|
||||
l2 = Mu::size_to_string(lower, true);
|
||||
u2 = Mu::size_to_string(upper, false);
|
||||
}
|
||||
|
||||
return { l2, u2 };
|
||||
return {l2, u2};
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Parser::Private::process_regex (const std::string& field, const std::regex& rx) const
|
||||
Parser::Private::process_regex(const std::string& field, const std::regex& rx) const
|
||||
{
|
||||
const auto id = field_id (field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return {};
|
||||
const auto id = field_id(field);
|
||||
if (id == MU_MSG_FIELD_ID_NONE)
|
||||
return {};
|
||||
|
||||
char pfx[] = { mu_msg_field_shortcut(id), '\0' };
|
||||
char pfx[] = {mu_msg_field_shortcut(id), '\0'};
|
||||
|
||||
std::vector<std::string> terms;
|
||||
store_.for_each_term(pfx,[&](auto&& str){
|
||||
if (std::regex_search(str.c_str() + 1, rx)) // avoid copy
|
||||
terms.emplace_back(str);
|
||||
return true;
|
||||
});
|
||||
std::vector<std::string> terms;
|
||||
store_.for_each_term(pfx, [&](auto&& str) {
|
||||
if (std::regex_search(str.c_str() + 1, rx)) // avoid copy
|
||||
terms.emplace_back(str);
|
||||
return true;
|
||||
});
|
||||
|
||||
return terms;
|
||||
return terms;
|
||||
}
|
||||
|
||||
static Token
|
||||
look_ahead (const Mu::Tokens& tokens)
|
||||
look_ahead(const Mu::Tokens& tokens)
|
||||
{
|
||||
return tokens.front();
|
||||
}
|
||||
@ -242,8 +243,10 @@ empty()
|
||||
}
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::value (const FieldInfoVec& fields, const std::string& v,
|
||||
size_t pos, WarningVec& warnings) const
|
||||
Parser::Private::value(const FieldInfoVec& fields,
|
||||
const std::string& v,
|
||||
size_t pos,
|
||||
WarningVec& warnings) const
|
||||
{
|
||||
auto val = utf8_flatten(v);
|
||||
|
||||
@ -253,42 +256,45 @@ Parser::Private::value (const FieldInfoVec& fields, const std::string& v,
|
||||
if (fields.size() == 1) {
|
||||
const auto item = fields.front();
|
||||
return Tree({Node::Type::Value,
|
||||
std::make_unique<Value>(
|
||||
item.field, item.prefix, item.id,
|
||||
process_value(item.field, val),
|
||||
item.supports_phrase)});
|
||||
std::make_unique<Value>(item.field,
|
||||
item.prefix,
|
||||
item.id,
|
||||
process_value(item.field, val),
|
||||
item.supports_phrase)});
|
||||
}
|
||||
|
||||
// a 'multi-field' such as "recip:"
|
||||
Tree tree(Node{Node::Type::OpOr});
|
||||
for (const auto& item: fields)
|
||||
tree.add_child (Tree({Node::Type::Value,
|
||||
std::make_unique<Value>(
|
||||
item.field, item.prefix, item.id,
|
||||
process_value(item.field, val),
|
||||
item.supports_phrase)}));
|
||||
for (const auto& item : fields)
|
||||
tree.add_child(Tree({Node::Type::Value,
|
||||
std::make_unique<Value>(item.field,
|
||||
item.prefix,
|
||||
item.id,
|
||||
process_value(item.field, val),
|
||||
item.supports_phrase)}));
|
||||
return tree;
|
||||
}
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::regex (const FieldInfoVec& fields, const std::string& v,
|
||||
size_t pos, WarningVec& warnings) const
|
||||
Parser::Private::regex(const FieldInfoVec& fields,
|
||||
const std::string& v,
|
||||
size_t pos,
|
||||
WarningVec& warnings) const
|
||||
{
|
||||
if (v.length() < 2)
|
||||
throw BUG("expected regexp, got '%s'", v.c_str());
|
||||
|
||||
const auto rxstr = utf8_flatten(v.substr(1, v.length()-2));
|
||||
const auto rxstr = utf8_flatten(v.substr(1, v.length() - 2));
|
||||
|
||||
try {
|
||||
Tree tree(Node{Node::Type::OpOr});
|
||||
const auto rx = std::regex (rxstr);
|
||||
for (const auto& field: fields) {
|
||||
const auto terms = process_regex (field.field, rx);
|
||||
for (const auto& term: terms) {
|
||||
tree.add_child (Tree(
|
||||
{Node::Type::Value,
|
||||
std::make_unique<Value>(field.field, "",
|
||||
field.id, term)}));
|
||||
try {
|
||||
Tree tree(Node{Node::Type::OpOr});
|
||||
const auto rx = std::regex(rxstr);
|
||||
for (const auto& field : fields) {
|
||||
const auto terms = process_regex(field.field, rx);
|
||||
for (const auto& term : terms) {
|
||||
tree.add_child(Tree(
|
||||
{Node::Type::Value,
|
||||
std::make_unique<Value>(field.field, "", field.id, term)}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,97 +305,104 @@ Parser::Private::regex (const FieldInfoVec& fields, const std::string& v,
|
||||
|
||||
} catch (...) {
|
||||
// fallback
|
||||
warnings.push_back ({pos, "invalid regexp"});
|
||||
return value (fields, v, pos, warnings);
|
||||
warnings.push_back({pos, "invalid regexp"});
|
||||
return value(fields, v, pos, warnings);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::range (const FieldInfoVec& fields, const std::string& lower,
|
||||
const std::string& upper, size_t pos, WarningVec& warnings) const
|
||||
Parser::Private::range(const FieldInfoVec& fields,
|
||||
const std::string& lower,
|
||||
const std::string& upper,
|
||||
size_t pos,
|
||||
WarningVec& warnings) const
|
||||
{
|
||||
if (fields.empty())
|
||||
throw BUG("expected field");
|
||||
|
||||
const auto& field = fields.front();
|
||||
if (!is_range_field(field.field))
|
||||
return value (fields, lower + ".." + upper, pos, warnings);
|
||||
return value(fields, lower + ".." + upper, pos, warnings);
|
||||
|
||||
auto prange = process_range (field.field, lower, upper);
|
||||
auto prange = process_range(field.field, lower, upper);
|
||||
if (prange.lower > prange.upper)
|
||||
prange = process_range (field.field, upper, lower);
|
||||
prange = process_range(field.field, upper, lower);
|
||||
|
||||
return Tree({Node::Type::Range,
|
||||
std::make_unique<Range>(field.field, field.prefix, field.id,
|
||||
prange.lower, prange.upper)});
|
||||
std::make_unique<Range>(field.field,
|
||||
field.prefix,
|
||||
field.id,
|
||||
prange.lower,
|
||||
prange.upper)});
|
||||
}
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::data (Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
Parser::Private::data(Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
{
|
||||
const auto token = look_ahead(tokens);
|
||||
if (token.type != Token::Type::Data)
|
||||
warnings.push_back ({token.pos, "expected: value"});
|
||||
warnings.push_back({token.pos, "expected: value"});
|
||||
|
||||
tokens.pop_front();
|
||||
|
||||
std::string field, val;
|
||||
const auto col = token.str.find (":");
|
||||
if (col != 0 && col != std::string::npos && col != token.str.length()-1) {
|
||||
const auto col = token.str.find(":");
|
||||
if (col != 0 && col != std::string::npos && col != token.str.length() - 1) {
|
||||
field = token.str.substr(0, col);
|
||||
val = token.str.substr(col + 1);
|
||||
val = token.str.substr(col + 1);
|
||||
} else
|
||||
val = token.str;
|
||||
|
||||
auto fields = process_field (field, flags_);
|
||||
if (fields.empty()) {// not valid field...
|
||||
warnings.push_back ({token.pos, format ("invalid field '%s'", field.c_str())});
|
||||
fields = process_field ("", flags_);
|
||||
auto fields = process_field(field, flags_);
|
||||
if (fields.empty()) { // not valid field...
|
||||
warnings.push_back({token.pos, format("invalid field '%s'", field.c_str())});
|
||||
fields = process_field("", flags_);
|
||||
// fallback, treat the whole of foo:bar as a value
|
||||
return value (fields, field + ":" + val, token.pos, warnings);
|
||||
return value(fields, field + ":" + val, token.pos, warnings);
|
||||
}
|
||||
|
||||
// does it look like a regexp?
|
||||
if (val.length() >= 2)
|
||||
if (val[0] == '/' && val[val.length()-1] == '/')
|
||||
return regex (fields, val, token.pos, warnings);
|
||||
if (val[0] == '/' && val[val.length() - 1] == '/')
|
||||
return regex(fields, val, token.pos, warnings);
|
||||
|
||||
// does it look like a range?
|
||||
const auto dotdot = val.find("..");
|
||||
if (dotdot != std::string::npos)
|
||||
return range(fields, val.substr(0, dotdot), val.substr(dotdot + 2),
|
||||
token.pos, warnings);
|
||||
return range(fields,
|
||||
val.substr(0, dotdot),
|
||||
val.substr(dotdot + 2),
|
||||
token.pos,
|
||||
warnings);
|
||||
else if (is_range_field(fields.front().field)) {
|
||||
// range field without a range - treat as field:val..val
|
||||
return range (fields, val, val, token.pos, warnings);
|
||||
return range(fields, val, val, token.pos, warnings);
|
||||
}
|
||||
|
||||
// if nothing else, it's a value.
|
||||
return value (fields, val, token.pos, warnings);
|
||||
return value(fields, val, token.pos, warnings);
|
||||
}
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::unit (Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
Parser::Private::unit(Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
{
|
||||
if (tokens.empty()) {
|
||||
warnings.push_back ({0, "expected: unit"});
|
||||
warnings.push_back({0, "expected: unit"});
|
||||
return empty();
|
||||
}
|
||||
|
||||
const auto token = look_ahead (tokens);
|
||||
const auto token = look_ahead(tokens);
|
||||
|
||||
if (token.type == Token::Type::Not) {
|
||||
tokens.pop_front();
|
||||
Tree tree{{Node::Type::OpNot}};
|
||||
tree.add_child(unit (tokens, warnings));
|
||||
tree.add_child(unit(tokens, warnings));
|
||||
return tree;
|
||||
}
|
||||
|
||||
if (token.type == Token::Type::Open) {
|
||||
tokens.pop_front();
|
||||
auto tree = term_1 (tokens, warnings);
|
||||
auto tree = term_1(tokens, warnings);
|
||||
if (tokens.empty())
|
||||
warnings.push_back({token.pos, "expected: ')'"});
|
||||
else {
|
||||
@ -398,21 +411,18 @@ Parser::Private::unit (Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
tokens.pop_front();
|
||||
else {
|
||||
warnings.push_back(
|
||||
{token2.pos,
|
||||
std::string("expected: ')' but got ") +
|
||||
token2.str});
|
||||
{token2.pos,
|
||||
std::string("expected: ')' but got ") + token2.str});
|
||||
}
|
||||
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
return data (tokens, warnings);
|
||||
return data(tokens, warnings);
|
||||
}
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::factor_2 (Mu::Tokens& tokens, Node::Type& op,
|
||||
WarningVec& warnings) const
|
||||
Parser::Private::factor_2(Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const
|
||||
{
|
||||
if (tokens.empty())
|
||||
return empty();
|
||||
@ -420,7 +430,7 @@ Parser::Private::factor_2 (Mu::Tokens& tokens, Node::Type& op,
|
||||
const auto token = look_ahead(tokens);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
switch (token.type) {
|
||||
case Token::Type::And: {
|
||||
tokens.pop_front();
|
||||
@ -433,51 +443,44 @@ Parser::Private::factor_2 (Mu::Tokens& tokens, Node::Type& op,
|
||||
op = Node::Type::OpAnd; // implicit AND
|
||||
break;
|
||||
|
||||
default:
|
||||
return empty();
|
||||
default: return empty();
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
return factor_1 (tokens, warnings);
|
||||
return factor_1(tokens, warnings);
|
||||
}
|
||||
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::factor_1 (Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
Parser::Private::factor_1(Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
{
|
||||
Node::Type op { Node::Type::Invalid };
|
||||
Node::Type op{Node::Type::Invalid};
|
||||
|
||||
auto t = unit (tokens, warnings);
|
||||
auto a2 = factor_2 (tokens, op, warnings);
|
||||
auto t = unit(tokens, warnings);
|
||||
auto a2 = factor_2(tokens, op, warnings);
|
||||
|
||||
if (a2.empty())
|
||||
return t;
|
||||
|
||||
Tree tree {{op}};
|
||||
Tree tree{{op}};
|
||||
tree.add_child(std::move(t));
|
||||
tree.add_child(std::move(a2));
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::term_2 (Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const
|
||||
Parser::Private::term_2(Mu::Tokens& tokens, Node::Type& op, WarningVec& warnings) const
|
||||
{
|
||||
if (tokens.empty())
|
||||
return empty();
|
||||
|
||||
const auto token = look_ahead (tokens);
|
||||
const auto token = look_ahead(tokens);
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||
switch (token.type) {
|
||||
case Token::Type::Or:
|
||||
op = Node::Type::OpOr;
|
||||
break;
|
||||
case Token::Type::Xor:
|
||||
op = Node::Type::OpXor;
|
||||
break;
|
||||
case Token::Type::Or: op = Node::Type::OpOr; break;
|
||||
case Token::Type::Xor: op = Node::Type::OpXor; break;
|
||||
default:
|
||||
if (token.type != Token::Type::Close)
|
||||
warnings.push_back({token.pos, "expected OR|XOR"});
|
||||
@ -487,43 +490,42 @@ Parser::Private::term_2 (Mu::Tokens& tokens, Node::Type& op, WarningVec& warning
|
||||
|
||||
tokens.pop_front();
|
||||
|
||||
return term_1 (tokens, warnings);
|
||||
return term_1(tokens, warnings);
|
||||
}
|
||||
|
||||
Mu::Tree
|
||||
Parser::Private::term_1 (Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
Parser::Private::term_1(Mu::Tokens& tokens, WarningVec& warnings) const
|
||||
{
|
||||
Node::Type op { Node::Type::Invalid };
|
||||
Node::Type op{Node::Type::Invalid};
|
||||
|
||||
auto t = factor_1 (tokens, warnings);
|
||||
auto o2 = term_2 (tokens, op, warnings);
|
||||
auto t = factor_1(tokens, warnings);
|
||||
auto o2 = term_2(tokens, op, warnings);
|
||||
|
||||
if (o2.empty())
|
||||
return t;
|
||||
else {
|
||||
Tree tree {{op}};
|
||||
Tree tree{{op}};
|
||||
tree.add_child(std::move(t));
|
||||
tree.add_child(std::move(o2));
|
||||
return tree;
|
||||
}
|
||||
}
|
||||
|
||||
Mu::Parser::Parser(const Store& store, Flags flags):
|
||||
priv_{std::make_unique<Private>(store, flags)}
|
||||
{}
|
||||
Mu::Parser::Parser(const Store& store, Flags flags) : priv_{std::make_unique<Private>(store, flags)}
|
||||
{
|
||||
}
|
||||
|
||||
Mu::Parser::~Parser() = default;
|
||||
|
||||
|
||||
Mu::Tree
|
||||
Mu::Parser::parse (const std::string& expr, WarningVec& warnings) const
|
||||
Mu::Parser::parse(const std::string& expr, WarningVec& warnings) const
|
||||
{
|
||||
try {
|
||||
auto tokens = tokenize (expr);
|
||||
if (tokens.empty())
|
||||
return empty ();
|
||||
else
|
||||
return priv_->term_1 (tokens, warnings);
|
||||
auto tokens = tokenize(expr);
|
||||
if (tokens.empty())
|
||||
return empty();
|
||||
else
|
||||
return priv_->term_1(tokens, warnings);
|
||||
|
||||
} catch (const std::runtime_error& ex) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user