namespace std
{
- template <> struct hash<std::pair<EvaluationValue::Kind, std::string>> {
- size_t operator()(const std::pair<EvaluationValue::Kind, std::string> &p) const
+ template <> struct hash<std::pair<detail::Kind, std::string>> {
+ size_t operator()(const std::pair<detail::Kind, std::string> &p) const
{
return std::hash<std::string>()(p.second) ^ (unsigned char)p.first;
}
std::shared_ptr<UIElement> root;
std::shared_ptr<NavigationElement> navigationContext;
std::unordered_map<std::string, EvaluationValue> variables;
- std::unordered_map<std::pair<EvaluationValue::Kind, std::string>, std::function<EvaluationValue(const EvaluationValue &, EvaluationValue)>> setters;
- std::unordered_map<std::pair<EvaluationValue::Kind, std::string>, std::function<EvaluationValue(const EvaluationValue &)>> getters;
+ std::unordered_map<std::pair<detail::Kind, std::string>, std::function<EvaluationValue(const EvaluationValue &, EvaluationValue)>> setters;
+ std::unordered_map<std::pair<detail::Kind, std::string>, std::function<EvaluationValue(const EvaluationValue &)>> getters;
std::mutex mt;
std::ostream &output;
{
insertRoleConstants();
insertStateConstants();
- variables["sleep"] = EvaluationValue::UserFunctionType<double> {
+ variables["sleep"] = detail::UserFunctionType<double> {
[&](EvaluationContext & ec, double tm) -> EvaluationValue {
if (tm > 0)
{
return {};
}
};
- variables["get_at_point"] = EvaluationValue::UserFunctionType<Point> {
+ variables["get_at_point"] = detail::UserFunctionType<Point> {
[&](EvaluationContext & ec, Point pt) -> EvaluationValue {
return convert(pt);
}
};
- variables["find_by_name"] = EvaluationValue::UserFunctionType<std::string, std::vector<int>, std::vector<int>> {
+ variables["find_by_name"] = detail::UserFunctionType<std::string, std::vector<int>, std::vector<int>> {
[&](EvaluationContext & ec, std::string name, std::vector<int> roles, std::vector<int> states) -> EvaluationValue {
auto root = getVisibleRoot();
if (!root) throw EvaluationFailure{} << "no visible root (context changed didn't happen)";
}, monitor);
}
};
- getters[ { EvaluationValue::Kind::UIELEMENT, "name" }] = [&](const EvaluationValue & self) -> EvaluationValue {
- auto uiElem = self.asUiElement();
+ getters[ { detail::Kind::UIELEMENT, "name" }] = [&](const EvaluationValue & self) -> EvaluationValue {
+ auto uiElem = self.as<std::shared_ptr<UIElement>>();
ASSERT(uiElem->getObject());
return executeOnMainThread([&]()
{
throw EvaluationFailure{} << "failed to get at-spi object's name (use dlogutil to get at-spi error message)";
});
};
- getters[ { EvaluationValue::Kind::UIELEMENT, "middle_point" }] = [&](const EvaluationValue & self) -> EvaluationValue {
- auto uiElem = self.asUiElement();
+ getters[ { detail::Kind::UIELEMENT, "middle_point" }] = [&](const EvaluationValue & self) -> EvaluationValue {
+ auto uiElem = self.as<std::shared_ptr<UIElement>>();
ASSERT(uiElem->getObject());
return executeOnMainThread([&]()
{
});
};
for (auto activityName : ActivityFactory::getInstance()->getAllActivityTypes()) {
- variables[activityName] = EvaluationValue::FunctionType::Type{
+ variables[activityName] = detail::FunctionType::Type{
[ = ](EvaluationContext & ec, std::vector<EvaluationValue> args) -> EvaluationValue {
auto activity = executeOnMainThread([&]()
{
#include "EvaluationContext.hpp"
+using detail::VectorType;
+using detail::SetType;
+using detail::FunctionType;
+using detail::DictType;
+
namespace std
{
- template <> struct hash<std::pair<EvaluationValue::Kind, EvaluationValue::Kind>> {
- size_t operator()(std::pair<EvaluationValue::Kind, EvaluationValue::Kind> p) const
+ template <> struct hash<std::pair<detail::Kind, detail::Kind>> {
+ size_t operator()(std::pair<detail::Kind, detail::Kind> p) const
{
return ((unsigned char)p.first << 8) | (unsigned char)p.second;
}
Optional<EvaluationValue> v;
switch (function.kind()) {
- case EvaluationValue::Kind::FUNCTION:
+ case detail::Kind::FUNCTION:
try {
- return function.asFunctionType()(*this, std::move(values));
+ return function.as<detail::FunctionType>()(*this, std::move(values));
} catch (EvaluationFailure &e) {
if (loc) e.setLocationIfMissing(*loc);
throw;
}
- case EvaluationValue::Kind::STRING:
- case EvaluationValue::Kind::INTEGER:
- case EvaluationValue::Kind::DOUBLE:
- case EvaluationValue::Kind::UIELEMENT:
- case EvaluationValue::Kind::BOOLEAN:
- case EvaluationValue::Kind::POINT:
- case EvaluationValue::Kind::EMPTY:
- case EvaluationValue::Kind::VECTOR:
- case EvaluationValue::Kind::SET:
- case EvaluationValue::Kind::DICT:
+ case detail::Kind::STRING:
+ case detail::Kind::INTEGER:
+ case detail::Kind::DOUBLE:
+ case detail::Kind::UIELEMENT:
+ case detail::Kind::BOOLEAN:
+ case detail::Kind::POINT:
+ case detail::Kind::EMPTY:
+ case detail::Kind::VECTOR:
+ case detail::Kind::SET:
+ case detail::Kind::DICT:
break;
}
throw EvaluationFailure{loc} << "value of kind " << EvaluationValue::toString(function.kind()) <<
}
}
-EvaluationValue EvaluationContext::convert(const Optional<TokenLocation> &loc, const EvaluationValue &value, EvaluationValue::Kind targetType)
+EvaluationValue EvaluationContext::convert(const Optional<TokenLocation> &loc, const EvaluationValue &value, detail::Kind targetType)
{
if (value.kind() == targetType) return value;
try {
switch (value.kind()) {
- case EvaluationValue::Kind::FUNCTION:
- case EvaluationValue::Kind::STRING:
+ case detail::Kind::FUNCTION:
+ case detail::Kind::STRING:
return detail::ConvertTo<std::string>::convert(*this, value);
- case EvaluationValue::Kind::INTEGER:
+ case detail::Kind::INTEGER:
return detail::ConvertTo<int>::convert(*this, value);
- case EvaluationValue::Kind::DOUBLE:
+ case detail::Kind::DOUBLE:
return detail::ConvertTo<double>::convert(*this, value);
- case EvaluationValue::Kind::UIELEMENT:
+ case detail::Kind::UIELEMENT:
return detail::ConvertTo<std::shared_ptr<UIElement>>::convert(*this, value);
- case EvaluationValue::Kind::BOOLEAN:
+ case detail::Kind::BOOLEAN:
return detail::ConvertTo<bool>::convert(*this, value);
- case EvaluationValue::Kind::POINT:
+ case detail::Kind::POINT:
return detail::ConvertTo<Point>::convert(*this, value);
- case EvaluationValue::Kind::EMPTY:
+ case detail::Kind::EMPTY:
return {};
- case EvaluationValue::Kind::VECTOR:
- case EvaluationValue::Kind::SET:
- case EvaluationValue::Kind::DICT:
+ case detail::Kind::VECTOR:
+ case detail::Kind::SET:
+ case detail::Kind::DICT:
break;
}
} catch (EvaluationFailure &e) {
throw;
}
throw EvaluationFailure{loc} << "can't convert from " << EvaluationValue::toString(value.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::FUNCTION);
+ " to " << EvaluationValue::toString(detail::Kind::FUNCTION);
}
int EvaluationContext::getSingleIndex(const std::vector<EvaluationValue> &args, int size, std::string typeName)
ASSERT(!args.empty());
auto &self = args[0];
switch (self.kind()) {
- case EvaluationValue::Kind::STRING:
+ case detail::Kind::STRING:
if (args.size() == 2) {
- auto index = getSingleIndex(args, static_cast<int>(self.asString().size()), "string");
- return self.asString().substr(index, 1);
+ auto index = getSingleIndex(args, static_cast<int>(self.as<std::string>().size()), "string");
+ return self.as<std::string>().substr(index, 1);
} else if (args.size() == 3) {
- auto indexes = getDoubleIndexes(args, static_cast<int>(self.asString().size()));
- return self.asString().substr(indexes.first, indexes.second - indexes.first);
+ auto indexes = getDoubleIndexes(args, static_cast<int>(self.as<std::string>().size()));
+ return self.as<std::string>().substr(indexes.first, indexes.second - indexes.first);
}
break;
- case EvaluationValue::Kind::FUNCTION:
- case EvaluationValue::Kind::INTEGER:
- case EvaluationValue::Kind::DOUBLE:
- case EvaluationValue::Kind::UIELEMENT:
- case EvaluationValue::Kind::BOOLEAN:
- case EvaluationValue::Kind::POINT:
- case EvaluationValue::Kind::EMPTY:
- case EvaluationValue::Kind::SET:
+ case detail::Kind::FUNCTION:
+ case detail::Kind::INTEGER:
+ case detail::Kind::DOUBLE:
+ case detail::Kind::UIELEMENT:
+ case detail::Kind::BOOLEAN:
+ case detail::Kind::POINT:
+ case detail::Kind::EMPTY:
+ case detail::Kind::SET:
break;
- case EvaluationValue::Kind::VECTOR:
+ case detail::Kind::VECTOR:
if (args.size() == 2) {
- auto index = getSingleIndex(args, static_cast<int>(self.asVector().size()), "vector");
- return self.asVector()[index];
+ auto index = getSingleIndex(args, static_cast<int>(self.as<VectorType>().size()), "vector");
+ return self.as<VectorType>()[index];
} else if (args.size() == 3) {
- auto indexes = getDoubleIndexes(args, static_cast<int>(self.asVector().size()));
+ auto indexes = getDoubleIndexes(args, static_cast<int>(self.as<VectorType>().size()));
std::vector<EvaluationValue> tmp;
tmp.reserve(indexes.second - indexes.first);
for (auto i = indexes.first; i < indexes.second; ++i)
- tmp.push_back(self.asVector()[i]);
+ tmp.push_back(self.as<VectorType>()[i]);
return std::move(tmp);
}
break;
- case EvaluationValue::Kind::DICT:
+ case detail::Kind::DICT:
if (args.size() == 2) {
auto key = EvaluationValueKey{ args[1] };
- auto it = self.asDict().find(key);
- if (it == self.asDict().end()) throw EvaluationFailure{loc} << "key not found";
+ auto it = self.as<detail::DictType>().find(key);
+ if (it == self.as<detail::DictType>().end()) throw EvaluationFailure{loc} << "key not found";
return it->second;
}
break;
ASSERT(!args.empty());
auto &self = args[0];
switch (self.kind()) {
- case EvaluationValue::Kind::STRING:
- case EvaluationValue::Kind::FUNCTION:
- case EvaluationValue::Kind::INTEGER:
- case EvaluationValue::Kind::DOUBLE:
- case EvaluationValue::Kind::UIELEMENT:
- case EvaluationValue::Kind::BOOLEAN:
- case EvaluationValue::Kind::POINT:
- case EvaluationValue::Kind::EMPTY:
- case EvaluationValue::Kind::SET:
+ case detail::Kind::STRING:
+ case detail::Kind::FUNCTION:
+ case detail::Kind::INTEGER:
+ case detail::Kind::DOUBLE:
+ case detail::Kind::UIELEMENT:
+ case detail::Kind::BOOLEAN:
+ case detail::Kind::POINT:
+ case detail::Kind::EMPTY:
+ case detail::Kind::SET:
break;
- case EvaluationValue::Kind::VECTOR:
+ case detail::Kind::VECTOR:
if (args.size() == 3) {
- auto index = getSingleIndex(args, static_cast<int>(self.asVector().size()), "vector");
- self.asVector()[index] = args[2];
+ auto index = getSingleIndex(args, static_cast<int>(self.as<VectorType>().size()), "vector");
+ self.as<VectorType>()[index] = args[2];
return std::move(args[2]);
- } else if (args.size() == 4 && args[3].kind() == EvaluationValue::Kind::VECTOR) {
- auto indexes = getDoubleIndexes(args, static_cast<int>(self.asVector().size()));
+ } else if (args.size() == 4 && args[3].kind() == detail::Kind::VECTOR) {
+ auto indexes = getDoubleIndexes(args, static_cast<int>(self.as<VectorType>().size()));
std::vector<EvaluationValue> tmp;
- tmp.reserve(self.asVector().size() - (indexes.second - indexes.first) + args[3].asVector().size());
- for (auto i = 0; i < indexes.first; ++i) tmp.push_back(std::move(self.asVector()[i]));
- for (auto &v : args[3].asVector()) tmp.push_back(v);
- for (auto i = indexes.second; i < static_cast<int>(self.asVector().size()); ++i) tmp.push_back(std::move(self.asVector()[i]));
- self.asVector() = std::move(tmp);
+ tmp.reserve(self.as<VectorType>().size() - (indexes.second - indexes.first) + args[3].as<VectorType>().size());
+ for (auto i = 0; i < indexes.first; ++i) tmp.push_back(std::move(self.as<VectorType>()[i]));
+ for (auto &v : args[3].as<VectorType>()) tmp.push_back(v);
+ for (auto i = indexes.second; i < static_cast<int>(self.as<VectorType>().size()); ++i) tmp.push_back(std::move(self.as<VectorType>()[i]));
+ self.as<VectorType>() = std::move(tmp);
return {};
}
break;
- case EvaluationValue::Kind::DICT:
+ case detail::Kind::DICT:
if (args.size() == 3) {
- self.asDict()[std::move(args[1])] = args[2];
+ self.as<DictType>()[std::move(args[1])] = args[2];
return std::move(args[2]);
}
break;
{
try {
switch (self.kind()) {
- case EvaluationValue::Kind::INTEGER:
- return -self.asInteger();
- case EvaluationValue::Kind::DOUBLE:
- return -self.asDouble();
- case EvaluationValue::Kind::STRING:
- case EvaluationValue::Kind::SET:
- case EvaluationValue::Kind::DICT:
- case EvaluationValue::Kind::VECTOR:
- case EvaluationValue::Kind::FUNCTION:
- case EvaluationValue::Kind::UIELEMENT:
- case EvaluationValue::Kind::BOOLEAN:
- case EvaluationValue::Kind::POINT:
- case EvaluationValue::Kind::EMPTY:
+ case detail::Kind::INTEGER:
+ return -self.as<int>();
+ case detail::Kind::DOUBLE:
+ return -self.as<double>();
+ case detail::Kind::STRING:
+ case detail::Kind::SET:
+ case detail::Kind::DICT:
+ case detail::Kind::VECTOR:
+ case detail::Kind::FUNCTION:
+ case detail::Kind::UIELEMENT:
+ case detail::Kind::BOOLEAN:
+ case detail::Kind::POINT:
+ case detail::Kind::EMPTY:
break;
}
} catch (EvaluationFailure &e) {
{
try {
switch (self.kind()) {
- case EvaluationValue::Kind::STRING: {
+ case detail::Kind::STRING: {
auto val = detail::ConvertTo<std::string>::convert(*this, value);
- return self.asString().find(val) != std::string::npos;
+ return self.as<std::string>().find(val) != std::string::npos;
}
- case EvaluationValue::Kind::SET: {
- return self.asSet().find(value) != self.asSet().end();
+ case detail::Kind::SET: {
+ return self.as<SetType>().find(value) != self.as<SetType>().end();
}
- case EvaluationValue::Kind::DICT: {
- return self.asDict().find(value) != self.asDict().end();
+ case detail::Kind::DICT: {
+ return self.as<DictType>().find(value) != self.as<DictType>().end();
}
- case EvaluationValue::Kind::VECTOR:
- for (auto &v : self.asVector())
+ case detail::Kind::VECTOR:
+ for (auto &v : self.as<VectorType>())
if (v == value) return true;
- return true;
- case EvaluationValue::Kind::FUNCTION:
- case EvaluationValue::Kind::INTEGER:
- case EvaluationValue::Kind::DOUBLE:
- case EvaluationValue::Kind::UIELEMENT:
- case EvaluationValue::Kind::BOOLEAN:
- case EvaluationValue::Kind::POINT:
- case EvaluationValue::Kind::EMPTY:
+ return false;
+ case detail::Kind::FUNCTION:
+ case detail::Kind::INTEGER:
+ case detail::Kind::DOUBLE:
+ case detail::Kind::UIELEMENT:
+ case detail::Kind::BOOLEAN:
+ case detail::Kind::POINT:
+ case detail::Kind::EMPTY:
break;
}
} catch (EvaluationFailure &e) {
EvaluationValue callFunction(const Optional<TokenLocation> &loc, EvaluationValue function, std::vector<EvaluationValue> values);
EvaluationValue getAttribute(const Optional<TokenLocation> &loc, EvaluationValue self, const std::string &identifier);
EvaluationValue setAttribute(const Optional<TokenLocation> &loc, EvaluationValue self, const std::string &identifier, EvaluationValue value);
- EvaluationValue convert(const Optional<TokenLocation> &loc, const EvaluationValue &value, EvaluationValue::Kind targetType);
+ EvaluationValue convert(const Optional<TokenLocation> &loc, const EvaluationValue &value, detail::Kind targetType);
EvaluationValue evaluateAccessGet(const Optional<TokenLocation> &loc, const std::vector<EvaluationValue> &args);
EvaluationValue evaluateAccessSet(const Optional<TokenLocation> &loc, std::vector<EvaluationValue> args);
bool evaluateIn(const Optional<TokenLocation> &loc, const EvaluationValue &self, const EvaluationValue &value);
return *location_;
}
-std::string EvaluationValue::toString(Kind k)
+std::string EvaluationValue::toString(detail::Kind k)
{
switch (k) {
- case Kind::EMPTY:
+ case detail::Kind::EMPTY:
return "EMPTY";
- case Kind::STRING:
+ case detail::Kind::STRING:
return "STRING";
- case Kind::INTEGER:
+ case detail::Kind::INTEGER:
return "INTEGER";
- case Kind::DOUBLE:
+ case detail::Kind::DOUBLE:
return "DOUBLE";
- case Kind::UIELEMENT:
+ case detail::Kind::UIELEMENT:
return "UIELEMENT";
- case Kind::BOOLEAN:
+ case detail::Kind::BOOLEAN:
return "BOOLEAN";
- case Kind::POINT:
+ case detail::Kind::POINT:
return "POINT";
- case Kind::FUNCTION:
+ case detail::Kind::FUNCTION:
return "FUNCTION";
- case Kind::VECTOR:
+ case detail::Kind::VECTOR:
return "VECTOR";
- case Kind::SET:
+ case detail::Kind::SET:
return "SET";
- case Kind::DICT:
+ case detail::Kind::DICT:
return "DICT";
}
return "";
}
-EvaluationValue::EvaluationValue()
-{
-}
+detail::Data::Data(int t) : integer(t) { }
+detail::Data::Data(double t) : double_(t) { }
+detail::Data::Data(bool t) : boolean(t) { }
+detail::Data::Data(std::string t) : string(std::move(t)) { }
+detail::Data::Data(std::shared_ptr<UIElement> t) : uiElement(std::move(t)) { }
+detail::Data::Data(Point t) : point(t) { }
+detail::Data::Data(FunctionType t) : function(std::move(t)) { }
+detail::Data::Data(VectorType t) : vector(std::make_shared<VectorType>(std::move(t))) { }
+detail::Data::Data(SetType t) : set(std::make_shared<SetType>(std::move(t))) { }
+detail::Data::Data(DictType t) : dict(std::make_shared<DictType>(std::move(t))) { }
-EvaluationValue::Data::Data(int t) : integer(t) { }
-EvaluationValue::Data::Data(double t) : double_(t) { }
-EvaluationValue::Data::Data(bool t) : boolean(t) { }
-EvaluationValue::Data::Data(std::string t) : string(std::move(t)) { }
-EvaluationValue::Data::Data(std::shared_ptr<UIElement> t) : uiElement(std::move(t)) { }
-EvaluationValue::Data::Data(Point t) : point(t) { }
-EvaluationValue::Data::Data(FunctionType t) : function(std::move(t.function)) { }
-EvaluationValue::Data::Data(std::shared_ptr<VectorType> t) : vector(std::move(t)) { }
-EvaluationValue::Data::Data(std::shared_ptr<SetType> t) : set(std::move(t)) { }
-EvaluationValue::Data::Data(std::shared_ptr<DictType> t) : dict(std::move(t)) { }
-
-EvaluationValue::EvaluationValue(std::nullptr_t) {}
-EvaluationValue::EvaluationValue(int integer) : data(integer), kind_(Kind::INTEGER) { }
-EvaluationValue::EvaluationValue(double double_) : data(double_), kind_(Kind::DOUBLE) { }
-EvaluationValue::EvaluationValue(bool boolean) : data(boolean), kind_(Kind::BOOLEAN) { }
-EvaluationValue::EvaluationValue(std::string string) : data(std::move(string)), kind_(Kind::STRING) { }
-EvaluationValue::EvaluationValue(std::shared_ptr<UIElement> e) : data(std::move(e)), kind_(Kind::UIELEMENT)
-{
- ASSERT(data.uiElement);
-}
-EvaluationValue::EvaluationValue(Point p) : data(p), kind_(Kind::POINT) { }
-EvaluationValue::EvaluationValue(FunctionType f) : data(std::move(f)), kind_(Kind::FUNCTION)
-{
- ASSERT(data.function);
-}
-EvaluationValue::EvaluationValue(FunctionType::Type f) : EvaluationValue(FunctionType{std::move(f)}) { }
-EvaluationValue::EvaluationValue(VectorType f) : data(std::make_shared<VectorType>(std::move(f))), kind_(Kind::VECTOR) { }
-EvaluationValue::EvaluationValue(SetType f) : data(std::make_shared<SetType>(std::move(f))), kind_(Kind::SET) { }
-EvaluationValue::EvaluationValue(DictType f) : data(std::make_shared<DictType>(std::move(f))), kind_(Kind::DICT) { }
size_t EvaluationValueKey::calculateHash(const EvaluationValue &self)
{
switch (self.kind()) {
- case EvaluationValue::Kind::STRING:
- return std::hash<std::string>()(self.asString());
- case EvaluationValue::Kind::INTEGER:
- return std::hash<int>()(self.asInteger());
- case EvaluationValue::Kind::DOUBLE:
- return std::hash<double>()(self.asDouble());
- case EvaluationValue::Kind::UIELEMENT:
- return std::hash<std::string>()(Atspi::getUniqueId(self.asUiElement()->getObject()));
- case EvaluationValue::Kind::BOOLEAN:
- return std::hash<bool>()(self.asBoolean());
- case EvaluationValue::Kind::POINT:
- return std::hash<int>()(self.asPoint().x) ^ std::hash<int>()(self.asPoint().y);
- case EvaluationValue::Kind::EMPTY:
+ case detail::Kind::STRING:
+ return std::hash<std::string>()(self.as<std::string>());
+ case detail::Kind::INTEGER:
+ return std::hash<int>()(self.as<int>());
+ case detail::Kind::DOUBLE:
+ return std::hash<double>()(self.as<double>());
+ case detail::Kind::UIELEMENT:
+ return std::hash<std::string>()(Atspi::getUniqueId(self.as<std::shared_ptr<UIElement>>()->getObject()));
+ case detail::Kind::BOOLEAN:
+ return std::hash<bool>()(self.as<bool>());
+ case detail::Kind::POINT:
+ return (std::hash<size_t>()(self.as<Point>().x) << 16) ^ std::hash<size_t>()(self.as<Point>().y);
+ case detail::Kind::EMPTY:
return 0;
- case EvaluationValue::Kind::FUNCTION:
- case EvaluationValue::Kind::SET:
- case EvaluationValue::Kind::VECTOR:
- case EvaluationValue::Kind::DICT:
+ case detail::Kind::FUNCTION:
+ case detail::Kind::SET:
+ case detail::Kind::VECTOR:
+ case detail::Kind::DICT:
break;
}
throw EvaluationFailure{} << "can't calculate hash for value of type " << EvaluationValue::toString(self.kind());
return getValue() == k.getValue();
}
-const std::string &EvaluationValue::asString() const
-{
- return data.string;
-}
-int EvaluationValue::asInteger() const
-{
- return data.integer;
-}
-const std::shared_ptr<UIElement> &EvaluationValue::asUiElement() const
-{
- return data.uiElement;
-}
-bool EvaluationValue::asBoolean() const
-{
- return data.boolean;
-}
-Point EvaluationValue::asPoint() const
-{
- return data.point;
-}
-double EvaluationValue::asDouble() const
-{
- return data.double_;
-}
-const EvaluationValue::FunctionType::Type &EvaluationValue::asFunctionType() const
-{
- return data.function;
-}
-EvaluationValue::VectorType &EvaluationValue::asVector() const
-{
- return *data.vector;
-}
-EvaluationValue::SetType &EvaluationValue::asSet() const
-{
- return *data.set;
-}
-EvaluationValue::DictType &EvaluationValue::asDict() const
-{
- return *data.dict;
-}
-
std::ostream &operator << (std::ostream &s, const EvaluationValue &v)
{
switch (v.kind()) {
- case EvaluationValue::Kind::EMPTY:
+ case detail::Kind::EMPTY:
s << "{}";
break;
- case EvaluationValue::Kind::STRING:
+ case detail::Kind::STRING:
s << "'" << v.data.string << "'";
break;
- case EvaluationValue::Kind::INTEGER:
+ case detail::Kind::INTEGER:
s << v.data.integer;
break;
- case EvaluationValue::Kind::DOUBLE:
+ case detail::Kind::DOUBLE:
s << v.data.double_;
break;
- case EvaluationValue::Kind::UIELEMENT:
+ case detail::Kind::UIELEMENT:
s << Atspi::getUniqueId(v.data.uiElement->getObject());
break;
- case EvaluationValue::Kind::BOOLEAN:
+ case detail::Kind::BOOLEAN:
s << (v.data.boolean ? "true" : "false");
break;
- case EvaluationValue::Kind::POINT:
+ case detail::Kind::POINT:
s << "<" << v.data.point.x << ", " << v.data.point.y << ">";
break;
- case EvaluationValue::Kind::FUNCTION:
+ case detail::Kind::FUNCTION:
s << "functor";
break;
- case EvaluationValue::Kind::VECTOR: {
+ case detail::Kind::VECTOR: {
s << "[";
bool first = true;
for (auto &a : *v.data.vector) {
s << " ]";
break;
}
- case EvaluationValue::Kind::SET: {
+ case detail::Kind::SET: {
s << "{";
bool first = true;
for (auto &a : *v.data.set) {
s << " }";
break;
}
- case EvaluationValue::Kind::DICT: {
+ case detail::Kind::DICT: {
s << "{";
bool first = true;
for (auto &a : *v.data.dict) {
return s << v.getValue();
}
-EvaluationValue::EvaluationValue(const EvaluationValue &v)
-{
- copyFrom(v);
-}
-EvaluationValue::EvaluationValue(EvaluationValue &&v)
-{
- moveFrom(v);
-}
-EvaluationValue::~EvaluationValue()
-{
- destroy();
-}
-EvaluationValue &EvaluationValue::operator = (const EvaluationValue &v)
-{
- copyFrom(v);
- return *this;
-}
-EvaluationValue &EvaluationValue::operator = (EvaluationValue &&v)
-{
- moveFrom(v);
- return *this;
-}
-
-EvaluationValue::Kind EvaluationValue::kind() const
+detail::Kind EvaluationValue::kind() const
{
return kind_;
}
-void EvaluationValue::destroy()
-{
- switch (kind()) {
- case Kind::EMPTY:
- break;
- case Kind::STRING:
- data.string = {};
- break;
- case Kind::INTEGER:
- break;
- case Kind::DOUBLE:
- break;
- case Kind::UIELEMENT:
- data.uiElement = {};
- break;
- case Kind::BOOLEAN:
- break;
- case Kind::POINT:
- break;
- case Kind::FUNCTION:
- data.function = {};
- break;
- case Kind::VECTOR:
- data.vector = {};
- break;
- case Kind::SET:
- data.set = {};
- break;
- case Kind::DICT:
- data.dict = {};
- break;
- }
- kind_ = Kind::EMPTY;
-}
-
-void EvaluationValue::copyFrom(const EvaluationValue &src)
-{
- if (this != &src) {
- destroy();
- kind_ = src.kind();
- switch (kind()) {
- case Kind::EMPTY:
- break;
- case Kind::STRING:
- data.string = src.data.string;
- break;
- case Kind::INTEGER:
- data.integer = src.data.integer;
- break;
- case Kind::DOUBLE:
- data.double_ = src.data.double_;
- break;
- case Kind::UIELEMENT:
- data.uiElement = src.data.uiElement;
- break;
- case Kind::BOOLEAN:
- data.boolean = src.data.boolean;
- break;
- case Kind::POINT:
- data.point = src.data.point;
- break;
- case Kind::FUNCTION:
- data.function = src.data.function;
- break;
- case Kind::VECTOR:
- data.vector = src.data.vector;
- break;
- case Kind::SET:
- data.set = src.data.set;
- break;
- case Kind::DICT:
- data.dict = src.data.dict;
- break;
- }
- }
-}
-
-void EvaluationValue::moveFrom(EvaluationValue &src)
-{
- if (this != &src) {
- destroy();
- kind_ = src.kind();
- switch (kind()) {
- case Kind::EMPTY:
- break;
- case Kind::STRING:
- data.string = std::move(src.data.string);
- break;
- case Kind::INTEGER:
- data.integer = src.data.integer;
- break;
- case Kind::DOUBLE:
- data.double_ = src.data.double_;
- break;
- case Kind::UIELEMENT:
- data.uiElement = std::move(src.data.uiElement);
- break;
- case Kind::BOOLEAN:
- data.boolean = src.data.boolean;
- break;
- case Kind::POINT:
- data.point = src.data.point;
- break;
- case Kind::FUNCTION:
- data.function = std::move(src.data.function);
- break;
- case Kind::VECTOR:
- data.vector = std::move(src.data.vector);
- break;
- case Kind::SET:
- data.set = std::move(src.data.set);
- break;
- case Kind::DICT:
- data.dict = std::move(src.data.dict);
- break;
- }
- }
-}
-
bool EvaluationValue::operator == (const EvaluationValue &other) const
{
if (kind() != other.kind()) {
- if (kind() == Kind::INTEGER && other.kind() == Kind::DOUBLE)
- return static_cast<double>(asInteger()) == other.asDouble();
- if (kind() == Kind::DOUBLE && other.kind() == Kind::INTEGER)
- return static_cast<double>(other.asInteger()) == asDouble();
+ if (kind() == detail::Kind::INTEGER && other.kind() == detail::Kind::DOUBLE)
+ return static_cast<double>(as<int>()) == other.as<double>();
+ if (kind() == detail::Kind::DOUBLE && other.kind() == detail::Kind::INTEGER)
+ return static_cast<double>(other.as<int>()) == as<double>();
return false;
}
switch (kind()) {
- case Kind::EMPTY:
+ case detail::Kind::EMPTY:
return true;
- case Kind::STRING:
- return data.string == other.data.string;
- case Kind::INTEGER:
- return data.integer == other.data.integer;
- case Kind::DOUBLE:
- return data.double_ == other.data.double_;
- case Kind::UIELEMENT:
- return Atspi::getUniqueId(data.uiElement->getObject()) == Atspi::getUniqueId(other.data.uiElement->getObject());
- case Kind::BOOLEAN:
- return data.boolean == other.data.boolean;
- case Kind::POINT:
- return data.point == other.data.point;
- case Kind::VECTOR:
- return *data.vector == *other.data.vector;
- case Kind::SET:
- return *data.set == *other.data.set;
- case Kind::DICT:
- return *data.dict == *other.data.dict;
- case Kind::FUNCTION:
+ case detail::Kind::STRING:
+ return as<std::string>() == other.as<std::string>();
+ case detail::Kind::INTEGER:
+ return as<int>() == other.as<int>();
+ case detail::Kind::DOUBLE:
+ return as<int>() == other.as<int>();
+ case detail::Kind::UIELEMENT:
+ return Atspi::getUniqueId(as<std::shared_ptr<UIElement>>()->getObject()) ==
+ Atspi::getUniqueId(other.as<std::shared_ptr<UIElement>>()->getObject());
+ case detail::Kind::BOOLEAN:
+ return as<bool>() == other.as<bool>();
+ case detail::Kind::POINT:
+ return as<Point>() == other.as<Point>();
+ case detail::Kind::VECTOR:
+ return as<detail::VectorType>() == other.as<detail::VectorType>();
+ case detail::Kind::SET:
+ return as<detail::SetType>() == other.as<detail::SetType>();
+ case detail::Kind::DICT:
+ return as<detail::DictType>() == other.as<detail::DictType>();
+ case detail::Kind::FUNCTION:
throw EvaluationFailure{} << "can't compare " << EvaluationValue::toString(kind()) <<
" with " << EvaluationValue::toString(other.kind());
};
bool EvaluationValue::operator < (const EvaluationValue &other) const
{
if (kind() != other.kind()) {
- if (kind() == Kind::INTEGER && other.kind() == Kind::DOUBLE)
- return static_cast<double>(asInteger()) < other.asDouble();
- if (kind() == Kind::DOUBLE && other.kind() == Kind::INTEGER)
- return asDouble() < static_cast<double>(other.asInteger());
+ if (kind() == detail::Kind::INTEGER && other.kind() == detail::Kind::DOUBLE)
+ return static_cast<double>(as<int>()) < other.as<double>();
+ if (kind() == detail::Kind::DOUBLE && other.kind() == detail::Kind::INTEGER)
+ return as<double>() < static_cast<double>(other.as<int>());
} else {
switch (kind()) {
- case Kind::EMPTY:
+ case detail::Kind::EMPTY:
break;
- case Kind::STRING:
- return data.string < other.data.string;
- case Kind::INTEGER:
- return data.integer < other.data.integer;
- case Kind::DOUBLE:
- return data.double_ < other.data.double_;
- case Kind::UIELEMENT:
+ case detail::Kind::STRING:
+ return as<std::string>() < other.as<std::string>();
+ case detail::Kind::INTEGER:
+ return as<int>() < other.as<int>();
+ case detail::Kind::DOUBLE:
+ return as<double>() < other.as<double>();
+ case detail::Kind::UIELEMENT:
break;
- case Kind::BOOLEAN:
+ case detail::Kind::BOOLEAN:
break;
- case Kind::POINT:
+ case detail::Kind::POINT:
break;
- case Kind::FUNCTION:
+ case detail::Kind::FUNCTION:
break;
- case Kind::VECTOR:
- for (auto i = 0u; i < std::min(asVector().size(), other.asVector().size()); ++i) {
- if (asVector()[i] < other.asVector()[i]) return true;
- if (!(asVector()[i] == other.asVector()[i])) return false;
+ case detail::Kind::VECTOR:
+ for (auto i = 0u; i < std::min(as<detail::VectorType>().size(), other.as<detail::VectorType>().size()); ++i) {
+ if (as<detail::VectorType>()[i] < other.as<detail::VectorType>()[i]) return true;
+ if (!(as<detail::VectorType>()[i] == other.as<detail::VectorType>()[i])) return false;
}
- return asVector().size() < other.asVector().size();
- case Kind::SET:
+ return as<detail::VectorType>().size() < other.as<detail::VectorType>().size();
+ case detail::Kind::SET:
break;
- case Kind::DICT:
+ case detail::Kind::DICT:
break;
};
}
EvaluationValue::operator bool () const
{
switch (kind()) {
- case EvaluationValue::Kind::INTEGER:
- return asInteger() != 0;
- case EvaluationValue::Kind::DOUBLE:
- return asDouble() != 0;
- case EvaluationValue::Kind::BOOLEAN:
- return asBoolean();
- case EvaluationValue::Kind::STRING:
- return !asString().empty();
- case EvaluationValue::Kind::UIELEMENT:
+ case detail::Kind::INTEGER:
+ return as<int>() != 0;
+ case detail::Kind::DOUBLE:
+ return as<double>() != 0;
+ case detail::Kind::BOOLEAN:
+ return as<bool>();
+ case detail::Kind::STRING:
+ return !as<std::string>().empty();
+ case detail::Kind::UIELEMENT:
return true;
- case EvaluationValue::Kind::FUNCTION:
+ case detail::Kind::FUNCTION:
return true;
- case EvaluationValue::Kind::POINT:
+ case detail::Kind::POINT:
return true;
- case EvaluationValue::Kind::VECTOR:
- return !asVector().empty();
- case EvaluationValue::Kind::SET:
- return !asSet().empty();
- case EvaluationValue::Kind::DICT:
- return !asDict().empty();
- case EvaluationValue::Kind::EMPTY:
+ case detail::Kind::VECTOR:
+ return !as<detail::VectorType>().empty();
+ case detail::Kind::SET:
+ return !as<detail::SetType>().empty();
+ case detail::Kind::DICT:
+ return !as<detail::DictType>().empty();
+ case detail::Kind::EMPTY:
return false;
}
ASSERT(0); // every type has a true / false value in boolean context
{
int ConvertTo<int>::convert(EvaluationContext &ec, EvaluationValue e)
{
- if (e.kind() == EvaluationValue::Kind::INTEGER) return e.asInteger();
- if (e.kind() == EvaluationValue::Kind::DOUBLE) {
- if (static_cast<double>(static_cast<int>(e.asDouble())) == e.asDouble()) {
- return static_cast<int>(e.asDouble());
+ if (e.kind() == detail::Kind::INTEGER) return e.as<int>();
+ if (e.kind() == detail::Kind::DOUBLE) {
+ if (static_cast<double>(static_cast<int>(e.as<double>())) == e.as<double>()) {
+ return static_cast<int>(e.as<double>());
}
- } else if (e.kind() == EvaluationValue::Kind::STRING) {
- auto text = e.asString();
+ } else if (e.kind() == detail::Kind::STRING) {
+ auto text = e.as<std::string>();
size_t pos = 0;
auto value = std::stoi(text, &pos);
if (pos == text.size())
return value;
}
throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::INTEGER);
+ " to " << EvaluationValue::toString(detail::Kind::INTEGER);
}
double ConvertTo<double>::convert(EvaluationContext &ec, EvaluationValue e)
{
- if (e.kind() == EvaluationValue::Kind::INTEGER) return e.asInteger();
- if (e.kind() == EvaluationValue::Kind::DOUBLE) return e.asDouble();
- if (e.kind() == EvaluationValue::Kind::STRING) {
- auto text = e.asString();
+ if (e.kind() == detail::Kind::INTEGER) return e.as<int>();
+ if (e.kind() == detail::Kind::DOUBLE) return e.as<double>();
+ if (e.kind() == detail::Kind::STRING) {
+ auto text = e.as<std::string>();
size_t pos = 0;
auto value = std::stod(text, &pos);
if (pos == text.size())
return value;
}
throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::DOUBLE);
+ " to " << EvaluationValue::toString(detail::Kind::DOUBLE);
}
std::string ConvertTo<std::string>::convert(EvaluationContext &ec, EvaluationValue e)
{
- if (e.kind() == EvaluationValue::Kind::INTEGER) return std::to_string(e.asInteger());
- if (e.kind() == EvaluationValue::Kind::BOOLEAN) return e.asBoolean() ? "true" : "false";
- if (e.kind() == EvaluationValue::Kind::STRING) return e.asString();
- if (e.kind() == EvaluationValue::Kind::POINT)
- return "<" + std::to_string(e.asPoint().x) + ", " + std::to_string(e.asPoint().y) + ">";
+ if (e.kind() == detail::Kind::INTEGER) return std::to_string(e.as<int>());
+ if (e.kind() == detail::Kind::BOOLEAN) return e.as<bool>() ? "true" : "false";
+ if (e.kind() == detail::Kind::STRING) return e.as<std::string>();
+ if (e.kind() == detail::Kind::POINT)
+ return "<" + std::to_string(e.as<Point>().x) + ", " + std::to_string(e.as<Point>().y) + ">";
throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::STRING);
+ " to " << EvaluationValue::toString(detail::Kind::STRING);
}
bool ConvertTo<bool>::convert(EvaluationContext &ec, EvaluationValue e)
{
}
std::shared_ptr<UIElement> ConvertTo<std::shared_ptr<UIElement>>::convert(EvaluationContext &ec, EvaluationValue e)
{
- if (e.kind() == EvaluationValue::Kind::UIELEMENT) return std::move(e.asUiElement());
- if (e.kind() == EvaluationValue::Kind::POINT) return ec.executionInterface().convert(e.asPoint());
- if (e.kind() == EvaluationValue::Kind::STRING) return ec.executionInterface().convert(e.asString());
+ if (e.kind() == detail::Kind::UIELEMENT) return std::move(e.as<std::shared_ptr<UIElement>>());
+ if (e.kind() == detail::Kind::POINT) return ec.executionInterface().convert(e.as<Point>());
+ if (e.kind() == detail::Kind::STRING) return ec.executionInterface().convert(e.as<std::string>());
throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::UIELEMENT);
+ " to " << EvaluationValue::toString(detail::Kind::UIELEMENT);
}
EvaluationValue ConvertTo<EvaluationValue>::convert(EvaluationContext &ec, EvaluationValue e)
{
}
Point ConvertTo<Point>::convert(EvaluationContext &ec, EvaluationValue e)
{
- if (e.kind() == EvaluationValue::Kind::POINT) return e.asPoint();
+ if (e.kind() == detail::Kind::POINT) return e.as<Point>();
throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::POINT);
+ " to " << EvaluationValue::toString(detail::Kind::POINT);
+ }
+
+ template <> std::string &get<std::string>(detail::Data &d)
+ {
+ return d.string;
+ }
+ template <> int &get<int>(detail::Data &d)
+ {
+ return d.integer;
+ }
+ template <> std::shared_ptr<UIElement> &get<std::shared_ptr<UIElement>>(detail::Data &d)
+ {
+ return d.uiElement;
+ }
+ template <> bool &get<bool>(detail::Data &d)
+ {
+ return d.boolean;
+ }
+ template <> double &get<double>(detail::Data &d)
+ {
+ return d.double_;
+ }
+ template <> Point &get<Point>(detail::Data &d)
+ {
+ return d.point;
+ }
+ template <> FunctionType &get<detail::FunctionType>(detail::Data &d)
+ {
+ return d.function;
+ }
+ template <> VectorType &get<detail::VectorType>(detail::Data &d)
+ {
+ return *d.vector;
+ }
+ template <> SetType &get<detail::SetType>(detail::Data &d)
+ {
+ return *d.set;
+ }
+ template <> DictType &get<detail::DictType>(detail::Data &d)
+ {
+ return *d.dict;
+ }
+
+ template <> std::string get<std::string>(const detail::Data &d)
+ {
+ return d.string;
+ }
+ template <> int get<int>(const detail::Data &d)
+ {
+ return d.integer;
+ }
+ template <> std::shared_ptr<UIElement> get<std::shared_ptr<UIElement>>(const detail::Data &d)
+ {
+ return d.uiElement;
+ }
+ template <> bool get<bool>(const detail::Data &d)
+ {
+ return d.boolean;
+ }
+ template <> double get<double>(const detail::Data &d)
+ {
+ return d.double_;
+ }
+ template <> Point get<Point>(const detail::Data &d)
+ {
+ return d.point;
+ }
+ template <> FunctionType get<detail::FunctionType>(const detail::Data &d)
+ {
+ return d.function;
+ }
+ template <> VectorType get<detail::VectorType>(const detail::Data &d)
+ {
+ return *d.vector;
+ }
+ template <> SetType get<detail::SetType>(const detail::Data &d)
+ {
+ return *d.set;
+ }
+ template <> DictType get<detail::DictType>(const detail::Data &d)
+ {
+ return *d.dict;
}
};
#include <tuple>
#include <ostream>
-class EvaluationValue;
class EvaluationContext;
+class EvaluationFailure;
+class EvaluationValue;
+class EvaluationValueKey
+{
+public:
+ EvaluationValueKey() = default;
+ EvaluationValueKey(EvaluationValue val);
+ EvaluationValueKey(EvaluationValue val, size_t hash);
+
+ const EvaluationValue &getValue() const
+ {
+ return *value;
+ }
+ operator const EvaluationValue &() const
+ {
+ return *value;
+ }
+
+ size_t getHash() const
+ {
+ return hash;
+ }
+
+ bool operator == (const EvaluationValueKey &k) const;
+
+ friend std::ostream &operator << (std::ostream &s, const EvaluationValue &v);
+
+ static size_t calculateHash(const EvaluationValue &v);
+private:
+ std::shared_ptr<EvaluationValue> value;
+ size_t hash = 0;
+};
+
+namespace std
+{
+ template <> struct hash<EvaluationValueKey> {
+ size_t operator()(const EvaluationValueKey &v) const
+ {
+ return v.getHash();
+ }
+ };
+}
+
class EvaluationFailure : public std::exception
{
public:
{
}
};
-}
-
-class EvaluationValue;
-class EvaluationValueKey
-{
-public:
- EvaluationValueKey() = default;
- EvaluationValueKey(EvaluationValue val);
- EvaluationValueKey(EvaluationValue val, size_t hash);
-
- const EvaluationValue &getValue() const
- {
- return *value;
- }
- operator const EvaluationValue &() const
- {
- return *value;
- }
-
- size_t getHash() const
- {
- return hash;
- }
-
- bool operator == (const EvaluationValueKey &k) const;
-
- friend std::ostream &operator << (std::ostream &s, const EvaluationValue &v);
-
- static size_t calculateHash(const EvaluationValue &v);
-private:
- std::shared_ptr<EvaluationValue> value;
- size_t hash = 0;
-};
-
-namespace std
-{
- template <> struct hash<EvaluationValueKey> {
- size_t operator()(const EvaluationValueKey &v) const
- {
- return v.getHash();
- }
- };
-}
-class EvaluationValue
-{
-public:
class FunctionType
{
public:
{
return bool(function);
}
- auto operator()(EvaluationContext &ec, std::vector<EvaluationValue> args) const
+
+ template <typename ... ARGS> auto operator()(ARGS &&... args) const
{
- return function(ec, std::move(args));
+ return function(std::forward<ARGS>(args)...);
}
+ private:
Type function;
};
template <typename ... ARGS> class UserFunctionType : public FunctionType
UserFunctionType(std::function<EvaluationValue(EvaluationContext &, ARGS...)> f) :
FunctionType(constructConvertingArgsFunction(std::move(f))) { }
private:
- static Type constructConvertingArgsFunction(std::function<EvaluationValue(EvaluationContext &, ARGS...)> f)
- {
- return [f = std::move(f)](EvaluationContext & ec, std::vector<EvaluationValue> sourceArgs) -> EvaluationValue {
- std::tuple<ARGS...> args;
- detail::Converter<0, sizeof...(ARGS)>::convert(ec, args, sourceArgs);
- return detail::apply(f, ec, args);
- };
- }
+ static Type constructConvertingArgsFunction(std::function<EvaluationValue(EvaluationContext &, ARGS...)> f);
};
+
using VectorType = std::vector<EvaluationValue>;
using SetType = std::unordered_set<EvaluationValueKey>;
using DictType = std::unordered_map<EvaluationValueKey, EvaluationValue>;
STRING, INTEGER, DOUBLE, UIELEMENT, BOOLEAN, POINT, FUNCTION, VECTOR, SET, DICT
};
- static std::string toString(Kind k);
-
- EvaluationValue();
- EvaluationValue(std::nullptr_t);
- EvaluationValue(const EvaluationValue &);
- EvaluationValue(EvaluationValue &&);
- EvaluationValue(int integer);
- EvaluationValue(bool boolean);
- EvaluationValue(double double_);
- EvaluationValue(std::string);
- EvaluationValue(std::shared_ptr<UIElement>);
- EvaluationValue(Point);
- EvaluationValue(VectorType);
- EvaluationValue(SetType);
- EvaluationValue(DictType);
- EvaluationValue(FunctionType);
- EvaluationValue(FunctionType::Type);
- template <typename T> EvaluationValue(const std::vector<T> &v) : EvaluationValue(VectorType{ v.begin(), v.end() }) { }
- template <typename T> EvaluationValue(const std::unordered_set<T> &v) : EvaluationValue(SetType{ v.begin(), v.end() }) { }
- template <typename K, typename V> EvaluationValue(const std::unordered_map<K, V> &v) : EvaluationValue(DictType{ v.begin(), v.end() }) { }
- ~EvaluationValue();
-
- EvaluationValue &operator = (const EvaluationValue &);
- EvaluationValue &operator = (EvaluationValue &&);
-
- Kind kind() const;
- const std::string &asString() const;
- int asInteger() const;
- const std::shared_ptr<UIElement> &asUiElement() const;
- bool asBoolean() const;
- Point asPoint() const;
- double asDouble() const;
- const FunctionType::Type &asFunctionType() const;
- VectorType &asVector() const;
- SetType &asSet() const;
- DictType &asDict() const;
-
- bool operator == (const EvaluationValue &other) const;
- bool operator < (const EvaluationValue &other) const;
- bool operator != (const EvaluationValue &other) const;
- bool operator > (const EvaluationValue &other) const;
- bool operator <= (const EvaluationValue &other) const;
- bool operator >= (const EvaluationValue &other) const;
-
- explicit operator bool () const;
-
- friend std::ostream &operator << (std::ostream &s, const EvaluationValue &v);
-private:
- void destroy();
- void copyFrom(const EvaluationValue &src);
- void moveFrom(EvaluationValue &src);
-
+ template <typename T> struct TypeToKind;
+ template <> struct TypeToKind<std::string> {
+ static constexpr auto kind = Kind::STRING;
+ };
+ template <> struct TypeToKind<int> {
+ static constexpr auto kind = Kind::INTEGER;
+ };
+ template <> struct TypeToKind<double> {
+ static constexpr auto kind = Kind::DOUBLE;
+ };
+ template <> struct TypeToKind<std::shared_ptr<UIElement>> {
+ static constexpr auto kind = Kind::UIELEMENT;
+ };
+ template <> struct TypeToKind<bool> {
+ static constexpr auto kind = Kind::BOOLEAN;
+ };
+ template <> struct TypeToKind<Point> {
+ static constexpr auto kind = Kind::STRING;
+ };
+ template <> struct TypeToKind<FunctionType> {
+ static constexpr auto kind = Kind::FUNCTION;
+ };
+ template <> struct TypeToKind<VectorType> {
+ static constexpr auto kind = Kind::VECTOR;
+ };
+ template <> struct TypeToKind<SetType> {
+ static constexpr auto kind = Kind::SET;
+ };
+ template <> struct TypeToKind<DictType> {
+ static constexpr auto kind = Kind::DICT;
+ };
+ template <typename ... ARGS> struct TypeToKind<UserFunctionType<ARGS...>> {
+ static constexpr auto kind = Kind::FUNCTION;
+ };
+ template <typename R, typename ... ARGS> struct TypeToKind<std::function<R(ARGS...)>> {
+ static constexpr auto kind = Kind::FUNCTION;
+ };
+ template <typename T> struct TypeToKind<std::vector<T>> {
+ static constexpr auto kind = Kind::VECTOR;
+ };
+ template <typename T> struct TypeToKind<std::unordered_set<T>> {
+ static constexpr auto kind = Kind::SET;
+ };
+ template <typename K, typename V> struct TypeToKind<std::unordered_map<K, V>> {
+ static constexpr auto kind = Kind::DICT;
+ };
// TODO: turn it into c++17 std::variant, when we upgrade to c++17
// although current version ain't optimal, it's not big of a deal
// as it's only used for testing and any DBUS call will be
bool boolean = false;
double double_ = 0;
Point point;
- FunctionType::Type function;
+ FunctionType function;
std::shared_ptr<VectorType> vector;
std::shared_ptr<SetType> set;
std::shared_ptr<DictType> dict;
Data(std::shared_ptr<UIElement>);
Data(Point);
Data(FunctionType);
- Data(std::shared_ptr<SetType>);
- Data(std::shared_ptr<DictType>);
- Data(std::shared_ptr<VectorType>);
- } data;
- Kind kind_ = Kind::EMPTY;
+ Data(SetType);
+ Data(DictType);
+ Data(VectorType);
+ template <typename T> Data(std::vector<T> t) : Data(VectorType{ t.begin(), t.end() }) { }
+ template <typename T> Data(std::unordered_set<T> t) : Data(SetType{ t.begin(), t.end() }) { }
+ template <typename K, typename V> Data(std::unordered_map<K, V> t) : Data(DictType{ t.begin(), t.end() }) { }
+ };
+
+ template <typename T> T &get(detail::Data &d) = delete;
+ template <> std::string &get<std::string>(detail::Data &d);
+ template <> int &get<int>(detail::Data &d);
+ template <> std::shared_ptr<UIElement> &get<std::shared_ptr<UIElement>>(detail::Data &d);
+ template <> bool &get<bool>(detail::Data &d);
+ template <> double &get<double>(detail::Data &d);
+ template <> Point &get<Point>(detail::Data &d);
+ template <> FunctionType &get<detail::FunctionType>(detail::Data &d);
+ template <> VectorType &get<detail::VectorType>(detail::Data &d);
+ template <> SetType &get<detail::SetType>(detail::Data &d);
+ template <> DictType &get<detail::DictType>(detail::Data &d);
+
+ template <typename T> T get(const detail::Data &d) = delete;
+ template <> std::string get<std::string>(const detail::Data &d);
+ template <> int get<int>(const detail::Data &d);
+ template <> std::shared_ptr<UIElement> get<std::shared_ptr<UIElement>>(const detail::Data &d);
+ template <> bool get<bool>(const detail::Data &d);
+ template <> double get<double>(const detail::Data &d);
+ template <> Point get<Point>(const detail::Data &d);
+ template <> FunctionType get<detail::FunctionType>(const detail::Data &d);
+ template <> VectorType get<detail::VectorType>(const detail::Data &d);
+ template <> SetType get<detail::SetType>(const detail::Data &d);
+ template <> DictType get<detail::DictType>(const detail::Data &d);
+}
+
+class EvaluationValue
+{
+public:
+ static std::string toString(detail::Kind k);
+
+ EvaluationValue() = default;
+ EvaluationValue(std::nullptr_t) {}
+ template <typename T, typename = typename std::enable_if<std::is_constructible<detail::Data, T>::value, void *>::type>
+ EvaluationValue(T && t) : data(std::move(t)), kind_(detail::TypeToKind<typename std::decay<T>::type>::kind) { }
+ EvaluationValue(const EvaluationValue &) = default;
+ EvaluationValue(EvaluationValue &&) = default;
+ ~EvaluationValue() = default;
+
+ EvaluationValue &operator = (const EvaluationValue &) = default;
+ EvaluationValue &operator = (EvaluationValue &&) = default;
+
+ detail::Kind kind() const;
+ template <typename T> auto &as()
+ {
+ ASSERT(kind() == detail::TypeToKind<typename std::decay<T>::type>::kind);
+ return detail::get<T>(data);
+ }
+ template <typename T> auto as() const
+ {
+ ASSERT(kind() == detail::TypeToKind<typename std::decay<T>::type>::kind);
+ return detail::get<T>(data);
+ }
+
+ bool operator == (const EvaluationValue &other) const;
+ bool operator < (const EvaluationValue &other) const;
+ bool operator != (const EvaluationValue &other) const;
+ bool operator > (const EvaluationValue &other) const;
+ bool operator <= (const EvaluationValue &other) const;
+ bool operator >= (const EvaluationValue &other) const;
+
+ explicit operator bool () const;
+
+ friend std::ostream &operator << (std::ostream &s, const EvaluationValue &v);
+private:
+ detail::Data data;
+ detail::Kind kind_ = detail::Kind::EMPTY;
};
namespace detail
{
std::vector<T> result;
- if (e.kind() == EvaluationValue::Kind::VECTOR) {
- result.reserve(e.asVector().size());
- for (auto &e : e.asVector()) {
+ if (e.kind() == detail::Kind::VECTOR) {
+ result.reserve(e.as<VectorType>().size());
+ for (auto &e : e.as<VectorType>()) {
result.push_back(ConvertTo<T>::convert(ec, e));
}
- } else if (e.kind() == EvaluationValue::Kind::SET) {
- result.reserve(e.asSet().size());
- for (auto &e : e.asSet()) {
+ } else if (e.kind() == detail::Kind::SET) {
+ result.reserve(e.as<SetType>().size());
+ for (auto &e : e.as<SetType>()) {
result.push_back(ConvertTo<T>::convert(ec, e));
}
- } else if (e.kind() == EvaluationValue::Kind::DICT) {
- result.reserve(e.asDict().size());
- for (auto &e : e.asDict()) {
+ } else if (e.kind() == detail::Kind::DICT) {
+ result.reserve(e.as<DictType>().size());
+ for (auto &e : e.as<DictType>()) {
result.push_back(ConvertTo<T>::convert(ec, e.first));
}
} else throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::VECTOR);
+ " to " << EvaluationValue::toString(detail::Kind::VECTOR);
return std::move(result);
}
template <typename T> std::unordered_set<T> ConvertTo<std::unordered_set<T>>::convert(EvaluationContext &ec, EvaluationValue e)
{
std::unordered_set<T> result;
- if (e.kind() == EvaluationValue::Kind::VECTOR) {
- result.reserve(e.asVector().size());
- for (auto &e : e.asVector()) {
+ if (e.kind() == detail::Kind::VECTOR) {
+ result.reserve(e.as<VectorType>().size());
+ for (auto &e : e.as<VectorType>()) {
result.insert(ConvertTo<T>::convert(ec, e));
}
- } else if (e.kind() == EvaluationValue::Kind::SET) {
- result.reserve(e.asSet().size());
- for (auto &e : e.asSet()) {
+ } else if (e.kind() == detail::Kind::SET) {
+ result.reserve(e.as<SetType>().size());
+ for (auto &e : e.as<SetType>()) {
result.insert(ConvertTo<T>::convert(ec, e));
}
- } else if (e.kind() == EvaluationValue::Kind::DICT) {
- result.reserve(e.asDict().size());
- for (auto &e : e.asDict()) {
+ } else if (e.kind() == detail::Kind::DICT) {
+ result.reserve(e.as<DictType>().size());
+ for (auto &e : e.as<DictType>()) {
result.insert(ConvertTo<T>::convert(ec, e.first));
}
} else throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::VECTOR);
+ " to " << EvaluationValue::toString(detail::Kind::VECTOR);
return std::move(result);
}
template <typename K, typename V> std::unordered_map<K, V> ConvertTo<std::unordered_map<K, V>>::convert(EvaluationContext &ec, EvaluationValue e)
{
std::unordered_map<K, V> result;
- if (e.kind() == EvaluationValue::Kind::DICT) {
- result.reserve(e.asDict().size());
- for (auto &e : e.asDict()) {
+ if (e.kind() == detail::Kind::DICT) {
+ result.reserve(e.as<DictType>().size());
+ for (auto &e : e.as<DictType>()) {
auto k = ConvertTo<K>::convert(ec, e.first);
auto v = ConvertTo<V>::convert(ec, e.second);
result.insert({ k, v });
}
} else throw EvaluationFailure{} << "can't convert from " << EvaluationValue::toString(e.kind()) <<
- " to " << EvaluationValue::toString(EvaluationValue::Kind::VECTOR);
+ " to " << EvaluationValue::toString(detail::Kind::VECTOR);
return std::move(result);
}
+ template <typename ... ARGS>
+ auto UserFunctionType<ARGS...>::constructConvertingArgsFunction(std::function<EvaluationValue(EvaluationContext &, ARGS...)> f) -> Type
+ {
+ return [f = std::move(f)](EvaluationContext & ec, std::vector<EvaluationValue> sourceArgs) -> EvaluationValue {
+ constexpr auto expectedArgs = sizeof...(ARGS);
+ if (sourceArgs.size() < expectedArgs)
+ throw EvaluationFailure{} << "not enough arguments, expected " << expectedArgs << ", got " << sourceArgs.size();
+ if (sourceArgs.size() > expectedArgs)
+ throw EvaluationFailure{} << "too many arguments, expected " << expectedArgs << ", got " << sourceArgs.size();
+ std::tuple<ARGS...> args;
+ detail::Converter<0, sizeof...(ARGS)>::convert(ec, args, sourceArgs);
+ return detail::apply(f, ec, args);
+ };
+ }
}
#endif
#include <string>
#include <iomanip>
+using detail::VectorType;
+using detail::SetType;
+using detail::FunctionType;
+using detail::DictType;
+
TokenLocation Evaluator::location() const
{
return tokenLocation;
return { std::move(vals) };
if (kind == Kind::SET) {
- EvaluationValue::SetType tmp;
+ SetType tmp;
for (auto &v : vals) {
tmp.insert(std::move(v));
}
}
ASSERT(kind == Kind::DICT);
- EvaluationValue::DictType tmp;
+ DictType tmp;
for (auto i = 0u; i < vals.size(); i += 2) {
tmp.insert({ std::move(vals[i]), std::move(vals[i + 1]) });
}
#include <sstream>
using VarsType = std::unordered_map<std::string, EvaluationValue>;
-using ActsType = std::unordered_map<std::string, EvaluationValue::FunctionType>;
+using ActsType = std::unordered_map<std::string, detail::FunctionType>;
struct TestExecutor : ExecutorInterface {
TestExecutor(VarsType variables = {}, ActsType activities = {},
std::string result2;
auto vars = VarsType {
{
- "foo", EvaluationValue::UserFunctionType<int, std::string, std::string, bool>{
+ "foo", detail::UserFunctionType<int, std::string, std::string, bool>{
[&](EvaluationContext &, int v1, std::string v2, std::string v3, bool v4) -> EvaluationValue {
return std::to_string(v1) + "," + v2 + "," + v3 + "," + (v4 ? "true" : "false");
}
}
},
{
- "bar", EvaluationValue::UserFunctionType<std::string>{
+ "bar", detail::UserFunctionType<std::string>{
[&](EvaluationContext &, std::string value) -> EvaluationValue {
result2 = value;
return nullptr;
size_t callCount = 0;
auto vars = VarsType { };
std::ostringstream output;
- vars["assert"] = EvaluationValue::UserFunctionType<bool> {
+ vars["assert"] = detail::UserFunctionType<bool> {
[&](EvaluationContext &, bool val) -> EvaluationValue {
if (!val) throw EvaluationFailure{} << "assertion failed2";
++callCount;
return {};
}
};
- vars["print"] = EvaluationValue::UserFunctionType<EvaluationValue> {
+ vars["print"] = detail::UserFunctionType<EvaluationValue> {
[&](EvaluationContext &, EvaluationValue val) -> EvaluationValue {
output << ">>> " << val << "\n";
return {};
"assert(v[1:2] == [2])\n"
"assert(v[-2:-1] == [2])\n"
"v[1:2] = [4, 5, 6]\n"
+ "print(v)\n"
"assert(v == [1, 4, 5, 6, 3])\n"
"assert([1] != [2])\n"
"assert([1] == [1])\n"
"assert([1, 2, 3] <= [1, 2, 3, 4])\n"
"assert([1, 2, 3, 5 ] > [1, 2, 3, 4])\n"
"assert([1, 2, 3, 5 ] >= [1, 2, 3, 4])\n"
- , 18);
+ "assert(1 in [1,2,3])\n"
+ "assert(1 not in [2,3])\n"
+ "assert(not (1 in [2,3]))\n"
+ , 21);
}
TEST_F(ScriptTest, set)