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

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.