Current Version: 1.0.10
Project Name: csspp
expr_unary.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 void expression::compile_args(bool divide_font_metrics)
41 {
42  if(!f_node->empty())
43  {
44  bool const end_with_bracket(f_node->get_last_child()->is(node_type_t::OPEN_CURLYBRACKET));
45  size_t const max_children(f_node->size() - (end_with_bracket ? 1 : 0));
46  for(size_t a(0); a < max_children; ++a)
47  {
48  expression arg_expr(f_node->get_child(a));
50  arg_expr.f_divide_font_metrics = divide_font_metrics;
51  arg_expr.compile_list(f_node);
52  }
53  }
54 }
55 
57 {
58  mark_start();
59  next();
60  node::pointer_t result;
61 
62  // result is a list: a b c ...
63  for(;;)
64  {
65  // we have one special case here: !important cannot be
66  // compiled as an expression...
68  {
69  // this is viewed as !important and only such
70  // can appear now so we can just return immediately
71  if(!end_of_nodes())
72  {
73  error::instance() << f_current->get_position()
74  << "A special flag, !"
75  << f_current->get_string()
76  << " in this case, must only appear at the end of a declaration."
78  }
79 
80  // we remove the !<word> from the declaration and
81  // setup a flag instead
82  f_node->remove_child(f_current);
83  if(f_pos > 0)
84  {
85  --f_pos;
86  }
87  parent->set_flag(f_current->get_string(), true);
88  }
89  else
90  {
91  result = conditional();
92  replace_with_result(result);
93  }
94  if(end_of_nodes())
95  {
96  break;
97  }
98  next();
99  // keep one whitespace between expressions if such exists
101  {
102  if(end_of_nodes())
103  {
104  // TODO: list of nodes ends with WHITESPACE
105  break; // LCOV_EXCL_LINE
106  }
107  mark_start();
108  next();
109  }
110  }
111 
112  return result;
113 }
114 
116 {
117  // unary: IDENTIFIER
118  // | INTEGER
119  // | DECIMAL_NUMBER
120  // | EXCLAMATION
121  // | STRING
122  // | PERCENT
123  // | BOOLEAN
124  // | HASH (-> COLOR)
125  // | UNICODE_RANGE
126  // | URL
127  // | FUNCTION argument_list ')' -- including url()
128  // | '(' expression_list ')'
129  // | '+' power
130  // | '-' power
131 
132  switch(f_current->get_type())
133  {
134  case node_type_t::ARRAY:
136  case node_type_t::COLOR:
138  case node_type_t::EXCLAMATION: // this is not a BOOLEAN NOT operator...
140  case node_type_t::MAP:
143  case node_type_t::STRING:
145  case node_type_t::URL:
146  {
147  node::pointer_t result(f_current);
148  // skip that token
149  next();
150  return result;
151  }
152 
154  {
156 
157  // skip the '<func>('
158  next();
159 
160  // calculate the arguments
161  parser::argify(func);
162  if(func->get_string() != "calc"
163  && func->get_string() != "expression")
164  {
165  expression args_expr(func);
167  args_expr.compile_args(false);
168  }
169  //else -- we may want to verify the calculations, but
170  // we cannot compile those
171 
172  return excecute_function(func);
173  }
174 
176  {
177  // calculate the result of the sub-expression
178  expression group(f_current);
180  group.next();
181 
182  // skip the '(' in the main expression
183  next();
184 
185  return group.expression_list();
186  }
187 
188  case node_type_t::ADD:
189  // completely ignore the '+' because we assume that
190  // '+<anything>' <=> '<anything>'
191 
192  // skip the '+'
193  next();
194  return power();
195 
197  {
198  // skip the '-'
199  next();
200 
201  node::pointer_t result(power());
202  if(!result)
203  {
204  return node::pointer_t();
205  }
206  switch(result->get_type())
207  {
209  result->set_integer(-result->get_integer());
210  return result;
211 
214  result->set_decimal_number(-result->get_decimal_number());
215  return result;
216 
217  default:
218  error::instance() << f_current->get_position()
219  << "unsupported type "
220  << result->get_type()
221  << " for operator '-'."
223  return node::pointer_t();
224 
225  }
226  }
227 
228  // This is not too good, we actually transform the !important in
229  // one 'EXCLAMATION + string' node; use the not(...) instead
230  //case node_type_t::EXCLAMATION:
231  // {
232  // // skip the '!'
233  // next();
234  // node::pointer_t result(power());
235  // bool const r(boolean(result));
236  // // make sure the result is a boolean
237  // if(!result->is(node_type_t::BOOLEAN))
238  // {
239  // result.reset(new node(node_type_t::BOOLEAN, result->get_position()));
240  // }
241  // result->set_boolean(!r);
242  // return result;
243  // }
244 
245  case node_type_t::HASH:
246  // a '#...' in an expression is expected to be a valid color
247  {
248  color hash;
249  if(!hash.set_color(f_current->get_string(), false))
250  {
251  error::instance() << f_current->get_position()
252  << "the color in #"
253  << f_current->get_string()
254  << " is not valid."
256 
257  // skip the HASH
258  next();
259  return node::pointer_t();
260  }
261  node::pointer_t color_node(new node(node_type_t::COLOR, f_current->get_position()));
262  color_node->set_color(hash);
263 
264  // skip the HASH
265  next();
266  return color_node;
267  }
268 
270  // an identifier may represent a color, null, true, or false
271  {
272  node::pointer_t result(f_current);
273  // skip the IDENTIFIER
274  next();
275 
276  std::string const identifier(result->get_string());
277 
278  // an internally recognized identifier? (null, true, false)
279  if(identifier == "null")
280  {
281  return node::pointer_t(new node(node_type_t::NULL_TOKEN, result->get_position()));
282  }
283  if(identifier == "true")
284  {
285  node::pointer_t b(new node(node_type_t::BOOLEAN, result->get_position()));
286  b->set_boolean(true);
287  return b;
288  }
289  if(identifier == "false")
290  {
291  // a boolean is false by default, so no need to set the value
292  return node::pointer_t(new node(node_type_t::BOOLEAN, result->get_position()));
293  }
294 
295  // a color?
296  color col;
297  if(col.set_color(identifier, true))
298  {
299  node::pointer_t color_node(new node(node_type_t::COLOR, result->get_position()));
300  color_node->set_color(col);
301 
302  return color_node;
303  }
304 
305  // an expression variable?
306  auto var(f_variables.find(identifier));
307  if(var != f_variables.end())
308  {
309  return var->second;
310  }
311 
312  // it is not a color or a variable, return as is
313  return result;
314  }
315 
316  default:
317  error::instance() << f_current->get_position()
318  << "unsupported type "
319  << f_current->get_type()
320  << " as a unary expression token."
322  return node::pointer_t();
323 
324  }
325  /*NOTREACHED*/
326 }
327 
328 } // namespace csspp
329 
330 // Local Variables:
331 // mode: cpp
332 // indent-tabs-mode: nil
333 // c-basic-offset: 4
334 // tab-width: 4
335 // End:
336 
337 // vim: ts=4 sw=4 et
node::pointer_t power()
Definition: expr_power.cpp:187
node::pointer_t unary()
Definition: expr_unary.cpp:115
std::shared_ptr< node > pointer_t
Definition: node.h:122
variable_vector_t f_variables
Definition: expression.h:152
void set_color(rgba_color_t const rgba)
Definition: color.cpp:217
node::pointer_t compile_list(node::pointer_t parent)
Definition: expr_unary.cpp:56
node::pointer_t replace_with_result(node::pointer_t result)
Definition: expression.cpp:72
static bool argify(node::pointer_t n, node_type_t const separator=node_type_t::COMMA)
Definition: parser.cpp:786
node::pointer_t expression_list()
Definition: expr_list.cpp:53
expression_variables_interface * f_variable_handler
Definition: expression.h:154
node::pointer_t f_current
Definition: expression.h:151
void compile_args(bool divide_font_metrics)
Definition: expr_unary.cpp:40
void set_variable_handler(expression_variables_interface *handler)
Definition: expression.cpp:49
node::pointer_t conditional()
node::pointer_t excecute_function(node::pointer_t func)
node::pointer_t f_node
Definition: expression.h:148
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.