Current Version: 1.0.33
Project Name: csspp
expr_additive.cpp
Go to the documentation of this file.
1// Copyright (c) 2015-2025 Made to Order Software Corp. All Rights Reserved
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation; either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License along
14// with this program; if not, write to the Free Software Foundation, Inc.,
15// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16
26// self
27//
28#include "csspp/expression.h"
29
30#include "csspp/exception.h"
31#include "csspp/parser.h"
32#include "csspp/unicode_range.h"
33
34
35// C++
36//
37#include <algorithm>
38#include <cmath>
39#include <iostream>
40
41
42// last include
43//
44#include <snapdev/poison.h>
45
46
47
48namespace csspp
49{
50
51namespace
52{
53
55{
56 switch(n->get_type())
57 {
60 return n->get_type();
61
62 default:
64
65 }
66}
67
69{
71 bool test_dimensions(true);
72 integer_t ai(0);
73 integer_t bi(0);
74 decimal_number_t af(0.0);
75 decimal_number_t bf(0.0);
76 bool swapped(false);
77
78 switch(mix_node_types(lhs->get_type(), rhs->get_type()))
79 {
81 if(!subtract)
82 {
83 // string concatenation
84 node::pointer_t result(new node(node_type_t::STRING, lhs->get_position()));
85 result->set_string(lhs->get_string() + rhs->get_string());
86 return result;
87 }
88 break;
89
91 ai = lhs->get_integer();
92 bi = rhs->get_integer();
94 break;
95
97 af = lhs->get_decimal_number();
98 bf = rhs->get_decimal_number();
100 break;
101
103 af = lhs->get_decimal_number();
104 bf = static_cast<decimal_number_t>(rhs->get_integer());
106 break;
107
109 af = static_cast<decimal_number_t>(lhs->get_integer());
110 bf = rhs->get_decimal_number();
112 break;
113
115 af = lhs->get_decimal_number();
116 bf = rhs->get_decimal_number();
118 test_dimensions = false;
119 break;
120
123 swap(lhs, rhs);
124 swapped = true;
125#if __cplusplus >= 201700
126 [[fallthrough]];
127#endif
130 if(rhs->get_string() == "")
131 {
132 decimal_number_t offset;
133 if(rhs->is(node_type_t::INTEGER))
134 {
135 offset = static_cast<decimal_number_t>(rhs->get_integer());
136 }
137 else
138 {
139 offset = rhs->get_decimal_number();
140 }
141 color c(lhs->get_color());
143 color_component_t green;
145 color_component_t alpha;
146 c.get_color(red, green, blue, alpha);
147 if(subtract)
148 {
149 if(swapped)
150 {
151 red = offset - red;
152 green = offset - green;
153 blue = offset - blue;
154 alpha = offset - alpha;
155 }
156 else
157 {
158 red -= offset;
159 green -= offset;
160 blue -= offset;
161 alpha -= offset;
162 }
163 }
164 else
165 {
166 red += offset;
167 green += offset;
168 blue += offset;
169 alpha += offset;
170 }
171 c.set_color(red, green, blue, alpha);
172 node::pointer_t result(new node(node_type_t::COLOR, lhs->get_position()));
173 result->set_color(c);
174 return result;
175 }
176 error::instance() << rhs->get_position()
177 << "color offsets (numbers added with + or - operators) must be unit less values, "
178 << (rhs->is(node_type_t::INTEGER)
179 ? static_cast<decimal_number_t>(rhs->get_integer())
180 : rhs->get_decimal_number())
181 << rhs->get_string()
182 << " is not acceptable."
184 return node::pointer_t();
185
187 {
188 color lc(lhs->get_color());
189 color const rc(rhs->get_color());
191 color_component_t lgreen;
192 color_component_t lblue;
193 color_component_t lalpha;
195 color_component_t rgreen;
196 color_component_t rblue;
197 color_component_t ralpha;
198 lc.get_color(lred, lgreen, lblue, lalpha);
199 rc.get_color(rred, rgreen, rblue, ralpha);
200 if(subtract)
201 {
202 lred -= rred;
203 lgreen -= rgreen;
204 lblue -= rblue;
205 lalpha -= ralpha;
206 }
207 else
208 {
209 lred += rred;
210 lgreen += rgreen;
211 lblue += rblue;
212 lalpha += ralpha;
213 }
214 lc.set_color(lred, lgreen, lblue, lalpha);
215 node::pointer_t result(new node(node_type_t::COLOR, lhs->get_position()));
216 result->set_color(lc);
217 return result;
218 }
219
220 default:
221 break;
222
223 }
224
225 if(type == node_type_t::UNKNOWN)
226 {
227 node_type_t lt(lhs->get_type());
228 node_type_t rt(rhs->get_type());
229
230 error::instance() << lhs->get_position()
231 << "incompatible types between "
232 << lt
233 << (lt == node_type_t::IDENTIFIER || lt == node_type_t::STRING ? " (" + lhs->get_string() + ")" : "")
234 << " and "
235 << rt
236 << (rt == node_type_t::IDENTIFIER || rt == node_type_t::STRING ? " (" + rhs->get_string() + ")" : "")
237 << " for operator '"
238 << (subtract ? "-" : "+")
239 << "'."
241 return node::pointer_t();
242 }
243
244 if(test_dimensions)
245 {
246 std::string const ldim(lhs->get_string());
247 std::string const rdim(rhs->get_string());
248 if(ldim != rdim)
249 {
250 error::instance() << lhs->get_position()
251 << "incompatible dimensions: \""
252 << ldim
253 << "\" and \""
254 << rdim
255 << "\" cannot be used as is with operator '"
256 << (subtract ? "-" : "+")
257 << "'."
259 return node::pointer_t();
260 }
261 }
262
263 node::pointer_t result(new node(type, lhs->get_position()));
264 if(type != node_type_t::PERCENT)
265 {
266 // do not lose the dimension
267 result->set_string(lhs->get_string());
268 }
269
270 switch(type)
271 {
273 if(subtract)
274 {
275 result->set_integer(ai - bi);
276 }
277 else
278 {
279 result->set_integer(ai + bi);
280 }
281 break;
282
285 if(subtract)
286 {
287 result->set_decimal_number(af - bf);
288 }
289 else
290 {
291 result->set_decimal_number(af + bf);
292 }
293 break;
294
295 default: // LCOV_EXCL_LINE
296 throw csspp_exception_logic("expression.cpp:add(): 'type' set to a value which is not handled here."); // LCOV_EXCL_LINE
297
298 }
299
300 return result;
301}
302
303} // no name namespace
304
306{
307 // additive: multiplicative
308 // | additive '+' multiplicative
309 // | additive '-' multiplicative
310
312 if(!result)
313 {
314 return node::pointer_t();
315 }
316
317 node_type_t op(additive_operator(f_current));
318 while(op != node_type_t::UNKNOWN)
319 {
320 // skip the additive operator
321 next();
322
324 if(!rhs)
325 {
326 return node::pointer_t();
327 }
328
329 // apply the additive operation
330 result = add(result, rhs, op == node_type_t::SUBTRACT);
331 if(!result)
332 {
333 return node::pointer_t();
334 }
335
336 op = additive_operator(f_current);
337 }
338
339 return result;
340}
341
342} // namespace csspp
343// vim: ts=4 sw=4 et
rgba_color_t get_color() const
Definition color.cpp:467
void set_color(rgba_color_t const rgba)
Definition color.cpp:228
static error & instance()
Definition error.cpp:77
node::pointer_t f_current
Definition expression.h:155
node::pointer_t multiplicative()
node::pointer_t additive()
std::shared_ptr< node > pointer_t
Definition node.h:132
node_type_t additive_operator(node::pointer_t n)
node::pointer_t add(node::pointer_t lhs, node::pointer_t rhs, bool subtract)
The namespace of all the classes in the CSS Preprocessor.
Definition csspp.h:48
node_type_t
Definition node.h:41
float color_component_t
Definition color.h:27
int64_t integer_t
Definition csspp.h:58
int32_t constexpr mix_node_types(node_type_t a, node_type_t b)
Definition node.h:119
double decimal_number_t
Definition csspp.h:59

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.