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

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.