Current Version: 1.0.10
Project Name: csspp
internal_functions.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 
32 #include <algorithm>
33 #include <cmath>
34 #include <climits>
35 #include <iostream>
36 
37 namespace csspp
38 {
39 
40 namespace
41 {
42 
44 
45 decimal_number_t dimension_to_radians(position const & pos, decimal_number_t n, std::string const & dimension)
46 {
47  if(dimension == "rad")
48  {
49  // all good as is
50  return n;
51  }
52  else if(dimension == "deg"
53  || dimension == "") // no angle dimension, use as if it were degrees (which has been the default in CSS)
54  {
55  // convert degrees to radians
56  return n * M_PI / 180.0;
57  }
58  else if(dimension == "grad")
59  {
60  // convert grads to radians
61  return n * M_PI / 200.0;
62  }
63  else if(dimension == "turn")
64  {
65  // convert turns to radians
66  return n * M_PI * 2.0;
67  }
68  else
69  {
70  error::instance() << pos
71  << "trigonometry functions expect an angle (deg, grad, rad, turn) as a parameter."
73 
74  // keep 'n' as is... what else could we do?
75  return n;
76  }
77 }
78 
79 } // no name namespace
80 
82 {
83  g_unique_id_counter = counter;
84 }
85 
87 {
88  return g_unique_id_counter;
89 }
90 
92 {
93  if(argn >= func->size())
94  {
95  return node::pointer_t(); // LCOV_EXCL_LINE
96  }
97 
98  node::pointer_t arg(func->get_child(argn));
99  if(arg->size() != 1)
100  {
101  return node::pointer_t();
102  }
103 
104  return arg->get_child(0);
105 }
106 
108 {
109  if(argn >= func->size())
110  {
111  return node::pointer_t(); // LCOV_EXCL_LINE
112  }
113 
114  node::pointer_t arg(func->get_child(argn));
115  if(arg->size() != 1)
116  {
117  return node::pointer_t();
118  }
119 
120  node::pointer_t value(arg->get_child(0));
121  if(value->is(node_type_t::COLOR))
122  {
123  col = value->get_color();
124  return value;
125  }
126 
127  return node::pointer_t();
128 }
129 
131 {
132  if(argn >= func->size())
133  {
134  return node::pointer_t();
135  }
136 
137  node::pointer_t arg(func->get_child(argn));
138  if(arg->size() != 1)
139  {
140  return node::pointer_t();
141  }
142 
143  node::pointer_t value(arg->get_child(0));
144  if(value->is(node_type_t::INTEGER))
145  {
146  number = static_cast<decimal_number_t>(value->get_integer());
147  return value;
148  }
149 
150  if(value->is(node_type_t::DECIMAL_NUMBER))
151  {
152  number = value->get_decimal_number();
153  return value;
154  }
155 
156  return node::pointer_t();
157 }
158 
160 {
161  if(argn >= func->size())
162  {
163  return node::pointer_t(); // LCOV_EXCL_LINE
164  }
165 
166  node::pointer_t arg(func->get_child(argn));
167  if(arg->size() != 1)
168  {
169  return node::pointer_t();
170  }
171 
172  node::pointer_t value(arg->get_child(0));
173  if(value->is(node_type_t::INTEGER))
174  {
175  number = static_cast<decimal_number_t>(value->get_integer());
176  return value;
177  }
178 
179  if(value->is(node_type_t::DECIMAL_NUMBER))
180  {
181  number = value->get_decimal_number();
182  return value;
183  }
184 
185  if(value->is(node_type_t::PERCENT))
186  {
187  number = value->get_decimal_number();
188  return value;
189  }
190 
191  return node::pointer_t();
192 }
193 
195 {
196  if(argn >= func->size())
197  {
198  return node::pointer_t(); // LCOV_EXCL_LINE
199  }
200 
201  node::pointer_t arg(func->get_child(argn));
202  if(arg->size() != 1)
203  {
204  return node::pointer_t();
205  }
206 
207  node::pointer_t value(arg->get_child(0));
208  if(value->is(node_type_t::STRING))
209  {
210  str = value->get_string();
211  return value;
212  }
213 
214  return node::pointer_t();
215 }
216 
218 {
219  if(argn >= func->size())
220  {
221  return node::pointer_t(); // LCOV_EXCL_LINE
222  }
223 
224  node::pointer_t arg(func->get_child(argn));
225  if(arg->size() != 1)
226  {
227  return node::pointer_t();
228  }
229 
230  node::pointer_t value(arg->get_child(0));
231  if(value->is(node_type_t::IDENTIFIER)
232  || value->is(node_type_t::STRING))
233  {
234  str = value->get_string();
235  return value;
236  }
237 
238  return node::pointer_t();
239 }
240 
242 {
243  // abs(number)
246  if(number)
247  {
248  if(number->is(node_type_t::INTEGER))
249  {
250  number->set_integer(labs(number->get_integer()));
251  }
252  else
253  {
254  number->set_decimal_number(fabs(number->get_decimal_number()));
255  }
256  return number;
257  }
258 
259  error::instance() << f_current->get_position()
260  << "abs() expects a number as parameter."
262 
263  return node::pointer_t();
264 }
265 
267 {
268  // acos(number)
271  if(number)
272  {
273  if(number->is(node_type_t::INTEGER))
274  {
275  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
276  }
277  // should we return the angle in degrees instead?
278  number->set_decimal_number(acos(n));
279  number->set_string("rad");
280  return number;
281  }
282 
283  error::instance() << f_current->get_position()
284  << "acos() expects a number as parameter."
286 
287  return node::pointer_t();
288 }
289 
291 {
292  // alpha(color)
293  color c;
295  if(col)
296  {
301  c.get_color(r, g, b, a);
302  node::pointer_t component(new node(node_type_t::DECIMAL_NUMBER, func->get_position()));
303  component->set_decimal_number(a);
304  return component;
305  }
306 
307  error::instance() << f_current->get_position()
308  << "alpha() expects a color as parameter."
310 
311  return node::pointer_t();
312 }
313 
315 {
316  // asin(number)
319  if(number)
320  {
321  if(number->is(node_type_t::INTEGER))
322  {
323  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
324  }
325  // should we return the angle in degrees instead?
326  number->set_decimal_number(asin(n));
327  number->set_string("rad");
328  return number;
329  }
330 
331  error::instance() << f_current->get_position()
332  << "asin() expects a number as parameter."
334 
335  return node::pointer_t();
336 }
337 
339 {
340  // atan(number)
343  if(number)
344  {
345  if(number->is(node_type_t::INTEGER))
346  {
347  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
348  }
349  // should we return the angle in degrees instead?
350  number->set_decimal_number(atan(n));
351  number->set_string("rad");
352  return number;
353  }
354 
355  error::instance() << f_current->get_position()
356  << "atan() expects a number as parameter."
358 
359  return node::pointer_t();
360 }
361 
363 {
364  // blue(color)
365  color c;
367  if(col)
368  {
373  c.get_color(r, g, b, a);
374  node::pointer_t component(new node(node_type_t::INTEGER, func->get_position()));
375  component->set_integer(static_cast<integer_t>(b * 255.0 + 0.5));
376  return component;
377  }
378 
379  error::instance() << f_current->get_position()
380  << "blue() expects a color as parameter."
382 
383  return node::pointer_t();
384 }
385 
387 {
388  // ceil(number)
391  if(number)
392  {
393  if(number->is(node_type_t::DECIMAL_NUMBER))
394  {
395  number->set_decimal_number(ceil(number->get_decimal_number()));
396  }
397  return number;
398  }
399 
400  error::instance() << f_current->get_position()
401  << "ceil() expects a number as parameter."
403 
404  return node::pointer_t();
405 }
406 
408 {
409  // cos(number)
412  if(number)
413  {
414  std::string const dimension(number->get_string());
415  if(number->is(node_type_t::INTEGER))
416  {
417  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
418  }
419  else
420  {
421  // we "lose" the dimension
422  number->set_string("");
423  }
424  n = dimension_to_radians(func->get_position(), n, dimension);
425  number->set_decimal_number(cos(n));
426  return number;
427  }
428 
429  error::instance() << f_current->get_position()
430  << "cos() expects an angle as parameter."
432 
433  return node::pointer_t();
434 }
435 
437 {
438  // decimal_number(expr)
440  if(any)
441  {
442  switch(any->get_type())
443  {
445  // already a decimal number, return as is
446  return any;
447 
449  {
450  node::pointer_t number(new node(node_type_t::DECIMAL_NUMBER, any->get_position()));
451  number->set_decimal_number(any->get_decimal_number());
452  return number;
453  }
454 
456  {
457  node::pointer_t number(new node(node_type_t::DECIMAL_NUMBER, any->get_position()));
458  number->set_decimal_number(any->get_integer());
459  number->set_string(any->get_string());
460  return number;
461  }
462 
464  case node_type_t::STRING:
465  case node_type_t::URL:
466  {
467  std::stringstream ss;
468  ss << any->get_string();
469  lexer l(ss, any->get_position());
470  node::pointer_t number(l.next_token());
471  if(number->is(node_type_t::WHITESPACE))
472  {
473  number = l.next_token();
474  }
475  switch(number->get_type())
476  {
478  return number;
479 
481  {
482  node::pointer_t result(new node(node_type_t::DECIMAL_NUMBER, any->get_position()));
483  result->set_decimal_number(number->get_decimal_number());
484  return result;
485  }
486 
488  {
489  node::pointer_t result(new node(node_type_t::DECIMAL_NUMBER, any->get_position()));
490  result->set_decimal_number(number->get_integer());
491  result->set_string(number->get_string());
492  return result;
493  }
494 
495  default:
496  break;
497 
498  }
499  }
500  error::instance() << f_current->get_position()
501  << "decimal_number() expects a string parameter to represent a valid integer, decimal number, or percent value."
503  return node::pointer_t();
504 
505  default:
506  break;
507 
508  }
509  }
510 
511  error::instance() << f_current->get_position()
512  << "decimal_number() expects one value as parameter."
514 
515  return node::pointer_t();
516 }
517 
519 {
520  // floor(number)
523  if(number)
524  {
525  if(number->is(node_type_t::DECIMAL_NUMBER))
526  {
527  number->set_decimal_number(floor(number->get_decimal_number()));
528  }
529  return number;
530  }
531 
532  error::instance() << f_current->get_position()
533  << "floor() expects a number as parameter."
535 
536  return node::pointer_t();
537 }
538 
540 {
541  // frgb(color)
542  // frgb(fred, fgreen, fblue)
543  color c;
545  if(col)
546  {
547  // force alpha to 1.0
552  c.get_color(r, g, b, a);
553  c.set_color(r, g, b, static_cast<color_component_t>(1.0));
554  col->set_color(c);
555  return col;
556  }
557  else
558  {
562 
566 
567  if(col1 && col2 && col3)
568  {
569  // force alpha to 1.0
570  c.set_color(r, g, b, 1.0);
571  col.reset(new node(node_type_t::COLOR, func->get_position()));
572  col->set_color(c);
573  return col;
574  }
575  }
576 
577  error::instance() << f_current->get_position()
578  << "frgb() expects exactly one color parameter or three numbers (Red, Green, Blue)."
580 
581  return node::pointer_t();
582 }
583 
585 {
586  // frgba(color, alpha)
587  // frgba(fred, fgreen, fblue, alpha)
588  color c;
592  if(col && alpha)
593  {
594  // replace alpha
598  color_component_t old_a;
599  c.get_color(r, g, b, old_a);
600  c.set_color(r, g, b, static_cast<color_component_t>(a));
601  col->set_color(c);
602  return col;
603  }
604  else
605  {
609 
614 
615  if(col1 && col2 && col3 && col4)
616  {
617  // set color with alpha
618  c.set_color(r, g, b, a);
619  col.reset(new node(node_type_t::COLOR, func->get_position()));
620  col->set_color(c);
621  return col;
622  }
623  }
624 
625  error::instance() << f_current->get_position()
626  << "frgba() expects exactly one color parameter followed by one number (Color, Alpha), or four numbers (Red, Green, Blue, Alpha)."
628 
629  return node::pointer_t();
630 }
631 
633 {
634  // function_exists(name)
635  std::string name;
637  if(id && !name.empty())
638  {
639  node::pointer_t result(new node(node_type_t::BOOLEAN, func->get_position()));
640 
641  // although variables were already applied they will still be
642  // defined when we reach these lines of code
644  {
646  if(var
647  && var->is(node_type_t::LIST)
648  && !var->empty()
649  && (var->get_child(0)->is(node_type_t::VARIABLE_FUNCTION) // $<name>()
650  || var->get_child(0)->is(node_type_t::FUNCTION))) // @mixin <name>()
651  {
652  result->set_boolean(true);
653  }
654  }
655  // else -- default is already false
656 
657  return result;
658  }
659 
660  error::instance() << f_current->get_position()
661  << "function_exists() expects a string or an identifier as parameter."
663 
664  return node::pointer_t();
665 }
666 
668 {
669  // green(color)
670  color c;
672  if(col)
673  {
678  c.get_color(r, g, b, a);
679  node::pointer_t component(new node(node_type_t::INTEGER, func->get_position()));
680  component->set_integer(static_cast<integer_t>(g * 255.0 + 0.5));
681  return component;
682  }
683 
684  error::instance() << f_current->get_position()
685  << "green() expects a color as parameter."
687 
688  return node::pointer_t();
689 }
690 
692 {
693  // global_variable_exists(name)
694  std::string name;
696  if(id && !name.empty())
697  {
698  node::pointer_t result(new node(node_type_t::BOOLEAN, func->get_position()));
699 
700  // although variables were already applied they will still be
701  // defined when we reach these lines of code
703  {
705  if(var
706  && var->is(node_type_t::LIST)
707  && !var->empty()
708  && (var->get_child(0)->is(node_type_t::VARIABLE) // $<name>
709  || var->get_child(0)->is(node_type_t::IDENTIFIER))) // @mixin <name>
710  {
711  result->set_boolean(true);
712  }
713  }
714  // else -- default is already false
715 
716  return result;
717  }
718 
719  error::instance() << f_current->get_position()
720  << "global_variable_exists() expects a string or an identifier as parameter."
722 
723  return node::pointer_t();
724 }
725 
727 {
728  // hsl(red, green, blue)
732 
736 
737  if(col1 && col2 && col3)
738  {
739  // transform the angle from whatever dimension it is defined as to
740  // radians as expected by set_hsl()
741  h = dimension_to_radians(func->get_position(), h, col1->get_string());
742 
743  // force alpha to 1.0
744  color c;
745  c.set_hsl(h, s, l, 1.0);
746  node::pointer_t col(new node(node_type_t::COLOR, func->get_position()));
747  col->set_color(c);
748  return col;
749  }
750 
751  error::instance() << f_current->get_position()
752  << "hsl() expects exactly three numbers: Hue (angle), Saturation (%), and Lightness (%)."
754 
755  return node::pointer_t();
756 }
757 
759 {
760  // hsla(red, green, blue, alpha)
765 
770 
771  if(col1 && col2 && col3 && col4)
772  {
773  // transform the angle from whatever dimension it is defined as to
774  // radians as expected by set_hsl()
775  h = dimension_to_radians(func->get_position(), h, col1->get_string());
776 
777  // set color with alpha
778  color c;
779  c.set_hsl(h, s, l, a);
780  node::pointer_t col(new node(node_type_t::COLOR, func->get_position()));
781  col->set_color(c);
782  return col;
783  }
784 
785  error::instance() << f_current->get_position()
786  << "hsla() expects exactly four numbers: Hue (angle), Saturation (%), Lightness (%), and Alpha (0.0 to 1.0)."
788 
789  return node::pointer_t();
790 }
791 
793 {
794  // hue(color)
795  color c;
797  if(col)
798  {
799  color_component_t hue;
800  color_component_t saturation;
801  color_component_t lightness;
803  c.get_hsl(hue, saturation, lightness, a);
804  node::pointer_t component(new node(node_type_t::DECIMAL_NUMBER, func->get_position()));
805  component->set_decimal_number(hue * 180.0 / M_PI);
806  component->set_string("deg");
807  return component;
808  }
809 
810  error::instance() << f_current->get_position()
811  << "hue() expects a color as parameter."
813 
814  return node::pointer_t();
815 }
816 
818 {
819  // identifier(expr)
821  if(any)
822  {
823  switch(any->get_type())
824  {
826  // already an identifier, return as is
827  return any;
828 
829  case node_type_t::COLOR:
833  {
834  node::pointer_t id(new node(node_type_t::IDENTIFIER, any->get_position()));
835  id->set_string(any->to_string(0));
836  return id;
837  }
838 
839  case node_type_t::STRING:
840  case node_type_t::URL:
841  {
842  node::pointer_t id(new node(node_type_t::IDENTIFIER, any->get_position()));
843  id->set_string(any->get_string());
844  return id;
845  }
846 
847  default:
848  break;
849 
850  }
851  }
852 
853  error::instance() << f_current->get_position()
854  << "identifier() expects one value as parameter."
856 
857  return node::pointer_t();
858 }
859 
861 {
862  // if(condition, if-true, if-false)
863  node::pointer_t arg1(func->get_child(0));
864  if(arg1->size() != 1)
865  {
866  error::instance() << f_current->get_position()
867  << "if() expects a boolean as its first argument."
869  return node::pointer_t();
870  }
871  else
872  {
873  // if boolean() returns true when arg1 is considered true
874  //
875  // Note:
876  // It generates an error and returns false if the node passed in
877  // is not considered to be a valid boolean node.
878  //
879  bool const r(boolean(arg1->get_child(0)));
880  node::pointer_t result(func->get_child(r ? 1 : 2));
881  if(result->size() == 1)
882  {
883  // very simple result, return as is
884  return result->get_child(0);
885  }
886  // complex result (multiple nodes), return in a list
887  node::pointer_t list(new node(node_type_t::LIST, result->get_position()));
888  list->take_over_children_of(result); // TBD: should we use clone() instead?
889  return list;
890  }
891 }
892 
894 {
895  // inspect(expression)
896  //
897  // no need to check whether child 0 exists since we get called only
898  // if the function has exactly 1 argument
899  //
900  node::pointer_t any(func->get_child(0));
901  node::pointer_t result(new node(node_type_t::STRING, any->get_position()));
902  result->set_string(any->to_string(node::g_to_string_flag_show_quotes));
903  return result;
904 }
905 
907 {
908  // integer(expression)
910  if(any)
911  {
912  switch(any->get_type())
913  {
915  // already an integer, return as is
916  return any;
917 
919  {
920  node::pointer_t number(new node(node_type_t::INTEGER, any->get_position()));
921  number->set_integer(any->get_decimal_number());
922  number->set_string(any->get_string());
923  return number;
924  }
925 
927  {
928  node::pointer_t number(new node(node_type_t::INTEGER, any->get_position()));
929  number->set_integer(any->get_decimal_number());
930  return number;
931  }
932 
934  case node_type_t::STRING:
935  case node_type_t::URL:
936  {
937  std::stringstream ss;
938  ss << any->get_string();
939  lexer l(ss, any->get_position());
940  node::pointer_t number(l.next_token());
941  if(number->is(node_type_t::WHITESPACE))
942  {
943  number = l.next_token();
944  }
945  switch(number->get_type())
946  {
948  return number;
949 
951  {
952  node::pointer_t result(new node(node_type_t::INTEGER, any->get_position()));
953  result->set_integer(number->get_decimal_number());
954  result->set_string(number->get_string());
955  return result;
956  }
957 
959  {
960  node::pointer_t result(new node(node_type_t::INTEGER, any->get_position()));
961  result->set_integer(number->get_decimal_number());
962  return result;
963  }
964 
965  default:
966  break;
967 
968  }
969  }
970  error::instance() << f_current->get_position()
971  << "decimal_number() expects a string parameter to represent a valid integer, decimal number, or percent value."
973  return node::pointer_t();
974 
975  default:
976  break;
977 
978  }
979  }
980 
981  error::instance() << f_current->get_position()
982  << "integer() expects one value as parameter."
984 
985  return node::pointer_t();
986 }
987 
989 {
990  // lightness(color)
991  color c;
993  if(col)
994  {
995  color_component_t hue;
996  color_component_t saturation;
997  color_component_t lightness;
999  c.get_hsl(hue, saturation, lightness, a);
1000  node::pointer_t component(new node(node_type_t::PERCENT, func->get_position()));
1001  component->set_decimal_number(lightness);
1002  return component;
1003  }
1004 
1005  error::instance() << f_current->get_position()
1006  << "lightness() expects a color as parameter."
1008 
1009  return node::pointer_t();
1010 }
1011 
1013 {
1014  // log(number)
1015  decimal_number_t n;
1016  node::pointer_t number(internal_function__get_number(func, 0, n));
1017  if(number)
1018  {
1019  if(!number->get_string().empty())
1020  {
1021  error::instance() << f_current->get_position()
1022  << "log() expects a unit less number as parameter."
1024 
1025  return node::pointer_t();
1026  }
1027  if(n <= 0.0)
1028  {
1029  error::instance() << f_current->get_position()
1030  << "log() expects a positive number as parameter."
1032 
1033  return node::pointer_t();
1034  }
1035  if(number->is(node_type_t::INTEGER))
1036  {
1037  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
1038  }
1039  number->set_decimal_number(log(n));
1040  return number;
1041  }
1042 
1043  error::instance() << f_current->get_position()
1044  << "log() expects a number as parameter."
1046 
1047  return node::pointer_t();
1048 }
1049 
1051 {
1052  // max(n1, n2, ...)
1053  node::pointer_t number;
1054  decimal_number_t maximum(0.0);
1055  std::string dimension;
1056  size_t const max_children(func->size());
1057  for(size_t idx(0); idx < max_children; ++idx)
1058  {
1059  decimal_number_t r;
1061  if(n)
1062  {
1063  if(idx == 0)
1064  {
1065  if(n->is(node_type_t::PERCENT))
1066  {
1067  dimension = "%";
1068  }
1069  else
1070  {
1071  dimension = n->get_string();
1072  }
1073  }
1074  else
1075  {
1076  bool valid_dimension(true);
1077  if(n->is(node_type_t::PERCENT))
1078  {
1079  valid_dimension = dimension == "%";
1080  }
1081  else
1082  {
1083  valid_dimension = dimension == n->get_string();
1084  }
1085  if(!valid_dimension)
1086  {
1087  // all dimensions must be the same
1088  error::instance() << f_current->get_position()
1089  << "max() expects all numbers to have the same dimension."
1091  }
1092  }
1093  if(idx == 0 || r > maximum)
1094  {
1095  number = n;
1096  maximum = r;
1097  }
1098  }
1099  else
1100  {
1101  error::instance() << f_current->get_position()
1102  << "max() expects any number of numbers."
1104  }
1105  }
1106  return number;
1107 }
1108 
1110 {
1111  // min(n1, n2, ...)
1112  node::pointer_t number;
1113  decimal_number_t minimum(0.0);
1114  std::string dimension;
1115  size_t const max_children(func->size());
1116  for(size_t idx(0); idx < max_children; ++idx)
1117  {
1118  decimal_number_t r;
1120  if(n)
1121  {
1122  if(idx == 0)
1123  {
1124  if(n->is(node_type_t::PERCENT))
1125  {
1126  dimension = "%";
1127  }
1128  else
1129  {
1130  dimension = n->get_string();
1131  }
1132  }
1133  else
1134  {
1135  bool valid_dimension(true);
1136  if(n->is(node_type_t::PERCENT))
1137  {
1138  valid_dimension = dimension == "%";
1139  }
1140  else
1141  {
1142  valid_dimension = dimension == n->get_string();
1143  }
1144  if(!valid_dimension)
1145  {
1146  // all dimensions must be the same
1147  error::instance() << f_current->get_position()
1148  << "min() expects all numbers to have the same dimension."
1150  }
1151  }
1152  if(idx == 0 || r < minimum)
1153  {
1154  number = n;
1155  minimum = r;
1156  }
1157  }
1158  else
1159  {
1160  error::instance() << f_current->get_position()
1161  << "min() expects any number of numbers."
1163  }
1164  }
1165  return number;
1166 }
1167 
1169 {
1170  // not(boolean)
1171  node::pointer_t arg1(func->get_child(0));
1172  if(arg1->size() != 1)
1173  {
1174  error::instance() << f_current->get_position()
1175  << "not() expects a boolean as its first argument."
1177  return node::pointer_t();
1178  }
1179  else
1180  {
1181  bool const r(boolean(arg1->get_child(0)));
1182  node::pointer_t result(new node(node_type_t::BOOLEAN, func->get_position()));
1183  result->set_boolean(!r); // this is 'not()' so false is true and vice versa
1184  return result;
1185  }
1186 }
1187 
1189 {
1190  // percentage(expr)
1192  if(any)
1193  {
1194  switch(any->get_type())
1195  {
1197  {
1198  node::pointer_t number(new node(node_type_t::PERCENT, any->get_position()));
1199  number->set_decimal_number(any->get_decimal_number());
1200  return number;
1201  }
1202 
1203  case node_type_t::PERCENT:
1204  // already a percentage, return as is
1205  return any;
1206 
1207  case node_type_t::INTEGER:
1208  {
1209  node::pointer_t number(new node(node_type_t::PERCENT, any->get_position()));
1210  number->set_decimal_number(any->get_integer());
1211  return number;
1212  }
1213 
1215  case node_type_t::STRING:
1216  case node_type_t::URL:
1217  {
1218  std::stringstream ss;
1219  ss << any->get_string();
1220  lexer l(ss, any->get_position());
1221  node::pointer_t number(l.next_token());
1222  if(number->is(node_type_t::WHITESPACE))
1223  {
1224  number = l.next_token();
1225  }
1226  switch(number->get_type())
1227  {
1229  {
1230  node::pointer_t result(new node(node_type_t::PERCENT, any->get_position()));
1231  result->set_decimal_number(number->get_decimal_number());
1232  return result;
1233  }
1234 
1235  case node_type_t::PERCENT:
1236  return number;
1237 
1238  case node_type_t::INTEGER:
1239  {
1240  node::pointer_t result(new node(node_type_t::PERCENT, any->get_position()));
1241  result->set_decimal_number(number->get_integer());
1242  return result;
1243  }
1244 
1245  default:
1246  break;
1247 
1248  }
1249  }
1250  error::instance() << f_current->get_position()
1251  << "percentage() expects a string parameter to represent a valid integer, decimal number, or percent value."
1253  return node::pointer_t();
1254 
1255  default:
1256  break;
1257 
1258  }
1259  }
1260 
1261  error::instance() << f_current->get_position()
1262  << "percentage() expects one value as parameter."
1264 
1265  return node::pointer_t();
1266 }
1267 
1269 {
1270  // red(color)
1271  color c;
1273  if(col)
1274  {
1279  c.get_color(r, g, b, a);
1280  node::pointer_t component(new node(node_type_t::INTEGER, func->get_position()));
1281  component->set_integer(static_cast<integer_t>(r * 255.0 + 0.5));
1282  return component;
1283  }
1284 
1285  error::instance() << f_current->get_position()
1286  << "red() expects a color as parameter."
1288 
1289  return node::pointer_t();
1290 }
1291 
1293 {
1294  // rgb(color)
1295  // rgb(red, green, blue)
1296  color c;
1298  if(col)
1299  {
1300  // force alpha to 1.0
1305  c.get_color(r, g, b, a);
1306  c.set_color(r, g, b, static_cast<color_component_t>(1.0));
1307  col->set_color(c);
1308  return col;
1309  }
1310  else
1311  {
1312  decimal_number_t r;
1313  decimal_number_t g;
1314  decimal_number_t b;
1315 
1319 
1320  if(col1 && col2 && col3)
1321  {
1322  // force alpha to 1.0
1323  c.set_color(r / 255.0, g / 255.0, b / 255.0, 1.0);
1324  col.reset(new node(node_type_t::COLOR, func->get_position()));
1325  col->set_color(c);
1326  return col;
1327  }
1328  }
1329 
1330  error::instance() << f_current->get_position()
1331  << "rgb() expects exactly one color parameter (Color) or three numbers (Red, Green, Blue)."
1333 
1334  return node::pointer_t();
1335 }
1336 
1338 {
1339  // rgba(color, alpha)
1340  // rgba(red, green, blue, alpha)
1341  color c;
1342  decimal_number_t a;
1345  if(col && alpha)
1346  {
1347  // replace alpha
1351  color_component_t old_a;
1352  c.get_color(r, g, b, old_a);
1353  c.set_color(r, g, b, static_cast<color_component_t>(a));
1354  col->set_color(c);
1355  return col;
1356  }
1357  else
1358  {
1359  decimal_number_t r;
1360  decimal_number_t g;
1361  decimal_number_t b;
1362 
1367 
1368  if(col1 && col2 && col3 && col4)
1369  {
1370  // set color with alpha
1371  c.set_color(r / 255.0, g / 255.0, b / 255.0, a);
1372  col.reset(new node(node_type_t::COLOR, func->get_position()));
1373  col->set_color(c);
1374  return col;
1375  }
1376  }
1377 
1378  error::instance() << f_current->get_position()
1379  << "rgba() expects exactly one color parameter followed by alpha (Color, Alpha) or four numbers (Red, Green, Blue, Alpha)."
1381 
1382  return node::pointer_t();
1383 }
1384 
1386 {
1387  // random()
1388  node::pointer_t number(new node(node_type_t::DECIMAL_NUMBER, func->get_position()));
1389  // rand() is certainly the worst function ever, but I am not even
1390  // sure why anyone would ever want to use random() in a CSS document
1391  // (frankly?! random CSS???)
1392  number->set_decimal_number(static_cast<decimal_number_t>(rand()) / (static_cast<decimal_number_t>(RAND_MAX) + 1.0));
1393  return number;
1394 }
1395 
1397 {
1398  // round(number)
1399  decimal_number_t n;
1400  node::pointer_t number(internal_function__get_number(func, 0, n));
1401  if(number)
1402  {
1403  if(number->is(node_type_t::DECIMAL_NUMBER))
1404  {
1405  number->set_decimal_number(round(number->get_decimal_number()));
1406  }
1407  return number;
1408  }
1409 
1410  error::instance() << f_current->get_position()
1411  << "round() expects a number as parameter."
1413 
1414  return node::pointer_t();
1415 }
1416 
1418 {
1419  // saturation(color)
1420  color c;
1422  if(col)
1423  {
1424  color_component_t hue;
1425  color_component_t saturation;
1426  color_component_t lightness;
1428  c.get_hsl(hue, saturation, lightness, a);
1429  node::pointer_t component(new node(node_type_t::PERCENT, func->get_position()));
1430  component->set_decimal_number(saturation);
1431  return component;
1432  }
1433 
1434  error::instance() << f_current->get_position()
1435  << "saturation() expects a color as parameter."
1437 
1438  return node::pointer_t();
1439 }
1440 
1442 {
1443  // sign(number)
1444  decimal_number_t n;
1446  if(number)
1447  {
1448  if(number->is(node_type_t::INTEGER))
1449  {
1450  number->set_integer(n < 0.0 ? -1 : (n > 0.0 ? 1 : 0));
1451  }
1452  else
1453  {
1454  number->set_decimal_number(n < 0.0 ? -1.0 : (n > 0.0 ? 1.0 : 0.0));
1455  }
1456  return number;
1457  }
1458 
1459  error::instance() << f_current->get_position()
1460  << "sign() expects a number as parameter."
1462 
1463  return node::pointer_t();
1464 }
1465 
1467 {
1468  // sin(number)
1469  decimal_number_t n;
1470  node::pointer_t number(internal_function__get_number(func, 0, n));
1471  if(number)
1472  {
1473  std::string const dimension(number->get_string());
1474  if(number->is(node_type_t::INTEGER))
1475  {
1476  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
1477  }
1478  else
1479  {
1480  // we "lose" the dimension
1481  number->set_string("");
1482  }
1483  n = dimension_to_radians(func->get_position(), n, dimension);
1484  number->set_decimal_number(sin(n));
1485  return number;
1486  }
1487 
1488  error::instance() << f_current->get_position()
1489  << "sin() expects an angle as parameter."
1491 
1492  return node::pointer_t();
1493 }
1494 
1496 {
1497  // sqrt(number)
1498  decimal_number_t n;
1499  node::pointer_t number(internal_function__get_number(func, 0, n));
1500  if(number)
1501  {
1502  if(n < 0.0)
1503  {
1504  // an error occured, we cannot handle those dimensions
1505  error::instance() << f_current->get_position()
1506  << "sqrt() expects zero or a positive number."
1508 
1509  return node::pointer_t();
1510  }
1511  std::string dimension(number->get_string());
1512  if(!dimension.empty())
1513  {
1514  // the dimension MUST be a square
1515  //
1516  // first get the current dimensions
1517  dimension_vector_t dividend;
1518  dimension_vector_t divisor;
1519  dimensions_to_vectors(number->get_position(), dimension, dividend, divisor);
1520 
1521  if(((dividend.size() & 1) == 0)
1522  && ((divisor.size() & 1) == 0))
1523  {
1524  dimension_vector_t new_dividend;
1525  while(dividend.size() > 0)
1526  {
1527  std::string const dim(*(dividend.end() - 1));
1528  // remove this instance
1529  dividend.erase(dividend.end() - 1);
1530  // make sure there is another instance
1531  dimension_vector_t::iterator it(std::find(dividend.begin(), dividend.end(), dim));
1532  if(it == dividend.end())
1533  {
1534  // it's not valid
1535  dimension.clear();
1536  break;
1537  }
1538  // remove the copy instance
1539  dividend.erase(it);
1540  // keep one instance here instead
1541  new_dividend.push_back(dim);
1542  }
1543 
1544  dimension_vector_t new_divisor;
1545  if(!dimension.empty())
1546  {
1547  while(divisor.size() > 0)
1548  {
1549  std::string const dim(*(divisor.end() - 1));
1550  // remove this instance
1551  divisor.erase(divisor.end() - 1);
1552  // make sure there is another instance
1553  dimension_vector_t::iterator it(std::find(divisor.begin(), divisor.end(), dim));
1554  if(it == divisor.end())
1555  {
1556  // it's not valid
1557  dimension.clear();
1558  break;
1559  }
1560  // remove the copy instance
1561  divisor.erase(it);
1562  // keep one instance here instead
1563  new_divisor.push_back(dim);
1564  }
1565  }
1566 
1567  if(!dimension.empty())
1568  {
1569  dimension = rebuild_dimension(new_dividend, new_divisor);
1570  }
1571  }
1572  else
1573  {
1574  dimension.clear();
1575  }
1576 
1577  if(dimension.empty())
1578  {
1579  // an error occured, we cannot handle those dimensions
1580  error::instance() << f_current->get_position()
1581  << "sqrt() expects dimensions to be squarely defined (i.e. 'px * px')."
1583 
1584  return node::pointer_t();
1585  }
1586  }
1587  if(number->is(node_type_t::INTEGER))
1588  {
1589  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
1590  }
1591  number->set_decimal_number(sqrt(n));
1592  number->set_string(dimension);
1593  return number;
1594  }
1595 
1596  error::instance() << f_current->get_position()
1597  << "sqrt() expects a number as parameter."
1599 
1600  return node::pointer_t();
1601 }
1602 
1604 {
1605  // string(expr)
1607  if(any)
1608  {
1609  switch(any->get_type())
1610  {
1611  case node_type_t::STRING:
1612  // already a string, return as is
1613  return any;
1614 
1615  case node_type_t::COLOR:
1617  case node_type_t::INTEGER:
1618  case node_type_t::PERCENT:
1619  {
1620  node::pointer_t id(new node(node_type_t::STRING, any->get_position()));
1621  id->set_string(any->to_string(0));
1622  return id;
1623  }
1624 
1626  case node_type_t::URL:
1627  {
1628  node::pointer_t id(new node(node_type_t::STRING, any->get_position()));
1629  id->set_string(any->get_string());
1630  return id;
1631  }
1632 
1633  default:
1634  break;
1635 
1636  }
1637  }
1638 
1639  error::instance() << f_current->get_position()
1640  << "string() expects one value as parameter."
1642 
1643  return node::pointer_t();
1644 }
1645 
1647 {
1648  // str_length(string)
1649  std::string copy;
1650  node::pointer_t str(internal_function__get_string(func, 0, copy));
1651  if(str)
1652  {
1653  // make sure to compute the proper UTF-8 length
1654  node::pointer_t length(new node(node_type_t::INTEGER, func->get_position()));
1655  size_t l(0);
1656  for(char const *s(copy.c_str()); *s != '\0'; ++s)
1657  {
1658  if(static_cast<unsigned char>(*s) < 0x80
1659  || static_cast<unsigned char>(*s) >= 0xC0)
1660  {
1661  ++l;
1662  }
1663  }
1664  length->set_integer(l);
1665  return length;
1666  }
1667 
1668  error::instance() << f_current->get_position()
1669  << "str_length() expects one string as parameter."
1671 
1672  return node::pointer_t();
1673 }
1674 
1676 {
1677  // tan(number)
1678  decimal_number_t n;
1679  node::pointer_t number(internal_function__get_number(func, 0, n));
1680  if(number)
1681  {
1682  std::string const dimension(number->get_string());
1683  if(number->is(node_type_t::INTEGER))
1684  {
1685  number.reset(new node(node_type_t::DECIMAL_NUMBER, number->get_position()));
1686  }
1687  else
1688  {
1689  // we "lose" the dimension
1690  number->set_string("");
1691  }
1692  n = dimension_to_radians(func->get_position(), n, dimension);
1693  number->set_decimal_number(tan(n));
1694  return number;
1695  }
1696 
1697  error::instance() << f_current->get_position()
1698  << "tan() expects an angle as parameter."
1700 
1701  return node::pointer_t();
1702 }
1703 
1705 {
1706  // unique_id()
1707  // unique_id(identifier)
1708  std::string id;
1709  if(func->size() == 1)
1710  {
1712  if(!user_id)
1713  {
1714  error::instance() << f_current->get_position()
1715  << "unique_id() expects a string or an identifier as its optional parameter."
1717  return node::pointer_t();
1718  }
1719  id = user_id->get_string();
1720  }
1721  if(id.empty())
1722  {
1723  id = "_csspp_unique";
1724  }
1725 
1726  // counter increases on each call
1727  // (this is not too good if the library is used by a GUI)
1729 
1730  id += std::to_string(g_unique_id_counter);
1731 
1732  node::pointer_t identifier(new node(node_type_t::IDENTIFIER, func->get_position()));
1733  identifier->set_string(id);
1734 
1735  return identifier;
1736 }
1737 
1739 {
1740  // type_of(expression)
1742  if(any)
1743  {
1744  node::pointer_t type(new node(node_type_t::STRING, func->get_position()));
1745  switch(any->get_type())
1746  {
1747  case node_type_t::ARRAY:
1748  case node_type_t::LIST:
1749  type->set_string("list");
1750  break;
1751 
1752  case node_type_t::BOOLEAN:
1753  type->set_string("bool");
1754  break;
1755 
1756  case node_type_t::COLOR:
1757  type->set_string("color");
1758  break;
1759 
1761  case node_type_t::PERCENT:
1762  type->set_string("number");
1763  break;
1764 
1766  type->set_string("identifier");
1767  break;
1768 
1769  case node_type_t::INTEGER:
1770  type->set_string("integer");
1771  break;
1772 
1773  case node_type_t::MAP:
1774  type->set_string("map");
1775  break;
1776 
1777  case node_type_t::STRING:
1778  type->set_string("string");
1779  break;
1780 
1782  type->set_string("unicode-range");
1783  break;
1784 
1785  //case node_type_t::NULL_TOKEN: -- null is like undefined
1786  default:
1787  type->set_string("undefined");
1788  break;
1789 
1790  }
1791  return type;
1792  }
1793 
1794  error::instance() << f_current->get_position()
1795  << "type_of() expects one value as a parameter."
1797 
1798  return node::pointer_t();
1799 }
1800 
1802 {
1803  // unit(number)
1804  decimal_number_t n;
1806  if(number)
1807  {
1808  node::pointer_t unit(new node(node_type_t::STRING, func->get_position()));
1809  if(number->is(node_type_t::PERCENT))
1810  {
1811  unit->set_string("%");
1812  }
1813  else
1814  {
1815  unit->set_string(number->get_string());
1816  }
1817  return unit;
1818  }
1819 
1820  error::instance() << f_current->get_position()
1821  << "unit() expects a number as parameter."
1823 
1824  return node::pointer_t();
1825 }
1826 
1828 {
1829  // variable_exists(name)
1830  std::string name;
1832  if(id && !name.empty())
1833  {
1834  node::pointer_t result(new node(node_type_t::BOOLEAN, func->get_position()));
1835 
1836  // although variables were already applied they will still be
1837  // defined when we reach these lines of code
1838  if(f_variable_handler)
1839  {
1840  node::pointer_t var(f_variable_handler->get_variable(name, false));
1841  if(var
1842  && var->is(node_type_t::LIST)
1843  && !var->empty()
1844  && (var->get_child(0)->is(node_type_t::VARIABLE) // $<name>
1845  || var->get_child(0)->is(node_type_t::IDENTIFIER))) // @mixin <name>
1846  {
1847  result->set_boolean(true);
1848  }
1849  }
1850  // else -- default is already false
1851 
1852  return result;
1853  }
1854 
1855  error::instance() << f_current->get_position()
1856  << "variable_exists() expects a string or an identifier as parameter."
1858 
1859  return node::pointer_t();
1860 }
1861 
1863 {
1864  typedef node::pointer_t (expression::*internal_function_t)(node::pointer_t func);
1865 
1866  // TODO: maybe add a parser which takes all the ARGs and transform
1867  // them in a list of ready to use nodes for our internal
1868  // functions?
1869  struct function_table_t
1870  {
1871  char const * f_name;
1872  int f_min_params;
1873  int f_max_params;
1874  internal_function_t f_func;
1875  };
1876 
1877  static function_table_t const g_functions[] =
1878  {
1879  {
1880  "abs",
1881  1,
1882  1,
1884  },
1885  {
1886  "acos",
1887  1,
1888  1,
1890  },
1891  {
1892  "alpha",
1893  1,
1894  1,
1896  },
1897  {
1898  "asin",
1899  1,
1900  1,
1902  },
1903  {
1904  "atan",
1905  1,
1906  1,
1908  },
1909  {
1910  "blue",
1911  1,
1912  1,
1914  },
1915  {
1916  "ceil",
1917  1,
1918  1,
1920  },
1921  {
1922  "cos",
1923  1,
1924  1,
1926  },
1927  {
1928  "decimal_number",
1929  1,
1930  1,
1932  },
1933  {
1934  "floor",
1935  1,
1936  1,
1938  },
1939  {
1940  "frgb",
1941  1,
1942  3,
1944  },
1945  {
1946  "frgba",
1947  2,
1948  4,
1950  },
1951  {
1952  "function_exists",
1953  1,
1954  1,
1956  },
1957  {
1958  "global_variable_exists",
1959  1,
1960  1,
1962  },
1963  {
1964  "green",
1965  1,
1966  1,
1968  },
1969  {
1970  "hsl",
1971  3,
1972  3,
1974  },
1975  {
1976  "hsla",
1977  4,
1978  4,
1980  },
1981  {
1982  "hue",
1983  1,
1984  1,
1986  },
1987  {
1988  "identifier",
1989  1,
1990  1,
1992  },
1993  {
1994  "if",
1995  3,
1996  3,
1998  },
1999  {
2000  "integer",
2001  1,
2002  1,
2004  },
2005  {
2006  "inspect",
2007  1,
2008  1,
2010  },
2011  {
2012  "lightness",
2013  1,
2014  1,
2016  },
2017  {
2018  "log",
2019  1,
2020  1,
2022  },
2023  {
2024  "max",
2025  1,
2026  INT_MAX,
2028  },
2029  {
2030  "min",
2031  1,
2032  INT_MAX,
2034  },
2035  {
2036  "not",
2037  1,
2038  1,
2040  },
2041  {
2042  "percentage",
2043  1,
2044  1,
2046  },
2047  {
2048  "random",
2049  0,
2050  0,
2052  },
2053  {
2054  "red",
2055  1,
2056  1,
2058  },
2059  {
2060  "rgb",
2061  1,
2062  3,
2064  },
2065  {
2066  "rgba",
2067  2,
2068  4,
2070  },
2071  {
2072  "round",
2073  1,
2074  1,
2076  },
2077  {
2078  "saturation",
2079  1,
2080  1,
2082  },
2083  {
2084  "sign",
2085  1,
2086  1,
2088  },
2089  {
2090  "sin",
2091  1,
2092  1,
2094  },
2095  {
2096  "sqrt",
2097  1,
2098  1,
2100  },
2101  {
2102  "string",
2103  1,
2104  1,
2106  },
2107  {
2108  "str_length",
2109  1,
2110  1,
2112  },
2113  {
2114  "tan", // WARNING: just 'tan' is a color... 'tan(...)' is a function
2115  1,
2116  1,
2118  },
2119  {
2120  "type_of",
2121  1,
2122  1,
2124  },
2125  {
2126  "unique_id",
2127  0,
2128  1,
2130  },
2131  {
2132  "unit",
2133  1,
2134  1,
2136  },
2137  {
2138  "variable_exists",
2139  1,
2140  1,
2142  }
2143  };
2144 
2145  std::string const function_name(func->get_string());
2146 
2147  // TODO: (1) verify that functions are properly sorted
2148  // (2) use a binary search
2149  for(size_t idx(0); idx < sizeof(g_functions) / sizeof(g_functions[0]); ++idx)
2150  {
2151  if(function_name == g_functions[idx].f_name)
2152  {
2153  // found the function, it is internal!
2154 
2155  // right number of parameters?
2156  if(func->size() >= static_cast<size_t>(g_functions[idx].f_min_params)
2157  && func->size() <= static_cast<size_t>(g_functions[idx].f_max_params))
2158  {
2159  if(function_name == "function_exists")
2160  {
2161  // first check whether the user is checking for an
2162  // internal function! (because the list of internal
2163  // functions is not available anywhere else)
2164  std::string name;
2166  if(id && !name.empty())
2167  {
2168  for(size_t j(0); j < sizeof(g_functions) / sizeof(g_functions[0]); ++j)
2169  {
2170  if(name == g_functions[j].f_name)
2171  {
2172  node::pointer_t result(new node(node_type_t::BOOLEAN, func->get_position()));
2173  result->set_boolean(true);
2174  return result;
2175  }
2176  }
2177  }
2178  }
2179  return (this->*g_functions[idx].f_func)(func);
2180  }
2181 
2182  if(g_functions[idx].f_min_params == g_functions[idx].f_max_params)
2183  {
2184  error::instance() << f_current->get_position()
2185  << function_name
2186  << "() expects exactly "
2187  << g_functions[idx].f_min_params
2188  << " parameter"
2189  << (g_functions[idx].f_min_params == 1 ? "" : "s")
2190  << "."
2192  }
2193  else
2194  {
2195  error::instance() << f_current->get_position()
2196  << function_name
2197  << "() expects between "
2198  << g_functions[idx].f_min_params
2199  << " and "
2200  << g_functions[idx].f_max_params
2201  << " parameters."
2203  }
2204  return node::pointer_t();
2205  }
2206  }
2207 
2208  // if we have a handler then allow the handler to run to execute
2209  // user defined functions (@mixin func() ...)
2210  if(f_variable_handler)
2211  {
2213  }
2214 
2215  // "unknown" functions have to be left alone since these may be
2216  // CSS functions that we do not want to transform (we already
2217  // worked on their arguments, that's the extend of it at this point.)
2218  //
2219  // For now I mark it as unreachable because we should always be
2220  // using expression objects with a variable handler.
2221  return func; // LCOV_EXCL_LINE
2222 }
2223 
2224 } // namespace csspp
2225 
2226 // Local Variables:
2227 // mode: cpp
2228 // indent-tabs-mode: nil
2229 // c-basic-offset: 4
2230 // tab-width: 4
2231 // End:
2232 
2233 // vim: ts=4 sw=4 et
void set_hsl(color_component_t h, color_component_t s, color_component_t l, color_component_t alpha)
Definition: color.cpp:343
node::pointer_t internal_function__random(node::pointer_t func)
node::pointer_t internal_function__unit(node::pointer_t func)
std::string rebuild_dimension(dimension_vector_t const &dividend, dimension_vector_t const &divisor)
node::pointer_t internal_function__identifier(node::pointer_t func)
node::pointer_t internal_function__frgba(node::pointer_t func)
node::pointer_t internal_function__get_string(node::pointer_t func, size_t argn, std::string &str)
node::pointer_t internal_function__max(node::pointer_t func)
node::pointer_t internal_function__atan(node::pointer_t func)
std::shared_ptr< node > pointer_t
Definition: node.h:122
node::pointer_t internal_function__integer(node::pointer_t func)
node::pointer_t internal_function__hsla(node::pointer_t func)
node::pointer_t internal_function__blue(node::pointer_t func)
node::pointer_t internal_function__string(node::pointer_t func)
node::pointer_t internal_function__get_string_or_identifier(node::pointer_t func, size_t argn, std::string &str)
node::pointer_t next_token()
Definition: lexer.cpp:60
node::pointer_t internal_function__get_number(node::pointer_t func, size_t argn, decimal_number_t &number)
node::pointer_t internal_function__rgba(node::pointer_t func)
node::pointer_t internal_function__cos(node::pointer_t func)
void set_color(rgba_color_t const rgba)
Definition: color.cpp:217
node::pointer_t internal_function__hue(node::pointer_t func)
virtual node::pointer_t get_variable(std::string const &variable_name, bool global_only=false) const =0
static int const g_to_string_flag_show_quotes
Definition: node.h:125
node::pointer_t internal_function__log(node::pointer_t func)
node::pointer_t internal_function__rgb(node::pointer_t func)
node::pointer_t internal_function__str_length(node::pointer_t func)
node::pointer_t internal_function__ceil(node::pointer_t func)
node::pointer_t internal_function__saturation(node::pointer_t func)
node::pointer_t internal_function__get_number_or_percent(node::pointer_t func, size_t argn, decimal_number_t &number)
node::pointer_t internal_function__function_exists(node::pointer_t func)
node::pointer_t internal_function__sin(node::pointer_t func)
node::pointer_t internal_function__round(node::pointer_t func)
void get_hsl(color_component_t &hue, color_component_t &saturation, color_component_t &lightness, color_component_t &alpha) const
Definition: color.cpp:404
decimal_number_t dimension_to_radians(position const &pos, decimal_number_t n, std::string const &dimension)
node::pointer_t internal_function__hsl(node::pointer_t func)
node::pointer_t internal_function__percentage(node::pointer_t func)
node::pointer_t internal_function__acos(node::pointer_t func)
node::pointer_t internal_function__sign(node::pointer_t func)
#define M_PI
Definition: csspp.h:38
expression_variables_interface * f_variable_handler
Definition: expression.h:154
node::pointer_t internal_function__type_of(node::pointer_t func)
float color_component_t
Definition: color.h:26
node::pointer_t internal_function__floor(node::pointer_t func)
node::pointer_t internal_function__sqrt(node::pointer_t func)
node::pointer_t internal_function__green(node::pointer_t func)
double decimal_number_t
Definition: csspp.h:53
node::pointer_t internal_function__unique_id(node::pointer_t funct)
virtual node::pointer_t execute_user_function(node::pointer_t func)=0
static int get_unique_id_counter()
void dimensions_to_vectors(position const &pos, std::string const &dimension, dimension_vector_t &dividend, dimension_vector_t &divisor)
rgba_color_t get_color() const
Definition: color.cpp:456
node::pointer_t internal_function__get_any(node::pointer_t func, size_t argn)
node::pointer_t internal_function__frgb(node::pointer_t func)
node::pointer_t f_current
Definition: expression.h:151
node::pointer_t internal_function__if(node::pointer_t func)
node::pointer_t internal_function__decimal_number(node::pointer_t func)
node::pointer_t internal_function__get_color(node::pointer_t func, size_t argn, color &col)
node::pointer_t internal_function__global_variable_exists(node::pointer_t func)
node::pointer_t internal_function__not(node::pointer_t func)
node::pointer_t internal_function__asin(node::pointer_t func)
static void set_unique_id_counter(int counter)
node::pointer_t internal_function__inspect(node::pointer_t func)
node::pointer_t internal_function__min(node::pointer_t func)
node::pointer_t excecute_function(node::pointer_t func)
node::pointer_t internal_function__variable_exists(node::pointer_t func)
node::pointer_t internal_function__red(node::pointer_t func)
static error & instance()
Definition: error.cpp:78
node::pointer_t internal_function__abs(node::pointer_t func)
node::pointer_t internal_function__alpha(node::pointer_t func)
std::vector< std::string > dimension_vector_t
Definition: expression.h:50
node::pointer_t internal_function__lightness(node::pointer_t func)
node::pointer_t internal_function__tan(node::pointer_t func)

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.