Current Version: 1.0.20
Project Name: csspp
node.cpp
Go to the documentation of this file.
1 // CSS Preprocessor
2 // Copyright (c) 2015-2018 Made to Order Software Corp. All Rights Reserved
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 
32 #include <csspp/node.h>
33 
34 #include <csspp/exceptions.h>
35 #include <csspp/nth_child.h>
36 #include <csspp/unicode_range.h>
37 
38 #include <algorithm>
39 #include <iostream>
40 
41 namespace csspp
42 {
43 
44 // make sure we have a copy (catch makes it a requirement probably because
45 // of template use)
46 size_t const node::npos;
47 
48 namespace
49 {
50 
51 uint32_t g_node_count = 0;
52 uint32_t g_node_max_count = 0;
53 
54 union convert_t
55 {
58 };
59 
61 {
62  switch(type)
63  {
65  case node_type_t::ARG:
70  break;
71 
72  default:
73  {
74  std::stringstream ss;
75  ss << "trying to access (read/write) the integer of a node of type " << type << ", which does not support integers.";
76  throw csspp_exception_logic(ss.str());
77  }
78 
79  }
80 }
81 
83 {
84  switch(type)
85  {
91  break;
92 
93  default:
94  {
95  std::stringstream ss;
96  ss << "trying to access (read/write) the boolean of a node of type " << type << ", which does not support booleans.";
97  throw csspp_exception_logic(ss.str());
98  }
99 
100  }
101 }
102 
104 {
105  switch(type)
106  {
109  case node_type_t::FRAME:
110  break;
111 
112  default:
113  {
114  std::stringstream ss;
115  ss << "trying to access (read/write) the decimal number of a node of type " << type << ", which does not support decimal numbers.";
116  throw csspp_exception_logic(ss.str());
117  }
118 
119  }
120 }
121 
123 {
124  switch(type)
125  {
132  case node_type_t::HASH:
136  case node_type_t::STRING:
137  case node_type_t::URL:
140  break;
141 
142  default:
143  {
144  std::stringstream ss;
145  ss << "trying to access (read/write) the string of a node of type " << type << ", which does not support strings.";
146  throw csspp_exception_logic(ss.str());
147  }
148 
149  }
150 }
151 
153 {
154  switch(type)
155  {
156  case node_type_t::COLOR:
157  break;
158 
159  default:
160  {
161  std::stringstream ss;
162  ss << "trying to access (read/write) the color of a node of type " << type << ", which does not support colors.";
163  throw csspp_exception_logic(ss.str());
164  }
165 
166  }
167 }
168 
170 {
171  switch(type)
172  {
174  break;
175 
176  default:
177  {
178  std::stringstream ss;
179  ss << "trying to access (read/write) the line height of a node of type " << type << ", which does not support line heights.";
180  throw csspp_exception_logic(ss.str());
181  }
182  }
183 }
184 
186 {
187  switch(type)
188  {
189  case node_type_t::ARG:
190  case node_type_t::ARRAY:
195  case node_type_t::LIST:
196  case node_type_t::MAP:
201  case node_type_t::FRAME:
202  break;
203 
204  default:
205  {
206  std::stringstream ss;
207  ss << "trying to access (read/write) the children of a node of type " << type << ", which does not support children.";
208  throw csspp_exception_logic(ss.str());
209  }
210 
211  }
212 }
213 
214 } // no name namespace
215 
216 node::node(node_type_t const type, position const & pos)
217  : f_type(type)
218  , f_position(pos)
219 {
220  ++g_node_count;
221  if(g_node_max_count != 0
223  {
224  // This is NOT a bug per se, you may limit the number of nodes in case
225  // you have a limited amount of memory available or you suspect the
226  // CSS Preprocessor has a bug which allocates nodes forever; this is
227  // used for our tests with a maximum number of nodes equal to one
228  // million (which generally represents a lot less than 1Gb of RAM.)
229  std::cerr << "error: node of type " << type << " cannot be allocated.\n"; // LCOV_EXCL_LINE
230  throw csspp_exception_overflow("node.cpp: node::node() too many nodes allocated at the same time, we are probably having a leak."); // LCOV_EXCL_LINE
231  }
232 }
233 
235 {
236  --g_node_count;
237 }
238 
240 {
241  // create the clone
242  pointer_t result(new node(f_type, f_position));
243 
244  // copy the other simple values
245  result->f_boolean = f_boolean;
246  result->f_integer = f_integer;
247  result->f_decimal_number = f_decimal_number;
248  result->f_string = f_string;
249  result->f_flags = f_flags;
250 
251  for(auto c : f_children)
252  {
253  result->f_children.push_back(c->clone());
254  }
255 
256  result->copy_variable(const_cast<node *>(this)->shared_from_this());
257 
258  return result;
259 }
260 
262 {
263  return f_type;
264 }
265 
266 bool node::is(node_type_t const type) const
267 {
268  return f_type == type;
269 }
270 
272 {
273  switch(f_type)
274  {
277 
279  if(f_string == "true")
280  {
282  }
283  if(f_string == "false"
284  || f_string == "null")
285  {
287  }
289 
292 
295 #pragma GCC diagnostic push
296 #pragma GCC diagnostic ignored "-Wfloat-equal"
298 #pragma GCC diagnostic pop
299 
300  case node_type_t::STRING:
302 
303  case node_type_t::ARRAY:
304  case node_type_t::LIST:
305  case node_type_t::MAP:
307 
308  case node_type_t::COLOR:
309  {
310  color c(get_color());
311  return (c.get_color() & 0x00FFFFFF) == 0
314  }
315  break;
316 
319 
320  default:
322 
323  }
324  /*NOTREACHED*/
325 }
326 
328 {
329  return f_position;
330 }
331 
332 std::string const & node::get_string() const
333 {
335  return f_string;
336 }
337 
338 void node::set_string(std::string const & str)
339 {
341  f_string = str;
342 }
343 
344 std::string const & node::get_lowercase_string() const
345 {
347  return f_lowercase_string;
348 }
349 
350 void node::set_lowercase_string(std::string const & str)
351 {
353  f_lowercase_string = str;
354 }
355 
357 {
359  return f_integer;
360 }
361 
363 {
365  f_integer = integer;
366 }
367 
368 bool node::get_boolean() const
369 {
371  return f_boolean;
372 }
373 
374 void node::set_boolean(bool boolean)
375 {
377  f_boolean = boolean;
378 }
379 
381 {
383  return f_decimal_number;
384 }
385 
387 {
389  f_decimal_number = decimal_number;
390 }
391 
393 {
395 
396  union color_transfer_t
397  {
398  uint64_t f_int;
399  double f_dbl;
400  float f_flt[2];
401  };
402 
403  color_transfer_t c1, c2;
404  c1.f_int = f_integer;
405  c2.f_dbl = f_decimal_number;
406 
407  color c;
408  c.set_color(c1.f_flt[0], c1.f_flt[1], c2.f_flt[0], c2.f_flt[1]);
409 
410  return c;
411 }
412 
414 {
416 
417  union color_transfer_t
418  {
419  uint64_t f_int;
420  double f_dbl;
421  float f_flt[2];
422  };
423 
424  color_transfer_t c1, c2;
425  c.get_color(c1.f_flt[0], c1.f_flt[1], c2.f_flt[0], c2.f_flt[1]);
426 
427  f_integer = c1.f_int;
428  f_decimal_number = c2.f_dbl;
429 }
430 
432 {
434 
435  return f_decimal_number;
436 }
437 
439 {
441 
442  f_decimal_number = font_size;
443 }
444 
446 {
448 
449  convert_t c;
450  c.f_int = f_integer;
451  return c.f_flt;
452 }
453 
455 {
457 
458  convert_t c;
459  c.f_flt = line_height;
460  f_integer = c.f_int;
461 }
462 
463 std::string node::get_dim1() const
464 {
466 
467  std::string::size_type pos(f_string.find('/'));
468  if(pos == std::string::npos)
469  {
470  return f_string;
471  }
472  else
473  {
474  return f_string.substr(0, pos);
475  }
476 }
477 
478 void node::set_dim1(std::string const & dimension)
479 {
481 
482  if(f_string.empty())
483  {
484  f_string = dimension;
485  }
486  else
487  {
488  std::string::size_type pos(f_string.find('/'));
489  if(pos == std::string::npos)
490  {
491  f_string = dimension;
492  }
493  else
494  {
495  f_string = dimension + f_string.substr(pos);
496  }
497  }
498 }
499 
500 std::string node::get_dim2() const
501 {
503 
504  std::string::size_type pos(f_string.find('/'));
505  if(pos == std::string::npos)
506  {
507  return "";
508  }
509  else
510  {
511  return f_string.substr(pos + 1);
512  }
513 }
514 
515 void node::set_dim2(std::string const & dimension)
516 {
518 
519  if(dimension.empty())
520  {
521  std::string::size_type pos(f_string.find('/'));
522  if(pos != std::string::npos)
523  {
524  // remove the '/...'
525  f_string = f_string.substr(0, pos);
526  }
527  return;
528  }
529 
530  if(f_string.empty())
531  {
532  f_string = "/" + dimension;
533  }
534  else
535  {
536  std::string::size_type pos(f_string.find('/'));
537  if(pos == std::string::npos)
538  {
539  f_string += "/" + dimension;
540  }
541  else
542  {
543  f_string = f_string.substr(0, pos + 1) + dimension;
544  }
545  }
546 }
547 
548 bool node::empty() const
549 {
551 
552  return f_children.empty();
553 }
554 
556 {
558 
559  f_children.clear();
560 }
561 
562 size_t node::size() const
563 {
565 
566  return f_children.size();
567 }
568 
570 {
572 
573  auto it(std::find(f_children.begin(), f_children.end(), child));
574  if(it == f_children.end())
575  {
576  return npos;
577  }
578 
579  return it - f_children.begin();
580 }
581 
583 {
585 
586  // make sure we totally ignore EOF in a child list
587  // (this dramatically ease the coding of the parser)
588  //
589  // also we do not need to save two WHITESPACE tokens
590  // one after another
591  //
592  if(!child->is(node_type_t::EOF_TOKEN)
593  && (!child->is(node_type_t::WHITESPACE)
594  || f_children.empty()
595  || !f_children.back()->is(node_type_t::WHITESPACE)))
596  {
597  f_children.push_back(child);
598  }
599 }
600 
601 void node::insert_child(size_t idx, pointer_t child)
602 {
603  // attempting to insert at the end?
604  if(idx == f_children.size())
605  {
606  add_child(child);
607  return;
608  }
609 
611 
612  if(idx >= f_children.size())
613  {
614  throw csspp_exception_overflow("insert_child() called with an index out of range.");
615  }
616 
617  // avoid the EOF_TOKEN, although really it should not happen here
618  if(!child->is(node_type_t::EOF_TOKEN))
619  {
620  f_children.insert(f_children.begin() + idx, child);
621  }
622 }
623 
625 {
627 
628  auto it(std::find(f_children.begin(), f_children.end(), child));
629  if(it == f_children.end())
630  {
631  throw csspp_exception_logic("remove_child() called with a node which is not a child of this node.");
632  }
633 
634  f_children.erase(it);
635 }
636 
637 void node::remove_child(size_t idx)
638 {
640 
641  if(idx >= f_children.size())
642  {
643  throw csspp_exception_overflow("remove_child() called with an index out of range.");
644  }
645 
646  f_children.erase(f_children.begin() + idx);
647 }
648 
650 {
652 
653  if(idx >= f_children.size())
654  {
655  throw csspp_exception_overflow("get_child() called with an index out of range.");
656  }
657 
658  return f_children[idx];
659 }
660 
662 {
663  // if empty, get_child() will throw
664  return get_child(f_children.size() - 1);
665 }
666 
668 {
670  type_supports_children(n->f_type);
671 
672  // children are copied to this node and cleared
673  // in the other node (TBD: should this node have
674  // an empty list of children to start with?)
675  f_children.clear();
676  std::swap(f_children, n->f_children);
677 }
678 
680 {
681  auto it(std::find(f_children.begin(), f_children.end(), o));
682  if(it == f_children.end())
683  {
684 //std::cerr << "------------ Node being replaced:\n" << *o
685 // << "------------ Node to replace with:\n" << *n
686 // << "------------ This node:\n" << *this
687 // << "+++++++++++++++++++++++++++++++++++++++\n";
688  throw csspp_exception_logic("replace_child() called with a node which is not a child of this node.");
689  }
690 
691  size_t const pos(it - f_children.begin());
692  f_children.insert(it, n);
693  f_children.erase(f_children.begin() + pos + 1);
694 }
695 
697 {
698  f_variables.clear();
699 }
700 
701 void node::set_variable(std::string const & name, pointer_t value)
702 {
703  f_variables[name] = value;
704 }
705 
707 {
708  if(source)
709  {
710  for(auto v : source->f_variables)
711  {
712  f_variables[v.first] = v.second->clone();
713  }
714  }
715 }
716 
717 node::pointer_t node::get_variable(std::string const & name)
718 {
719  auto const it(f_variables.find(name));
720  if(it == f_variables.end())
721  {
722  return pointer_t();
723  }
724  return it->second;
725 }
726 
728 {
729  f_flags.clear();
730 }
731 
732 void node::set_flag(std::string const & name, bool value)
733 {
734  if(value)
735  {
736  f_flags[name] = value;
737  }
738  else
739  {
740  auto it(f_flags.find(name));
741  if(it != f_flags.end())
742  {
743  f_flags.erase(it);
744  }
745  }
746 }
747 
748 bool node::get_flag(std::string const & name)
749 {
750  auto it(f_flags.find(name));
751  return it != f_flags.end();
752 }
753 
754 std::string node::to_string(int flags) const
755 {
756  std::stringstream out;
757 
758  switch(f_type)
759  {
760  case node_type_t::ADD:
761  out << "+";
762  break;
763 
764  case node_type_t::AND:
765  out << "&&";
766  break;
767 
769  out << ":=";
770  break;
771 
773  out << "@" << f_string;
774  break;
775 
777  out << (f_boolean ? "true" : "false");
778  break;
779 
780  case node_type_t::COLON:
781  out << ":";
782  break;
783 
784  case node_type_t::COLOR:
785  {
786  color c(get_color());
787  out << c.to_string();
788  }
789  break;
790 
791  case node_type_t::COLUMN:
792  out << "||";
793  break;
794 
795  case node_type_t::COMMA:
796  out << ",";
797  break;
798 
800  if(f_integer == 0)
801  {
802  // note: a completely empty comment is possible here and
803  // nothing will be output; however, in a valid CSS Preprocessor
804  // output, only comments with the @preserve keyword are kept
805  // so it won't be empty (until we decide to remove the @preserve
806  // from the comments...)
807  //
808  std::string::size_type start(0);
809  std::string::size_type end(f_string.find('\n'));
810  while(end != std::string::npos)
811  {
812  out << "// " << f_string.substr(start, end - start) << std::endl;
813  start = end + 1;
814  end = f_string.find('\n', start);
815  }
816  if(start < f_string.size())
817  {
818  out << "// " << f_string.substr(start) << std::endl;
819  }
820  }
821  else
822  {
823  out << "/* " << f_string << " */";
824  }
825  break;
826 
828  out << '?';
829  break;
830 
832  out << "|=";
833  break;
834 
836  // this may be a dimension, if not f_string is empty anyway
837  out << (f_boolean && f_integer >= 0 ? "+" : "") << f_decimal_number << f_string;
838  break;
839 
840  case node_type_t::DIVIDE:
841  if((flags & g_to_string_flag_add_spaces) != 0)
842  {
843  out << " / ";
844  }
845  else
846  {
847  out << "/";
848  }
849  break;
850 
851  case node_type_t::DOLLAR:
852  out << '$';
853  break;
854 
855  case node_type_t::EQUAL:
856  out << '=';
857  break;
858 
860  out << '!';
861  break;
862 
864  // this is a mouthful!
865  out << decimal_number_to_string(get_font_size() * (get_dim1() == "%" ? 100.0 : 1.0), false) << get_dim1()
866  << "/" << decimal_number_to_string(get_line_height() * (get_dim2() == "%" ? 100.0 : 1.0), false) << get_dim2();
867  break;
868 
870  out << '$';
871  /*FALLTHROUGH*/
873  {
874  out << f_string << "(";
875  bool first(true);
876  for(auto c : f_children)
877  {
878  if(first)
879  {
880  first = false;
881  }
882  else
883  {
884  out << ",";
885  }
886  out << c->to_string(flags);
887  }
888  out << ")";
889  }
890  break;
891 
893  out << ">=";
894  break;
895 
897  out << ">";
898  break;
899 
900  case node_type_t::HASH:
901  out << "#" << f_string;
902  break;
903 
905  out << f_string;
906  break;
907 
909  out << "~=";
910  break;
911 
913  // this may be a dimension, if not f_string is empty anyway
914  out << (f_boolean && f_integer >= 0 ? "+" : "") << f_integer << f_string;
915  break;
916 
918  out << "<=";
919  break;
920 
922  out << "<";
923  break;
924 
925  case node_type_t::MODULO:
926  if((flags & g_to_string_flag_add_spaces) != 0)
927  {
928  out << " % ";
929  }
930  else
931  {
932  out << "%";
933  }
934  break;
935 
937  out << "*";
938  break;
939 
941  out << "!=";
942  break;
943 
945  // should null be "null" or ""?
946  out << "";
947  break;
948 
950  out << "{";
951  for(auto c : f_children)
952  {
953  out << c->to_string(flags);
954  }
955  out << "}";
956  break;
957 
959  out << "(";
960  for(auto c : f_children)
961  {
962  out << c->to_string(flags);
963  }
964  out << ")";
965  break;
966 
968  out << "[";
969  for(auto c : f_children)
970  {
971  out << c->to_string(flags);
972  }
973  out << "]";
974  break;
975 
977  out << (f_boolean && f_integer >= 0 ? "+" : "") << decimal_number_to_string(f_decimal_number * 100.0, false) << "%";
978  break;
979 
980  case node_type_t::PERIOD:
981  out << ".";
982  break;
983 
985  out << "%" << f_string;
986  break;
987 
988  case node_type_t::POWER:
989  out << "**";
990  break;
991 
993  out << "~";
994  break;
995 
997  out << "^=";
998  break;
999 
1001  out << "&";
1002  break;
1003 
1004  case node_type_t::SCOPE:
1005  out << "|";
1006  break;
1007 
1009  out << ";";
1010  break;
1011 
1012  case node_type_t::STRING:
1013  if((flags & g_to_string_flag_show_quotes) != 0)
1014  {
1015  int sq(0);
1016  int dq(0);
1017  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1018  {
1019  if(*s == '\'')
1020  {
1021  ++sq;
1022  }
1023  else if(*s == '"')
1024  {
1025  ++dq;
1026  }
1027  }
1028  if(sq >= dq)
1029  {
1030  // use " in this case
1031  out << '"';
1032  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1033  {
1034  if(*s == '"')
1035  {
1036  out << "\\\"";
1037  }
1038  else
1039  {
1040  out << *s;
1041  }
1042  }
1043  out << '"';
1044  }
1045  else
1046  {
1047  // use ' in this case
1048  out << '\'';
1049  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1050  {
1051  if(*s == '\'')
1052  {
1053  out << "\\'";
1054  }
1055  else
1056  {
1057  out << *s;
1058  }
1059  }
1060  out << '\'';
1061  }
1062  }
1063  else
1064  {
1065  // for errors and other messages we do not want the quotes
1066  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1067  {
1068  out << *s;
1069  }
1070  }
1071  break;
1072 
1074  out << "*=";
1075  break;
1076 
1077  case node_type_t::SUBTRACT:
1078  out << "-";
1079  break;
1080 
1082  out << "$=";
1083  break;
1084 
1086  {
1087  unicode_range_t const range(static_cast<range_value_t>(f_integer));
1088  out << "U+" << range.to_string();
1089  }
1090  break;
1091 
1092  case node_type_t::URL:
1093  // TODO: escape special characters or we won't be able to re-read this one
1094  out << "url(" << f_string << ")";
1095  break;
1096 
1097  case node_type_t::VARIABLE:
1098  out << '$' << f_string;
1099  break;
1100 
1102  // this could have been \t or \n...
1103  out << " ";
1104  break;
1105 
1107  {
1108  bool first(true);
1109  for(auto c : f_children)
1110  {
1111  if(c->is(node_type_t::ARG))
1112  {
1113  if(first)
1114  {
1115  first = false;
1116  }
1117  else
1118  {
1119  switch(static_cast<node_type_t>(c->get_integer()))
1120  {
1121  case node_type_t::UNKNOWN: // this is the default if the integer is never set
1122  case node_type_t::COMMA:
1123  out << ",";
1124  break;
1125 
1126  case node_type_t::DIVIDE:
1127  out << "/";
1128  break;
1129 
1130  default:
1131  throw csspp_exception_logic("ARG only supports ',' and '/' as separators.");
1132 
1133  }
1134  }
1135  out << c->to_string(flags);
1136  }
1137  else
1138  {
1139  // this should not happen unless we did not argify yet
1140  // and in that case commas are inline
1141  out << c->to_string(flags);
1142  }
1143  }
1144  }
1145  break;
1146 
1148  {
1149  nth_child const an_b(f_integer);
1150  out << an_b.to_string();
1151  }
1152  break;
1153 
1154  case node_type_t::ARG:
1155  for(auto c : f_children)
1156  {
1157  out << c->to_string(flags);
1158  }
1159  break;
1160 
1162  if(!f_string.empty())
1163  {
1164  out << f_string << ": ";
1165  }
1166  for(size_t idx(0); idx < f_children.size(); ++idx)
1167  {
1168  if(f_children[idx]->f_type == node_type_t::ARG)
1169  {
1170  out << f_children[idx]->to_string(flags);
1171  if(idx + 1 != f_children.size())
1172  {
1173  // multiple lists of arguments are comma separated
1174  out << ",";
1175  }
1176  }
1177  else
1178  {
1179  out << f_children[idx]->to_string(flags);
1180  }
1181  }
1182  break;
1183 
1184  case node_type_t::LIST:
1185  for(size_t idx(0); idx < f_children.size(); ++idx)
1186  {
1187  if(f_children[idx]->f_type == node_type_t::DECLARATION)
1188  {
1189  out << f_children[idx]->to_string(flags);
1190  if(idx + 1 != f_children.size())
1191  {
1192  // multiple declarations are semi-colon separated
1193  out << ";";
1194  }
1195  }
1196  else
1197  {
1198  out << f_children[idx]->to_string(flags);
1199  }
1200  }
1201  break;
1202 
1203  case node_type_t::ARRAY:
1204  {
1205  out << "(";
1206  bool first(true);
1207  for(auto c : f_children)
1208  {
1209  if(first)
1210  {
1211  first = false;
1212  }
1213  else
1214  {
1215  out << ", ";
1216  }
1217  out << c->to_string(flags | g_to_string_flag_show_quotes);
1218  }
1219  out << ")";
1220  }
1221  break;
1222 
1223  case node_type_t::MAP:
1224  {
1225  out << "(";
1226  bool first(true);
1227  bool label(true);
1228  for(auto c : f_children)
1229  {
1230  if(label)
1231  {
1232  if(first)
1233  {
1234  first = false;
1235  }
1236  else
1237  {
1238  out << ", ";
1239  }
1240  }
1241  out << c->to_string(flags | g_to_string_flag_show_quotes);
1242  if(label)
1243  {
1244  out << ": ";
1245  }
1246  label = !label;
1247  }
1248  out << ")";
1249  }
1250  break;
1251 
1252  case node_type_t::FRAME:
1253  if(f_decimal_number <= 0.0)
1254  {
1255  out << "from";
1256  }
1257  else if(f_decimal_number >= 1.0)
1258  {
1259  out << "to";
1260  }
1261  else
1262  {
1263  out << decimal_number_to_string(f_decimal_number * 100.0, false) << "%";
1264  }
1265  out << "{";
1266  for(auto c : f_children)
1267  {
1268  out << c->to_string(flags);
1269  }
1270  out << "}";
1271  break;
1272 
1273  case node_type_t::UNKNOWN:
1274  case node_type_t::CDC:
1275  case node_type_t::CDO:
1280  case node_type_t::max_type:
1281  // many of the nodes are not expected in a valid tree being compiled
1282  // all of those will generate this exception
1283  throw csspp_exception_logic("unexpected token in to_string() call.");
1284 
1285  }
1286 
1287  return out.str();
1288 }
1289 
1290 void node::display(std::ostream & out, uint32_t indent) const
1291 {
1292  std::string indent_str;
1293  for(uint32_t i(0); i < indent; ++i)
1294  {
1295  indent_str += " ";
1296  }
1297  out << indent_str << f_type;
1298 
1299  switch(f_type)
1300  {
1302  case node_type_t::COMMENT:
1306  case node_type_t::FUNCTION:
1307  case node_type_t::HASH:
1309  case node_type_t::INTEGER:
1311  case node_type_t::STRING:
1312  case node_type_t::URL:
1313  case node_type_t::VARIABLE:
1315  out << " \"" << f_string << "\"";
1316  break;
1317 
1318  default:
1319  break;
1320 
1321  }
1322 
1323  switch(f_type)
1324  {
1325  case node_type_t::BOOLEAN:
1327  out << " B:" << (f_boolean ? "true" : "false");
1328  break;
1329 
1330  default:
1331  break;
1332 
1333  }
1334 
1335  switch(f_type)
1336  {
1338  case node_type_t::COMMENT:
1339  case node_type_t::INTEGER:
1341  out << " I:" << f_integer;
1342  break;
1343 
1344  default:
1345  break;
1346 
1347  }
1348 
1349  switch(f_type)
1350  {
1351  case node_type_t::COLOR:
1352  {
1353  color c(get_color());
1354  out << " H:" << std::hex << c.get_color() << std::dec;
1355  }
1356  break;
1357 
1358  default:
1359  break;
1360 
1361  }
1362 
1363  switch(f_type)
1364  {
1366  out << " FM:" << decimal_number_to_string(get_font_size() * (get_dim1() == "%" ? 100.0 : 1.0), false) << get_dim1()
1367  << "/" << decimal_number_to_string(get_line_height() * (get_dim2() == "%" ? 100.0 : 1.0), false) << get_dim2();
1368  break;
1369 
1370  default:
1371  break;
1372 
1373  }
1374 
1375  switch(f_type)
1376  {
1378  {
1379  nth_child const an_b(f_integer);
1380  out << " S:" << an_b.to_string();
1381  }
1382  break;
1383 
1384  default:
1385  break;
1386 
1387  }
1388 
1389  switch(f_type)
1390  {
1392  case node_type_t::PERCENT:
1393  case node_type_t::FRAME:
1394  out << " D:" << decimal_number_to_string(f_decimal_number, false);
1395  break;
1396 
1397  default:
1398  break;
1399 
1400  }
1401 
1402  for(auto f : f_flags)
1403  {
1404  out << " F:" << f.first;
1405  }
1406 
1407  out << "\n";
1408 
1409  for(auto v : f_variables)
1410  {
1411  out << indent_str << " V:" << v.first << "\n";
1412  v.second->display(out, indent + 6);
1413  }
1414 
1415 
1416  switch(f_type)
1417  {
1418  case node_type_t::ARG:
1419  case node_type_t::ARRAY:
1424  case node_type_t::FUNCTION:
1425  case node_type_t::LIST:
1426  case node_type_t::MAP:
1431  case node_type_t::FRAME:
1432  // display the children now
1433  for(size_t i(0); i < f_children.size(); ++i)
1434  {
1435  f_children[i]->display(out, indent + 2);
1436  }
1437  break;
1438 
1439  default:
1440  break;
1441 
1442  }
1443 }
1444 
1445 void node::limit_nodes_to(uint32_t count)
1446 {
1447  g_node_max_count = count;
1448 }
1449 
1450 } // namespace csspp
1451 
1452 std::ostream & operator << (std::ostream & out, csspp::node_type_t const type)
1453 {
1454  switch(type)
1455  {
1457  out << "UNKNOWN";
1458  break;
1459 
1461  out << "ADD";
1462  break;
1463 
1465  out << "AND";
1466  break;
1467 
1469  out << "ASSIGNMENT";
1470  break;
1471 
1473  out << "AT_KEYWORD";
1474  break;
1475 
1477  out << "BOOLEAN";
1478  break;
1479 
1481  out << "CDC";
1482  break;
1483 
1485  out << "CDO";
1486  break;
1487 
1489  out << "CLOSE_CURLYBRACKET";
1490  break;
1491 
1493  out << "CLOSE_PARENTHESIS";
1494  break;
1495 
1497  out << "CLOSE_SQUAREBRACKET";
1498  break;
1499 
1501  out << "COLON";
1502  break;
1503 
1505  out << "COLOR";
1506  break;
1507 
1509  out << "COLUMN";
1510  break;
1511 
1513  out << "COMMA";
1514  break;
1515 
1517  out << "COMMENT";
1518  break;
1519 
1521  out << "CONDITIONAL";
1522  break;
1523 
1525  out << "DASH_MATCH";
1526  break;
1527 
1529  out << "DECIMAL_NUMBER";
1530  break;
1531 
1533  out << "DIVIDE";
1534  break;
1535 
1537  out << "DOLLAR";
1538  break;
1539 
1541  out << "EOF_TOKEN";
1542  break;
1543 
1545  out << "EQUAL";
1546  break;
1547 
1549  out << "EXCLAMATION";
1550  break;
1551 
1553  out << "FONT_METRICS";
1554  break;
1555 
1557  out << "FUNCTION";
1558  break;
1559 
1561  out << "GREATER_EQUAL";
1562  break;
1563 
1565  out << "GREATER_THAN";
1566  break;
1567 
1569  out << "HASH";
1570  break;
1571 
1573  out << "IDENTIFIER";
1574  break;
1575 
1577  out << "INCLUDE_MATCH";
1578  break;
1579 
1581  out << "INTEGER";
1582  break;
1583 
1585  out << "LESS_EQUAL";
1586  break;
1587 
1589  out << "LESS_THAN";
1590  break;
1591 
1593  out << "MODULO";
1594  break;
1595 
1597  out << "MULTIPLY";
1598  break;
1599 
1601  out << "NOT_EQUAL";
1602  break;
1603 
1605  out << "NULL_TOKEN";
1606  break;
1607 
1609  out << "OPEN_CURLYBRACKET";
1610  break;
1611 
1613  out << "OPEN_PARENTHESIS";
1614  break;
1615 
1617  out << "OPEN_SQUAREBRACKET";
1618  break;
1619 
1621  out << "PERCENT";
1622  break;
1623 
1625  out << "PERIOD";
1626  break;
1627 
1629  out << "PLACEHOLDER";
1630  break;
1631 
1633  out << "POWER";
1634  break;
1635 
1637  out << "PRECEDED";
1638  break;
1639 
1641  out << "PREFIX_MATCH";
1642  break;
1643 
1645  out << "REFERENCE";
1646  break;
1647 
1649  out << "SCOPE";
1650  break;
1651 
1653  out << "SEMICOLON";
1654  break;
1655 
1657  out << "STRING";
1658  break;
1659 
1661  out << "SUBSTRING_MATCH";
1662  break;
1663 
1665  out << "SUBTRACT";
1666  break;
1667 
1669  out << "SUFFIX_MATCH";
1670  break;
1671 
1673  out << "UNICODE_RANGE";
1674  break;
1675 
1677  out << "URL";
1678  break;
1679 
1681  out << "VARIABLE";
1682  break;
1683 
1685  out << "VARIABLE_FUNCTION";
1686  break;
1687 
1689  out << "WHITESPACE";
1690  break;
1691 
1692  // Grammar related nodes (i.e. composed nodes)
1694  out << "AN_PLUS_B";
1695  break;
1696 
1698  out << "ARG";
1699  break;
1700 
1702  out << "ARRAY";
1703  break;
1704 
1706  out << "COMPONENT_VALUE";
1707  break;
1708 
1710  out << "DECLARATION";
1711  break;
1712 
1714  out << "LIST";
1715  break;
1716 
1718  out << "MAP";
1719  break;
1720 
1722  out << "FRAME";
1723  break;
1724 
1726  out << "max_type";
1727  break;
1728 
1729  }
1730 
1731  return out;
1732 }
1733 
1734 std::ostream & operator << (std::ostream & out, csspp::node const & n)
1735 {
1736  n.display(out, 0);
1737  return out;
1738 }
1739 
1741 {
1742  std::stringstream ss;
1743  ss << type;
1744  out << ss.str();
1745  return out;
1746 }
1747 
1748 // Local Variables:
1749 // mode: cpp
1750 // indent-tabs-mode: nil
1751 // c-basic-offset: 4
1752 // tab-width: 4
1753 // End:
1754 
1755 // vim: ts=4 sw=4 et
pointer_t clone() const
Definition: node.cpp:239
static size_t const npos
Definition: node.h:129
void add_child(pointer_t child)
Definition: node.cpp:582
void clear_flags()
Definition: node.cpp:727
bool empty() const
Definition: node.cpp:548
list_t f_children
Definition: node.h:204
position const & get_position() const
Definition: node.cpp:327
std::string decimal_number_to_string(decimal_number_t d, bool remove_leading_zero)
Definition: csspp.cpp:75
void insert_child(size_t idx, pointer_t child)
Definition: node.cpp:601
std::string to_string() const
Definition: color.cpp:484
std::shared_ptr< node > pointer_t
Definition: node.h:128
std::string to_string(int flags) const
Definition: node.cpp:754
int64_t integer_t
Definition: csspp.h:54
bool f_boolean
Definition: node.h:199
variable_table_t f_variables
Definition: node.h:205
void type_supports_children(node_type_t const type)
Definition: node.cpp:185
pointer_t get_variable(std::string const &name)
Definition: node.cpp:717
The namespace of all the classes in the CSS Preprocessor.
Definition: assembler.cpp:40
decimal_number_t get_line_height() const
Definition: node.cpp:445
std::string const & get_string() const
Definition: node.cpp:332
node_type_t
Definition: node.h:36
void set_flag(std::string const &name, bool value)
Definition: node.cpp:732
pointer_t get_last_child() const
Definition: node.cpp:661
void take_over_children_of(pointer_t n)
Definition: node.cpp:667
decimal_number_t get_font_size() const
Definition: node.cpp:431
void set_lowercase_string(std::string const &str)
Definition: node.cpp:350
void set_dim1(std::string const &font_size)
Definition: node.cpp:478
void type_supports_integer(node_type_t const type)
Definition: node.cpp:60
void remove_child(pointer_t child)
Definition: node.cpp:624
color get_color() const
Definition: node.cpp:392
void set_color(rgba_color_t const rgba)
Definition: color.cpp:217
void set_line_height(decimal_number_t line_height)
Definition: node.cpp:454
bool get_flag(std::string const &name)
Definition: node.cpp:748
void type_supports_color(node_type_t const type)
Definition: node.cpp:152
static int const g_to_string_flag_show_quotes
Definition: node.h:131
decimal_number_t f_decimal_number
Definition: node.h:201
bool is(node_type_t const type) const
Definition: node.cpp:266
void set_decimal_number(decimal_number_t decimal_number)
Definition: node.cpp:386
position f_position
Definition: node.h:198
void display(std::ostream &out, uint32_t indent) const
Definition: node.cpp:1290
std::string to_string() const
void set_variable(std::string const &name, pointer_t value)
Definition: node.cpp:701
void clear()
Definition: node.cpp:555
void set_string(std::string const &str)
Definition: node.cpp:338
boolean_t
Definition: node.h:29
size_t size() const
Definition: node.cpp:562
node(node_type_t const type, position const &pos)
Definition: node.cpp:216
void set_font_size(decimal_number_t font_size)
Definition: node.cpp:438
void set_dim2(std::string const &line_height)
Definition: node.cpp:515
static int const g_to_string_flag_add_spaces
Definition: node.h:132
std::string get_dim1() const
Definition: node.cpp:463
pointer_t get_child(size_t idx) const
Definition: node.cpp:649
std::string get_dim2() const
Definition: node.cpp:500
void type_supports_string(node_type_t const type)
Definition: node.cpp:122
void type_supports_boolean(node_type_t const type)
Definition: node.cpp:82
void replace_child(pointer_t o, pointer_t n)
Definition: node.cpp:679
decimal_number_t get_decimal_number() const
Definition: node.cpp:380
double decimal_number_t
Definition: csspp.h:55
void set_integer(integer_t integer)
Definition: node.cpp:362
static void limit_nodes_to(uint32_t count)
Definition: node.cpp:1445
std::string f_string
Definition: node.h:202
rgba_color_t get_color() const
Definition: color.cpp:456
std::string f_lowercase_string
Definition: node.h:203
node_type_t get_type() const
Definition: node.cpp:261
void set_color(color c)
Definition: node.cpp:413
void set_boolean(bool integer)
Definition: node.cpp:374
boolean_t to_boolean() const
Definition: node.cpp:271
integer_t f_integer
Definition: node.h:200
std::string to_string() const
Definition: nth_child.cpp:356
bool get_boolean() const
Definition: node.cpp:368
std::string const & get_lowercase_string() const
Definition: node.cpp:344
std::ostream & operator<<(std::ostream &out, csspp::node_type_t const type)
Definition: node.cpp:1452
void type_supports_font_metrics(node_type_t const type)
Definition: node.cpp:169
node_type_t f_type
Definition: node.h:197
void copy_variable(node::pointer_t source)
Definition: node.cpp:706
integer_t get_integer() const
Definition: node.cpp:356
void type_supports_decimal_number(node_type_t const type)
Definition: node.cpp:103
flag_table_t f_flags
Definition: node.h:206
void clear_variables()
Definition: node.cpp:696
size_t child_position(pointer_t child)
Definition: node.cpp:569

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.