sassc 1.7.1 → 1.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/ext/libsass/.gitignore +10 -6
  4. data/ext/libsass/.travis.yml +4 -1
  5. data/ext/libsass/GNUmakefile.am +88 -0
  6. data/ext/libsass/Makefile +157 -76
  7. data/ext/libsass/Makefile.conf +47 -0
  8. data/ext/libsass/Readme.md +13 -14
  9. data/ext/libsass/appveyor.yml +25 -41
  10. data/ext/libsass/configure.ac +20 -7
  11. data/ext/libsass/contrib/plugin.cpp +1 -1
  12. data/ext/libsass/include/sass.h +15 -0
  13. data/ext/libsass/{sass.h → include/sass/base.h} +17 -9
  14. data/ext/libsass/{sass_context.h → include/sass/context.h} +3 -1
  15. data/ext/libsass/{sass_functions.h → include/sass/functions.h} +4 -4
  16. data/ext/libsass/{sass_interface.h → include/sass/interface.h} +5 -2
  17. data/ext/libsass/{sass_values.h → include/sass/values.h} +15 -1
  18. data/ext/libsass/{sass_version.h → include/sass/version.h} +0 -0
  19. data/ext/libsass/{sass_version.h.in → include/sass/version.h.in} +0 -0
  20. data/ext/libsass/{sass2scss.h → include/sass2scss.h} +6 -7
  21. data/ext/libsass/m4/m4-ax_cxx_compile_stdcxx_11.m4 +167 -0
  22. data/ext/libsass/script/ci-build-libsass +67 -23
  23. data/ext/libsass/src/GNUmakefile.am +54 -0
  24. data/ext/libsass/src/ast.cpp +2029 -0
  25. data/ext/libsass/{ast.hpp → src/ast.hpp} +832 -660
  26. data/ext/libsass/src/ast_def_macros.hpp +47 -0
  27. data/ext/libsass/src/ast_factory.hpp +93 -0
  28. data/ext/libsass/{ast_fwd_decl.hpp → src/ast_fwd_decl.hpp} +9 -4
  29. data/ext/libsass/{b64 → src/b64}/cencode.h +1 -1
  30. data/ext/libsass/{b64 → src/b64}/encode.h +0 -0
  31. data/ext/libsass/{backtrace.hpp → src/backtrace.hpp} +9 -10
  32. data/ext/libsass/{base64vlq.cpp → src/base64vlq.cpp} +2 -2
  33. data/ext/libsass/{base64vlq.hpp → src/base64vlq.hpp} +1 -2
  34. data/ext/libsass/{bind.cpp → src/bind.cpp} +96 -59
  35. data/ext/libsass/{bind.hpp → src/bind.hpp} +1 -1
  36. data/ext/libsass/src/c99func.c +54 -0
  37. data/ext/libsass/{cencode.c → src/cencode.c} +5 -5
  38. data/ext/libsass/src/color_maps.cpp +643 -0
  39. data/ext/libsass/src/color_maps.hpp +333 -0
  40. data/ext/libsass/{constants.cpp → src/constants.cpp} +10 -1
  41. data/ext/libsass/{constants.hpp → src/constants.hpp} +7 -0
  42. data/ext/libsass/{context.cpp → src/context.cpp} +152 -122
  43. data/ext/libsass/src/context.hpp +150 -0
  44. data/ext/libsass/{cssize.cpp → src/cssize.cpp} +123 -109
  45. data/ext/libsass/{cssize.hpp → src/cssize.hpp} +9 -13
  46. data/ext/libsass/{debug.hpp → src/debug.hpp} +9 -9
  47. data/ext/libsass/src/debugger.hpp +683 -0
  48. data/ext/libsass/{emitter.cpp → src/emitter.cpp} +13 -13
  49. data/ext/libsass/{emitter.hpp → src/emitter.hpp} +10 -11
  50. data/ext/libsass/src/environment.cpp +184 -0
  51. data/ext/libsass/src/environment.hpp +92 -0
  52. data/ext/libsass/src/error_handling.cpp +46 -0
  53. data/ext/libsass/src/error_handling.hpp +34 -0
  54. data/ext/libsass/src/eval.cpp +1462 -0
  55. data/ext/libsass/src/eval.hpp +107 -0
  56. data/ext/libsass/src/expand.cpp +653 -0
  57. data/ext/libsass/{expand.hpp → src/expand.hpp} +17 -16
  58. data/ext/libsass/{extend.cpp → src/extend.cpp} +198 -139
  59. data/ext/libsass/{extend.hpp → src/extend.hpp} +7 -8
  60. data/ext/libsass/{file.cpp → src/file.cpp} +103 -57
  61. data/ext/libsass/{file.hpp → src/file.hpp} +23 -14
  62. data/ext/libsass/{functions.cpp → src/functions.cpp} +642 -333
  63. data/ext/libsass/{functions.hpp → src/functions.hpp} +17 -4
  64. data/ext/libsass/{inspect.cpp → src/inspect.cpp} +147 -260
  65. data/ext/libsass/{inspect.hpp → src/inspect.hpp} +7 -7
  66. data/ext/libsass/{json.cpp → src/json.cpp} +33 -43
  67. data/ext/libsass/{json.hpp → src/json.hpp} +1 -1
  68. data/ext/libsass/{kwd_arg_macros.hpp → src/kwd_arg_macros.hpp} +0 -0
  69. data/ext/libsass/{lexer.cpp → src/lexer.cpp} +28 -0
  70. data/ext/libsass/{lexer.hpp → src/lexer.hpp} +25 -10
  71. data/ext/libsass/{listize.cpp → src/listize.cpp} +17 -13
  72. data/ext/libsass/{listize.hpp → src/listize.hpp} +0 -2
  73. data/ext/libsass/{mapping.hpp → src/mapping.hpp} +0 -0
  74. data/ext/libsass/src/memory_manager.cpp +76 -0
  75. data/ext/libsass/src/memory_manager.hpp +48 -0
  76. data/ext/libsass/{node.cpp → src/node.cpp} +89 -18
  77. data/ext/libsass/{node.hpp → src/node.hpp} +5 -6
  78. data/ext/libsass/{operation.hpp → src/operation.hpp} +18 -12
  79. data/ext/libsass/{output.cpp → src/output.cpp} +47 -55
  80. data/ext/libsass/{output.hpp → src/output.hpp} +5 -4
  81. data/ext/libsass/src/parser.cpp +2529 -0
  82. data/ext/libsass/{parser.hpp → src/parser.hpp} +84 -60
  83. data/ext/libsass/{paths.hpp → src/paths.hpp} +10 -13
  84. data/ext/libsass/{plugins.cpp → src/plugins.cpp} +14 -17
  85. data/ext/libsass/{plugins.hpp → src/plugins.hpp} +10 -11
  86. data/ext/libsass/{position.cpp → src/position.cpp} +5 -6
  87. data/ext/libsass/{position.hpp → src/position.hpp} +19 -22
  88. data/ext/libsass/{prelexer.cpp → src/prelexer.cpp} +401 -53
  89. data/ext/libsass/{prelexer.hpp → src/prelexer.hpp} +50 -10
  90. data/ext/libsass/{remove_placeholders.cpp → src/remove_placeholders.cpp} +12 -16
  91. data/ext/libsass/{remove_placeholders.hpp → src/remove_placeholders.hpp} +1 -7
  92. data/ext/libsass/{sass.cpp → src/sass.cpp} +3 -5
  93. data/ext/libsass/{sass2scss.cpp → src/sass2scss.cpp} +51 -46
  94. data/ext/libsass/{sass_context.cpp → src/sass_context.cpp} +114 -112
  95. data/ext/libsass/{sass_functions.cpp → src/sass_functions.cpp} +11 -18
  96. data/ext/libsass/{sass_interface.cpp → src/sass_interface.cpp} +44 -81
  97. data/ext/libsass/{sass_util.cpp → src/sass_util.cpp} +26 -8
  98. data/ext/libsass/{sass_util.hpp → src/sass_util.hpp} +14 -18
  99. data/ext/libsass/{sass_values.cpp → src/sass_values.cpp} +91 -20
  100. data/ext/libsass/{source_map.cpp → src/source_map.cpp} +13 -13
  101. data/ext/libsass/{source_map.hpp → src/source_map.hpp} +9 -9
  102. data/ext/libsass/{subset_map.hpp → src/subset_map.hpp} +29 -31
  103. data/ext/libsass/{support → src/support}/libsass.pc.in +0 -0
  104. data/ext/libsass/src/to_c.cpp +73 -0
  105. data/ext/libsass/src/to_c.hpp +41 -0
  106. data/ext/libsass/src/to_string.cpp +47 -0
  107. data/ext/libsass/{to_string.hpp → src/to_string.hpp} +9 -7
  108. data/ext/libsass/src/to_value.cpp +109 -0
  109. data/ext/libsass/src/to_value.hpp +50 -0
  110. data/ext/libsass/{units.cpp → src/units.cpp} +56 -51
  111. data/ext/libsass/{units.hpp → src/units.hpp} +8 -9
  112. data/ext/libsass/{utf8.h → src/utf8.h} +0 -0
  113. data/ext/libsass/{utf8 → src/utf8}/checked.h +0 -0
  114. data/ext/libsass/{utf8 → src/utf8}/core.h +12 -12
  115. data/ext/libsass/{utf8 → src/utf8}/unchecked.h +0 -0
  116. data/ext/libsass/{utf8_string.cpp → src/utf8_string.cpp} +0 -0
  117. data/ext/libsass/{utf8_string.hpp → src/utf8_string.hpp} +6 -6
  118. data/ext/libsass/{util.cpp → src/util.cpp} +144 -86
  119. data/ext/libsass/src/util.hpp +59 -0
  120. data/ext/libsass/src/values.cpp +137 -0
  121. data/ext/libsass/src/values.hpp +12 -0
  122. data/ext/libsass/test/test_node.cpp +33 -33
  123. data/ext/libsass/test/test_paths.cpp +5 -6
  124. data/ext/libsass/test/test_selector_difference.cpp +4 -5
  125. data/ext/libsass/test/test_specificity.cpp +4 -5
  126. data/ext/libsass/test/test_subset_map.cpp +91 -91
  127. data/ext/libsass/test/test_superselector.cpp +11 -11
  128. data/ext/libsass/test/test_unification.cpp +4 -4
  129. data/ext/libsass/win/libsass.targets +101 -0
  130. data/ext/libsass/win/libsass.vcxproj +45 -127
  131. data/ext/libsass/win/libsass.vcxproj.filters +303 -0
  132. data/lib/sassc/import_handler.rb +1 -1
  133. data/lib/sassc/native/native_functions_api.rb +3 -3
  134. data/lib/sassc/version.rb +1 -1
  135. data/test/custom_importer_test.rb +1 -4
  136. data/test/functions_test.rb +3 -2
  137. data/test/native_test.rb +4 -3
  138. metadata +117 -110
  139. data/ext/libsass/Makefile.am +0 -146
  140. data/ext/libsass/ast.cpp +0 -945
  141. data/ext/libsass/ast_def_macros.hpp +0 -21
  142. data/ext/libsass/ast_factory.hpp +0 -92
  143. data/ext/libsass/color_names.hpp +0 -327
  144. data/ext/libsass/context.hpp +0 -157
  145. data/ext/libsass/contextualize.cpp +0 -148
  146. data/ext/libsass/contextualize.hpp +0 -46
  147. data/ext/libsass/contextualize_eval.cpp +0 -93
  148. data/ext/libsass/contextualize_eval.hpp +0 -44
  149. data/ext/libsass/debugger.hpp +0 -558
  150. data/ext/libsass/environment.hpp +0 -163
  151. data/ext/libsass/error_handling.cpp +0 -35
  152. data/ext/libsass/error_handling.hpp +0 -32
  153. data/ext/libsass/eval.cpp +0 -1392
  154. data/ext/libsass/eval.hpp +0 -88
  155. data/ext/libsass/expand.cpp +0 -575
  156. data/ext/libsass/memory_manager.hpp +0 -57
  157. data/ext/libsass/parser.cpp +0 -2403
  158. data/ext/libsass/posix/getopt.c +0 -562
  159. data/ext/libsass/posix/getopt.h +0 -95
  160. data/ext/libsass/to_c.cpp +0 -61
  161. data/ext/libsass/to_c.hpp +0 -44
  162. data/ext/libsass/to_string.cpp +0 -34
  163. data/ext/libsass/util.hpp +0 -54
  164. data/ext/libsass/win/libsass.filters +0 -312
