Current Version: 1.0.10
Project Name: csspp
node.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 
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  break;
110 
111  default:
112  {
113  std::stringstream ss;
114  ss << "trying to access (read/write) the decimal number of a node of type " << type << ", which does not support decimal numbers.";
115  throw csspp_exception_logic(ss.str());
116  }
117 
118  }
119 }
120 
122 {
123  switch(type)
124  {
131  case node_type_t::HASH:
135  case node_type_t::STRING:
136  case node_type_t::URL:
139  break;
140 
141  default:
142  {
143  std::stringstream ss;
144  ss << "trying to access (read/write) the string of a node of type " << type << ", which does not support strings.";
145  throw csspp_exception_logic(ss.str());
146  }
147 
148  }
149 }
150 
152 {
153  switch(type)
154  {
155  case node_type_t::COLOR:
156  break;
157 
158  default:
159  {
160  std::stringstream ss;
161  ss << "trying to access (read/write) the color of a node of type " << type << ", which does not support colors.";
162  throw csspp_exception_logic(ss.str());
163  }
164 
165  }
166 }
167 
169 {
170  switch(type)
171  {
173  break;
174 
175  default:
176  {
177  std::stringstream ss;
178  ss << "trying to access (read/write) the line height of a node of type " << type << ", which does not support line heights.";
179  throw csspp_exception_logic(ss.str());
180  }
181  }
182 }
183 
185 {
186  switch(type)
187  {
188  case node_type_t::ARG:
189  case node_type_t::ARRAY:
194  case node_type_t::LIST:
195  case node_type_t::MAP:
200  break;
201 
202  default:
203  {
204  std::stringstream ss;
205  ss << "trying to access (read/write) the children of a node of type " << type << ", which does not support children.";
206  throw csspp_exception_logic(ss.str());
207  }
208 
209  }
210 }
211 
212 } // no name namespace
213 
214 node::node(node_type_t const type, position const & pos)
215  : f_type(type)
216  , f_position(pos)
217 {
218  ++g_node_count;
219  if(g_node_max_count != 0
221  {
222  // This is NOT a bug per se, you may limit the number of nodes in case
223  // you have a limited amount of memory available or you suspect the
224  // CSS Preprocessor has a bug which allocates nodes forever; this is
225  // used for our tests with a maximum number of nodes equal to one
226  // million (which generally represents a lot less than 1Gb of RAM.)
227  std::cerr << "error: node of type " << type << " cannot be allocated.\n"; // LCOV_EXCL_LINE
228  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
229  }
230 }
231 
233 {
234  --g_node_count;
235 }
236 
238 {
239  // create the clone
240  pointer_t result(new node(f_type, f_position));
241 
242  // copy the other simple values
243  result->f_boolean = f_boolean;
244  result->f_integer = f_integer;
245  result->f_decimal_number = f_decimal_number;
246  result->f_string = f_string;
247  result->f_flags = f_flags;
248 
249  for(auto c : f_children)
250  {
251  result->f_children.push_back(c->clone());
252  }
253 
254  result->copy_variable(const_cast<node *>(this)->shared_from_this());
255 
256  return result;
257 }
258 
260 {
261  return f_type;
262 }
263 
264 bool node::is(node_type_t const type) const
265 {
266  return f_type == type;
267 }
268 
270 {
271  switch(f_type)
272  {
275 
277  if(f_string == "true")
278  {
280  }
281  if(f_string == "false"
282  || f_string == "null")
283  {
285  }
287 
290 
293 #pragma GCC diagnostic push
294 #pragma GCC diagnostic ignored "-Wfloat-equal"
296 #pragma GCC diagnostic pop
297 
298  case node_type_t::STRING:
300 
301  case node_type_t::ARRAY:
302  case node_type_t::LIST:
303  case node_type_t::MAP:
305 
306  case node_type_t::COLOR:
307  {
308  color c(get_color());
309  return (c.get_color() & 0x00FFFFFF) == 0
312  }
313  break;
314 
317 
318  default:
320 
321  }
322  /*NOTREACHED*/
323 }
324 
326 {
327  return f_position;
328 }
329 
330 std::string const & node::get_string() const
331 {
333  return f_string;
334 }
335 
336 void node::set_string(std::string const & str)
337 {
339  f_string = str;
340 }
341 
342 std::string const & node::get_lowercase_string() const
343 {
345  return f_lowercase_string;
346 }
347 
348 void node::set_lowercase_string(std::string const & str)
349 {
351  f_lowercase_string = str;
352 }
353 
355 {
357  return f_integer;
358 }
359 
361 {
363  f_integer = integer;
364 }
365 
366 bool node::get_boolean() const
367 {
369  return f_boolean;
370 }
371 
372 void node::set_boolean(bool boolean)
373 {
375  f_boolean = boolean;
376 }
377 
379 {
381  return f_decimal_number;
382 }
383 
385 {
387  f_decimal_number = decimal_number;
388 }
389 
391 {
393 
394  union color_transfer_t
395  {
396  uint64_t f_int;
397  double f_dbl;
398  float f_flt[2];
399  };
400 
401  color_transfer_t c1, c2;
402  c1.f_int = f_integer;
403  c2.f_dbl = f_decimal_number;
404 
405  color c;
406  c.set_color(c1.f_flt[0], c1.f_flt[1], c2.f_flt[0], c2.f_flt[1]);
407 
408  return c;
409 }
410 
412 {
414 
415  union color_transfer_t
416  {
417  uint64_t f_int;
418  double f_dbl;
419  float f_flt[2];
420  };
421 
422  color_transfer_t c1, c2;
423  c.get_color(c1.f_flt[0], c1.f_flt[1], c2.f_flt[0], c2.f_flt[1]);
424 
425  f_integer = c1.f_int;
426  f_decimal_number = c2.f_dbl;
427 }
428 
430 {
432 
433  return f_decimal_number;
434 }
435 
437 {
439 
440  f_decimal_number = font_size;
441 }
442 
444 {
446 
447  convert_t c;
448  c.f_int = f_integer;
449  return c.f_flt;
450 }
451 
453 {
455 
456  convert_t c;
457  c.f_flt = line_height;
458  f_integer = c.f_int;
459 }
460 
461 std::string node::get_dim1() const
462 {
464 
465  std::string::size_type pos(f_string.find('/'));
466  if(pos == std::string::npos)
467  {
468  return f_string;
469  }
470  else
471  {
472  return f_string.substr(0, pos);
473  }
474 }
475 
476 void node::set_dim1(std::string const & dimension)
477 {
479 
480  if(f_string.empty())
481  {
482  f_string = dimension;
483  }
484  else
485  {
486  std::string::size_type pos(f_string.find('/'));
487  if(pos == std::string::npos)
488  {
489  f_string = dimension;
490  }
491  else
492  {
493  f_string = dimension + f_string.substr(pos);
494  }
495  }
496 }
497 
498 std::string node::get_dim2() const
499 {
501 
502  std::string::size_type pos(f_string.find('/'));
503  if(pos == std::string::npos)
504  {
505  return "";
506  }
507  else
508  {
509  return f_string.substr(pos + 1);
510  }
511 }
512 
513 void node::set_dim2(std::string const & dimension)
514 {
516 
517  if(dimension.empty())
518  {
519  std::string::size_type pos(f_string.find('/'));
520  if(pos != std::string::npos)
521  {
522  // remove the '/...'
523  f_string = f_string.substr(0, pos);
524  }
525  return;
526  }
527 
528  if(f_string.empty())
529  {
530  f_string = "/" + dimension;
531  }
532  else
533  {
534  std::string::size_type pos(f_string.find('/'));
535  if(pos == std::string::npos)
536  {
537  f_string += "/" + dimension;
538  }
539  else
540  {
541  f_string = f_string.substr(0, pos + 1) + dimension;
542  }
543  }
544 }
545 
546 bool node::empty() const
547 {
549 
550  return f_children.empty();
551 }
552 
554 {
556 
557  f_children.clear();
558 }
559 
560 size_t node::size() const
561 {
563 
564  return f_children.size();
565 }
566 
568 {
570 
571  auto it(std::find(f_children.begin(), f_children.end(), child));
572  if(it == f_children.end())
573  {
574  return npos;
575  }
576 
577  return it - f_children.begin();
578 }
579 
581 {
583 
584  // make sure we totally ignore EOF in a child list
585  // (this dramatically ease the coding of the parser)
586  //
587  // also we do not need to save two WHITESPACE tokens
588  // one after another
589  //
590  if(!child->is(node_type_t::EOF_TOKEN)
591  && (!child->is(node_type_t::WHITESPACE)
592  || f_children.empty()
593  || !f_children.back()->is(node_type_t::WHITESPACE)))
594  {
595  f_children.push_back(child);
596  }
597 }
598 
599 void node::insert_child(size_t idx, pointer_t child)
600 {
601  // attempting to insert at the end?
602  if(idx == f_children.size())
603  {
604  add_child(child);
605  return;
606  }
607 
609 
610  if(idx >= f_children.size())
611  {
612  throw csspp_exception_overflow("insert_child() called with an index out of range.");
613  }
614 
615  // avoid the EOF_TOKEN, although really it should not happen here
616  if(!child->is(node_type_t::EOF_TOKEN))
617  {
618  f_children.insert(f_children.begin() + idx, child);
619  }
620 }
621 
623 {
625 
626  auto it(std::find(f_children.begin(), f_children.end(), child));
627  if(it == f_children.end())
628  {
629  throw csspp_exception_logic("remove_child() called with a node which is not a child of this node.");
630  }
631 
632  f_children.erase(it);
633 }
634 
635 void node::remove_child(size_t idx)
636 {
638 
639  if(idx >= f_children.size())
640  {
641  throw csspp_exception_overflow("remove_child() called with an index out of range.");
642  }
643 
644  f_children.erase(f_children.begin() + idx);
645 }
646 
648 {
650 
651  if(idx >= f_children.size())
652  {
653  throw csspp_exception_overflow("get_child() called with an index out of range.");
654  }
655 
656  return f_children[idx];
657 }
658 
660 {
661  // if empty, get_child() will throw
662  return get_child(f_children.size() - 1);
663 }
664 
666 {
668  type_supports_children(n->f_type);
669 
670  // children are copied to this node and cleared
671  // in the other node (TBD: should this node have
672  // an empty list of children to start with?)
673  f_children.clear();
674  std::swap(f_children, n->f_children);
675 }
676 
678 {
679  auto it(std::find(f_children.begin(), f_children.end(), o));
680  if(it == f_children.end())
681  {
682 //std::cerr << "------------ Node being replaced:\n" << *o
683 // << "------------ Node to replace with:\n" << *n
684 // << "------------ This node:\n" << *this
685 // << "+++++++++++++++++++++++++++++++++++++++\n";
686  throw csspp_exception_logic("replace_child() called with a node which is not a child of this node.");
687  }
688 
689  size_t const pos(it - f_children.begin());
690  f_children.insert(it, n);
691  f_children.erase(f_children.begin() + pos + 1);
692 }
693 
695 {
696  f_variables.clear();
697 }
698 
699 void node::set_variable(std::string const & name, pointer_t value)
700 {
701  f_variables[name] = value;
702 }
703 
705 {
706  if(source)
707  {
708  for(auto v : source->f_variables)
709  {
710  f_variables[v.first] = v.second->clone();
711  }
712  }
713 }
714 
715 node::pointer_t node::get_variable(std::string const & name)
716 {
717  auto const it(f_variables.find(name));
718  if(it == f_variables.end())
719  {
720  return pointer_t();
721  }
722  return it->second;
723 }
724 
726 {
727  f_flags.clear();
728 }
729 
730 void node::set_flag(std::string const & name, bool value)
731 {
732  if(value)
733  {
734  f_flags[name] = value;
735  }
736  else
737  {
738  auto it(f_flags.find(name));
739  if(it != f_flags.end())
740  {
741  f_flags.erase(it);
742  }
743  }
744 }
745 
746 bool node::get_flag(std::string const & name)
747 {
748  auto it(f_flags.find(name));
749  return it != f_flags.end();
750 }
751 
752 std::string node::to_string(int flags) const
753 {
754  std::stringstream out;
755 
756  switch(f_type)
757  {
758  case node_type_t::ADD:
759  out << "+";
760  break;
761 
762  case node_type_t::AND:
763  out << "&&";
764  break;
765 
767  out << ":=";
768  break;
769 
771  out << "@" << f_string;
772  break;
773 
775  out << (f_boolean ? "true" : "false");
776  break;
777 
778  case node_type_t::COLON:
779  out << ":";
780  break;
781 
782  case node_type_t::COLOR:
783  {
784  color c(get_color());
785  out << c.to_string();
786  }
787  break;
788 
789  case node_type_t::COLUMN:
790  out << "||";
791  break;
792 
793  case node_type_t::COMMA:
794  out << ",";
795  break;
796 
798  if(f_integer == 0)
799  {
800  // note: a completely empty comment is possible here and
801  // nothing will be output; however, in a valid CSS Preprocessor
802  // output, only comments with the @preserve keyword are kept
803  // so it won't be empty (until we decide to remove the @preserve
804  // from the comments...)
805  //
806  std::string::size_type start(0);
807  std::string::size_type end(f_string.find('\n'));
808  while(end != std::string::npos)
809  {
810  out << "// " << f_string.substr(start, end - start) << std::endl;
811  start = end + 1;
812  end = f_string.find('\n', start);
813  }
814  if(start < f_string.size())
815  {
816  out << "// " << f_string.substr(start) << std::endl;
817  }
818  }
819  else
820  {
821  out << "/* " << f_string << " */";
822  }
823  break;
824 
826  out << '?';
827  break;
828 
830  out << "|=";
831  break;
832 
834  // this may be a dimension, if not f_string is empty anyway
835  out << (f_boolean && f_integer >= 0 ? "+" : "") << f_decimal_number << f_string;
836  break;
837 
838  case node_type_t::DIVIDE:
839  if((flags & g_to_string_flag_add_spaces) != 0)
840  {
841  out << " / ";
842  }
843  else
844  {
845  out << "/";
846  }
847  break;
848 
849  case node_type_t::DOLLAR:
850  out << '$';
851  break;
852 
853  case node_type_t::EQUAL:
854  out << '=';
855  break;
856 
858  out << '!';
859  break;
860 
862  // this is a mouthful!
863  out << decimal_number_to_string(get_font_size() * (get_dim1() == "%" ? 100.0 : 1.0), false) << get_dim1()
864  << "/" << decimal_number_to_string(get_line_height() * (get_dim2() == "%" ? 100.0 : 1.0), false) << get_dim2();
865  break;
866 
868  out << '$';
869  /*FALLTHROUGH*/
871  {
872  out << f_string << "(";
873  bool first(true);
874  for(auto c : f_children)
875  {
876  if(first)
877  {
878  first = false;
879  }
880  else
881  {
882  out << ",";
883  }
884  out << c->to_string(flags);
885  }
886  out << ")";
887  }
888  break;
889 
891  out << ">=";
892  break;
893 
895  out << ">";
896  break;
897 
898  case node_type_t::HASH:
899  out << "#" << f_string;
900  break;
901 
903  out << f_string;
904  break;
905 
907  out << "~=";
908  break;
909 
911  // this may be a dimension, if not f_string is empty anyway
912  out << (f_boolean && f_integer >= 0 ? "+" : "") << f_integer << f_string;
913  break;
914 
916  out << "<=";
917  break;
918 
920  out << "<";
921  break;
922 
923  case node_type_t::MODULO:
924  if((flags & g_to_string_flag_add_spaces) != 0)
925  {
926  out << " % ";
927  }
928  else
929  {
930  out << "%";
931  }
932  break;
933 
935  out << "*";
936  break;
937 
939  out << "!=";
940  break;
941 
943  // should null be "null" or ""?
944  out << "";
945  break;
946 
948  out << "{";
949  for(auto c : f_children)
950  {
951  out << c->to_string(flags);
952  }
953  out << "}";
954  break;
955 
957  out << "(";
958  for(auto c : f_children)
959  {
960  out << c->to_string(flags);
961  }
962  out << ")";
963  break;
964 
966  out << "[";
967  for(auto c : f_children)
968  {
969  out << c->to_string(flags);
970  }
971  out << "]";
972  break;
973 
975  out << (f_boolean && f_integer >= 0 ? "+" : "") << decimal_number_to_string(f_decimal_number * 100.0, false) << "%";
976  break;
977 
978  case node_type_t::PERIOD:
979  out << ".";
980  break;
981 
983  out << "%" << f_string;
984  break;
985 
986  case node_type_t::POWER:
987  out << "**";
988  break;
989 
991  out << "~";
992  break;
993 
995  out << "^=";
996  break;
997 
999  out << "&";
1000  break;
1001 
1002  case node_type_t::SCOPE:
1003  out << "|";
1004  break;
1005 
1007  out << ";";
1008  break;
1009 
1010  case node_type_t::STRING:
1011  if((flags & g_to_string_flag_show_quotes) != 0)
1012  {
1013  int sq(0);
1014  int dq(0);
1015  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1016  {
1017  if(*s == '\'')
1018  {
1019  ++sq;
1020  }
1021  else if(*s == '"')
1022  {
1023  ++dq;
1024  }
1025  }
1026  if(sq >= dq)
1027  {
1028  // use " in this case
1029  out << '"';
1030  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1031  {
1032  if(*s == '"')
1033  {
1034  out << "\\\"";
1035  }
1036  else
1037  {
1038  out << *s;
1039  }
1040  }
1041  out << '"';
1042  }
1043  else
1044  {
1045  // use ' in this case
1046  out << '\'';
1047  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1048  {
1049  if(*s == '\'')
1050  {
1051  out << "\\'";
1052  }
1053  else
1054  {
1055  out << *s;
1056  }
1057  }
1058  out << '\'';
1059  }
1060  }
1061  else
1062  {
1063  // for errors and other messages we do not want the quotes
1064  for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1065  {
1066  out << *s;
1067  }
1068  }
1069  break;
1070 
1072  out << "*=";
1073  break;
1074 
1075  case node_type_t::SUBTRACT:
1076  out << "-";
1077  break;
1078 
1080  out << "$=";
1081  break;
1082 
1084  {
1085  unicode_range_t const range(static_cast<range_value_t>(f_integer));
1086  out << "U+" << range.to_string();
1087  }
1088  break;
1089 
1090  case node_type_t::URL:
1091  // TODO: escape special characters or we won't be able to re-read this one
1092  out << "url(" << f_string << ")";
1093  break;
1094 
1095  case node_type_t::VARIABLE:
1096  out << '$' << f_string;
1097  break;
1098 
1100  // this could have been \t or \n...
1101  out << " ";
1102  break;
1103 
1105  {
1106  bool first(true);
1107  for(auto c : f_children)
1108  {
1109  if(c->is(node_type_t::ARG))
1110  {
1111  if(first)
1112  {
1113  first = false;
1114  }
1115  else
1116  {
1117  switch(static_cast<node_type_t>(c->get_integer()))
1118  {
1119  case node_type_t::UNKNOWN: // this is the default if the integer is never set
1120  case node_type_t::COMMA:
1121  out << ",";
1122  break;
1123 
1124  case node_type_t::DIVIDE:
1125  out << "/";
1126  break;
1127 
1128  default:
1129  throw csspp_exception_logic("ARG only supports ',' and '/' as separators.");
1130 
1131  }
1132  }
1133  out << c->to_string(flags);
1134  }
1135  else
1136  {
1137  // this should not happen unless we did not argify yet
1138  // and in that case commas are inline
1139  out << c->to_string(flags);
1140  }
1141  }
1142  }
1143  break;
1144 
1146  {
1147  nth_child const an_b(f_integer);
1148  out << an_b.to_string();
1149  }
1150  break;
1151 
1152  case node_type_t::ARG:
1153  for(auto c : f_children)
1154  {
1155  out << c->to_string(flags);
1156  }
1157  break;
1158 
1160  for(size_t idx(0); idx < f_children.size(); ++idx)
1161  {
1162  if(f_children[idx]->f_type == node_type_t::ARG)
1163  {
1164  out << f_children[idx]->to_string(flags);
1165  if(idx + 1 != f_children.size())
1166  {
1167  // multiple lists of arguments are comma separated
1168  out << ",";
1169  }
1170  }
1171  else
1172  {
1173  out << f_children[idx]->to_string(flags);
1174  }
1175  }
1176  break;
1177 
1178  case node_type_t::LIST:
1179  for(size_t idx(0); idx < f_children.size(); ++idx)
1180  {
1181  if(f_children[idx]->f_type == node_type_t::DECLARATION)
1182  {
1183  out << f_children[idx]->to_string(flags);
1184  if(idx + 1 != f_children.size())
1185  {
1186  // multiple declarations are semi-colon separated
1187  out << ";";
1188  }
1189  }
1190  else
1191  {
1192  out << f_children[idx]->to_string(flags);
1193  }
1194  }
1195  break;
1196 
1197  case node_type_t::ARRAY:
1198  {
1199  out << "(";
1200  bool first(true);
1201  for(auto c : f_children)
1202  {
1203  if(first)
1204  {
1205  first = false;
1206  }
1207  else
1208  {
1209  out << ", ";
1210  }
1211  out << c->to_string(flags | g_to_string_flag_show_quotes);
1212  }
1213  out << ")";
1214  }
1215  break;
1216 
1217  case node_type_t::MAP:
1218  {
1219  out << "(";
1220  bool first(true);
1221  bool label(true);
1222  for(auto c : f_children)
1223  {
1224  if(label)
1225  {
1226  if(first)
1227  {
1228  first = false;
1229  }
1230  else
1231  {
1232  out << ", ";
1233  }
1234  }
1235  out << c->to_string(flags | g_to_string_flag_show_quotes);
1236  if(label)
1237  {
1238  out << ": ";
1239  }
1240  label = !label;
1241  }
1242  out << ")";
1243  }
1244  break;
1245 
1246  case node_type_t::UNKNOWN:
1247  case node_type_t::CDC:
1248  case node_type_t::CDO:
1253  case node_type_t::max_type:
1254  // many of the nodes are not expected in a valid tree being compiled
1255  // all of those will generate this exception
1256  throw csspp_exception_logic("unexpected token in to_string() call.");
1257 
1258  }
1259 
1260  return out.str();
1261 }
1262 
1263 void node::display(std::ostream & out, uint32_t indent) const
1264 {
1265  std::string indent_str;
1266  for(uint32_t i(0); i < indent; ++i)
1267  {
1268  indent_str += " ";
1269  }
1270  out << indent_str << f_type;
1271 
1272  switch(f_type)
1273  {
1275  case node_type_t::COMMENT:
1279  case node_type_t::FUNCTION:
1280  case node_type_t::HASH:
1282  case node_type_t::INTEGER:
1284  case node_type_t::STRING:
1285  case node_type_t::URL:
1286  case node_type_t::VARIABLE:
1288  out << " \"" << f_string << "\"";
1289  break;
1290 
1291  default:
1292  break;
1293 
1294  }
1295 
1296  switch(f_type)
1297  {
1298  case node_type_t::BOOLEAN:
1300  out << " B:" << (f_boolean ? "true" : "false");
1301  break;
1302 
1303  default:
1304  break;
1305 
1306  }
1307 
1308  switch(f_type)
1309  {
1311  case node_type_t::COMMENT:
1312  case node_type_t::INTEGER:
1314  out << " I:" << f_integer;
1315  break;
1316 
1317  default:
1318  break;
1319 
1320  }
1321 
1322  switch(f_type)
1323  {
1324  case node_type_t::COLOR:
1325  {
1326  color c(get_color());
1327  out << " H:" << std::hex << c.get_color() << std::dec;
1328  }
1329  break;
1330 
1331  default:
1332  break;
1333 
1334  }
1335 
1336  switch(f_type)
1337  {
1339  out << " FM:" << decimal_number_to_string(get_font_size() * (get_dim1() == "%" ? 100.0 : 1.0), false) << get_dim1()
1340  << "/" << decimal_number_to_string(get_line_height() * (get_dim2() == "%" ? 100.0 : 1.0), false) << get_dim2();
1341  break;
1342 
1343  default:
1344  break;
1345 
1346  }
1347 
1348  switch(f_type)
1349  {
1351  {
1352  nth_child const an_b(f_integer);
1353  out << " S:" << an_b.to_string();
1354  }
1355  break;
1356 
1357  default:
1358  break;
1359 
1360  }
1361 
1362  switch(f_type)
1363  {
1365  case node_type_t::PERCENT:
1366  out << " D:" << decimal_number_to_string(f_decimal_number, false);
1367  break;
1368 
1369  default:
1370  break;
1371 
1372  }
1373 
1374  for(auto f : f_flags)
1375  {
1376  out << " F:" << f.first;
1377  }
1378 
1379  out << "\n";
1380 
1381  for(auto v : f_variables)
1382  {
1383  out << indent_str << " V:" << v.first << "\n";
1384  v.second->display(out, indent + 6);
1385  }
1386 
1387 
1388  switch(f_type)
1389  {
1390  case node_type_t::ARG:
1391  case node_type_t::ARRAY:
1396  case node_type_t::FUNCTION:
1397  case node_type_t::LIST:
1398  case node_type_t::MAP:
1403  // display the children now
1404  for(size_t i(0); i < f_children.size(); ++i)
1405  {
1406  f_children[i]->display(out, indent + 2);
1407  }
1408  break;
1409 
1410  default:
1411  break;
1412 
1413  }
1414 }
1415 
1416 void node::limit_nodes_to(uint32_t count)
1417 {
1418  g_node_max_count = count;
1419 }
1420 
1421 } // namespace csspp
1422 
1423 std::ostream & operator << (std::ostream & out, csspp::node_type_t const type)
1424 {
1425  switch(type)
1426  {
1428  out << "UNKNOWN";
1429  break;
1430 
1432  out << "ADD";
1433  break;
1434 
1436  out << "AND";
1437  break;
1438 
1440  out << "ASSIGNMENT";
1441  break;
1442 
1444  out << "AT_KEYWORD";
1445  break;
1446 
1448  out << "BOOLEAN";
1449  break;
1450 
1452  out << "CDC";
1453  break;
1454 
1456  out << "CDO";
1457  break;
1458 
1460  out << "CLOSE_CURLYBRACKET";
1461  break;
1462 
1464  out << "CLOSE_PARENTHESIS";
1465  break;
1466 
1468  out << "CLOSE_SQUAREBRACKET";
1469  break;
1470 
1472  out << "COLON";
1473  break;
1474 
1476  out << "COLOR";
1477  break;
1478 
1480  out << "COLUMN";
1481  break;
1482 
1484  out << "COMMA";
1485  break;
1486 
1488  out << "COMMENT";
1489  break;
1490 
1492  out << "CONDITIONAL";
1493  break;
1494 
1496  out << "DASH_MATCH";
1497  break;
1498 
1500  out << "DECIMAL_NUMBER";
1501  break;
1502 
1504  out << "DIVIDE";
1505  break;
1506 
1508  out << "DOLLAR";
1509  break;
1510 
1512  out << "EOF_TOKEN";
1513  break;
1514 
1516  out << "EQUAL";
1517  break;
1518 
1520  out << "EXCLAMATION";
1521  break;
1522 
1524  out << "FONT_METRICS";
1525  break;
1526 
1528  out << "FUNCTION";
1529  break;
1530 
1532  out << "GREATER_EQUAL";
1533  break;
1534 
1536  out << "GREATER_THAN";
1537  break;
1538 
1540  out << "HASH";
1541  break;
1542 
1544  out << "IDENTIFIER";
1545  break;
1546 
1548  out << "INCLUDE_MATCH";
1549  break;
1550 
1552  out << "INTEGER";
1553  break;
1554 
1556  out << "LESS_EQUAL";
1557  break;
1558 
1560  out << "LESS_THAN";
1561  break;
1562 
1564  out << "MODULO";
1565  break;
1566 
1568  out << "MULTIPLY";
1569  break;
1570 
1572  out << "NOT_EQUAL";
1573  break;
1574 
1576  out << "NULL_TOKEN";
1577  break;
1578 
1580  out << "OPEN_CURLYBRACKET";
1581  break;
1582 
1584  out << "OPEN_PARENTHESIS";
1585  break;
1586 
1588  out << "OPEN_SQUAREBRACKET";
1589  break;
1590 
1592  out << "PERCENT";
1593  break;
1594 
1596  out << "PERIOD";
1597  break;
1598 
1600  out << "PLACEHOLDER";
1601  break;
1602 
1604  out << "POWER";
1605  break;
1606 
1608  out << "PRECEDED";
1609  break;
1610 
1612  out << "PREFIX_MATCH";
1613  break;
1614 
1616  out << "REFERENCE";
1617  break;
1618 
1620  out << "SCOPE";
1621  break;
1622 
1624  out << "SEMICOLON";
1625  break;
1626 
1628  out << "STRING";
1629  break;
1630 
1632  out << "SUBSTRING_MATCH";
1633  break;
1634 
1636  out << "SUBTRACT";
1637  break;
1638 
1640  out << "SUFFIX_MATCH";
1641  break;
1642 
1644  out << "UNICODE_RANGE";
1645  break;
1646 
1648  out << "URL";
1649  break;
1650 
1652  out << "VARIABLE";
1653  break;
1654 
1656  out << "VARIABLE_FUNCTION";
1657  break;
1658 
1660  out << "WHITESPACE";
1661  break;
1662 
1663  // Grammar related nodes (i.e. composed nodes)
1665  out << "AN_PLUS_B";
1666  break;
1667 
1669  out << "ARG";
1670  break;
1671 
1673  out << "ARRAY";
1674  break;
1675 
1677  out << "COMPONENT_VALUE";
1678  break;
1679 
1681  out << "DECLARATION";
1682  break;
1683 
1685  out << "LIST";
1686  break;
1687 
1689  out << "MAP";
1690  break;
1691 
1693  out << "max_type";
1694  break;
1695 
1696  }
1697 
1698  return out;
1699 }
1700 
1701 std::ostream & operator << (std::ostream & out, csspp::node const & n)
1702 {
1703  n.display(out, 0);
1704  return out;
1705 }
1706 
1708 {
1709  std::stringstream ss;
1710  ss << type;
1711  out << ss.str();
1712  return out;
1713 }
1714 
1715 // Local Variables:
1716 // mode: cpp
1717 // indent-tabs-mode: nil
1718 // c-basic-offset: 4
1719 // tab-width: 4
1720 // End:
1721 
1722 // vim: ts=4 sw=4 et
pointer_t clone() const
Definition: node.cpp:237
static size_t const npos
Definition: node.h:123
void add_child(pointer_t child)
Definition: node.cpp:580
void clear_flags()
Definition: node.cpp:725
bool empty() const
Definition: node.cpp:546
list_t f_children
Definition: node.h:198
position const & get_position() const
Definition: node.cpp:325
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:599
std::string to_string() const
Definition: color.cpp:484
std::shared_ptr< node > pointer_t
Definition: node.h:122
std::string to_string(int flags) const
Definition: node.cpp:752
int64_t integer_t
Definition: csspp.h:52
bool f_boolean
Definition: node.h:193
variable_table_t f_variables
Definition: node.h:199
void type_supports_children(node_type_t const type)
Definition: node.cpp:184
pointer_t get_variable(std::string const &name)
Definition: node.cpp:715
decimal_number_t get_line_height() const
Definition: node.cpp:443
std::string const & get_string() const
Definition: node.cpp:330
node_type_t
Definition: node.h:36
void set_flag(std::string const &name, bool value)
Definition: node.cpp:730
pointer_t get_last_child() const
Definition: node.cpp:659
void take_over_children_of(pointer_t n)
Definition: node.cpp:665
decimal_number_t get_font_size() const
Definition: node.cpp:429
void set_lowercase_string(std::string const &str)
Definition: node.cpp:348
void set_dim1(std::string const &font_size)
Definition: node.cpp:476
void type_supports_integer(node_type_t const type)
Definition: node.cpp:60
void remove_child(pointer_t child)
Definition: node.cpp:622
color get_color() const
Definition: node.cpp:390
void set_color(rgba_color_t const rgba)
Definition: color.cpp:217
void set_line_height(decimal_number_t line_height)
Definition: node.cpp:452
bool get_flag(std::string const &name)
Definition: node.cpp:746
void type_supports_color(node_type_t const type)
Definition: node.cpp:151
static int const g_to_string_flag_show_quotes
Definition: node.h:125
decimal_number_t f_decimal_number
Definition: node.h:195
bool is(node_type_t const type) const
Definition: node.cpp:264
void set_decimal_number(decimal_number_t decimal_number)
Definition: node.cpp:384
position f_position
Definition: node.h:192
void display(std::ostream &out, uint32_t indent) const
Definition: node.cpp:1263
std::string to_string() const
void set_variable(std::string const &name, pointer_t value)
Definition: node.cpp:699
void clear()
Definition: node.cpp:553
void set_string(std::string const &str)
Definition: node.cpp:336
boolean_t
Definition: node.h:29
size_t size() const
Definition: node.cpp:560
node(node_type_t const type, position const &pos)
Definition: node.cpp:214
void set_font_size(decimal_number_t font_size)
Definition: node.cpp:436
void set_dim2(std::string const &line_height)
Definition: node.cpp:513
static int const g_to_string_flag_add_spaces
Definition: node.h:126
std::string get_dim1() const
Definition: node.cpp:461
pointer_t get_child(size_t idx) const
Definition: node.cpp:647
std::string get_dim2() const
Definition: node.cpp:498
void type_supports_string(node_type_t const type)
Definition: node.cpp:121
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:677
decimal_number_t get_decimal_number() const
Definition: node.cpp:378
double decimal_number_t
Definition: csspp.h:53
void set_integer(integer_t integer)
Definition: node.cpp:360
static void limit_nodes_to(uint32_t count)
Definition: node.cpp:1416
std::string f_string
Definition: node.h:196
rgba_color_t get_color() const
Definition: color.cpp:456
std::string f_lowercase_string
Definition: node.h:197
node_type_t get_type() const
Definition: node.cpp:259
void set_color(color c)
Definition: node.cpp:411
void set_boolean(bool integer)
Definition: node.cpp:372
boolean_t to_boolean() const
Definition: node.cpp:269
integer_t f_integer
Definition: node.h:194
std::string to_string() const
Definition: nth_child.cpp:356
bool get_boolean() const
Definition: node.cpp:366
std::string const & get_lowercase_string() const
Definition: node.cpp:342
std::ostream & operator<<(std::ostream &out, csspp::node_type_t const type)
Definition: node.cpp:1423
void type_supports_font_metrics(node_type_t const type)
Definition: node.cpp:168
node_type_t f_type
Definition: node.h:191
void copy_variable(node::pointer_t source)
Definition: node.cpp:704
integer_t get_integer() const
Definition: node.cpp:354
void type_supports_decimal_number(node_type_t const type)
Definition: node.cpp:103
flag_table_t f_flags
Definition: node.h:200
void clear_variables()
Definition: node.cpp:694
size_t child_position(pointer_t child)
Definition: node.cpp:567

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.