sassc 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.gitmodules +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +21 -0
- data/ext/libsass/.editorconfig +15 -0
- data/ext/libsass/.gitattributes +2 -0
- data/ext/libsass/.gitignore +61 -0
- data/ext/libsass/.travis.yml +38 -0
- data/ext/libsass/COPYING +25 -0
- data/ext/libsass/INSTALL +1 -0
- data/ext/libsass/LICENSE +25 -0
- data/ext/libsass/Makefile +223 -0
- data/ext/libsass/Makefile.am +145 -0
- data/ext/libsass/Readme.md +93 -0
- data/ext/libsass/appveyor.yml +76 -0
- data/ext/libsass/ast.cpp +581 -0
- data/ext/libsass/ast.hpp +1949 -0
- data/ext/libsass/ast_def_macros.hpp +16 -0
- data/ext/libsass/ast_factory.hpp +87 -0
- data/ext/libsass/ast_fwd_decl.hpp +72 -0
- data/ext/libsass/b64/cencode.h +32 -0
- data/ext/libsass/b64/encode.h +77 -0
- data/ext/libsass/backtrace.hpp +81 -0
- data/ext/libsass/base64vlq.cpp +43 -0
- data/ext/libsass/base64vlq.hpp +28 -0
- data/ext/libsass/bind.cpp +187 -0
- data/ext/libsass/bind.hpp +18 -0
- data/ext/libsass/cencode.c +102 -0
- data/ext/libsass/color_names.hpp +324 -0
- data/ext/libsass/configure.ac +130 -0
- data/ext/libsass/constants.cpp +144 -0
- data/ext/libsass/constants.hpp +145 -0
- data/ext/libsass/context.cpp +507 -0
- data/ext/libsass/context.hpp +150 -0
- data/ext/libsass/contextualize.cpp +157 -0
- data/ext/libsass/contextualize.hpp +65 -0
- data/ext/libsass/copy_c_str.cpp +13 -0
- data/ext/libsass/copy_c_str.hpp +5 -0
- data/ext/libsass/debug.hpp +39 -0
- data/ext/libsass/environment.hpp +75 -0
- data/ext/libsass/error_handling.cpp +28 -0
- data/ext/libsass/error_handling.hpp +28 -0
- data/ext/libsass/eval.cpp +1149 -0
- data/ext/libsass/eval.hpp +80 -0
- data/ext/libsass/expand.cpp +430 -0
- data/ext/libsass/expand.hpp +77 -0
- data/ext/libsass/extconf.rb +6 -0
- data/ext/libsass/extend.cpp +1962 -0
- data/ext/libsass/extend.hpp +50 -0
- data/ext/libsass/file.cpp +291 -0
- data/ext/libsass/file.hpp +18 -0
- data/ext/libsass/functions.cpp +1565 -0
- data/ext/libsass/functions.hpp +187 -0
- data/ext/libsass/inspect.cpp +727 -0
- data/ext/libsass/inspect.hpp +108 -0
- data/ext/libsass/json.cpp +1411 -0
- data/ext/libsass/json.hpp +117 -0
- data/ext/libsass/kwd_arg_macros.hpp +23 -0
- data/ext/libsass/m4/.gitkeep +0 -0
- data/ext/libsass/mapping.hpp +17 -0
- data/ext/libsass/memory_manager.hpp +54 -0
- data/ext/libsass/node.cpp +251 -0
- data/ext/libsass/node.hpp +122 -0
- data/ext/libsass/operation.hpp +153 -0
- data/ext/libsass/output_compressed.cpp +401 -0
- data/ext/libsass/output_compressed.hpp +95 -0
- data/ext/libsass/output_nested.cpp +364 -0
- data/ext/libsass/output_nested.hpp +108 -0
- data/ext/libsass/parser.cpp +2016 -0
- data/ext/libsass/parser.hpp +264 -0
- data/ext/libsass/paths.hpp +69 -0
- data/ext/libsass/position.hpp +22 -0
- data/ext/libsass/posix/getopt.c +562 -0
- data/ext/libsass/posix/getopt.h +95 -0
- data/ext/libsass/prelexer.cpp +688 -0
- data/ext/libsass/prelexer.hpp +513 -0
- data/ext/libsass/remove_placeholders.cpp +59 -0
- data/ext/libsass/remove_placeholders.hpp +43 -0
- data/ext/libsass/res/resource.rc +35 -0
- data/ext/libsass/sass.cpp +33 -0
- data/ext/libsass/sass.h +60 -0
- data/ext/libsass/sass2scss.cpp +834 -0
- data/ext/libsass/sass2scss.h +110 -0
- data/ext/libsass/sass_context.cpp +709 -0
- data/ext/libsass/sass_context.h +120 -0
- data/ext/libsass/sass_functions.cpp +137 -0
- data/ext/libsass/sass_functions.h +90 -0
- data/ext/libsass/sass_interface.cpp +277 -0
- data/ext/libsass/sass_interface.h +97 -0
- data/ext/libsass/sass_util.cpp +136 -0
- data/ext/libsass/sass_util.hpp +259 -0
- data/ext/libsass/sass_values.cpp +337 -0
- data/ext/libsass/sass_values.h +124 -0
- data/ext/libsass/script/bootstrap +10 -0
- data/ext/libsass/script/branding +10 -0
- data/ext/libsass/script/ci-build-libsass +72 -0
- data/ext/libsass/script/ci-install-compiler +4 -0
- data/ext/libsass/script/ci-install-deps +19 -0
- data/ext/libsass/script/ci-report-coverage +25 -0
- data/ext/libsass/script/coveralls-debug +32 -0
- data/ext/libsass/script/spec +5 -0
- data/ext/libsass/script/tap-driver +652 -0
- data/ext/libsass/script/tap-runner +1 -0
- data/ext/libsass/source_map.cpp +133 -0
- data/ext/libsass/source_map.hpp +46 -0
- data/ext/libsass/subset_map.hpp +145 -0
- data/ext/libsass/support/libsass.pc.in +11 -0
- data/ext/libsass/test-driver +127 -0
- data/ext/libsass/test/test_node.cpp +98 -0
- data/ext/libsass/test/test_paths.cpp +29 -0
- data/ext/libsass/test/test_selector_difference.cpp +28 -0
- data/ext/libsass/test/test_specificity.cpp +28 -0
- data/ext/libsass/test/test_subset_map.cpp +472 -0
- data/ext/libsass/test/test_superselector.cpp +71 -0
- data/ext/libsass/test/test_unification.cpp +33 -0
- data/ext/libsass/to_c.cpp +61 -0
- data/ext/libsass/to_c.hpp +44 -0
- data/ext/libsass/to_string.cpp +29 -0
- data/ext/libsass/to_string.hpp +32 -0
- data/ext/libsass/token.hpp +32 -0
- data/ext/libsass/units.cpp +54 -0
- data/ext/libsass/units.hpp +10 -0
- data/ext/libsass/utf8.h +34 -0
- data/ext/libsass/utf8/checked.h +327 -0
- data/ext/libsass/utf8/core.h +329 -0
- data/ext/libsass/utf8/unchecked.h +228 -0
- data/ext/libsass/utf8_string.cpp +102 -0
- data/ext/libsass/utf8_string.hpp +36 -0
- data/ext/libsass/util.cpp +189 -0
- data/ext/libsass/util.hpp +26 -0
- data/ext/libsass/win/libsass.filters +291 -0
- data/ext/libsass/win/libsass.sln +28 -0
- data/ext/libsass/win/libsass.vcxproj +255 -0
- data/lib/sassc.rb +6 -0
- data/lib/sassc/engine.rb +13 -0
- data/lib/sassc/native.rb +44 -0
- data/lib/sassc/native/native_context_api.rb +140 -0
- data/lib/sassc/native/native_functions_api.rb +41 -0
- data/lib/sassc/native/sass_input_style.rb +11 -0
- data/lib/sassc/native/sass_output_style.rb +10 -0
- data/lib/sassc/native/sass_value.rb +95 -0
- data/lib/sassc/native/string_list.rb +8 -0
- data/lib/sassc/version.rb +3 -0
- data/sassc.gemspec +43 -0
- data/test/smoke_test.rb +171 -0
- data/test/test_helper.rb +4 -0
- metadata +281 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#define SASS_NODE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
#include <deque>
|
|
5
|
+
#include <iostream>
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
#ifndef SASS_AST
|
|
9
|
+
#include "ast.hpp"
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
namespace Sass {
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
using namespace std;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
struct Context;
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
There are a lot of stumbling blocks when trying to port the ruby extend code to C++. The biggest is the choice of
|
|
23
|
+
data type. The ruby code will pretty seamlessly switch types between an Array<SimpleSequence or Op> (libsass'
|
|
24
|
+
equivalent is the Complex_Selector) to a Sequence, which contains more metadata about the sequence than just the
|
|
25
|
+
selector info. They also have the ability to have arbitrary nestings of arrays like [1, [2]], which is hard to
|
|
26
|
+
implement using Array equivalents in C++ (like the deque or vector). They also have the ability to include nil
|
|
27
|
+
in the arrays, like [1, nil, 3], which has potential semantic differences than an empty array [1, [], 3]. To be
|
|
28
|
+
able to represent all of these as unique cases, we need to create a tree of variant objects. The tree nature allows
|
|
29
|
+
the inconsistent nesting levels. The variant nature (while making some of the C++ code uglier) allows the code to
|
|
30
|
+
more closely match the ruby code, which is a huge benefit when attempting to implement an complex algorithm like
|
|
31
|
+
the Extend operator.
|
|
32
|
+
|
|
33
|
+
Note that the current libsass data model also pairs the combinator with the Complex_Selector that follows it, but
|
|
34
|
+
ruby sass has no such restriction, so we attempt to create a data structure that can handle them split apart.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
class Node;
|
|
38
|
+
typedef deque<Node> NodeDeque;
|
|
39
|
+
typedef shared_ptr<NodeDeque> NodeDequePtr;
|
|
40
|
+
|
|
41
|
+
class Node {
|
|
42
|
+
public:
|
|
43
|
+
enum TYPE {
|
|
44
|
+
SELECTOR,
|
|
45
|
+
COMBINATOR,
|
|
46
|
+
COLLECTION,
|
|
47
|
+
NIL
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
TYPE type() const { return mType; }
|
|
51
|
+
bool isCombinator() const { return mType == COMBINATOR; }
|
|
52
|
+
bool isSelector() const { return mType == SELECTOR; }
|
|
53
|
+
bool isCollection() const { return mType == COLLECTION; }
|
|
54
|
+
bool isNil() const { return mType == NIL; }
|
|
55
|
+
|
|
56
|
+
Complex_Selector::Combinator combinator() const { return mCombinator; }
|
|
57
|
+
|
|
58
|
+
Complex_Selector* selector() { return mpSelector; }
|
|
59
|
+
const Complex_Selector* selector() const { return mpSelector; }
|
|
60
|
+
|
|
61
|
+
NodeDequePtr collection() { return mpCollection; }
|
|
62
|
+
const NodeDequePtr collection() const { return mpCollection; }
|
|
63
|
+
|
|
64
|
+
static Node createCombinator(const Complex_Selector::Combinator& combinator);
|
|
65
|
+
|
|
66
|
+
// This method will clone the selector, stripping off the tail and combinator
|
|
67
|
+
static Node createSelector(Complex_Selector* pSelector, Context& ctx);
|
|
68
|
+
|
|
69
|
+
static Node createCollection();
|
|
70
|
+
static Node createCollection(const NodeDeque& values);
|
|
71
|
+
|
|
72
|
+
static Node createNil();
|
|
73
|
+
|
|
74
|
+
Node clone(Context& ctx) const;
|
|
75
|
+
|
|
76
|
+
bool operator==(const Node& rhs) const;
|
|
77
|
+
inline bool operator!=(const Node& rhs) const { return !(*this == rhs); }
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
COLLECTION FUNCTIONS
|
|
82
|
+
|
|
83
|
+
Most types don't need any helper methods (nil and combinator due to their simplicity and
|
|
84
|
+
selector due to the fact that we leverage the non-node selector code on the Complex_Selector
|
|
85
|
+
whereever possible). The following methods are intended to be called on Node objects whose
|
|
86
|
+
type is COLLECTION only.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
// rhs and this must be node collections. Shallow copy the nodes from rhs to the end of this.
|
|
90
|
+
// This function DOES NOT remove the nodes from rhs.
|
|
91
|
+
void plus(Node& rhs);
|
|
92
|
+
|
|
93
|
+
// potentialChild must be a node collection of selectors/combinators. this must be a collection
|
|
94
|
+
// of collections of nodes/combinators. This method checks if potentialChild is a child of this
|
|
95
|
+
// Node.
|
|
96
|
+
bool contains(const Node& potentialChild, bool simpleSelectorOrderDependent) const;
|
|
97
|
+
|
|
98
|
+
private:
|
|
99
|
+
// Private constructor; Use the static methods (like createCombinator and createSelector)
|
|
100
|
+
// to instantiate this object. This is more expressive, and it allows us to break apart each
|
|
101
|
+
// case into separate functions.
|
|
102
|
+
Node(const TYPE& type, Complex_Selector::Combinator combinator, Complex_Selector* pSelector, NodeDequePtr& pCollection);
|
|
103
|
+
|
|
104
|
+
TYPE mType;
|
|
105
|
+
|
|
106
|
+
// TODO: can we union these to save on memory?
|
|
107
|
+
Complex_Selector::Combinator mCombinator;
|
|
108
|
+
Complex_Selector* mpSelector; // this is an AST_Node, so it will be handled by the Memory_Manager
|
|
109
|
+
NodeDequePtr mpCollection;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
ostream& operator<<(ostream& os, const Node& node);
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
Node complexSelectorToNode(Complex_Selector* pToConvert, Context& ctx);
|
|
117
|
+
Complex_Selector* nodeToComplexSelector(const Node& toConvert, Context& ctx);
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
bool nodesEqual(const Node& one, const Node& two, bool simpleSelectorOrderDependent);
|
|
121
|
+
|
|
122
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#define SASS_OPERATION
|
|
2
|
+
|
|
3
|
+
#include "ast_fwd_decl.hpp"
|
|
4
|
+
|
|
5
|
+
#include <iostream>
|
|
6
|
+
using namespace std;
|
|
7
|
+
#include <typeinfo>
|
|
8
|
+
|
|
9
|
+
namespace Sass {
|
|
10
|
+
|
|
11
|
+
template<typename T>
|
|
12
|
+
class Operation {
|
|
13
|
+
public:
|
|
14
|
+
virtual T operator()(AST_Node* x) = 0;
|
|
15
|
+
virtual ~Operation() { }
|
|
16
|
+
// statements
|
|
17
|
+
virtual T operator()(Block* x) = 0;
|
|
18
|
+
virtual T operator()(Ruleset* x) = 0;
|
|
19
|
+
virtual T operator()(Propset* x) = 0;
|
|
20
|
+
virtual T operator()(Feature_Block* x) = 0;
|
|
21
|
+
virtual T operator()(Media_Block* x) = 0;
|
|
22
|
+
virtual T operator()(At_Rule* x) = 0;
|
|
23
|
+
virtual T operator()(Declaration* x) = 0;
|
|
24
|
+
virtual T operator()(Assignment* x) = 0;
|
|
25
|
+
virtual T operator()(Import* x) = 0;
|
|
26
|
+
virtual T operator()(Import_Stub* x) = 0;
|
|
27
|
+
virtual T operator()(Warning* x) = 0;
|
|
28
|
+
virtual T operator()(Error* x) = 0;
|
|
29
|
+
virtual T operator()(Debug* x) = 0;
|
|
30
|
+
virtual T operator()(Comment* x) = 0;
|
|
31
|
+
virtual T operator()(If* x) = 0;
|
|
32
|
+
virtual T operator()(For* x) = 0;
|
|
33
|
+
virtual T operator()(Each* x) = 0;
|
|
34
|
+
virtual T operator()(While* x) = 0;
|
|
35
|
+
virtual T operator()(Return* x) = 0;
|
|
36
|
+
virtual T operator()(Content* x) = 0;
|
|
37
|
+
virtual T operator()(Extension* x) = 0;
|
|
38
|
+
virtual T operator()(Definition* x) = 0;
|
|
39
|
+
virtual T operator()(Mixin_Call* x) = 0;
|
|
40
|
+
// expressions
|
|
41
|
+
virtual T operator()(List* x) = 0;
|
|
42
|
+
virtual T operator()(Map* x) = 0;
|
|
43
|
+
virtual T operator()(Binary_Expression* x) = 0;
|
|
44
|
+
virtual T operator()(Unary_Expression* x) = 0;
|
|
45
|
+
virtual T operator()(Function_Call* x) = 0;
|
|
46
|
+
virtual T operator()(Function_Call_Schema* x) = 0;
|
|
47
|
+
virtual T operator()(Variable* x) = 0;
|
|
48
|
+
virtual T operator()(Textual* x) = 0;
|
|
49
|
+
virtual T operator()(Number* x) = 0;
|
|
50
|
+
virtual T operator()(Color* x) = 0;
|
|
51
|
+
virtual T operator()(Boolean* x) = 0;
|
|
52
|
+
virtual T operator()(String_Schema* x) = 0;
|
|
53
|
+
virtual T operator()(String_Constant* x) = 0;
|
|
54
|
+
virtual T operator()(Feature_Query* x) = 0;
|
|
55
|
+
virtual T operator()(Feature_Query_Condition* x)= 0;
|
|
56
|
+
virtual T operator()(Media_Query* x) = 0;
|
|
57
|
+
virtual T operator()(Media_Query_Expression* x) = 0;
|
|
58
|
+
virtual T operator()(Null* x) = 0;
|
|
59
|
+
// parameters and arguments
|
|
60
|
+
virtual T operator()(Parameter* x) = 0;
|
|
61
|
+
virtual T operator()(Parameters* x) = 0;
|
|
62
|
+
virtual T operator()(Argument* x) = 0;
|
|
63
|
+
virtual T operator()(Arguments* x) = 0;
|
|
64
|
+
// selectors
|
|
65
|
+
virtual T operator()(Selector_Schema* x) = 0;
|
|
66
|
+
virtual T operator()(Selector_Reference* x) = 0;
|
|
67
|
+
virtual T operator()(Selector_Placeholder* x) = 0;
|
|
68
|
+
virtual T operator()(Type_Selector* x) = 0;
|
|
69
|
+
virtual T operator()(Selector_Qualifier* x) = 0;
|
|
70
|
+
virtual T operator()(Attribute_Selector* x) = 0;
|
|
71
|
+
virtual T operator()(Pseudo_Selector* x) = 0;
|
|
72
|
+
virtual T operator()(Wrapped_Selector* x) = 0;
|
|
73
|
+
virtual T operator()(Compound_Selector* x) = 0;
|
|
74
|
+
virtual T operator()(Complex_Selector* x) = 0;
|
|
75
|
+
virtual T operator()(Selector_List* x) = 0;
|
|
76
|
+
|
|
77
|
+
template <typename U>
|
|
78
|
+
T fallback(U x) { return T(); }
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
template <typename T, typename D>
|
|
82
|
+
class Operation_CRTP : public Operation<T> {
|
|
83
|
+
public:
|
|
84
|
+
virtual T operator()(AST_Node* x) { return static_cast<D*>(this)->fallback(x); }
|
|
85
|
+
virtual ~Operation_CRTP() = 0;
|
|
86
|
+
// statements
|
|
87
|
+
virtual T operator()(Block* x) { return static_cast<D*>(this)->fallback(x); }
|
|
88
|
+
virtual T operator()(Ruleset* x) { return static_cast<D*>(this)->fallback(x); }
|
|
89
|
+
virtual T operator()(Propset* x) { return static_cast<D*>(this)->fallback(x); }
|
|
90
|
+
virtual T operator()(Feature_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
|
91
|
+
virtual T operator()(Media_Block* x) { return static_cast<D*>(this)->fallback(x); }
|
|
92
|
+
virtual T operator()(At_Rule* x) { return static_cast<D*>(this)->fallback(x); }
|
|
93
|
+
virtual T operator()(Declaration* x) { return static_cast<D*>(this)->fallback(x); }
|
|
94
|
+
virtual T operator()(Assignment* x) { return static_cast<D*>(this)->fallback(x); }
|
|
95
|
+
virtual T operator()(Import* x) { return static_cast<D*>(this)->fallback(x); }
|
|
96
|
+
virtual T operator()(Import_Stub* x) { return static_cast<D*>(this)->fallback(x); }
|
|
97
|
+
virtual T operator()(Warning* x) { return static_cast<D*>(this)->fallback(x); }
|
|
98
|
+
virtual T operator()(Error* x) { return static_cast<D*>(this)->fallback(x); }
|
|
99
|
+
virtual T operator()(Debug* x) { return static_cast<D*>(this)->fallback(x); }
|
|
100
|
+
virtual T operator()(Comment* x) { return static_cast<D*>(this)->fallback(x); }
|
|
101
|
+
virtual T operator()(If* x) { return static_cast<D*>(this)->fallback(x); }
|
|
102
|
+
virtual T operator()(For* x) { return static_cast<D*>(this)->fallback(x); }
|
|
103
|
+
virtual T operator()(Each* x) { return static_cast<D*>(this)->fallback(x); }
|
|
104
|
+
virtual T operator()(While* x) { return static_cast<D*>(this)->fallback(x); }
|
|
105
|
+
virtual T operator()(Return* x) { return static_cast<D*>(this)->fallback(x); }
|
|
106
|
+
virtual T operator()(Content* x) { return static_cast<D*>(this)->fallback(x); }
|
|
107
|
+
virtual T operator()(Extension* x) { return static_cast<D*>(this)->fallback(x); }
|
|
108
|
+
virtual T operator()(Definition* x) { return static_cast<D*>(this)->fallback(x); }
|
|
109
|
+
virtual T operator()(Mixin_Call* x) { return static_cast<D*>(this)->fallback(x); }
|
|
110
|
+
// expressions
|
|
111
|
+
virtual T operator()(List* x) { return static_cast<D*>(this)->fallback(x); }
|
|
112
|
+
virtual T operator()(Map* x) { return static_cast<D*>(this)->fallback(x); }
|
|
113
|
+
virtual T operator()(Binary_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
|
114
|
+
virtual T operator()(Unary_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
|
115
|
+
virtual T operator()(Function_Call* x) { return static_cast<D*>(this)->fallback(x); }
|
|
116
|
+
virtual T operator()(Function_Call_Schema* x) { return static_cast<D*>(this)->fallback(x); }
|
|
117
|
+
virtual T operator()(Variable* x) { return static_cast<D*>(this)->fallback(x); }
|
|
118
|
+
virtual T operator()(Textual* x) { return static_cast<D*>(this)->fallback(x); }
|
|
119
|
+
virtual T operator()(Number* x) { return static_cast<D*>(this)->fallback(x); }
|
|
120
|
+
virtual T operator()(Color* x) { return static_cast<D*>(this)->fallback(x); }
|
|
121
|
+
virtual T operator()(Boolean* x) { return static_cast<D*>(this)->fallback(x); }
|
|
122
|
+
virtual T operator()(String_Schema* x) { return static_cast<D*>(this)->fallback(x); }
|
|
123
|
+
virtual T operator()(String_Constant* x) { return static_cast<D*>(this)->fallback(x); }
|
|
124
|
+
virtual T operator()(Feature_Query* x) { return static_cast<D*>(this)->fallback(x); }
|
|
125
|
+
virtual T operator()(Feature_Query_Condition* x){ return static_cast<D*>(this)->fallback(x); }
|
|
126
|
+
virtual T operator()(Media_Query* x) { return static_cast<D*>(this)->fallback(x); }
|
|
127
|
+
virtual T operator()(Media_Query_Expression* x) { return static_cast<D*>(this)->fallback(x); }
|
|
128
|
+
virtual T operator()(Null* x) { return static_cast<D*>(this)->fallback(x); }
|
|
129
|
+
// parameters and arguments
|
|
130
|
+
virtual T operator()(Parameter* x) { return static_cast<D*>(this)->fallback(x); }
|
|
131
|
+
virtual T operator()(Parameters* x) { return static_cast<D*>(this)->fallback(x); }
|
|
132
|
+
virtual T operator()(Argument* x) { return static_cast<D*>(this)->fallback(x); }
|
|
133
|
+
virtual T operator()(Arguments* x) { return static_cast<D*>(this)->fallback(x); }
|
|
134
|
+
// selectors
|
|
135
|
+
virtual T operator()(Selector_Schema* x) { return static_cast<D*>(this)->fallback(x); }
|
|
136
|
+
virtual T operator()(Selector_Reference* x) { return static_cast<D*>(this)->fallback(x); }
|
|
137
|
+
virtual T operator()(Selector_Placeholder* x) { return static_cast<D*>(this)->fallback(x); }
|
|
138
|
+
virtual T operator()(Type_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
|
139
|
+
virtual T operator()(Selector_Qualifier* x) { return static_cast<D*>(this)->fallback(x); }
|
|
140
|
+
virtual T operator()(Attribute_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
|
141
|
+
virtual T operator()(Pseudo_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
|
142
|
+
virtual T operator()(Wrapped_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
|
143
|
+
virtual T operator()(Compound_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
|
144
|
+
virtual T operator()(Complex_Selector* x) { return static_cast<D*>(this)->fallback(x); }
|
|
145
|
+
virtual T operator()(Selector_List* x) { return static_cast<D*>(this)->fallback(x); }
|
|
146
|
+
|
|
147
|
+
template <typename U>
|
|
148
|
+
T fallback(U x) { return T(); }
|
|
149
|
+
};
|
|
150
|
+
template<typename T, typename D>
|
|
151
|
+
inline Operation_CRTP<T, D>::~Operation_CRTP() { }
|
|
152
|
+
|
|
153
|
+
}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
#include "output_compressed.hpp"
|
|
2
|
+
#include "inspect.hpp"
|
|
3
|
+
#include "ast.hpp"
|
|
4
|
+
#include "context.hpp"
|
|
5
|
+
#include "to_string.hpp"
|
|
6
|
+
#include "util.hpp"
|
|
7
|
+
#include <cmath>
|
|
8
|
+
#include <iomanip>
|
|
9
|
+
|
|
10
|
+
namespace Sass {
|
|
11
|
+
using namespace std;
|
|
12
|
+
|
|
13
|
+
Output_Compressed::Output_Compressed(Context* ctx) : buffer(""), rendered_imports(""), ctx(ctx), seen_utf8(false) { }
|
|
14
|
+
Output_Compressed::~Output_Compressed() { }
|
|
15
|
+
|
|
16
|
+
inline void Output_Compressed::fallback_impl(AST_Node* n)
|
|
17
|
+
{
|
|
18
|
+
Inspect i(ctx);
|
|
19
|
+
n->perform(&i);
|
|
20
|
+
const string& text = i.get_buffer();
|
|
21
|
+
for(const char& chr : text) {
|
|
22
|
+
// abort clause
|
|
23
|
+
if (seen_utf8) break;
|
|
24
|
+
// skip all normal ascii chars
|
|
25
|
+
if (Util::isAscii(chr)) continue;
|
|
26
|
+
// singleton
|
|
27
|
+
seen_utf8 = true;
|
|
28
|
+
}
|
|
29
|
+
buffer += text;
|
|
30
|
+
if (ctx && !ctx->_skip_source_map_update)
|
|
31
|
+
ctx->source_map.update_column(text);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void Output_Compressed::operator()(Import* imp)
|
|
35
|
+
{
|
|
36
|
+
Inspect insp(ctx);
|
|
37
|
+
imp->perform(&insp);
|
|
38
|
+
rendered_imports += insp.get_buffer();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
void Output_Compressed::operator()(Block* b)
|
|
42
|
+
{
|
|
43
|
+
if (!b->is_root()) return;
|
|
44
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
45
|
+
(*b)[i]->perform(this);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
void Output_Compressed::operator()(Ruleset* r)
|
|
50
|
+
{
|
|
51
|
+
Selector* s = r->selector();
|
|
52
|
+
Block* b = r->block();
|
|
53
|
+
|
|
54
|
+
// Filter out rulesets that aren't printable (process its children though)
|
|
55
|
+
if (!Util::isPrintable(r)) {
|
|
56
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
57
|
+
Statement* stm = (*b)[i];
|
|
58
|
+
if (dynamic_cast<Has_Block*>(stm)) {
|
|
59
|
+
stm->perform(this);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (b->has_non_hoistable()) {
|
|
66
|
+
s->perform(this);
|
|
67
|
+
append_singleline_part_to_buffer("{");
|
|
68
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
69
|
+
Statement* stm = (*b)[i];
|
|
70
|
+
if (!stm->is_hoistable()) {
|
|
71
|
+
stm->perform(this);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
size_t l = buffer.length();
|
|
75
|
+
if (l > 0 && buffer.at(l - 1) == ';') buffer.erase(l - 1);
|
|
76
|
+
append_singleline_part_to_buffer("}");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (b->has_hoistable()) {
|
|
80
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
81
|
+
Statement* stm = (*b)[i];
|
|
82
|
+
if (stm->is_hoistable()) {
|
|
83
|
+
stm->perform(this);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
void Output_Compressed::operator()(Media_Block* m)
|
|
90
|
+
{
|
|
91
|
+
List* q = m->media_queries();
|
|
92
|
+
Block* b = m->block();
|
|
93
|
+
|
|
94
|
+
// Filter out media blocks that aren't printable (process its children though)
|
|
95
|
+
if (!Util::isPrintable(m)) {
|
|
96
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
97
|
+
Statement* stm = (*b)[i];
|
|
98
|
+
if (dynamic_cast<Has_Block*>(stm)) {
|
|
99
|
+
stm->perform(this);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ctx->source_map.add_mapping(m);
|
|
106
|
+
append_singleline_part_to_buffer("@media ");
|
|
107
|
+
q->perform(this);
|
|
108
|
+
append_singleline_part_to_buffer("{");
|
|
109
|
+
|
|
110
|
+
Selector* e = m->selector();
|
|
111
|
+
if (e && b->has_non_hoistable()) {
|
|
112
|
+
// JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
|
|
113
|
+
e->perform(this);
|
|
114
|
+
append_singleline_part_to_buffer("{");
|
|
115
|
+
|
|
116
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
117
|
+
Statement* stm = (*b)[i];
|
|
118
|
+
if (!stm->is_hoistable()) {
|
|
119
|
+
stm->perform(this);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
append_singleline_part_to_buffer("}");
|
|
124
|
+
|
|
125
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
126
|
+
Statement* stm = (*b)[i];
|
|
127
|
+
if (stm->is_hoistable()) {
|
|
128
|
+
stm->perform(this);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// JMA - not hoisted, just output in order
|
|
134
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
135
|
+
Statement* stm = (*b)[i];
|
|
136
|
+
stm->perform(this);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
append_singleline_part_to_buffer("}");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void Output_Compressed::operator()(At_Rule* a)
|
|
144
|
+
{
|
|
145
|
+
string kwd = a->keyword();
|
|
146
|
+
Selector* s = a->selector();
|
|
147
|
+
Expression* v = a->value();
|
|
148
|
+
Block* b = a->block();
|
|
149
|
+
|
|
150
|
+
append_singleline_part_to_buffer(kwd);
|
|
151
|
+
if (s) {
|
|
152
|
+
append_singleline_part_to_buffer(" ");
|
|
153
|
+
s->perform(this);
|
|
154
|
+
}
|
|
155
|
+
else if (v) {
|
|
156
|
+
append_singleline_part_to_buffer(" ");
|
|
157
|
+
v->perform(this);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!b) {
|
|
161
|
+
append_singleline_part_to_buffer(";");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
append_singleline_part_to_buffer("{");
|
|
166
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
167
|
+
Statement* stm = (*b)[i];
|
|
168
|
+
if (!stm->is_hoistable()) {
|
|
169
|
+
stm->perform(this);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for (size_t i = 0, L = b->length(); i < L; ++i) {
|
|
174
|
+
Statement* stm = (*b)[i];
|
|
175
|
+
if (stm->is_hoistable()) {
|
|
176
|
+
stm->perform(this);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
append_singleline_part_to_buffer("}");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void Output_Compressed::operator()(Declaration* d)
|
|
184
|
+
{
|
|
185
|
+
bool bPrintExpression = true;
|
|
186
|
+
// Check print conditions
|
|
187
|
+
if (d->value()->concrete_type() == Expression::NULL_VAL) {
|
|
188
|
+
bPrintExpression = false;
|
|
189
|
+
}
|
|
190
|
+
if (d->value()->concrete_type() == Expression::STRING) {
|
|
191
|
+
String_Constant* valConst = static_cast<String_Constant*>(d->value());
|
|
192
|
+
string val(valConst->value());
|
|
193
|
+
if (val.empty()) {
|
|
194
|
+
bPrintExpression = false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Print if OK
|
|
198
|
+
if(bPrintExpression) {
|
|
199
|
+
if (ctx) ctx->source_map.add_mapping(d->property());
|
|
200
|
+
d->property()->perform(this);
|
|
201
|
+
append_singleline_part_to_buffer(":");
|
|
202
|
+
if (ctx) ctx->source_map.add_mapping(d->value());
|
|
203
|
+
d->value()->perform(this);
|
|
204
|
+
if (d->is_important()) append_singleline_part_to_buffer("!important");
|
|
205
|
+
append_singleline_part_to_buffer(";");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
void Output_Compressed::operator()(Comment* c)
|
|
210
|
+
{
|
|
211
|
+
To_String to_string;
|
|
212
|
+
string txt = c->text()->perform(&to_string);
|
|
213
|
+
if(txt[2] != '!') {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
Inspect i(ctx);
|
|
218
|
+
c->perform(&i);
|
|
219
|
+
const string& text = i.get_buffer();
|
|
220
|
+
for(const char& chr : text) {
|
|
221
|
+
// abort clause
|
|
222
|
+
if (seen_utf8) break;
|
|
223
|
+
// skip all normal ascii chars
|
|
224
|
+
if (Util::isAscii(chr)) continue;
|
|
225
|
+
// singleton
|
|
226
|
+
seen_utf8 = true;
|
|
227
|
+
}
|
|
228
|
+
buffer += text;
|
|
229
|
+
if (ctx && !ctx->_skip_source_map_update)
|
|
230
|
+
ctx->source_map.update_column(text);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
void Output_Compressed::operator()(List* list)
|
|
235
|
+
{
|
|
236
|
+
string sep(list->separator() == List::SPACE ? " " : ",");
|
|
237
|
+
if (list->empty()) return;
|
|
238
|
+
Expression* first = (*list)[0];
|
|
239
|
+
bool first_invisible = first->is_invisible();
|
|
240
|
+
if (!first_invisible) first->perform(this);
|
|
241
|
+
for (size_t i = 1, L = list->length(); i < L; ++i) {
|
|
242
|
+
Expression* next = (*list)[i];
|
|
243
|
+
bool next_invisible = next->is_invisible();
|
|
244
|
+
if (i == 1 && !first_invisible && !next_invisible) append_singleline_part_to_buffer(sep);
|
|
245
|
+
else if (!next_invisible) append_singleline_part_to_buffer(sep);
|
|
246
|
+
next->perform(this);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// helper function for serializing colors
|
|
251
|
+
template <size_t range>
|
|
252
|
+
static double cap_channel(double c) {
|
|
253
|
+
if (c > range) return range;
|
|
254
|
+
else if (c < 0) return 0;
|
|
255
|
+
else return c;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
void Output_Compressed::operator()(Color* c)
|
|
259
|
+
{
|
|
260
|
+
stringstream ss;
|
|
261
|
+
double r = round(cap_channel<0xff>(c->r()));
|
|
262
|
+
double g = round(cap_channel<0xff>(c->g()));
|
|
263
|
+
double b = round(cap_channel<0xff>(c->b()));
|
|
264
|
+
double a = cap_channel<1> (c->a());
|
|
265
|
+
|
|
266
|
+
// retain the originally specified color definition if unchanged
|
|
267
|
+
if (!c->disp().empty()) {
|
|
268
|
+
ss << c->disp();
|
|
269
|
+
}
|
|
270
|
+
else if (r == 0 && g == 0 && b == 0 && a == 0) {
|
|
271
|
+
ss << "transparent";
|
|
272
|
+
}
|
|
273
|
+
else if (a >= 1) {
|
|
274
|
+
// see if it's a named color
|
|
275
|
+
int numval = r * 0x10000;
|
|
276
|
+
numval += g * 0x100;
|
|
277
|
+
numval += b;
|
|
278
|
+
if (ctx && ctx->colors_to_names.count(numval)) {
|
|
279
|
+
ss << ctx->colors_to_names[numval];
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// otherwise output the hex triplet
|
|
283
|
+
ss << '#' << setw(2) << setfill('0');
|
|
284
|
+
ss << hex << setw(2) << static_cast<unsigned long>(r);
|
|
285
|
+
ss << hex << setw(2) << static_cast<unsigned long>(g);
|
|
286
|
+
ss << hex << setw(2) << static_cast<unsigned long>(b);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
ss << "rgba(";
|
|
291
|
+
ss << static_cast<unsigned long>(r) << ",";
|
|
292
|
+
ss << static_cast<unsigned long>(g) << ",";
|
|
293
|
+
ss << static_cast<unsigned long>(b) << ",";
|
|
294
|
+
ss << a << ')';
|
|
295
|
+
}
|
|
296
|
+
append_singleline_part_to_buffer(ss.str());
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
void Output_Compressed::operator()(Media_Query_Expression* mqe)
|
|
300
|
+
{
|
|
301
|
+
if (mqe->is_interpolated()) {
|
|
302
|
+
mqe->feature()->perform(this);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
append_singleline_part_to_buffer("(");
|
|
306
|
+
mqe->feature()->perform(this);
|
|
307
|
+
if (mqe->value()) {
|
|
308
|
+
append_singleline_part_to_buffer(":");
|
|
309
|
+
mqe->value()->perform(this);
|
|
310
|
+
}
|
|
311
|
+
append_singleline_part_to_buffer(")");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
void Output_Compressed::operator()(Null* n)
|
|
316
|
+
{
|
|
317
|
+
// noop
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
void Output_Compressed::operator()(Argument* a)
|
|
321
|
+
{
|
|
322
|
+
if (!a->name().empty()) {
|
|
323
|
+
append_singleline_part_to_buffer(a->name());
|
|
324
|
+
append_singleline_part_to_buffer(":");
|
|
325
|
+
}
|
|
326
|
+
a->value()->perform(this);
|
|
327
|
+
if (a->is_rest_argument()) {
|
|
328
|
+
append_singleline_part_to_buffer("...");
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
void Output_Compressed::operator()(Arguments* a)
|
|
333
|
+
{
|
|
334
|
+
append_singleline_part_to_buffer("(");
|
|
335
|
+
if (!a->empty()) {
|
|
336
|
+
(*a)[0]->perform(this);
|
|
337
|
+
for (size_t i = 1, L = a->length(); i < L; ++i) {
|
|
338
|
+
append_singleline_part_to_buffer(",");
|
|
339
|
+
(*a)[i]->perform(this);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
append_singleline_part_to_buffer(")");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
void Output_Compressed::operator()(Complex_Selector* c)
|
|
346
|
+
{
|
|
347
|
+
Compound_Selector* head = c->head();
|
|
348
|
+
Complex_Selector* tail = c->tail();
|
|
349
|
+
Complex_Selector::Combinator comb = c->combinator();
|
|
350
|
+
if (head && head->is_empty_reference() && tail)
|
|
351
|
+
{
|
|
352
|
+
tail->perform(this);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (head && !head->is_empty_reference()) head->perform(this);
|
|
356
|
+
switch (comb) {
|
|
357
|
+
case Complex_Selector::ANCESTOR_OF:
|
|
358
|
+
if (tail) append_singleline_part_to_buffer(" ");
|
|
359
|
+
break;
|
|
360
|
+
case Complex_Selector::PARENT_OF:
|
|
361
|
+
append_singleline_part_to_buffer(">");
|
|
362
|
+
break;
|
|
363
|
+
case Complex_Selector::PRECEDES:
|
|
364
|
+
// Apparently need to preserve spaces around this combinator?
|
|
365
|
+
if (head && !head->is_empty_reference()) append_singleline_part_to_buffer(" ");
|
|
366
|
+
append_singleline_part_to_buffer("~");
|
|
367
|
+
if (tail) append_singleline_part_to_buffer(" ");
|
|
368
|
+
break;
|
|
369
|
+
case Complex_Selector::ADJACENT_TO:
|
|
370
|
+
append_singleline_part_to_buffer("+");
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
if (tail) tail->perform(this);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
void Output_Compressed::operator()(Selector_List* g)
|
|
377
|
+
{
|
|
378
|
+
if (g->empty()) return;
|
|
379
|
+
(*g)[0]->perform(this);
|
|
380
|
+
for (size_t i = 1, L = g->length(); i < L; ++i) {
|
|
381
|
+
append_singleline_part_to_buffer(",");
|
|
382
|
+
(*g)[i]->perform(this);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
void Output_Compressed::append_singleline_part_to_buffer(const string& text)
|
|
387
|
+
{
|
|
388
|
+
buffer += text;
|
|
389
|
+
if (ctx && !ctx->_skip_source_map_update)
|
|
390
|
+
ctx->source_map.update_column(text);
|
|
391
|
+
for(const char& chr : text) {
|
|
392
|
+
// abort clause
|
|
393
|
+
if (seen_utf8) break;
|
|
394
|
+
// skip all normal ascii chars
|
|
395
|
+
if (Util::isAscii(chr)) continue;
|
|
396
|
+
// singleton
|
|
397
|
+
seen_utf8 = true;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
}
|