@@ -1,57 +0,0 @@
1
- #ifndef SASS_MEMORY_MANAGER_H
2
- #define SASS_MEMORY_MANAGER_H
3
-
4
- #include <vector>
5
- #include <iostream>
6
-
7
- namespace Sass {
8
- using namespace std;
9
- /////////////////////////////////////////////////////////////////////////////
10
- // A class for tracking allocations of AST_Node objects. The intended usage
11
- // is something like: Some_Node* n = new (mem_mgr) Some_Node(...);
12
- // Then, at the end of the program, the memory manager will delete all of the
13
- // allocated nodes that have been passed to it.
14
- // In the future, this class may implement a custom allocator.
15
- /////////////////////////////////////////////////////////////////////////////
16
- template <typename T>
17
- class Memory_Manager {
18
- vector<T*> nodes;
19
-
20
- public:
21
- Memory_Manager(size_t size = 0) : nodes(vector<T*>())
22
- { nodes.reserve(size); }
23
-
24
- ~Memory_Manager()
25
- {
26
- for (size_t i = 0, S = nodes.size(); i < S; ++i) {
27
- // cout << "deleting " << typeid(*nodes[i]).name() << endl;
28
- delete nodes[i];
29
- }
30
- }
31
-
32
- T* operator()(T* np)
33
- {
34
- nodes.push_back(np);
35
- // cout << "registering " << typeid(*np).name() << endl;
36
- return np;
37
- }
38
-
39
- void remove(T* np)
40
- {
41
- nodes.erase(find(nodes.begin(), nodes.end(), np));
42
- }
43
- };
44
- }
45
-
46
- template <typename T>
47
- inline void* operator new(size_t size, Sass::Memory_Manager<T>& mem_mgr)
48
- { return mem_mgr(static_cast<T*>(operator new(size))); }
49
-
50
- template <typename T>
51
- inline void operator delete(void *np, Sass::Memory_Manager<T>& mem_mgr)
52
- {
53
- mem_mgr.remove(reinterpret_cast<T*>(np));
54
- operator delete(np);
55
- }
56
-
57
- #endif
@@ -1,2403 +0,0 @@
1
- #include <cstdlib>
2
- #include <iostream>
3
- #include <vector>
4
- #include "parser.hpp"
5
- #include "file.hpp"
6
- #include "inspect.hpp"
7
- #include "to_string.hpp"
8
- #include "constants.hpp"
9
- #include "util.hpp"
10
- #include "prelexer.hpp"
11
- #include "sass_functions.h"
12
-
13
- #include <typeinfo>
14
-
15
- namespace Sass {
16
- using namespace std;
17
- using namespace Constants;
18
-
19
- Parser Parser::from_c_str(const char* str, Context& ctx, ParserState pstate)
20
- {
21
- Parser p(ctx, pstate);
22
- p.source = str;
23
- p.position = p.source;
24
- p.end = str + strlen(str);
25
- Block* root = new (ctx.mem) Block(pstate);
26
- p.block_stack.push_back(root);
27
- root->is_root(true);
28
- return p;
29
- }
30
-
31
- Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate)
32
- {
33
- Parser p(ctx, pstate);
34
- p.source = beg;
35
- p.position = p.source;
36
- p.end = end;
37
- Block* root = new (ctx.mem) Block(pstate);
38
- p.block_stack.push_back(root);
39
- root->is_root(true);
40
- return p;
41
- }
42
-
43
- Selector_List* Parser::parse_selector(const char* src, Context& ctx, ParserState pstate)
44
- {
45
- Parser p = Parser::from_c_str(src, ctx, pstate);
46
- // ToDo: ruby sass errors on parent references
47
- // ToDo: remap the source-map entries somehow
48
- return p.parse_selector_group();
49
- }
50
-
51
- bool Parser::peek_newline(const char* start)
52
- {
53
- return peek_linefeed(start ? start : position);
54
- }
55
-
56
- Parser Parser::from_token(Token t, Context& ctx, ParserState pstate)
57
- {
58
- Parser p(ctx, pstate);
59
- p.source = t.begin;
60
- p.position = p.source;
61
- p.end = t.end;
62
- Block* root = new (ctx.mem) Block(pstate);
63
- p.block_stack.push_back(root);
64
- root->is_root(true);
65
- return p;
66
- }
67
-
68
- Block* Parser::parse()
69
- {
70
- Block* root = new (ctx.mem) Block(pstate);
71
- block_stack.push_back(root);
72
- root->is_root(true);
73
- read_bom();
74
-
75
- if (ctx.queue.size() == 1) {
76
- Import* pre = new (ctx.mem) Import(pstate);
77
- string load_path(ctx.queue[0].load_path);
78
- do_import(load_path, pre, ctx.c_headers, false);
79
- ctx.head_imports = ctx.queue.size() - 1;
80
- if (!pre->urls().empty()) (*root) << pre;
81
- if (!pre->files().empty()) {
82
- for (size_t i = 0, S = pre->files().size(); i < S; ++i) {
83
- (*root) << new (ctx.mem) Import_Stub(pstate, pre->files()[i]);
84
- }
85
- }
86
- }
87
-
88
- bool semicolon = false;
89
- string(error_message);
90
- lex< optional_spaces >();
91
- Selector_Lookahead lookahead_result;
92
- while (position < end) {
93
- parse_block_comments(root);
94
- if (peek< kwd_import >()) {
95
- Import* imp = parse_import();
96
- if (!imp->urls().empty()) (*root) << imp;
97
- if (!imp->files().empty()) {
98
- for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
99
- (*root) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
100
- }
101
- }
102
- semicolon = true;
103
- error_message = "top-level @import directive must be terminated by ';'";
104
- }
105
- else if (peek< kwd_mixin >() || peek< kwd_function >()) {
106
- (*root) << parse_definition();
107
- }
108
- else if (peek< variable >()) {
109
- (*root) << parse_assignment();
110
- semicolon = true;
111
- error_message = "top-level variable binding must be terminated by ';'";
112
- }
113
- /*else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
114
- (*root) << parse_propset();
115
- }*/
116
- else if (peek< kwd_include >() /* || peek< exactly<'+'> >() */) {
117
- Mixin_Call* mixin_call = parse_mixin_call();
118
- (*root) << mixin_call;
119
- if (!mixin_call->block()) {
120
- semicolon = true;
121
- error_message = "top-level @include directive must be terminated by ';'";
122
- }
123
- }
124
- else if (peek< kwd_if_directive >()) {
125
- (*root) << parse_if_directive();
126
- }
127
- else if (peek< kwd_for_directive >()) {
128
- (*root) << parse_for_directive();
129
- }
130
- else if (peek< kwd_each_directive >()) {
131
- (*root) << parse_each_directive();
132
- }
133
- else if (peek< kwd_while_directive >()) {
134
- (*root) << parse_while_directive();
135
- }
136
- else if (peek< kwd_media >()) {
137
- (*root) << parse_media_block();
138
- }
139
- else if (peek< kwd_at_root >()) {
140
- (*root) << parse_at_root_block();
141
- }
142
- else if (peek< kwd_supports >()) {
143
- (*root) << parse_feature_block();
144
- }
145
- else if (peek< kwd_warn >()) {
146
- (*root) << parse_warning();
147
- semicolon = true;
148
- error_message = "top-level @warn directive must be terminated by ';'";
149
- }
150
- else if (peek< kwd_err >()) {
151
- (*root) << parse_error();
152
- semicolon = true;
153
- error_message = "top-level @error directive must be terminated by ';'";
154
- }
155
- else if (peek< kwd_dbg >()) {
156
- (*root) << parse_debug();
157
- semicolon = true;
158
- error_message = "top-level @debug directive must be terminated by ';'";
159
- }
160
- // ignore the @charset directive for now
161
- else if (lex< exactly< charset_kwd > >()) {
162
- lex< quoted_string >();
163
- lex< one_plus< exactly<';'> > >();
164
- }
165
- else if (peek< at_keyword >()) {
166
- At_Rule* at_rule = parse_at_rule();
167
- (*root) << at_rule;
168
- if (!at_rule->block()){
169
- semicolon = true;
170
- error_message = "top-level directive must be terminated by ';'";
171
- }
172
- }
173
- else if ((lookahead_result = lookahead_for_selector(position)).found) {
174
- (*root) << parse_ruleset(lookahead_result);
175
- }
176
- else if (peek< exactly<';'> >()) {
177
- lex< one_plus< exactly<';'> > >();
178
- }
179
- else {
180
- lex< css_whitespace >();
181
- if (position >= end) break;
182
- error("invalid top-level expression", after_token);
183
- }
184
- if (semicolon) {
185
- if (!lex< one_plus< exactly<';'> > >() && peek_css< optional_css_whitespace >() != end)
186
- { error(error_message, pstate); }
187
- semicolon = false;
188
- }
189
- lex< optional_spaces >();
190
- }
191
- block_stack.pop_back();
192
- return root;
193
- }
194
-
195
- void Parser::add_single_file (Import* imp, string import_path) {
196
-
197
- string extension;
198
- string unquoted(unquote(import_path));
199
- if (unquoted.length() > 4) { // 2 quote marks + the 4 chars in .css
200
- // a string constant is guaranteed to end with a quote mark, so make sure to skip it when indexing from the end
201
- extension = unquoted.substr(unquoted.length() - 4, 4);
202
- }
203
-
204
- if (extension == ".css") {
205
- String_Constant* loc = new (ctx.mem) String_Constant(pstate, unquote(import_path));
206
- Argument* loc_arg = new (ctx.mem) Argument(pstate, loc);
207
- Arguments* loc_args = new (ctx.mem) Arguments(pstate);
208
- (*loc_args) << loc_arg;
209
- Function_Call* new_url = new (ctx.mem) Function_Call(pstate, "url", loc_args);
210
- imp->urls().push_back(new_url);
211
- }
212
- else {
213
- string current_dir = File::dir_name(path);
214
- string resolved(ctx.add_file(current_dir, unquoted));
215
- if (resolved.empty()) error("file to import not found or unreadable: " + unquoted + "\nCurrent dir: " + current_dir, pstate);
216
- imp->files().push_back(resolved);
217
- }
218
-
219
- }
220
-
221
- void Parser::import_single_file (Import* imp, string import_path) {
222
-
223
- if (!unquote(import_path).substr(0, 7).compare("http://") ||
224
- !unquote(import_path).substr(0, 8).compare("https://") ||
225
- !unquote(import_path).substr(0, 2).compare("//"))
226
- {
227
- imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
228
- }
229
- else {
230
- add_single_file(imp, import_path);
231
- }
232
-
233
- }
234
-
235
- bool Parser::do_import(const string& import_path, Import* imp, vector<Sass_Importer_Entry> importers, bool only_one)
236
- {
237
- bool has_import = false;
238
- string load_path = unquote(import_path);
239
- for (auto importer : importers) {
240
- // int priority = sass_importer_get_priority(importer);
241
- Sass_Importer_Fn fn = sass_importer_get_function(importer);
242
- if (Sass_Import_List includes =
243
- fn(load_path.c_str(), importer, ctx.c_compiler)
244
- ) {
245
- Sass_Import_List list = includes;
246
- while (*includes) {
247
- Sass_Import_Entry include = *includes;
248
- const char *file = sass_import_get_path(include);
249
- char* source = sass_import_take_source(include);
250
- size_t line = sass_import_get_error_line(include);
251
- size_t column = sass_import_get_error_column(include);
252
- const char* message = sass_import_get_error_message(include);
253
- if (message) {
254
- if (line == string::npos && column == string::npos) error(message, pstate);
255
- else error(message, ParserState(message, source, Position(line, column)));
256
- } else if (source) {
257
- if (file) {
258
- ctx.add_source(file, load_path, source);
259
- imp->files().push_back(file);
260
- } else {
261
- ctx.add_source(load_path, load_path, source);
262
- imp->files().push_back(load_path);
263
- }
264
- } else if(file) {
265
- import_single_file(imp, file);
266
- }
267
- ++includes;
268
- }
269
- // deallocate returned memory
270
- sass_delete_import_list(list);
271
- // set success flag
272
- has_import = true;
273
- // break import chain
274
- if (only_one) return true;
275
- }
276
- }
277
- // return result
278
- return has_import;
279
- }
280
-
281
- Import* Parser::parse_import()
282
- {
283
- lex< kwd_import >();
284
- Import* imp = new (ctx.mem) Import(pstate);
285
- bool first = true;
286
- do {
287
- while (lex< block_comment >());
288
- if (lex< quoted_string >()) {
289
- if (!do_import(lexed, imp, ctx.c_importers, true))
290
- {
291
- // push single file import
292
- import_single_file(imp, lexed);
293
- }
294
- }
295
- else if (lex< uri_prefix >()) {
296
- Arguments* args = new (ctx.mem) Arguments(pstate);
297
- Function_Call* result = new (ctx.mem) Function_Call(pstate, "url", args);
298
- if (lex< quoted_string >()) {
299
- Expression* the_url = parse_string();
300
- *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
301
- }
302
- else if (lex < uri_value >(position)) { // chunk seems to work too!
303
- String* the_url = parse_interpolated_chunk(lexed);
304
- *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
305
- }
306
- else if (peek < skip_over_scopes < exactly < '(' >, exactly < ')' > > >(position)) {
307
- Expression* the_url = parse_list(); // parse_interpolated_chunk(lexed);
308
- *args << new (ctx.mem) Argument(the_url->pstate(), the_url);
309
- }
310
- else {
311
- error("malformed URL", pstate);
312
- }
313
- if (!lex< exactly<')'> >()) error("URI is missing ')'", pstate);
314
- imp->urls().push_back(result);
315
- }
316
- else {
317
- if (first) error("@import directive requires a url or quoted path", pstate);
318
- else error("expecting another url or quoted path in @import list", pstate);
319
- }
320
- first = false;
321
- } while (lex_css< exactly<','> >());
322
- return imp;
323
- }
324
-
325
- Definition* Parser::parse_definition()
326
- {
327
- Definition::Type which_type = Definition::MIXIN;
328
- if (lex< kwd_mixin >()) which_type = Definition::MIXIN;
329
- else if (lex< kwd_function >()) which_type = Definition::FUNCTION;
330
- string which_str(lexed);
331
- if (!lex< identifier >()) error("invalid name in " + which_str + " definition", pstate);
332
- string name(Util::normalize_underscores(lexed));
333
- if (which_type == Definition::FUNCTION && (name == "and" || name == "or" || name == "not"))
334
- { error("Invalid function name \"" + name + "\".", pstate); }
335
- ParserState source_position_of_def = pstate;
336
- Parameters* params = parse_parameters();
337
- if (!peek< exactly<'{'> >()) error("body for " + which_str + " " + name + " must begin with a '{'", pstate);
338
- if (which_type == Definition::MIXIN) stack.push_back(mixin_def);
339
- else stack.push_back(function_def);
340
- Block* body = parse_block();
341
- stack.pop_back();
342
- Definition* def = new (ctx.mem) Definition(source_position_of_def, name, params, body, &ctx, which_type);
343
- return def;
344
- }
345
-
346
- Parameters* Parser::parse_parameters()
347
- {
348
- string name(lexed);
349
- Position position = after_token;
350
- Parameters* params = new (ctx.mem) Parameters(pstate);
351
- if (lex_css< exactly<'('> >()) {
352
- // if there's anything there at all
353
- if (!peek_css< exactly<')'> >()) {
354
- do (*params) << parse_parameter();
355
- while (lex_css< exactly<','> >());
356
- }
357
- if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
358
- }
359
- return params;
360
- }
361
-
362
- Parameter* Parser::parse_parameter()
363
- {
364
- while (lex< alternatives < spaces, block_comment > >());
365
- lex< variable >();
366
- string name(Util::normalize_underscores(lexed));
367
- ParserState pos = pstate;
368
- Expression* val = 0;
369
- bool is_rest = false;
370
- while (lex< alternatives < spaces, block_comment > >());
371
- if (lex< exactly<':'> >()) { // there's a default value
372
- while (lex< block_comment >());
373
- val = parse_space_list();
374
- val->is_delayed(false);
375
- }
376
- else if (lex< exactly< ellipsis > >()) {
377
- is_rest = true;
378
- }
379
- Parameter* p = new (ctx.mem) Parameter(pos, name, val, is_rest);
380
- return p;
381
- }
382
-
383
- Mixin_Call* Parser::parse_mixin_call()
384
- {
385
- lex< kwd_include >() /* || lex< exactly<'+'> >() */;
386
- if (!lex< identifier >()) error("invalid name in @include directive", pstate);
387
- ParserState source_position_of_call = pstate;
388
- string name(Util::normalize_underscores(lexed));
389
- Arguments* args = parse_arguments();
390
- Block* content = 0;
391
- if (peek< exactly<'{'> >()) {
392
- content = parse_block();
393
- }
394
- Mixin_Call* the_call = new (ctx.mem) Mixin_Call(source_position_of_call, name, args, content);
395
- return the_call;
396
- }
397
-
398
- Arguments* Parser::parse_arguments(bool has_url)
399
- {
400
- string name(lexed);
401
- Position position = after_token;
402
- Arguments* args = new (ctx.mem) Arguments(pstate);
403
- if (lex_css< exactly<'('> >()) {
404
- // if there's anything there at all
405
- if (!peek_css< exactly<')'> >()) {
406
- do (*args) << parse_argument(has_url);
407
- while (lex_css< exactly<','> >());
408
- }
409
- if (!lex_css< exactly<')'> >()) error("expected a variable name (e.g. $x) or ')' for the parameter list for " + name, position);
410
- }
411
- return args;
412
- }
413
-
414
- Argument* Parser::parse_argument(bool has_url)
415
- {
416
-
417
- Argument* arg;
418
- // some urls can look like line comments (parse literally - chunk would not work)
419
- if (has_url && lex< sequence < uri_value, lookahead < loosely<')'> > > >(false)) {
420
- String* the_url = parse_interpolated_chunk(lexed);
421
- arg = new (ctx.mem) Argument(the_url->pstate(), the_url);
422
- }
423
- else if (peek_css< sequence < variable, optional_css_comments, exactly<':'> > >()) {
424
- lex_css< variable >();
425
- string name(Util::normalize_underscores(lexed));
426
- ParserState p = pstate;
427
- lex_css< exactly<':'> >();
428
- Expression* val = parse_space_list();
429
- val->is_delayed(false);
430
- arg = new (ctx.mem) Argument(p, val, name);
431
- }
432
- else {
433
- bool is_arglist = false;
434
- bool is_keyword = false;
435
- Expression* val = parse_space_list();
436
- val->is_delayed(false);
437
- if (lex_css< exactly< ellipsis > >()) {
438
- if (val->concrete_type() == Expression::MAP) is_keyword = true;
439
- else is_arglist = true;
440
- }
441
- arg = new (ctx.mem) Argument(pstate, val, "", is_arglist, is_keyword);
442
- }
443
- return arg;
444
- }
445
-
446
- Assignment* Parser::parse_assignment()
447
- {
448
- lex< variable >();
449
- string name(Util::normalize_underscores(lexed));
450
- ParserState var_source_position = pstate;
451
- if (!lex< exactly<':'> >()) error("expected ':' after " + name + " in assignment statement", pstate);
452
- Expression* val;
453
- Selector_Lookahead lookahead = lookahead_for_value(position);
454
- if (lookahead.has_interpolants && lookahead.found) {
455
- val = parse_value_schema(lookahead.found);
456
- } else {
457
- val = parse_list();
458
- }
459
- val->is_delayed(false);
460
- bool is_default = false;
461
- bool is_global = false;
462
- while (peek< default_flag >() || peek< global_flag >()) {
463
- is_default = lex< default_flag >() || is_default;
464
- is_global = lex< global_flag >() || is_global;
465
- }
466
- Assignment* var = new (ctx.mem) Assignment(var_source_position, name, val, is_default, is_global);
467
- return var;
468
- }
469
-
470
- /* not used anymore - remove?
471
- Propset* Parser::parse_propset()
472
- {
473
- String* property_segment;
474
- if (peek< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
475
- property_segment = parse_identifier_schema();
476
- }
477
- else {
478
- lex< sequence< optional< exactly<'*'> >, identifier > >();
479
- property_segment = new (ctx.mem) String_Quoted(pstate, lexed);
480
- }
481
- Propset* propset = new (ctx.mem) Propset(pstate, property_segment);
482
- lex< exactly<':'> >();
483
-
484
- if (!peek< exactly<'{'> >()) error("expected a '{' after namespaced property", pstate);
485
-
486
- propset->block(parse_block());
487
-
488
- propset->tabs(indentation);
489
-
490
- return propset;
491
- } */
492
-
493
- Ruleset* Parser::parse_ruleset(Selector_Lookahead lookahead)
494
- {
495
- Selector* sel;
496
- if (lookahead.has_interpolants) {
497
- sel = parse_selector_schema(lookahead.found);
498
- }
499
- else {
500
- sel = parse_selector_group();
501
- }
502
- bool old_in_at_root = in_at_root;
503
- ParserState r_source_position = pstate;
504
- lex < css_comments >();
505
- in_at_root = false;
506
- if (!peek< exactly<'{'> >()) error("expected a '{' after the selector", pstate);
507
- Block* block = parse_block();
508
- in_at_root = old_in_at_root;
509
- old_in_at_root = false;
510
- Ruleset* ruleset = new (ctx.mem) Ruleset(r_source_position, sel, block);
511
- return ruleset;
512
- }
513
-
514
- Selector_Schema* Parser::parse_selector_schema(const char* end_of_selector)
515
- {
516
- lex< optional_spaces >();
517
- const char* i = position;
518
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
519
- while (i < end_of_selector) {
520
- // try to parse mutliple interpolants
521
- if (const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector)) {
522
- // accumulate the preceding segment if the position has advanced
523
- if (i < p) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
524
- // skip to the delimiter by skipping occurences in quoted strings
525
- if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
526
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
527
- }
528
- const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
529
- Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
530
- interpolant->is_interpolant(true);
531
- (*schema) << interpolant;
532
- i = j;
533
- }
534
- // no more interpolants have been found
535
- // add the last segment if there is one
536
- else {
537
- if (i < end_of_selector) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, end_of_selector));
538
- break;
539
- }
540
- }
541
- position = end_of_selector;
542
- Selector_Schema* selector_schema = new (ctx.mem) Selector_Schema(pstate, schema);
543
- selector_schema->media_block(last_media_block);
544
- selector_schema->last_block(block_stack.back());
545
- return selector_schema;
546
- }
547
-
548
- Selector_List* Parser::parse_selector_group()
549
- {
550
- bool reloop = true;
551
- To_String to_string(&ctx);
552
- lex< css_whitespace >();
553
- Selector_List* group = new (ctx.mem) Selector_List(pstate);
554
- group->media_block(last_media_block);
555
- group->last_block(block_stack.back());
556
- do {
557
- reloop = false;
558
- if (peek< alternatives <
559
- exactly<'{'>,
560
- exactly<'}'>,
561
- exactly<')'>,
562
- exactly<';'>
563
- > >())
564
- break; // in case there are superfluous commas at the end
565
- Complex_Selector* comb = parse_selector_combination();
566
- if (!comb->has_reference() && !in_at_root) {
567
- ParserState sel_source_position = pstate;
568
- Selector_Reference* ref = new (ctx.mem) Selector_Reference(sel_source_position);
569
- Compound_Selector* ref_wrap = new (ctx.mem) Compound_Selector(sel_source_position);
570
- ref_wrap->media_block(last_media_block);
571
- ref_wrap->last_block(block_stack.back());
572
- (*ref_wrap) << ref;
573
- if (!comb->head()) {
574
- comb->head(ref_wrap);
575
- comb->has_reference(true);
576
- }
577
- else {
578
- comb = new (ctx.mem) Complex_Selector(sel_source_position, Complex_Selector::ANCESTOR_OF, ref_wrap, comb);
579
- comb->media_block(last_media_block);
580
- comb->last_block(block_stack.back());
581
- comb->has_reference(true);
582
- }
583
- if (peek_newline()) ref_wrap->has_line_break(true);
584
- }
585
- while (peek_css< exactly<','> >())
586
- {
587
- // consume everything up and including the comma speparator
588
- reloop = lex< sequence < optional_css_comments, exactly<','> > >() != 0;
589
- // remember line break (also between some commas)
590
- if (peek_newline()) comb->has_line_feed(true);
591
- if (comb->tail() && peek_newline()) comb->tail()->has_line_feed(true);
592
- if (comb->tail() && comb->tail()->head() && peek_newline()) comb->tail()->head()->has_line_feed(true);
593
- // remember line break (also between some commas)
594
- }
595
- (*group) << comb;
596
- }
597
- while (reloop);
598
- while (lex< optional >()) {
599
- group->is_optional(true);
600
- }
601
- return group;
602
- }
603
-
604
- Complex_Selector* Parser::parse_selector_combination()
605
- {
606
- Position sel_source_position(-1);
607
- Compound_Selector* lhs;
608
- if (peek_css< alternatives <
609
- exactly<'+'>,
610
- exactly<'~'>,
611
- exactly<'>'>
612
- > >())
613
- // no selector before the combinator
614
- { lhs = 0; }
615
- else {
616
- lhs = parse_simple_selector_sequence();
617
- sel_source_position = before_token;
618
- lhs->has_line_break(peek_newline());
619
- }
620
-
621
- Complex_Selector::Combinator cmb;
622
- if (lex< exactly<'+'> >()) cmb = Complex_Selector::ADJACENT_TO;
623
- else if (lex< exactly<'~'> >()) cmb = Complex_Selector::PRECEDES;
624
- else if (lex< exactly<'>'> >()) cmb = Complex_Selector::PARENT_OF;
625
- else cmb = Complex_Selector::ANCESTOR_OF;
626
- bool cpx_lf = peek_newline();
627
-
628
- Complex_Selector* rhs;
629
- if (peek_css< alternatives <
630
- exactly<','>,
631
- exactly<')'>,
632
- exactly<'{'>,
633
- exactly<'}'>,
634
- exactly<';'>,
635
- optional
636
- > >())
637
- // no selector after the combinator
638
- { rhs = 0; }
639
- else {
640
- rhs = parse_selector_combination();
641
- sel_source_position = before_token;
642
- }
643
- if (!sel_source_position.line) sel_source_position = before_token;
644
- Complex_Selector* cpx = new (ctx.mem) Complex_Selector(ParserState(path, source, sel_source_position), cmb, lhs, rhs);
645
- cpx->media_block(last_media_block);
646
- cpx->last_block(block_stack.back());
647
- if (cpx_lf) cpx->has_line_break(cpx_lf);
648
- return cpx;
649
- }
650
-
651
- Compound_Selector* Parser::parse_simple_selector_sequence()
652
- {
653
- Compound_Selector* seq = new (ctx.mem) Compound_Selector(pstate);
654
- seq->media_block(last_media_block);
655
- seq->last_block(block_stack.back());
656
- bool sawsomething = false;
657
- if (lex_css< exactly<'&'> >()) {
658
- // check if we have a parent selector on the root level block
659
- if (block_stack.back() && block_stack.back()->is_root()) {
660
- //error("Base-level rules cannot contain the parent-selector-referencing character '&'.", pstate);
661
- }
662
- (*seq) << new (ctx.mem) Selector_Reference(pstate);
663
- sawsomething = true;
664
- // if you see a space after a &, then you're done
665
- if(peek< spaces >() || peek< alternatives < spaces, exactly<';'> > >()) {
666
- return seq;
667
- }
668
- }
669
- if (sawsomething && lex_css< sequence< negate< functional >, alternatives< identifier_alnums, universal, quoted_string, dimension, percentage, number > > >()) {
670
- // saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
671
- (*seq) << new (ctx.mem) Type_Selector(pstate, unquote(lexed));
672
- } else if (lex_css< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
673
- // if you see a type selector
674
- (*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
675
- sawsomething = true;
676
- }
677
- if (!sawsomething) {
678
- // don't blindly do this if you saw a & or selector
679
- (*seq) << parse_simple_selector();
680
- }
681
-
682
- while (!peek< spaces >(position) &&
683
- !(peek_css < alternatives <
684
- exactly<'+'>,
685
- exactly<'~'>,
686
- exactly<'>'>,
687
- exactly<','>,
688
- exactly<')'>,
689
- exactly<'{'>,
690
- exactly<'}'>,
691
- exactly<';'>
692
- > >(position))) {
693
- (*seq) << parse_simple_selector();
694
- }
695
- return seq;
696
- }
697
-
698
- Simple_Selector* Parser::parse_simple_selector()
699
- {
700
- lex < css_comments >();
701
- if (lex< alternatives < id_name, class_name > >()) {
702
- return new (ctx.mem) Selector_Qualifier(pstate, unquote(lexed));
703
- }
704
- else if (lex< quoted_string >()) {
705
- return new (ctx.mem) Type_Selector(pstate, unquote(lexed));
706
- }
707
- else if (lex< alternatives < number, kwd_sel_deep > >()) {
708
- return new (ctx.mem) Type_Selector(pstate, lexed);
709
- }
710
- else if (peek< pseudo_not >()) {
711
- return parse_negated_selector();
712
- }
713
- else if (peek< exactly<':'> >(position) || peek< functional >()) {
714
- return parse_pseudo_selector();
715
- }
716
- else if (peek< exactly<'['> >(position)) {
717
- return parse_attribute_selector();
718
- }
719
- else if (lex< placeholder >()) {
720
- Selector_Placeholder* sel = new (ctx.mem) Selector_Placeholder(pstate, unquote(lexed));
721
- sel->media_block(last_media_block);
722
- sel->last_block(block_stack.back());
723
- return sel;
724
- }
725
- else {
726
- error("invalid selector after " + lexed.to_string(), pstate);
727
- }
728
- // unreachable statement
729
- return 0;
730
- }
731
-
732
- Wrapped_Selector* Parser::parse_negated_selector()
733
- {
734
- lex< pseudo_not >();
735
- string name(lexed);
736
- ParserState nsource_position = pstate;
737
- Selector* negated = parse_selector_group();
738
- if (!lex< exactly<')'> >()) {
739
- error("negated selector is missing ')'", pstate);
740
- }
741
- return new (ctx.mem) Wrapped_Selector(nsource_position, name, negated);
742
- }
743
-
744
- Simple_Selector* Parser::parse_pseudo_selector() {
745
- if (lex< sequence< pseudo_prefix, functional > >() || lex< functional >()) {
746
- string name(lexed);
747
- String* expr = 0;
748
- ParserState p = pstate;
749
- Selector* wrapped = 0;
750
- if (lex< alternatives< even, odd > >()) {
751
- expr = new (ctx.mem) String_Quoted(p, lexed);
752
- }
753
- else if (lex< binomial >(position)) {
754
- expr = new (ctx.mem) String_Constant(p, lexed);
755
- ((String_Constant*)expr)->can_compress_whitespace(true);
756
- }
757
- else if (peek< sequence< optional<sign>,
758
- zero_plus<digit>,
759
- exactly<'n'>,
760
- optional_css_whitespace,
761
- exactly<')'> > >()) {
762
- lex< sequence< optional<sign>,
763
- zero_plus<digit>,
764
- exactly<'n'> > >();
765
- expr = new (ctx.mem) String_Quoted(p, lexed);
766
- }
767
- else if (lex< sequence< optional<sign>, one_plus < digit > > >()) {
768
- expr = new (ctx.mem) String_Quoted(p, lexed);
769
- }
770
- else if (peek< sequence< identifier, optional_css_whitespace, exactly<')'> > >()) {
771
- lex< identifier >();
772
- expr = new (ctx.mem) String_Quoted(p, lexed);
773
- }
774
- else if (lex< quoted_string >()) {
775
- expr = new (ctx.mem) String_Quoted(p, lexed);
776
- }
777
- else if (peek< exactly<')'> >()) {
778
- expr = new (ctx.mem) String_Constant(p, "");
779
- }
780
- else {
781
- wrapped = parse_selector_group();
782
- }
783
- if (!lex< exactly<')'> >()) error("unterminated argument to " + name + "...)", pstate);
784
- if (wrapped) {
785
- return new (ctx.mem) Wrapped_Selector(p, name, wrapped);
786
- }
787
- return new (ctx.mem) Pseudo_Selector(p, name, expr);
788
- }
789
- else if (lex < sequence< pseudo_prefix, identifier > >()) {
790
- return new (ctx.mem) Pseudo_Selector(pstate, unquote(lexed));
791
- }
792
- else {
793
- error("unrecognized pseudo-class or pseudo-element", pstate);
794
- }
795
- // unreachable statement
796
- return 0;
797
- }
798
-
799
- Attribute_Selector* Parser::parse_attribute_selector()
800
- {
801
- lex_css< exactly<'['> >();
802
- ParserState p = pstate;
803
- if (!lex_css< attribute_name >()) error("invalid attribute name in attribute selector", pstate);
804
- string name(lexed);
805
- if (lex_css< exactly<']'> >()) return new (ctx.mem) Attribute_Selector(p, name, "", 0);
806
- if (!lex_css< alternatives< exact_match, class_match, dash_match,
807
- prefix_match, suffix_match, substring_match > >()) {
808
- error("invalid operator in attribute selector for " + name, pstate);
809
- }
810
- string matcher(lexed);
811
-
812
- String* value = 0;
813
- if (lex_css< identifier >()) {
814
- value = new (ctx.mem) String_Constant(p, lexed);
815
- }
816
- else if (lex_css< quoted_string >()) {
817
- value = parse_interpolated_chunk(lexed, true); // needed!
818
- }
819
- else {
820
- error("expected a string constant or identifier in attribute selector for " + name, pstate);
821
- }
822
-
823
- if (!lex_css< exactly<']'> >()) error("unterminated attribute selector for " + name, pstate);
824
- return new (ctx.mem) Attribute_Selector(p, name, matcher, value);
825
- }
826
-
827
- /* parse block comment and add to block */
828
- void Parser::parse_block_comments(Block* block)
829
- {
830
- while (lex< block_comment >()) {
831
- bool is_important = lexed.begin[2] == '!';
832
- String* contents = parse_interpolated_chunk(lexed);
833
- (*block) << new (ctx.mem) Comment(pstate, contents, is_important);
834
- }
835
- }
836
-
837
- Block* Parser::parse_block()
838
- {
839
- lex< exactly<'{'> >();
840
- bool semicolon = false;
841
- Selector_Lookahead lookahead_result;
842
- Block* block = new (ctx.mem) Block(pstate);
843
- block_stack.push_back(block);
844
- lex< zero_plus < alternatives < space, line_comment > > >();
845
- // JMA - ensure that a block containing only block_comments is parsed
846
- parse_block_comments(block);
847
-
848
- while (!lex< exactly<'}'> >()) {
849
- parse_block_comments(block);
850
- if (semicolon) {
851
- if (!lex< one_plus< exactly<';'> > >()) {
852
- error("non-terminal statement or declaration must end with ';'", pstate);
853
- }
854
- semicolon = false;
855
- parse_block_comments(block);
856
- if (lex< sequence< exactly<'}'>, zero_plus< exactly<';'> > > >()) break;
857
- }
858
- else if (peek< kwd_import >(position)) {
859
- if (stack.back() == mixin_def || stack.back() == function_def) {
860
- lex< kwd_import >(); // to adjust the before_token number
861
- error("@import directives are not allowed inside mixins and functions", pstate);
862
- }
863
- Import* imp = parse_import();
864
- if (!imp->urls().empty()) (*block) << imp;
865
- if (!imp->files().empty()) {
866
- for (size_t i = 0, S = imp->files().size(); i < S; ++i) {
867
- (*block) << new (ctx.mem) Import_Stub(pstate, imp->files()[i]);
868
- }
869
- }
870
- semicolon = true;
871
- }
872
- else if (lex< variable >()) {
873
- (*block) << parse_assignment();
874
- semicolon = true;
875
- }
876
- else if (lex< line_comment >()) {
877
- // throw line comments away
878
- }
879
- else if (peek< kwd_if_directive >()) {
880
- (*block) << parse_if_directive();
881
- }
882
- else if (peek< kwd_for_directive >()) {
883
- (*block) << parse_for_directive();
884
- }
885
- else if (peek< kwd_each_directive >()) {
886
- (*block) << parse_each_directive();
887
- }
888
- else if (peek < kwd_while_directive >()) {
889
- (*block) << parse_while_directive();
890
- }
891
- else if (lex < kwd_return_directive >()) {
892
- (*block) << new (ctx.mem) Return(pstate, parse_list());
893
- semicolon = true;
894
- }
895
- else if (peek< kwd_warn >()) {
896
- (*block) << parse_warning();
897
- semicolon = true;
898
- }
899
- else if (peek< kwd_err >()) {
900
- (*block) << parse_error();
901
- semicolon = true;
902
- }
903
- else if (peek< kwd_dbg >()) {
904
- (*block) << parse_debug();
905
- semicolon = true;
906
- }
907
- else if (stack.back() == function_def) {
908
- error("only variable declarations and control directives are allowed inside functions", pstate);
909
- }
910
- else if (peek< kwd_mixin >() || peek< kwd_function >()) {
911
- (*block) << parse_definition();
912
- }
913
- else if (peek< kwd_include >(position)) {
914
- Mixin_Call* the_call = parse_mixin_call();
915
- (*block) << the_call;
916
- // don't need a semicolon after a content block
917
- semicolon = (the_call->block()) ? false : true;
918
- }
919
- else if (lex< kwd_content >()) {
920
- if (stack.back() != mixin_def) {
921
- error("@content may only be used within a mixin", pstate);
922
- }
923
- (*block) << new (ctx.mem) Content(pstate);
924
- semicolon = true;
925
- }
926
- /*
927
- else if (peek< exactly<'+'> >()) {
928
- (*block) << parse_mixin_call();
929
- semicolon = true;
930
- }
931
- */
932
- else if (lex< kwd_extend >()) {
933
- Selector_Lookahead lookahead = lookahead_for_extension_target(position);
934
- if (!lookahead.found) error("invalid selector for @extend", pstate);
935
- Selector* target;
936
- if (lookahead.has_interpolants) target = parse_selector_schema(lookahead.found);
937
- else target = parse_selector_group();
938
- (*block) << new (ctx.mem) Extension(pstate, target);
939
- semicolon = true;
940
- }
941
- else if (peek< kwd_media >()) {
942
- (*block) << parse_media_block();
943
- }
944
- else if (peek< kwd_supports >()) {
945
- (*block) << parse_feature_block();
946
- }
947
- else if (peek< kwd_at_root >()) {
948
- (*block) << parse_at_root_block();
949
- }
950
- // ignore the @charset directive for now
951
- else if (lex< exactly< charset_kwd > >()) {
952
- lex< quoted_string >();
953
- lex< one_plus< exactly<';'> > >();
954
- }
955
- else if (peek< at_keyword >()) {
956
- At_Rule* at_rule = parse_at_rule();
957
- (*block) << at_rule;
958
- if (!at_rule->block()) semicolon = true;
959
- }
960
- else if ((lookahead_result = lookahead_for_selector(position)).found) {
961
- (*block) << parse_ruleset(lookahead_result);
962
- }/* not used anymore - remove?
963
- else if (peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position)) {
964
- (*block) << parse_propset();
965
- }*/
966
- else if (!peek< exactly<';'> >()) {
967
- bool indent = ! peek< sequence< optional< exactly<'*'> >, alternatives< identifier_schema, identifier >, optional_spaces, exactly<':'>, optional_spaces, exactly<'{'> > >(position);
968
- /* not used anymore - remove?
969
- if (peek< sequence< optional< exactly<'*'> >, identifier_schema, exactly<':'>, exactly<'{'> > >()) {
970
- (*block) << parse_propset();
971
- }
972
- else if (peek< sequence< optional< exactly<'*'> >, identifier, exactly<':'>, exactly<'{'> > >()) {
973
- (*block) << parse_propset();
974
- }
975
- else */ {
976
- Declaration* decl = parse_declaration();
977
- decl->tabs(indentation);
978
- (*block) << decl;
979
- if (peek< exactly<'{'> >()) {
980
- // parse a propset that rides on the declaration's property
981
- if (indent) indentation++;
982
- Propset* ps = new (ctx.mem) Propset(pstate, decl->property(), parse_block());
983
- if (indent) indentation--;
984
- (*block) << ps;
985
- }
986
- else {
987
- // finish and let the semicolon get munched
988
- semicolon = true;
989
- }
990
- }
991
- }
992
- else lex< one_plus< exactly<';'> > >();
993
- parse_block_comments(block);
994
- }
995
- block_stack.pop_back();
996
- return block;
997
- }
998
-
999
- Declaration* Parser::parse_declaration() {
1000
- String* prop = 0;
1001
- if (peek< sequence< optional< exactly<'*'> >, identifier_schema > >()) {
1002
- prop = parse_identifier_schema();
1003
- }
1004
- else if (lex< sequence< optional< exactly<'*'> >, identifier > >()) {
1005
- prop = new (ctx.mem) String_Quoted(pstate, lexed);
1006
- prop->is_delayed(true);
1007
- }
1008
- else {
1009
- error("invalid property name", pstate);
1010
- }
1011
- const string property(lexed);
1012
- if (!lex_css< one_plus< exactly<':'> > >()) error("property \"" + property + "\" must be followed by a ':'", pstate);
1013
- if (peek_css< exactly<';'> >()) error("style declaration must contain a value", pstate);
1014
- if (peek_css< static_value >()) {
1015
- return new (ctx.mem) Declaration(prop->pstate(), prop, parse_static_value()/*, lex<important>()*/);
1016
- }
1017
- else {
1018
- Expression* value;
1019
- Selector_Lookahead lookahead = lookahead_for_value(position);
1020
- if (lookahead.found) {
1021
- if (lookahead.has_interpolants) {
1022
- value = parse_value_schema(lookahead.found);
1023
- } else {
1024
- value = parse_list();
1025
- }
1026
- }
1027
- else {
1028
- value = parse_list();
1029
- if (List* list = dynamic_cast<List*>(value)) {
1030
- if (list->length() == 0 && !peek< exactly <'{'> >()) {
1031
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1032
- }
1033
- }
1034
- }
1035
-
1036
- return new (ctx.mem) Declaration(prop->pstate(), prop, value/*, lex<important>()*/);
1037
- }
1038
- }
1039
-
1040
- // parse +/- and return false if negative
1041
- bool Parser::parse_number_prefix()
1042
- {
1043
- bool positive = true;
1044
- while(true) {
1045
- if (lex < block_comment >()) continue;
1046
- if (lex < number_prefix >()) continue;
1047
- if (lex < exactly < '-' > >()) {
1048
- positive = !positive;
1049
- continue;
1050
- }
1051
- break;
1052
- }
1053
- return positive;
1054
- }
1055
-
1056
- Expression* Parser::parse_map()
1057
- {
1058
- ParserState opstate = pstate;
1059
- Expression* key = parse_list();
1060
- if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
1061
- if (!str->quote_mark() && !str->is_delayed()) {
1062
- if (ctx.names_to_colors.count(str->value())) {
1063
- Color* c = new (ctx.mem) Color(*ctx.names_to_colors[str->value()]);
1064
- c->pstate(str->pstate());
1065
- c->disp(str->value());
1066
- key = c;
1067
- }
1068
- }
1069
- }
1070
-
1071
- // it's not a map so return the lexed value as a list value
1072
- if (!peek< exactly<':'> >())
1073
- { return key; }
1074
-
1075
- lex< exactly<':'> >();
1076
-
1077
- Expression* value = parse_space_list();
1078
-
1079
- Map* map = new (ctx.mem) Map(opstate, 1);
1080
- (*map) << make_pair(key, value);
1081
-
1082
- while (lex_css< exactly<','> >())
1083
- {
1084
- // allow trailing commas - #495
1085
- if (peek_css< exactly<')'> >(position))
1086
- { break; }
1087
-
1088
- Expression* key = parse_list();
1089
- if (String_Quoted* str = dynamic_cast<String_Quoted*>(key)) {
1090
- if (!str->quote_mark() && !str->is_delayed()) {
1091
- if (ctx.names_to_colors.count(str->value())) {
1092
- Color* c = new (ctx.mem) Color(*ctx.names_to_colors[str->value()]);
1093
- c->pstate(str->pstate());
1094
- c->disp(str->value());
1095
- key = c;
1096
- }
1097
- }
1098
- }
1099
-
1100
- if (!(lex< exactly<':'> >()))
1101
- { error("invalid syntax", pstate); }
1102
-
1103
- Expression* value = parse_space_list();
1104
-
1105
- (*map) << make_pair(key, value);
1106
- }
1107
-
1108
- ParserState ps = map->pstate();
1109
- ps.offset = pstate - ps + pstate.offset;
1110
- map->pstate(ps);
1111
-
1112
- return map;
1113
- }
1114
-
1115
- Expression* Parser::parse_list()
1116
- {
1117
- return parse_comma_list();
1118
- }
1119
-
1120
- Expression* Parser::parse_comma_list()
1121
- {
1122
- if (peek_css< alternatives <
1123
- // exactly<'!'>,
1124
- // exactly<':'>,
1125
- exactly<';'>,
1126
- exactly<'}'>,
1127
- exactly<'{'>,
1128
- exactly<')'>,
1129
- exactly<ellipsis>
1130
- > >(position))
1131
- { return new (ctx.mem) List(pstate, 0); }
1132
- Expression* list1 = parse_space_list();
1133
- // if it's a singleton, return it directly; don't wrap it
1134
- if (!peek_css< exactly<','> >(position)) return list1;
1135
-
1136
- List* comma_list = new (ctx.mem) List(pstate, 2, List::COMMA);
1137
- (*comma_list) << list1;
1138
-
1139
- while (lex_css< exactly<','> >())
1140
- {
1141
- if (peek_css< alternatives <
1142
- // exactly<'!'>,
1143
- exactly<';'>,
1144
- exactly<'}'>,
1145
- exactly<'{'>,
1146
- exactly<')'>,
1147
- exactly<':'>,
1148
- exactly<ellipsis>
1149
- > >(position)
1150
- ) { break; }
1151
- Expression* list = parse_space_list();
1152
- (*comma_list) << list;
1153
- }
1154
-
1155
- return comma_list;
1156
- }
1157
-
1158
- Expression* Parser::parse_space_list()
1159
- {
1160
- Expression* disj1 = parse_disjunction();
1161
- // if it's a singleton, return it directly; don't wrap it
1162
- if (peek_css< alternatives <
1163
- // exactly<'!'>,
1164
- exactly<';'>,
1165
- exactly<'}'>,
1166
- exactly<'{'>,
1167
- exactly<')'>,
1168
- exactly<','>,
1169
- exactly<':'>,
1170
- exactly<ellipsis>,
1171
- default_flag,
1172
- global_flag
1173
- > >(position)
1174
- ) { return disj1; }
1175
-
1176
- List* space_list = new (ctx.mem) List(pstate, 2, List::SPACE);
1177
- (*space_list) << disj1;
1178
-
1179
- while (!(peek_css< alternatives <
1180
- // exactly<'!'>,
1181
- exactly<';'>,
1182
- exactly<'}'>,
1183
- exactly<'{'>,
1184
- exactly<')'>,
1185
- exactly<','>,
1186
- exactly<':'>,
1187
- exactly<ellipsis>,
1188
- default_flag,
1189
- global_flag
1190
- > >(position)) && peek_css< optional_css_whitespace >() != end
1191
- ) {
1192
- (*space_list) << parse_disjunction();
1193
- }
1194
-
1195
- return space_list;
1196
- }
1197
-
1198
- Expression* Parser::parse_disjunction()
1199
- {
1200
- Expression* conj1 = parse_conjunction();
1201
- // if it's a singleton, return it directly; don't wrap it
1202
- if (!peek_css< kwd_or >()) return conj1;
1203
-
1204
- vector<Expression*> operands;
1205
- while (lex_css< kwd_or >())
1206
- operands.push_back(parse_conjunction());
1207
-
1208
- return fold_operands(conj1, operands, Binary_Expression::OR);
1209
- }
1210
-
1211
- Expression* Parser::parse_conjunction()
1212
- {
1213
- Expression* rel1 = parse_relation();
1214
- // if it's a singleton, return it directly; don't wrap it
1215
- if (!peek_css< kwd_and >()) return rel1;
1216
-
1217
- vector<Expression*> operands;
1218
- while (lex_css< kwd_and >())
1219
- operands.push_back(parse_relation());
1220
-
1221
- return fold_operands(rel1, operands, Binary_Expression::AND);
1222
- }
1223
-
1224
- Expression* Parser::parse_relation()
1225
- {
1226
- Expression* expr1 = parse_expression();
1227
- // if it's a singleton, return it directly; don't wrap it
1228
- if (!(peek< alternatives <
1229
- kwd_eq,
1230
- kwd_neq,
1231
- kwd_gte,
1232
- kwd_gt,
1233
- kwd_lte,
1234
- kwd_lt
1235
- > >(position)))
1236
- { return expr1; }
1237
-
1238
- Binary_Expression::Type op
1239
- = lex<kwd_eq>() ? Binary_Expression::EQ
1240
- : lex<kwd_neq>() ? Binary_Expression::NEQ
1241
- : lex<kwd_gte>() ? Binary_Expression::GTE
1242
- : lex<kwd_lte>() ? Binary_Expression::LTE
1243
- : lex<kwd_gt>() ? Binary_Expression::GT
1244
- : lex<kwd_lt>() ? Binary_Expression::LT
1245
- : Binary_Expression::LT; // whatever
1246
-
1247
- Expression* expr2 = parse_expression();
1248
-
1249
- return new (ctx.mem) Binary_Expression(expr1->pstate(), op, expr1, expr2);
1250
- }
1251
-
1252
- Expression* Parser::parse_expression()
1253
- {
1254
- Expression* term1 = parse_term();
1255
- // if it's a singleton, return it directly; don't wrap it
1256
- if (!(peek< exactly<'+'> >(position) ||
1257
- (peek< no_spaces >(position) && peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< space > > >(position)) ||
1258
- (peek< sequence< negate< unsigned_number >, exactly<'-'>, negate< unsigned_number > > >(position))) ||
1259
- peek< identifier >(position))
1260
- { return term1; }
1261
-
1262
- vector<Expression*> operands;
1263
- vector<Binary_Expression::Type> operators;
1264
- while (lex< exactly<'+'> >() || lex< sequence< negate< digit >, exactly<'-'> > >()) {
1265
- operators.push_back(lexed.to_string() == "+" ? Binary_Expression::ADD : Binary_Expression::SUB);
1266
- operands.push_back(parse_term());
1267
- }
1268
-
1269
- return fold_operands(term1, operands, operators);
1270
- }
1271
-
1272
- Expression* Parser::parse_term()
1273
- {
1274
- Expression* factor = parse_factor();
1275
- // Special case: Ruby sass never tries to modulo if the lhs contains an interpolant
1276
- if (peek_css< exactly<'%'> >(position) && factor->concrete_type() == Expression::STRING) {
1277
- String_Schema* ss = dynamic_cast<String_Schema*>(factor);
1278
- if (ss && ss->has_interpolants()) return factor;
1279
- }
1280
- // if it's a singleton, return it directly; don't wrap it
1281
- if (!peek< class_char< static_ops > >(position)) return factor;
1282
- return parse_operators(factor);
1283
- }
1284
-
1285
- Expression* Parser::parse_operators(Expression* factor)
1286
- {
1287
- // parse more factors and operators
1288
- vector<Expression*> operands; // factors
1289
- vector<Binary_Expression::Type> operators; // ops
1290
- while (lex_css< class_char< static_ops > >()) {
1291
- switch(*lexed.begin) {
1292
- case '*': operators.push_back(Binary_Expression::MUL); break;
1293
- case '/': operators.push_back(Binary_Expression::DIV); break;
1294
- case '%': operators.push_back(Binary_Expression::MOD); break;
1295
- default: throw runtime_error("unknown static op parsed"); break;
1296
- }
1297
- operands.push_back(parse_factor());
1298
- }
1299
- // operands and operators to binary expression
1300
- return fold_operands(factor, operands, operators);
1301
- }
1302
-
1303
- Expression* Parser::parse_factor()
1304
- {
1305
- if (lex_css< exactly<'('> >()) {
1306
- Expression* value = parse_map();
1307
- if (!lex_css< exactly<')'> >()) error("unclosed parenthesis", pstate);
1308
- value->is_delayed(false);
1309
- // make sure wrapped lists and division expressions are non-delayed within parentheses
1310
- if (value->concrete_type() == Expression::LIST) {
1311
- List* l = static_cast<List*>(value);
1312
- if (!l->empty()) (*l)[0]->is_delayed(false);
1313
- } else if (typeid(*value) == typeid(Binary_Expression)) {
1314
- Binary_Expression* b = static_cast<Binary_Expression*>(value);
1315
- Binary_Expression* lhs = static_cast<Binary_Expression*>(b->left());
1316
- if (lhs && lhs->type() == Binary_Expression::DIV) lhs->is_delayed(false);
1317
- }
1318
- return value;
1319
- }
1320
- else if (peek< ie_property >()) {
1321
- return parse_ie_property();
1322
- }
1323
- else if (peek< ie_keyword_arg >()) {
1324
- return parse_ie_keyword_arg();
1325
- }
1326
- else if (peek< exactly< calc_kwd > >() ||
1327
- peek< exactly< moz_calc_kwd > >() ||
1328
- peek< exactly< ms_calc_kwd > >() ||
1329
- peek< exactly< webkit_calc_kwd > >()) {
1330
- return parse_calc_function();
1331
- }
1332
- else if (peek< functional_schema >()) {
1333
- return parse_function_call_schema();
1334
- }
1335
- else if (peek< sequence< identifier_schema, negate< exactly<'%'> > > >()) {
1336
- return parse_identifier_schema();
1337
- }
1338
- else if (peek< functional >()) {
1339
- return parse_function_call();
1340
- }
1341
- else if (lex< sequence< exactly<'+'>, optional_css_whitespace, negate< number > > >()) {
1342
- return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::PLUS, parse_factor());
1343
- }
1344
- else if (lex< sequence< exactly<'-'>, optional_css_whitespace, negate< number> > >()) {
1345
- return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_factor());
1346
- }
1347
- else if (lex< sequence< kwd_not, css_whitespace > >()) {
1348
- return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::NOT, parse_factor());
1349
- }
1350
- else if (peek < sequence < one_plus < alternatives < css_whitespace, exactly<'-'>, exactly<'+'> > >, number > >()) {
1351
- if (parse_number_prefix()) return parse_value(); // prefix is positive
1352
- return new (ctx.mem) Unary_Expression(pstate, Unary_Expression::MINUS, parse_value());
1353
- }
1354
- else {
1355
- return parse_value();
1356
- }
1357
- }
1358
-
1359
- Expression* Parser::parse_value()
1360
- {
1361
- lex< css_comments >();
1362
- if (lex< ampersand >())
1363
- {
1364
- return new (ctx.mem) Parent_Selector(pstate, parse_selector_group()); }
1365
-
1366
- if (lex< important >())
1367
- { return new (ctx.mem) String_Constant(pstate, "!important"); }
1368
-
1369
- const char* stop;
1370
- if ((stop = peek< value_schema >()))
1371
- { return parse_value_schema(stop); }
1372
-
1373
- if (lex< kwd_true >())
1374
- { return new (ctx.mem) Boolean(pstate, true); }
1375
-
1376
- if (lex< kwd_false >())
1377
- { return new (ctx.mem) Boolean(pstate, false); }
1378
-
1379
- if (lex< kwd_null >())
1380
- { return new (ctx.mem) Null(pstate); }
1381
-
1382
- if (lex< identifier >()) {
1383
- String_Constant* str = new (ctx.mem) String_Quoted(pstate, lexed);
1384
- // Dont' delay this string if it is a name color. Fixes #652.
1385
- str->is_delayed(ctx.names_to_colors.count(unquote(lexed)) == 0);
1386
- return str;
1387
- }
1388
-
1389
- if (lex< percentage >())
1390
- { return new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed); }
1391
-
1392
- // match hex number first because 0x000 looks like a number followed by an indentifier
1393
- if (lex< alternatives< hex, hex0 > >())
1394
- { return new (ctx.mem) Textual(pstate, Textual::HEX, lexed); }
1395
-
1396
- // also handle the 10em- foo special case
1397
- if (lex< sequence< dimension, optional< sequence< exactly<'-'>, negate< digit > > > > >())
1398
- { return new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed); }
1399
-
1400
- if (lex< number >())
1401
- { return new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed); }
1402
-
1403
- if (peek< quoted_string >())
1404
- { return parse_string(); }
1405
-
1406
- if (lex< variable >())
1407
- { return new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed)); }
1408
-
1409
- // Special case handling for `%` proceeding an interpolant.
1410
- if (lex< sequence< exactly<'%'>, optional< percentage > > >())
1411
- { return new (ctx.mem) String_Quoted(pstate, lexed); }
1412
-
1413
- error("error reading values after " + lexed.to_string(), pstate);
1414
-
1415
- // unreachable statement
1416
- return 0;
1417
- }
1418
-
1419
- // this parses interpolation inside other strings
1420
- // means the result should later be quoted again
1421
- String* Parser::parse_interpolated_chunk(Token chunk, bool constant)
1422
- {
1423
- const char* i = chunk.begin;
1424
- // see if there any interpolants
1425
- const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
1426
- if (!p) {
1427
- String_Quoted* str_quoted = new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
1428
- if (!constant && str_quoted->quote_mark()) str_quoted->quote_mark('*');
1429
- str_quoted->is_delayed(true);
1430
- return str_quoted;
1431
- }
1432
-
1433
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1434
- while (i < chunk.end) {
1435
- p = find_first_in_interval< exactly<hash_lbrace> >(i, chunk.end);
1436
- if (p) {
1437
- if (i < p) {
1438
- // accumulate the preceding segment if it's nonempty
1439
- (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, p));
1440
- }
1441
- // we need to skip anything inside strings
1442
- // create a new target in parser/prelexer
1443
- if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
1444
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1445
- }
1446
- const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, chunk.end); // find the closing brace
1447
- if (j) { --j;
1448
- // parse the interpolant and accumulate it
1449
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
1450
- interp_node->is_interpolant(true);
1451
- (*schema) << interp_node;
1452
- i = j;
1453
- }
1454
- else {
1455
- // throw an error if the interpolant is unterminated
1456
- error("unterminated interpolant inside string constant " + chunk.to_string(), pstate);
1457
- }
1458
- }
1459
- else { // no interpolants left; add the last segment if nonempty
1460
- // check if we need quotes here (was not sure after merge)
1461
- if (i < chunk.end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, chunk.end));
1462
- break;
1463
- }
1464
- ++ i;
1465
- }
1466
- return schema;
1467
- }
1468
-
1469
- String_Constant* Parser::parse_static_expression()
1470
- {
1471
- if (peek< sequence< number, optional_spaces, exactly<'/'>, optional_spaces, number > >()) {
1472
- return parse_static_value();
1473
- }
1474
- return 0;
1475
- }
1476
-
1477
- String_Constant* Parser::parse_static_value()
1478
- {
1479
- lex< static_value >();
1480
- Token str(lexed);
1481
- --str.end;
1482
- --position;
1483
-
1484
- String_Constant* str_node = new (ctx.mem) String_Constant(pstate, str.time_wspace());
1485
- str_node->is_delayed(true);
1486
- return str_node;
1487
- }
1488
-
1489
- String* Parser::parse_string()
1490
- {
1491
- lex< quoted_string >();
1492
- Token token(lexed);
1493
- return parse_interpolated_chunk(token);
1494
- }
1495
-
1496
- String* Parser::parse_ie_property()
1497
- {
1498
- lex< ie_property >();
1499
- Token str(lexed);
1500
- const char* i = str.begin;
1501
- // see if there any interpolants
1502
- const char* p = find_first_in_interval< exactly<hash_lbrace> >(str.begin, str.end);
1503
- if (!p) {
1504
- String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
1505
- str_node->is_delayed(true);
1506
- str_node->quote_mark('*');
1507
- return str_node;
1508
- }
1509
-
1510
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1511
- while (i < str.end) {
1512
- p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
1513
- if (p) {
1514
- if (i < p) {
1515
- String_Constant* part = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(i, p))); // accumulate the preceding segment if it's nonempty
1516
- part->is_delayed(true);
1517
- part->quote_mark('*'); // avoid unquote in interpolation
1518
- (*schema) << part;
1519
- }
1520
- if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
1521
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1522
- }
1523
- const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, str.end); // find the closing brace
1524
- if (j) {
1525
- // parse the interpolant and accumulate it
1526
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
1527
- interp_node->is_interpolant(true);
1528
- (*schema) << interp_node;
1529
- i = j;
1530
- }
1531
- else {
1532
- // throw an error if the interpolant is unterminated
1533
- error("unterminated interpolant inside IE function " + str.to_string(), pstate);
1534
- }
1535
- }
1536
- else { // no interpolants left; add the last segment if nonempty
1537
- if (i < str.end) {
1538
- String_Constant* part = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(i, str.end)));
1539
- part->is_delayed(true);
1540
- part->quote_mark('*'); // avoid unquote in interpolation
1541
- (*schema) << part;
1542
- }
1543
- break;
1544
- }
1545
- }
1546
- return schema;
1547
- }
1548
-
1549
- String* Parser::parse_ie_keyword_arg()
1550
- {
1551
- String_Schema* kwd_arg = new (ctx.mem) String_Schema(pstate, 3);
1552
- if (lex< variable >()) {
1553
- *kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
1554
- } else {
1555
- lex< alternatives< identifier_schema, identifier > >();
1556
- *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
1557
- }
1558
- lex< exactly<'='> >();
1559
- *kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
1560
- if (peek< variable >()) *kwd_arg << parse_list();
1561
- else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
1562
- else if (peek < ie_keyword_arg_value >()) { *kwd_arg << parse_list(); }
1563
- return kwd_arg;
1564
- }
1565
-
1566
- String_Schema* Parser::parse_value_schema(const char* stop)
1567
- {
1568
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1569
- size_t num_items = 0;
1570
- if (peek<exactly<'}'>>()) {
1571
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1572
- }
1573
- while (position < stop) {
1574
- if (lex< spaces >() && num_items) {
1575
- (*schema) << new (ctx.mem) String_Constant(pstate, " ");
1576
- }
1577
- else if (lex< interpolant >()) {
1578
- Token insides(Token(lexed.begin + 2, lexed.end - 1));
1579
- Expression* interp_node;
1580
- Parser p = Parser::from_token(insides, ctx, pstate);
1581
- if (!(interp_node = p.parse_static_expression())) {
1582
- interp_node = p.parse_list();
1583
- interp_node->is_interpolant(true);
1584
- }
1585
- (*schema) << interp_node;
1586
- }
1587
- else if (lex< exactly<'%'> >()) {
1588
- (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
1589
- }
1590
- else if (lex< identifier >()) {
1591
- (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1592
- }
1593
- else if (lex< percentage >()) {
1594
- (*schema) << new (ctx.mem) Textual(pstate, Textual::PERCENTAGE, lexed);
1595
- }
1596
- else if (lex< dimension >()) {
1597
- (*schema) << new (ctx.mem) Textual(pstate, Textual::DIMENSION, lexed);
1598
- }
1599
- else if (lex< number >()) {
1600
- Expression* factor = new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed);
1601
- if (peek< class_char< static_ops > >()) {
1602
- (*schema) << parse_operators(factor);
1603
- } else {
1604
- (*schema) << factor;
1605
- }
1606
- }
1607
- else if (lex< hex >()) {
1608
- (*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, unquote(lexed));
1609
- }
1610
- else if (lex < exactly < '-' > >()) {
1611
- (*schema) << new (ctx.mem) String_Constant(pstate, lexed);
1612
- }
1613
- else if (lex< quoted_string >()) {
1614
- (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1615
- }
1616
- else if (lex< variable >()) {
1617
- (*schema) << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
1618
- }
1619
- else if (peek< parenthese_scope >()) {
1620
- (*schema) << parse_factor();
1621
- }
1622
- else {
1623
- error("error parsing interpolated value", pstate);
1624
- }
1625
- ++num_items;
1626
- }
1627
- return schema;
1628
- }
1629
-
1630
- /* not used anymore - remove?
1631
- String_Schema* Parser::parse_url_schema()
1632
- {
1633
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1634
-
1635
- while (position < end) {
1636
- if (position[0] == '/') {
1637
- lexed = Token(position, position+1, before_token);
1638
- (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1639
- ++position;
1640
- }
1641
- else if (lex< interpolant >()) {
1642
- Token insides(Token(lexed.begin + 2, lexed.end - 1, before_token));
1643
- Expression* interp_node = Parser::from_token(insides, ctx, pstate).parse_list();
1644
- interp_node->is_interpolant(true);
1645
- (*schema) << interp_node;
1646
- }
1647
- else if (lex< sequence< identifier, exactly<':'> > >()) {
1648
- (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1649
- }
1650
- else if (lex< filename >()) {
1651
- (*schema) << new (ctx.mem) String_Quoted(pstate, lexed);
1652
- }
1653
- else {
1654
- error("error parsing interpolated url", pstate);
1655
- }
1656
- }
1657
- return schema;
1658
- } */
1659
-
1660
- // this parses interpolation outside other strings
1661
- // means the result must not be quoted again later
1662
- String* Parser::parse_identifier_schema()
1663
- {
1664
- // first lex away whatever we have found
1665
- lex< sequence< optional< exactly<'*'> >, identifier_schema > >();
1666
- Token id(lexed);
1667
- const char* i = id.begin;
1668
- // see if there any interpolants
1669
- const char* p = find_first_in_interval< exactly<hash_lbrace> >(id.begin, id.end);
1670
- if (!p) {
1671
- return new (ctx.mem) String_Quoted(pstate, string(id.begin, id.end));
1672
- }
1673
-
1674
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1675
- while (i < id.end) {
1676
- p = find_first_in_interval< exactly<hash_lbrace> >(i, id.end);
1677
- if (p) {
1678
- if (i < p) {
1679
- // accumulate the preceding segment if it's nonempty
1680
- (*schema) << new (ctx.mem) String_Constant(pstate, string(i, p));
1681
- }
1682
- // we need to skip anything inside strings
1683
- // create a new target in parser/prelexer
1684
- if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
1685
- css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
1686
- }
1687
- const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p+2, id.end); // find the closing brace
1688
- if (j) {
1689
- // parse the interpolant and accumulate it
1690
- Expression* interp_node = Parser::from_token(Token(p+2, j), ctx, pstate).parse_list();
1691
- interp_node->is_interpolant(true);
1692
- (*schema) << interp_node;
1693
- schema->has_interpolants(true);
1694
- i = j;
1695
- }
1696
- else {
1697
- // throw an error if the interpolant is unterminated
1698
- error("unterminated interpolant inside interpolated identifier " + id.to_string(), pstate);
1699
- }
1700
- }
1701
- else { // no interpolants left; add the last segment if nonempty
1702
- if (i < end) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, id.end));
1703
- break;
1704
- }
1705
- }
1706
- return schema;
1707
- }
1708
-
1709
- Function_Call* Parser::parse_calc_function()
1710
- {
1711
- lex< identifier >();
1712
- string name(lexed);
1713
- ParserState call_pos = pstate;
1714
- lex< exactly<'('> >();
1715
- ParserState arg_pos = pstate;
1716
- const char* arg_beg = position;
1717
- parse_list();
1718
- const char* arg_end = position;
1719
- lex< exactly<')'> >();
1720
-
1721
- Argument* arg = new (ctx.mem) Argument(arg_pos, parse_interpolated_chunk(Token(arg_beg, arg_end)));
1722
- Arguments* args = new (ctx.mem) Arguments(arg_pos);
1723
- *args << arg;
1724
- return new (ctx.mem) Function_Call(call_pos, name, args);
1725
- }
1726
-
1727
- Function_Call* Parser::parse_function_call()
1728
- {
1729
- lex< identifier >();
1730
- string name(lexed);
1731
-
1732
- ParserState call_pos = pstate;
1733
- Arguments* args = parse_arguments(name == "url");
1734
- return new (ctx.mem) Function_Call(call_pos, name, args);
1735
- }
1736
-
1737
- Function_Call_Schema* Parser::parse_function_call_schema()
1738
- {
1739
- String* name = parse_identifier_schema();
1740
- ParserState source_position_of_call = pstate;
1741
-
1742
- Function_Call_Schema* the_call = new (ctx.mem) Function_Call_Schema(source_position_of_call, name, parse_arguments());
1743
- return the_call;
1744
- }
1745
-
1746
- If* Parser::parse_if_directive(bool else_if)
1747
- {
1748
- lex< kwd_if_directive >() || (else_if && lex< exactly<if_after_else_kwd> >());
1749
- ParserState if_source_position = pstate;
1750
- Expression* predicate = parse_list();
1751
- predicate->is_delayed(false);
1752
- if (!peek< exactly<'{'> >()) error("expected '{' after the predicate for @if", pstate);
1753
- Block* consequent = parse_block();
1754
- Block* alternative = 0;
1755
-
1756
- if (lex< elseif_directive >()) {
1757
- alternative = new (ctx.mem) Block(pstate);
1758
- (*alternative) << parse_if_directive(true);
1759
- }
1760
- else if (lex< kwd_else_directive >()) {
1761
- if (!peek< exactly<'{'> >()) {
1762
- error("expected '{' after @else", pstate);
1763
- }
1764
- else {
1765
- alternative = parse_block();
1766
- }
1767
- }
1768
- return new (ctx.mem) If(if_source_position, predicate, consequent, alternative);
1769
- }
1770
-
1771
- For* Parser::parse_for_directive()
1772
- {
1773
- lex< kwd_for_directive >();
1774
- ParserState for_source_position = pstate;
1775
- if (!lex< variable >()) error("@for directive requires an iteration variable", pstate);
1776
- string var(Util::normalize_underscores(lexed));
1777
- if (!lex< kwd_from >()) error("expected 'from' keyword in @for directive", pstate);
1778
- Expression* lower_bound = parse_expression();
1779
- lower_bound->is_delayed(false);
1780
- bool inclusive = false;
1781
- if (lex< kwd_through >()) inclusive = true;
1782
- else if (lex< kwd_to >()) inclusive = false;
1783
- else error("expected 'through' or 'to' keyword in @for directive", pstate);
1784
- Expression* upper_bound = parse_expression();
1785
- upper_bound->is_delayed(false);
1786
- if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @for directive", pstate);
1787
- Block* body = parse_block();
1788
- return new (ctx.mem) For(for_source_position, var, lower_bound, upper_bound, body, inclusive);
1789
- }
1790
-
1791
- Each* Parser::parse_each_directive()
1792
- {
1793
- lex < kwd_each_directive >();
1794
- ParserState each_source_position = pstate;
1795
- if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
1796
- vector<string> vars;
1797
- vars.push_back(Util::normalize_underscores(lexed));
1798
- while (lex< exactly<','> >()) {
1799
- if (!lex< variable >()) error("@each directive requires an iteration variable", pstate);
1800
- vars.push_back(Util::normalize_underscores(lexed));
1801
- }
1802
- if (!lex< kwd_in >()) error("expected 'in' keyword in @each directive", pstate);
1803
- Expression* list = parse_list();
1804
- list->is_delayed(false);
1805
- if (list->concrete_type() == Expression::LIST) {
1806
- List* l = static_cast<List*>(list);
1807
- for (size_t i = 0, L = l->length(); i < L; ++i) {
1808
- (*l)[i]->is_delayed(false);
1809
- }
1810
- }
1811
- if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive", pstate);
1812
- Block* body = parse_block();
1813
- return new (ctx.mem) Each(each_source_position, vars, list, body);
1814
- }
1815
-
1816
- While* Parser::parse_while_directive()
1817
- {
1818
- lex< kwd_while_directive >();
1819
- ParserState while_source_position = pstate;
1820
- Expression* predicate = parse_list();
1821
- predicate->is_delayed(false);
1822
- Block* body = parse_block();
1823
- return new (ctx.mem) While(while_source_position, predicate, body);
1824
- }
1825
-
1826
- Media_Block* Parser::parse_media_block()
1827
- {
1828
- lex< kwd_media >();
1829
- ParserState media_source_position = pstate;
1830
-
1831
- List* media_queries = parse_media_queries();
1832
-
1833
- if (!peek< exactly<'{'> >()) {
1834
- error("expected '{' in media query", pstate);
1835
- }
1836
- Media_Block* media_block = new (ctx.mem) Media_Block(media_source_position, media_queries, 0);
1837
- Media_Block* prev_media_block = last_media_block;
1838
- last_media_block = media_block;
1839
- media_block->block(parse_block());
1840
- last_media_block = prev_media_block;
1841
-
1842
- return media_block;
1843
- }
1844
-
1845
- List* Parser::parse_media_queries()
1846
- {
1847
- List* media_queries = new (ctx.mem) List(pstate, 0, List::COMMA);
1848
- if (!peek< exactly<'{'> >()) (*media_queries) << parse_media_query();
1849
- while (lex< exactly<','> >()) (*media_queries) << parse_media_query();
1850
- return media_queries;
1851
- }
1852
-
1853
- // Expression* Parser::parse_media_query()
1854
- Media_Query* Parser::parse_media_query()
1855
- {
1856
- Media_Query* media_query = new (ctx.mem) Media_Query(pstate);
1857
-
1858
- if (lex< exactly< not_kwd > >()) media_query->is_negated(true);
1859
- else if (lex< exactly< only_kwd > >()) media_query->is_restricted(true);
1860
-
1861
- if (peek< identifier_schema >()) media_query->media_type(parse_identifier_schema());
1862
- else if (lex< identifier >()) media_query->media_type(parse_interpolated_chunk(lexed));
1863
- else (*media_query) << parse_media_expression();
1864
-
1865
- while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
1866
- if (peek< identifier_schema >()) {
1867
- String_Schema* schema = new (ctx.mem) String_Schema(pstate);
1868
- *schema << media_query->media_type();
1869
- *schema << new (ctx.mem) String_Constant(pstate, " ");
1870
- *schema << parse_identifier_schema();
1871
- media_query->media_type(schema);
1872
- }
1873
- while (lex< exactly< and_kwd > >()) (*media_query) << parse_media_expression();
1874
- return media_query;
1875
- }
1876
-
1877
- Media_Query_Expression* Parser::parse_media_expression()
1878
- {
1879
- if (peek< identifier_schema >()) {
1880
- String* ss = parse_identifier_schema();
1881
- return new (ctx.mem) Media_Query_Expression(pstate, ss, 0, true);
1882
- }
1883
- if (!lex< exactly<'('> >()) {
1884
- error("media query expression must begin with '('", pstate);
1885
- }
1886
- Expression* feature = 0;
1887
- if (peek< exactly<')'> >()) {
1888
- error("media feature required in media query expression", pstate);
1889
- }
1890
- feature = parse_expression();
1891
- Expression* expression = 0;
1892
- if (lex< exactly<':'> >()) {
1893
- expression = parse_list();
1894
- }
1895
- if (!lex< exactly<')'> >()) {
1896
- error("unclosed parenthesis in media query expression", pstate);
1897
- }
1898
- return new (ctx.mem) Media_Query_Expression(feature->pstate(), feature, expression);
1899
- }
1900
-
1901
- Feature_Block* Parser::parse_feature_block()
1902
- {
1903
- lex< kwd_supports >();
1904
- ParserState supports_source_position = pstate;
1905
-
1906
- Feature_Query* feature_queries = parse_feature_queries();
1907
-
1908
- if (!peek< exactly<'{'> >()) {
1909
- error("expected '{' in feature query", pstate);
1910
- }
1911
- Block* block = parse_block();
1912
-
1913
- return new (ctx.mem) Feature_Block(supports_source_position, feature_queries, block);
1914
- }
1915
-
1916
- Feature_Query* Parser::parse_feature_queries()
1917
- {
1918
- Feature_Query* fq = new (ctx.mem) Feature_Query(pstate);
1919
- Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
1920
- cond->is_root(true);
1921
- while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
1922
- (*cond) << parse_feature_query();
1923
- (*fq) << cond;
1924
-
1925
- if (fq->empty()) error("expected @supports condition (e.g. (display: flexbox))", pstate);
1926
-
1927
- return fq;
1928
- }
1929
-
1930
- Feature_Query_Condition* Parser::parse_feature_query()
1931
- {
1932
- if (peek< kwd_not >(position)) return parse_supports_negation();
1933
- else if (peek< kwd_and >(position)) return parse_supports_conjunction();
1934
- else if (peek< kwd_or >(position)) return parse_supports_disjunction();
1935
- else if (peek< exactly<'('> >(position)) return parse_feature_query_in_parens();
1936
- else return parse_supports_declaration();
1937
- }
1938
-
1939
- Feature_Query_Condition* Parser::parse_feature_query_in_parens()
1940
- {
1941
- Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(pstate);
1942
-
1943
- if (!lex< exactly<'('> >()) error("@supports declaration expected '('", pstate);
1944
- while (!peek< exactly<')'> >(position) && !peek< exactly<'{'> >(position))
1945
- (*cond) << parse_feature_query();
1946
- if (!lex< exactly<')'> >()) error("unclosed parenthesis in @supports declaration", pstate);
1947
-
1948
- return (cond->length() == 1) ? (*cond)[0] : cond;
1949
- }
1950
-
1951
- Feature_Query_Condition* Parser::parse_supports_negation()
1952
- {
1953
- lex< kwd_not >();
1954
-
1955
- Feature_Query_Condition* cond = parse_feature_query();
1956
- cond->operand(Feature_Query_Condition::NOT);
1957
-
1958
- return cond;
1959
- }
1960
-
1961
- Feature_Query_Condition* Parser::parse_supports_conjunction()
1962
- {
1963
- lex< kwd_and >();
1964
-
1965
- Feature_Query_Condition* cond = parse_feature_query();
1966
- cond->operand(Feature_Query_Condition::AND);
1967
-
1968
- return cond;
1969
- }
1970
-
1971
- Feature_Query_Condition* Parser::parse_supports_disjunction()
1972
- {
1973
- lex< kwd_or >();
1974
-
1975
- Feature_Query_Condition* cond = parse_feature_query();
1976
- cond->operand(Feature_Query_Condition::OR);
1977
-
1978
- return cond;
1979
- }
1980
-
1981
- Feature_Query_Condition* Parser::parse_supports_declaration()
1982
- {
1983
- Declaration* declaration = parse_declaration();
1984
- Feature_Query_Condition* cond = new (ctx.mem) Feature_Query_Condition(declaration->pstate(),
1985
- 1,
1986
- declaration->property(),
1987
- declaration->value());
1988
- return cond;
1989
- }
1990
-
1991
- At_Root_Block* Parser::parse_at_root_block()
1992
- {
1993
- lex<kwd_at_root>();
1994
- ParserState at_source_position = pstate;
1995
- Block* body = 0;
1996
- At_Root_Expression* expr = 0;
1997
- Selector_Lookahead lookahead_result;
1998
- in_at_root = true;
1999
- if (peek< exactly<'('> >()) {
2000
- expr = parse_at_root_expression();
2001
- body = parse_block();
2002
- }
2003
- else if (peek< exactly<'{'> >()) {
2004
- body = parse_block();
2005
- }
2006
- else if ((lookahead_result = lookahead_for_selector(position)).found) {
2007
- Ruleset* r = parse_ruleset(lookahead_result);
2008
- body = new (ctx.mem) Block(r->pstate(), 1);
2009
- *body << r;
2010
- }
2011
- in_at_root = false;
2012
- At_Root_Block* at_root = new (ctx.mem) At_Root_Block(at_source_position, body);
2013
- if (expr) at_root->expression(expr);
2014
- return at_root;
2015
- }
2016
-
2017
- At_Root_Expression* Parser::parse_at_root_expression()
2018
- {
2019
- lex< exactly<'('> >();
2020
- if (peek< exactly<')'> >()) error("at-root feature required in at-root expression", pstate);
2021
-
2022
- if (!peek< alternatives< kwd_with_directive, kwd_without_directive > >()) {
2023
- css_error("Invalid CSS", " after ", ": expected \"with\" or \"without\", was ");
2024
- }
2025
-
2026
- Declaration* declaration = parse_declaration();
2027
- List* value = new (ctx.mem) List(declaration->value()->pstate(), 1);
2028
-
2029
- if (declaration->value()->concrete_type() == Expression::LIST) {
2030
- value = static_cast<List*>(declaration->value());
2031
- }
2032
- else *value << declaration->value();
2033
-
2034
- At_Root_Expression* cond = new (ctx.mem) At_Root_Expression(declaration->pstate(),
2035
- declaration->property(),
2036
- value);
2037
- if (!lex< exactly<')'> >()) error("unclosed parenthesis in @at-root expression", pstate);
2038
- return cond;
2039
- }
2040
-
2041
- At_Rule* Parser::parse_at_rule()
2042
- {
2043
- lex<at_keyword>();
2044
- string kwd(lexed);
2045
- ParserState at_source_position = pstate;
2046
- Selector* sel = 0;
2047
- Expression* val = 0;
2048
- Selector_Lookahead lookahead = lookahead_for_extension_target(position);
2049
- if (lookahead.found) {
2050
- if (lookahead.has_interpolants) {
2051
- sel = parse_selector_schema(lookahead.found);
2052
- }
2053
- else {
2054
- sel = parse_selector_group();
2055
- }
2056
- }
2057
- else if (!(peek<exactly<'{'> >() || peek<exactly<'}'> >() || peek<exactly<';'> >())) {
2058
- val = parse_list();
2059
- }
2060
- Block* body = 0;
2061
- if (peek< exactly<'{'> >()) body = parse_block();
2062
- At_Rule* rule = new (ctx.mem) At_Rule(at_source_position, kwd, sel, body);
2063
- if (!sel) rule->value(val);
2064
- return rule;
2065
- }
2066
-
2067
- Warning* Parser::parse_warning()
2068
- {
2069
- lex< kwd_warn >();
2070
- return new (ctx.mem) Warning(pstate, parse_list());
2071
- }
2072
-
2073
- Error* Parser::parse_error()
2074
- {
2075
- lex< kwd_err >();
2076
- return new (ctx.mem) Error(pstate, parse_list());
2077
- }
2078
-
2079
- Debug* Parser::parse_debug()
2080
- {
2081
- lex< kwd_dbg >();
2082
- return new (ctx.mem) Debug(pstate, parse_list());
2083
- }
2084
-
2085
- Selector_Lookahead Parser::lookahead_for_selector(const char* start)
2086
- {
2087
- const char* p = start ? start : position;
2088
- const char* q;
2089
- bool saw_stuff = false;
2090
- bool saw_interpolant = false;
2091
-
2092
- while ((q = peek< identifier >(p)) ||
2093
- (q = peek< hyphens_and_identifier >(p)) ||
2094
- (q = peek< hyphens_and_name >(p)) ||
2095
- (q = peek< type_selector >(p)) ||
2096
- (q = peek< id_name >(p)) ||
2097
- (q = peek< class_name >(p)) ||
2098
- (q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
2099
- (q = peek< percentage >(p)) ||
2100
- (q = peek< variable >(p)) ||
2101
- (q = peek< dimension >(p)) ||
2102
- (q = peek< quoted_string >(p)) ||
2103
- (q = peek< exactly<'*'> >(p)) ||
2104
- (q = peek< exactly<sel_deep_kwd> >(p)) ||
2105
- (q = peek< exactly<'('> >(p)) ||
2106
- (q = peek< exactly<')'> >(p)) ||
2107
- (q = peek< exactly<'['> >(p)) ||
2108
- (q = peek< exactly<']'> >(p)) ||
2109
- (q = peek< exactly<'+'> >(p)) ||
2110
- (q = peek< exactly<'~'> >(p)) ||
2111
- (q = peek< exactly<'>'> >(p)) ||
2112
- (q = peek< exactly<','> >(p)) ||
2113
- (saw_stuff && (q = peek< exactly<'-'> >(p))) ||
2114
- (q = peek< binomial >(p)) ||
2115
- (q = peek< block_comment >(p)) ||
2116
- (q = peek< sequence< optional<sign>,
2117
- zero_plus<digit>,
2118
- exactly<'n'> > >(p)) ||
2119
- (q = peek< sequence< optional<sign>,
2120
- one_plus<digit> > >(p)) ||
2121
- (q = peek< number >(p)) ||
2122
- (q = peek< sequence< exactly<'&'>,
2123
- identifier_alnums > >(p)) ||
2124
- (q = peek< exactly<'&'> >(p)) ||
2125
- (q = peek< exactly<'%'> >(p)) ||
2126
- (q = peek< alternatives<exact_match,
2127
- class_match,
2128
- dash_match,
2129
- prefix_match,
2130
- suffix_match,
2131
- substring_match> >(p)) ||
2132
- (q = peek< sequence< exactly<'.'>, interpolant > >(p)) ||
2133
- (q = peek< sequence< exactly<'#'>, interpolant > >(p)) ||
2134
- (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p)) ||
2135
- (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
2136
- (q = peek< interpolant >(p))) {
2137
- saw_stuff = true;
2138
- p = q;
2139
- if (*(p - 1) == '}') saw_interpolant = true;
2140
- }
2141
-
2142
- Selector_Lookahead result;
2143
- result.found = saw_stuff && peek< exactly<'{'> >(p) ? p : 0;
2144
- result.has_interpolants = saw_interpolant;
2145
-
2146
- return result;
2147
- }
2148
-
2149
- Selector_Lookahead Parser::lookahead_for_extension_target(const char* start)
2150
- {
2151
- const char* p = start ? start : position;
2152
- const char* q;
2153
- bool saw_interpolant = false;
2154
- bool saw_stuff = false;
2155
-
2156
- while ((q = peek< identifier >(p)) ||
2157
- (q = peek< type_selector >(p)) ||
2158
- (q = peek< id_name >(p)) ||
2159
- (q = peek< class_name >(p)) ||
2160
- (q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
2161
- (q = peek< percentage >(p)) ||
2162
- (q = peek< dimension >(p)) ||
2163
- (q = peek< quoted_string >(p)) ||
2164
- (q = peek< exactly<'*'> >(p)) ||
2165
- (q = peek< exactly<'('> >(p)) ||
2166
- (q = peek< exactly<')'> >(p)) ||
2167
- (q = peek< exactly<'['> >(p)) ||
2168
- (q = peek< exactly<']'> >(p)) ||
2169
- (q = peek< exactly<'+'> >(p)) ||
2170
- (q = peek< exactly<'~'> >(p)) ||
2171
- (q = peek< exactly<'>'> >(p)) ||
2172
- (q = peek< exactly<','> >(p)) ||
2173
- (saw_stuff && (q = peek< exactly<'-'> >(p))) ||
2174
- (q = peek< binomial >(p)) ||
2175
- (q = peek< block_comment >(p)) ||
2176
- (q = peek< sequence< optional<sign>,
2177
- zero_plus<digit>,
2178
- exactly<'n'> > >(p)) ||
2179
- (q = peek< sequence< optional<sign>,
2180
- one_plus<digit> > >(p)) ||
2181
- (q = peek< number >(p)) ||
2182
- (q = peek< sequence< exactly<'&'>,
2183
- identifier_alnums > >(p)) ||
2184
- (q = peek< exactly<'&'> >(p)) ||
2185
- (q = peek< exactly<'%'> >(p)) ||
2186
- (q = peek< alternatives<exact_match,
2187
- class_match,
2188
- dash_match,
2189
- prefix_match,
2190
- suffix_match,
2191
- substring_match> >(p)) ||
2192
- (q = peek< sequence< exactly<'.'>, interpolant > >(p)) ||
2193
- (q = peek< sequence< exactly<'#'>, interpolant > >(p)) ||
2194
- (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p)) ||
2195
- (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
2196
- (q = peek< interpolant >(p)) ||
2197
- (q = peek< optional >(p))) {
2198
- p = q;
2199
- if (*(p - 1) == '}') saw_interpolant = true;
2200
- saw_stuff = true;
2201
- }
2202
-
2203
- Selector_Lookahead result;
2204
- result.found = peek< alternatives< exactly<';'>, exactly<'}'>, exactly<'{'> > >(p) && saw_stuff ? p : 0;
2205
- result.has_interpolants = saw_interpolant;
2206
-
2207
- return result;
2208
- }
2209
-
2210
-
2211
- Selector_Lookahead Parser::lookahead_for_value(const char* start)
2212
- {
2213
- const char* p = start ? start : position;
2214
- const char* q;
2215
- bool saw_interpolant = false;
2216
- bool saw_stuff = false;
2217
-
2218
- while ((q = peek< identifier >(p)) ||
2219
- (q = peek< percentage >(p)) ||
2220
- (q = peek< dimension >(p)) ||
2221
- (q = peek< quoted_string >(p)) ||
2222
- (q = peek< variable >(p)) ||
2223
- (q = peek< exactly<'*'> >(p)) ||
2224
- (q = peek< exactly<'+'> >(p)) ||
2225
- (q = peek< exactly<'~'> >(p)) ||
2226
- (q = peek< exactly<'>'> >(p)) ||
2227
- (q = peek< exactly<','> >(p)) ||
2228
- (q = peek< sequence<parenthese_scope, interpolant>>(p)) ||
2229
- (saw_stuff && (q = peek< exactly<'-'> >(p))) ||
2230
- (q = peek< binomial >(p)) ||
2231
- (q = peek< block_comment >(p)) ||
2232
- (q = peek< sequence< optional<sign>,
2233
- zero_plus<digit>,
2234
- exactly<'n'> > >(p)) ||
2235
- (q = peek< sequence< optional<sign>,
2236
- one_plus<digit> > >(p)) ||
2237
- (q = peek< number >(p)) ||
2238
- (q = peek< sequence< exactly<'&'>,
2239
- identifier_alnums > >(p)) ||
2240
- (q = peek< exactly<'&'> >(p)) ||
2241
- (q = peek< exactly<'%'> >(p)) ||
2242
- (q = peek< sequence< exactly<'.'>, interpolant > >(p)) ||
2243
- (q = peek< sequence< exactly<'#'>, interpolant > >(p)) ||
2244
- (q = peek< sequence< one_plus< exactly<'-'> >, interpolant > >(p)) ||
2245
- (q = peek< sequence< pseudo_prefix, interpolant > >(p)) ||
2246
- (q = peek< interpolant >(p)) ||
2247
- (q = peek< optional >(p))) {
2248
- p = q;
2249
- if (*(p - 1) == '}') saw_interpolant = true;
2250
- saw_stuff = true;
2251
- }
2252
-
2253
- Selector_Lookahead result;
2254
- result.found = peek< alternatives< exactly<';'>, exactly<'}'>, exactly<'{'> > >(p) && saw_stuff ? p : 0;
2255
- result.has_interpolants = saw_interpolant;
2256
-
2257
- return result;
2258
- }
2259
-
2260
- void Parser::read_bom()
2261
- {
2262
- size_t skip = 0;
2263
- string encoding;
2264
- bool utf_8 = false;
2265
- switch ((unsigned char) source[0]) {
2266
- case 0xEF:
2267
- skip = check_bom_chars(source, end, utf_8_bom, 3);
2268
- encoding = "UTF-8";
2269
- utf_8 = true;
2270
- break;
2271
- case 0xFE:
2272
- skip = check_bom_chars(source, end, utf_16_bom_be, 2);
2273
- encoding = "UTF-16 (big endian)";
2274
- break;
2275
- case 0xFF:
2276
- skip = check_bom_chars(source, end, utf_16_bom_le, 2);
2277
- skip += (skip ? check_bom_chars(source, end, utf_32_bom_le, 4) : 0);
2278
- encoding = (skip == 2 ? "UTF-16 (little endian)" : "UTF-32 (little endian)");
2279
- break;
2280
- case 0x00:
2281
- skip = check_bom_chars(source, end, utf_32_bom_be, 4);
2282
- encoding = "UTF-32 (big endian)";
2283
- break;
2284
- case 0x2B:
2285
- skip = check_bom_chars(source, end, utf_7_bom_1, 4)
2286
- | check_bom_chars(source, end, utf_7_bom_2, 4)
2287
- | check_bom_chars(source, end, utf_7_bom_3, 4)
2288
- | check_bom_chars(source, end, utf_7_bom_4, 4)
2289
- | check_bom_chars(source, end, utf_7_bom_5, 5);
2290
- encoding = "UTF-7";
2291
- break;
2292
- case 0xF7:
2293
- skip = check_bom_chars(source, end, utf_1_bom, 3);
2294
- encoding = "UTF-1";
2295
- break;
2296
- case 0xDD:
2297
- skip = check_bom_chars(source, end, utf_ebcdic_bom, 4);
2298
- encoding = "UTF-EBCDIC";
2299
- break;
2300
- case 0x0E:
2301
- skip = check_bom_chars(source, end, scsu_bom, 3);
2302
- encoding = "SCSU";
2303
- break;
2304
- case 0xFB:
2305
- skip = check_bom_chars(source, end, bocu_1_bom, 3);
2306
- encoding = "BOCU-1";
2307
- break;
2308
- case 0x84:
2309
- skip = check_bom_chars(source, end, gb_18030_bom, 4);
2310
- encoding = "GB-18030";
2311
- break;
2312
- }
2313
- if (skip > 0 && !utf_8) error("only UTF-8 documents are currently supported; your document appears to be " + encoding, pstate);
2314
- position += skip;
2315
- }
2316
-
2317
- size_t check_bom_chars(const char* src, const char *end, const unsigned char* bom, size_t len)
2318
- {
2319
- size_t skip = 0;
2320
- if (src + len > end) return 0;
2321
- for (size_t i = 0; i < len; ++i, ++skip) {
2322
- if ((unsigned char) src[i] != bom[i]) return 0;
2323
- }
2324
- return skip;
2325
- }
2326
-
2327
-
2328
- Expression* Parser::fold_operands(Expression* base, vector<Expression*>& operands, Binary_Expression::Type op)
2329
- {
2330
- for (size_t i = 0, S = operands.size(); i < S; ++i) {
2331
- base = new (ctx.mem) Binary_Expression(pstate, op, base, operands[i]);
2332
- Binary_Expression* b = static_cast<Binary_Expression*>(base);
2333
- if (op == Binary_Expression::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
2334
- base->is_delayed(true);
2335
- }
2336
- else {
2337
- b->left()->is_delayed(false);
2338
- b->right()->is_delayed(false);
2339
- }
2340
- }
2341
- return base;
2342
- }
2343
-
2344
- Expression* Parser::fold_operands(Expression* base, vector<Expression*>& operands, vector<Binary_Expression::Type>& ops)
2345
- {
2346
- for (size_t i = 0, S = operands.size(); i < S; ++i) {
2347
- base = new (ctx.mem) Binary_Expression(base->pstate(), ops[i], base, operands[i]);
2348
- Binary_Expression* b = static_cast<Binary_Expression*>(base);
2349
- if (ops[i] == Binary_Expression::DIV && b->left()->is_delayed() && b->right()->is_delayed()) {
2350
- base->is_delayed(true);
2351
- }
2352
- else {
2353
- b->left()->is_delayed(false);
2354
- b->right()->is_delayed(false);
2355
- }
2356
- }
2357
- return base;
2358
- }
2359
-
2360
- void Parser::error(string msg, Position pos)
2361
- {
2362
- throw Sass_Error(Sass_Error::syntax, ParserState(path, source, pos.line ? pos : before_token, Offset(0, 0)), msg);
2363
- }
2364
-
2365
- // print a css parsing error with actual context information from parsed source
2366
- void Parser::css_error(const string& msg, const string& prefix, const string& middle)
2367
- {
2368
- int max_len = 14;
2369
- const char* pos = peek < optional_spaces >();
2370
- bool ellipsis_left = false;
2371
- const char* pos_left(pos);
2372
- while (*pos_left && pos_left > source) {
2373
- if (pos - pos_left > max_len) {
2374
- ellipsis_left = true;
2375
- break;
2376
- }
2377
- const char* prev = pos_left - 1;
2378
- if (*prev == '\r') break;
2379
- if (*prev == '\n') break;
2380
- if (*prev == 10) break;
2381
- pos_left = prev;
2382
- }
2383
- bool ellipsis_right = false;
2384
- const char* pos_right(pos);
2385
- while (*pos_right && pos_right <= end) {
2386
- if (pos_right - pos > max_len) {
2387
- ellipsis_right = true;
2388
- break;
2389
- }
2390
- if (*pos_right == '\r') break;
2391
- if (*pos_right == '\n') break;
2392
- if (*pos_left == 10) break;
2393
- ++ pos_right;
2394
- }
2395
- string left(pos_left, pos);
2396
- string right(pos, pos_right);
2397
- if (ellipsis_left) left = ellipsis + left;
2398
- if (ellipsis_right) right = right + ellipsis;
2399
- // now pass new message to the more generic error function
2400
- error(msg + prefix + quote(left) + middle + quote(right), pstate);
2401
- }
2402
-
2403
- }