Current Version: 1.0.33
Project Name: csspp
assembler.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
30// self
31//
32#include "csspp/assembler.h"
33
34#include "csspp/exception.h"
35#include "csspp/lexer.h"
36#include "csspp/nth_child.h"
37#include "csspp/unicode_range.h"
38
39
40// C++
41//
42#include <iostream>
43
44
45// last include
46//
47#include <snapdev/poison.h>
48
49
50
51namespace csspp
52{
53
54namespace
55{
56
57typedef uint32_t flags_t;
58
66
68{
69 std::string const dimension(n->get_string());
70 std::string::size_type pos(dimension.find_first_of(" */"));
71 if(pos != std::string::npos)
72 {
73 error::instance() << n->get_position()
74 << "\""
75 << dimension
76 << "\" is not a valid CSS dimension."
78 }
79}
80
81} // no name namespace
82
83// base class
85{
86public:
87 assembler_impl(std::ostream & out)
88 : f_out(out)
89 {
90 }
91
93 {
94 }
95
96 virtual void output_string(std::string const & str)
97 {
98 if(!str.empty())
99 {
100 f_started = str.back() != '\n';
101 }
102 f_out << str;
103 }
104
105 virtual void output_operator(std::string const & str, flags_t flags)
106 {
107 static_cast<void>(flags);
108
109 // the default prints that as is
110 if((flags & g_flag_optional_operator) == 0)
111 {
112 output_string(str);
113 }
114 }
115
116 virtual void output_token(std::string const & str)
117 {
118 // the default prints that as is
119 output_string(str);
120 }
121
122 virtual void newline()
123 {
124 // by default do not write newlines
125 }
126
127 virtual void newline_if_not_empty()
128 {
129 if(f_started)
130 {
131 f_started = false;
132 f_out << std::endl;
133 }
134 }
135
136 virtual void output_identation()
137 {
138 // by default do not write identation
139 }
140
141protected:
142 std::ostream & f_out;
143 bool f_started = false;
144};
145
147{
148public:
149 assembler_compressed(std::ostream & out)
150 : assembler_impl(out)
151 {
152 }
153
155 {
156 }
157};
158
160{
161public:
162 assembler_tidy(std::ostream & out)
164 {
165 }
166
168 {
169 }
170
171 virtual void newline()
172 {
173 f_started = false;
174 f_out << std::endl;
175 }
176};
177
179{
180public:
181 assembler_compact(std::ostream & out)
182 : assembler_tidy(out)
183 {
184 }
185
187 {
188 }
189
190 virtual void output_operator(std::string const & str, flags_t flags)
191 {
192 f_started = true;
193 if((flags & (g_flag_optional_spaces | g_flag_optional_spaces_or_newlines)) != 0)
194 {
195 f_out << " " << str << " ";
196 }
197 else if((flags & (g_flag_optional_space_before | g_flag_optional_space_before_or_newline)) != 0)
198 {
199 f_out << " " << str;
200 }
201 else if((flags & (g_flag_optional_space_after | g_flag_optional_space_after_or_newline)) != 0)
202 {
203 f_out << str << " ";
204 }
205 else
206 {
208 }
209 }
210};
211
213{
214public:
215 assembler_expanded(std::ostream & out)
216 : assembler_compact(out)
217 {
218 }
219
221 {
222 }
223
224 virtual void output_operator(std::string const & str, flags_t flags)
225 {
226 if((flags & g_flag_optional_spaces_or_newlines) != 0)
227 {
228 f_started = false;
229 f_out << std::endl << str << std::endl;
230 }
231 else if((flags & g_flag_optional_space_before_or_newline) != 0)
232 {
233 f_started = false;
234 f_out << std::endl << str;
235 }
236 else if((flags & g_flag_optional_space_after_or_newline) != 0)
237 {
238 f_started = false;
239 f_out << str << std::endl;
240 }
241 else if((flags & g_flag_optional_operator) != 0)
242 {
243 f_started = true;
244 f_out << str;
245 }
246 else
247 {
249 }
250 }
251
252 virtual void output_identation()
253 {
254 f_out << " ";
255 }
256};
257
258assembler::assembler(std::ostream & out)
259 : f_out(out)
260{
261}
262
263std::string assembler::escape_id(std::string const & id)
264{
265 std::string result;
266
267 // create a temporary lexer to apply the conversion
268 std::stringstream ss;
269 position pos("assembler.css");
270 lexer l(ss, pos);
271
272 bool first_char(true);
273 for(char const *s(id.c_str()); *s != '\0'; )
274 {
275 char mb[5];
276 unsigned char c(static_cast<unsigned char>(*s));
277 size_t len(1);
278 if(c >= 0xF0)
279 {
280 len = 4;
281 }
282 else if(c >= 0xE0)
283 {
284 len = 3;
285 }
286 else if(c >= 0xC0)
287 {
288 len = 2;
289 }
290 //else len = 1 -- already set to 1 by default
291 for(size_t i(0); i < len; ++i, ++s)
292 {
293 if(*s == '\0')
294 {
295 // UTF-8 should be perfect when we reach the assembler
296 throw csspp_exception_logic("assembler.cpp: assembler::escape_id(): invalid UTF-8 character found."); // LCOV_EXCL_LINE
297 }
298 mb[i] = *s;
299 }
300 mb[len] = '\0';
301
302 wide_char_t wc(l.mbtowc(mb));
303
304 if((first_char && lexer::is_start_identifier(wc))
305 || (!first_char && lexer::is_identifier(wc)))
306 {
307 result += mb;
308 }
309 else
310 {
311 result += '\\';
312 if(wc >= '0' && wc <= '9')
313 {
314 // digits need to be defined as hexa
315 result += '3';
316 result += wc;
317 // add a space if the next character requires us to do so
318 // (by now identifier letters should all be lower case so
319 // the 'A' to 'F' should never match)
320 if((s[0] >= '0' && s[0] <= '9')
321 || (s[0] >= 'a' && s[0] <= 'f')
322 || (s[0] >= 'A' && s[0] <= 'F')) // LCOV_EXCL_LINE
323 {
324 result += ' ';
325 }
326 }
327 else
328 {
329 result += mb;
330 }
331 }
332 first_char = false;
333 }
334
335 return result;
336}
337
339{
340 f_root = n;
341
342 f_impl.reset();
343 switch(mode)
344 {
346 f_impl.reset(new assembler_compact(f_out));
347 break;
348
351 break;
352
354 f_impl.reset(new assembler_expanded(f_out));
355 break;
356
358 f_impl.reset(new assembler_tidy(f_out));
359 break;
360
361 }
362 if(!f_impl)
363 {
364 throw csspp_exception_logic("assembler.cpp: assembler::output(): called with an invalid mode.");
365 }
366
367 output(n);
368}
369
371{
372 switch(n->get_type())
373 {
374 case node_type_t::ADD:
375 f_impl->output_operator("+", g_flag_optional_spaces);
376 break;
377
378 case node_type_t::ARG:
379 {
380 size_t const max_children(n->size());
381 for(size_t idx(0); idx < max_children; ++idx)
382 {
383 output(n->get_child(idx));
384 }
385 }
386 break;
387
390 break;
391
393 f_impl->output_operator(":", 0);
394 break;
395
397 {
398 color c(n->get_color());
399 f_impl->output_token(c.to_string());
400 }
401 break;
402
403 // This should have been transformed to a list (ARG for selectors
404 // and functions...)
405 //case node_type_t::COMMA:
406 // f_impl->output_operator(",", g_flag_optional_space_after);
407 // break;
408
411 break;
412
414 f_impl->output_operator("|=", g_flag_optional_spaces);
415 break;
416
418 // this may be a dimension, if not f_string is empty anyway
419 verify_dimension(n);
420 f_out << decimal_number_to_string(n->get_decimal_number(), true) << n->get_string();
421 break;
422
424 {
425 f_impl->output_identation();
426 f_out << n->get_string();
427 f_impl->output_operator(":", g_flag_optional_space_after);
428 size_t const max_children(n->size());
429 for(size_t idx(0); idx < max_children; ++idx)
430 {
431 node::pointer_t child(n->get_child(idx));
432 output(child);
433 if(child->is(node_type_t::ARG)
434 && idx + 1 != max_children)
435 {
436 f_impl->output_operator(",", g_flag_optional_space_after);
437 }
438 }
439 // we make sure it appears at the end
440 if(n->get_flag("important"))
441 {
442 f_impl->output_operator("!", g_flag_optional_space_before);
443 f_out << "important";
444 }
445 }
446 break;
447
449 f_impl->output_operator("/", 0);
450 break;
451
453 f_impl->output_operator("=", g_flag_optional_spaces);
454 break;
455
457 // this is a mouthful!
458 f_out << decimal_number_to_string(n->get_font_size() * (n->get_dim1() == "%" ? 100.0 : 1.0), true) << n->get_dim1()
459 << "/" << decimal_number_to_string(n->get_line_height() * (n->get_dim2() == "%" ? 100.0 : 1.0), true) << n->get_dim2();
460 break;
461
463 {
464 f_out << n->get_string();
465 f_impl->output_operator("(", 0);
466 if(!n->empty())
467 {
468 if(n->get_child(0)->is(node_type_t::ARG))
469 {
470 bool first(true);
471 size_t const max_children(n->size());
472 for(size_t idx(0); idx < max_children; ++idx)
473 {
474 if(first)
475 {
476 first = false;
477 }
478 else
479 {
480 f_impl->output_operator(",", g_flag_optional_space_after);
481 }
482 output(n->get_child(idx));
483 }
484 }
485 else
486 {
487 // no ARG then no commas; this happens in :not(),
488 // :lang(), nth-child(), etc.
489 size_t const max_children(n->size());
490 for(size_t idx(0); idx < max_children; ++idx)
491 {
492 output(n->get_child(idx));
493 }
494 }
495 }
496 f_impl->output_operator(")", 0);
497 }
498 break;
499
501 f_impl->output_operator(">", g_flag_optional_spaces);
502 break;
503
505 f_out << "#" << n->get_string();
506 break;
507
509 f_out << escape_id(n->get_string());
510 break;
511
513 f_impl->output_operator("~=", g_flag_optional_spaces);
514 break;
515
517 // this may be a dimension, if not f_string is empty anyway
518 verify_dimension(n);
519 f_out << n->get_integer() << n->get_string();
520 break;
521
523 {
524 size_t const max_children(n->size());
525 for(size_t idx(0); idx < max_children; ++idx)
526 {
527 node::pointer_t child(n->get_child(idx));
528 output(child);
529 if(child->is(node_type_t::DECLARATION)
530 && idx + 1 != max_children)
531 {
532 f_impl->output_operator(";", g_flag_optional_space_after_or_newline);
533 }
534 }
535 }
536 break;
537
539 f_impl->output_operator("*", 0);
540 break;
541
543 {
544 f_impl->output_operator("{", g_flag_optional_spaces_or_newlines);
545 size_t const max_children(n->size());
546 for(size_t idx(0); idx < max_children; ++idx)
547 {
548 node::pointer_t item(n->get_child(idx));
549 output(n->get_child(idx));
550 if(item->is(node_type_t::DECLARATION)
551 && idx + 1 < max_children)
552 {
553 f_impl->output_operator(";", g_flag_optional_space_after_or_newline);
554 }
555 }
556 f_impl->output_operator(";", g_flag_optional_operator);
557 f_impl->output_operator("}", g_flag_optional_space_before_or_newline);
558 f_impl->newline();
559 }
560 break;
561
563 output_parenthesis(n, 0);
564 break;
565
567 {
568 f_impl->output_operator("[", 0);
569 size_t const max_children(n->size());
570 for(size_t idx(0); idx < max_children; ++idx)
571 {
572 output(n->get_child(idx));
573 }
574 f_impl->output_operator("]", 0);
575 }
576 break;
577
579 f_out << decimal_number_to_string(n->get_decimal_number() * 100.0, true) << "%";
580 break;
581
583 f_impl->output_operator(".", 0);
584 break;
585
587 f_impl->output_operator("~", g_flag_optional_spaces);
588 break;
589
591 f_impl->output_operator("^=", g_flag_optional_spaces);
592 break;
593
595 f_impl->output_operator("|", 0);
596 break;
597
599 output_string(n->get_string());
600 break;
601
603 f_impl->output_operator("*=", g_flag_optional_spaces);
604 break;
605
606 case node_type_t::SUBTRACT: // for calc() / expression()
607 f_impl->output_operator("-", 0);
608 break;
609
611 f_impl->output_operator("$=", g_flag_optional_spaces);
612 break;
613
615 {
616 unicode_range_t const range(static_cast<range_value_t>(n->get_integer()));
617 f_out << "U+" << range.to_string();
618 }
619 break;
620
621 case node_type_t::URL:
622 // TODO: escape special characters or we won't be able to re-read this one
623 output_url(n->get_string());
624 break;
625
627 // explicit whitespace that we still have in the tree are kept as is
628 f_out << " ";
629 break;
630
633 break;
634
636 {
637 // TODO: support adding around the operator?
638 nth_child const an_b(n->get_integer());
639 f_out << an_b.to_string();
640 }
641 break;
642
644 {
645 // output the frame position
646 //
647 decimal_number_t p(n->get_decimal_number());
648 if(p >= 1.0)
649 {
650 f_out << "to"; // strlen("to") < strlen("100%")!
651 }
652 else
653 {
654 // strlen("from") > strlen("0%") so we use "0%"
655 //
656 if(p < 0.0)
657 {
658 p = 0.0;
659 }
660 f_out << decimal_number_to_string(p * 100.0, true) << "%";
661 }
662
663 // output the frame component values
664 //
665 f_impl->output_operator("{", g_flag_optional_spaces_or_newlines);
666 size_t const max_children(n->size());
667 for(size_t idx(0); idx < max_children; ++idx)
668 {
669 node::pointer_t item(n->get_child(idx));
670 output(n->get_child(idx));
671 if(item->is(node_type_t::DECLARATION)
672 && idx + 1 < max_children)
673 {
674 f_impl->output_operator(";", g_flag_optional_space_after_or_newline);
675 }
676 }
677 f_impl->output_operator(";", g_flag_optional_operator);
678 f_impl->output_operator("}", g_flag_optional_space_before_or_newline);
679 f_impl->newline();
680 }
681 break;
682
684 case node_type_t::AND:
688 case node_type_t::CDC:
689 case node_type_t::CDO:
702 case node_type_t::MAP:
713 // many of the nodes are not expected in a valid tree being compiled
714 // all of those will generate this exception
715 {
716 std::stringstream ss;
717 ss << "assembler.cpp: unexpected token "
718 << n->get_type()
719 << " in output() call.";
720 throw csspp_exception_logic(ss.str());
721 }
722
723 }
724}
725
727{
728 bool first(true);
729 bool has_arg(false);
730 size_t const max_children(n->size());
731 for(size_t idx(0); idx < max_children; ++idx)
732 {
733 node::pointer_t c(n->get_child(idx));
735 {
736 if(has_arg)
737 {
738 output(c);
739 }
740 }
741 else if(!c->is(node_type_t::ARG))
742 {
743 // unexpected for a component value
744 //
745 std::stringstream ss; // LCOV_EXCL_LINE
746 ss << "assembler.cpp: expected all direct children of COMPONENT_VALUE to be ARG instead of " // LCOV_EXCL_LINE
747 << c->get_type() // LCOV_EXCL_LINE
748 << " on line " // LCOV_EXCL_LINE
749 << c->get_position().get_line() // LCOV_EXCL_LINE
750 << " in \"" // LCOV_EXCL_LINE
751 << c->get_position().get_filename() // LCOV_EXCL_LINE
752 << "\"."; // LCOV_EXCL_LINE
753 if(c->is(node_type_t::IDENTIFIER)) // LCOV_EXCL_LINE
754 {
755 ss << " (identifier is \"" << escape_id(c->get_string()) << "\")"; // LCOV_EXCL_LINE
756 }
757 throw csspp_exception_logic(ss.str()); // LCOV_EXCL_LINE
758 } // LCOV_EXCL_LINE
759 else if(c->empty() || !c->get_last_child()->is(node_type_t::PLACEHOLDER))
760 {
761 // TODO: if we compile out PLACEHOLDER nodes in the compiler
762 // then we can remove the test here... (on the line prior)
763 has_arg = true;
764 if(first)
765 {
766 first = false;
767 }
768 else
769 {
770 f_impl->output_operator(",", g_flag_optional_space_after);
771 }
772 output(c);
773 }
774 }
775}
776
778{
779 if(flags == 0)
780 {
781 // we must have a space here otherwise the '(' transforms a
782 // preceeding identifier in a function
783 //
784 // TODO: once our assembler is smarter we will know what is
785 // before and thus avoid the space if possible.
786 //
787 f_out << " ";
788 }
789 f_impl->output_operator("(", 0);
790 size_t const max_children(n->size());
791 for(size_t idx(0); idx < max_children; ++idx)
792 {
793 node::pointer_t child(n->get_child(idx));
794 if(child->is(node_type_t::OPEN_PARENTHESIS))
795 {
796 if(idx != 0)
797 {
798 f_out << " ";
799 }
800 output_parenthesis(child, 1);
801 }
802 else
803 {
804 output(child);
805 }
806 }
807 f_impl->output_operator(")", flags == 0 ? g_flag_optional_space_after : 0);
808}
809
811{
812 f_out << "@" << n->get_string() << " ";
813 bool no_block(true);
814 size_t const max_children(n->size());
815 if(max_children > 0)
816 {
817 if(n->get_string() == "-o-keyframes"
818 || n->get_string() == "-webkit-keyframes"
819 || n->get_string() == "keyframes")
820 {
821 // in this case we have one identifier followed by X frames
822 // which need to appear between '{' ... '}'
823 //
824 output(n->get_child(0));
825 f_impl->output_operator("{", g_flag_optional_space_before);
826 f_impl->newline();
827 for(size_t idx(1); idx < max_children; ++idx)
828 {
829 output(n->get_child(idx));
830 }
831 f_impl->output_operator("}", 0);
832 no_block = false; // do not output ';'
833 }
834 else
835 {
836 for(size_t idx(0); idx < max_children; ++idx)
837 {
838 node::pointer_t child(n->get_child(idx));
839 if(idx + 1 == max_children
840 && child->is(node_type_t::OPEN_CURLYBRACKET))
841 {
842 f_impl->newline();
843 no_block = false; // do not output ';'
844 }
845 //if(child->is(node_type_t::COMPONENT_VALUE))
846 //{
847 // f_impl->newline();
848 // f_impl->output_operator("{", 0);
849 // f_impl->newline();
850 // output(child);
851 // f_impl->output_operator("}", 0);
852 // f_impl->newline();
853 //}
854 //else
855 if(child->is(node_type_t::OPEN_CURLYBRACKET))
856 {
857 // nearly like output(child), except that we do not add
858 // a ';' before the '}'
859 f_impl->output_operator("{", 0);
860 f_impl->newline();
861 size_t const max_sub_children(child->size());
862 for(size_t j(0); j < max_sub_children; ++j)
863 {
864 output(child->get_child(j));
865 }
866 f_impl->output_operator("}", 0);
867 f_impl->newline();
868 }
869 else if(child->is(node_type_t::ARG))
870 {
871 output(child);
872 if(idx + 1 < max_children
873 && n->get_child(idx + 1)->is(node_type_t::ARG))
874 {
875 f_impl->output_operator(",", g_flag_optional_space_after);
876 }
877 }
878 else
879 {
880 output(child);
881 }
882 }
883 }
884 }
885 if(no_block)
886 {
887 f_out << ";";
888 }
889
890 // extra newline after an @-keyword
891 f_impl->newline();
892}
893
895{
896 // we take care of comments and don't give the impl's a chance to
897 // do anything about this; (1) we force a newline before if we
898 // already output something; (2) we force a newline at the end
899 //
900 f_impl->newline_if_not_empty();
901 std::string const comment(n->get_string());
902 if(n->get_integer() == 0)
903 {
904 // note: a C++ comment is not valid in a .css file, so here we
905 // convert it
906 //
907 bool first(true);
908 std::string::size_type start(0);
909 std::string::size_type end(comment.find('\n'));
910 while(end != std::string::npos)
911 {
912 if(first)
913 {
914 first = false;
915 f_out << "/* ";
916 }
917 else
918 {
919 f_out << " * ";
920 }
921 f_out << comment.substr(start, end - start) << std::endl;
922 start = end + 1;
923 end = comment.find('\n', start);
924 }
925 if(start < comment.size())
926 {
927 if(first)
928 {
929 // write the whole thing on a single line
930 f_out << "/* "
931 << comment.substr(start)
932 << " */"
933 << std::endl;
934 }
935 else
936 {
937 f_out << " * " << comment.substr(start) << std::endl
938 << " */" << std::endl;
939 }
940 }
941 }
942 else
943 {
944 // TODO: add the " * " on each line? (I don't think we remove
945 // those thus we would already have them if present in the
946 // source)
947 //
948 f_out << "/* " << comment << " */" << std::endl;
949 }
950}
951
952void assembler::output_string(std::string const & str)
953{
954 // count the single and double quotes
955 int sq(0);
956 int dq(0);
957 for(char const *s(str.c_str()); *s != '\0'; ++s)
958 {
959 if(*s == '\'')
960 {
961 ++sq;
962 }
963 else if(*s == '"')
964 {
965 ++dq;
966 }
967 }
968
969 // more single quotes? if so use "..."
970 if(sq >= dq)
971 {
972 // use " in this case
973 f_out << '"';
974 for(char const *s(str.c_str()); *s != '\0'; ++s)
975 {
976 if(*s == '"')
977 {
978 f_out << "\\\"";
979 }
980 else
981 {
982 f_out << *s;
983 }
984 }
985 f_out << '"';
986 }
987 else
988 {
989 // use ' in this case
990 f_out << '\'';
991 for(char const *s(str.c_str()); *s != '\0'; ++s)
992 {
993 if(*s == '\'')
994 {
995 f_out << "\\'";
996 }
997 else
998 {
999 f_out << *s;
1000 }
1001 }
1002 f_out << '\'';
1003 }
1004}
1005
1006void assembler::output_url(std::string const & str)
1007{
1008 f_out << "url";
1009 f_impl->output_operator("(", g_flag_optional_space_after);
1010
1011 //
1012 // the URI can be output as is if it does not include one of:
1013 // '('
1014 // ')'
1015 // "'"
1016 // '"'
1017 // non-printable character (see lexer)
1018 //
1019 bool direct(true);
1020 for(char const *s(str.c_str()); *s != '\0'; ++s)
1021 {
1022 char const c(*s);
1023 if(c == '('
1024 || c == ')'
1025 || c == '\''
1026 || c == '"'
1027 || lexer::is_non_printable(static_cast<wide_char_t>(c))) // this is UTF-8 compatible
1028 {
1029 direct = false;
1030 break;
1031 }
1032 }
1033 if(direct)
1034 {
1035 // we can output that one as is
1036 f_out << str;
1037 }
1038 else
1039 {
1040 // output this URI as a string
1041 output_string(str);
1042 }
1043
1044 f_impl->output_operator(")", g_flag_optional_space_before);
1045}
1046
1047} // namespace csspp
1048
1049std::ostream & operator << (std::ostream & out, csspp::output_mode_t const type)
1050{
1051 switch(type)
1052 {
1054 out << "COMPACT";
1055 break;
1056
1058 out << "COMPRESSED";
1059 break;
1060
1062 out << "EXPANDED";
1063 break;
1064
1066 out << "TIDY";
1067 break;
1068
1069 }
1070
1071 return out;
1072}
1073
1074// Local Variables:
1075// mode: cpp
1076// indent-tabs-mode: nil
1077// c-basic-offset: 4
1078// tab-width: 4
1079// End:
1080
1081// vim: ts=4 sw=4 et
std::ostream & operator<<(std::ostream &out, csspp::output_mode_t const type)
virtual void output_operator(std::string const &str, flags_t flags)
assembler_compact(std::ostream &out)
assembler_compressed(std::ostream &out)
virtual void output_identation()
virtual void output_operator(std::string const &str, flags_t flags)
assembler_expanded(std::ostream &out)
assembler_impl(std::ostream &out)
Definition assembler.cpp:87
virtual void newline()
virtual void output_token(std::string const &str)
virtual void output_string(std::string const &str)
Definition assembler.cpp:96
std::ostream & f_out
virtual void output_identation()
virtual void output_operator(std::string const &str, flags_t flags)
virtual void newline_if_not_empty()
virtual ~assembler_impl()
Definition assembler.cpp:92
virtual void newline()
assembler_tidy(std::ostream &out)
std::shared_ptr< assembler_impl > f_impl
Definition assembler.h:54
void output_at_keyword(node::pointer_t n)
std::string escape_id(std::string const &id)
node::pointer_t f_root
Definition assembler.h:56
void output_component_value(node::pointer_t n)
assembler(std::ostream &out)
void output_string(std::string const &str)
void output_comment(node::pointer_t n)
std::ostream & f_out
Definition assembler.h:55
void output_url(std::string const &str)
void output_parenthesis(node::pointer_t n, int flags)
void output(node::pointer_t n, output_mode_t mode)
std::string to_string() const
Definition color.cpp:495
static error & instance()
Definition error.cpp:77
static bool constexpr is_start_identifier(wide_char_t c)
Definition lexer.h:78
wide_char_t mbtowc(char const *mb)
Definition lexer.cpp:488
static bool constexpr is_identifier(wide_char_t c)
Definition lexer.h:67
static bool constexpr is_non_printable(wide_char_t c)
Definition lexer.h:47
std::shared_ptr< node > pointer_t
Definition node.h:132
std::string to_string() const
std::string to_string() const
void verify_dimension(node::pointer_t n)
Definition assembler.cpp:67
The namespace of all the classes in the CSS Preprocessor.
Definition csspp.h:48
output_mode_t
Definition assembler.h:27
uint64_t range_value_t
int32_t wide_char_t
Definition csspp.h:55
std::string decimal_number_to_string(decimal_number_t d, bool remove_leading_zero)
Definition csspp.cpp:86
double decimal_number_t
Definition csspp.h:59

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.