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

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.