6#include "mapcssterm_p.h"
8#include "mapcssdeclaration_p.h"
9#include "mapcssexpressioncontext_p.h"
10#include "mapcssresult.h"
11#include "mapcssstate_p.h"
14#include "content/osmconditionalexpression_p.h"
15#include "content/osmconditionalexpressioncontext_p.h"
25MapCSSTerm::MapCSSTerm(Operation op)
30MapCSSTerm::~MapCSSTerm() =
default;
32void MapCSSTerm::addChildTerm(MapCSSTerm *term)
34 m_children.emplace_back(term);
40 MapCSSTerm::Operation op;
41}
static constexpr const function_name_map[] = {
42 {
"KOSM_conditional", MapCSSTerm::KOSM_Conditional },
43 {
"any", MapCSSTerm::Any },
44 {
"boolean", MapCSSTerm::BooleanCast },
45 {
"concat", MapCSSTerm::Concatenate },
46 {
"cond", MapCSSTerm::Conditional },
47 {
"int", MapCSSTerm::Integer },
48 {
"max", MapCSSTerm::Maximum },
49 {
"metric", MapCSSTerm::Metric },
50 {
"min", MapCSSTerm::Minimum },
51 {
"num", MapCSSTerm::NumericalCast },
52 {
"prop", MapCSSTerm::ReadProperty },
53 {
"replace", MapCSSTerm::Replace },
54 {
"sqrt", MapCSSTerm::Sqrt },
55 {
"str", MapCSSTerm::StringCast },
56 {
"tag", MapCSSTerm::ReadTag },
57 {
"zmetric", MapCSSTerm::ZMetric },
60MapCSSTerm::Operation MapCSSTerm::parseOperation(
const char *str, std::size_t len)
62 const auto it = std::lower_bound(std::begin(function_name_map), std::end(function_name_map), std::span(str, len), [](
const auto &m,
const auto &name) {
63 return std::strncmp(m.name, name.data(), name.size()) < 0;
65 if (it != std::end(function_name_map) && std::strncmp((*it).name, str, len) == 0) {
75}
static constexpr const argument_count_map[] = {
100 { 1, std::numeric_limits<uint16_t>::max() },
102 { 2, std::numeric_limits<uint16_t>::max() },
106 { 2, std::numeric_limits<uint16_t>::max() },
107 { 2, std::numeric_limits<uint16_t>::max() },
120bool MapCSSTerm::validChildCount()
const
122 return m_children.size() >= argument_count_map[m_op].minArgs && m_children.size() <= argument_count_map[m_op].maxArgs;
127 for (
const auto &c : m_children) {
135MapCSSValue MapCSSTerm::evaluate(
const MapCSSExpressionContext &context)
const
144 return m_children[0]->evaluate(context).asNumber() + m_children[1]->evaluate(context).asNumber();
146 return m_children[0]->evaluate(context).asNumber() - m_children[1]->evaluate(context).asNumber();
148 return m_children[0]->evaluate(context).asNumber() * m_children[1]->evaluate(context).asNumber();
150 const auto divisor = m_children[1]->evaluate(context);
151 if (!divisor.isNone() && divisor.asNumber() != 0.0) {
152 return m_children[0]->evaluate(context).asNumber() / divisor.asNumber();
158 return m_children[0]->evaluate(context).asBoolean() && m_children[1]->evaluate(context).asBoolean();
160 return m_children[0]->evaluate(context).asBoolean() || m_children[1]->evaluate(context).asBoolean();
162 return !m_children[0]->evaluate(context).asBoolean();
165 return m_children[0]->evaluate(context).compareEqual(m_children[1]->evaluate(context));
166 case CompareNotEqual:
167 return !m_children[0]->evaluate(context).compareEqual(m_children[1]->evaluate(context));
169 return m_children[0]->evaluate(context).asNumber() < m_children[1]->evaluate(context).asNumber();
171 return m_children[0]->evaluate(context).asNumber() > m_children[1]->evaluate(context).asNumber();
172 case CompareLessOrEqual:
173 return m_children[0]->evaluate(context).asNumber() <= m_children[1]->evaluate(context).asNumber();
174 case CompareGreaterOrEqual:
175 return m_children[0]->evaluate(context).asNumber() >= m_children[1]->evaluate(context).asNumber();
178 return m_children[0]->evaluate(context).asNumber();
180 return m_children[0]->evaluate(context).asString();
182 return m_children[0]->evaluate(context).asBoolean();
185 if (m_children[0]->evaluate(context).asBoolean()) {
186 return m_children[1]->evaluate(context);
188 return m_children[2]->evaluate(context);
192 for (
const auto &child : m_children) {
193 auto r = child->evaluate(context);
204 for (
const auto &child : m_children) {
205 s += child->evaluate(context).asString();
210 return m_children[0]->evaluate(context).asString().replace(m_children[1]->evaluate(context).asString(), m_children[2]->evaluate(context).asString());
213 const auto i = (int)m_children[0]->evaluate(context).asNumber();
217 double r = std::numeric_limits<double>::lowest();
218 for (
const auto &child : m_children) {
219 r = std::max(r, child->evaluate(context).asNumber());
224 double r = std::numeric_limits<double>::max();
225 for (
const auto &child : m_children) {
226 r = std::min(r, child->evaluate(context).asNumber());
231 return std::sqrt(m_children[0]->evaluate(context).asNumber());
235 return m_children[0]->evaluate(context);
238 const auto propName = m_children[0]->evaluate(context).asString();
239 const auto prop = MapCSSDeclaration::propertyFromName(propName.constData(), propName.size());
240 const auto decl = context.result.declaration(prop);
241 if (!decl || !decl->isValid()) {
244 if (decl->hasExpression()) {
245 qCWarning(
Log) <<
"Recursive eval() expression not supported, evaluation aborted";
248 return decl->stringValue().toUtf8();
252 const auto v = context.result.resolvedTagValue(m_children[0]->evaluate(context).asString().constData(), context.state);
253 return v ? *v : MapCSSValue();
255 case KOSM_Conditional:
257 OSMConditionalExpression expr;
258 expr.parse(m_children[0]->evaluate(context).asString());
260 OSMConditionalExpressionContext condContext;
261 condContext.element = context.state.element;
262 condContext.openingHoursCache = context.state.openingHours;
263 return expr.evaluate(condContext);
271 MapCSSTerm::Operation op;
273}
static constexpr const infix_output_map[] = {
274 { MapCSSTerm::Addition,
"+" },
275 { MapCSSTerm::Subtraction,
"-" },
276 { MapCSSTerm::Multiplication,
"*" },
277 { MapCSSTerm::Division,
"/" },
278 { MapCSSTerm::LogicalAnd,
"&&" },
279 { MapCSSTerm::LogicalOr,
"||" },
280 { MapCSSTerm::CompareEqual,
"==" },
281 { MapCSSTerm::CompareNotEqual,
"!=" },
282 { MapCSSTerm::CompareLess,
"<" },
283 { MapCSSTerm::CompareGreater,
">" },
284 { MapCSSTerm::CompareLessOrEqual,
"<=", },
285 { MapCSSTerm::CompareGreaterOrEqual,
">=" },
288void MapCSSTerm::write(
QIODevice *out)
const
290 if (m_op == Unknown) {
293 if (m_op == Literal) {
294 m_literal.write(out);
297 if (m_op == LogicalNot) {
299 m_children[0]->write(out);
302 for (
const auto &m : infix_output_map) {
305 m_children[0]->write(out);
307 m_children[1]->write(out);
313 for (
const auto &m : function_name_map) {
317 if (!m_children.empty()) {
318 for (
auto it = m_children.begin(); it != std::prev(m_children.end()); ++it) {
322 m_children.back()->write(out);
A set of nodes, ways and relations.
OSM-based multi-floor indoor maps for buildings.
qint64 write(const QByteArray &data)