Current Version: 1.0.33
Project Name: csspp
node.cpp
Go to the documentation of this file.
1// Copyright (c) 2015-2025 Made to Order Software Corp. All Rights Reserved
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation; either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License along
14// with this program; if not, write to the Free Software Foundation, Inc.,
15// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16
31// self
32//
33#include <csspp/node.h>
34
35#include <csspp/exception.h>
36#include <csspp/nth_child.h>
37#include <csspp/unicode_range.h>
38
39
40// C++
41//
42#include <algorithm>
43#include <iostream>
44
45
46// last include
47//
48#include <snapdev/poison.h>
49
50
51
52namespace csspp
53{
54
55// make sure we have a copy (catch makes it a requirement probably because
56// of template use)
57size_t const node::npos;
58
59namespace
60{
61
62uint32_t g_node_count = 0;
63uint32_t g_node_max_count = 0;
64
70
72{
73 switch(type)
74 {
81 break;
82
83 default:
84 {
85 std::stringstream ss;
86 ss << "trying to access (read/write) the integer of a node of type " << type << ", which does not support integers.";
87 throw csspp_exception_logic(ss.str());
88 }
89
90 }
91}
92
94{
95 switch(type)
96 {
102 break;
103
104 default:
105 {
106 std::stringstream ss;
107 ss << "trying to access (read/write) the boolean of a node of type " << type << ", which does not support booleans.";
108 throw csspp_exception_logic(ss.str());
109 }
110
111 }
112}
113
115{
116 switch(type)
117 {
121 break;
122
123 default:
124 {
125 std::stringstream ss;
126 ss << "trying to access (read/write) the decimal number of a node of type " << type << ", which does not support decimal numbers.";
127 throw csspp_exception_logic(ss.str());
128 }
129
130 }
131}
132
134{
135 switch(type)
136 {
148 case node_type_t::URL:
151 break;
152
153 default:
154 {
155 std::stringstream ss;
156 ss << "trying to access (read/write) the string of a node of type " << type << ", which does not support strings.";
157 throw csspp_exception_logic(ss.str());
158 }
159
160 }
161}
162
164{
165 switch(type)
166 {
168 break;
169
170 default:
171 {
172 std::stringstream ss;
173 ss << "trying to access (read/write) the color of a node of type " << type << ", which does not support colors.";
174 throw csspp_exception_logic(ss.str());
175 }
176
177 }
178}
179
181{
182 switch(type)
183 {
185 break;
186
187 default:
188 {
189 std::stringstream ss;
190 ss << "trying to access (read/write) the line height of a node of type " << type << ", which does not support line heights.";
191 throw csspp_exception_logic(ss.str());
192 }
193 }
194}
195
197{
198 switch(type)
199 {
200 case node_type_t::ARG:
207 case node_type_t::MAP:
213 break;
214
215 default:
216 {
217 std::stringstream ss;
218 ss << "trying to access (read/write) the children of a node of type " << type << ", which does not support children.";
219 throw csspp_exception_logic(ss.str());
220 }
221
222 }
223}
224
225} // no name namespace
226
227node::node(node_type_t const type, position const & pos)
228 : f_type(type)
229 , f_position(pos)
230{
231 ++g_node_count;
232 if(g_node_max_count != 0
233 && g_node_count >= g_node_max_count)
234 {
235 // This is NOT a bug per se, you may limit the number of nodes in case
236 // you have a limited amount of memory available or you suspect the
237 // CSS Preprocessor has a bug which allocates nodes forever; this is
238 // used for our tests with a maximum number of nodes equal to one
239 // million (which generally represents a lot less than 1Gb of RAM.)
240 std::cerr << "error: node of type " << type << " cannot be allocated.\n"; // LCOV_EXCL_LINE
241 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
242 }
243}
244
246{
247 --g_node_count;
248}
249
251{
252 // create the clone
253 pointer_t result(new node(f_type, f_position));
254
255 // copy the other simple values
256 result->f_boolean = f_boolean;
257 result->f_integer = f_integer;
258 result->f_decimal_number = f_decimal_number;
259 result->f_string = f_string;
260 result->f_flags = f_flags;
261
262 for(auto c : f_children)
263 {
264 result->f_children.push_back(c->clone());
265 }
266
267 result->copy_variable(const_cast<node *>(this)->shared_from_this());
268
269 return result;
270}
271
273{
274 return f_type;
275}
276
277bool node::is(node_type_t const type) const
278{
279 return f_type == type;
280}
281
283{
284 switch(f_type)
285 {
288
290 if(f_string == "true")
291 {
293 }
294 if(f_string == "false"
295 || f_string == "null")
296 {
298 }
300
303
306#pragma GCC diagnostic push
307#pragma GCC diagnostic ignored "-Wfloat-equal"
309#pragma GCC diagnostic pop
310
313
316 case node_type_t::MAP:
318
320 {
321 color c(get_color());
322 return (c.get_color() & 0x00FFFFFF) == 0
325 }
326 break;
327
330
331 default:
333
334 }
335 /*NOTREACHED*/
336}
337
339{
340 return f_position;
341}
342
343std::string const & node::get_string() const
344{
345 type_supports_string(f_type);
346 return f_string;
347}
348
349void node::set_string(std::string const & str)
350{
351 type_supports_string(f_type);
352 f_string = str;
353}
354
355std::string const & node::get_lowercase_string() const
356{
357 type_supports_string(f_type);
358 return f_lowercase_string;
359}
360
361void node::set_lowercase_string(std::string const & str)
362{
363 type_supports_string(f_type);
364 f_lowercase_string = str;
365}
366
368{
369 type_supports_integer(f_type);
370 return f_integer;
371}
372
374{
375 type_supports_integer(f_type);
376 f_integer = integer;
377}
378
380{
381 type_supports_boolean(f_type);
382 return f_boolean;
383}
384
385void node::set_boolean(bool boolean)
386{
387 type_supports_boolean(f_type);
388 f_boolean = boolean;
389}
390
392{
393 type_supports_decimal_number(f_type);
394 return f_decimal_number;
395}
396
398{
399 type_supports_decimal_number(f_type);
400 f_decimal_number = decimal_number;
401}
402
404{
405 type_supports_color(f_type);
406
407 union color_transfer_t
408 {
409 uint64_t f_int;
410 double f_dbl;
411 float f_flt[2];
412 };
413
414 color_transfer_t c1, c2;
415 c1.f_int = f_integer;
416 c2.f_dbl = f_decimal_number;
417
418 color c;
419 c.set_color(c1.f_flt[0], c1.f_flt[1], c2.f_flt[0], c2.f_flt[1]);
420
421 return c;
422}
423
425{
426 type_supports_color(f_type);
427
428 union color_transfer_t
429 {
430 uint64_t f_int;
431 double f_dbl;
432 float f_flt[2];
433 };
434
435 color_transfer_t c1, c2;
436 c.get_color(c1.f_flt[0], c1.f_flt[1], c2.f_flt[0], c2.f_flt[1]);
437
438 f_integer = c1.f_int;
439 f_decimal_number = c2.f_dbl;
440}
441
443{
444 type_supports_font_metrics(f_type);
445
446 return f_decimal_number;
447}
448
450{
451 type_supports_font_metrics(f_type);
452
453 f_decimal_number = font_size;
454}
455
457{
458 type_supports_font_metrics(f_type);
459
460 convert_t c;
461 c.f_int = f_integer;
462 return c.f_flt;
463}
464
466{
467 type_supports_font_metrics(f_type);
468
469 convert_t c;
470 c.f_flt = line_height;
471 f_integer = c.f_int;
472}
473
474std::string node::get_dim1() const
475{
476 type_supports_font_metrics(f_type);
477
478 std::string::size_type pos(f_string.find('/'));
479 if(pos == std::string::npos)
480 {
481 return f_string;
482 }
483 else
484 {
485 return f_string.substr(0, pos);
486 }
487}
488
489void node::set_dim1(std::string const & dimension)
490{
491 type_supports_font_metrics(f_type);
492
493 if(f_string.empty())
494 {
495 f_string = dimension;
496 }
497 else
498 {
499 std::string::size_type pos(f_string.find('/'));
500 if(pos == std::string::npos)
501 {
502 f_string = dimension;
503 }
504 else
505 {
506 f_string = dimension + f_string.substr(pos);
507 }
508 }
509}
510
511std::string node::get_dim2() const
512{
513 type_supports_font_metrics(f_type);
514
515 std::string::size_type pos(f_string.find('/'));
516 if(pos == std::string::npos)
517 {
518 return "";
519 }
520 else
521 {
522 return f_string.substr(pos + 1);
523 }
524}
525
526void node::set_dim2(std::string const & dimension)
527{
528 type_supports_font_metrics(f_type);
529
530 if(dimension.empty())
531 {
532 std::string::size_type pos(f_string.find('/'));
533 if(pos != std::string::npos)
534 {
535 // remove the '/...'
536 f_string = f_string.substr(0, pos);
537 }
538 return;
539 }
540
541 if(f_string.empty())
542 {
543 f_string = "/" + dimension;
544 }
545 else
546 {
547 std::string::size_type pos(f_string.find('/'));
548 if(pos == std::string::npos)
549 {
550 f_string += "/" + dimension;
551 }
552 else
553 {
554 f_string = f_string.substr(0, pos + 1) + dimension;
555 }
556 }
557}
558
559bool node::empty() const
560{
561 type_supports_children(f_type);
562
563 return f_children.empty();
564}
565
567{
568 type_supports_children(f_type);
569
570 f_children.clear();
571}
572
573size_t node::size() const
574{
575 type_supports_children(f_type);
576
577 return f_children.size();
578}
579
581{
582 type_supports_children(f_type);
583
584 auto it(std::find(f_children.begin(), f_children.end(), child));
585 if(it == f_children.end())
586 {
587 return npos;
588 }
589
590 return it - f_children.begin();
591}
592
594{
595 type_supports_children(f_type);
596
597 // make sure we totally ignore EOF in a child list
598 // (this dramatically ease the coding of the parser)
599 //
600 // also we do not need to save two WHITESPACE tokens
601 // one after another
602 //
603 if(!child->is(node_type_t::EOF_TOKEN)
604 && (!child->is(node_type_t::WHITESPACE)
605 || f_children.empty()
606 || !f_children.back()->is(node_type_t::WHITESPACE)))
607 {
608 f_children.push_back(child);
609 }
610}
611
612void node::insert_child(size_t idx, pointer_t child)
613{
614 // attempting to insert at the end?
615 if(idx == f_children.size())
616 {
617 add_child(child);
618 return;
619 }
620
621 type_supports_children(f_type);
622
623 if(idx >= f_children.size())
624 {
625 throw csspp_exception_overflow("insert_child() called with an index out of range.");
626 }
627
628 // avoid the EOF_TOKEN, although really it should not happen here
629 if(!child->is(node_type_t::EOF_TOKEN))
630 {
631 f_children.insert(f_children.begin() + idx, child);
632 }
633}
634
636{
637 type_supports_children(f_type);
638
639 auto it(std::find(f_children.begin(), f_children.end(), child));
640 if(it == f_children.end())
641 {
642 throw csspp_exception_logic("remove_child() called with a node which is not a child of this node.");
643 }
644
645 f_children.erase(it);
646}
647
648void node::remove_child(size_t idx)
649{
650 type_supports_children(f_type);
651
652 if(idx >= f_children.size())
653 {
654 throw csspp_exception_overflow("remove_child() called with an index out of range.");
655 }
656
657 f_children.erase(f_children.begin() + idx);
658}
659
661{
662 type_supports_children(f_type);
663
664 if(idx >= f_children.size())
665 {
666 throw csspp_exception_overflow("get_child() called with an index out of range.");
667 }
668
669 return f_children[idx];
670}
671
673{
674 // if empty, get_child() will throw
675 return get_child(f_children.size() - 1);
676}
677
679{
680 type_supports_children(f_type);
681 type_supports_children(n->f_type);
682
683 // children are copied to this node and cleared
684 // in the other node (TBD: should this node have
685 // an empty list of children to start with?)
686 f_children.clear();
687 swap(f_children, n->f_children);
688}
689
691{
692 auto it(std::find(f_children.begin(), f_children.end(), o));
693 if(it == f_children.end())
694 {
695//std::cerr << "------------ Node being replaced:\n" << *o
696// << "------------ Node to replace with:\n" << *n
697// << "------------ This node:\n" << *this
698// << "+++++++++++++++++++++++++++++++++++++++\n";
699 throw csspp_exception_logic("replace_child() called with a node which is not a child of this node.");
700 }
701
702 size_t const pos(it - f_children.begin());
703 f_children.insert(it, n);
704 f_children.erase(f_children.begin() + pos + 1);
705}
706
708{
709 f_variables.clear();
710}
711
712void node::set_variable(std::string const & name, pointer_t value)
713{
714 f_variables[name] = value;
715}
716
718{
719 if(source)
720 {
721 for(auto v : source->f_variables)
722 {
723 f_variables[v.first] = v.second->clone();
724 }
725 }
726}
727
728node::pointer_t node::get_variable(std::string const & name)
729{
730 auto const it(f_variables.find(name));
731 if(it == f_variables.end())
732 {
733 return pointer_t();
734 }
735 return it->second;
736}
737
739{
740 f_flags.clear();
741}
742
743void node::set_flag(std::string const & name, bool value)
744{
745 if(value)
746 {
747 f_flags[name] = value;
748 }
749 else
750 {
751 auto it(f_flags.find(name));
752 if(it != f_flags.end())
753 {
754 f_flags.erase(it);
755 }
756 }
757}
758
759bool node::get_flag(std::string const & name)
760{
761 auto it(f_flags.find(name));
762 return it != f_flags.end();
763}
764
765std::string node::to_string(int flags) const
766{
767 std::stringstream out;
768
769 switch(f_type)
770 {
771 case node_type_t::ADD:
772 out << "+";
773 break;
774
775 case node_type_t::AND:
776 out << "&&";
777 break;
778
780 out << ":=";
781 break;
782
784 out << "@" << f_string;
785 break;
786
788 out << (f_boolean ? "true" : "false");
789 break;
790
792 out << ":";
793 break;
794
796 {
797 color c(get_color());
798 out << c.to_string();
799 }
800 break;
801
803 out << "||";
804 break;
805
807 out << ",";
808 break;
809
811 if(f_integer == 0)
812 {
813 // note: a completely empty comment is possible here and
814 // nothing will be output; however, in a valid CSS Preprocessor
815 // output, only comments with the @preserve keyword are kept
816 // so it won't be empty (until we decide to remove the @preserve
817 // from the comments...)
818 //
819 std::string::size_type start(0);
820 std::string::size_type end(f_string.find('\n'));
821 while(end != std::string::npos)
822 {
823 out << "// " << f_string.substr(start, end - start) << std::endl;
824 start = end + 1;
825 end = f_string.find('\n', start);
826 }
827 if(start < f_string.size())
828 {
829 out << "// " << f_string.substr(start) << std::endl;
830 }
831 }
832 else
833 {
834 out << "/* " << f_string << " */";
835 }
836 break;
837
839 out << '?';
840 break;
841
843 out << "|=";
844 break;
845
847 // this may be a dimension, if not f_string is empty anyway
848 out << (f_boolean && f_integer >= 0 ? "+" : "") << f_decimal_number << f_string;
849 break;
850
852 if((flags & g_to_string_flag_add_spaces) != 0)
853 {
854 out << " / ";
855 }
856 else
857 {
858 out << "/";
859 }
860 break;
861
863 out << '$';
864 break;
865
867 out << '=';
868 break;
869
871 out << '!';
872 break;
873
875 // this is a mouthful!
876 out << decimal_number_to_string(get_font_size() * (get_dim1() == "%" ? 100.0 : 1.0), false) << get_dim1()
877 << "/" << decimal_number_to_string(get_line_height() * (get_dim2() == "%" ? 100.0 : 1.0), false) << get_dim2();
878 break;
879
881 out << '$';
882#if __cplusplus >= 201700
883 [[fallthrough]];
884#endif
886 {
887 out << f_string << "(";
888 bool first(true);
889 for(auto c : f_children)
890 {
891 if(first)
892 {
893 first = false;
894 }
895 else
896 {
897 out << ",";
898 }
899 out << c->to_string(flags);
900 }
901 out << ")";
902 }
903 break;
904
906 out << ">=";
907 break;
908
910 out << ">";
911 break;
912
914 out << "#" << f_string;
915 break;
916
918 out << f_string;
919 break;
920
922 out << "~=";
923 break;
924
926 // this may be a dimension, if not f_string is empty anyway
927 out << (f_boolean && f_integer >= 0 ? "+" : "") << f_integer << f_string;
928 break;
929
931 out << "<=";
932 break;
933
935 out << "<";
936 break;
937
939 if((flags & g_to_string_flag_add_spaces) != 0)
940 {
941 out << " % ";
942 }
943 else
944 {
945 out << "%";
946 }
947 break;
948
950 out << "*";
951 break;
952
954 out << "!=";
955 break;
956
958 // should null be "null" or ""?
959 out << "";
960 break;
961
963 out << "{";
964 for(auto c : f_children)
965 {
966 out << c->to_string(flags);
967 }
968 out << "}";
969 break;
970
972 out << "(";
973 for(auto c : f_children)
974 {
975 out << c->to_string(flags);
976 }
977 out << ")";
978 break;
979
981 out << "[";
982 for(auto c : f_children)
983 {
984 out << c->to_string(flags);
985 }
986 out << "]";
987 break;
988
990 out << (f_boolean && f_integer >= 0 ? "+" : "") << decimal_number_to_string(f_decimal_number * 100.0, false) << "%";
991 break;
992
994 out << ".";
995 break;
996
998 out << "%" << f_string;
999 break;
1000
1001 case node_type_t::POWER:
1002 out << "**";
1003 break;
1004
1006 out << "~";
1007 break;
1008
1010 out << "^=";
1011 break;
1012
1014 out << "&";
1015 break;
1016
1017 case node_type_t::SCOPE:
1018 out << "|";
1019 break;
1020
1022 out << ";";
1023 break;
1024
1026 if((flags & g_to_string_flag_show_quotes) != 0)
1027 {
1028 int sq(0);
1029 int dq(0);
1030 for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1031 {
1032 if(*s == '\'')
1033 {
1034 ++sq;
1035 }
1036 else if(*s == '"')
1037 {
1038 ++dq;
1039 }
1040 }
1041 if(sq >= dq)
1042 {
1043 // use " in this case
1044 out << '"';
1045 for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1046 {
1047 if(*s == '"')
1048 {
1049 out << "\\\"";
1050 }
1051 else
1052 {
1053 out << *s;
1054 }
1055 }
1056 out << '"';
1057 }
1058 else
1059 {
1060 // use ' in this case
1061 out << '\'';
1062 for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1063 {
1064 if(*s == '\'')
1065 {
1066 out << "\\'";
1067 }
1068 else
1069 {
1070 out << *s;
1071 }
1072 }
1073 out << '\'';
1074 }
1075 }
1076 else
1077 {
1078 // for errors and other messages we do not want the quotes
1079 for(char const *s(f_string.c_str()); *s != '\0'; ++s)
1080 {
1081 out << *s;
1082 }
1083 }
1084 break;
1085
1087 out << "*=";
1088 break;
1089
1091 out << "-";
1092 break;
1093
1095 out << "$=";
1096 break;
1097
1099 {
1100 unicode_range_t const range(static_cast<range_value_t>(f_integer));
1101 out << "U+" << range.to_string();
1102 }
1103 break;
1104
1105 case node_type_t::URL:
1106 // TODO: escape special characters or we won't be able to re-read this one
1107 out << "url(" << f_string << ")";
1108 break;
1109
1111 out << '$' << f_string;
1112 break;
1113
1115 // this could have been \t or \n...
1116 out << " ";
1117 break;
1118
1120 {
1121 bool first(true);
1122 for(auto c : f_children)
1123 {
1124 if(c->is(node_type_t::ARG))
1125 {
1126 if(first)
1127 {
1128 first = false;
1129 }
1130 else
1131 {
1132 switch(static_cast<node_type_t>(c->get_integer()))
1133 {
1134 case node_type_t::UNKNOWN: // this is the default if the integer is never set
1135 case node_type_t::COMMA:
1136 out << ",";
1137 break;
1138
1140 out << "/";
1141 break;
1142
1143 default:
1144 throw csspp_exception_logic("ARG only supports ',' and '/' as separators.");
1145
1146 }
1147 }
1148 out << c->to_string(flags);
1149 }
1150 else
1151 {
1152 // this should not happen unless we did not argify yet
1153 // and in that case commas are inline
1154 out << c->to_string(flags);
1155 }
1156 }
1157 }
1158 break;
1159
1161 {
1162 nth_child const an_b(f_integer);
1163 out << an_b.to_string();
1164 }
1165 break;
1166
1167 case node_type_t::ARG:
1168 for(auto c : f_children)
1169 {
1170 out << c->to_string(flags);
1171 }
1172 break;
1173
1175 if(!f_string.empty())
1176 {
1177 out << f_string << ": ";
1178 }
1179 for(size_t idx(0); idx < f_children.size(); ++idx)
1180 {
1182 {
1183 out << f_children[idx]->to_string(flags);
1184 if(idx + 1 != f_children.size())
1185 {
1186 // multiple lists of arguments are comma 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::LIST:
1198 for(size_t idx(0); idx < f_children.size(); ++idx)
1199 {
1201 {
1202 out << f_children[idx]->to_string(flags);
1203 if(idx + 1 != f_children.size())
1204 {
1205 // multiple declarations are semi-colon separated
1206 out << ";";
1207 }
1208 }
1209 else
1210 {
1211 out << f_children[idx]->to_string(flags);
1212 }
1213 }
1214 break;
1215
1216 case node_type_t::ARRAY:
1217 {
1218 out << "(";
1219 bool first(true);
1220 for(auto c : f_children)
1221 {
1222 if(first)
1223 {
1224 first = false;
1225 }
1226 else
1227 {
1228 out << ", ";
1229 }
1230 out << c->to_string(flags | g_to_string_flag_show_quotes);
1231 }
1232 out << ")";
1233 }
1234 break;
1235
1236 case node_type_t::MAP:
1237 {
1238 out << "(";
1239 bool first(true);
1240 bool label(true);
1241 for(auto c : f_children)
1242 {
1243 if(label)
1244 {
1245 if(first)
1246 {
1247 first = false;
1248 }
1249 else
1250 {
1251 out << ", ";
1252 }
1253 }
1254 out << c->to_string(flags | g_to_string_flag_show_quotes);
1255 if(label)
1256 {
1257 out << ": ";
1258 }
1259 label = !label;
1260 }
1261 out << ")";
1262 }
1263 break;
1264
1265 case node_type_t::FRAME:
1266 if(f_decimal_number <= 0.0)
1267 {
1268 out << "from";
1269 }
1270 else if(f_decimal_number >= 1.0)
1271 {
1272 out << "to";
1273 }
1274 else
1275 {
1276 out << decimal_number_to_string(f_decimal_number * 100.0, false) << "%";
1277 }
1278 out << "{";
1279 for(auto c : f_children)
1280 {
1281 out << c->to_string(flags);
1282 }
1283 out << "}";
1284 break;
1285
1287 case node_type_t::CDC:
1288 case node_type_t::CDO:
1294 // many of the nodes are not expected in a valid tree being compiled
1295 // all of those will generate this exception
1296 throw csspp_exception_logic("unexpected token in to_string() call.");
1297
1298 }
1299
1300 return out.str();
1301}
1302
1303void node::display(std::ostream & out, uint32_t indent) const
1304{
1305 std::string indent_str;
1306 for(uint32_t i(0); i < indent; ++i)
1307 {
1308 indent_str += " ";
1309 }
1310 out << indent_str << f_type;
1311
1312 switch(f_type)
1313 {
1320 case node_type_t::HASH:
1325 case node_type_t::URL:
1328 out << " \"" << f_string << "\"";
1329 break;
1330
1331 default:
1332 break;
1333
1334 }
1335
1336 switch(f_type)
1337 {
1340 out << " B:" << (f_boolean ? "true" : "false");
1341 break;
1342
1343 default:
1344 break;
1345
1346 }
1347
1348 switch(f_type)
1349 {
1354 out << " I:" << f_integer;
1355 break;
1356
1357 default:
1358 break;
1359
1360 }
1361
1362 switch(f_type)
1363 {
1364 case node_type_t::COLOR:
1365 {
1366 color c(get_color());
1367 out << " H:" << std::hex << c.get_color() << std::dec;
1368 }
1369 break;
1370
1371 default:
1372 break;
1373
1374 }
1375
1376 switch(f_type)
1377 {
1379 out << " FM:" << decimal_number_to_string(get_font_size() * (get_dim1() == "%" ? 100.0 : 1.0), false) << get_dim1()
1380 << "/" << decimal_number_to_string(get_line_height() * (get_dim2() == "%" ? 100.0 : 1.0), false) << get_dim2();
1381 break;
1382
1383 default:
1384 break;
1385
1386 }
1387
1388 switch(f_type)
1389 {
1391 {
1392 nth_child const an_b(f_integer);
1393 out << " S:" << an_b.to_string();
1394 }
1395 break;
1396
1397 default:
1398 break;
1399
1400 }
1401
1402 switch(f_type)
1403 {
1406 case node_type_t::FRAME:
1407 out << " D:" << decimal_number_to_string(f_decimal_number, false);
1408 break;
1409
1410 default:
1411 break;
1412
1413 }
1414
1415 for(auto f : f_flags)
1416 {
1417 out << " F:" << f.first;
1418 }
1419
1420 out << "\n";
1421
1422 for(auto v : f_variables)
1423 {
1424 out << indent_str << " V:" << v.first << "\n";
1425 v.second->display(out, indent + 6);
1426 }
1427
1428
1429 switch(f_type)
1430 {
1431 case node_type_t::ARG:
1432 case node_type_t::ARRAY:
1438 case node_type_t::LIST:
1439 case node_type_t::MAP:
1444 case node_type_t::FRAME:
1445 // display the children now
1446 for(size_t i(0); i < f_children.size(); ++i)
1447 {
1448 f_children[i]->display(out, indent + 2);
1449 }
1450 break;
1451
1452 default:
1453 break;
1454
1455 }
1456}
1457
1458void node::limit_nodes_to(uint32_t count)
1459{
1460 g_node_max_count = count;
1461}
1462
1463} // namespace csspp
1464
1465std::ostream & operator << (std::ostream & out, csspp::node_type_t const type)
1466{
1467 switch(type)
1468 {
1470 out << "UNKNOWN";
1471 break;
1472
1474 out << "ADD";
1475 break;
1476
1478 out << "AND";
1479 break;
1480
1482 out << "ASSIGNMENT";
1483 break;
1484
1486 out << "AT_KEYWORD";
1487 break;
1488
1490 out << "BOOLEAN";
1491 break;
1492
1494 out << "CDC";
1495 break;
1496
1498 out << "CDO";
1499 break;
1500
1502 out << "CLOSE_CURLYBRACKET";
1503 break;
1504
1506 out << "CLOSE_PARENTHESIS";
1507 break;
1508
1510 out << "CLOSE_SQUAREBRACKET";
1511 break;
1512
1514 out << "COLON";
1515 break;
1516
1518 out << "COLOR";
1519 break;
1520
1522 out << "COLUMN";
1523 break;
1524
1526 out << "COMMA";
1527 break;
1528
1530 out << "COMMENT";
1531 break;
1532
1534 out << "CONDITIONAL";
1535 break;
1536
1538 out << "DASH_MATCH";
1539 break;
1540
1542 out << "DECIMAL_NUMBER";
1543 break;
1544
1546 out << "DIVIDE";
1547 break;
1548
1550 out << "DOLLAR";
1551 break;
1552
1554 out << "EOF_TOKEN";
1555 break;
1556
1558 out << "EQUAL";
1559 break;
1560
1562 out << "EXCLAMATION";
1563 break;
1564
1566 out << "FONT_METRICS";
1567 break;
1568
1570 out << "FUNCTION";
1571 break;
1572
1574 out << "GREATER_EQUAL";
1575 break;
1576
1578 out << "GREATER_THAN";
1579 break;
1580
1582 out << "HASH";
1583 break;
1584
1586 out << "IDENTIFIER";
1587 break;
1588
1590 out << "INCLUDE_MATCH";
1591 break;
1592
1594 out << "INTEGER";
1595 break;
1596
1598 out << "LESS_EQUAL";
1599 break;
1600
1602 out << "LESS_THAN";
1603 break;
1604
1606 out << "MODULO";
1607 break;
1608
1610 out << "MULTIPLY";
1611 break;
1612
1614 out << "NOT_EQUAL";
1615 break;
1616
1618 out << "NULL_TOKEN";
1619 break;
1620
1622 out << "OPEN_CURLYBRACKET";
1623 break;
1624
1626 out << "OPEN_PARENTHESIS";
1627 break;
1628
1630 out << "OPEN_SQUAREBRACKET";
1631 break;
1632
1634 out << "PERCENT";
1635 break;
1636
1638 out << "PERIOD";
1639 break;
1640
1642 out << "PLACEHOLDER";
1643 break;
1644
1646 out << "POWER";
1647 break;
1648
1650 out << "PRECEDED";
1651 break;
1652
1654 out << "PREFIX_MATCH";
1655 break;
1656
1658 out << "REFERENCE";
1659 break;
1660
1662 out << "SCOPE";
1663 break;
1664
1666 out << "SEMICOLON";
1667 break;
1668
1670 out << "STRING";
1671 break;
1672
1674 out << "SUBSTRING_MATCH";
1675 break;
1676
1678 out << "SUBTRACT";
1679 break;
1680
1682 out << "SUFFIX_MATCH";
1683 break;
1684
1686 out << "UNICODE_RANGE";
1687 break;
1688
1690 out << "URL";
1691 break;
1692
1694 out << "VARIABLE";
1695 break;
1696
1698 out << "VARIABLE_FUNCTION";
1699 break;
1700
1702 out << "WHITESPACE";
1703 break;
1704
1705 // Grammar related nodes (i.e. composed nodes)
1707 out << "AN_PLUS_B";
1708 break;
1709
1711 out << "ARG";
1712 break;
1713
1715 out << "ARRAY";
1716 break;
1717
1719 out << "COMPONENT_VALUE";
1720 break;
1721
1723 out << "DECLARATION";
1724 break;
1725
1727 out << "LIST";
1728 break;
1729
1731 out << "MAP";
1732 break;
1733
1735 out << "FRAME";
1736 break;
1737
1739 out << "max_type";
1740 break;
1741
1742 }
1743
1744 return out;
1745}
1746
1747std::ostream & operator << (std::ostream & out, csspp::node const & n)
1748{
1749 n.display(out, 0);
1750 return out;
1751}
1752
1754{
1755 std::stringstream ss;
1756 ss << type;
1757 out << ss.str();
1758 return out;
1759}
1760
1761// Local Variables:
1762// mode: cpp
1763// indent-tabs-mode: nil
1764// c-basic-offset: 4
1765// tab-width: 4
1766// End:
1767
1768// vim: ts=4 sw=4 et
rgba_color_t get_color() const
Definition color.cpp:467
void set_color(rgba_color_t const rgba)
Definition color.cpp:228
std::string to_string() const
Definition color.cpp:495
void add_child(pointer_t child)
Definition node.cpp:593
integer_t get_integer() const
Definition node.cpp:367
std::string f_string
Definition node.h:206
void copy_variable(node::pointer_t source)
Definition node.cpp:717
color get_color() const
Definition node.cpp:403
variable_table_t f_variables
Definition node.h:209
bool f_boolean
Definition node.h:203
void take_over_children_of(pointer_t n)
Definition node.cpp:678
void remove_child(pointer_t child)
Definition node.cpp:635
void set_flag(std::string const &name, bool value)
Definition node.cpp:743
pointer_t get_last_child() const
Definition node.cpp:672
position const & get_position() const
Definition node.cpp:338
void set_line_height(decimal_number_t line_height)
Definition node.cpp:465
pointer_t get_child(size_t idx) const
Definition node.cpp:660
node_type_t f_type
Definition node.h:201
bool get_flag(std::string const &name)
Definition node.cpp:759
void clear_variables()
Definition node.cpp:707
void display(std::ostream &out, uint32_t indent) const
Definition node.cpp:1303
void clear()
Definition node.cpp:566
pointer_t get_variable(std::string const &name)
Definition node.cpp:728
void set_dim1(std::string const &font_size)
Definition node.cpp:489
static int const g_to_string_flag_add_spaces
Definition node.h:136
bool get_boolean() const
Definition node.cpp:379
bool is(node_type_t const type) const
Definition node.cpp:277
void set_boolean(bool integer)
Definition node.cpp:385
node_type_t get_type() const
Definition node.cpp:272
std::string const & get_lowercase_string() const
Definition node.cpp:355
void clear_flags()
Definition node.cpp:738
flag_table_t f_flags
Definition node.h:210
void set_string(std::string const &str)
Definition node.cpp:349
void set_dim2(std::string const &line_height)
Definition node.cpp:526
list_t f_children
Definition node.h:208
decimal_number_t get_font_size() const
Definition node.cpp:442
std::string get_dim1() const
Definition node.cpp:474
decimal_number_t get_decimal_number() const
Definition node.cpp:391
pointer_t clone() const
Definition node.cpp:250
void insert_child(size_t idx, pointer_t child)
Definition node.cpp:612
position f_position
Definition node.h:202
size_t child_position(pointer_t child)
Definition node.cpp:580
std::string to_string(int flags) const
Definition node.cpp:765
void set_decimal_number(decimal_number_t decimal_number)
Definition node.cpp:397
integer_t f_integer
Definition node.h:204
std::string f_lowercase_string
Definition node.h:207
size_t size() const
Definition node.cpp:573
static size_t const npos
Definition node.h:133
std::string get_dim2() const
Definition node.cpp:511
void set_color(color c)
Definition node.cpp:424
std::string const & get_string() const
Definition node.cpp:343
boolean_t to_boolean() const
Definition node.cpp:282
static int const g_to_string_flag_show_quotes
Definition node.h:135
static void limit_nodes_to(uint32_t count)
Definition node.cpp:1458
void replace_child(pointer_t o, pointer_t n)
Definition node.cpp:690
bool empty() const
Definition node.cpp:559
node(node_type_t const type, position const &pos)
Definition node.cpp:227
void set_font_size(decimal_number_t font_size)
Definition node.cpp:449
void set_integer(integer_t integer)
Definition node.cpp:373
decimal_number_t get_line_height() const
Definition node.cpp:456
void set_lowercase_string(std::string const &str)
Definition node.cpp:361
std::shared_ptr< node > pointer_t
Definition node.h:132
decimal_number_t f_decimal_number
Definition node.h:205
void set_variable(std::string const &name, pointer_t value)
Definition node.cpp:712
std::string to_string() const
std::string to_string() const
void type_supports_color(node_type_t const type)
Definition node.cpp:163
void type_supports_font_metrics(node_type_t const type)
Definition node.cpp:180
void type_supports_integer(node_type_t const type)
Definition node.cpp:71
void type_supports_decimal_number(node_type_t const type)
Definition node.cpp:114
void type_supports_children(node_type_t const type)
Definition node.cpp:196
void type_supports_boolean(node_type_t const type)
Definition node.cpp:93
void type_supports_string(node_type_t const type)
Definition node.cpp:133
The namespace of all the classes in the CSS Preprocessor.
Definition csspp.h:48
uint64_t range_value_t
std::string decimal_number_to_string(decimal_number_t d, bool remove_leading_zero)
Definition csspp.cpp:86
node_type_t
Definition node.h:41
int64_t integer_t
Definition csspp.h:58
boolean_t
Definition node.h:34
@ BOOLEAN_FALSE
Definition node.h:36
@ BOOLEAN_TRUE
Definition node.h:37
@ BOOLEAN_INVALID
Definition node.h:35
double decimal_number_t
Definition csspp.h:59
std::ostream & operator<<(std::ostream &out, csspp::node_type_t const type)
Definition node.cpp:1465

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.